前端代码质量工具链详解
本文面向前端开发者,系统讲解现代前端项目中代码质量保障工具链的配置和使用。涵盖 ESLint(代码规范)、Prettier(格式化)、TypeScript(类型检查)、Stylelint(样式规范)等工具的最佳实践。
# 一、代码质量概述
# 为什么需要代码质量工具
- 统一代码风格:团队协作中保持一致的代码风格
- 减少错误:编译时发现潜在问题,避免运行时错误
- 提高可维护性:规范的代码更易理解和维护
- 提升开发效率:自动化工具减少人工审查工作
- 降低技术债务:及早发现和修复代码问题
# 工具链全景图
┌─────────────────────────────────────────────────────────┐
│ 代码质量工具链 │
├─────────────────────────────────────────────────────────┤
│ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ ESLint │ │ TypeScript │ │ Prettier │ │
│ │ 代码规范 │ │ 类型检查 │ │ 代码格式化 │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
│ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ Stylelint │ │ Commitlint │ │ Husky │ │
│ │ 样式规范 │ │ 提交规范 │ │ Git Hooks │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
│ │
│ ┌──────────────┐ ┌──────────────┐ │
│ │ lint-staged │ │ EditorConfig│ │
│ │ 暂存区检查 │ │ 编辑器配置 │ │
│ └──────────────┘ └──────────────┘ │
│ │
└─────────────────────────────────────────────────────────┘
# 工具分类
| 工具 | 类型 | 主要功能 | 运行时机 |
|---|---|---|---|
| ESLint | 代码检查 | JavaScript/TypeScript 代码规范 | 编辑器、提交前、CI/CD |
| TypeScript | 类型检查 | 静态类型检查 | 编辑器、构建时、CI/CD |
| Prettier | 代码格式化 | 统一代码格式 | 编辑器保存、提交前 |
| Stylelint | 样式检查 | CSS/SCSS/Less 规范 | 编辑器、提交前 |
| Commitlint | 提交检查 | Git 提交信息规范 | 提交时 |
| Husky | Git Hooks | 执行 Git 钩子 | Git 操作时 |
| lint-staged | 暂存检查 | 只检查暂存文件 | 提交前 |
# 二、ESLint - 代码规范
# ESLint 简介
ESLint 是一个插件化的 JavaScript 代码检查工具,用于识别和报告代码中的模式,帮助开发者编写一致性和无错误的代码。
# 安装和初始化
# 安装 ESLint
npm install -D eslint
# 初始化配置(交互式)
npx eslint --init
# 或者手动创建配置文件
# 配置文件
ESLint 支持多种配置文件格式:
// .eslintrc.js(推荐)
module.exports = {
// 运行环境:指定代码运行的环境,决定哪些全局变量可用
env: {
browser: true, // 浏览器全局变量(如 window、document)
es2021: true, // ES2021 语法和全局变量(如 Promise、Set)
node: true // Node.js 全局变量和作用域(如 global、process)
},
// 继承的规则集:从预设配置中继承规则,避免从零配置
extends: [
'eslint:recommended', // ESLint 内置的推荐规则集
'plugin:@typescript-eslint/recommended', // TypeScript 推荐规则(需要安装 @typescript-eslint/eslint-plugin)
'plugin:vue/vue3-recommended', // Vue 3 推荐规则(需要安装 eslint-plugin-vue)
'plugin:prettier/recommended' // Prettier 集成,关闭与 Prettier 冲突的 ESLint 规则(需要安装 eslint-plugin-prettier 和 eslint-config-prettier)
],
// 解析器:指定 ESLint 使用的解析器来解析代码
parser: '@typescript-eslint/parser', // 使用 TypeScript 解析器,支持解析 TypeScript 语法(需要安装 @typescript-eslint/parser)
// 解析器选项:配置解析器的行为
parserOptions: {
ecmaVersion: 'latest', // 支持最新的 ECMAScript 语法
sourceType: 'module', // 代码是 ECMAScript 模块(使用 import/export)
ecmaFeatures: {
jsx: true // 启用 JSX 语法支持(用于 React)
}
},
// 插件:扩展 ESLint 功能的第三方插件
plugins: [
'@typescript-eslint', // TypeScript 支持(提供 TypeScript 特定的规则)
'vue' // Vue.js 支持(提供 Vue 特定的规则)
],
// 自定义规则:覆盖或添加具体的检查规则
// 规则值:'off' 或 0(关闭)、'warn' 或 1(警告)、'error' 或 2(错误)
rules: {
// 关闭规则:允许使用 console(开发时常用)
'no-console': 'off',
// 警告级别:未使用的变量会触发警告但不阻止提交
'no-unused-vars': 'warn',
// 错误级别:违反规则会报错
'semi': ['error', 'never'], // 禁止使用分号(自动修复)
'quotes': ['error', 'single'], // 强制使用单引号(自动修复)
// TypeScript 特定规则
'@typescript-eslint/no-explicit-any': 'warn', // 警告使用 any 类型(鼓励使用更具体的类型)
'@typescript-eslint/explicit-function-return-type': 'off', // 关闭强制函数返回类型注解(TypeScript 可以推断)
// Vue 特定规则
'vue/multi-word-component-names': 'off', // 关闭组件名必须多词的要求(Vue 推荐但可能过于严格)
'vue/max-attributes-per-line': ['error', {
singleline: 3, // 单行标签允许最多 3 个属性
multiline: 1 // 多行标签每行只允许 1 个属性
}]
},
// 忽略文件:不对以下文件/目录进行检查
ignorePatterns: [
'dist', // 构建输出目录
'node_modules', // 依赖包目录
'*.config.js' // 配置文件(通常使用 CommonJS 语法,可能与项目规则冲突)
]
}
# 常用规则配置
// .eslintrc.js
module.exports = {
rules: {
// ===== 代码质量 =====
'no-console': 'warn', // 禁止 console(开发时警告)
'no-debugger': 'error', // 禁止 debugger
'no-unused-vars': 'warn', // 未使用的变量
'no-undef': 'error', // 未定义的变量
'no-var': 'error', // 禁止使用 var
'prefer-const': 'error', // 优先使用 const
'eqeqeq': ['error', 'always'], // 强制使用 ===
// ===== 代码风格 =====
'semi': ['error', 'never'], // 不使用分号
'quotes': ['error', 'single'], // 使用单引号
'indent': ['error', 2], // 2 空格缩进
'comma-dangle': ['error', 'never'], // 禁止尾随逗号
'arrow-parens': ['error', 'always'], // 箭头函数参数括号
// ===== 最佳实践 =====
'curly': ['error', 'all'], // 强制使用花括号
'default-case': 'error', // switch 需要 default
'no-else-return': 'error', // 禁止 if 后不必要的 else
'no-empty-function': 'warn', // 禁止空函数
'no-eval': 'error', // 禁止 eval
'no-implied-eval': 'error', // 禁止隐式 eval
// ===== ES6 =====
'arrow-spacing': 'error', // 箭头函数空格
'no-duplicate-imports': 'error', // 禁止重复导入
'prefer-arrow-callback': 'error', // 优先使用箭头函数
'prefer-template': 'error' // 优先使用模板字符串
}
}
# TypeScript 项目配置
# 安装依赖
npm install -D @typescript-eslint/parser @typescript-eslint/eslint-plugin
// .eslintrc.js
module.exports = {
parser: '@typescript-eslint/parser',
parserOptions: {
project: './tsconfig.json',
tsconfigRootDir: __dirname,
sourceType: 'module'
},
plugins: ['@typescript-eslint'],
extends: [
'eslint:recommended',
'plugin:@typescript-eslint/recommended',
'plugin:@typescript-eslint/recommended-requiring-type-checking'
],
rules: {
// TypeScript 特定规则
'@typescript-eslint/explicit-function-return-type': 'off',
'@typescript-eslint/explicit-module-boundary-types': 'off',
'@typescript-eslint/no-explicit-any': 'warn',
'@typescript-eslint/no-unused-vars': ['warn', {
argsIgnorePattern: '^_'
}],
'@typescript-eslint/no-non-null-assertion': 'warn',
// 覆盖基础规则
'no-unused-vars': 'off',
'@typescript-eslint/no-unused-vars': 'warn'
}
}
# Vue 项目配置
# 安装依赖
npm install -D eslint-plugin-vue
// .eslintrc.js
module.exports = {
extends: [
'plugin:vue/vue3-recommended',
'@vue/typescript/recommended'
],
rules: {
// Vue 规则
'vue/multi-word-component-names': 'off',
'vue/no-v-html': 'warn',
'vue/require-default-prop': 'error',
'vue/require-prop-types': 'error',
'vue/component-name-in-template-casing': ['error', 'PascalCase'],
'vue/html-indent': ['error', 2],
'vue/max-attributes-per-line': ['error', {
singleline: 3,
multiline: 1
}],
'vue/first-attribute-linebreak': ['error', {
singleline: 'ignore',
multiline: 'below'
}]
}
}
# React 项目配置
# 安装依赖
npm install -D eslint-plugin-react eslint-plugin-react-hooks
// .eslintrc.js
module.exports = {
extends: [
'plugin:react/recommended',
'plugin:react-hooks/recommended'
],
settings: {
react: {
version: 'detect'
}
},
rules: {
'react/react-in-jsx-scope': 'off', // React 17+ 不需要
'react/prop-types': 'off', // 使用 TypeScript
'react-hooks/rules-of-hooks': 'error',
'react-hooks/exhaustive-deps': 'warn'
}
}
# 使用 ESLint
# 检查所有文件
npx eslint .
# 检查特定文件
npx eslint src/**/*.ts
# 自动修复
npx eslint . --fix
# 指定格式输出
npx eslint . --format stylish
# 忽略警告,只显示错误
npx eslint . --quiet
# package.json 脚本
{
"scripts": {
"lint": "eslint . --ext .js,.ts,.vue",
"lint:fix": "eslint . --ext .js,.ts,.vue --fix"
}
}
# 忽略文件
# .eslintignore
dist
node_modules
*.config.js
public
.nuxt
.output
coverage
# 三、Prettier - 代码格式化
# Prettier 简介
Prettier 是一个有主见的代码格式化工具,支持多种语言,与 ESLint 配合使用可以实现代码规范和格式化的完美结合。
Prettier vs ESLint:
- ESLint:关注代码质量(潜在错误、最佳实践)
- Prettier:关注代码风格(缩进、引号、换行)
# 安装
# 安装 Prettier
npm install -D prettier
# 安装 ESLint 集成插件
npm install -D eslint-config-prettier eslint-plugin-prettier
# 配置文件
// .prettierrc.js
module.exports = {
// 行宽:一行代码的最大字符数,超过会自动换行
printWidth: 80,
// 缩进宽度:一个缩进等于多少个空格
tabWidth: 2,
// 是否使用制表符(Tab)缩进,false 表示使用空格
useTabs: false,
// 分号:语句末尾是否添加分号(false = 不添加)
semi: false,
// 引号:字符串使用单引号还是双引号
singleQuote: true, // true = 单引号,false = 双引号
// 对象属性引号:何时给对象属性名加引号
// 'as-needed' = 仅在需要时加引号(如属性名包含特殊字符)
// 'consistent' = 同一对象中保持一致
// 'preserve' = 保留原有引号
quoteProps: 'as-needed',
// JSX 引号:JSX 属性使用单引号还是双引号
jsxSingleQuote: false, // false = 双引号(符合 HTML 习惯)
// 尾随逗号:多行时是否在最后一项后添加逗号
// 'none' = 不添加
// 'es5' = 在 ES5 有效的地方添加(对象、数组)
// 'all' = 尽可能添加(包括函数参数)
trailingComma: 'none',
// 对象字面量空格:大括号内是否添加空格
// true = { foo: bar }
// false = {foo: bar}
bracketSpacing: true,
// JSX 标签闭合:多行 JSX 元素的 `>` 是否单独一行
// false = 单独一行
// true = 放在最后一行末尾
bracketSameLine: false,
// 箭头函数参数括号:单参数箭头函数是否需要括号
// 'always' = 总是添加括号 (x) => x
// 'avoid' = 尽可能省略括号 x => x
arrowParens: 'always',
// 换行符:使用哪种换行符
// 'lf' = Linux/macOS 风格 (\n)
// 'crlf' = Windows 风格 (\r\n)
// 'cr' = 旧 macOS 风格 (\r)
// 'auto' = 保持现有换行符
endOfLine: 'lf',
// Vue 文件中的 script 和 style 标签缩进
// false = 不缩进(与标签同级)
// true = 缩进一级
vueIndentScriptAndStyle: false,
// HTML 空白敏感度:如何处理 HTML 中的空白字符
// 'css' = 遵循 CSS display 属性(推荐)
// 'strict' = 所有空白都敏感
// 'ignore' = 所有空白都不敏感
htmlWhitespaceSensitivity: 'css'
}
endOfLine: 'lf',
// Vue 文件中的 script 和 style 标签缩进
vueIndentScriptAndStyle: false,
// HTML 空白敏感度
htmlWhitespaceSensitivity: 'css'
}
# 忽略文件
# .prettierignore
dist
node_modules
*.config.js
public
.nuxt
.output
coverage
pnpm-lock.yaml
package-lock.json
# 与 ESLint 集成
// .eslintrc.js
module.exports = {
extends: [
// ... 其他配置
'plugin:prettier/recommended' // 必须放在最后
]
}
这个配置做了三件事:
- 启用
eslint-plugin-prettier - 设置
prettier/prettier规则为error - 使用
eslint-config-prettier关闭 ESLint 中与 Prettier 冲突的规则
# 使用 Prettier
# 格式化所有文件
npx prettier --write .
# 检查文件是否已格式化
npx prettier --check .
# 格式化特定文件
npx prettier --write "src/**/*.{js,ts,vue}"
# package.json 脚本
{
"scripts": {
"format": "prettier --write .",
"format:check": "prettier --check ."
}
}
# 编辑器集成
# VS Code
安装 Prettier 插件,然后配置:
// .vscode/settings.json
{
"editor.formatOnSave": true,
"editor.defaultFormatter": "esbenp.prettier-vscode",
"[javascript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[typescript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[vue]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[json]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
}
}
# 四、TypeScript - 类型检查
# TypeScript 配置详解
如果你还不熟悉 TypeScript 基础,建议先阅读 TypeScript极简入门。
# tsconfig.json 严格模式
{
"compilerOptions": {
// ===== 基础配置 =====
// 编译目标:将 TypeScript 编译成的 JavaScript 版本
"target": "ES2020",
// 模块系统:生成的模块代码格式
// 'ESNext' = 使用最新的 ES 模块语法(import/export)
"module": "ESNext",
// 类型库:编译时包含的类型声明文件
"lib": ["ES2020", "DOM", "DOM.Iterable"], // ES2020 API + 浏览器 DOM API
// 模块解析策略:如何查找导入的模块
// 'bundler' = 适配 Vite、Webpack 等打包工具(推荐)
// 'node' = Node.js 风格解析
"moduleResolution": "bundler",
// 是否允许导入 .json 文件作为模块
"resolveJsonModule": true,
// ===== 路径配置 =====
// 基础路径:相对路径的起点(通常是项目根目录)
"baseUrl": ".",
// 路径别名:简化导入路径
// 使用 '@/utils/helper' 代替 '../../utils/helper'
"paths": {
"@/*": ["./src/*"], // @ 指向 src 目录
"@components/*": ["./src/components/*"],
"@utils/*": ["./src/utils/*"]
},
// ===== 输出配置 =====
// 编译输出目录
"outDir": "./dist",
// 源代码根目录
"rootDir": "./src",
// 是否生成 .d.ts 类型声明文件(供其他项目使用)
"declaration": true,
// 是否生成类型声明的 source map(方便调试)
"declarationMap": true,
// 是否生成 source map 文件(调试时映射到源码)
"sourceMap": true,
// 是否移除编译后的注释
"removeComments": false,
// ===== 严格模式(推荐全部开启)=====
// 启用所有严格类型检查选项(包含下面所有 strict* 选项)
"strict": true,
// 禁止隐式 any:变量必须有明确的类型
// ❌ function test(param) {}
// ✅ function test(param: string) {}
"noImplicitAny": true,
// 严格空值检查:null 和 undefined 必须显式处理
// ❌ let name: string = null
// ✅ let name: string | null = null
"strictNullChecks": true,
// 严格函数类型检查:函数参数逆变检查
"strictFunctionTypes": true,
// 严格 bind/call/apply 检查:确保参数类型正确
"strictBindCallApply": true,
// 严格属性初始化:类属性必须在构造函数中初始化或声明为可选
"strictPropertyInitialization": true,
// 禁止隐式 this:this 必须有明确的类型
"noImplicitThis": true,
// 始终以严格模式解析:生成的 JS 代码包含 'use strict'
"alwaysStrict": true,
// ===== 额外检查 =====
// 禁止未使用的本地变量(函数内)
"noUnusedLocals": true,
// 禁止未使用的参数
"noUnusedParameters": true,
// 禁止隐式返回:函数所有分支都必须有返回值
"noImplicitReturns": true,
// 禁止 switch 穿透:case 必须有 break 或 return
"noFallthroughCasesInSwitch": true,
// 索引访问检查:通过索引访问的属性可能为 undefined
// arr[0] 的类型是 T | undefined
"noUncheckedIndexedAccess": true,
// 禁止隐式覆盖:子类覆盖父类方法必须使用 override 关键字
"noImplicitOverride": true,
// 禁止通过索引签名访问属性:强制使用 [] 而非 . 访问动态属性
"noPropertyAccessFromIndexSignature": true,
// ===== 模块配置 =====
// ES 模块互操作:允许使用 import foo from 'foo' 导入 CommonJS 模块
"esModuleInterop": true,
// 允许合成默认导入:没有默认导出的模块也可以 import foo from 'foo'
"allowSyntheticDefaultImports": true,
// 强制文件名大小写一致:避免跨平台问题
"forceConsistentCasingInFileNames": true,
// ===== 其他 =====
// 跳过类型库检查:加快编译速度(不检查 node_modules 中的 .d.ts)
"skipLibCheck": true,
// 隔离模块:确保每个文件都可以独立编译(适配 Babel、esbuild)
"isolatedModules": true
},
// 包含的文件:需要编译的文件路径
"include": ["src/**/*"],
// 排除的文件:不需要编译的文件路径
"exclude": ["node_modules", "dist"]
}
# 类型检查最佳实践
// ✅ 推荐:明确的类型注解
function add(a: number, b: number): number {
return a + b
}
// ❌ 不推荐:隐式 any
function add(a, b) {
return a + b
}
// ✅ 推荐:接口定义
interface User {
id: number
name: string
email: string
}
function getUser(id: number): User {
// ...
}
// ✅ 推荐:类型断言(确定时使用)
const input = document.getElementById('input') as HTMLInputElement
// ❌ 不推荐:any 类型
const data: any = fetchData()
// ✅ 推荐:unknown 类型(需要类型检查)
const data: unknown = fetchData()
if (typeof data === 'object' && data !== null) {
// 使用 data
}
// ✅ 推荐:严格空值检查
function greet(name: string | null): string {
if (name === null) {
return 'Hello, Guest'
}
return `Hello, ${name}`
}
// ✅ 推荐:可选链和空值合并
const userName = user?.profile?.name ?? 'Anonymous'
# 在构建时进行类型检查
// package.json
{
"scripts": {
"type-check": "tsc --noEmit",
"build": "tsc && vite build"
}
}
# Vue 项目类型检查
# 安装 vue-tsc
npm install -D vue-tsc
// package.json
{
"scripts": {
"type-check": "vue-tsc --noEmit"
}
}
# 类型声明文件
// src/types/global.d.ts
declare global {
interface Window {
customProperty: string
}
}
export {}
// src/types/api.d.ts
export interface ApiResponse<T> {
code: number
message: string
data: T
}
export interface User {
id: number
name: string
email: string
}
# 五、Stylelint - 样式规范
# Stylelint 简介
Stylelint 是一个强大的现代 CSS 检查工具,帮助你避免错误并强制执行约定。
# 安装
# 基础安装
npm install -D stylelint stylelint-config-standard
# SCSS 支持
npm install -D stylelint-config-standard-scss postcss-scss
# Vue 支持
npm install -D stylelint-config-standard-vue
# Prettier 集成
npm install -D stylelint-config-prettier
# 配置文件
// .stylelintrc.js
module.exports = {
// 继承的规则集:使用社区维护的规则预设
extends: [
'stylelint-config-standard', // 标准 CSS 规则(需要安装 stylelint-config-standard)
'stylelint-config-standard-scss', // SCSS 支持(需要安装 stylelint-config-standard-scss)
'stylelint-config-standard-vue', // Vue 单文件组件支持(需要安装 stylelint-config-standard-vue)
'stylelint-config-prettier' // 关闭与 Prettier 冲突的规则(需要安装 stylelint-config-prettier)
],
// 自定义规则
rules: {
// ===== 颜色 =====
// 颜色十六进制长度:'short' = #fff,'long' = #ffffff
'color-hex-length': 'short',
// 禁止使用颜色名称:避免使用 'red'、'blue' 等,统一使用十六进制或 rgb
'color-named': 'never',
// ===== 字体 =====
// 字体名称引号:建议在必要时添加引号(如字体名包含空格)
'font-family-name-quotes': 'always-where-recommended',
// ===== 选择器 =====
// 类选择器命名规范:使用 camelCase 风格(如 myClass、btnPrimary)
'selector-class-pattern': '^[a-z][a-zA-Z0-9]*$',
// ID 选择器命名规范:使用 camelCase 风格
'selector-id-pattern': '^[a-z][a-zA-Z0-9]*$',
// 禁止使用 ID 选择器:避免样式权重过高
'selector-max-id': 0,
// 通配符选择器最多使用 1 次:限制 * 选择器的使用
'selector-max-universal': 1,
// ===== 属性 =====
// 禁止属性使用浏览器前缀:交给 autoprefixer 处理
'property-no-vendor-prefix': true,
// 禁止属性值使用浏览器前缀
'value-no-vendor-prefix': true,
// ===== 声明 =====
// 禁止使用 !important:避免样式优先级混乱
'declaration-no-important': true,
// ===== 规则 =====
// 规则前空行:每个规则前必须有空行(except 表示例外情况)
'rule-empty-line-before': ['always', {
except: ['first-nested'] // 嵌套的第一个规则除外
}],
// ===== 注释 =====
// 注释前空行:注释前必须有空行
'comment-empty-line-before': 'always',
// 注释内部空格:注释符号内必须有空格(/* 内容 */)
'comment-whitespace-inside': 'always',
// ===== SCSS 特定规则 =====
// @import 时不需要文件扩展名:@import 'variables' 而非 @import 'variables.scss'
'scss/at-import-partial-extension': 'never',
// 禁止未知的 @ 规则:避免拼写错误
'scss/at-rule-no-unknown': true,
// SCSS 变量命名规范:使用 camelCase 风格(如 $primaryColor)
'scss/dollar-variable-pattern': '^[a-z][a-zA-Z0-9]*$',
// ===== 禁用的规则 =====
// 禁用降序特异性检查:有时后面的规则覆盖前面的规则是合理的
'no-descending-specificity': null,
// 允许 Vue 的 :deep、:global 等伪类
'selector-pseudo-class-no-unknown': [true, {
ignorePseudoClasses: ['deep', 'global'] // 忽略 Vue 特有的伪类
}]
},
// 忽略文件:不对以下文件/目录进行检查
ignoreFiles: [
'dist/**/*', // 构建输出目录
'node_modules/**/*' // 依赖包目录
]
}
# 使用 Stylelint
# 检查所有样式文件
npx stylelint "**/*.{css,scss,vue}"
# 自动修复
npx stylelint "**/*.{css,scss,vue}" --fix
// package.json
{
"scripts": {
"lint:style": "stylelint \"**/*.{css,scss,vue}\"",
"lint:style:fix": "stylelint \"**/*.{css,scss,vue}\" --fix"
}
}
# 六、Git Hooks - 提交前检查
# Husky - Git Hooks 管理
# 安装 Husky
npm install -D husky
# 初始化
npx husky init
这会创建 .husky 目录和示例钩子。
# 配置 pre-commit 钩子
# .husky/pre-commit
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
# 运行 lint-staged
npx lint-staged
# 或者运行类型检查
npm run type-check
# lint-staged - 暂存文件检查
只对 Git 暂存区的文件进行检查,提高检查速度。
# 安装
npm install -D lint-staged
// .lintstagedrc.js
module.exports = {
// JavaScript/TypeScript 文件的检查流程
// 对 Git 暂存区中的 .js、.jsx、.ts、.tsx 文件执行以下命令
'*.{js,jsx,ts,tsx}': [
'eslint --fix', // 1. 运行 ESLint 并自动修复问题
'prettier --write' // 2. 使用 Prettier 格式化代码
],
// Vue 文件的检查流程
// Vue 文件需要同时检查脚本、样式和格式
'*.vue': [
'eslint --fix', // 1. 检查 Vue 文件中的 JavaScript/TypeScript(<script> 部分)
'stylelint --fix', // 2. 检查 Vue 文件中的样式(<style> 部分)
'prettier --write' // 3. 格式化整个 Vue 文件
],
// 样式文件的检查流程
// 对纯样式文件(.css、.scss、.less)执行检查
'*.{css,scss,less}': [
'stylelint --fix', // 1. 运行 Stylelint 并自动修复样式问题
'prettier --write' // 2. 格式化样式代码
],
// JSON、Markdown 等文件的格式化
// 这些文件只需要格式化,不需要 lint 检查
'*.{json,md}': [
'prettier --write' // 使用 Prettier 统一格式
],
// TypeScript 类型检查(可选,建议在 CI 中运行)
// 注意:类型检查会检查整个项目,不仅仅是暂存文件,可能较慢
'*.{ts,tsx}': [
() => 'tsc --noEmit' // 运行 TypeScript 类型检查(不生成文件,只检查类型)
]
}
或者使用 package.json:
{
"lint-staged": {
"*.{js,jsx,ts,tsx,vue}": [
"eslint --fix",
"prettier --write"
],
"*.{css,scss,vue}": [
"stylelint --fix",
"prettier --write"
]
}
}
# Commitlint - 提交信息规范
# 安装
npm install -D @commitlint/cli @commitlint/config-conventional
// commitlint.config.js
module.exports = {
// 继承 Conventional Commits 规范
// 这是业界广泛使用的提交信息规范(需要安装 @commitlint/config-conventional)
extends: ['@commitlint/config-conventional'],
// 自定义规则
rules: {
// 提交类型枚举:限制允许的提交类型
// [2, 'always', [...]] 表示:错误级别、何时应用、允许的值
'type-enum': [2, 'always', [
'feat', // 新功能(feature)
'fix', // 修复 bug
'docs', // 文档更新(documentation)
'style', // 代码格式调整(不影响功能,如空格、分号)
'refactor', // 重构(既不是新功能也不是修复 bug 的代码改动)
'perf', // 性能优化(performance)
'test', // 测试相关(添加或修改测试)
'chore', // 构建过程或辅助工具的变动(如修改构建脚本、更新依赖)
'revert' // 回退之前的提交
]],
// 类型必须小写
// 错误: 'Feat: add feature'
// 正确: 'feat: add feature'
'type-case': [2, 'always', 'lower-case'],
// 类型不能为空
// 错误: ': add feature'
// 正确: 'feat: add feature'
'type-empty': [2, 'never'],
// 主题(subject)不能为空
// 错误: 'feat:'
// 正确: 'feat: add feature'
'subject-empty': [2, 'never'],
// 主题不能以句号结尾
// 错误: 'feat: add feature.'
// 正确: 'feat: add feature'
'subject-full-stop': [2, 'never', '.'],
// 提交信息标题最大长度:100 个字符
// 超过会报错,建议保持简洁
'header-max-length': [2, 'always', 100]
}
}
# .husky/commit-msg
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
npx --no -- commitlint --edit $1
提交信息格式:
<type>(<scope>): <subject>
<body>
<footer>
示例:
feat(auth): add login functionality
- Implement JWT authentication
- Add login form validation
- Create auth store
Closes #123
# 完整的 Git Hooks 配置
# .husky/pre-commit
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
echo "🔍 Running pre-commit checks..."
# 运行 lint-staged
npx lint-staged
# 类型检查
echo "🔍 Type checking..."
npm run type-check || {
echo "❌ Type check failed"
exit 1
}
echo "✅ Pre-commit checks passed"
# .husky/commit-msg
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
echo "🔍 Validating commit message..."
npx --no -- commitlint --edit $1
# .husky/pre-push
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
echo "🔍 Running pre-push checks..."
# 运行测试
npm run test || {
echo "❌ Tests failed"
exit 1
}
echo "✅ Pre-push checks passed"
# 七、EditorConfig - 编辑器配置
# 什么是 EditorConfig
EditorConfig 是一个用于统一不同编辑器和 IDE 编码风格的配置文件。它可以让团队成员在使用不同编辑器(如 VS Code、WebStorm、Sublime Text、Vim 等)时保持一致的代码风格。
与 Prettier 的区别:
- EditorConfig:在编辑器层面生效,实时控制编辑器行为(如按 Tab 键时插入空格)
- Prettier:代码格式化工具,保存时或手动执行时格式化代码
- 配合使用:EditorConfig 控制编辑器基础行为,Prettier 负责最终的代码格式化
# 安装
大多数现代编辑器都内置或通过插件支持 EditorConfig:
VS Code:
# 安装 EditorConfig 插件
# 在扩展市场搜索 "EditorConfig for VS Code"
WebStorm / IntelliJ IDEA:
- 内置支持,无需额外安装
Sublime Text:
# 通过 Package Control 安装 EditorConfig 插件
# 配置文件详解
# .editorconfig
# root = true 表示这是项目的根配置文件,编辑器会停止向上查找其他 .editorconfig 文件
root = true
# [*] 表示对所有文件生效(通配符)
[*]
# 字符编码:使用 UTF-8 编码
# 确保中文、emoji 等字符正确显示
charset = utf-8
# 换行符类型:使用 LF(\n)换行
# lf = Linux/macOS 风格(推荐,Git 默认)
# crlf = Windows 风格(\r\n)
# cr = 旧 macOS 风格(\r)
end_of_line = lf
# 文件末尾插入空行
# true = 文件最后一行是空行(符合 POSIX 标准,某些工具需要)
insert_final_newline = true
# 删除行尾空格
# true = 自动删除每行末尾的空格和 Tab(避免无意义的 diff)
trim_trailing_whitespace = true
# [*.{...}] 表示对特定文件类型生效
# 针对 JavaScript、TypeScript、Vue 文件
[*.{js,jsx,ts,tsx,vue}]
# 缩进风格:使用空格缩进
# space = 空格
# tab = 制表符(Tab)
indent_style = space
# 缩进大小:2 个空格
# 也可以设置为 4(根据团队习惯)
indent_size = 2
# 针对样式文件
[*.{css,scss,less}]
indent_style = space
indent_size = 2
# 针对配置文件
[*.{json,yml,yaml}]
indent_style = space
indent_size = 2
# 针对 Markdown 文件
[*.md]
# Markdown 中行尾空格有特殊含义(两个空格表示换行)
# 所以不删除行尾空格
trim_trailing_whitespace = false
# 针对 Makefile
# Makefile 必须使用 Tab 缩进(语法要求)
[Makefile]
indent_style = tab
# 支持的配置选项
EditorConfig 支持以下常用配置项:
| 配置项 | 说明 | 可选值 |
|---|---|---|
indent_style | 缩进风格 | space(空格)、tab(制表符) |
indent_size | 缩进大小 | 数字(如 2、4) |
tab_width | Tab 字符显示宽度 | 数字(默认与 indent_size 相同) |
end_of_line | 换行符类型 | lf、crlf、cr |
charset | 字符编码 | utf-8、utf-16be、utf-16le、latin1 |
trim_trailing_whitespace | 删除行尾空格 | true、false |
insert_final_newline | 文件末尾插入空行 | true、false |
max_line_length | 最大行长度 | 数字或 off |
# 最佳实践
项目初期就创建
.editorconfig- 避免后期大量修改缩进、换行符等带来的 diff 混乱
保持简洁
- 只配置必要的选项(缩进、换行符、编码)
- 其他复杂规则交给 Prettier 和 ESLint
与团队达成一致
- EditorConfig 配置应该是团队共识
- 不要随意修改已有配置(会影响整个代码库)
提交到版本控制
git add .editorconfig git commit -m "chore: add EditorConfig"在 README 中说明
## 开发环境配置 本项目使用 EditorConfig 统一编码风格,请确保你的编辑器已安装 EditorConfig 插件: - **VS Code**: 安装 "EditorConfig for VS Code" 扩展 - **WebStorm**: 内置支持,无需安装 - **Sublime Text**: 通过 Package Control 安装 EditorConfig 插件
# 八、编辑器集成
# VS Code 配置
# 推荐插件
// .vscode/extensions.json
{
"recommendations": [
"dbaeumer.vscode-eslint",
"esbenp.prettier-vscode",
"stylelint.vscode-stylelint",
"editorconfig.editorconfig",
"vue.volar"
]
}
# 工作区配置
// .vscode/settings.json
{
// ===== 编辑器 =====
"editor.formatOnSave": true,
"editor.codeActionsOnSave": {
"source.fixAll.eslint": "explicit",
"source.fixAll.stylelint": "explicit"
},
"editor.defaultFormatter": "esbenp.prettier-vscode",
// ===== ESLint =====
"eslint.validate": [
"javascript",
"javascriptreact",
"typescript",
"typescriptreact",
"vue"
],
"eslint.codeActionsOnSave.rules": null,
// ===== Stylelint =====
"stylelint.validate": [
"css",
"scss",
"vue"
],
"css.validate": false,
"scss.validate": false,
// ===== Prettier =====
"prettier.enable": true,
"prettier.requireConfig": true,
// ===== 文件关联 =====
"files.associations": {
"*.css": "css",
"*.scss": "scss"
},
// ===== Vue =====
"[vue]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
// ===== TypeScript =====
"[typescript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[typescriptreact]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
}
}
# WebStorm / IntelliJ IDEA 配置
启用 ESLint:
Settings→Languages & Frameworks→JavaScript→Code Quality Tools→ESLint- 勾选
Automatic ESLint configuration - 勾选
Run eslint --fix on save
启用 Prettier:
Settings→Languages & Frameworks→JavaScript→Prettier- 设置 Prettier 包路径
- 勾选
On save
启用 Stylelint:
Settings→Languages & Frameworks→Style Sheets→Stylelint- 勾选
Enable
# 九、CI/CD 集成
# GitHub Actions
# .github/workflows/lint.yml
name: Lint
on:
push:
branches: [main, develop]
pull_request:
branches: [main, develop]
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: Run Prettier check
run: npm run format:check
- name: Run Stylelint
run: npm run lint:style
- name: Type check
run: npm run type-check
- name: Run tests
run: npm run test
# GitLab CI
# .gitlab-ci.yml
stages:
- lint
- test
lint:
stage: lint
image: node:18
cache:
paths:
- node_modules/
script:
- npm ci
- npm run lint
- npm run format:check
- npm run lint:style
- npm run type-check
only:
- merge_requests
- main
# 十、最佳实践总结
# 1. 渐进式采用
# 第一步:基础配置
npm install -D eslint prettier
# 第二步:框架支持
npm install -D eslint-plugin-vue
# 第三步:TypeScript
npm install -D @typescript-eslint/parser @typescript-eslint/eslint-plugin
# 第四步:样式检查
npm install -D stylelint
# 第五步:Git Hooks
npm install -D husky lint-staged
# 2. 团队规范
- 统一配置:将所有配置文件提交到代码仓库
- 文档化:在 README 中说明如何使用
- CI 检查:在 CI/CD 中强制执行检查
- 定期更新:保持工具和规则的更新
# 3. 性能优化
- 使用
.eslintignore和.prettierignore排除不需要检查的文件 lint-staged只检查暂存文件- 避免在 Git Hooks 中运行耗时的全局类型检查
- 使用缓存加速 ESLint(
--cache选项)
# 4. 规则制定
- 从宽松到严格:初期使用
warn,逐步改为error - 团队协商:规则应由团队共同决定
- 持续改进:根据实际情况调整规则
- 有理有据:每条自定义规则都应有明确的原因
# 5. 工具选择
| 场景 | 推荐工具 |
|---|---|
| 代码规范 | ESLint |
| 代码格式化 | Prettier |
| 类型检查 | TypeScript |
| 样式规范 | Stylelint |
| 提交规范 | Commitlint |
| Git Hooks | Husky + lint-staged |
# 十一、学习资源
# 官方文档
- ESLint 官方文档 (opens new window)
- Prettier 官方文档 (opens new window)
- TypeScript 官方文档 (opens new window)
- Stylelint 官方文档 (opens new window)
- Husky 官方文档 (opens new window)
# 推荐资源
- Awesome ESLint (opens new window)
- ESLint 规则速查 (opens new window)
- TypeScript ESLint (opens new window)
- Airbnb JavaScript Style Guide (opens new window)
# 相关文章
祝你变得更强!