代码规范是软件开发领域经久不衰的话题,几乎所有工程师在开发过程中都会遇到或思考过这一问题。而随着前端应用的大型化和复杂化,越来越多的前端团队也开始重视代码规范。同样,前段时间,笔者所在的团队也开展了一波开源治理,而其中代码规范就占据了很重要的一项。接下来的几篇文章,将会对JS代码规范、CSS规范、Git提交规范以及Git工作流规范进行详细的介绍~
系列文章:
- 前端规范之JS代码规范(ESLint + Prettier)
- 前端规范之CSS规范(Stylelint)
- 前端规范之Git提交规范(Commitizen)
- 前端规范之Gti工作流规范(Husky + Commitlint + Lint-staged)
本文主要介绍了前端规范之JS代码规范(ESLint + Prettier),将会对ESLint和Prettier的使用进行介绍,欢迎大家交流讨论~
1. 统一代码风格的重要性
1.1 为什么要统一代码风格
团队千千万,团队中每个人的代码风格也是千千万。比如有的同学写代码就喜欢用双引号,缩进用两个字符,而其他同学却可能更喜欢用单引号,四个字符缩进。而团队中的人一多,一往代码仓库提交代码,难免会出现下面这些情况:
(1)如果没有统一代码风格,diff时可能会出现很多因为格式不同的问题,不便于我们查看提交代码所做的修改
如下图所示,提交的文件内容其实没有变化,只是代码风格变了(双引号变成了单引号,缩进从两个字符变成了四个字符),但是diff时大段代码会标红,不利于我们查看提交的修改。
(2)每个团队都有自己的标准,新人加入需要花较长时间才能熟悉团队所使用的代码风格,不利于效率的提
1.2 如何统一代码风格
为了统一代码风格,并且克服每个团队自己制定标准所带来的不足,一种简单方便的方法就是采用业界提供的标准和工具,也就是我们经常所说的Lint检查工具。前端中常用的Lint检查工具包括了JSLint、ESLint和Stylelint等,这些工具能够提供代码质量和代码风格检查的功能,并且可以根据个人/团队的代码风格进行对配置文件进行配置,有效的提高了我们代码开发的效率和质量。
下面主要列举了我们团队现在主要采用的一些Lint检查工具,以及相关的VSCode辅助插件,帮助我们完成JS代码规范、CSS代码规范和Git工作流规范的检查。
2. ESLint
2.1 什么是ESLint
ESLint 是一款插件化的JavaScript代码静态检查工具,其核心是通过对代码解析得到的 AST(Abstract Syntax Tree,抽象语法树)进行模式匹配,来分析代码达到检查代码质量和风格问题的能力。
ESLint 的使用其实并不复杂。安装相关依赖之后,可以直接使用开源的配置方案,例如eslint-config-airbnb或eslint-config-standard,当然,你也可以根据个人或团队的代码风格进行配置。配置完成之后,就可以通过命令行工具或借助编辑器集成的 ESLint 功能对工程代码进行静态检查,发现和修复不符合规范的代码,ESLint提供的auto-fix能力也能够帮助我们自动修复一些代码格式问题。
2.2 安装ESLint
(1)脚手架自动安装
如果是采用脚手架如Vue-Cli创建项目,在创建项目时就可以选择安装ESLint,安装完成后,会自动在项目根目录生成一个.eslintrc.js文件,里面已经生成了ESLint的初始化默认配置。
(2)手动安装
如果是已经存在一个项目,并且想要安装ESLint,可以通过npm的方式进行安装。
npm install eslint --save-dev
安装完成后,可以执行下面命令进行ESLint的初始化配置。
eslint --init
经过一系列一问一答的环节后,你会发现在你项目根目录已经生成了一个 .eslintrc.js文件,该文件主要用来进行ESLint的配置。
2.3 ESLint配置方式
ESlint 被设计为完全可配置的,我们可以混合和匹配 ESLint 默认绑定的规则和自己定义的规则,根据实际需求对每一个规则进行开启或关闭,以让 ESLint 更适合我们的项目。一般有两种主要的方式来配置 ESLint:
(1)Configuration Comments - 使用注释把lint规则嵌入到源码中
这种配置方式允许我们使用JavaScript注释把配置信息直接嵌入到一个代码源文件中,如下面的代码所示,可以直接在代码中使用ESLint能够识别的注释方式,进行Lint规则的定义,下面的规则表示如果使用console语法便会报错。
/* eslint no-console: "error" */ console.log('this is an eslint rule check!');
当我们用命令行执行eslint xxx.js检查上述文件时,就会发现eslint给出报错信息。
(2)Configuration Files - 使用配置文件进行lint规则配置
除了上面的配置方式,另外一个更好的方式就是在项目根目录创建配置文件进行ESLint的配置,目前配置文件主要支持以下三种文件类型:
- JavaScript(eslintrc.js)
- YAML(eslintrc.yaml)
- JSON(eslintrc.json)
另外,我们也可以在package.json文件中添加 eslintConfig字段进行配置。
在我们团队平时的开发中,一般采用了在根目录创建.eslintrc.js的方式对eslint进行配置。如下图所示,给出了使用Vue-Cli创建项目后.eslintrc.js中的默认配置。
module.exports = { root: true, env: { node: true, }, extends: ["plugin:vue/essential", "eslint:recommended", "@vue/prettier"], parserOptions: { parser: "babel-eslint", }, rules: { "no-console": process.env.NODE_ENV === "production" ? "warn" : "off", "no-debugger": process.env.NODE_ENV === "production" ? "warn" : "off", }, };
2.4 ESLint配置项解析
接下来主要对ESLint配置文件中的配置项进行介绍。
(1)parser解析器
ESLint 默认使用Espreer作为其解析器,但是该解析器仅支持最新的ECMPScript(es5)标准,对于实验性的语法和非标准(例如 Flow或TypeScript类型)语法是不支持的。因此,开源社区提供了以下两种解析器来丰富相关的功能:
babel-eslint:Babel一个工具链,主要用于将ECMAScript 2015+(es6+) 版本的代码转换为向后兼容的JavaScript语法,以便能够运行在当前和旧版本的浏览器或其他环境中。因此,如果在项目中使用es6,就需要将解析器改成babel-eslint。
@typescript-eslint/parser:该解析器将TypeScript转换成与estree兼容的形式, 允许ESLint验证TypeScript源代码。
(2)parserOptions解析器选项
除了可以自定义解析器外,ESLint允许指定你想要支持的JavaScript语言选项。默认情况下,ESLint支持ECMPScript 5语法。你可以覆盖该设置,以启用对ECMPScript其它版本和JSX的支持。
(3)env和global - 环境和全局变量
ESLint 会检测未声明的变量,并发出警告,但是有些变量是我们引入的库声明的,这里就需要提前在配置中声明。每个变量有三个选项,writable,readonly和off,分别表示可重写,不可重写和禁用。
{ "globals": { // 声明 jQuery 对象为全局变量 "$": false, // true表示该变量为 writeable,而 false 表示 readonly "jQuery": false } }
在globals中一个个的进行声明未免有点繁琐,这个时候就需要使用到env,这是对一个环境定义的一组全局变量的预设。当然,我们可以在golbals中使用字符串off禁用全局变量来覆盖env中的声明。
{ "env": { "browser": true, "es2021": true, "jquery": true // 环境中开启jquery,表示声明了jquery相关的全局变量,无需在globals二次声明 } }
如果是微信小程序开发,env并没有定义微信小程序变量,需要在globals中手动声明全局变量,否则在文件中引入变量,会提示报错。声明如下所示:
{ globals: { wx: true, App: true, Page: true, Component: true, getApp: true, getCurrentPages: true, Behavior: true, global: true, __wxConfig: true, }, }
(4)rules规则
ESLint 附带有大量的规则,你可以在配置文件的rules属性中配置你想要的规则。要改变一个规则设置,你必须将规则 ID 设置为下列值之一:
- off或 0:关闭规则
- warn或 1:开启规则,warn级别的错误 (不会导致程序退出)
- error或 2:开启规则,error级别的错误(当被触发的时候,程序会退出)
如以下代码,在rules中设置关闭某些规则
rules: {'no-loop-func': 'off', 'no-param-reassign': 'off', 'no-nested-ternary': 'off', no-underscore-dangle': 'off', },
(5)plugins插件
虽然官方提供了上百种的规则可供选择,但是这还不够,因为官方的规则只能检查标准的JavaScript语法,如果你写的是JSX或者TypeScript,ESLint 的规则就开始束手无策了。
这个时候就需要安装 ESLint 的插件,来定制一些特定的规则进行检查。ESLint 的插件与扩展一样有固定的命名格式,以eslint-plugin-开头,使用的时候也可以省略这个头。
举个例子,我们要在项目中使用TypeScript,前面提到过,需要将解析器改为@typescript-eslint/parser,同时需要安装@typescript-eslint/eslint-plugin插件来拓展规则,添加的plugins中的规则默认是不开启的,我们需要在rules中选择我们要使用的规则。也就是说 plugins是要和rules结合使用的。如下所示:
// npm i --save-dev @typescript-eslint/eslint-plugin // 注册插件 { "parser": "@typescript-eslint/parser", "plugins": ["@typescript-eslint"], // 引入插件 "rules": { "@typescript-eslint/rule-name": "error" // 使用插件规则 '@typescript-eslint/adjacent-overload-signatures': 'error', '@typescript-eslint/ban-ts-comment': 'error', '@typescript-eslint/ban-types': 'error', '@typescript-eslint/explicit-module-boundary-types': 'warn', '@typescript-eslint/no-array-constructor': 'error', 'no-empty-function': 'off', '@typescript-eslint/no-empty-function': 'error', '@typescript-eslint/no-empty-interface': 'error', '@typescript-eslint/no-explicit-any': 'warn', '@typescript-eslint/no-extra-non-null-assertion': 'error', ... } }
(6)extends扩展
extends可以理解为一份配置好的plugin和rules,extends属性值一般包括以下两种:
- 指定配置的字符串: 比如官方提供的两个拓展eslint:recommended或eslint:all,可以启用当前安装的 ESLint 中所有的核心规则,省得我们在rules中一一配置。
- 字符串数组:每个配置继承它前面的配置。如下所示,拓展是一个数组,ESLint 递归地扩展配置, 然后使用rules属性来拓展或者覆盖extends配置规则。
{ "extends": [ "eslint:recommended", // 官方拓展 "plugin:@typescript-eslint/recommended", // 插件拓展 "standard", // npm包,开源社区流行的配置方案,比如:eslint-config-airbnb、eslint-config-standard ], "rules": { "indent": ["error", 4], // 拓展或覆盖extends配置的规则 "no-console": "off", } };
2.5 运行ESLint检查文件
当我们配置好.eslintrc.js文件后,我们就可以通过运行ESLint相关命令,对指定文件进行检查,假设当前的项目目录如下所示:
其中,.eslintrc.js文件的配置如下,这里采用了Vue-Cli创建项目后给出的默认配置。
module.exports = { root: true, env: { node: true, }, extends: ["plugin:vue/essential", "eslint:recommended", "@vue/prettier"], parserOptions: { parser: "babel-eslint", }, rules: { "no-console": process.env.NODE_ENV === "production" ? "warn" : "off", "no-debugger": process.env.NODE_ENV === "production" ? "warn" : "off", }, };
当我们想对某个文件进行检查时,只需要在当前目录打开命令行窗口,输入以下命令,就可以对某个文件或某个目录下的所有文件进行检查。如果执行完命令后什么也没有输出,就说明我们的代码已经通过ESLint检查,可以放心提交代码。
eslint src/APP.vue // 检查指定的文件
eslint src/*.vue // 检查src目录下的所有文件
但是如果出现以下提示或报错,就说明我们的代码没有通过ESLint的检查,需要按照提示进行修改。
有些同学一执行完上述命令,可能会吓了一跳,怎么报了这么多错误?不急,我们可以执行以下的ESLint自动修复命令,对一些错误进行自动修复。不过,这个命令只能自动修复一些代码格式上的错误(比如ESLint的配置要求需要使用双引号,但是写代码时采用了单引号而报错),对于一些语法错误,就需要我们手动去修复。
eslint src/APP.vue --fix // 检查指定的文件,并且自动修复错误 eslint src/*.vue --fix // 检查src目录下的所有文件,并且自动修复错误
2.6 跳过ESLint的检查
在实际的使用场景中,我们可能存在某些文件或某行代码,希望能够跳过ESLint的检查,下面主要介绍了几种跳过ESLint检查的方式:
(1)使用注释跳过ESLint的检查
- 块注释: 使用如下方式,可以在整个文件或者代码块禁用所有规则或者禁用特定规则:
/* eslint-disable */ alert('该注释放在文件顶部,整个文件都不会出现 lint 警告'); /* eslint-disable */ alert('块注释 - 禁用所有规则'); /* eslint-enable */ /* eslint-disable no-console, no-alert */ alert('块注释 - 禁用 no-console, no-alert 特定规则'); /* eslint-enable no-console, no-alert */
- 行注释: 使用如下方式可以在某一特定的行上禁用所有规则或者禁用特定规则:
alert('禁用该行所有规则'); // eslint-disable-line // eslint-disable-next-line alert('禁用该行所有规则'); /* eslint-disable-next-line no-alert */ alert('禁用该行 no-alert 特定规则'); alert( '禁用该行 no-alert, quotes, semi 特定规则' ); /* eslint-disable-line no-alert, quotes, semi*/
(2)创建.eslintignore文件忽略某些文件的检查
在项目根目录创建.eslintignore文件,在该文件中添加需要跳过检查的文件名称,ESLint将会跳过这些文件的检查。如下所示,ESLint将会跳过dist、node_modules和package.json文件的检查。
dist
node_modules
package.json
3. Prettier
3.1 什么是Prettier
Prettier是一个代码格式化工具,可以格式化代码,但不具备代码检查功能,它可以通过解析代码并使用自己的规则重新打印它,并考虑最大行长来强制一致的样式,并在必要时包装代码,如今,它已成为解决所有代码格式问题的优选方案,支持多种语言,可以将ESLint和Prettier结合使用,提高代码质量。
3.2 为什么要用Prettier
上面Prettier的定义一看,是不是觉得和ESLint差不了多少?那么,有了ESLint,为什么还要用Prettier呢?
其实呀,ESLint虽然是一个代码检测工具,可以检测代码质量问题并给出提示,但是提供的格式化功能有限,在代码风格上面做的不是很好,并且也只能格式化JS,不支持CSS,HTML等语言。而在代码风格上面,Prettier具有更加强大的功能,并且能够支持包括 JavaScript、TypeScript、各种 CSS、Vue 和 Markdown 等前端绝大部分的语言和文件格式。因此,我们一般会将ESLint和Prettier一起结合起来使用,用ESLint进行代码校验,用Prettier统一代码风格。
3.3 安装Prettier
(1)脚手架自动安装
如果是采用脚手架如Vue-Cli创建项目,在创建项目时就可以选择安装Prettier,安装完成后,会自动在项目根目录生成一个.eslintrc.js文件,里面的默认配置中已经包含了prettier的相关扩展。
(2)手动安装
如果已经存在一个项目,并且想要安装Prettier,可以通过npm的方式进行安装。
npm install prettier --save-dev
3.4 安装eslint-config-prettier
安装好Prettier之后,我们还需要安装eslint-config-prettier,这是因为eslint和prettier里面的一些规则可能会存在冲突,这个时候我们就需要安装eslint-config-prettier,并且关掉所有和prettier冲突的eslint配置。
通过npm安装eslint-config-prettier。
npm install eslint-config-prettier --save-dev
安装好eslint-config-prettier之后,接下来我们就需要关掉所有和prettier冲突的eslint配置。这里只需要在.eslintrc.js的extends中将prettier设置为最后一个extends即可,相当于用 prettier 的规则,覆盖掉 eslint:recommended 的部分规则。
extends: ["eslint:recommended", "prettier"],
3.5 安装eslint-plugin-prettier
接下来,我们还需要安装eslint-plugin-prettier,eslint-plugin-prettier的作用时是将prettier 的能力集成到eslint中,使得我们在运行eslint检查我们的代码时,能够按照prettier的规则检查代码规范性,并进行修复。
使用npm安装eslint-plugin-prettier。
npm install eslint-plugin-prettier
安装eslint-plugin-prettier后,需要对.eslintrc.js进行配置。
{ "rules":{ "prettier/prettier":"error" }, "plugins": ["prettier"],
}
除了上面这种配置之外,我们也可以直接将上面两个步骤结合在一起,使用下面的配置就可以。
{ "extends": [ "eslint:recommended", "plugin:prettier/recommended" ] }
3.6 配置文件
Prettier和ESLint一样,支持我们通过配置文件的方式,实现自定义配置,覆盖原来的Prettier配置。
我们可以在根目录创建.prettierrc文件,.prettierrc文件支持写入YAML,JSON的配置格式,并且支持.yaml,.yml,.json和.js后缀。在平时的开发中,我们团队一般会选择创建.prettierrc.js文件,实现对prettier配置的覆盖。
在.prettierrc.js文件中,我们可以对prettier的默认配置进行修改。
module.exports = { // 一行最多 120 字符 printWidth: 120, // 使用 2 个空格缩进 tabWidth: 2, // 不使用缩进符,而使用空格 useTabs: false, // 行尾需要有分号 semi: true, // 使用单引号 singleQuote: true, // 对象的 key 仅在必要时用引号 quoteProps: 'as-needed', // jsx 不使用单引号,而使用双引号 jsxSingleQuote: false, // 末尾需要有逗号 trailingComma: 'all', // 大括号内的首尾需要空格 bracketSpacing: true, // jsx 标签的反尖括号需要换行 jsxBracketSameLine: false, // 箭头函数,只有一个参数的时候,也需要括号 arrowParens: 'always', // 每个文件格式化的范围是文件的全部内容 rangeStart: 0, rangeEnd: null, // 不需要写文件开头的 @prettier requirePragma: false, // 不需要自动在文件开头插入 @prettier insertPragma: false, // 使用默认的折行标准 proseWrap: 'preserve', // 根据显示样式决定 html 要不要折行 htmlWhitespaceSensitivity: 'css', // vue 文件中的 script 和 style 内不用缩进 vueIndentScriptAndStyle: false, // 换行符使用 lf endOfLine: 'lf', // 格式化内嵌代码 embeddedLanguageFormatting: 'auto', };
3.7 忽略某些文件的格式化
Prettier和ESLint一样,也支持忽略对某些文件的格式化。如果我们存在一些不需要格式化的文件,可以在根目录创建.prettierignore文件,并且将不需要格式化的文件或目录名称写在该文件中。
dist
node_modules
.eslintignore
.prettierignore
4. VSCode插件
4.1 安装VSCode插件
配置好ESLint和Prettier之后,我们通过运行eslint命令,就可以对我们代码进行检查啦。但是,每次要手动运行命令才能检查我们的代码还是有点麻烦,有没有更简单的方式,让我们在编写代码的过程中,只要保存文件就能够对当前文件进行检查,并且自动修复一些错误呢?接下来,接下来,VSCode插件就登场啦~
首先,我们需要安装的ESLint插件,安装方法很简单,在VSCode的EXTENSIONS中找到ESLint插件,然后点击install就可以啦。
接着,我们还需要安装Prettier插件。
最后,我们也把EditorConfig for VS Code插件安装上,这个插件可以让编译器读取配置文件,并且按照配置文件里面的规定来格式化代码,有了这个插件,只要定义好一份配置文件,就算团队成员用的编译器不同,也能够输出风格统一的代码。
4.2 配置settings.json文件
安装好插件之后,我们还需要设置VSCode的settings.json文件,实现保存代码时就自动执行ESLint检查。VSCode的setting.json设置分为工作区和用户两个级别,其中用户区会对所有项目生效,而工作区的设置只会对当前项目生效。
(1)用户区settings.json配置
点击VSCode左下角的设置按钮,选择Settings,选择以文本编辑形式打开settings.json,并且在setting.json中加入以下代码。配置完成之后,当我们保存某个文件时,就可以自动对当前文件进行ESLint检查,并且自动对一些错误进行修复啦。
{ // #每次保存的时候自动格式化 "editor.formatOnSave": true, "editor.codeActionsOnSave": { "source.fixAll.eslint": true },
(2)工作区settings.json配置
除了配置用户区的settings.json之外,我们也可以配置工作区的settings.json,工作区的配置只会对当前项目生效。
首先,我们需要在项目根目录创建.vscode目录,并且在该目录下创建settings.json文件。
接着,在settings.json中加入以下代码,配置完成后,当我们保存该项目中某个文件时,也会自动对该文件进行ESLint检查,并且自动修复一些问题。
{ "editor.formatOnSave": true, "editor.codeActionsOnSave": { "source.fixAll.eslint": true, }, "eslint.validate": ["typescript", "javascript", "vue"] }
4.3 配置EditorConfig文件
上面在安装VSCode插件时,我们提到了要安装EditorConfig for VS Code插件,那这个插件需要怎么起作用呢?
首先,我们需要在项目根目录创建.editorconfig文件。创建完成之后,这个文件里面定义的代码规范规则会高于编译器默认的代码规范规则。
接着,我们只需要在.editorconfig文件中加入我们想要覆盖的编译器的配置,比如下面的配置定义了缩进为2个空格,那么就算编译器默认的是4个空格的缩进,最后也会按照我们的.editorconfig配置,按照2个空格进行缩进。
root = true [*] charset = utf-8 indent_style = space indent_size = 2 insert_final_newline = true trim_trailing_whitespace = true end_of_line = auto
当我们完成上面的步骤之后,接下来我们只要编写代码,保存,就能够得到一份风格统一的代码啦~