1. 引入扫描工具的初衷
1.1 针对痛点
目前在梳理前端应用时发现很多代码不规范的地方, 包括简单的 JS 问题以及代码格式化的问题, 造成了代码可读性下降, 另外各种历史代码也是 "风格迥异", 甚至影响了应用质量. 应用开发成员大部分由于之前是开发后端, 对前端开发经验不足以及许多前端知识体系都是在开发过程中现学现用慢慢积累的, 另外, 痛定思痛总在想对于前端应用代码质量是否也存在诸如 Java 开发规约扫描插件, 类似的前端代码质量扫描插件进行把控. 经过查阅资料, 采用 eslint+husky+prettier+lint-staged 方式来对前端质量进行一定程度上的提升, 之所以采用这样的方式, 针对的痛点如下:
代码规范落地难: 代码规约相当于团队乃至公司的整个技术团队协作的契约, 同时这些规范是经过许许多多前辈大师经过项目的洗礼留下的宝贵财富可以在开发中少走很多的弯路, 但是, 面对开发规范经常面临的现状是很难落地, 总是 "拆东墙补西墙", 归根结底在于需要工具去强行保证代码必须经过代码开发规范的扫描;
低质量代码带入线上应用: 在实际开发现状中开发人员可以很简单的执行 Git push 操作将本地代码带入远程分支上, 如果代码质量低下就很容易对线上应用质量埋下隐患, 至于在合并的时候在进行 CR, 这样反馈链路太长, 最好的方式本地进行 commit 的时候, 最起码需要保证当前代码能够满足团队制定的开发规范, 如果不通过, commit 都无法成功, 这样能够从最源头保证代码质量问题;
代码格式难统一: 按照现状团队的开发成员对代码的格式都有很大的不同, 甚至有些人字符串喜欢用双引号, 有的人喜欢使用单引号等等问题, 如果代码格式化问题不统一, 总觉得互相查看其它人的代码总觉得怪怪的, 甚至代码格式错乱, 严重影响了代码可读性, 无疑也增加了团队内的沟通成本, 针对这样的情况, 需要一种工具能够保证团队内代码的格式是一致;
代码质量文化难落地: 通过引入代码质量工具, 在开发过程中能够时刻对自身代码质量进行约束, 逐渐培养自身对代码质量有 "洁癖" 的开发观念, 同时也会成为团队乃至自身对质量文化落地的一个抓手.
针对以上痛点, 采用 eslint+husky+prettier+lint-staged 这几个工具能够有效解决上述问题, 其中执行流程和原理在下面给出(同时关于对代码质量文化另一个抓手 - CR 也可见于这篇文章).
1.2 达成效果
要想防患于未然, 防止将存在潜在问题的代码带到线上环境, 最好的办法是在本地提交代码时就能够扫描出潜在的错误, 并强制将其修改后才能提交, 这样就不会将问题代码携带到线上, 就能保证线上代码至少不会存在低级的程序错误. 针对这样的诉求, 可以采用 husky,lint-staged,eslint 以及 prettier 插件来实现, 具体效果如下:
如上图, 当试图 commit 代码时, 由于扫描出错误就不能进行提交成功, 必须将其修改成功方可 commit.
1.3 配置文件
在前端应用中的 package.JSON 中新增如下文件:
- {
- "scripts": {
- "precommit": "lint-staged"
- },
- "lint-staged": {
- "src/**/*.js": [
- "eslint --fix --ext .js",
- "prettier --write",
- "git add"
- ]
- },
- "devDependencies": {
- "eslint": "^5.0.0",
- "eslint-config-ali": "^2.0.1",
- "eslint-plugin-import": "^2.6.0",
- "eslint-plugin-react": "^7.1.0",
- "husky": "^0.14.2",
- "babel-eslint": "^8.1.1",
- "lint-staged": "^4.0.0",
- "prettier":"^1.16.4",
- "eslint-plugin-prettier":"^3.0.1",
- "eslint-config-prettier":"^4.0.0"
- },
- }
增加. eslintrc.JS 扫描规则:
- module.exports = {
- "extends": ["eslint-config-ali","prettier", "plugin:prettier/recommended"],
- "parser": "babel-eslint",
- "rules": {
- "prettier/prettier": "error",
- "strict": "off",
- "no-console": "off",
- "import/no-dynamic-require": "off",
- "global-require": "off",
- "require-yield": "off",
- },
- "plugins": ["prettier"],
- "globals": {
- "React": "readable"
- }
- };
增加. prettierrc.JS 文件, 用于在扫描通过后格式化代码(该步骤可选, 如果不引入 prettier 的话, 相应的在 package 和 eslintrc 中去除掉相应配置即可)
- module.exports = {
- printWidth: 80,
- semi: true,
- singleQuote: true,
- trailingComma: 'none',
- bracketSpacing: true,
- jsxBracketSameLine: false,
- arrowParens: 'avoid',
- requirePragma: false,
- proseWrap: 'preserve'
- };
在前端工程中引入以上的配置文件即可, 这样就可以达到 1.3 中的效果. 置于其中的实现原理在下面进行分析, 有兴趣的可以继续往下看
2. 实现原理
2.1 执行流程
达到上述效果, 执行的流程如下:
待提交的代码 Git add 添加到暂存区;
执行 Git commit;
husky 注册在 Git pre-commit 的钩子函数被调用, 执行 lint-staged;
lint-staged 取得所有被提交的文件依次执行写好的任务(ESLint 和 Prettier);
如果有错误 (没通过 ESlint 检查) 则停止任务, 同时打印错误信息, 等待修复后再执行 commit;
成功 commit, 可 push 到远程
在上述流程中, 有这样几个核心点:
husky 注册 Git 的钩子函数保证在 Git 执行 commit 时调用代码扫描的动作;
eslint 完成按照配置的规则进行扫描;
Lint-staged 保证只对当前 add 到 Git stage 区的文件进行扫描操作, 这样做的原因在于, 如果对全工程的文件进行扫描的话, 并且之前的前端工程并未注重代码规则的检测的话, 很大可能性会出现成百上千的 error, 基本上心里是崩溃的. 因此, 只对当前 add 的文件进行检测, 达到及时止损的目的, 历史代码可以切到新的分支进行修复后再进行合并.
2.2 插件说明
在 2.1 中的执行流程中主要使用到 eslint,lint-staged 等插件, 下面分别对这几个插件进行说明.
2.2.1 eslint
lint 是什么?
lint 是对前端代码按照代码规则进行静态扫描的工具, 主要负责对当前本地代码进行规范检查, 如果不符合当前制定的规范则 lint 则会报出 error, 并且和 lint-staged 结合使用就会保证未通过代码规范的检查不能被提交到远程分支上, 这样就能保证线上代码的质量.
为什么要引入 eslint?
引入 eslint 在我的思考中可以具备如下的优点:
既然是代码扫描的工具, 自然可以保证开发规约的落地, 诸如 java 开发规约的扫描插件, 对于前端而言 eslint 就是这样的一个工具, 通过配置代码规范来确保指定的代码规约进行落地. 常见的一些大厂的代码规范有阿里的前端规范 https://www.npmjs.com/package/eslint-config-ali ,airbnb, 鹅厂 alloyteam 团队 http://www.alloyteam.com/2017/08/13065/ 等;
确保应用的线上质量, 这点无须赘述, 结合其他工具的使用, 不满足代码规范的代码都不能 push 到远程分支上去;
更高的可读性, eslint 会对代码质量进行扫描, 并且一般结合 prettier 使用的话, 在通过代码规范后可以对代码进行格式化, 可以保证代码可读性;
避免低级的错误, 通过 eslint --fix 可以根据规范对代码的部分低级问题进行更正.
怎样使用 eslint?
按照文章开头给出的 package.JSON 进行配置即可, 关于 lint 的使用可以看官方文档 https://eslint.org/docs/user-guide/configuring ,eslint 配置的代码规范也在文章给出的 eslintrc.JS 中给出, 所谓代码规范自然而然是根据团队现状指定的, 我们当前采用的是阿里前端规范 eslint-config-ali, 当然也可以按根据现状 "因地制宜" 的去制定. 另外需要指出的是, 在 eslintrc.JS 配置文件中配置了 globals 变量:
- "globals": {
- "React": "readable"
- }
这是因为前端使用的 React 框架, eslint 会对 React 等变量进行扫描会报出 no-undefined 的 error, 需要另其为 global 变量才能避开扫描. 在 eslint 的 rules 的设计中是可配置化的, 在 rules 的属性中可以设置, 具体 eslint 的 rule 可见官方文档 https://eslint.org/docs/rules/ , 其中打勾的是 eslint:recommended 推荐使用的规则.
2.2.2 husky
试想如果将代码已经 push 到远程后, 再进行扫描发现多了一个分号然后被打回修改后才能发布, 这样是不是很崩溃, 最好的方式自然是确保本地的代码已经通过检查才能 push 到远程, 这样才能从一定程度上确保应用的线上质量, 同时也能够避免 lint 的反馈流程过长的问题.
那么什么时候开始进行扫描检查呢? 这个时机自然而然是本地进行 Git commit 的时候, 如果能在本地执行 Git commit 操作时能够触发对代码检查就是最好的一种方式. 这里就需要使用的 Git hook.
什么是 Git 的 hook
Git 的 hook 可以理解成当执行如 Git add,Git commit 等 Git 操作时的回调, 可以查看. Git 文件下的 hooks 目录, 这里存放的是 Git 相关操作的一些脚本例子. 通过 Git hook 就可以在本地进行 commit 的时候触发代码扫描来确保本地代码的质量. 关于 Git hook 可以看这篇文章 https://www.jianshu.com/p/f0d31f92bfab .
2.2.3 lint-staged
在使用 eslint 和 husky 能够保证代码的质量问题, 但是在实际工程中却还必须面临一个问题. 现实情况下, 一个应用一般是多个开发参与, 并且在应用的生命周期中还涉及到人员变更, 这就意味着一个应用是被来自 "五湖四海" 人共同维护, 难不免有 "广式烧腊, 天津狗不理" 各种口味, 更难免的还有 "臭味相投" 的.
针对这些历史代码时, 如果提交代码时, 对其他未修改文件都进行检查, 一下出现成百上千个错误, 估计会吓得立马删掉管理 eslint 的配置, 冒出一身冷汗. 如下图所示(来源于网络)
修改了 A 文件, B,C,D 等文件的错全部都冒出来了. 针对这样的痛点问题, 就是每次只对当前修改后的文件进行扫描, 即进行 Git add 加入到 stage 区的文件进行扫描即可, 完成对增量代码进行检查. 如何实现呢? 这里就需要使用到 lint-staged 工具来识别被加入到 stage 区文件. 关于 lint-stage 可以看官方文档 https://github.com/okonet/lint-staged , 现在会过头来看 package.JSON 文件就能够理解其中的意思:
- "scripts": {
- "precommit": "lint-staged"
- },
- "lint-staged": {
- "src/**/*.js": [
- "eslint --fix --ext .js",
- "prettier --write",
- "git add"
- ]
- },
在进行 Git commit 的时候回触发到 Git hook 进而执行 precommit, 而 precommit 脚本引用了 lint-staged 配置表明只对 Git add 到 stage 区的文件进行扫描, 具体 lint-staged 做了三件事情: 1. 执行 eslint --fix 操作, 进行扫描, 若发现工具可修复的问题进行 fix;2. 执行 prettier 脚本, 这是对代码进行格式化的, 在下面具体来说; 3. 上述两项任务完成后对代码重新 add.
2.2.4 prettier
Prettier 工具主要用来统一代码格式的, eslint 也会对代码进行一定程度的格式校验, 但主要是用来对代码规范的扫描, 而 prettier 则是专门用来对代码进行格式化, 两个工具各司其职, 为代码质量进行保驾护航. 它的主要原理是将格式化前的代码和格式化后的代码进行比对, 如果发现不一样, prettier 就会对其进行标记并按照指定的格式化规范进行修复. 下面的图可以看出 prettier 的能力(配套来源于网络)
可以看出 prettier 能够对代码进行格式化, 这样就可以保证代码的可读性. perttier 能够支持多种格式如 JSX,html 等等, 具体可查看官方文档 https://prettier.io/docs/en/index.html , 对代码格式化标准可以根据团队现状共同来决定.
与 eslint 配合使用的插件
为了和 eslint 配合使用需要引入两个插件 eslint-plugin-prettier 和 eslint-config-prettier, 其中需要说明的是 eslint-config-prettier 插件的作用, 这个插件是如果 eslint 的规则和 prettier 的规则发生冲突的时候(主要是不必要的冲突), 例如 eslint 限制了必须单引号, prettier 也限制了必须单引号, 那么如果用 eslint 驱动 prettier 来做代码检查的话, 就会提示 2 种报错, 虽然他们都指向同一种代码错误, 这个时候就会由这个插件来关闭掉额外的报错. 关于 eslint-config-prettier 可以看它的官方文档 https://github.com/prettier/eslint-config-prettier .
3. IDE 插件配套使用
在实际开发中可以在 IDE 中安装适配的插件来提升开发效率, 安装开发插件后在编码的时候如果存在不符合规范的地方会有红色的波浪线提示, 并且有一键 fix 的功能, 这样能够提升效率. 下面以 webstorm 举例
eslint 的插件安装方式
如图, 在 webstorm 中只需要指定 eslint 的配置文件即可.
prettier 插件的安装方式
如图, webstorm 已经内置了 prettier 功能, 只需要保证当前工程已经安装了 prettier package 即可.
4. 写在最后
通过引入以上这些工具能够在一定程度上保证应用的质量问题, 并能达到事半功倍的效果. 但归根结底, 对代码质量的提升需要自身与内心达成契约, 也需要团队之间志趣相投. 对代码质量能够保证最起码的 "洁癖", 如果和 coder 这项事业, 确认过眼神他就是对的人, 那么也请和他一起往后余生, 内心所至, 全都是你.
5. References
Git commit 前检测 husky 与 pre-commit https://www.jianshu.com/p/f0d31f92bfab
使用 ESlint,lint-staged 半自动提升项目代码质量 https://www.jianshu.com/p/cdd749c624d9
用 husky 和 lint-staged 构建超溜的代码检查工作流 https://segmentfault.com/a/1190000009546913
梳理前端开发使用 eslint 和 prettier 来检查和格式化代码问题
AlloyTeam ESLint 配置指南 http://www.alloyteam.com/2017/08/13065/
使用 ESLint+Prettier 来统一前端代码风格 https://segmentfault.com/a/1190000015315545
用 eslint + prettier + pre-commit 管理项目(React) https://segmentfault.com/a/1190000015862803
React-native ESLint & Prettier & Pre-commit Hook 配置 https://www.cnblogs.com/qiqi715/p/10247598.html
用 eslint + prettier + pre-commit 管理项目(React)
Prettier 介绍与基本用法 https://www.jianshu.com/p/d6a69eb08f07
来源: https://juejin.im/post/5c67fcaae51d457fcb4078c9