A opinionated ESLint config preset for JavaScript, TypeScript, Vue 2 or Vue 3, and Prettier.
- Format with Prettier.
- Designed to work with TypeScript, Vue 2 and 3 out-of-box.
- Support Astro, JSON(5), YAML, Markdown, ...
- Sort imports,
package.json
,tsconfig.json
... - ESLint Flat config, compose easily!
- Ignores common files like
dist
,node_modules
,coverage
, and files in.gitignore
. - Reasonable defaults, best practices, only one-line of config
- Reasonable strict, but with better code quality.
- Requires ESLint v9.5.0+
npm i -D @xwbx/eslint-config
Require Node.js >= 18.18, and ESLint >= 9.5.0.
import { xwbx } from "@xwbx/eslint-config";
export default xwbx(
{
// TypeScript, Vue, Unocss And Astro are autodetected, you can also explicitly enable them:
typescript: true,
vue: true,
unocss: true,
astro: true,
// Disable jsonc yaml and toml support
jsonc: false,
yaml: false,
toml: false,
// `.eslintignore` is no longer supported in Flat config, use `ignores` instead
ignores: [
"**/fixtures",
// ...globs
],
},
// From the second arguments they are ESLint Flat Configs
// you can have multiple configs
{
files: ["**/*.ts"],
rules: {},
},
);
Unocss support is detected automatically by checking if unocss
or@unocss/webpack
or@unocss/nuxt'
is installed in your project. You can also explicitly enable/disable it:
// eslint.config.js
import xwbx from "@xwbx/eslint-config";
export default xwbx({
unocss: true,
});
Running npx eslint
should prompt you to install the required dependencies, otherwise, you can install them manually:
pnpm i -D @unocss/eslint-plugin
Astro support is detected automatically by checking if astro
is installed in your project. You can also explicitly enable/disable it:
// eslint.config.js
import xwbx from "@xwbx/eslint-config";
export default xwbx({
astro: true,
});
Running npx eslint
should prompt you to install the required dependencies, otherwise, you can install them manually:
pnpm i -D astro-eslint-parser eslint-plugin-astro prettier-plugin-astro
Default option is
const prettierOptions = {
tabWidth: 2,
useTabs: false,
trailingComma: "all",
singleQuote: false,
semi: true,
endOfLine: "lf",
};
Override by formatters.prettierOptions
// eslint.config.js
export default xwbx({
formatters: {
prettierOptions: {
semi: false,
},
},
});
This plugin eslint-plugin-perfectionist
allows you to sort object keys, imports, etc, with auto-fix.
The plugin is installed, but only perfectionist/sort-imports
, perfectionist/sort-named-exports
and perfectionist/sort-named-imports
are enabled by default.
It's recommended to opt-in on each file individually using configuration comments.
/* eslint perfectionist/sort-exports: "error" */
export * from "./astro";
export * from "./command";
export * from "./comments";
Powered by eslint-plugin-command
. It is not a typical rule for linting, but an on-demand micro-codemod tool that triggers by specific comments.
For a few triggers, for example:
/// to-function
- converts an arrow function to a normal function/// to-arrow
- converts a normal function to an arrow function/// to-for-each
- converts a for-in/for-of loop to.forEach()
/// to-for-of
- converts a.forEach()
to a for-of loop/// keep-sorted
- sorts an object/array/interface- ... etc. - refer to the documentation
You can add the trigger comment one line above the code you want to transform, for example (note the triple slash):
/// to-function
const foo = async (msg: string): void => {
console.log(msg)
}
Will be transformed to this when you hit save with your editor or run eslint . --fix
:
async function foo(msg: string): void {
console.log(msg);
}
The command comments are usually one-off and will be removed along with the transformation.
Since flat config requires us to explicitly provide the plugin names (instead of the mandatory convention from npm package name), we renamed some plugins to make the overall scope more consistent and easier to write.
New Prefix | Original Prefix | Source Plugin |
---|---|---|
import/* |
import-x/* |
eslint-plugin-import-x |
node/* |
n/* |
eslint-plugin-n |
yaml/* |
yml/* |
eslint-plugin-yml |
ts/* |
@typescript-eslint/* |
@typescript-eslint/eslint-plugin |
style/* |
@stylistic/* |
@stylistic/eslint-plugin |
test/* |
vitest/* |
@vitest/eslint-plugin |
test/* |
no-only-tests/* |
eslint-plugin-no-only-tests |
When you want to override rules, or disable them inline, you need to update to the new prefix:
-// eslint-disable-next-line @typescript-eslint/consistent-type-definitions
+// eslint-disable-next-line ts/consistent-type-definitions
type foo = { bar: 2 }
Some rules are disabled when inside ESLint IDE integrations, namely unused-imports/no-unused-imports
test/no-only-tests
This is to prevent unused imports from getting removed by the IDE during refactoring to get a better developer experience. Those rules will be applied when you run ESLint in the terminal or Lint Staged. If you don't want this behavior, you can disable them:
// eslint.config.js
import xwbx from "@xwbx/eslint-config";
export default xwbx({
isInEditor: false,
});
Certain rules would only be enabled in specific files, for example, ts/*
rules would only be enabled in .ts
files and vue/*
rules would only be enabled in .vue
files. If you want to override the rules, you need to specify the file extension:
// eslint.config.js
import xwbx from "@xwbx/eslint-config";
export default xwbx(
{
vue: true,
typescript: true,
},
{
// Remember to specify the file glob here, otherwise it might cause the vue plugin to handle non-vue files
files: ["**/*.vue"],
rules: {
"vue/operator-linebreak": ["error", "before"],
},
},
{
// Without `files`, they are general rules for all files
rules: {
"style/semi": ["error", "never"],
},
},
);
We also provided the overrides
options in each integration to make it easier:
// eslint.config.js
import xwbx from "@xwbx/eslint-config";
export default xwbx({
vue: {
overrides: {
"vue/operator-linebreak": ["error", "before"],
},
},
typescript: {
overrides: {
"ts/consistent-type-definitions": ["error", "interface"],
},
},
yaml: {
overrides: {
// ...
},
},
});
Enable flat config if you are using ESLint < 9.
{
// Disable the default formatter, use eslint instead
"prettier.enable": false,
"eslint.experimental.useFlatConfig": true,
"eslint.useFlatConfig": true,
// Auto fix
"editor.codeActionsOnSave": {
"source.fixAll.eslint": "explicit",
"source.organizeImports": "never",
},
// Enable eslint for all supported languages
"eslint.validate": [
"javascript",
"javascriptreact",
"typescript",
"typescriptreact",
"vue",
"html",
"markdown",
"json",
"jsonc",
"yaml",
"toml",
"xml",
"svg",
"gql",
"graphql",
"astro",
"css",
"less",
"scss",
"pcss",
"postcss",
],
}
This setup is heavily inspired on a few projects: