前端代码规范和编码风格详解

本文以 VS Code 编辑器为例展开,可以搭配 vscode-linter-examplearrow-up-right 这个例子对照着实践一下。

VS Code 编辑器自身配置

VS Code 的配置有三种形式:全局默认配置、用户配置、工作区配置。

  • 全局默认配置:VS Code 在安装完成后,在安装目录会有一个 settings.json 配置文件。

  • 用户配置:对应的是软件目录中跟当前用户相关联的特定文件夹中的 settings.json 配置文件(类似于 macOS 中 $HOME/Library/Application Support/Code/User/settings.json),用户配置在所有打开窗口都生效。通过 ctrl/cmd + , 打开的设置就是用户配置 settings.json 的 UI 视图。

  • 工作区配置:也称项目配置,此时的 settings.json 存放于项目所在根目录的 .vscode 文件中,当项目在 VS Code 中打开时,仅针对当前项目打开的窗口生效。

这三种形式的配置优先级:项目配置 > 用户配置 > 全局默认配置。

如果存在多种配置,那么优先级高的会覆盖优先级低的,这样的好处是可以为不同项目、不同用户做不同配置,而不会相互干扰,并且项目配置特定于项目,方便开发人员之间共享,达到统一开发环境和编码风格的目的。

VS Code 的 .vscode 文件夹

项目根目录中的.vscode 文件夹,除了存放项目配置,还有其他的配置。

.vscode 文件夹下包含的配置:

  • settings.json

  • extensions.json

  • tasks.json

  • launch.json

settings.json

可以在这个项目配置文件中利用编辑器自身默认格式化程序来进行编码风格统一,这也是最基本的格式化。

常用配置

屏蔽文件

项目开发中,有些生成的中间文件或者有一些不希望项目普通开发者改动的配置文件等,就可以在 settings.json 中配置,屏蔽这些文件。

其他配置

extensions.json

后续会用到的 eslint 和 prettier 插件可以直接添加在 extensions.json,方便其他开发人员安装。

配置完成后,项目开发者在第一次打开项目的时候会收到 VS Code 的推荐提醒,可以进行一键安装。如果错过了这次提醒,在侧边栏的插件选项中,也可以筛选出推荐插件进行一键安装。

关于 任务相关 tasks.json 和 调试相关的 launch.json,后续有机会再聊。

EditorConfig

EditorConfigarrow-up-right 是用来帮助开发者定义和维护编码风格的(例如缩进样式,行尾字符等),EditorConfig 包含一个用于定义代码格式的自定义文件 .editorconfig 和一批编辑器插件,这些插件是让编辑器能够使用自定义配置文件并以此来格式化代码。

使用了 EditorConfig 后,编辑器的行为会与 .editorconfig 文件中定义的一致,并且其优先级比编辑器自身的设置要高(比上一小节讲到的 VS Code 自身配置优先级高)。有些编辑器默认支持 EditorConfig,如 WebStorm;而有些编辑器则需要安装 EditorConfig 插件,如 Sublime、VS Code 等(所以说可以跨编辑器生效)。

VS Code 安装非常简单,直接在插件市场搜索 EditorConfig for VS Codearrow-up-right 安装然后重启编辑器。

当打开一个文件时,EditorConfig 插件会在打开文件的目录和其每一级父目录查找 .editorconfig 文件,直到有一个配置文件出现 root=true

EditorConfig 的配置文件是从上往下读取的,并且最近的 .editorconfig 会被最先读取,匹配 .editorconfig 中的配置项会按照读取顺序被应用,如果 .editorconfig 文件没有进行某些配置,则使用编辑器默认的设置。

配置 .editorconfig

文件名匹配:

常用属性:

使用的基础库和内置对象实例

安装完 EditorConfig 插件,并且创建并完善了 .editorconfig 自定义规则,此时,.editorconfig 中的规则会覆盖 VS Code user/workspace settings 中对应的配置。

例如一个示例 .editorconfig

EditorConfig 仅能够简单的配置一些规则,并不能完全满足需求,只是起到一个跨编辑器和 IDE 统一编码风格的兜底配置,如果要达到很好的代码规范和编码风格的统一,还需要配置其他代码检查和格式化工具使用,比如:ESLint 和 Prettier。

