进阶篇:前端代码规范工具链

多人协作的项目中,保持编码风格统一至关重要,一致的代码可以降低阅读、维护成本。

只依靠文档约定、开发者自觉,很难真正落地代码规范。工程化环境下,可以借助工具链自动完成代码检查、格式化,保障提交到代码仓库的代码质量。

ESLint

ESLint 是开源 JS 静态代码检查工具,2013 年由 Nicholas C. Zakas 创建。它对代码做静态分析,在不运行代码的前提下发现潜在问题;所有规则均可插拔,支持自定义规则与插件。

核心目标:发现代码错误、规范编码质量,兼顾部分代码风格校验,基于 Node.js 运行。

npm install eslint -D
eslint --init

配置文件

支持多种格式配置文件,优先级从高到低:

  • .eslintrc.js
  • .eslintrc.yaml.eslintrc.yml
  • .eslintrc.json
  • package.jsoneslintConfig 字段

查找逻辑:默认会向上遍历父目录;配置中设置 "root": true,停止向上查找,限定仅本项目生效。

配置优先级(由高到低):

  • 行内注释配置:/*eslint-disable*//*global*/ 等;
  • 命令行参数:--rule--env-c 指定配置文件;
  • 项目目录下的 .eslintrc.*,向上查找直到遇到 "root": true 为止;- 用户全局配置 ~/.eslintrc(不推荐项目使用)。

常用命令行

eslint --fix '{src,packages}/**/*.{js,vue,ts}'

eslint --ext .js -c ./my-eslint.js --rulesdir ./my-rules/ --ignore-path ./.eslintignore --quiet -o ./report.html -f compact --fix ./lib

参数说明:

  • --ext:指定识别的文件后缀;默认仅识别 .js
  • -c--config:指定外部配置文件;
  • --rulesdir:加载自定义规则目录;
  • --ignore-path:指定忽略文件,替代 .eslintignore
  • --quiet:只输出 error,屏蔽 warning;
  • -o--output-file:输出报告到文件;
  • -f--format:输出格式,默认 stylish;- --fix:自动修复规则支持的问题,无法修复的依旧输出报错。

配置字段详解

module.exports = {
    root: true,
    parser: "vue-eslint-parser",
    parserOptions: {
        parser: 'babel-eslint'
    },
    env: {
        node: true,
        browser: true
    },
    globals: {},
    plugins: [],
    extends: ['plugin:vue/recommended', 'eslint:recommended'],
    rules: {
        "no-unused-vars": 0,
        "quotes": ["error", "double"],
        "vue/max-attributes-per-line": 2
    }
}
  • roottrue 停止向上递归查找配置,限定为项目根配置。
  • parser:语法解析器;默认 Espree;Vue 使用 vue-eslint-parser;TS 使用 @typescript-eslint/parser
  • parserOptions:解析器配置;ecmaVersion 指定 ES 版本,sourceType 区分 scriptmoduleecmaFeatures 开启 JSX 等特性。
  • env:预设全局变量环境,browsernodees6commonjs。- globals:手动声明全局变量,writable 允许修改,readonly 只读。
  • plugins:第三方插件包,可省略 eslint-plugin- 前缀。
  • extends:继承配置,支持 npm 包、本地文件、插件内置 config;数组后面项覆盖前面项。
  • rules:规则配置;支持 off(0) 关闭、warn(1) 警告、error(2) 报错退出;数组格式可携带规则子参数。- overrides:针对特定文件集合覆盖规则,优先级高于顶层配置。
  • settings:插件之间共享配置信息。
  • processor:处理器,提取非 JS 文件内 JS 片段做校验(如 markdown)。

eslint-config-*eslint-plugin-*eslint-config-* 是一套完整可继承的规则集合,在 extends 中引入;eslint-plugin-* 提供新规则,仅引入插件不会开启规则,需要手动在 rules 中开启,或继承插件提供的 config。

忽略校验

// eslint-disable-next-line
alert('foo');

alert('foo'); // eslint-disable-line

/* eslint-disable no-alert, no-console */
alert('test')
console.log('demo')
/* eslint-enable no-alert, no-console */

.eslintignore 文件,语法同 .gitignore,用于过滤不需要校验的文件:

node_modules
/dist
.DS_Store
.env.local
.env.*.local

备注:ESLint 默认自动忽略 node_modulesbower_components。也可在 package.json 使用 eslintIgnore 字段。

自定义规则

两种实现方案:

  • 封装为 npm 插件 eslint-plugin-xxx
  • 本地规则目录,命令行通过 --rulesdir 加载。

简单本地规则示例(禁止标识符包含 hello):

// rules/lib/no-hello-in-identifier.js
module.exports = {
    meta: {
        type: "suggestion",
        messages: {
            invalidName: "避免标识符出现 'hello' "
        }
    },
    create(context) {
        return {
            Identifier(node) {
                if (node.name.toLowerCase().includes('hello')) {
                    context.report({ node, messageId: 'invalidName' })
                }
            }
        }
    }
}

配置启用规则:

// .eslintrc.js
module.exports = {
    rules: {
        "no-hello-in-identifier": 1
    }
}

运行:

eslint --rulesdir ./rules/lib --config .eslintrc.js demo.js

集成方式

  • 编辑器:VS Code、Sublime、Atom 等提供插件,保存实时提示;
  • 构建工具:Webpack、Rollup、Gulp;
  • Git Hooks:提交前校验代码。

​```js // webpack.config.js module.exports = { module: { rules: [ { test: /.(js|vue)$/, loader: 'eslint-loader', enforce: "pre", include: [resolve('src'), resolve('packages')], options: { formatter: require('eslint-friendly-formatter'), fix: true } } ] } }


## Stylelint

Stylelint 对标 ESLint,用于 CSS 系代码静态检查,捕获样式错误,统一样式书写规范。

```bash
npm install stylelint stylelint-config-standard -D

配置文件

加载优先级(从高到低):

  • stylelint.config.js
  • .stylelintrc.yml
  • .stylelintrc.yaml
  • .stylelintrc.json
  • .stylelintrc
  • package.jsonstylelint 字段

查找规则:从被处理文件所在目录向上递归查找配置文件,找到第一个有效配置文件就停止向上查找。

// stylelint.config.js
module.exports = {
    plugins: [],
    extends: ["stylelint-config-standard"],
    rules: {
        "color-no-invalid-hex": true
    }
}

运行方式

  • 命令行stylelint src/**/*.css --fix
  • Node.js APIstylelint.lint(options),用于 JS 程序调用;
  • PostCSS 插件:集成到 PostCSS 处理流水线;

配置字段详解

  • extends:继承配置,数组后面项覆盖前面项;支持 npm 包、本地文件路径。
  • plugins:第三方插件,提供额外规则。
  • rules:规则配置,null 关闭规则;支持 [主配置, {severity:"warning" | "error", message:"自定义提示"}]
  • processors:处理器,提取非 CSS 文件中的样式代码做校验,不支持自动修复。
  • ignoreFiles:glob 忽略文件,仅根配置生效,会覆盖默认忽略 node_modules;大量文件忽略优先使用 .stylelintignore
  • defaultSeverity:全局默认报错等级 warningerror

    忽略校验

    ```css / stylelint-disable / a {} / stylelint-enable /

demo { / stylelint-disable-line /

color: red !important; /* stylelint-disable-line declaration-no-important */

}

demo {

/* stylelint-disable-next-line declaration-no-important */
color: red !important;

}


`.stylelintignore`,语法遵循 `.gitignore`,相对 `process.cwd()` 解析。CLI 参数 `--ignore-path` 可以指定忽略文件路径。

### 配套生态

编辑器插件、webpack-plugin、gulp-stylelint、git pre-commit 钩子。

## Prettier(代码格式化工具)
Prettier 专注代码格式化,不做代码质量检查。输入代码,直接按照统一规则重写输出,消除团队关于代码风格的无休止讨论。

**核心功能**:只管格式(换行、引号、缩进、逗号、括号位置),**不捕获业务逻辑错误**。

**Linter 两类规则**:格式类规则(缩进、引号、逗号)交给 Prettier,关闭 linter 的同类规则,避免冲突;代码质量类规则(未使用变量、错误模式)由 linter 负责。

```bash
npm install prettier -D

配置文件

配置文件优先级(从高到低):

  • prettier.config.js.prettierrc.js
  • .prettierrc.json.prettierrc.yml.prettierrc.yaml.prettierrc.json5- .prettierrc
  • package.jsonprettier 字段

常用命令行

# 输出格式化结果到控制台
prettier ./src/index.js

# 直接重写文件
prettier --write ./src/index.js

# 检查文件是否已经格式化,CI 流水线使用
prettier --check ./src/**/*.js

# 列出所有需要修改的文件
prettier --list-different ./src/**/*.js

关键参数:

  • --write-w:改写源文件;
  • --check-c:仅校验,不修改;适合 CI;
  • --ignore-path:指定忽略文件,默认读取 .prettierignore

    配置字段详解

    // prettier.config.js
    module.exports = {
      printWidth: 80,
      tabWidth: 2,
      useTabs: false,
      semi: true,
      singleQuote: false,
      quoteProps: "as-needed",
      trailingComma: "es5",
      bracketSpacing: true,
      bracketSameLine: false,
      arrowParens: "always",
      endOfLine: "lf"
    }
    
  • printWidth:期望每行最大字符,不是强制硬限制;超长字符串不会强制截断。

  • tabWidth:缩进空格数。
  • useTabs:是否使用 tab 缩进。
  • semi:语句末尾是否加分号。
  • singleQuote:是否使用单引号;JSX 使用 jsxSingleQuote
  • trailingComma:尾随逗号策略 es5noneall。- bracketSpacing:对象字面量括号内部是否保留空格。
  • bracketSameLine:JSX 闭合 > 是否放在同一行。
  • arrowParens:箭头函数单参数是否保留括号 alwaysavoid
  • endOfLine:换行符 lfcrlfcrauto

    忽略格式化

    // prettier-ignore
    const longVar = 123;
    

创建 .prettierignore 批量忽略文件,语法类似 gitignore。

集成方式

  • 在命令行使用 prettier 命令;
  • Node 应用 Prettier 提供的 API;* 编辑器集成:VS Code 安装 Prettier 插件,开启保存自动格式化。

EditorConfig

解决不同编辑器、IDE 之间基础编码配置不一致。

只处理最基础:缩进、换行符、字符编码、行尾空格。

WebStorm、IDEA 原生支持;VS Code、Sublime 需要安装对应插件。

.editorconfig

root = true

[*]
charset = utf-8
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true

[*.{js,ts,jsx,tsx}]
indent_style = space
indent_size = 2

[*.py]
indent_style = space
indent_size = 4

核心属性:

  • root = true:停止向上目录查找配置。
  • indent_stylespacetab,缩进模式。- indent_size:缩进宽度。
  • end_of_linelfcrlfcr,换行符类型。- charset:文件编码。
  • trim_trailing_whitespace:删除行末尾空白字符。
  • insert_final_newline:文件末尾保留换行。

注意:Prettier 会自动读取 .editorconfig 作为配置兜底,Prettier 自身配置优先级高于 EditorConfig。

冲突解决方案:ESLint、Stylelint、Prettier、EditorConfig

工具各司其职,但部分配置项重叠,会出现校验冲突。

三种处理策略:

  • 专事专办(推荐)

    • EditorConfig:只负责编辑器底层基础配置(缩进、换行、编码)。

    • Prettier:全权接管代码格式化(引号、分号、括号、换行)。

    • ESLint、Stylelint:关闭所有格式化类规则,只保留代码质量、业务逻辑校验规则

      // .eslintrc.js
      module.exports = {
          plugins: ["prettier"],
          extends: [
              "eslint:recommended",
              "plugin:prettier/recommended"
          ],
          rules: {
              "prettier/prettier": "error"
          }
      }
      

      备注eslint-config-prettier 关闭 ESLint 中和 Prettier 冲突的格式类规则;eslint-plugin-prettier 把 Prettier 作为一条 ESLint 规则运行。

  • 配置保持一致:所有工具的重叠配置(缩进、引号、换行)手动设置完全一样。

  • 优先级约定:Prettier 配置 > EditorConfig;Linter 规则受 extends 继承顺序影响,后面继承项覆盖前面。

