前言
在团队协作中,代码规范往往是一个容易引发争议却又不得不解决的问题。每个人都有自己的编码习惯,有人喜欢加分号,有人不喜欢;有人用两个空格缩进,有人用四个;有人变量命名用 camelCase,有人用 snake_case。这些差异在 Code Review 时往往演变成无休止的争论,消耗着团队的宝贵时间。
这就是为什么要建立自动化代码规范工作流——让工具做工具擅长的事,让人做人擅长的事。
为什么需要自动化代码规范?
没有规范带来的问题
// 团队成员A写的代码
function fetchData(){
let result = getData()
return result
}
// 团队成员B写的代码
function fetchData() {
const result = getData();
return result;
}
上述两段代码看起来差不多,但:
- 格式不一致(缩进、空格、分号)
- 变量命名风格不同
- Code Review 时会争论这些细节
有了自动化工具之后
// 不管我们怎么写,保存时自动变成统一格式
function fetchData() {
const result = getData()
return result
}
// 提交时自动检查,有问题就拦截
// 再也不用手动改格式了
自动化工作流的价值
传统流程:
写代码 → 手动检查 → 提交 → Code Review → 发现问题 → 修改 → 再次提交
自动化流程:
写代码 → 保存时自动格式化 → 提交时自动检查 → 提交成功
↓
发现问题自动拦截
收益:
- 减少 90% 的代码风格争论
- 提前发现 70% 的潜在错误
- Code Review 时间缩短 50%
- 新人融入时间减少 60%
工具链全景图
四大工具的分工
ESLint:代码质量检查
- 发现潜在错误(未定义变量、未使用变量)
- 强制最佳实践(使用 === 代替 ==)
- 统一代码风格(但能力有限)
Prettier:代码美容师
- 统一代码风格(空格、换行、引号)
- 专注格式化,不做质量检查
Husky:看门人
- 在 Git 操作时触发脚本
- 确保提交前代码符合规范
lint-staged:高效助手
- 只检查即将提交的文件
- 避免检查整个项目,提高效率
工作流程示意图
开发阶段
┌─────────────────┐
│ VS Code 编辑器 │
│ - 保存时格式化 │
│ - 实时错误提示 │
└────────┬────────┘
↓
Git 提交阶段
┌─────────────────┐
│ git commit │
└────────┬────────┘
↓
Husky 触发 pre-commit
┌─────────────────┐
│ 执行 lint-staged│
└────────┬────────┘
↓
lint-staged 检查暂存区
┌─────────────────┐
│ 1. 运行 ESLint │
│ 2. 运行 Prettier│
└────────┬────────┘
有问题?→ 拦截提交
↓
没问题 → 提交成功
ESLint - 代码质量守门员
什么是 ESLint?
ESLint 就像考试时的阅卷老师,专门帮我们找出代码中的"错误"和"不规范":
// 1. 未使用的变量
let unusedVar = '没人用我' // ESLint: 'unusedVar' is defined but never used
// 2. 未定义的变量
console.log(notDefined) // ESLint: 'notDefined' is not defined
// 3. 不安全的比较
if (count == 1) { // ESLint: Expected '===' and instead saw '=='
// ...
}
// 4. 重复定义
let name = '张三'
let name = '李四' // ESLint: 'name' is already defined
安装和初始化
# 安装 ESLint
npm install eslint --save-dev
# 初始化配置
npx eslint --init
# 交互式选择:
# - How would you like to use ESLint? → To check syntax and find problems
# - What type of modules does your project use? → JavaScript modules (import/export)
# - Which framework does your project use? → Vue.js
# - Does your project use TypeScript? → Yes
# - Where does your code run? → Browser
# - What format do you want your config file to be in? → JavaScript
Vue 3 + TypeScript 项目的最佳配置
// .eslintrc.js
module.exports = {
root: true,
env: {
browser: true,
es2021: true,
node: true,
'vue/setup-compiler-macros': true
},
extends: [
'eslint:recommended',
'plugin:vue/vue3-recommended', // 使用推荐规则
'plugin:@typescript-eslint/recommended',
'plugin:prettier/recommended' // 整合 Prettier
],
parser: 'vue-eslint-parser',
parserOptions: {
ecmaVersion: 'latest',
parser: '@typescript-eslint/parser',
sourceType: 'module',
extraFileExtensions: ['.vue']
},
plugins: ['vue', '@typescript-eslint'],
rules: {
// 关闭与 Prettier 冲突的规则
'vue/max-attributes-per-line': 'off',
'vue/singleline-html-element-content-newline': 'off',
'vue/html-self-closing': 'off',
// 自定义规则
'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
// Vue 3 推荐
'vue/multi-word-component-names': 'off',
'vue/no-v-model-argument': 'off',
// TypeScript
'@typescript-eslint/no-explicit-any': 'warn',
'@typescript-eslint/explicit-module-boundary-types': 'off',
'@typescript-eslint/no-unused-vars': ['error', {
argsIgnorePattern: '^_'
}]
},
globals: {
defineProps: 'readonly',
defineEmits: 'readonly',
defineExpose: 'readonly',
withDefaults: 'readonly'
}
}
自定义规则详解
// .eslintrc.js
module.exports = {
rules: {
// 规则级别:off(0) 关闭 / warn(1) 警告 / error(2) 错误
// ========== 最佳实践 ==========
'eqeqeq': ['error', 'always'], // 必须用 === 和 !==
'no-eval': 'error', // 禁止 eval
'no-implied-eval': 'error', // 禁止隐式 eval
'no-with': 'error', // 禁止 with 语句
// ========== 变量相关 ==========
'no-unused-vars': ['error', {
vars: 'all', // 检查所有变量
args: 'after-used', // 检查使用后的参数
ignoreRestSiblings: true // 忽略剩余参数
}],
'no-use-before-define': ['error', {
functions: false, // 函数可以在定义前使用
classes: true, // 类不行
variables: true // 变量也不行
}],
// ========== 代码风格 ==========
// 这些规则会被 Prettier 覆盖,但保留作为参考
'array-bracket-spacing': ['error', 'never'], // [1, 2, 3] 而不是 [ 1, 2, 3 ]
'object-curly-spacing': ['error', 'always'], // { foo: bar } 而不是 {foo: bar}
'comma-dangle': ['error', 'never'], // 不加尾逗号
'quotes': ['error', 'single'], // 用单引号
'semi': ['error', 'never'], // 不加分号
// ========== 复杂度控制 ==========
'max-depth': ['warn', 4], // 最大嵌套深度不超过4
'max-params': ['warn', 5], // 函数参数不超过5个
'max-statements': ['warn', 30], // 函数语句不超过30行
'complexity': ['warn', 10] // 圈复杂度不超过10
}
}
在 package.json 中添加脚本
{
"scripts": {
"lint": "eslint . --ext .js,.ts,.vue",
"lint:fix": "eslint . --ext .js,.ts,.vue --fix",
"lint:src": "eslint src --ext .js,.ts,.vue"
}
}
Prettier - 代码美容师
什么是 Prettier?
Prettier 是格式化工具,它只有一个任务:把代码变得好看:
// 这是我们写的(乱七八糟)
function hello( name ){
console.log( `Hello ${ name }` ) }
// Prettier 帮我们变成这样
function hello(name) {
console.log(`Hello ${name}`)
}
安装与基础配置
# 安装 Prettier
npm install --save-dev prettier
# 安装 ESLint 整合插件
npm install --save-dev eslint-config-prettier eslint-plugin-prettier
Prettier 配置文件
// .prettierrc.js
module.exports = {
// 基础配置
printWidth: 100, // 每行最大宽度
tabWidth: 2, // 缩进空格数
useTabs: false, // 用空格代替 tab
semi: false, // 不加分号
singleQuote: true, // 用单引号
quoteProps: 'as-needed', // 对象属性只在必要时加引号
trailingComma: 'none', // 不加尾逗号
bracketSpacing: true, // 对象括号内加空格 { foo: bar }
arrowParens: 'always', // 箭头函数参数总是加括号 (x) => x
endOfLine: 'auto', // 自动处理换行符
// Vue 相关
vueIndentScriptAndStyle: true, // 缩进 <script> 和 <style>
htmlWhitespaceSensitivity: 'strict',
// 针对不同文件的特殊配置
overrides: [
{
files: '*.vue',
options: {
printWidth: 120
}
},
{
files: '*.md',
options: {
proseWrap: 'always'
}
}
]
}
添加格式化脚本
{
"scripts": {
"format": "prettier --write \"src/**/*.{js,ts,vue,json,md}\"",
"format:check": "prettier --check \"src/**/*.{js,ts,vue,json,md}\""
}
}
编辑器集成(VS Code)
// .vscode/settings.json
{
// 保存时自动格式化
"editor.formatOnSave": true,
// 使用 Prettier 作为默认格式化工具
"editor.defaultFormatter": "esbenp.prettier-vscode",
// 对特定文件使用不同的格式化工具
"[javascript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[typescript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[vue]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
// 保存时自动修复 ESLint 问题
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true
},
// 禁用内置的 CSS/HTML 格式化器
"css.validate": false,
"scss.validate": false,
"html.validate.scripts": false,
"html.validate.styles": false
}
Husky + lint-staged:Git 钩子自动化
什么是 Git 钩子?
Git 钩子就像"守门员":我们在做某个 Git 操作之前,可以先执行一些检查:
你想提交代码 → 守门员检查 → 没问题 → 提交成功
↓
有问题 → 不让提交,让你改
Husky 安装与配置
# 安装 Husky
npm install --save-dev husky
# 初始化 Husky(创建 .husky 目录)
npx husky install
# 添加 prepare 脚本,确保其他人安装后自动启用
npm pkg set scripts.prepare="husky install"
# 创建 pre-commit 钩子
npx husky add .husky/pre-commit "npx lint-staged"
lint-staged 配置
// .lintstagedrc.js
module.exports = {
// 对 JS/TS/Vue 文件运行 ESLint(并自动修复)
'*.{js,jsx,ts,tsx,vue}': ['eslint --fix', 'prettier --write'],
// 对其他文件只运行 Prettier
'*.{json,md,yml,yaml,html,css,scss}': ['prettier --write']
}
添加提交信息规范
# 安装 commitlint
npm install --save-dev @commitlint/cli @commitlint/config-conventional
# 创建配置
cat > commitlint.config.js << 'EOF'
module.exports = {
extends: ['@commitlint/config-conventional'],
rules: {
'type-enum': [
2,
'always',
[
'feat', // 新功能
'fix', // 修复
'docs', // 文档
'style', // 代码风格
'refactor', // 重构
'perf', // 性能优化
'test', // 测试
'chore', // 构建/工具
'revert' // 回滚
]
],
'subject-full-stop': [2, 'never', '.'], // 结尾不能有句号
'header-max-length': [2, 'always', 100] // 最大长度100
}
}
EOF
# 添加 commit-msg 钩子
npx husky add .husky/commit-msg 'npx --no-install commitlint --edit "$1"'
提交信息格式
# 格式
<type>(<scope>): <subject>
# 示例
feat(user): 添加用户登录功能
fix(api): 修复请求超时问题
docs(readme): 更新安装说明
style(component): 格式化代码
refactor(utils): 重构日期处理函数
perf(list): 优化列表渲染性能
完整工作流演示
日常开发流程
1. 写代码
↓
2. 保存文件(VS Code 自动格式化)
↓
3. 提交代码
↓
4. pre-commit 钩子触发
↓
5. lint-staged 检查要提交的文件
├─ 通过 → 提交成功
└─ 不通过 → 显示错误,拒绝提交
常见问题
场景1:提交被拦截,因为代码有问题
$ git commit -m "feat: 添加功能"
→ lint-staged 检查发现错误
→ 提交失败
解决方案:修复错误后重新提交
$ npm run lint:fix
$ git add .
$ git commit -m "feat: 添加功能"
场景2:紧急情况,跳过检查
$ git commit --no-verify -m "hotfix: 紧急修复"
CI/CD 集成
GitHub Actions 配置
# .github/workflows/lint.yml
name: Code Quality
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: '18'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Run ESLint
run: npm run lint
- name: Check formatting
run: npm run format:check
- name: Run TypeScript check
run: npm run type-check
package.json 脚本
{
"scripts": {
"dev": "vite",
"build": "vue-tsc && vite build",
"preview": "vite preview",
"lint": "eslint . --ext .js,.ts,.vue",
"lint:fix": "eslint . --ext .js,.ts,.vue --fix",
"format": "prettier --write \"src/**/*.{js,ts,vue,json,md}\"",
"format:check": "prettier --check \"src/**/*.{js,ts,vue,json,md}\"",
"type-check": "vue-tsc --noEmit",
"prepare": "husky install"
}
}
常见问题与解决方案
ESLint 和 Prettier 冲突
让 Prettier 说了算:
// .eslintrc.js
module.exports = {
extends: [
'plugin:vue/vue3-recommended',
'plugin:prettier/recommended' // 放在最后,覆盖冲突规则
]
}
Husky 钩子不执行
检查钩子权限:
# 1. 检查钩子文件
ls -la .husky/pre-commit
# 2. 添加执行权限
chmod +x .husky/pre-commit
# 3. 重新安装
npm run prepare
lint-staged 运行太慢
// .lintstagedrc.js
module.exports = {
// 方法1:限制每次检查的文件数
'*.{js,ts,vue}': files => {
const chunks = chunk(files, 10)
return chunks.map(chunk => `eslint --fix ${chunk.join(' ')}`)
},
// 方法2:先跑 Prettier 再跑 ESLint
'*.{js,ts,vue}': ['prettier --write', 'eslint --fix']
}
function chunk(arr, size) {
return Array.from({ length: Math.ceil(arr.length / size) }, (_, i) =>
arr.slice(i * size, i * size + size)
)
}
新成员加入时配置不一致
# 解决方案1:提交配置文件到仓库
git add .eslintrc.js .prettierrc.js .vscode/
# 解决方案2:在 README 中说明
## 开发环境配置
1. 安装 Node.js 18+
2. 运行 `npm install`
3. 安装 VS Code 推荐插件
4. 运行 `npm run dev`
# 解决方案3:添加快速启动脚本
npm run setup
完整配置清单
项目文件结构
my-project/
├── .husky/
│ ├── pre-commit # 提交前检查
│ └── commit-msg # 提交信息检查
├── .vscode/
│ ├── settings.json # VS Code 设置
│ └── extensions.json # 推荐插件
├── .eslintrc.js # ESLint 配置
├── .prettierrc.js # Prettier 配置
├── .lintstagedrc.js # lint-staged 配置
├── commitlint.config.js # 提交信息规范
├── package.json
└── README.md
快速初始化脚本
#!/bin/bash
# setup.sh - 一键配置代码规范
echo "开始配置代码规范工具链..."
# 1. 安装依赖
npm install --save-dev \
eslint \
prettier \
eslint-config-prettier \
eslint-plugin-prettier \
eslint-plugin-vue \
@typescript-eslint/parser \
@typescript-eslint/eslint-plugin \
husky \
lint-staged \
@commitlint/cli \
@commitlint/config-conventional
# 2. 初始化配置文件
# (这里可以复制配置文件内容)
# 3. 初始化 Husky
npx husky install
npm pkg set scripts.prepare="husky install"
npx husky add .husky/pre-commit "npx lint-staged"
npx husky add .husky/commit-msg 'npx --no-install commitlint --edit "$1"'
echo "配置完成!"
规则选择原则
-
不要过度约束
- 能自动修复的用 error
- 不能自动修复的用 warn
-
优先使用社区推荐
- eslint:recommended
- vue/vue3-recommended
-
团队共识优先
- 有争议的规则,团队讨论决定
- 少数服从多数
工具使用原则
-
让工具做工具的事
- 格式化的交给 Prettier
- 质量检查交给 ESLint
- 提交检查交给 Git 钩子
-
减少手动操作
- 保存时自动格式化
- 提交前自动检查
- CI 自动验证
-
允许特殊情况
- 可以用 --no-verify 跳过
- 可以用 eslint-disable 忽略
- 可以用 prettier-ignore 忽略
团队协作建议
-
配置纳入版本控制
- 所有配置文件提交到仓库
- 新人 clone 后直接可用
-
做好文档
- README 说明如何配置
- 记录特殊规则的原因
-
定期回顾
- 收集反馈
- 调整规则
- 持续优化
结语
工具是辅助,不是目的。代码规范的核心是提升团队效率和代码质量,而不是制造障碍。自动化的代码规范工具链,不是为了限制开发者,而是为了解放开发者。让工具处理那些可以自动化的琐事,让人专注于真正需要思考的业务逻辑。
对于文章中错误的地方或有任何疑问,欢迎在评论区留言讨论!