ESLint(V9 以下)

ESLint 是一款插件化的 JavaScript 代码静态检查工具,其核心是通过 Espree(默认解析器)对 JavaScript 代码解析得到的 AST(抽象语法树)进行模式匹配(每条规则都会对匹配的过程进行监听,每当匹配到一个类型,相应的规则就会进行检查),分析代码达到检查代码质量和编码风格的能力,同时有些 lint 规则可以避免 bug 的产生,在提高代码可读性、可维护性的前提下,减少问题数量。

代码检查是一种静态的分析,常用于寻找有问题的模式或者代码,并且不依赖于具体的编码风格。对大多数编程语言来说都会有代码检查,一般来说编译程序会内置检查工具。

ESLint 能够获得成功的几个原因:

  • 可以用其他的 parser 来代替默认的 parser,只要它的输出与 Esprima(或 Espree)兼容;

  • 可扩展性是关键

  • 规则设置为完全可配置,意味着可以关闭每一个规则而只运行基础语法验证,或把 ESLint 默认绑定的规则和你的自定义规则混合

ESLint 命令行

初始化 ESLint

在 eslint 初始化的时候会询问如何配置,具体问题及选项可以参考:https://github.com/eslint/eslint/blob/v6.0.1/lib/init/config-initializer.js#L422 。

eslint 初始化后会在文件夹的根目录生成一个 .eslintrc.js 文件。

运行 npx eslint . 可以校验文件夹下的所有文件。

运行 npx eslint . --fix 可以修复文件中的问题

VS Code 使用 ESLint 插件

使用 ESLint 命令行的方式是主动进行的编译动作,这个动作注定不是高频的,但是谁也不想写了几百行代码后,运行 ESLint 校验发现有 n 个警告和报错,所以在编码的过程中实时看到校验结果是很有必要的。

在 VS Code 中可以安装 ESLint 插件,就可以让编辑器实时的提示警告和报错,不必再等到编译时提示了。

当然也可以为 ESLint 启用“保存时自动修复”:

VS Code 插件运行需要本地项目的 ESLint 相关插件和配置都存在(依赖、配置文件),但不一定要被编译。

既然在 VS Code 中用上了 ESLint 插件能实时提示警告和报错了,那么是不是就用不到命令行的 ESLint 了?

答案是还需要命令行的 ESLint,因为不能保证项目的所有开发者都用了 VS Code,或者也有可能把 ESLint 插件手动关掉了,不管怎样,提交到仓库中的代码必须符合统一的代码规范和编码风格,所以在提交到仓库之前必须要进行一次 ESLint 校验。

ESLint 配置项解析

ESLint 的配置文件命名可以是 eslintrc.jseslintrc.yamleslintrc.json,甚至配置在 package.json 中的 eslintConfig 属性。不过 .eslintrc 这个配置文件命名据说要被废弃。

源码arrow-up-right中可以看出配置文件的优先级如下:

以下是较为全面的配置项解析:

解析器(parse)

简单说一下三种解析器:

额外说一下,ESLint 默认解析器到底是 Esprima 还是 Espree? ESLint 最早的版本默认解析器是使用的开源的 Esprima,不过当 ESLint 打算支持 ES6 和 JSX 时发现 Esprima 维护频率不高并且还没有打算发布对 ES6 的支持,经过多方调研,最后选择实现自己的解析器就是 Espree,现在的 ESLint 默认解析器是 Espree。

扩展(extends)

扩展可以共享配置,并且可以修改规则,然后覆盖掉某些不需要的配置。

简单说一下几种常见的扩展:

  • eslint-config-airbnbarrow-up-right :提供了所有的 Airbnb 的 ESLint 配置。该配置包含了 React 相关的 ESLint 规则,所以需要安装 eslint-plugin-import, eslint-plugin-react, eslint-plugin-react-hooks, eslint-plugin-jsx-a11y 这四个插件,并且它不支持 React Hooks rules,如果要支持还需要启用 eslint-config-airbnb/hooks 这个扩展。

  • eslint-config-airbnb-basearrow-up-right : 不包含 React 的规则,一般用于服务端检查

  • eslint-config-prettierarrow-up-right :禁用掉所有那些非必须或者和 prettier 冲突的 ESLint 规则,这样可以避免其他共享配置影响到 Prettier 的格式化。注意该扩展只是将涉及到的规则关掉了(off),所以它只有在和别的配置一起使用的时候才有意义。例如 extends: ["eslint:recommended", "prettier"],prettier 写在最后,后面的规则会覆盖前面的。

