@vue/cli-plugin-eslint:为 Vue CLI 项目接入 ESLint 代码规范检查与自动修复
@vue/cli-plugin-eslint:为 Vue CLI 项目接入 ESLint 代码规范检查与自动修复
本文基于 vue-cli 仓库中 docs/ru/core-plugins/eslint.md 与 docs/core-plugins/eslint.md 整理而成,并结合 @vue/cli-plugin-eslint 包源码进行深度印证。文章面向使用 Vue CLI 5 创建项目的开发者,讲解如何通过
@vue/cli-plugin-eslint为项目注入vue-cli-service lint命令、配置lintOnSave实现保存即检查,以及该插件的底层 webpack 集成原理,让读者能够完整掌握 Vue CLI 项目中 ESLint 的接入、配置与调优方法。
插件定位:vue-cli 的官方 ESLint 集成方案
@vue/cli-plugin-eslint 是 vue-cli 生态中负责代码规范检查(Linting)与自动修复(Auto-fix)的官方插件。它的核心职责可以概括为三件事:
- 在
vue create创建项目时或通过vue add eslint向已有项目注入一套完整的 ESLint 配置、依赖与 npm scripts; - 向
@vue/cli-service注册一条vue-cli-service lint命令,用于命令行批量检查与修复代码; - 通过 webpack 插件在开发服务器和构建流程中启用“保存即检查”(Lint-on-save),并可选地把检查结果以 overlay 形式呈现在浏览器中。
从包结构看(packages/@vue/cli-plugin-eslint/package.json),插件本身依赖 eslint-webpack-plugin、globby、yorkie(Git hooks 工具)与 @vue/cli-shared-utils,并以 eslint >= 7.5.0 作为 peer 依赖——也就是说,ESLint 本体并不由插件打包,而是安装在项目自己的依赖树中,用户完全可以根据需要锁定 ESLint 版本。
安装与初始化:两种接入路径
路径一:创建项目时选择
在 vue create 的交互式功能列表中勾选 Linter / Formatter 即可随项目脚手架一并安装。插件会以交互问题(prompts)的形式收集偏好,见 packages/@vue/cli-plugin-eslint/prompts.js:
- Pick an ESLint config(单选):
Error prevention only(base,仅做基础错误预防)、Airbnb、Standard、Prettier; - Pick additional lint features(多选):
Lint on save(保存时检查,默认勾选)与Lint and fix on commit(提交前检查修复,需要 Git 环境)。
选择结果会被写入 package.json:生成 lint: vue-cli-service lint 脚本、eslintConfig 配置块以及对应 preset 的 devDependencies,具体实现见 packages/@vue/cli-plugin-eslint/generator/index.js。
路径二:已有项目接入
原文档给出了一条命令即可完成向已有项目注入插件:
vue add eslint
vue add 会调用该插件的 generator,此时同样会弹出上述两个 prompts 让你选择配置预设与 lint 特性。源码中还有两个值得注意的细节:
- 若未勾选 “Lint on save”,generator 会在
package.json的vue字段中写入lintOnSave: false(见 generator/index.js); - 若勾选 “Lint and fix on commit”,会追加
lint-staged依赖,并通过yorkie写入gitHooks: { 'pre-commit': 'lint-staged' },同时根据插件支持的扩展名生成lint-staged匹配规则,例如*.{js,jsx,vue}对应的命令为vue-cli-service lint。
项目创建完成后,generator 还会以静默模式({ silent: true })自动执行一次 lint,把脚手架生成的代码统一修复为所选代码风格(见 generator/index.js 的 afterAnyInvoke hooks)。测试用例 eslintPlugin.spec.js 中即验证了 “airbnb 预设下自动补全分号、提交前 lint-staged 自动修复” 的完整链路。
注入命令:vue-cli-service lint 完全指南
安装插件后,项目即可使用 vue-cli-service lint 对源码进行批量检查与自动修复。原文档给出了命令的帮助信息:
Usage: vue-cli-service lint [options] [...files]
Options:
--format [formatter] 指定格式化器 (默认: stylish)
--no-fix 关闭自动修复
--max-errors 错误数达到该值则构建失败 (默认: 0)
--max-warnings 警告数达到该值则构建失败 (默认: Infinity)
在英文版文档中还有一条:
--output-file 指定报告输出文件
默认检查范围
如果不显式传入文件列表,vue-cli-service lint 默认检查:
src目录下的所有文件;tests目录下的所有文件;- 根目录下所有 JavaScript 文件——最常见的便是
babel.config.js、.eslintrc.js等配置文件。
这一默认行为对应源码 lint.js 中的 defaultFilesToLint 计算逻辑:依次对 src、tests、*.js、.*.js 四个模式进行 globby 匹配,并用 eslint.isPathIgnored() 过滤掉被忽略的目录,最终保留存在实际检查对象的模式。
关于点文件的提示(原文档 tip)
默认情况下 vue-cli-service lint 会检查形如 .*.js 的点文件。
如果想遵循 ESLint 的默认行为,请在项目中添加 .eslintignore 文件。
这一行为背后的原因值得说明:ESLint 默认会忽略点文件(dotfiles),但 Vue CLI 项目希望 babel.config.js 这类配置文件也能参与 lint 与自动修复,以保证默认脚手架生成的代码风格与用户选定的 ESLint 配置一致。因此在 lint.js 中,当项目不存在 .eslintignore 且用户未提供 --ignore-pattern 时,插件会向 overrideConfig.ignorePatterns 注入 !.*.js 与 !{src,tests}/**/.*.js 两条否定模式,把点文件“拉回”检查范围。一旦用户提供了自己的 .eslintignore,插件便不再注入自定义忽略规则(遵循最小惊讶原则)。
更多受支持的 ESLint CLI 选项
原文档提到该命令还支持其他 ESLint CLI 选项。从 lint.js 的 normalizeConfig 可以看出,这些 CLI 参数会被映射为 ESLint 的编程式配置,实际支持项包括:
| 命令行参数 | 映射目标 | 说明 |
|---|---|---|
--no-fix-warnings |
fixWarnings: false |
只修复错误、不修复警告 |
--ext [extensions] |
extensions |
指定待检查的文件扩展名列表(逗号分隔) |
--rulesdir [paths] |
rulePaths |
附加的规则目录 |
--plugin [name] |
overrideConfig.plugins |
追加 ESLint 插件 |
--ignore-pattern [pattern] |
overrideConfig.ignorePatterns |
追加忽略模式 |
--env [name:true/false] |
overrideConfig.env |
设置环境变量 |
--global [name:true/false] |
overrideConfig.globals |
设置全局变量 |
--rule [name:level] |
overrideConfig.rules |
覆盖规则级别 |
--inline-config |
allowInlineConfig |
是否允许行内注释配置 |
--eslintrc |
useEslintrc |
是否读取 .eslintrc 配置文件 |
-c / --config [file] |
overrideConfigFile |
指定配置文件 |
--output-file [file] |
outputFile |
将报告写入文件 |
命令执行流程与退出码
结合 lint.js 可以梳理出完整的执行链路:
- 通过
@vue/cli-shared-utils的loadModule从项目目录加载 ESLint(用户可自定义 ESLint 版本),失败时回退到插件自身安装的版本; - 以
cwd为项目根目录、fix: true为默认值构造ESLint实例配置; - 调用
eslint.lintFiles(files)批量检查; - 若指定了
--output-file,将格式化后的报告写入该文件; - 若开启了修复,调用
ESLint.outputFixes(resultResults)把可自动修复的结果写回磁盘,并列出已自动修复的文件; - 统计 errorCount 与 warningCount,与
--max-errors(默认 0)、--max-warnings(默认 Infinity)比较,超出阈值即exit(1)使命令以失败结束;否则输出No lint errors found!或All lint errors auto-fixed.。
需要注意:命令内部会临时将 process.cwd mock 为项目根目录再执行 lint,这是为了规避 eslint-plugin-import 等依赖 process.cwd() 解析路径的插件在 monorepo/子目录场景下的误判(对应 lint.js 及其中引用的 vuejs/vue-cli#2554 等 issue)。
ESLint 配置:从 .eslintrc 到脚手架生成的预设
原文档指出,ESLint 可通过项目根目录的 .eslintrc 文件或 package.json 中的 eslintConfig 字段进行配置,详细语法可参考 ESLint 官方配置文档。
插件默认生成的配置骨架
当通过 Vue CLI 脚手架创建项目时,generator 会调用 eslintOptions.js 中的 config() 生成 eslintConfig,其基础结构为:
{
root: true, // 停止向上级目录查找配置
env: { node: true }, // 启用 Node 环境全局变量
extends: ['plugin:vue/essential'],// Vue 官方推荐的必要规则
parserOptions: {
ecmaVersion: 2020
},
rules: {
'no-console': "process.env.NODE_ENV === 'production' ? 'warn' : 'off'",
'no-debugger': "process.env.NODE_ENV === 'production' ? 'warn' : 'off'"
}
}
其中 no-console 与 no-debugger 两条规则比较有 Vue CLI 特色:它们在开发环境完全关闭,仅在 production 构建时降级为 warning,避免误伤调试输出。
不同 preset 会进一步追加 extends 与解析器:
| 预设 | 追加的 extends | 额外说明 |
|---|---|---|
base(默认) |
eslint:recommended |
仅基础错误预防 |
airbnb |
@vue/airbnb |
需要 @vue/eslint-config-airbnb 等依赖 |
standard |
@vue/standard |
无分号风格 |
prettier |
eslint:recommended + plugin:prettier/recommended |
与 Prettier 格式化器协同 |
对应的依赖映射集中在 eslintDeps.js 的 DEPS_MAP 中,例如 base 预设安装 eslint@^7.32.0 与 eslint-plugin-vue@^8.0.3,airbnb 预设额外安装 @vue/eslint-config-airbnb 等。
与其他插件组合时的自动适配
config() 函数还处理了几种组合场景:
- 启用 Babel 且未启用 TypeScript:
parserOptions.parser设为@babel/eslint-parser,并自动安装@babel/core与@babel/eslint-parser依赖; - 启用 TypeScript:追加
@vue/typescript/recommended(Prettier 预设下会调整顺序以保证与 prettier 规则兼容),检查扩展名自动扩展为.js, .jsx, .vue, .ts, .tsx(见 eslintOptions.js 的extensions导出); - Vue 3 项目(
rootOptions.vueVersion === '3'):将plugin:vue/essential等规则集自动替换为plugin:vue/vue3-essential对应的 Vue 3 版本。
此外,ESLint 8 的迁移也由插件内置的 migrator 处理(migrator/index.js):老项目升级时,若检测到本地 ESLint 主版本小于等于 6,会自动把依赖提升到 ESLint v7、将 babel-eslint 替换为 @babel/eslint-parser,并修正 @vue/typescript 等旧式 extends 名称。
lintOnSave:开发期“保存即检查”的完整配置
原文档将 lintOnSave 归入 vue.config.js 的配置项,并强调:该选项只有在安装了 @vue/cli-plugin-eslint 时才会生效。
开发服务器中基于 eslint-loader(Vue CLI 5 实际已替换为 eslint-webpack-plugin,见下文“底层原理”)的保存即检查默认开启,可通过如下配置关闭:
// vue.config.js
module.exports = {
lintOnSave: false
}
三种取值的行为差异
原文档给出了关键的三档取值,结合 index.js 与 packages/@vue/cli-service/lib/options.js 的校验规则(合法值为 true | false | 'error' | 'warning' | 'default'),可以整理成如下对照:
| 取值 | 处理方式 | 编译是否失败 |
|---|---|---|
true(或 'warning') |
所有 lint 结果以 warning 形式发出,仅打印到终端 | 不失败(failOnError: false) |
'error' |
所有 lint 结果强制以 error 形式发出,并在浏览器 overlay 中展示 | 失败(failOnError: true、failOnWarning: true) |
false |
完全禁用 webpack 阶段的 lint | — |
'default' |
项目默认值 | — |
源码中的对应逻辑为:
const treatAllAsWarnings = lintOnSave === true || lintOnSave === 'warning'
const treatAllAsErrors = lintOnSave === 'error'
const failOnWarning = treatAllAsErrors
const failOnError = !treatAllAsWarnings
也就是说,lintOnSave: true 时 eslint-webpack-plugin 的 failOnError 被置为 false,所有问题只作为警告记录在终端日志中,不会中断热更新编译;而 lintOnSave: 'error' 时则完全相反。
浏览器 overlay 的精细化控制
当使用 lintOnSave: 'error' 让错误显示在浏览器中后,还可以通过 devServer.overlay 同时控制警告与错误的展示:
// vue.config.js
module.exports = {
devServer: {
overlay: {
warnings: true,
errors: true
}
}
}
生产构建时关闭 lint
lintOnSave 为真值时,eslint-webpack-plugin 在开发与生产构建中都会启用。如果只想在开发阶段做保存即检查、避免拖慢生产构建,可以结合环境变量:
// vue.config.js
module.exports = {
lintOnSave: process.env.NODE_ENV !== 'production'
}
底层原理:webpack 集成与缓存机制
原文档在结尾列出了插件注入的 webpack-chain 规则,这是理解插件工作方式的关键线索:
config.module.rule('eslint')config.module.rule('eslint').use('eslint-loader')
需要说明的是:文档撰写时插件基于 eslint-loader 注入规则;在 Vue CLI 5 的当前实现中,插件已改用 eslint-webpack-plugin(见 packages/@vue/cli-plugin-eslint/package.json 的 dependencies 与 index.js),其职责与效果保持一致——在 webpack 编译管线中加入 ESLint 检查环节。
插件装配逻辑
index.js 展示了完整的装配流程:
- 读取
options.lintOnSave,为假值则跳过 webpack 集成(仅保留 lint 命令); - 通过
api.genCacheConfig('eslint', { eslint: eslintPkg.version }, ['package.json'])生成缓存标识符——把 ESLint 版本与package.json(含依赖锁文件信息)纳入缓存 key,避免升级 ESLint 插件后命中过期缓存; - 在
chainWebpack钩子中向webpackConfig.plugin('eslint')注入eslint-webpack-plugin,并传入extensions(.js/.jsx/.vue,TypeScript 项目追加.ts/.tsx)、cwd、cache、cacheLocation、failOnWarning/failOnError、eslintPath等选项; - 同时调用
api.registerCommand('lint', ...)注册命令行任务。
其中 eslintPath 的解析同样遵循“项目优先”原则:优先使用项目 node_modules 中的 ESLint,找不到才回退到插件自身的依赖,这保证了用户可以自由升降级 ESLint 版本。
lint 命令与 webpack 插件的分工
vue-cli-service lint:一次性的全量检查 + 修复,面向 CI 与开发者手动执行;eslint-webpack-plugin(保存即检查):跟随 webpack 编译持续运行,把结果映射为编译警告/错误,并驱动浏览器 overlay 展示。
两者复用同一套 eslintOptions.extensions 与项目级 ESLint 配置,因此命令行检查与开发期检查的规则口径天然一致。
升级与迁移注意事项
对于从 Vue CLI 3/4 迁移的老项目,migrator/index.js 会自动处理以下变更:
- 将 ESLint 从 v4/v5/v6 升级到 v7,并把 ESLint 依赖从插件内部提取到项目
devDependencies; - 用
@babel/eslint-parser(需@babel/core >= 7.2.0)替换已废弃的babel-eslint; - TypeScript 项目将解析器统一为
@typescript-eslint/parser; - 依据项目已有依赖(airbnb/standard/prettier)自动补齐对应配置包的升级。
升级完成后,原有 extends: ['@vue/typescript'] 等旧式写法建议按 v7 规范迁移为 @vue/typescript/recommended(源码 TODO 注释也提示了后续计划,可关注 ESLint 官方迁移文档)。
小结
@vue/cli-plugin-eslint 将 ESLint 的能力无缝嵌入了 Vue CLI 的开发闭环:创建项目时可交互式选择代码风格预设,开发期通过 lintOnSave 实现保存即检查与浏览器 overlay 报错,提交前可借助 lint-staged 自动修复,命令行则有功能完整的 vue-cli-service lint 支撑 CI 质量门禁。理解 lintOnSave 的四种取值语义、默认检查范围与点文件规则、以及 webpack 层 lint 与命令行 lint 的分工,就能在真实项目中把代码规范从“事后检查”升级为“过程约束”。
延伸阅读
- 插件主入口与命令注册:packages/@vue/cli-plugin-eslint/index.js
- lint 命令实现与 CLI 参数映射:packages/@vue/cli-plugin-eslint/lint.js
- 默认 ESLint 配置与扩展名规则:packages/@vue/cli-plugin-eslint/eslintOptions.js
- 依赖映射与生成器:packages/@vue/cli-plugin-eslint/eslintDeps.js、generator/index.js
- 交互式 prompts 与迁移器:prompts.js、migrator/index.js
lintOnSave选项校验与默认值:packages/@vue/cli-service/lib/options.js、packages/@vue/cli-service/types/ProjectOptions.d.ts- 端到端行为测试:packages/@vue/cli-plugin-eslint/tests/eslintPlugin.spec.js
vue.config.js全量配置参考:docs/ru/config/index.md