.gitignore by defaultpnpm add -D eslint @vinicunca/eslint-config
npm install -D eslint @vinicunca/eslint-config
bun add -d eslint @vinicunca/eslint-config
And create eslint.config.mjs in your project root:
import { vinicuncaESLint } from '@vinicunca/eslint-config';
export default vinicuncaESLint();
For example:
{
"scripts": {
"lint": "eslint",
"lint:fix": "eslint --fix"
}
}
Install VS Code ESLint extension then add the following settings to your .vscode/settings.json:
{
// Disable the default formatter, use eslint instead
"prettier.enable": false,
"editor.formatOnSave": false,
// 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",
"gql",
"graphql",
"astro",
"svelte",
"css",
"less",
"scss",
"pcss",
"postcss"
]
}
Update your configuration to use the following:
local customizations = {
{ rule = 'style/*', severity = 'off', fixable = true },
{ rule = 'format/*', severity = 'off', fixable = true },
{ rule = '*-indent', severity = 'off', fixable = true },
{ rule = '*-spacing', severity = 'off', fixable = true },
{ rule = '*-spaces', severity = 'off', fixable = true },
{ rule = '*-order', severity = 'off', fixable = true },
{ rule = '*-dangle', severity = 'off', fixable = true },
{ rule = '*-newline', severity = 'off', fixable = true },
{ rule = '*quotes', severity = 'off', fixable = true },
{ rule = '*semi', severity = 'off', fixable = true },
}
local lspconfig = require('lspconfig')
-- Enable eslint for all supported languages
lspconfig.eslint.setup(
{
filetypes = {
"javascript",
"javascriptreact",
"javascript.jsx",
"typescript",
"typescriptreact",
"typescript.tsx",
"vue",
"html",
"markdown",
"json",
"jsonc",
"yaml",
"toml",
"xml",
"gql",
"graphql",
"astro",
"svelte",
"css",
"less",
"scss",
"pcss",
"postcss"
},
settings = {
-- Silent the stylistic rules in your IDE, but still auto fix them
rulesCustomizations = customizations,
},
}
)
There's few ways you can achieve format on save in neovim:
nvim-lspconfig has a EslintFixAll command predefined, you can create a autocmd to call this command after saving file.lspconfig.eslint.setup({
--- ...
on_attach = function(client, bufnr)
vim.api.nvim_create_autocmd("BufWritePre", {
buffer = bufnr,
command = "EslintFixAll",
})
end,
})
Normally you only need to import the eslint-config preset:
import { vinicuncaESLint } from '@vinicunca/eslint-config';
export default vinicuncaESLint();
And that's it! Or you can configure each integration individually, for example:
import { vinicuncaESLint } from '@vinicunca/eslint-config';
export default vinicuncaESLint(
{
// Type of the project. 'lib' for libraries, the default is 'app'
type: 'lib',
// `.eslintignore` is no longer supported in Flat config, use `ignores` instead
// The `ignores` option in the option (first argument) is specifically treated to always be global ignores
// And will **extend** the config's default ignores, not override them
// You can also pass a function to modify the default ignores
ignores: [
'**/fixtures',
// ...globs
],
// Parse the `.gitignore` file to get the ignores, on by default
gitignore: true,
// Enable stylistic formatting rules
stylistic: true,
// Or customize the stylistic rules
stylistic: {
indent: 2, // 4, or 'tab'
quotes: 'single', // or 'double'
},
// TypeScript and Vue are autodetected, you can also explicitly enable them:
typescript: true,
vue: true,
// Disable jsonc and yaml support
jsonc: false,
yaml: false,
}
);
The vinicuncaESLint factory function also accepts any number of arbitrary custom config overrides:
import { vinicuncaESLint } from '@vinicunca/eslint-config';
export default vinicuncaESLint(
{
// Configures for vinicuncaESLint's config
},
// From the second arguments they are ESLint Flat Configs
// you can have multiple configs
{
files: ['**/*.ts'],
rules: {},
},
{
rules: {},
},
);
Going more advanced, you can also import fine-grained configs and compose them as you wish:
We wouldn't recommend using this style in general unless you know exactly what they are doing, as there are shared options between configs and might need extra care to make them consistent.
import {
combine,
comments,
ignores,
imports,
javascript,
jsdoc,
jsonc,
markdown,
node,
sortPackageJson,
sortTsconfig,
stylistic,
toml,
typescript,
unicorn,
vue,
yaml,
} from '@vinicunca/eslint-config';
export default combine(
ignores(),
javascript(/* Options */),
comments(),
node(),
jsdoc(),
imports(),
unicorn(),
typescript(/* Options */),
stylistic(),
vue(),
jsonc(),
yaml(),
toml(),
markdown(),
);
Check out the configs and factory for more details.
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-lite/* | eslint-plugin-import-lite |
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 |
next/* | @next/next | @next/eslint-plugin-next |
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 }
import/order without ever knowing the underlying plugin has migrated twice to eslint-plugin-i and then to eslint-plugin-import-x. User are also not forced to migrate to the implicit i/order halfway only because we swapped the implementation to a fork.This preset will automatically rename the plugins also for your custom configs. You can use the original prefix to override the rules directly.
If you really want to use the original prefix, you can revert the plugin renaming by:
import { vinicuncaESLint } from '@vinicunca/eslint-config';
export default vinicuncaESLint()
.renamePlugins({
ts: '@typescript-eslint',
yaml: 'yml',
node: 'n'
// ...
});
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:
import { vinicuncaESLint } from '@vinicunca/eslint-config';
export default vinicuncaESLint(
{
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:
import { vinicuncaESLint } from '@vinicunca/eslint-config';
export default vinicuncaESLint({
vue: {
overrides: {
'vue/operator-linebreak': ['error', 'before'],
},
},
typescript: {
overrides: {
'ts/consistent-type-definitions': ['error', 'interface'],
},
},
yaml: {
overrides: {
// ...
},
},
});
The factory function vinicuncaESLint() returns a FlatConfigComposer object from eslint-flat-config-utils where you can chain the methods to compose the config even more flexibly.
import { vinicuncaESLint } from '@vinicunca/eslint-config';
export default vinicuncaESLint()
.prepend(
// some configs before the main config
)
// overrides any named configs
.override(
'antfu/stylistic/rules',
{
rules: {
'style/generator-star-spacing': ['error', { after: true, before: false }],
}
}
)
// rename plugin prefixes
.renamePlugins({
'old-prefix': 'new-prefix',
// ...
});
// ...
Vue support is detected automatically by checking if vue is installed in your project. You can also explicitly enable/disable it:
import { vinicuncaESLint } from '@vinicunca/eslint-config';
export default vinicuncaESLint({
vue: true
});
To enable Vue accessibility support, you need to explicitly turn it on:
import { vinicuncaESLint } from '@vinicunca/eslint-config';
export default vinicuncaESLint({
vue: {
a11y: true
},
});
Running pnpx eslint should prompt you to install the required dependencies, otherwise, you can install them manually:
pnpm add -D eslint-plugin-vuejs-accessibility
npm install -D eslint-plugin-vuejs-accessibility
bun add -d eslint-plugin-vuejs-accessibility
We provide some optional configs for specific use cases, that we don't include their dependencies by default.
Use external formatters to format files that ESLint cannot handle yet (.css, .html, etc). Powered by eslint-plugin-format.
import { vinicuncaESLint } from '@vinicunca/eslint-config';
export default vinicuncaESLint({
formatters: {
/**
* Format CSS, LESS, SCSS files, also the `<style>` blocks in Vue
* By default uses Prettier
*/
css: true,
/**
* Format HTML files
* By default uses Prettier
*/
html: true,
/**
* Format Markdown files
* Supports Prettier and dprint
* By default uses Prettier
*/
markdown: 'prettier'
}
});
Running pnpx eslint should prompt you to install the required dependencies, otherwise, you can install them manually:
pnpm add -D eslint-plugin-format
npm install -D eslint-plugin-format
bun add -d eslint-plugin-format
To enable React support, you need to explicitly turn it on:
import { vinicuncaESLint } from '@vinicunca/eslint-config';
export default vinicuncaESLint({
react: true,
});
Running pnpx eslint should prompt you to install the required dependencies, otherwise, you can install them manually:
pnpm add -D @eslint-react/eslint-plugin eslint-plugin-react-hooks eslint-plugin-react-refresh
npm install -D @eslint-react/eslint-plugin eslint-plugin-react-hooks eslint-plugin-react-refresh
bun add -d @eslint-react/eslint-plugin eslint-plugin-react-hooks eslint-plugin-react-refresh
To enable Next.js support, you need to explicitly turn it on:
import { vinicuncaESLint } from '@vinicunca/eslint-config';
export default vinicuncaESLint({
nextjs: true,
});
Running pnpx eslint should prompt you to install the required dependencies, otherwise, you can install them manually:
pnpm add -D @next/eslint-plugin-next
npm install -D @next/eslint-plugin-next
bun add -d @next/eslint-plugin-next
To enable svelte support, you need to explicitly turn it on:
import { vinicuncaESLint } from '@vinicunca/eslint-config';
export default vinicuncaESLint({
svelte: true,
});
Running pnpx eslint should prompt you to install the required dependencies, otherwise, you can install them manually:
pnpm add -D eslint-plugin-svelte
npm install -D eslint-plugin-svelte
bun add -d eslint-plugin-svelte
To enable astro support, you need to explicitly turn it on:
import { vinicuncaESLint } from '@vinicunca/eslint-config';
export default vinicuncaESLint({
astro: true,
});
Running pnpx eslint should prompt you to install the required dependencies, otherwise, you can install them manually:
pnpm add -D eslint-plugin-astro
npm install -D eslint-plugin-astro
bun add -d eslint-plugin-astro
To enable Solid support, you need to explicitly turn it on:
import { vinicuncaESLint } from '@vinicunca/eslint-config';
export default vinicuncaESLint({
solid: true,
});
Running pnpx eslint should prompt you to install the required dependencies, otherwise, you can install them manually:
pnpm add -D eslint-plugin-solid
npm install -D eslint-plugin-solid
bun add -d eslint-plugin-solid
To enable UnoCSS support, you need to explicitly turn it on:
import { vinicuncaESLint } from '@vinicunca/eslint-config';
export default vinicuncaESLint({
unocss: true,
});
Running pnpx eslint should prompt you to install the required dependencies, otherwise, you can install them manually:
pnpm add -D @unocss/eslint-plugin
npm install -D @unocss/eslint-plugin
bun add -d @unocss/eslint-plugin
This config also provides some optional plugins/rules for extended usage.
commandPowered 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/interfaceYou 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.
You can optionally enable the type aware rules by passing the options object to the typescript config:
import { vinicuncaESLint } from '@vinicunca/eslint-config';
export default vinicuncaESLint({
typescript: {
tsconfigPath: 'tsconfig.json',
},
});
Auto-fixing for the following rules are disabled when ESLint is running in a code editor:
They are no longer disabled, but made non-fixable using this helper.
This is to prevent unused imports from getting removed by the editor 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:
import { vinicuncaESLint } from '@vinicunca/eslint-config';
export default vinicuncaESLint({
isInEditor: false
});
If you want to apply lint and auto-fix before every commit, you can add the following to your package.json:
{
"simple-git-hooks": {
"pre-commit": "pnpm lint-staged"
},
"lint-staged": {
"*": "eslint --fix"
}
}
and then
pnpm add -D lint-staged simple-git-hooks
npm install -D lint-staged simple-git-hooks
bun add -d lint-staged simple-git-hooks
// to active the hooks
pnpx simple-git-hooks
Antfu built a visual tool to help you view what rules are enabled in your project and apply them to what files, @eslint/config-inspector
Go to your project root that contains eslint.config.js and run:
pnpx @eslint/config-inspector