插件(plugins)

简单说一下几种常见的插件:

规则(rules)

重点说一下 ESLint 的 rules。官方推荐的规则可以使用 "extends": ["eslint:recommended"] 来开启推荐规则,点击查看详细文档arrow-up-right

ESLint 的规则提示等级:

  • off 或 0:关闭规则

  • warn 或 1:开启规则,warn 级别的错误只是警告,不会导致程序退出

  • error 或 2:开启规则,error 级别的错误当被触发时,程序会推出

ESlint 的规则本身又可以分为两类:

  1. 规则没有属性,只需控制是开启还是关闭,例如:"eqeqeq": "off" 关闭全等校验

  2. 规则有自己的属性,例如:"quotes": ["error", "double"]

还有一点很重要,我们可以通过 rules 这个配置项配置任何想要的规则,它会覆盖 extendsplugins 中引入的配置项,也就是说 .eslintrc.*rules 配置的规则优先级很高。

有时候我们需要使用自定义规则,自定义 ESLint 规则的实现主要在于理解一个 rule 的结构:

例如:no-with

开发一个自定义规则,可以查看官方文档:https://eslint.org/docs/latest/developer-guide/working-with-rules。

有几个开发插件或介绍 ESLint 原理的文章可以看一下:

几个不常见的配置

  • overrides :我们在 .eslintrc.* 的 rules 中配置的规则一般都是全局生效,通过 overrides 可以针对一些文件覆盖一些规则。

  • settings : 通过 settings 可以像每条 rule 传入一些自定义的配置内容。

ESLint 检测配置文件步骤

  1. 先查看有没有内联配置,如果是命令行在查看有没有配置参数

  2. 在要检测的文件同一目录里寻找 .eslintrc.*package.json

  3. 紧接着在父级目录寻找,一直找到文件系统的根目录

  4. 如果在前两步发现有 root: true 的配置,停止在父级目录中寻找 .eslintrc.*

  5. 如果以上步骤都没找到,则回退到用户主目录 ~/.eslintrc 中定义的默认配置

.eslintignore 文件

可以通过在项目根目录创建一个 .eslintignore 文件告诉 ESLint 去忽略特定的文件和目录。.eslintignore 文件是一个纯文本文件,其中的每一行都是一个 glob 模式表明哪些路径应该忽略检测,类似于.gitignore

例如:

ESLint 忽略文件还可以再命令行中通过参数重新设置: eslint . --ignore-path .gitignore,即直接使用 .gitignore 当做 .eslintignore

Prettier

Prettier 官网介绍是这样说的,Prettier 是一个有主见的代码格式化工具,支持多种语言并且集成到了很多编辑器中,并且已经成为了解决所有代码格式问题的优先方案了。

在格式化代码方面,Prettier 和 ESLint 确实有一些重叠,但是从大局观看两者的侧重点不同:ESLint 主要工作是检查代码质量并给出提示,它所能提供的格式化功能很有限(ESLint 也不推荐使用自己的格式化功能),并且只支持 JavaScript/TypeScript;而 Prettier 在格式化代码方面具有更大优势,支持 JavaScript、Flow、TypeScript、CSS、SCSS、Less、JSX、Vue、GraphQL、JSON、Markdown 等语言。

Prettier 命令行

VS Code 使用 Prettier 插件

当我们提交代码时,使用命令行校验代码格式,再回去逐行改动格式,重新提交代码是十分影响效率的行为,另外如果项目过大,改动的文件很多,使用 Prettier 进行格式化的时间可能也会较长。

VS Code 安装了 Prettier 插件,这样在保存文件时就能格式化文件从而实现即时格式化。

安装完 Prettier 插件后,在用户或者工作区设置(即 settings.json)中将 VS Code 的默认格式化程序设置为 Prettier。

