大家好,欢迎来到今天的“代码质量提升大法”讲座!今天我们要聊聊怎么在 Vue 项目里玩转代码分析和静态检查,让我们的代码既健壮又漂亮,就像给代码做个全身 SPA!
一、开场白:为什么要给代码做 SPA?
想象一下,你辛辛苦苦写了一堆代码,结果上线之后各种bug冒出来,用户体验差到爆,老板天天催你修复,是不是感觉整个世界都灰暗了?这就是代码质量不高惹的祸!
好的代码就像一个健康的身体,需要定期检查、及时修复问题。代码分析和静态检查就是给代码做的 SPA,帮助我们:
- 提前发现问题: 在代码提交之前,就能发现潜在的bug、代码风格问题、安全漏洞等。
- 统一代码风格: 保证团队成员的代码风格一致,提高代码可读性和可维护性。
- 提高代码质量: 减少bug,提高性能,让代码更健壮。
- 减少维护成本: 降低后期维护的难度,节省时间和精力。
二、主角登场:ESLint 和 SonarQube
今天的主角是 ESLint 和 SonarQube,它们就像代码界的“神医”,一个擅长“望闻问切”,一个擅长“全面体检”。
-
ESLint: 专注于代码风格和潜在问题的静态检查工具。它可以根据预设的规则,检查代码是否符合规范,例如缩进、空格、命名等。就像一个严格的代码风格警察,时刻监督你的代码。
-
SonarQube: 一个全面的代码质量管理平台。它可以分析代码中的bug、漏洞、代码异味、代码重复率等,并提供详细的报告和改进建议。就像一个专业的体检中心,帮你全面了解代码的健康状况。
三、实战演练:ESLint 的配置与使用
接下来,我们就来实战演练一下,看看如何在 Vue 项目中配置和使用 ESLint。
-
安装 ESLint:
首先,我们需要在项目中安装 ESLint 相关的依赖包。打开你的终端,输入以下命令:
npm install eslint eslint-plugin-vue --save-dev
或者使用 yarn:
yarn add eslint eslint-plugin-vue -D
eslint
: ESLint 的核心包。eslint-plugin-vue
: ESLint 的 Vue 插件,用于检查 Vue 组件中的代码。--save-dev
或-D
: 将这些依赖包安装到开发依赖中。
-
初始化 ESLint 配置:
安装完成后,我们需要初始化 ESLint 的配置文件。在终端中输入以下命令:
npx eslint --init
这个命令会引导你创建一个
.eslintrc.js
或.eslintrc.json
文件,用于配置 ESLint 的规则。按照提示选择适合你项目的配置:- How would you like to use ESLint? (选择一种使用方式)
- To check syntax, find problems, and enforce code style (检查语法、发现问题、强制代码风格)
- What type of modules does your project use? (选择模块类型)
- JavaScript modules (import/export) (JavaScript 模块,使用 import/export)
- Which framework does your project use? (选择框架)
- Vue.js
- Does your project use TypeScript? (是否使用 TypeScript)
- Yes/No (根据你的项目选择)
- Where does your code run? (代码运行环境)
- Browser (浏览器)
- Node (Node.js)
- How would you like to define a style for your project? (选择一种风格定义方式)
- Use a popular style guide (使用流行的风格指南)
- Which style guide do you want to follow? (选择风格指南)
- What format do you want your config file to be in? (选择配置文件格式)
- JavaScript
- Would you like to install them now with npm? (是否立即安装依赖)
- Yes
根据你的选择,ESLint 会自动安装相关的插件和依赖包。例如,如果你选择了 Airbnb 风格指南,它会自动安装
eslint-config-airbnb-base
和eslint-plugin-import
等依赖。 - How would you like to use ESLint? (选择一种使用方式)
-
配置 ESLint 规则:
打开
.eslintrc.js
文件,你可以看到 ESLint 的配置信息。例如,一个简单的配置如下:module.exports = { root: true, env: { node: true, }, extends: [ 'plugin:vue/vue3-essential', 'eslint:recommended', '@vue/airbnb', ], parserOptions: { parser: 'babel-eslint', }, rules: { 'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off', 'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off', 'indent': ['error', 2], // 强制使用两个空格缩进 'quotes': ['error', 'single'], // 强制使用单引号 'semi': ['error', 'always'], // 强制使用分号 'vue/multi-word-component-names': 'off', // 关闭vue文件名称校验 }, };
root: true
: 表示这是 ESLint 的根配置文件,停止在父目录中查找配置文件。env
: 指定代码运行的环境,例如node: true
表示代码运行在 Node.js 环境中。extends
: 继承 ESLint 的配置,例如eslint:recommended
表示使用 ESLint 的推荐规则,@vue/airbnb
表示使用 Vue 的 Airbnb 风格指南。parserOptions
: 指定代码解析器,例如parser: 'babel-eslint'
表示使用 Babel 解析器。rules
: 自定义 ESLint 规则。你可以根据自己的需求,修改或添加规则。例如:'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off'
: 在生产环境中,将console.log
语句视为警告,否则关闭。'indent': ['error', 2]
: 强制使用两个空格缩进,如果违反规则,则报错。'quotes': ['error', 'single']
: 强制使用单引号,如果违反规则,则报错。'semi': ['error', 'always']
: 强制使用分号,如果违反规则,则报错。'vue/multi-word-component-names': 'off'
: 关闭 Vue 组件名称必须是多单词的校验,否则会报错。这个规则在实际开发中可以关闭,因为很多时候组件名称使用单个单词更简洁明了。
常用的 ESLint 规则:
规则名称 描述 no-unused-vars
禁止使用未使用的变量。 no-console
禁止使用 console.log
等语句。no-debugger
禁止使用 debugger
语句。indent
强制使用一致的缩进。 quotes
强制使用一致的引号风格。 semi
强制使用一致的分号风格。 eqeqeq
强制使用 ===
和!==
代替==
和!=
。no-alert
禁止使用 alert
语句。no-eval
禁止使用 eval
函数。no-implied-eval
禁止使用 setTimeout
、setInterval
和execScript
等函数,因为它们可能会执行字符串形式的代码。no-new-func
禁止使用 new Function()
构造函数。no-caller
禁止使用 arguments.caller
和arguments.callee
属性。no-iterator
禁止使用 __iterator__
属性。no-proto
禁止使用 __proto__
属性。no-script-url
禁止使用 javascript:
URL。no-useless-call
禁止使用不必要的 .call()
和.apply()
。no-void
禁止使用 void
操作符。no-with
禁止使用 with
语句。array-callback-return
强制数组的回调函数必须返回值。 block-scoped-var
强制在块级作用域中使用变量。 complexity
限制代码的复杂度。 consistent-return
强制函数必须始终返回值或始终不返回值。 default-case
在 switch
语句中强制使用default
分支。for-direction
强制 for
循环的方向正确。getter-return
强制 getter
函数必须返回值。no-await-in-loop
禁止在循环中使用 await
语句。no-compare-neg-zero
禁止与 -0
进行比较。no-cond-assign
禁止在条件语句中使用赋值表达式。 no-constant-condition
禁止使用常量作为条件。 no-control-regex
禁止在正则表达式中使用控制字符。 no-dupe-args
禁止在函数定义中使用重复的参数名。 no-dupe-keys
禁止在对象字面量中使用重复的键名。 no-duplicate-case
禁止在 switch
语句中使用重复的case
分支。no-empty
禁止使用空的代码块。 no-empty-character-class
禁止在正则表达式中使用空的字符类。 no-ex-assign
禁止在 catch
语句中重新赋值异常变量。no-extra-boolean-cast
禁止不必要的布尔类型转换。 no-extra-parens
禁止不必要的括号。 no-extra-semi
禁止不必要的分号。 no-fallthrough
禁止 switch
语句的case
分支没有break
语句。no-func-assign
禁止重新赋值函数声明。 no-global-assign
禁止修改只读的全局变量。 no-inner-declarations
禁止在嵌套的代码块中使用变量或函数声明。 no-invalid-regexp
禁止在 RegExp()
构造函数中使用无效的正则表达式。no-irregular-whitespace
禁止使用不规则的空白字符。 no-loop-func
禁止在循环中创建函数。 no-multi-spaces
禁止使用多个空格。 no-new
禁止使用 new
关键字但没有赋值给变量。no-new-wrappers
禁止使用 String()
、Number()
和Boolean()
构造函数。no-obj-calls
禁止将全局对象作为函数调用,例如 Math()
或JSON()
。no-octal
禁止使用八进制字面量。 no-param-reassign
禁止重新赋值函数参数。 no-redeclare
禁止重复声明变量。 no-regex-spaces
禁止在正则表达式中使用多个空格。 no-return-assign
禁止在 return
语句中使用赋值表达式。no-return-await
禁止不必要的 await
语句。no-self-assign
禁止将变量赋值给自己。 no-self-compare
禁止将变量与自身进行比较。 no-sequences
禁止使用逗号运算符。 no-shadow
禁止变量声明覆盖外部作用域中的变量。 no-shadow-restricted-names
禁止使用保留字作为变量名。 no-sparse-arrays
禁止使用稀疏数组。 no-template-curly-in-string
禁止在普通字符串中使用模板字面量占位符。 no-throw-literal
禁止抛出字面量作为异常。 no-undef
禁止使用未声明的变量。 no-undef-init
禁止将变量初始化为 undefined
。no-undefined
禁止使用 undefined
变量。no-unmodified-loop-condition
禁止在循环中没有修改的循环条件。 no-unneeded-ternary
禁止不必要的三元运算符。 no-unreachable
禁止在 return
、throw
、continue
和break
语句之后出现不可达的代码。no-unsafe-finally
禁止在 finally
代码块中使用控制语句,例如return
、throw
、break
和continue
。no-unused-expressions
禁止使用未使用的表达式。 no-unused-labels
禁止使用未使用的标签。 no-useless-computed-key
禁止使用不必要的计算属性键名。 no-useless-concat
禁止不必要的字符串拼接。 no-useless-constructor
禁止不必要的构造函数。 no-useless-escape
禁止不必要的转义字符。 no-useless-rename
禁止不必要的重命名。 no-var
强制使用 let
和const
代替var
。no-whitespace-before-property
禁止在对象属性之前出现空白。 nonblock-statement-body-position
强制单行语句的位置。 object-curly-newline
强制大括号内的换行符。 object-curly-spacing
强制大括号内的空格。 object-property-newline
强制对象属性的换行符。 one-var
强制每个作用域中只声明一个变量。 operator-linebreak
强制操作符的换行符。 padded-blocks
强制代码块的填充。 padding-line-between-statements
强制语句之间的填充。 prefer-const
建议使用 const
声明那些声明后不再被修改的变量。prefer-destructuring
建议使用解构赋值。 prefer-numeric-literals
建议使用数字字面量。 prefer-promise-reject-errors
建议使用 Error
对象作为Promise
的拒绝原因。quote-props
强制对象字面量属性名称的引号风格。 radix
强制使用 parseInt()
函数时指定基数。require-await
建议在异步函数中使用 await
语句。require-unicode-regexp
建议在正则表达式中使用 Unicode 模式。 sort-imports
强制导入语句的排序。 sort-keys
强制对象键的排序。 sort-vars
强制变量声明的排序。 space-before-blocks
强制在块之前使用空格。 space-before-function-paren
强制在函数括号之前使用空格。 space-in-parens
强制在括号内使用空格。 space-infix-ops
强制在操作符周围使用空格。 space-unary-ops
强制在一元操作符之前或之后使用空格。 spaced-comment
强制注释的间距。 strict
强制使用严格模式。 symbol-description
强制 Symbol
必须有一个描述。template-curly-spacing
强制在模板字面量占位符中使用空格。 unicode-bom
强制使用 Unicode BOM。 vars-on-top
强制将变量声明放在作用域顶部。 wrap-iife
强制将立即执行函数表达式 (IIFE) 包装在括号中。 wrap-regex
强制将正则表达式包装在括号中。 yoda
强制使用 Yoda 条件。 Vue 相关的 ESLint 规则:
规则名称 描述 vue/no-dupe-keys
禁止在 Vue 组件中使用重复的键名。 vue/no-duplicate-attributes
禁止在 Vue 组件中使用重复的属性。 vue/no-parsing-error
禁止在 Vue 组件中使用解析错误。 vue/no-reserved-keys
禁止在 Vue 组件中使用保留的键名。 vue/no-shared-component-data
禁止在 Vue 组件中使用共享的组件数据。 vue/no-side-effects-in-computed-properties
禁止在计算属性中使用副作用。 vue/no-template-key
禁止在 template
标签中使用key
属性。vue/no-textarea-mustache
禁止在 textarea
标签中使用插值表达式。vue/no-unused-components
禁止在 Vue 组件中使用未使用的组件。 vue/no-unused-vars
禁止在 Vue 组件中使用未使用的变量。 vue/script-setup-uses-vars
防止 <script setup>
中使用的变量被标记为未使用。vue/require-prop-types
强制 Vue 组件必须声明 props
的类型。vue/require-render-return
强制 Vue 组件的 render
函数必须返回值。vue/require-v-for-key
强制在使用 v-for
指令时必须指定key
属性。vue/return-in-computed-property
强制计算属性必须返回值。 vue/valid-template-root
强制 Vue 组件的 template
必须有一个根元素。vue/valid-v-bind
强制 v-bind
指令必须是有效的。vue/valid-v-cloak
强制 v-cloak
指令必须是有效的。vue/valid-v-else
强制 v-else
指令必须是有效的。vue/valid-v-else-if
强制 v-else-if
指令必须是有效的。vue/valid-v-for
强制 v-for
指令必须是有效的。vue/valid-v-html
强制 v-html
指令必须是有效的。vue/valid-v-if
强制 v-if
指令必须是有效的。vue/valid-v-model
强制 v-model
指令必须是有效的。vue/valid-v-on
强制 v-on
指令必须是有效的。vue/valid-v-once
强制 v-once
指令必须是有效的。vue/valid-v-pre
强制 v-pre
指令必须是有效的。vue/valid-v-show
强制 v-show
指令必须是有效的。vue/valid-v-slot
强制 v-slot
指令必须是有效的。vue/attribute-hyphenation
强制 HTML 属性的连字符风格。 vue/html-closing-bracket-newline
强制 HTML 闭合括号的换行符。 vue/html-end-tags
强制 HTML 结束标签。 vue/html-indent
强制 HTML 缩进。 vue/max-attributes-per-line
限制每行 HTML 属性的数量。 vue/mustache-interpolation-spacing
强制插值表达式的空格。 vue/no-multi-spaces
禁止使用多个空格。 vue/prop-name-casing
强制 prop
名称的命名风格。vue/singleline-html-element-content-newline
强制单行 HTML 元素内容的换行符。 vue/v-bind-style
强制 v-bind
指令的风格。vue/v-on-style
强制 v-on
指令的风格。vue/attributes-order
强制属性的顺序。 vue/order-in-components
强制组件的顺序。 vue/this-in-template
强制在模板中使用 this
关键字。 -
运行 ESLint:
配置完成后,你就可以在终端中运行 ESLint 来检查你的代码了。在
package.json
文件中添加一个 script:{ "scripts": { "lint": "eslint src/**/*.{js,vue}" } }
然后运行以下命令:
npm run lint
或者使用 yarn:
yarn lint
ESLint 会检查
src
目录下所有.js
和.vue
文件,并输出检查结果。 -
集成到 IDE:
为了更方便地使用 ESLint,你可以将其集成到你的 IDE 中。例如,在 VS Code 中,你可以安装 ESLint 插件,它可以实时检查你的代码,并在编辑器中显示错误和警告。
四、SonarQube 的配置与使用
接下来,我们来看看如何在项目中配置和使用 SonarQube。
-
安装 SonarQube:
首先,你需要下载并安装 SonarQube 服务器。你可以从 SonarQube 官网下载最新版本的 SonarQube:https://www.sonarqube.org/downloads/
下载完成后,解压到你想要安装的目录,然后按照官网的说明启动 SonarQube 服务器。
-
安装 SonarScanner:
SonarScanner 是一个命令行工具,用于将代码分析结果发送到 SonarQube 服务器。你需要下载并安装 SonarScanner:https://docs.sonarqube.org/latest/analysis/scan/sonarscanner/
下载完成后,解压到你想要安装的目录,并将 SonarScanner 的
bin
目录添加到你的环境变量中。 -
配置 SonarQube:
启动 SonarQube 服务器后,你需要登录 SonarQube 管理界面(默认地址是
http://localhost:9000
,默认用户名和密码是admin/admin
)。- 创建项目: 在 SonarQube 管理界面中,创建一个新的项目。
- 生成 Token: 为项目生成一个 Token,用于 SonarScanner 的身份验证。
-
配置 SonarScanner:
在你的 Vue 项目根目录下创建一个
sonar-project.properties
文件,用于配置 SonarScanner。例如:sonar.projectKey=my-vue-project sonar.projectName=My Vue Project sonar.projectVersion=1.0 sonar.sources=src sonar.sourceEncoding=UTF-8 sonar.javascript.linter.eslint.reportPaths=eslint-report.json sonar.exclusions=**/node_modules/**
sonar.projectKey
: 项目的唯一标识符。sonar.projectName
: 项目的名称。sonar.projectVersion
: 项目的版本。sonar.sources
: 源代码的目录。sonar.sourceEncoding
: 源代码的编码。sonar.javascript.linter.eslint.reportPaths
: ESLint 报告的路径。sonar.exclusions
: 需要排除的目录或文件