5 min read
My Personal Eslint Setup

Setup from antfu/eslint-config

  1. Install @antfu/eslint-config
pnpm i -D @antfu/eslint-config
  1. Manually set up eslint.config.mjs under project root
import antfu from "@antfu/eslint-config";

export default antfu(
  {
    type: "app",
    react: true,
    typescript: true,
    formatters: true,
    stylistic: {
      indent: 2,
      semi: true,
      quotes: "double",
    },
  },
  {
    rules: {
      "ts/no-redeclare": "off",
      "ts/consistent-type-definitions": ["error", "type"],
      "no-console": ["warn"],
      "antfu/no-top-level-await": ["off"],
      "node/prefer-global/process": ["off"],
      "node/no-process-env": ["error"],
      "perfectionist/sort-imports": [
        "error",
        {
          tsconfigRootDir: ".",
        },
      ],
      "unicorn/filename-case": [
        "error",
        {
          case: "kebabCase",
          ignore: ["README.md"],
        },
      ],
    },
  },
);
  1. Add lint scripts for package.json
{
  "scripts": {
    "lint": "eslint .",
    "lint:fix": "eslint . --fix"
  }
}
  1. Install required eslint config plugins
pnpm lint

VS Code settings for eslint

  1. Enable lint auto fix on save on IDE (VS Code)

Add the following settings to .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"
  },

  // Silent the stylistic rules in you IDE, but still auto fix them
  "eslint.rules.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 }
  ],

  // 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"
  ]
}
  1. Stage the .vscode/settings.json in order to commit and push to remote

Normally, the file under .vscode will be ignored inside .gitignore, you can run the following cmd to force stage it:

git add .vscode/settings.json -f

Then, you will find it has been staged!🎉

Pre-commit hooks with Husky

Enable the lint before each commit happens

  1. Install package
pnpm i -D husky
  1. Husky init

The init command simplifies setting up husky in a project. It creates a pre-commit script in .husky/ and updates the prepare script in package.json

pnpm exec husky init
  1. Update .husky/pre-commit

For now, just use script pnpm lint to enable lint before each commit:

pnpm lint

Test it out, try to make some lint errors and commit it, you should see some lint errors!🎉

In some cases, you want to skip the pre-commit hooks(which means disable lint check pre-commit):

git commit -m "..." -n # Skips Git hooks

However, each time we commit, the lint will check the whole codebase, which is kind of dump and will slow the process down…

Optimization: Set up lint-staged

Instead to check the whole codebase, we use lint-staged to only run the lint for changed files.

  1. Install
pnpm i -D lint-staged
  1. Add the lint-staged command under package.json
{
  "lint-staged": {
    "*": "pnpm lint"
  }
}
  1. Stage some changes and run the following command to test it out if the lint only runs for these staged changes:
pnpm exec lint-staged

Lint should only works for these staged files!🎉

  1. Update .husky/pre-commit

Remove pnpm lint script inside and update, so that the lint-staged cmd will be executed before each commit:

pnpm exec lint-staged

Test it out, make some changes and try to commit, you will be noticed how many files have been checked by eslint and if there are any lint errors or not.

Optional: Github actions for eslint check when making PR

Enable lint check for each PR, this is optional but recommended personally.

  1. Write workflows for lint

Create .github/workflows/lint.yaml file under project root, paste following:

name: Lint
on:
  pull_request:
    branches:
      - master
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Install pnpm
        uses: pnpm/action-setup@v4
        with:
          version: 10
      - name: Use Node.js
        uses: actions/setup-node@v4
        with:
          node-version: 22.x
      - run: pnpm i
      - run: pnpm lint

This workflow will be triggered each time the PR is made from XXX to master branch.

Test it out, checkout a new branch, make a few changes and commit it, make a PR to master branch, you should see the action is running!🎉