This note does not pretend to be complete - in fact, I don’t even want to understand how this junk works under the hood. However, it might save someone a day of work.
For some reason, the ESLint developers once again changed (this 9.0.0 v. is the second or third time in my memory) the configuration file format and plugin packages, so now the old configs do not work, so adding a linter to a new project may cause a problem. In fact, thanks to the efforts of these wonderful people, even this note will most likely soon become useless.
Official way
To get started, you can use the command that is recommended to use for setup in the official guide:
npm init @eslint/config
However, after this, simply running the linter will most likely not produce any result. Even if you run the linter with the correct command specifying the files to check, it still won’t work:
The most interesting thing here is that the official guide gives a completely empty example of the config, as if you did not execute their command npm init @eslint/config
After running this command, the config will look something like this (if they haven’t changed anything again, lol):
import path from "path";
import { fileURLToPath } from "url";
import { FlatCompat } from "@eslint/eslintrc";
import pluginJs from "@eslint/js";
// mimic CommonJS variables -- not needed if using CommonJS
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const compat = new FlatCompat({
baseDirectory: __dirname,
recommendedConfig: pluginJs.configs.recommended
});
export default [
...compat.extends("standard-with-typescript")
];
Example of the eslint.config.js for the new version
Another way
Since the official config, apparently, is quite crooked (and, to be honest, I don’t even know if it works correctly), you may want to install the linter yourself. For this config you will need to install the following packages in the project:
{
"devDependencies": {
... // your other deps
"@eslint/eslintrc": "^3.0.2",
"@eslint/js": "^9.0.0",
"@typescript-eslint/eslint-plugin": "^6.21.0",
"eslint": "^8.57.0",
"eslint-config-standard-with-typescript": "^43.0.1",
"eslint-plugin-import": "^2.29.1",
"eslint-plugin-n": "^16.6.2",
"eslint-plugin-promise": "^6.1.1"
}
}
As i already said, just after install linter wouldn't work anyway, because you still need add files section in config and, possible add some your own rules to it.
I found out that if need to add rules to the config file, you must do it in a certain way: since we already have some rules created by config command, we don't need to just add new ones, but do it next way:
import path from "path";
import { fileURLToPath } from "url";
import { FlatCompat } from "@eslint/eslintrc";
import pluginJs from "@eslint/js";
// mimic CommonJS variables -- not needed if using CommonJS
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const compat = new FlatCompat({
baseDirectory: __dirname,
recommendedConfig: pluginJs.configs.recommended
});
export default [
...compat.extends("standard-with-typescript").map(
config => ({
...config,
files: ["**/*.tsx"],
rules: {
...config.rules,
"semi": "off", // For some reason the old rule is buggy and needs to be disabled IDK
"@typescript-eslint/semi": ["error", "always"],
"no-unreachable": "error", // Already in ts, but perhaps it catches more cases
"@typescript-eslint/explicit-function-return-type": "off",
"@typescript-eslint/strict-boolean-expressions": "off", // Often works incorrectly
"@typescript-eslint/no-floating-promises": "off",
}
})
),
];
Working example of eslint.config.js with custom rules
Now you can start the linter with the following command (for some reason it is still necessary to additionally specify files in the console, i have no idea why):
npx eslint 'src/**/*.{ts,tsx}' --no-ignore
You can add it to your scripts section of package.json
for easy launch via npm run
.
What's next? Code formatting?
The next stage, which may throw you into frustration, is that it turns out that the new linter now does not know how to properly format code out of the box.
Now a linter is purely a linter. Wow! Such great idea!
You can read about it here (the indentation problem that no one wanted to fix) and here (about the integration between a linter and a formatter), and here is even more detailed information about the “problems” with using linters as formatters.
So, in addition to the file with the linter settings, you will also have to add a .prettierrc
file with the prettier settings:
{
"tabWidth": 4,
"singleQuote": true
}
...as well as install the prettier itself:
npm install --save-dev eslint-plugin-prettier eslint-config-prettier
npm install --save-dev --save-exact prettier
Yes, and besides, you will once again have to correct the linter config. Here's the final version:
import path from "path";
import { fileURLToPath } from "url";
import { FlatCompat } from "@eslint/eslintrc";
import pluginJs from "@eslint/js";
import prettierConfig from 'eslint-config-prettier';
import eslintPluginPrettierRecommended from 'eslint-plugin-prettier/recommended';
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const compat = new FlatCompat({
baseDirectory: __dirname,
recommendedConfig: pluginJs.configs.recommended
});
export default [
...compat.extends("standard-with-typescript").map(
config => ({
...config,
files: ["**/*.tsx"],
rules: {
...config.rules,
// ...other your custom rules
}
})
),
prettierConfig, // Turns off all ESLint rules that have the potential to interfere with Prettier rules.
eslintPluginPrettierRecommended
];
Note: While it is possible to pass options to Prettier via your ESLint configuration file, it is not recommended because editor extensions such as prettier-atom and prettier-vscode will read .prettierrc, but won't read settings from ESLint, which can lead to an inconsistent experience.
Well, now, after all these crutches and a bunch of new garbage wonderful files in the root of your project, you can now use the linter. I think those who have read to the end already understand why the linter is a lousy tool in general.
But everything should work now. I hope this is useful to someone.
As for my opinion, ESLint is absolute garbage, a perfect example of a garbage application, so if you have a choice, try looking for something else. In my company it is a standard tool, so for years i have had to deal with changing config formats, constant renaming of plugin packages (FOR THAT?) and compatibility problems caused by this junk software. ESLint you must burn in hell!
Top comments (5)
Heyo!
Just a reminder that you likely want to add tags to your post to help with discoverability. Folks follow tags to discover posts in their "relevant" feed on the DEV homepage, so tags are really important for getting your posts seen.
You can add popular, established tags, more niche tags, or create a brand new tag if there's one that has yet to be created. Some tags are centered around a technology (#python, #javascript) and others are more functional (#discuss, #help, #tutorial)... you can use a combination of 4 tags on your post, so choose wisely.
Always make sure that the tags you choose fit the subject matter of your post. Different tags have submission guidelines set up for them which you can view on a tag's landing page. For example, view the landing page for #career - dev.to/t/career and you'll see that the submission guidelines read:
Note that we recruit Tag Moderators to help us create submission guidelines and ensure that posts are properly tagged.
Those are some of the basics of tags! Feel free to visit DEV Help for other helpful information!
Thanks, I completely forgot about them
That small notes at the end of this article is such valuable! 😆
Not sure if I can follow your last comment about ESLint being absolute garbage. At least, I would expect to get some suggestions for alternative tools with similar capabilities.
I adhere to the following position: firstly (this is the most important thing), even ESLint will not protect you from serious bugs, no matter how you configure it. Secondly, using TypeScript correctly allows you to catch a huge number of errors (although i don't really like TypeScript, i can't help but admit that it actually works).
If you still want an alternative, I would advise you to look at Quick-lint-js or OxLint.