在前端 Vue 项目中,利用 Git 的 pre-commit 钩子,结合 Prettier、ESLint 和 Stylelint 实现代码提交时的自动格式化和修复,并包含自定义规则的校验。
核心流程概览:
- 环境准备: 确保 Node.js 和 npm/yarn 环境,以及一个 Vue 项目。
- 安装依赖: 安装 Prettier, ESLint, Stylelint 及其相关插件和配置。
- 配置 Prettier: 定义代码格式化规则。
- 配置 ESLint: 定义 JavaScript/Vue 脚本部分的规范,集成 Prettier,添加自定义规则。
- 配置 Stylelint: 定义 CSS/SCSS/Less 等样式部分的规范,集成 Prettier,添加自定义规则。
- 安装与配置 Husky: 用于管理 Git 钩子。
- 安装与配置 lint-staged: 用于仅对 Git 暂存区的文件执行 Linter 和 Formatter。
- 整合配置: 在
lint-staged中配置 Prettier, ESLint, Stylelint 的执行命令。 - 测试: 尝试提交代码,验证钩子是否生效。
详细步骤与代码讲解
第一步:环境准备
确保你的开发环境已经安装了 Node.js (建议 LTS 版本) 和 npm 或 yarn。同时,你需要一个 Vue 项目。如果还没有,可以使用 Vue CLI 或 Vite 创建一个:
# 使用 Vue CLI
# npm install -g @vue/cli
# vue create my-vue-app
# 或者使用 Vite
# npm create vite@latest my-vue-app -- --template vue
# cd my-vue-app
# npm install # 或者 yarn install
第二步:安装开发依赖
我们需要安装一系列的开发依赖项。
# 使用 npm
npm install --save-dev \
prettier \
eslint eslint-plugin-vue @vue/eslint-config-prettier @babel/eslint-parser \
stylelint stylelint-config-standard-vue stylelint-config-prettier postcss-html \
husky lint-staged
# 或者使用 yarn
yarn add --dev \
prettier \
eslint eslint-plugin-vue @vue/eslint-config-prettier @babel/eslint-parser \
stylelint stylelint-config-standard-vue stylelint-config-prettier postcss-html \
husky lint-staged
# 如果你的项目使用 TypeScript,还需要安装:
# npm install --save-dev @typescript-eslint/parser @typescript-eslint/eslint-plugin @vue/eslint-config-typescript
# yarn add --dev @typescript-eslint/parser @typescript-eslint/eslint-plugin @vue/eslint-config-typescript
依赖说明:
prettier: 核心代码格式化工具。eslint: JavaScript 和 Vue<script>部分的 Linter。eslint-plugin-vue: ESLint 官方推荐的 Vue.js 插件,提供 Vue 特定的 linting 规则。@vue/eslint-config-prettier: (Vue CLI 创建项目时可能已包含) 关闭eslint-plugin-vue中与 Prettier 冲突的规则。注意: 现在更推荐直接使用eslint-config-prettier并确保它在extends数组的最后。我们后面会用eslint-config-prettier。eslint-config-prettier: (替代@vue/eslint-config-prettier) 关闭 ESLint 核心和各种插件(如eslint-plugin-vue,@typescript-eslint/eslint-plugin)中与 Prettier 冲突的所有格式化相关规则。@babel/eslint-parser: (如果不用 TypeScript) 一个 ESLint 解析器,允许 ESLint lint 所有有效的 Babel 代码。对于现代 JS 语法和 Vue 项目很有用。如果你用了@vue/cli-plugin-babel,它通常是默认的。stylelint: CSS, SCSS, Less, 以及 Vue<style>部分的 Linter。stylelint-config-standard-vue: 适用于 Vue 单文件组件的 Stylelint 标准配置,它内部包含了stylelint-config-standard并添加了对 Vue SFC 的支持。stylelint-config-prettier: 关闭 Stylelint 中与 Prettier 冲突的规则。postcss-html: 让 Stylelint 能够解析.vue,.html文件中的<style>标签内容。husky: Git Hooks 管理工具,简化钩子脚本的创建和维护。lint-staged: 在 Git 暂存文件上运行 linters/formatters 的工具,避免对整个项目进行检查,提高效率。- (可选 TypeScript)
@typescript-eslint/parser: 允许 ESLint lint TypeScript 代码。 - (可选 TypeScript)
@typescript-eslint/eslint-plugin: 提供 TypeScript 特定的 linting 规则。 - (可选 TypeScript)
@vue/eslint-config-typescript: (Vue CLI 创建项目时可能已包含) 结合了 Vue 和 TypeScript 的 ESLint 基础配置。
第三步:配置 Prettier
在项目根目录下创建 .prettierrc.js (或 .prettierrc.json, .prettierrc.yaml 等) 文件。
// .prettierrc.js
// 访问 https://prettier.io/docs/en/options.html 查看所有选项
module.exports = {
// 每行最大字符数
printWidth: 100,
// tab宽度为2空格
tabWidth: 2,
// 是否使用tab替代空格
useTabs: false,
// 结尾是否添加分号
semi: true,
// 是否使用单引号
singleQuote: true,
// 对象属性的引号使用:'as-needed' | 'consistent' | 'preserve'
quoteProps: 'as-needed',
// JSX中使用单引号
jsxSingleQuote: false,
// 多行时尽可能打印尾随逗号 'none' | 'es5' | 'all'
trailingComma: 'es5', // 在ES5中有效的结尾逗号(对象、数组等), 'all' 包括函数参数
// 对象前后添加空格 { foo: bar }
bracketSpacing: true,
// JSX标签闭合括号是否换行
// <button
// className="prettier-class"
// id="prettier-id"
// onClick={this.handleClick}>
// Click Here
// </button>
// false:
// <button
// className="prettier-class"
// id="prettier-id"
// onClick={this.handleClick}
// >
// Click Here
// </button>
bracketSameLine: false, // 在jsx中把'>' 是否单独放一行, 旧版叫 jsxBracketSameLine
// 箭头函数参数是否总是带括号 'always' | 'avoid'
arrowParens: 'always',
// Range 相关,通常不需要改
// rangeStart: 0,
// rangeEnd: Infinity,
// 解析器推断,通常不需要指定
// parser: undefined,
// 文件路径,通常不需要指定
// filepath: undefined,
// 是否需要在文件开头插入 @format pragma
requirePragma: false,
// 是否在已被 Prettier 格式化的文件顶部插入 @format pragma
insertPragma: false,
// Markdown 处理方式 'always' | 'never' | 'preserve'
proseWrap: 'preserve',
// HTML 空白敏感度 'css' | 'strict' | 'ignore'
htmlWhitespaceSensitivity: 'css',
// Vue 文件脚本和样式标签缩进
vueIndentScriptAndStyle: false,
// 行尾换行符 'lf' | 'crlf' | 'cr' | 'auto'
endOfLine: 'lf',
// 是否格式化嵌入式语言 'auto' | 'off'
embeddedLanguageFormatting: 'auto',
// 单个属性换行时,是否将属性放在单独的行上
singleAttributePerLine: false, // Vue/JSX中单个属性是否独占一行
};
同时,创建 .prettierignore 文件,告诉 Prettier 忽略哪些文件或目录:
# .prettierignore
# 忽略编译后的目录
/dist
/node_modules
# 忽略特定的配置文件 (如果它们不应该被格式化)
# /public
# /coverage
# 忽略自动生成的文件
# yarn.lock
# package-lock.json
# 特定类型的文件
*.svg
*.min.js
*.min.css
第四步:配置 ESLint
在项目根目录下创建 .eslintrc.js 文件。
// .eslintrc.js
module.exports = {
// 指定脚本运行环境,支持的全局变量
env: {
browser: true, // 浏览器环境
es2021: true, // 支持 ES2021 语法
node: true, // Node.js 环境
'vue/setup-compiler-macros': true, // 为了支持 <script setup> 中的 defineProps/defineEmits 等宏
},
// 继承的配置,后面的会覆盖前面的
extends: [
// Vue 推荐的规则集 (包含 base, essential, strongly-recommended, recommended)
'plugin:vue/vue3-recommended', // 或 'plugin:vue/essential', 'plugin:vue/strongly-recommended' 根据项目需求选择
// ESLint 推荐的基础规则
'eslint:recommended',
// 如果使用 TypeScript,取消注释下面这行,并确保安装了 @vue/eslint-config-typescript
// '@vue/eslint-config-typescript/recommended', // 注意:这通常会包含 @typescript-eslint/recommended
// 关键:放在最后,用于关闭与 Prettier 冲突的 ESLint 规则
'prettier', // 使用 eslint-config-prettier 关闭冲突规则 (需要 npm install --save-dev eslint-config-prettier)
// 如果你使用的 Vue 配置(如 @vue/eslint-config-xxx)没有自动包含 prettier,则需要显式添加
],
// 指定 ESLint 解析器
// 对于普通 JavaScript 或 Vue 项目中的 <script>(未使用 TypeScript)
parser: 'vue-eslint-parser', // 必须使用 vue-eslint-parser 来解析 .vue 文件
parserOptions: {
ecmaVersion: 'latest', // 使用最新的 ECMAScript 标准
sourceType: 'module', // 支持模块化
// 如果使用 @babel/eslint-parser 作为 JS 解析器 (vue-eslint-parser 内部会调用它)
parser: '@babel/eslint-parser',
requireConfigFile: false, // 如果没有 Babel 配置文件,需要设置为 false
babelOptions: {
// 如果需要,可以在这里指定 Babel 插件或预设
// presets: ["@babel/preset-env"],
},
// 如果项目使用 TypeScript,需要替换 parser 和添加 parserOptions.parser
// parser: 'vue-eslint-parser',
// parserOptions: {
// parser: '@typescript-eslint/parser', // 让 vue-eslint-parser 使用 TS 解析器
// ecmaVersion: 'latest',
// sourceType: 'module',
// jsxPragma: 'React',
// ecmaFeatures: {
// jsx: true
// },
// // 如果 tsconfig.json 不在根目录,需要指定路径
// // project: './tsconfig.json',
// // extraFileExtensions: ['.vue'], // 确保能解析 .vue 文件中的 TS
// },
},
// 使用的插件列表
plugins: [
'vue',
// 如果使用 TypeScript,取消注释下面这行
// '@typescript-eslint',
// 可选:如果你想用 eslint-plugin-prettier 来报告 Prettier 格式问题作为 ESLint 错误(通常不推荐,因为 Prettier 自动格式化更好)
// 'prettier'
],
// 自定义规则 (会覆盖 extends 中的规则)
// "off" 或 0 - 关闭规则
// "warn" 或 1 - 开启规则,使用警告级别的错误:warn (不会导致程序退出)
// "error" 或 2 - 开启规则,使用错误级别的错误:error (当被触发的时候,程序会退出)
rules: {
// === Prettier 兼容性 ===
// 如果使用了 eslint-plugin-prettier (不推荐与自动修复同时使用,因为 Prettier 会修复)
// 'prettier/prettier': 'warn', // 将 Prettier 问题报告为 ESLint 警告
// === ESLint 核心规则自定义 ===
'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off', // 生产环境禁止 console,开发环境允许
'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off', // 生产环境禁止 debugger
'no-unused-vars': ['warn', { argsIgnorePattern: '^_' }], // 未使用的变量警告,忽略以下划线开头的参数
'no-undef': 'error', // 禁止使用未定义的变量
'semi': ['error', 'always'], // 必须使用分号
'quotes': ['error', 'single'], // 必须使用单引号
'comma-dangle': ['error', 'always-multiline'], // 多行时必须使用尾随逗号
// === Vue 相关规则自定义 (基于 'plugin:vue/vue3-recommended') ===
'vue/html-indent': ['error', 2], // Vue 模板缩进为 2 空格
'vue/max-attributes-per-line': ['warn', {
singleline: 3, // 单行最多 3 个属性
multiline: 1, // 多行时每行 1 个属性
}],
'vue/singleline-html-element-content-newline': 'off', // 关闭单行 HTML 元素内容强制换行
'vue/multiline-html-element-content-newline': 'off', // 关闭多行 HTML 元素内容强制换行
'vue/html-self-closing': ['error', {
html: {
void: 'always', // 对于没有内容的 HTML 标签(如 <br>)总是自闭合
normal: 'never', // 对于普通 HTML 标签(如 <div>)从不自闭合
component: 'always', // 对于 Vue 组件总是自闭合
},
svg: 'always',
math: 'always',
}],
'vue/no-v-html': 'warn', // 警告使用 v-html,防止 XSS 攻击,根据需要调整
'vue/attribute-hyphenation': ['error', 'always'], // 组件 prop 和 HTML 属性名使用 kebab-case
'vue/component-name-in-template-casing': ['error', 'kebab-case', {
registeredComponentsOnly: false // 对所有组件标签应用 kebab-case
}],
'vue/v-on-event-hyphenation': ['error', 'always', { // v-on 事件名使用 kebab-case
autofix: true, // 启用自动修复
}],
'vue/custom-event-name-casing': ['error', 'kebab-case'], // 自定义事件名使用 kebab-case
'vue/no-unused-components': 'warn', // 未使用的组件警告
'vue/no-unused-vars': 'warn', // Vue 模板中未使用的变量警告 (作用域变量)
// === 自定义规则示例 ===
// 强制组件的 name 选项必须设置 (对于调试和 DevTools 很有用)
'vue/require-name-property': 'error',
// 限制每个文件的代码行数 (示例,可能过于严格)
// 'max-lines': ['warn', { max: 500, skipBlankLines: true, skipComments: true }],
// 限制函数复杂度 (示例)
// 'complexity': ['warn', 10],
// === 如果使用 TypeScript,可以添加 TS 相关规则 ===
// '@typescript-eslint/no-unused-vars': ['warn', { argsIgnorePattern: '^_' }],
// '@typescript-eslint/explicit-function-return-type': 'off', // 通常关闭,除非需要强制返回类型
// '@typescript-eslint/no-explicit-any': 'warn', // 警告使用 any 类型
},
// 全局变量声明
globals: {
// 如果使用了 defineProps, defineEmits 等编译器宏 (env 中已配置 'vue/setup-compiler-macros': true)
// defineProps: 'readonly',
// defineEmits: 'readonly',
// defineExpose: 'readonly',
// withDefaults: 'readonly',
// 如果有其他全局变量,在这里声明
// myGlobalVar: 'readonly',
},
// 文件忽略配置(也可以使用 .eslintignore 文件)
ignorePatterns: [
'node_modules/',
'dist/',
'public/',
'*.min.js',
'*.md',
// 其他需要忽略的文件或目录
],
};
说明:
env: 定义了代码运行的环境,ESLint 会据此预设一些全局变量 (如window,documentforbrowser,require,modulefornode)。extends: 继承预设的规则集。顺序很重要,后面的配置会覆盖前面的。prettier必须放在最后,以确保它能覆盖掉所有可能与 Prettier 冲突的格式化规则。parser: 指定解析器。vue-eslint-parser用于解析.vue文件,它内部可以配置使用哪个 JS/TS 解析器来解析<script>标签。parserOptions: 配置解析器的选项。plugins: 加载 ESLint 插件。rules: 自定义或覆盖规则。这里我们添加了一些常用的 ESLint 核心规则和 Vue 相关规则的自定义配置,并展示了如何添加完全自定义的规则。你可以根据团队规范调整。globals: 声明不需要import或require就能使用的全局变量。ignorePatterns: 定义 ESLint 应忽略的文件或目录,效果同.eslintignore文件。
第五步:配置 Stylelint
在项目根目录下创建 .stylelintrc.js 文件。
// .stylelintrc.js
module.exports = {
// 继承的配置
extends: [
// Stylelint 标准规则集,包含了许多最佳实践规则
// 'stylelint-config-standard', // stylelint-config-standard-vue 已经包含了它
// 适用于 Vue 的 Stylelint 配置,处理 <style> 标签和 .vue 文件
'stylelint-config-standard-vue', // 需要 npm install --save-dev stylelint-config-standard-vue
// 关键:放在最后,用于关闭与 Prettier 冲突的 Stylelint 规则
'stylelint-config-prettier', // 需要 npm install --save-dev stylelint-config-prettier
],
// 使用的插件 (如果有需要)
// plugins: [
// 'stylelint-order', // 例如,强制属性排序
// ],
// 解析 .vue 文件中的 <style> 标签
// `stylelint-config-standard-vue` 通常会自动处理这个,但显式指定有时更清晰
// 注意: postcss-html 是必须的,我们已经安装了
overrides: [
{
files: ['**/*.vue'],
customSyntax: 'postcss-html', // 指定解析 .vue 文件的语法
},
// 如果你还用 SCSS 或 Less
// {
// files: ["**/*.scss"],
// customSyntax: "postcss-scss" // 需要 npm install --save-dev postcss-scss
// },
// {
// files: ["**/*.less"],
// customSyntax: "postcss-less" // 需要 npm install --save-dev postcss-less
// }
],
// 自定义规则
rules: {
// === Stylelint 核心规则自定义 ===
'selector-class-pattern': null, // 不强制类名选择器的模式 (例如 BEM),根据需要设置,例如:'^[a-z]([a-z0-9-]+)?(__([a-z0-9]+-?)+)?(--([a-z0-9]+-?)+){0,2}$'
'selector-pseudo-class-no-unknown': [true, { ignorePseudoClasses: ['deep', 'global'] }], // 忽略 Vue 的 :deep 和 :global
'selector-pseudo-element-no-unknown': [true, { ignorePseudoElements: ['v-deep', 'v-global', 'v-slotted'] }], // 忽略 Vue 的 ::v-deep 等
'at-rule-no-unknown': [true, { ignoreAtRules: ['tailwind', 'apply', 'variants', 'responsive', 'screen', 'layer'] }], // 忽略 Tailwind CSS 的 @ 指令
'rule-empty-line-before': ['always', { // 在规则之前总是需要空行(除了第一个规则和在@规则块内的规则)
except: ['first-nested'],
ignore: ['after-comment'],
}],
'unit-no-unknown': true, // 禁止未知的单位
'block-no-empty': true, // 禁止空块
'no-descending-specificity': null, // 允许特异性较低的选择器出现在较高的选择器之后 (有时难以避免)
'font-family-no-missing-generic-family-keyword': null, // 不强制要求字体族必须有通用族关键字 (如 sans-serif)
// === Vue (<style scoped>) 相关规则 (通常由 stylelint-config-standard-vue 处理) ===
// 确保 scoped 样式中的选择器是有效的
// === 自定义规则示例 ===
// 颜色值必须使用小写十六进制或 rgb/rgba
'color-hex-case': 'lower',
'color-function-notation': 'legacy', // 使用旧版逗号分隔的 rgb()/rgba() 而不是现代空格分隔的语法,根据兼容性需求选择 'modern'
// 禁止使用 ID 选择器
'selector-max-id': 0,
// 限制选择器的嵌套深度
'max-nesting-depth': [3, { ignore: ['pseudo-classes'] }], // 嵌套深度最多 3 层,忽略伪类
// 禁止使用 !important
'declaration-no-important': true,
// === 如果使用 stylelint-order 插件 ===
// 'order/properties-order': [ // 定义 CSS 属性的书写顺序
// 'position',
// 'top',
// 'right',
// 'bottom',
// 'left',
// 'z-index',
// 'display',
// // ... 更多属性
// ],
},
// 忽略文件配置 (也可以使用 .stylelintignore 文件)
ignoreFiles: [
'node_modules/**/*',
'dist/**/*',
'public/**/*',
'*.min.css',
'*.md',
// 其他需要忽略的文件
],
// 默认严重性级别 ("warning" 或 "error")
defaultSeverity: 'error',
};
说明:
extends: 同样,继承预设配置,stylelint-config-prettier放在最后。stylelint-config-standard-vue是关键,它为 Vue SFC 的<style>提供了良好的基础。overrides: 针对特定文件类型应用不同的配置,特别是为.vue文件指定customSyntax: 'postcss-html',这样 Stylelint 才能正确解析<style>块。如果使用 SCSS/Less,也需要类似配置并安装对应的postcss-scss或postcss-less。rules: 自定义规则。这里添加了一些常用的自定义项,比如放宽类名模式、忽略 Vue 特定的伪类/伪元素、忽略 Tailwind 指令、设置颜色格式、禁止 ID 选择器、限制嵌套深度等。ignoreFiles: 忽略文件。defaultSeverity: 设置违反规则时的默认严重级别。
第六步:安装与配置 Husky
Husky 能让我们更容易地管理 Git 钩子。
-
初始化 Husky:
npx husky init npm install # 或者 yarn install (如果 husky init 没有自动安装) # 或者 (旧版方式,或手动安装后) # npx husky install # 在 CI 环境或首次设置后可能需要这会在项目根目录创建一个
.husky文件夹,并在package.json中添加prepare脚本(用于在npm install后自动启用 Husky 钩子)。 -
创建 pre-commit 钩子:
npx husky add .husky/pre-commit "npx lint-staged"这会创建一个名为
pre-commit的文件在.husky目录下,内容大致如下:#!/usr/bin/env sh . "$(dirname -- "$0")/_/husky.sh" npx lint-staged这个脚本会在每次执行
git commit命令之前运行npx lint-staged命令。
第七步:安装与配置 lint-staged
lint-staged 的作用是只对 Git 暂存区(git add 之后的文件)执行我们定义的命令,这样可以大大加快提交前的检查速度。
在 package.json 文件中添加 lint-staged 配置项,或者在根目录创建 .lintstagedrc.js (或 .lintstagedrc.json 等) 文件。推荐使用 package.json:
// package.json
{
// ... 其他配置如 name, version, scripts, dependencies ...
"devDependencies": {
// ... 你安装的所有开发依赖 ...
},
"scripts": {
// ... 其他脚本如 serve, build ...
"lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs --fix && stylelint "**/*.{vue,css,scss,less}" --fix",
"format": "prettier --write "**/*.{vue,js,jsx,cjs,mjs,ts,tsx,json,css,scss,less,html,md}""
// "prepare": "husky install" // husky init 应该已经自动添加了这个
},
// lint-staged 配置
"lint-staged": {
// 对所有暂存的指定类型文件,先执行 Prettier 格式化
"*.{vue,js,jsx,cjs,mjs,ts,tsx,json,css,scss,less,html,md}": [
"prettier --write"
],
// 对暂存的 .vue, .js 文件执行 ESLint 检查和自动修复
// 注意:ESLint 应该在 Prettier 格式化之后运行
"*.{vue,js,jsx,cjs,mjs}": [
"eslint --fix"
],
// 如果使用 TypeScript
// "*.{vue,ts,tsx}": [
// "eslint --fix"
// ],
// 对暂存的样式相关文件执行 Stylelint 检查和自动修复
// 注意:Stylelint 也应该在 Prettier 之后运行
"*.{vue,css,scss,less}": [
"stylelint --fix"
]
// 如果你的命令很复杂或者需要链式操作失败则停止,可以这样写:
// "*.{js,vue}": [
// "prettier --write",
// "eslint --fix",
// "git add" // 可选:如果修复后需要重新暂存,但 lint-staged 默认会处理
// ]
}
}
说明:
-
我们在
package.json中添加了lint和format脚本,方便手动执行全项目的检查和格式化。 -
lint-staged配置是一个对象,键是匹配文件模式的 glob 表达式,值是一个数组,包含要在匹配文件上执行的命令。 -
执行顺序很重要:
- 先运行
prettier --write对所有相关类型的文件进行格式化。这样可以确保 ESLint 和 Stylelint 检查的是已经被 Prettier 格式化后的代码,避免它们因为格式问题报错。 - 然后运行
eslint --fix对 JS/Vue 文件进行 linting 和自动修复。 - 最后运行
stylelint --fix对样式文件 (包括 Vue 文件中的<style>) 进行 linting 和自动修复。
- 先运行
-
lint-staged会自动处理命令执行和文件暂存。如果一个命令失败(例如 ESLint 发现无法自动修复的错误),lint-staged会退出,阻止git commit继续执行。修复错误后,你需要重新git add文件,然后再次尝试git commit。
第八步:整合配置(检查)
现在,我们已经完成了所有工具的安装和配置。检查一下:
.prettierrc.js定义了格式化规则。.eslintrc.js定义了 JS/Vue 的 linting 规则,继承了推荐配置,关闭了与 Prettier 的冲突,并添加了自定义规则。.stylelintrc.js定义了样式的 linting 规则,继承了推荐配置 (Vue 适用),关闭了与 Prettier 的冲突,配置了.vue文件解析,并添加了自定义规则。.husky/pre-commit脚本已存在,内容是npx lint-staged。package.json中有lint-staged配置,指定了对暂存文件依次运行 Prettier, ESLint, Stylelint 的修复命令。
第九步:测试
现在,尝试修改项目中的一些 .vue, .js, 或样式文件,故意引入一些不符合规范的代码(比如:使用双引号、忘记分号、错误的缩进、不符合自定义规则的代码、无效的 CSS 属性等)。
然后执行:
git add . # 将修改的文件添加到暂存区
git commit -m "feat: add feature with auto formatting and linting test"
观察终端输出:
- 你应该能看到
lint-staged正在运行 Prettier, ESLint, Stylelint。 - 如果代码有可以自动修复的格式问题或 linting 问题,这些工具会尝试修复它们。修复后的文件会自动被
lint-staged重新添加到暂存区。 - 如果修复成功且没有其他无法自动修复的错误,commit 会成功。
- 如果存在无法自动修复的 ESLint 或 Stylelint 错误(规则设置为
error),lint-staged会报错,commit 会被阻止。你需要根据错误提示手动修改代码,然后再次git add和git commit。
示例:触发自定义规则
假设你在 .eslintrc.js 中添加了规则 'vue/require-name-property': 'error'。现在创建一个没有 name 选项的 Vue 组件:
<template>
<div>Hello</div>
</template>
<script>
export default {
// Missing name property
props: {
msg: String,
},
};
</script>
<style scoped>
div {
color: blue; /* 符合 Stylelint 规则 */
}
</style>
当你尝试提交这个文件时 (git add src/components/MyComponent.vue && git commit -m "test"), ESLint 会因为违反了 vue/require-name-property 规则而报错,commit 会失败。你需要添加 name 属性才能成功提交。
总结与后续
通过以上步骤,你已经成功地在 Vue 项目中配置了一个强大的 pre-commit 工作流。每次提交代码时,Husky 会触发 lint-staged,后者会智能地对你修改并暂存的文件执行 Prettier 格式化、ESLint 检查与修复、Stylelint 检查与修复。这不仅保证了代码风格的统一,还能在早期发现并修复潜在的错误,极大地提高了代码质量和团队协作效率。
你可以根据项目的具体需求和团队规范,随时调整 .prettierrc.js, .eslintrc.js, .stylelintrc.js 中的规则。记住,良好的配置需要持续维护和根据项目演进进行调整。