进阶篇:前端代码规范工具链
多人协作的项目中,保持编码风格统一至关重要,一致的代码可以降低阅读、维护成本。
只依靠文档约定、开发者自觉,很难真正落地代码规范。工程化环境下,可以借助工具链自动完成代码检查、格式化,保障提交到代码仓库的代码质量。
ESLint
ESLint 是开源 JS 静态代码检查工具,2013 年由 Nicholas C. Zakas 创建。它对代码做静态分析,在不运行代码的前提下发现潜在问题;所有规则均可插拔,支持自定义规则与插件。
核心目标:发现代码错误、规范编码质量,兼顾部分代码风格校验,基于 Node.js 运行。
npm install eslint -D
eslint --init
配置文件
支持多种格式配置文件,优先级从高到低:
.eslintrc.js.eslintrc.yaml、.eslintrc.yml.eslintrc.jsonpackage.json的eslintConfig字段
查找逻辑:默认会向上遍历父目录;配置中设置 "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
}
}
root:true停止向上递归查找配置,限定为项目根配置。parser:语法解析器;默认 Espree;Vue 使用vue-eslint-parser;TS 使用@typescript-eslint/parser。parserOptions:解析器配置;ecmaVersion指定 ES 版本,sourceType区分script、module,ecmaFeatures开启 JSX 等特性。env:预设全局变量环境,browser、node、es6、commonjs。-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_modules、bower_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.stylelintrcpackage.json的stylelint字段
查找规则:从被处理文件所在目录向上递归查找配置文件,找到第一个有效配置文件就停止向上查找。
// stylelint.config.js
module.exports = {
plugins: [],
extends: ["stylelint-config-standard"],
rules: {
"color-no-invalid-hex": true
}
}
运行方式
- 命令行:
stylelint src/**/*.css --fix。 - Node.js API:
stylelint.lint(options),用于 JS 程序调用; - PostCSS 插件:集成到 PostCSS 处理流水线;
配置字段详解
extends:继承配置,数组后面项覆盖前面项;支持 npm 包、本地文件路径。plugins:第三方插件,提供额外规则。rules:规则配置,null关闭规则;支持[主配置, {severity:"warning" | "error", message:"自定义提示"}]。processors:处理器,提取非 CSS 文件中的样式代码做校验,不支持自动修复。ignoreFiles:glob 忽略文件,仅根配置生效,会覆盖默认忽略node_modules;大量文件忽略优先使用.stylelintignore。defaultSeverity:全局默认报错等级warning、error。忽略校验
```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-.prettierrcpackage.json的prettier字段
常用命令行
# 输出格式化结果到控制台
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:尾随逗号策略es5、none、all。-bracketSpacing:对象字面量括号内部是否保留空格。bracketSameLine:JSX 闭合>是否放在同一行。arrowParens:箭头函数单参数是否保留括号always、avoid。endOfLine:换行符lf、crlf、cr、auto。忽略格式化
// 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_style:space、tab,缩进模式。-indent_size:缩进宽度。end_of_line:lf、crlf、cr,换行符类型。-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.json的lint-staged字段.lintstagedrclint-staged.config.jspackage.json配置:
{
"lint-staged": {
"{src,packages}/**/*.{js,vue,ts}": [
"eslint --fix",
"prettier --write",
"git add"
],
"{src,packages}/**/*.{css,scss,vue}": [
"stylelint --fix",
"git add"
]
}
}