一些 linter & formatter 配置最佳实践

花了好长时间调研的一些最佳实践,感觉基本上应该是够用了(?

这里的纯 eslint 部分是参考了 @antfu/eslint-config 的配置,rules 里面塞了一些格式化规则。

建议如果用的话,最好也加一下 .vscode/settings.json,能够确保正确开启这些扩展,以及保证不会被其他的格式化扩展影响修复行为。

纯 TypeScript 的 Node.js 项目

eslint

安装依赖

bash 复制代码
pnpm add -D eslint @eslint/js @typescript-eslint/eslint-plugin @typescript-eslint/parser typescript-eslint eslint-plugin-n eslint-plugin-unicorn eslint-plugin-simple-import-sort eslint-plugin-jsonc jsonc-eslint-parser eslint-plugin-yml yaml-eslint-parser eslint-plugin-markdown

eslint.config.mjs

javascript 复制代码
// @ts-check

import eslint from '@eslint/js'
import markdown from '@eslint/markdown'
import eslintPluginJsonc from 'eslint-plugin-jsonc'
import pluginN from 'eslint-plugin-n'
import simpleImportSort from 'eslint-plugin-simple-import-sort'
import eslintPluginUnicorn from 'eslint-plugin-unicorn'
import eslintPluginYml from 'eslint-plugin-yml'
import tseslint from 'typescript-eslint'

export default tseslint.config(
  eslint.configs.recommended,
  markdown.configs.processor,
  tseslint.configs.strict,
  tseslint.configs.stylistic,
  eslintPluginUnicorn.configs.recommended,
  pluginN.configs['flat/recommended-module'],
  ...eslintPluginJsonc.configs['flat/recommended-with-jsonc'],
  ...eslintPluginYml.configs['flat/recommended'],
  {
    languageOptions: {
      sourceType: 'module',
    },
    plugins: {
      'simple-import-sort': simpleImportSort,
    },
    rules: {
      /* plugin rules */
      'simple-import-sort/imports': 'error',
      'simple-import-sort/exports': 'error',

      /* stylistic rules */
      'quotes': ['error', 'single', { avoidEscape: true }],
      'indent': ['error', 2, { SwitchCase: 1 }],
      'key-spacing': ['error', { beforeColon: false, afterColon: true }],
      'object-curly-spacing': ['error', 'always'],
      'array-bracket-spacing': ['error', 'never'],
      'computed-property-spacing': ['error', 'never'],
      'array-element-newline': ['error', 'consistent'],
      'comma-spacing': ['error', { before: false, after: true }],
      'arrow-parens': ['error', 'always'],
      'comma-dangle': ['error', 'always-multiline'],
      'space-before-function-paren': [
        'error',
        {
          anonymous: 'always',
          named: 'never',
          asyncArrow: 'always',
        },
      ],
      'padding-line-between-statements': [
        'error',
        { blankLine: 'always', prev: 'multiline-block-like', next: '*' },
        { blankLine: 'always', prev: '*', next: 'return' },
        { blankLine: 'always', prev: 'const', next: 'function' },
        { blankLine: 'always', prev: 'let', next: 'function' },
        { blankLine: 'any', prev: 'const', next: 'const' },
        { blankLine: 'any', prev: 'let', next: 'let' },
      ],
      'no-multi-spaces': 'error',
      'no-multiple-empty-lines': ['error', { max: 1, maxEOF: 0 }],
      'dot-location': ['error', 'property'],
      'no-empty': ['error', { allowEmptyCatch: true }],
    },
  },
)

.vscode/settings.json

json 复制代码
{
  "prettier.enable": false,
  "biome.enabled": false,
  "editor.formatOnSave": false,
  "editor.codeActionsOnSave": {
    "source.fixAll.eslint": "explicit",
    "source.organizeImports": "never"
  },
  "[typescript]": {
    "editor.defaultFormatter": null
  },
  "[javascript]": {
    "editor.defaultFormatter": null
  },
  "eslint.rules.customizations": [
    { "rule": "@stylistic/*", "severity": "off" },
    { "rule": "*-indent", "severity": "off" },
    { "rule": "*-spacing", "severity": "off" },
    { "rule": "*-spaces", "severity": "off" },
    { "rule": "*-order", "severity": "off" },
    { "rule": "*-dangle", "severity": "off" },
    { "rule": "*-newline", "severity": "off" },
    { "rule": "*-multiline", "severity": "off" },
    { "rule": "*quotes", "severity": "off" },
    { "rule": "*semi", "severity": "off" }
  ],
  "eslint.validate": [
    "javascript",
    "typescript",
    "javascriptreact",
    "typescriptreact",
    "json",
    "jsonc",
    "yaml",
    "markdown"
  ]
}

eslint + prettier

安装依赖

bash 复制代码
pnpm add -D eslint @eslint/js eslint-plugin-n eslint-plugin-unicorn @eslint/markdown eslint-plugin-jsonc eslint-plugin-yml eslint-config-prettier typescript-eslint prettier @trivago/prettier-plugin-sort-imports

eslint.config.mjs

javascript 复制代码
// @ts-check

import eslint from '@eslint/js'
import markdown from '@eslint/markdown'
import eslintConfigPrettier from 'eslint-config-prettier'
import eslintPluginJsonc from 'eslint-plugin-jsonc'
import pluginN from 'eslint-plugin-n'
import eslintPluginUnicorn from 'eslint-plugin-unicorn'
import eslintPluginYml from 'eslint-plugin-yml'
import tseslint from 'typescript-eslint'

export default tseslint.config(
  eslint.configs.recommended,
  tseslint.configs.strict,
  eslintPluginUnicorn.configs.recommended,
  pluginN.configs['flat/recommended-module'],
  markdown.configs.processor,
  ...eslintPluginJsonc.configs['flat/recommended-with-jsonc'],
  ...eslintPluginYml.configs['flat/recommended'],
  {
    rules: {
      'no-empty': ['error', { allowEmptyCatch: true }],
    },
  },
  eslintConfigPrettier,
)

prettier.config.mjs

javascript 复制代码
/** @type {import("prettier").Config} */
export default {
  plugins: ['@trivago/prettier-plugin-sort-imports'],
  singleQuote: true,
  tabWidth: 2,
  trailingComma: 'all',
  arrowParens: 'always',
  bracketSpacing: true,
  semi: false,
  importOrder: ['^node:(.*)$', '<THIRD_PARTY_MODULES>', '^@/(.*)$', '^[./]'],
  importOrderSeparation: true,
  importOrderSortSpecifiers: true,
}

.prettierignore

csharp 复制代码
# Dependencies
node_modules/

# Build output
dist/
build/

# Cache directories
.cache/

# Log files
*.log

# Environment files
.env*

# Coverage output
coverage/

# Lock files
package-lock.json
yarn.lock
pnpm-lock.yaml

.vscode/settings.json

json 复制代码
{
  "biome.enabled": false,
  "editor.defaultFormatter": "esbenp.prettier-vscode",
  "editor.formatOnSave": true,
  "editor.codeActionsOnSave": {
    "source.fixAll.eslint": "explicit",
    "source.organizeImports": "never"
  },
  "[typescript]": {
    "editor.defaultFormatter": "esbenp.prettier-vscode"
  },
  "[javascript]": {
    "editor.defaultFormatter": "esbenp.prettier-vscode"
  },
  "eslint.validate": ["javascript", "typescript", "javascriptreact", "typescriptreact"]
}

biome

安装依赖

bash 复制代码
pnpm add -D @biomejs/biome

biome.json

json 复制代码
{
  "$schema": "https://biomejs.dev/schemas/latest/schema.json",
  "organizeImports": {
    "enabled": true
  },
  "formatter": {
    "enabled": true,
    "formatWithErrors": false,
    "indentStyle": "space",
    "indentWidth": 2,
    "lineWidth": 100
  },
  "linter": {
    "enabled": true,
    "rules": {
      "recommended": true,
      "suspicious": {
        "noExplicitAny": "warn",
        "noShadowRestrictedNames": "error"
      },
      "style": {
        "noNonNullAssertion": "warn",
        "useFilenamingConvention": "error"
      },
      "correctness": {
        "noSwitchDeclarations": "error"
      }
    }
  },
  "javascript": {
    "formatter": {
      "quoteStyle": "single",
      "semicolons": "asNeeded",
      "trailingCommas": "es5",
      "quoteProperties": "asNeeded"
    }
  },
  "json": {
    "parser": {
      "allowComments": true
    },
    "formatter": {
      "enabled": true,
      "trailingCommas": "none"
    }
  }
}

.vscode/settings.json

json 复制代码
{
  // Disable Prettier & ESLint
  "prettier.enable": false,
  "editor.codeActionsOnSave": {},
  "eslint.enable": false,

  // Enable Biome plugin formatting functionality
  "editor.defaultFormatter": "biomejs.biome",

  // Formatting related settings
  "editor.formatOnSave": true,
  "editor.formatOnPaste": true,
  "editor.formatOnType": false,

  // Enable Biome formatter for specific languages
  "[javascript]": {
    "editor.defaultFormatter": "biomejs.biome"
  },
  "[javascriptreact]": {
    "editor.defaultFormatter": "biomejs.biome"
  },
  "[typescript]": {
    "editor.defaultFormatter": "biomejs.biome"
  },
  "[typescriptreact]": {
    "editor.defaultFormatter": "biomejs.biome"
  },
  "[json]": {
    "editor.defaultFormatter": "biomejs.biome"
  },
  "[jsonc]": {
    "editor.defaultFormatter": "biomejs.biome"
  }
}

纯 JavaScript 的 Node.js 项目

eslint

安装依赖

bash 复制代码
pnpm add -D eslint @eslint/js eslint-plugin-n eslint-plugin-simple-import-sort eslint-plugin-unicorn eslint-plugin-jsonc eslint-plugin-yml @eslint/markdown globals typescript-eslint

eslint.config.mjs

javascript 复制代码
// @ts-check

import eslint from '@eslint/js'
import markdown from '@eslint/markdown'
import eslintPluginJsonc from 'eslint-plugin-jsonc'
import pluginN from 'eslint-plugin-n'
import simpleImportSort from 'eslint-plugin-simple-import-sort'
import eslintPluginUnicorn from 'eslint-plugin-unicorn'
import eslintPluginYml from 'eslint-plugin-yml'
import globals from 'globals'
import tseslint from 'typescript-eslint'

export default tseslint.config(
  eslint.configs.recommended,
  markdown.configs.processor,
  pluginN.configs['flat/recommended-module'],
  eslintPluginUnicorn.configs.recommended,
  ...eslintPluginJsonc.configs['flat/recommended-with-jsonc'],
  ...eslintPluginYml.configs['flat/recommended'],
  {
    languageOptions: {
      ecmaVersion: 'latest',
      sourceType: 'module',
      globals: {
        ...globals.node,
      },
    },

    plugins: {
      'simple-import-sort': simpleImportSort,
    },

    rules: {
      'simple-import-sort/imports': 'error',
      'simple-import-sort/exports': 'error',

      'quotes': ['error', 'single', { avoidEscape: true }],
      'indent': ['error', 2, { SwitchCase: 1 }],
      'key-spacing': ['error', { beforeColon: false, afterColon: true }],
      'object-curly-spacing': ['error', 'always'],
      'array-bracket-spacing': ['error', 'never'],
      'computed-property-spacing': ['error', 'never'],
      'array-element-newline': ['error', 'consistent'],
      'comma-spacing': ['error', { before: false, after: true }],
      'arrow-parens': ['error', 'always'],
      'comma-dangle': ['error', 'always-multiline'],
      'space-before-function-paren': [
        'error',
        {
          anonymous: 'always',
          named: 'never',
          asyncArrow: 'always',
        },
      ],
      'padding-line-between-statements': [
        'error',
        { blankLine: 'always', prev: 'multiline-block-like', next: '*' },
        { blankLine: 'always', prev: '*', next: 'return' },
        { blankLine: 'always', prev: 'const', next: 'function' },
        { blankLine: 'always', prev: 'let', next: 'function' },
        { blankLine: 'any', prev: 'const', next: 'const' },
        { blankLine: 'any', prev: 'let', next: 'let' },
      ],
      'no-multi-spaces': 'error',
      'no-multiple-empty-lines': ['error', { max: 1, maxEOF: 0 }],
      'dot-location': ['error', 'property'],
      'no-empty': ['error', { allowEmptyCatch: true }],
    },
  }
)

.vscode/settings.json

json 复制代码
{
  "prettier.enable": false,
  "biome.enabled": false,
  "editor.formatOnSave": false,
  "editor.codeActionsOnSave": {
    "source.fixAll.eslint": "explicit",
    "source.organizeImports": "never"
  },
  "[typescript]": {
    "editor.defaultFormatter": null
  },
  "[javascript]": {
    "editor.defaultFormatter": null
  },
  "eslint.rules.customizations": [
    { "rule": "@stylistic/*", "severity": "off" },
    { "rule": "*-indent", "severity": "off" },
    { "rule": "*-spacing", "severity": "off" },
    { "rule": "*-spaces", "severity": "off" },
    { "rule": "*-order", "severity": "off" },
    { "rule": "*-dangle", "severity": "off" },
    { "rule": "*-newline", "severity": "off" },
    { "rule": "*-multiline", "severity": "off" },
    { "rule": "*quotes", "severity": "off" },
    { "rule": "*semi", "severity": "off" }
  ],
  "eslint.validate": [
    "javascript",
    "typescript",
    "javascriptreact",
    "typescriptreact",
    "json",
    "jsonc",
    "yaml",
    "markdown"
  ]
}

eslint + prettier

安装依赖

bash 复制代码
pnpm add -D eslint @eslint/js eslint-plugin-n eslint-plugin-unicorn @eslint/markdown eslint-plugin-jsonc eslint-plugin-yml eslint-config-prettier globals prettier @trivago/prettier-plugin-sort-imports

eslint.config.mjs

javascript 复制代码
// @ts-check
import eslint from '@eslint/js'
import markdown from '@eslint/markdown'
import eslintConfigPrettier from 'eslint-config-prettier'
import eslintPluginJsonc from 'eslint-plugin-jsonc'
import pluginN from 'eslint-plugin-n'
import eslintPluginUnicorn from 'eslint-plugin-unicorn'
import eslintPluginYml from 'eslint-plugin-yml'
import globals from 'globals'

export default [
  eslint.configs.recommended,
  pluginN.configs['flat/recommended-module'],
  eslintPluginUnicorn.configs.recommended,
  markdown.configs.processor,
  ...eslintPluginJsonc.configs['flat/recommended-with-jsonc'],
  ...eslintPluginYml.configs['flat/recommended'],
  {
    languageOptions: {
      ecmaVersion: 'latest',
      sourceType: 'module',
      globals: {
        ...globals.node,
      },
    },
    rules: {
      'no-empty': ['error', { allowEmptyCatch: true }],
    },
  },
  eslintConfigPrettier,
]

prettier.config.mjs

javascript 复制代码
/** @type {import("prettier").Config} */
export default {
  plugins: ['@trivago/prettier-plugin-sort-imports'],
  singleQuote: true,
  tabWidth: 2,
  trailingComma: 'all',
  arrowParens: 'always',
  bracketSpacing: true,
  semi: false,
  importOrder: ['^node:(.*)$', '<THIRD_PARTY_MODULES>', '^@/(.*)$', '^[./]'],
  importOrderSeparation: true,
  importOrderSortSpecifiers: true,
}

.prettierignore

csharp 复制代码
# Dependencies
node_modules/

# Build output
dist/
build/

# Cache directories
.cache/

# Log files
*.log

# Environment files
.env*

# Coverage output
coverage/

# Lock files
package-lock.json
yarn.lock
pnpm-lock.yaml

.vscode/settings.json

json 复制代码
{
  "biome.enabled": false,
  "editor.defaultFormatter": "esbenp.prettier-vscode",
  "editor.formatOnSave": true,
  "editor.codeActionsOnSave": {
    "source.fixAll.eslint": "explicit",
    "source.organizeImports": "never"
  },
  "[typescript]": {
    "editor.defaultFormatter": "esbenp.prettier-vscode"
  },
  "[javascript]": {
    "editor.defaultFormatter": "esbenp.prettier-vscode"
  },
  "eslint.validate": ["javascript", "typescript", "javascriptreact", "typescriptreact"]
}

biome

安装依赖

bash 复制代码
pnpm add -D @biomejs/biome

biome.json

json 复制代码
{
  "$schema": "https://biomejs.dev/schemas/latest/schema.json",
  "organizeImports": {
    "enabled": true
  },
  "formatter": {
    "enabled": true,
    "formatWithErrors": false,
    "indentStyle": "space",
    "indentWidth": 2,
    "lineWidth": 100
  },
  "linter": {
    "enabled": true,
    "rules": {
      "recommended": true,
      "suspicious": {
        "noShadowRestrictedNames": "error"
      },
      "style": {
        "useFilenamingConvention": "error"
      },
      "correctness": {
        "noSwitchDeclarations": "error"
      },
      "nursery": {
        "useValidTypeof": "error"
      }
    }
  },
  "javascript": {
    "formatter": {
      "quoteStyle": "single",
      "semicolons": "asNeeded",
      "trailingCommas": "es5",
      "quoteProperties": "asNeeded"
    }
  },
  "json": {
    "parser": {
      "allowComments": true
    },
    "formatter": {
      "enabled": true,
      "trailingCommas": "none"
    }
  }
}

.vscode/settings.json

json 复制代码
{
  // Disable Prettier & ESLint
  "prettier.enable": false,
  "editor.codeActionsOnSave": {},
  "eslint.enable": false,

  // Enable Biome plugin formatting functionality
  "editor.defaultFormatter": "biomejs.biome",

  // Formatting related settings
  "editor.formatOnSave": true,
  "editor.formatOnPaste": true,
  "editor.formatOnType": false,

  // Enable Biome formatter for specific languages
  "[javascript]": {
    "editor.defaultFormatter": "biomejs.biome"
  },
  "[javascriptreact]": {
    "editor.defaultFormatter": "biomejs.biome"
  },
  "[typescript]": {
    "editor.defaultFormatter": "biomejs.biome"
  },
  "[typescriptreact]": {
    "editor.defaultFormatter": "biomejs.biome"
  },
  "[json]": {
    "editor.defaultFormatter": "biomejs.biome"
  },
  "[jsonc]": {
    "editor.defaultFormatter": "biomejs.biome"
  }
}
相关推荐
None32116 小时前
【NestJs】基于Redlock装饰器分布式锁设计与实现
后端·node.js
时光不负努力21 小时前
编程常用模式集合
前端·javascript·typescript
时光不负努力21 小时前
ts+vue3开发规范
vue.js·typescript
Gogo112121 小时前
构建高性能 Node.js 集中式日志体系 (下篇):Pino + PM2 + OpenSearch 代码落地实战
node.js
小岛前端21 小时前
Node.js 宣布重大调整,运行十年的规则要改了!
前端·node.js
时光不负努力21 小时前
typescript常用的dom 元素类型
前端·typescript
时光不负努力21 小时前
TS 常用工具类型
前端·javascript·typescript
前端付豪1 天前
Nest 项目小实践之前端注册登陆
前端·node.js·nestjs
codingWhat2 天前
整理「祖传」代码,就是在开发脚手架?
前端·javascript·node.js
Wect2 天前
LeetCode 210. 课程表 II 题解:Kahn算法+DFS 双解法精讲
前端·算法·typescript