Git 提交阶段校验:husky + lint-staged

开发者执行 git commit 时,自动对暂存区变更文件执行 lint、格式化;修复失败直接阻断提交,保证入库代码质量。

Git Hook

Git 能够在特定动作执行前后触发自定义脚本,分为客户端钩子、服务端钩子。

  • 客户端钩子:在本地执行,如提交、合并操作触发;存放于项目 .git/hooks 目录。
  • 服务端钩子:在 Git 服务端执行,处理推送等远程操作。

原生 Git 自带 .sample 结尾的钩子示例文件,直接修改 .git/hooks 内文件有缺陷:

  • .git 目录不会被提交到仓库,团队其他成员拉取代码不会拿到自定义钩子脚本。
  • 原生方式需要手动重命名、维护脚本,协作项目维护成本高。

备注:husky 工具就是用来解决该痛点,把 Git 钩子脚本托管到项目目录,可随项目版本管理,团队所有成员安装依赖后自动生效。

客户端常用钩子:

  • pre-commit:执行 git commit 之前运行。可以做代码检查、格式化。脚本返回非零退出码,直接终止本次提交;可以使用 git commit --no-verify 绕过。
  • prepare-commit-msg:提交信息编辑器启动前执行。
  • commit-msg:校验提交信息内容,非零退出码终止提交。
  • post-commit:提交完成之后执行,无法阻断提交。

服务端常用钩子:

  • pre-receive:接收客户端推送前执行,可拒绝全部推送。
  • update:每一个分支更新时执行,可以拒绝单条分支更新。
  • post-receive:推送全部完成后执行,用于通知、CI 触发。

    husky@6+ 工作原理

  • Git 2.9 版本新增配置项 core.hooksPath,可以自定义 Git 钩子目录,不再使用默认的 .git/hooks
  • husky 通过 husky install 命令,修改项目的 core.hooksPath,指向项目根目录下的 .husky 文件夹。
  • 所有自定义钩子脚本统一放在 .husky,该目录可以提交到 Git 仓库,团队成员拉取代码,执行 npm install 后钩子即可生效。
  • 使用 husky add 命令新增钩子脚本,不需要手动写 shell。

lint-staged

直接全局执行 ESLint、Stylelint 会扫描项目全部文件,速度慢。 lint-staged 只会获取 git 暂存区(git add)的文件列表,只对变更文件执行校验与格式化,大幅提升执行速度。处理完成后会把修复后的文件重新加入暂存区。

注意:lint-staged 本身不会阻断提交,依靠内部执行命令的进程退出码;如果命令返回非 0,整个任务失败,触发 pre-commit 钩子终止 commit。

实操步骤

安装依赖:

npm install husky lint-staged -D

配置 prepare 脚本,自动初始化 husky:在 package.json 添加 prepare 脚本。prepare 是 npm 生命周期钩子,执行 npm install 的时候自动运行。

如果是本地初始化新项目,手动执行一次 npm run prepare,生成 .husky 目录。

{
    "scripts": {
        "prepare": "husky install"
    }
}

创建 pre-commit 钩子:执行 husky add 命令,生成 .husky/pre-commit,钩子内部执行 lint-staged

npx husky add .husky/pre-commit "npx lint-staged"

配置 lint-staged,支持多种配置方式:

  • package.jsonlint-staged 字段
  • .lintstagedrc
  • lint-staged.config.js package.json 配置:
{
    "lint-staged": {
        "{src,packages}/**/*.{js,vue,ts}": [
            "eslint --fix",
            "prettier --write",
            "git add"
        ],
        "{src,packages}/**/*.{css,scss,vue}": [
            "stylelint --fix",
            "git add"
        ]
    }
}

参考链接

ESLint 官方文档

stylelint 官方文档

Prettier 中文网

EditorConfig 官方文档

husky

© lizhao all right reserved,powered by Gitbook文件修订时间: 2026-08-22 15:00:19

results matching ""

    No results matching ""