例如:

关于特定语言默认有:javascriptjavascriptreacttypescripttypescriptreactjsongraphql。其他的语言可以在 settings.json 中使用 files.associations 关联文件格式。

还是跟 ESLint 一样的问题,既然在 VS Code 中用上了 Prettier 插件能即时进行格式化了,那么是不是就用不到命令行的 Prettier?

答案是还需要命令行的 Prettier ,因为不能保证项目的所有开发者都用了 VS Code,或者也有可能把 Prettier 插件手动关掉了,不管怎样,提交到仓库中的代码必须符合统一的代码规范和编码风格,所以在提交到仓库之前必须要进行一次 Prettier 格式化。

Prettier 配置

配置文件

Prettier 配置文件支持多种形式:

  • 根目录创建 .prettierrc 文件,能够写入 YMLJSON 的配置格式,并且支持 .yaml.yml.json.js

  • 根目录创建 prettier.config.js 文件,并对外 export 一个对象

  • package.json 中新建 Prettier 属性

属性

例如创建 prettierrc.js

.prettierignore 文件

使用 .prettierignore 文件完全忽略(即不重新格式化)某些文件和文件夹,跟 .eslintignore 文件一样。

Prettier 与 ESLint 配合

ESLint 和 Prettier 搭配使用时,他们有交集的那部分规则可能会导致 ESLint 和 Prettier 格式化后的代码格式不一致(比如单双引号/是否使用分号等)。例如 Prettier 格式化代码后再用 ESLint 去检测,会出现一些因为格式化导致的警告或报错,ESLint 进行修复后,又不符合 Prettier 的格式,然后保存的时候又会被格式化,然后陷入“死循环”。

这种问题的主要解决思路是在 ESLint 的规则配置文件上做文章,安装特定的扩展,把其配置到规则的尾部,实现 Prettier 规则对 ESLint 规则的覆盖。

这就需要之前说的 eslint-config-prettierarrow-up-right 扩展,它的作用就是禁用掉所有那些非必须或者和 prettier 冲突的 ESLint 规则。

以上只是把 ESLint 和 Prettier 会产生的一些冲突解决掉了,实现了运行 ESLint 命令会按照 Prettier 的规则做相关校验。但是如果要实现代码格式化,还得需要手动运行 Prettier 的相关命令来进行格式化,社区的解决方案是在使用 eslint --fix 的时候,实际使用 Prettier 来替代 ESLint 的格式化功能。

这时候就需要用到之前讲过的 eslint-plugin-prettierarrow-up-right

此时再执行 eslint --fix 实际使用的是 Prettier 的规则去格式化代码。在 rules 中添加 "prettier/prettier": "error",当代码出现 Prettier 的规则校验出的格式化问题,ESLint 会报错。

如果想同时解决规则冲突和自动格式化,可以通过如下方式简化:

上面的配置等价与下面的配置:

Husky + lint-staged

在整个前端代码规范和编程风格的流程最后两个工具,简单介绍一下。

为了保证仓库中的代码是符合代码规范和编程风格的,最好的方法是确保本地的代码已经通过检查才能 push 到远程,即在本地进行 git commit 操作前触发对代码的检查,所以就需要 githook 工具 husky

不过每次提交都检查所有的文件效率非常低,最好是每次只对当前修改后的文件进行扫描,即只对 git add 加入到 stage 缓存区的文件进行扫描,从而实现只对增量代码进行检查。这里就需要使用 lint-staged 工具来识别被加入到 stage 缓存区的文件。

对当前改动的 .js 文件在提交时进行检测和自动修复,自动修复完成后 lint-staged 默认会把改动的文件再次 add 到暂存区,如果有无法修复的错误会报错提示。

搭配 husky 使用时,修改 .husky/pre-commit,在 commit 之前运行 npx lint-staged 来校验提交到暂存区中的文件:

husky + lint-staged + eslint 更简单的集成方式

使用 mrmarrow-up-right

它其实相当于一个任务,做了三件事:

  • package.json 中增加了 lint-staged 的配置

  • 设置 pre-commit git hook

  • 安装依赖

推荐阅读

Last updated