本文是《从零到一:构建现代化企业级 Monorepo 项目实战》系列的第四篇。前面我们完成了项目搭建,这篇文章将配置完整的代码质量工具链,让团队协作更高效。
🎯 本文目标
读完这篇文章,你将学会:
- ESLint 9.x 扁平配置的最佳实践
- Prettier 与 ESLint 的冲突解决
- Stylelint 样式检查配置
- Git Hooks 自动化检查
- VSCode 编辑器集成
📖 为什么需要代码质量工具?
真实场景
没有工具时的团队协作:
typescript
// 开发者 A 的代码
function getUserInfo() {
const data = { name: '张三', age: 25 }
return data
}
// 开发者 B 的代码
function getUserInfo() {
const data = {
name: '李四',
age: 30,
}
return data
}
// 同一个团队,两种完全不同的代码风格!😱
配置工具后:
typescript
// 所有人的代码风格统一
function getUserInfo() {
const data = {
name: '张三',
age: 25,
}
return data
}
// ✅ 统一、规范、易读
🔧 工具链架构
bash
代码质量工具链
├── ESLint # JS/TS 代码检查
├── Prettier # 代码格式化
├── Stylelint # CSS/SCSS 检查
├── Husky # Git Hooks
└── lint-staged # 提交时增量检查
1️⃣ ESLint 9.x 扁平配置
为什么是 ESLint 9.x?
旧版配置(.eslintrc.js):
javascript
// ❌ 已废弃
module.exports = {
extends: ['eslint:recommended', 'plugin:vue/vue3-recommended'],
rules: {
'no-console': 'warn',
},
}
新版配置(eslint.config.js):
javascript
// ✅ ESLint 9.x 扁平配置
import js from '@eslint/js'
import vue from 'eslint-plugin-vue'
export default [
js.configs.recommended,
...vue.configs['flat/recommended'],
{
rules: {
'no-console': 'warn',
},
},
]
优势:
- ✅ 更简单的配置结构
- ✅ 更好的 TypeScript 支持
- ✅ 更灵活的规则组合
安装依赖
bash
# 安装 ESLint 及相关插件
pnpm add -Dw eslint \
@eslint/js \
@typescript-eslint/eslint-plugin \
@typescript-eslint/parser \
eslint-plugin-vue \
vue-eslint-parser \
eslint-config-prettier \
eslint-plugin-prettier
完整配置文件
javascript
// eslint.config.js
import js from '@eslint/js'
import tseslint from '@typescript-eslint/eslint-plugin'
import tsparser from '@typescript-eslint/parser'
import prettierConfig from 'eslint-config-prettier'
import vue from 'eslint-plugin-vue'
import vueParser from 'vue-eslint-parser'
export default [
// 基础 JavaScript 配置
js.configs.recommended,
// Vue 3 配置
...vue.configs['flat/recommended'],
// 全局配置
{
files: ['**/*.{js,ts,tsx,vue}'],
languageOptions: {
ecmaVersion: 'latest',
sourceType: 'module',
globals: {
process: 'readonly',
console: 'readonly',
window: 'readonly',
document: 'readonly',
},
},
rules: {
'no-console': 'off',
'no-debugger': 'error',
'prefer-const': 'error',
'no-var': 'error',
},
},
// TypeScript 配置
{
files: ['**/*.{ts,tsx}'],
languageOptions: {
parser: tsparser,
},
plugins: {
'@typescript-eslint': tseslint,
},
rules: {
'@typescript-eslint/no-unused-vars': 'error',
'@typescript-eslint/no-explicit-any': 'off',
},
},
// Vue 文件配置
{
files: ['**/*.vue'],
languageOptions: {
parser: vueParser,
parserOptions: {
parser: tsparser,
extraFileExtensions: ['.vue'],
},
},
rules: {
'vue/multi-word-component-names': 'off',
'vue/no-v-html': 'off',
},
},
// 忽略文件
{
ignores: ['node_modules/**', '**/dist/**', '**/.turbo/**', 'coverage/**'],
},
// Prettier 配置(必须放最后)
prettierConfig,
]
在 package.json 中添加脚本
json
{
"scripts": {
"lint": "turbo run lint",
"lint:fix": "turbo run lint:fix"
}
}
各包的 lint 脚本
json
// packages/shared/package.json
{
"scripts": {
"lint": "eslint . --ext .js,.ts",
"lint:fix": "eslint . --ext .js,.ts --fix"
}
}
// packages/ui/package.json
{
"scripts": {
"lint": "eslint . --ext .js,.ts,.vue",
"lint:fix": "eslint . --ext .js,.ts,.vue --fix"
}
}
2️⃣ Prettier 代码格式化
安装和配置
bash
# 安装 Prettier
pnpm add -Dw prettier
创建 .prettierrc
:
json
{
"semi": false,
"singleQuote": true,
"printWidth": 120,
"tabWidth": 2,
"trailingComma": "es5",
"arrowParens": "avoid",
"endOfLine": "lf"
}
创建 .prettierignore
:
csharp
node_modules
dist
.turbo
coverage
pnpm-lock.yaml
CHANGELOG.md
添加脚本
json
{
"scripts": {
"format": "turbo run format",
"format:check": "turbo run format:check"
}
}
json
// packages/*/package.json
{
"scripts": {
"format": "prettier --write \"src/**/*.{js,ts,vue,json}\"",
"format:check": "prettier --check \"src/**/*.{js,ts,vue,json}\""
}
}
ESLint 与 Prettier 冲突解决
关键配置:
javascript
// eslint.config.js
import prettierConfig from 'eslint-config-prettier'
export default [
// ... 其他配置
prettierConfig, // 必须放在最后,关闭冲突规则
// 重新启用某些规则(让 ESLint 能检测到错误)
{
rules: {
semi: ['error', 'never'],
quotes: ['error', 'single'],
},
},
]
工作流程:
编写代码 → ESLint 检查语法 → Prettier 格式化 → 完美代码 ✅
3️⃣ Stylelint 样式检查
安装依赖
bash
pnpm add -Dw stylelint \
stylelint-config-standard \
stylelint-config-standard-scss \
stylelint-config-recommended-vue \
postcss-html \
postcss-scss
配置文件
json
// .stylelintrc.json
{
"extends": ["stylelint-config-standard", "stylelint-config-standard-scss", "stylelint-config-recommended-vue"],
"rules": {
"selector-class-pattern": null,
"custom-property-pattern": null,
"scss/dollar-variable-pattern": null,
"selector-pseudo-class-no-unknown": [
true,
{
"ignorePseudoClasses": ["deep", "global"]
}
]
},
"ignoreFiles": ["node_modules/**", "dist/**", ".turbo/**", "coverage/**"]
}
添加脚本
json
// 根 package.json
{
"scripts": {
"lint:style": "turbo run lint:style",
"lint:style:fix": "turbo run lint:style:fix"
}
}
// packages/ui/package.json
{
"scripts": {
"lint:style": "stylelint \"src/**/*.{css,scss,vue}\"",
"lint:style:fix": "stylelint \"src/**/*.{css,scss,vue}\" --fix"
}
}
4️⃣ Git Hooks 自动化
安装 Husky
bash
pnpm add -Dw husky lint-staged
pnpm exec husky init
配置 pre-commit
bash
# .husky/pre-commit
pnpm lint-staged
配置 lint-staged
json
// .lintstagedrc.json
{
"*.{js,ts,tsx,vue}": ["eslint --fix", "prettier --write"],
"*.{css,scss,vue}": ["stylelint --fix"],
"*.{json,md}": ["prettier --write"]
}
配置 commit-msg
bash
# 安装 commitlint
pnpm add -Dw @commitlint/cli @commitlint/config-conventional
# .husky/commit-msg
npx --no -- commitlint --edit $1
javascript
// commitlint.config.js
export default {
extends: ['@commitlint/config-conventional'],
rules: {
'type-enum': [
2,
'always',
[
'feat', // 新功能
'fix', // Bug 修复
'docs', // 文档
'style', // 格式
'refactor', // 重构
'perf', // 性能
'test', // 测试
'chore', // 构建/工具
],
],
},
}
5️⃣ VSCode 集成
安装推荐扩展
创建 .vscode/extensions.json
:
json
{
"recommendations": ["dbaeumer.vscode-eslint", "esbenp.prettier-vscode", "stylelint.vscode-stylelint", "vue.volar"]
}
配置 VSCode 设置
创建 .vscode/settings.json
:
json
{
// ESLint 配置
"eslint.enable": true,
"eslint.run": "onType",
"eslint.format.enable": true,
// Prettier 配置
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.formatOnSave": true,
// Stylelint 配置
"stylelint.enable": true,
"stylelint.validate": ["css", "scss", "vue"],
// Vue 配置
"volar.takeOverMode": true,
// 保存时自动修复
"editor.codeActionsOnSave": {
"source.fixAll.eslint": "never" // 关闭自动修复,只显示错误
},
// 文件关联
"files.associations": {
"*.css": "css",
"*.scss": "scss"
}
}
EditorConfig 统一编辑器配置
ini
# .editorconfig
root = true
[*]
charset = utf-8
end_of_line = lf
indent_style = space
indent_size = 2
insert_final_newline = true
trim_trailing_whitespace = true
[*.md]
trim_trailing_whitespace = false
🎯 完整的工作流
开发阶段
bash
# 1. 编写代码
vim packages/ui/src/components/Button/button.vue
# 2. 保存时自动格式化(Prettier)
# 3. 编辑器实时显示 ESLint 错误(红色波浪线)
提交阶段
bash
git add .
git commit -m "feat: 添加 Button 组件"
# 自动触发:
# 1. lint-staged → 检查暂存文件
# 2. ESLint 自动修复
# 3. Prettier 格式化
# 4. Stylelint 修复样式
# 5. commitlint 检查 commit 消息
# 如果有错误,提交会被阻止
CI/CD 阶段
yaml
# .gitlab-ci.yml
lint:
stage: check
script:
- pnpm lint:all
- pnpm format:check
🚀 实战:配置完整的检查流程
第一步:安装所有依赖
bash
# 创建安装脚本
cat > install-tools.sh << 'EOF'
#!/bin/bash
# ESLint
pnpm add -Dw eslint \
@eslint/js \
@typescript-eslint/eslint-plugin \
@typescript-eslint/parser \
eslint-plugin-vue \
vue-eslint-parser \
eslint-config-prettier \
eslint-plugin-prettier
# Prettier
pnpm add -Dw prettier
# Stylelint
pnpm add -Dw stylelint \
stylelint-config-standard \
stylelint-config-standard-scss \
stylelint-config-recommended-vue \
postcss-html \
postcss-scss
# Git Hooks
pnpm add -Dw husky lint-staged
# Commitlint
pnpm add -Dw @commitlint/cli @commitlint/config-conventional
echo "✅ 所有工具安装完成!"
EOF
chmod +x install-tools.sh
./install-tools.sh
第二步:创建配置文件
bash
# ESLint
touch eslint.config.js
# Prettier
touch .prettierrc .prettierignore
# Stylelint
touch .stylelintrc.json
# Commitlint
touch commitlint.config.js
# lint-staged
touch .lintstagedrc.json
# EditorConfig
touch .editorconfig
第三步:配置 Turbo 任务
json
// turbo.json
{
"tasks": {
"lint": {
"dependsOn": [],
"inputs": ["$TURBO_DEFAULT$", "!{dist,.turbo}/**"],
"cache": true
},
"lint:fix": {
"dependsOn": [],
"cache": false,
"outputs": []
},
"lint:style": {
"cache": true
},
"lint:style:fix": {
"cache": false
},
"format": {
"cache": false
},
"format:check": {
"cache": true
}
}
}
第四步:添加统一脚本
json
// 根 package.json
{
"scripts": {
"lint": "turbo run lint",
"lint:fix": "turbo run lint:fix",
"lint:style": "turbo run lint:style",
"lint:style:fix": "turbo run lint:style:fix",
"format": "turbo run format",
"format:check": "turbo run format:check",
"lint:all": "turbo run lint lint:style",
"fix:all": "turbo run lint:fix lint:style:fix format"
}
}
🎨 各工具的职责划分
工具 | 职责 | 检查内容 | 能否自动修复 |
---|---|---|---|
ESLint | 代码质量 | 语法错误、代码规范、潜在bug | ✅ 部分可以 |
Prettier | 代码格式 | 缩进、换行、引号、分号 | ✅ 全部可以 |
Stylelint | 样式质量 | CSS/SCSS 规范、顺序 | ✅ 部分可以 |
示例代码
typescript
// ❌ 有问题的代码
const data = { name: 'test', value: 123 }
if (data) {
console.log(data)
}
// ESLint 检查后
const data = { name: 'test', value: 123 } // ✅ 变量声明规范
if (data) {
// ✅ 条件语句格式
console.log(data) // ✅ 缩进正确
}
// Prettier 格式化后
const data = { name: 'test', value: 123 }
if (data) {
console.log(data)
}
// ✅ 完美!
🔥 实战案例:修复代码问题
场景1:多余的空行
typescript
// ❌ 错误:过多的空行
function test() {
console.log('test')
return true
}
ESLint 规则:
javascript
{
rules: {
'no-multiple-empty-lines': ['error', {
max: 1, // 最多1个空行
maxEOF: 1, // 文件末尾最多1个空行
maxBOF: 0 // 文件开头不允许空行
}]
}
}
修复后:
typescript
// ✅ 正确
function test() {
console.log('test')
return true
}
场景2:未使用的变量
typescript
// ❌ 错误
function calculate() {
const unused = 123 // 未使用
const result = 456
return result
}
ESLint 会报错:
vbnet
error: 'unused' is assigned a value but never used
修复:
typescript
// ✅ 删除未使用的变量
function calculate() {
const result = 456
return result
}
场景3:样式属性顺序
scss
// ❌ 样式属性乱序
.button {
cursor: pointer;
padding: 10px;
display: flex;
color: white;
background: blue;
}
Stylelint 自动修复:
scss
// ✅ 按照标准顺序排列
.button {
display: flex;
padding: 10px;
color: white;
cursor: pointer;
background: blue;
}
🤖 自动化检查流程
Git Hooks 触发时机
bash
# pre-commit: 提交前检查
git commit
→ lint-staged 运行
→ ESLint 检查修改的文件
→ Prettier 格式化修改的文件
→ Stylelint 检查样式文件
→ 如果有错误,终止提交 ❌
→ 如果通过,继续提交 ✅
# commit-msg: 检查提交信息
git commit -m "add button"
→ commitlint 检查格式
→ ❌ 错误:缺少类型前缀
git commit -m "feat: add button"
→ ✅ 通过检查
lint-staged 增量检查
传统方式:
bash
# 检查所有文件(慢)
eslint .
# 1000个文件,耗时 30s 😫
lint-staged 方式:
bash
# 只检查暂存的文件(快)
# 修改了 3 个文件,耗时 0.5s ⚡
配置:
json
{
"*.{js,ts,vue}": [
"eslint --fix", // 1. 修复 ESLint 问题
"prettier --write" // 2. 格式化代码
],
"*.{css,scss,vue}": [
"stylelint --fix" // 3. 修复样式问题
]
}
💡 团队协作最佳实践
1. 统一的代码风格
javascript
// ✅ 团队统一使用单引号
const name = 'gdu-common'
// ✅ 团队统一不使用分号
const version = '1.0.0'
// ✅ 团队统一使用 2 空格缩进
function hello() {
console.log('hello')
}
2. 渐进式规则
第一阶段:基础规则
javascript
{
rules: {
'no-console': 'off', // 允许 console
'no-debugger': 'error', // 禁止 debugger
'@typescript-eslint/no-explicit-any': 'off' // 允许 any
}
}
第二阶段:严格规则
javascript
{
rules: {
'no-console': 'warn', // 警告 console
'@typescript-eslint/no-explicit-any': 'warn' // 警告 any
}
}
第三阶段:最严格
javascript
{
rules: {
'no-console': 'error', // 禁止 console
'@typescript-eslint/no-explicit-any': 'error' // 禁止 any
}
}
3. 规则说明文档
markdown
# 代码规范
## 命名规范
- 变量:小驼峰 `userInfo`
- 常量:大写下划线 `API_BASE_URL`
- 组件:大驼峰 `ButtonComponent`
- 文件:小写连字符 `user-info.ts`
## 代码风格
- 使用单引号
- 不使用分号
- 2 空格缩进
- 最多 1 个连续空行
## Vue 组件规范
- 使用 Composition API
- Props 必须定义类型
- 事件使用 emit 定义
📊 效果展示
代码质量提升
配置前:
typescript
// 各种问题:
;-代码风格不统一 - 存在未使用的变量 - 缺少类型定义 - 样式属性乱序
配置后:
bash
# 运行检查
pnpm lint:all
# 输出
✓ @gdu-common/shared:lint (1.2s)
✓ @gdu-common/utils:lint (0.8s)
✓ @gdu-common/ui:lint (2.1s)
✓ @gdu-common/ui:lint:style (1.5s)
# ✅ 0 errors, 0 warnings
提交前自动修复
bash
git add .
git commit -m "feat: add button component"
# 输出
✔ Preparing lint-staged...
✔ Running tasks for staged files...
✔ packages/ui/src/**/*.{js,ts,vue}
✔ eslint --fix
✔ prettier --write
✔ packages/ui/src/**/*.{css,scss,vue}
✔ stylelint --fix
✔ Applying modifications from tasks...
✔ Cleaning up temporary files...
# ✅ 自动修复完成,提交成功
🤔 常见问题
Q1: ESLint 和 Prettier 冲突怎么办?
解决方案:
javascript
// 1. 安装 eslint-config-prettier
pnpm add -Dw eslint-config-prettier
// 2. 在 eslint.config.js 最后添加
import prettierConfig from 'eslint-config-prettier'
export default [
// ... 其他配置
prettierConfig // 必须在最后
]
Q2: 如何在编辑器中实时看到错误?
配置 VSCode:
json
{
"eslint.run": "onType", // 输入时检查
"editor.codeActionsOnSave": {
"source.fixAll.eslint": "never" // 不自动修复,只显示错误
}
}
Q3: 提交时检查太慢怎么办?
使用 lint-staged 增量检查:
json
// 只检查修改的文件
{
"*.ts": "eslint --fix" // 不是 "eslint ."
}
Q4: 如何跳过 Git Hooks?
bash
# 不推荐,但紧急情况可以用
git commit --no-verify -m "feat: urgent fix"
🎉 总结
完整的代码质量工具链配置:
工具清单
- ✅ ESLint 9.x(扁平配置)
- ✅ Prettier(代码格式化)
- ✅ Stylelint(样式检查)
- ✅ Husky(Git Hooks)
- ✅ lint-staged(增量检查)
- ✅ Commitlint(提交信息规范)
效果
- 📈 代码质量显著提升
- 🚀 自动化程度 100%
- 👥 团队协作更顺畅
- ⏱️ Code Review 时间减少 50%
关键配置
bash
# 一键检查所有代码
pnpm lint:all
# 一键修复所有问题
pnpm fix:all
# 提交时自动检查和修复
git commit
在下一篇文章中,我将分享版本管理的实践,包括:
- Changeset 工作流程
- 语义化版本控制
- CHANGELOG 自动生成
- 自动化发布流程
🔗 系列文章
- 📖 上一篇: 从零搭建:pnpm + Turborepo 项目架构实战
- 📖 下一篇: 《版本管理实战:Changeset 工作流完全指南》
- 🏠 专栏首页: 从零到一:构建现代化企业级 Monorepo 项目实战
代码质量工具配置好了吗?觉得有用的话点个赞支持一下! 👍
你的团队用的是什么代码检查工具?有什么踩坑经验?欢迎评论区分享! 💬