前端开发··2 阅读·预计 14 分钟

JavaScript 工程化规范落地实战:从 Prettier/ESLint 到 pre-commit 的完整防线

为什么规范需要「落地」而不仅仅是「写一份文档」

团队规范最常见的两种结局:① 写在 Wiki 里无人问津;② 写在 Wiki 里每个人都用「我有自己的习惯」为由无视。

规范只有自动化、强制化,才叫落地。本文聚焦三类自动化:

  • 格式 — Prettier 统一,零争议
  • 质量 — ESLint 拦截,提前发现 Bug
  • 门禁 — pre-commit 强制执行,不让坏代码进仓库

1. ESLint + Prettier:分工明确,互不打架

反例:配置冲突

// .eslintrc.json — 新手常犯:格式化规则和逻辑规则混在一起
{
  "rules": {
    "indent": ["error", 2],
    "quotes": ["error", "single"],
    "no-var": "error"
  }
}

这样配导致两个问题:

  1. indent / quotes 这类格式规则会和 Prettier 冲突
  2. CI 里 ESLint 报格式错,本地 Prettier 却认为没问题,修复 A 引入 B 的飘红

正例:职责分离

npm i -D eslint prettier eslint-config-prettier eslint-plugin-prettier
// .eslintrc.cjs — 让 Prettier 管格式,ESLint 只管逻辑质量
module.exports = {
  extends: [
    'eslint:recommended',
    'plugin:prettier/recommended' // 必须放最后,关闭 ESLint 的格式规则
  ],
  rules: {
    'no-var': 'error',                 // 不用 var
    'prefer-const': 'error',           // 能 const 不用 let
    'no-unused-vars': ['error', { argsIgnorePattern: '^_' }],
    'no-console': 'warn',              // prod 前必须清
    'require-await': 'error'           // 无 await 的 async 大概率是 bug
  }
}
// .prettierrc — 格式决策全部放在这里
{
  "semi": true,
  "singleQuote": true,
  "trailingComma": "all",
  "printWidth": 100,
  "tabWidth": 2
}

关键决策点

  • eslint-config-prettier 关闭 ESLint 中与 Prettier 冲突的所有规则
  • plugin:prettier/recommended = extends: ['prettier'] + plugins: ['prettier'] + rules: { 'prettier/prettier': 'error' } 三合一
  • 这样 Prettier 的违规会作为 ESLint 错误暴露,一条 eslint --fix 搞定全部

2. 规则分层:error vs warn 的工程化决策

// .eslintrc.cjs rules 区段 — 有意识的分层
rules: {
  // ── Layer 0: 立即阻塞提交的硬错误 ──
  'no-var': 'error',
  'no-const-assign': 'error',
  'no-duplicate-imports': 'error',
  'no-unreachable': 'error',

  // ── Layer 1: 开发期警告,CI 里提级为 error ──
  'no-console': 'warn',
  'no-debugger': 'warn',

  // ── Layer 2: 渐进迁移期的临时降级 ──
  '@typescript-eslint/no-explicit-any': 'warn', // 先 warn,存量清理后升 error
}

为什么不在本地全开 error

  • warn 级别的 no-console 允许开发时打 log,但不让过 CI
  • 存量项目引入新规范时,先 warn 再逐步升 error,避免一次性改动爆炸

CI 中的覆盖策略:

# .github/workflows/lint.yml
- run: npx eslint . --max-warnings 0

--max-warnings 0 把 warn 也视为失败,保证 CI 零容忍。


3. pre-commit 防线:husky + lint-staged 精确打击

反例:在 pre-commit 里全量 lint

// package.json — 不推荐的做法
{
  "husky": {
    "hooks": {
      "pre-commit": "npx eslint . && npx prettier --check ."
    }
  }
}

这导致改一个文件,全项目扫描十几秒以上,严重影响提交流畅度。

正例:lint-staged 只 check 暂存文件

npm i -D husky lint-staged
npx husky init
# .husky/pre-commit — Husky v9 写法
npx lint-staged
// package.json
{
  "lint-staged": {
    "*.{js,jsx,ts,tsx}": [
      "eslint --fix --max-warnings 0",
      "prettier --write"
    ],
    "*.{json,md,yaml,css}": [
      "prettier --write"
    ]
  }
}

三条铁律

  1. 只 lint staged 文件 — 改了 3 个文件就只看 3 个,耗时 < 1s
  2. 先 fix 再 checkeslint --fix 先自动修,修复失败才阻塞
  3. 按文件类型分离.json 不该跑 ESLint,.ts 必须跑

4. 团队统一:Override Report 与 .vscode 共享

规范在编辑器里实时生效比 pre-commit 更重要——不要让开发者等到提交才看到飘红。

// .vscode/settings.json — 提交到仓库,全团队共享
{
  "editor.formatOnSave": true,
  "editor.defaultFormatter": "esbenp.prettier-vscode",
  "editor.codeActionsOnSave": {
    "source.fixAll.eslint": "explicit"
  },
  "eslint.validate": ["javascript", "javascriptreact", "typescript", "typescriptreact"]
}
// .vscode/extensions.json — 强制推荐插件
{
  "recommendations": [
    "dbaeumer.vscode-eslint",
    "esbenp.prettier-vscode"
  ]
}

新人 clone 项目后 VSCode 会自动提示安装推荐的插件和 settings,零配置即可获得同样的保存自动修复体验。


5. 进阶:用 eslint-plugin-import 管 import 顺序

// .eslintrc.cjs 补充
{
  plugins: ['import'],
  rules: {
    'import/order': ['error', {
      groups: [
        'builtin',     // node:fs、node:path
        'external',    // react、lodash
        'internal',    // @/ 别名
        ['parent', 'sibling', 'index']
      ],
      'newlines-between': 'always',
      alphabetize: { order: 'asc', caseInsensitive: true }
    }],
    'import/no-cycle': 'error',
    'import/no-self-import': 'error'
  }
}

效果:

// ❌ 混乱的 import — 谁都会改着改着就乱了
import { debounce } from 'lodash';
import { Button } from '@/components/Button';
import fs from 'node:fs';
import React from 'react';

// ✅ 自动排序后
import fs from 'node:fs';

import { debounce } from 'lodash';
import React from 'react';

import { Button } from '@/components/Button';

配合 eslint --fix,import 排序全自动,review 不再为顺序浪费时间。


6. 完整落地 Checklist

阶段做了什么时间成本
初始化ESLint + Prettier + eslint-config-prettier10 min
规则分层区分 error / warn,CI 用 --max-warnings 05 min
pre-commithusky + lint-staged,只处理 staged 文件5 min
编辑器.vscode/settings.json 共享,formatOnSave3 min
import 管理eslint-plugin-import 排序 + 循环检测3 min
CI 强制GitHub Actions 跑 lint --max-warnings 05 min

总计约 30 分钟,一劳永逸。


总结:规范落地的本质

  • Prettier 管格式,ESLint 管质量 — 职责分离是避免冲突的第一原则
  • warn 是过渡,error 是目标 — 用 --max-warnings 0 在 CI 中统一提级
  • lint-staged 是效率关键 — 只查变更文件,让规范不成为开发的阻碍
  • 编辑器配置进仓库 — 让规范在敲代码时就生效,而非提交时阻击
  • CI 是最后一道防线 — 本地提交可能跳过 hook,但 CI 绕不过

规范不会让代码变好,但会让代码变好的可能性更高。

0 评论

评论区

登录 后参与评论