对于一个成熟的前端团队,统一的编码规范和提交规范尤其重要。要保证秩序井然、风格统一、整齐有序,光把规范写在文档里是没有太多实际价值的。没有人愿意去一条一条看规则,然后背下来,最后在写代码时按照规范来遵守。
如何优雅的开发,守住代码质量的护城河(moat),是尤其值得我们思考的问题。
本文是如上这篇的番外篇,除了原文中的内容外,增加了 StyleLint 来检查样式,增加了 Preiiter 来美化代码并与 ESLint 和 StyleLint 优雅配合,增加了 VSCode 配置来实现整套开发体验在 VSCode 下的开箱即用。
护城河
一个理想的开发体验可以抽象成这样:
只关心业务代码,具备优雅的工作流,调试时所有代码都在源码中,产物符合规范要求。
但要想真正符合规范的要求,光靠字面约束以及开发自觉是远远不够的,必须利用工程手段,让开发在开发过程中能使用自动化的工具来完成规范化的要求,而开发本身可以全身心的投入到业务开发中。
**本文结合 eslint 、 stylelint 、 prettier 、 vscode 、standardjs 、 husky 、 lint-staged 、 commitizen 、commitlint 等工具,系统化的构建了前端规范解决方案。
**
后续考虑把整套规范写成工具(moat),能一键应用到其他项目工程中。
前端编码规范主要包括JS和CSS两部分,分别使用 ESLint 和 Stylelint 来落地工程中使用,同时结合 Prettier 来做编码风格统一。如下图所示:
ESLint + StyleLint + Prettier 搭配完成编码约束的自动化
工程集成了 ESLint,自动发现并修复 JavaScript 中的问题。其中 .eslintrc.js 为 eslint 的配置文件。根据不同的工程,配置会不一样,本文工程使用的配置内容如下:
module.exports = {
env: {
browser: true,
es2021: true,
},
extends: ['plugin:react/recommended', 'standard', 'plugin:prettier/recommended'],
parser: '@typescript-eslint/parser',
parserOptions: {
ecmaFeatures: {
jsx: true,
},
ecmaVersion: 'latest',
sourceType: 'module',
},
plugins: ['react', '@typescript-eslint'],
rules: {
// eslint 规则写这里
'comma-dangle': ['error', 'only-multiline'],
}
}
配置的具体含义以及作用,请参考 [ESLint](https://github.com/eslint/eslint) 官网文档。
需要安装的包有:
eslint: ESLint 的程序入口,在 lint-staged 中设定针对 JS 文件执行该程序
eslint-config-standard: 一套通用的 ESLint 规则配置。
eslint-config-prettier:关闭与 Prettier 可能冲突的 ESLint 规则,解决 ESLint + Prettier 时的冲突问题
eslint-plugin-prettier:Prettier 的插件,使得 ESLint + Prettier 结合使用成为可能。让 Prettier 的格式化操作归属在 ESLint 的过程中执行,对于 Prettier 发现的格式问题,也在 ESLint 的过程中自动修复
其中 eslint-config-standard 就是一套行业通用的 ESLint 规则配置,由 JavaScript Standard Style 提供。具体单项规则可以参考:https://standardjs.com/rules.html
JavaScript Standard Style
上面 ESLint 配置文件中 extends 字段配置的 standard 表示校验以及修复的规则使用 JavaScript Standard Style 标准
standardjs 能提前发现风格及程序问题,减少代码审查过程中反反复复的修改过程,节约大量时间并且保持全局统一。
默认情况下,使用 standardjs 就够了,不用再制定额外的规则,如果实际开发中确有需要,可以在.eslintrc.js 的 rules 中配置
Stylelint 是一个强大、先进的 CSS 代码检查器(linter),能够帮助开发规避 CSS 代码中的错误并保持一致的编码风格。
它具有如下功能:
理解 最新的(modern) CSS 语法和功能
拥有超过 170 条内置规则 以捕获错误并强制执行编码约定
支持 插件 以创建你自己的规则
自动 修复 大多数代码格式上的问题
拥有一个 不断增长的社区,并且被 Google、GitHub 和 WordPress 所使用
还可以被扩展为:
解析 类似 CSS 的语法,例如 SCSS、Sass、Less 以及 SugarSS
能够从 HTML、Markdown 和 CSS-in-JS 对象以及模板文本中提取 内嵌的样式代码
需要安装的包有:
stylelint: Stylelint 的程序入口,在 lint-staged 中设定针对样式文件执行该程序
stylelint-config-standard: Stylelint 约定的规则配置集,Stylelint 按照这个规则执行
stylelint-config-prettier: 关闭与 Prettier 可能冲突的规则,解决 Stylelint + Prettier 时的冲突问题
stylelint-prettier:Prettier 的插件,使得 Stylelint + Prettier 结合使用成为可能。让 Prettier 的格式化操作归属在 Stylelint 的过程中执行,对于 Prettier 发现的格式问题,也在 Stylelint 的过程中自动修复
其中 stylelint-config-standard 就是一套行业通用的 Stylelint 规则配置。包括如下具体规则: The Idiomatic CSS Principles, Google’s CSS Style Guide, Airbnb’s Styleguide, and @mdo’s Code Guide.
Prettier 是一个“有态度”的代码格式化工具,支持大量编程语言。和 ESLint (主要关注语法错误,做了一部分格式化的事情) 相比,更侧重于代码风格以及样式。所以日常开发中需要结合 Prettier 和 ESLint 一起使用,才能优雅无懈可击。
本工程配置,参考 prettier.config.js 文件
需要安装的包有:
prettier
上面完成了 ESLint + Stylelint +Prettier 的配置,已经可以在工程中使用 yarn eslint xx.tsx 、 yarn stylelint xx.less 、yarn prettier xx.md 等来校验和修复不同的文件。但依靠开发手动去执行命令不太现实,依然需要工程化的手段来帮助开发自动完成。
如下介绍使用 husky + lint-staged + commitizen + commitlint 来实现在提交时自动进行校验和修复,同时约束提交本身的格式等。核心流程如下图所示:
提交约束核心流程图示
commitizen 是用来格式化 git commit message 的工具,它提供了一种问询式的方式去获取所需的提交信息。
问询式提交
cz-conventional-changelog 是用来规定提交时需要输入哪些信息,譬如提交的类型是修复问题还是功能开发,提交影响范围等等,cz-conventional-changelog 是官网提供的规则,有追求的前端团队完全可以根据项目实际情况自已开发适合的规则,但现阶段够用了,没必要修改。
由于 windows 平台不支持复用 git commit 来提交,所以可以通过 package.json 中的 cz 脚本命令来提交
// package.json
"scripts": {
"cz": "git-cz"
}
本质上就是在工程根目录执行 git-cz 命令来提交,所以你可以使用 yarn cz**、yarn git-cz、npm run cz、**npx git-cz 任意一个来完成你的提交。
需要安装的包有:
commitizen
cz-conventional-changelog
husky 是处理 git hooks 的工具,能够拦截 git hooks,让“校验提交格式”、“校验代码”等等成为可能。
lint-staged 是针对暂存区进行 lint 操作的工具。一来不用每次 lint 全局的代码节省时间;二来对于老项目应用 lint 规则时,由于历史遗留原因导致所有提交都没法通过,所以也需要只针对即将要提交的代码进行 lint。
工具使用说明详见: husky
结合使用 lint-staged 工具只针对当前修改的部分进行检测。
// package.json
"lint-staged": {
"*.{js,jsx,ts,tsx}": [
"eslint --fix"
],
"*.{less,css}": [
"stylelint --fix"
]
}
安装好 husky 后,项目根目录会多出 .husky 文件夹,用于存在 git hooks 的配置,同时 package.json 中增加 lint-staged 配置,如上所示表示对于 js、jsx、ts、tsx 在提交时自动使用 eslint 进行校验和自动修复, 对于 less、css 在提交时自动使用 styleint 进行校验和修复。
只有通过的代码才会被提交,如果存在不符合规范的,会在提交时报错,按照要求修复即可.
需要安装的包有:
husky:处理 git hooks
lint-staged:只对暂存区生效
使用 husky+lint-staged 会在提交时拦截和自动修复,如果能在开发时实时提示错误,在保存时自动修复错误,就能避免在提交时集中修复错误的问题。如何实现,请参考工程配置章节。
上面通过 commitizen 实现了问询式的提交方式,但没法保证开发遵守这个约定,为了防止开发误操作,使用 git commmit 自行提交代码,所以在提交入库前,使用 commitlint 对提交信息进行校验。
commitlint 是用来校验提交是否符合规范的工具。
需要的安装包有:
@commitlint/cli : 提供校验的执行入口 commitlint , 结合 husky 使用 commmit-msg 的 git hook,在提交代码来执行提交信息的检查,如果不符合提交规范,就会报错提示。
@commitlint/config-conventional 一套通用的提交信息校验方案,是 Angular 团队出品的。如果需要也可定制自己团队的规范。
前面部署了规范以及校验的工具,对于提交也进行了拦截,已经能保证代码的质量。但为了进一步提高开发的效率,不希望在提交时才发现一堆校验错误。
以下以 vscode 为例,实现能在开发过程中 实时提示错误 并 一键自动格式化&修复 的功能,达到所有开发保持一致的开箱即用。
其它编辑器类似,可以参考各自编辑器的配置
如果想要在开发时,编辑器自动提示错误并自动修复,请务必安装 ESLint 插件 和 StyleLint 插件
工程依赖的插件配置在 .vscode/extensions.json, 后续如果有新的依赖插件,可以配置在这里,并提交,保证所有开发者依赖插件的统一。
{
"recommendations": ["dbaeumer.vscode-eslint", "stylelint.vscode-stylelint"]
}
目前只需要 ESLint 、 StyleLint 两个插件。
插件安装好后,对于代码中出错的问题,会显示如下图所示错误提示:
引用于Modern.js ,侵删
同时文件名、右侧预览框中都有提示,非常醒目。
工程依赖的 vscode 配置在 .vscode/setting.json,是这些配置让“编辑器实时提示错误”、“保存时自动修复”、“右键格式化文件时自动修复”成为可能。
安装好插件后,还需要对插件进行相应的配置,才能适应不同的开发需要。
譬如,需要把 typescript、javascript、typescriptreact、javascriptreact 等文件默认格式化的工具设置成 eslint 的自动修复。这样在这些文件里,右键 - 格式化文档 能自动调起 eslint 进行校验和格式化。
StyleLint 同理进行配置。
本文工程的配置如下,开启了保存时自动 lint, 这样在保存文件时,自动完成所有校验和修复。
{
"eslint.run": "onType",
"eslint.codeActionsOnSave.mode": "all",
"eslint.format.enable": true, // 允许eslint 格式化对应的文件
"[typescript]": {
"editor.defaultFormatter": "dbaeumer.vscode-eslint",
"editor.codeActionsOnSave": {
// 开启保存时执行eslint进行校验和格式化
"source.fixAll.eslint": true
},
"editor.formatOnSave": false // 所以编辑器默认的格式化设置为false,避免重复格式化
},
"[javascript]": {
"editor.defaultFormatter": "dbaeumer.vscode-eslint",
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true
},
"editor.formatOnSave": false
},
"[typescriptreact]": {
"editor.defaultFormatter": "dbaeumer.vscode-eslint",
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true
},
"editor.formatOnSave": false
},
"[javascriptreact]": {
"editor.defaultFormatter": "dbaeumer.vscode-eslint",
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true
},
"editor.formatOnSave": false
},
"[sass]": {
"editor.defaultFormatter": "stylelint.vscode-stylelint", // 设置编辑器默认格式化工具为stylelint
"editor.codeActionsOnSave": {
"source.fixAll.stylelint": true // 保存时自动使用sytlelint 修复
},
"editor.formatOnSave": false // 关闭编辑器默认的保存格式化
},
"[css]": {
"editor.defaultFormatter": "stylelint.vscode-stylelint",
"editor.codeActionsOnSave": {
"source.fixAll.stylelint": true
},
"editor.formatOnSave": false
},
"[less]": {
"editor.defaultFormatter": "stylelint.vscode-stylelint",
"editor.codeActionsOnSave": {
"source.fixAll.stylelint": true
},
"editor.formatOnSave": false
}
}
最后希望每一个前端仓库都守城成功!