There are a thousand Hamlets in a thousand people's eyes.
一千个程序员,就有一千种代码风格。在前端开发中,有几个至今还在争论的代码风格差别:javascript
这几个代码风格差别在协同开发中常常会被互相吐槽,甚至不能忍受。前端
除此以外,因为 JavaScript 的灵活性,每每一段代码能有多种写法,这时候也会致使协同时差别。而且,有一些写法可能会致使不易发现的 bug,或者这些写法的性能很差,开发时也应该避免。vue
为了解决这类静态代码问题,每一个团队都须要一个统一的 JavaScript 代码规范,团队成员都遵照这份代码规范来编写代码。固然,靠人来保障代码规范是不可靠的,须要有对应的工具来保障,ESLint 就是这个工具。java
有的读者看到这里,可能会说:Prettier 也能够保证代码风格一致。是的,Prettier 确实能够按照设置的规则对代码进行统一格式化,后面的文章也会有对应的介绍。可是须要明确的一点是,Prettier 只会在格式上对代码进行格式化,一些隐藏的代码质量问题 Prettier 是没法发现的,而 ESLint 能够。node
关于 ESLint,它的 Slogan 是 Find and fix problems in your JavaScript code。如上文所说,它能够发现并修复你 JavaScript 代码中的问题。来看一下官网上描述 ESLint 具有的三个特性:react
基于以上描述,咱们在前端工程化中能够这样使用 ESLint:git
先简单介绍一下如何使用 ESLint,若是已经有所了解的同窗,能够直接跳过这一节。程序员
新建一个包含 package.json
的目录(能够在空目录下执行 npm init -y
),新建一个 index.js
:github
// index.js const name = 'axuebin'
安装 eslint
:typescript
npm install eslint --save-dev
而后执行 ./node_modules/.bin/eslint --init
或者 npx eslint --init
生成一个 ESLint 配置文件 .eslintc.js
:
module.exports = { env: { es2021: true, }, extends: 'eslint:recommended', parserOptions: { ecmaVersion: 12, }, rules: {}, };
生成好配置文件以后,就能够执行 ./node_modules/.bin/eslint index.js
或者 npx eslint index.js
命令对文件进行检查。结果以下:index.js
中的代码命中了 no-unused-vars
这个规则,默认状况下,这个规则是会报 error
的,也就是 ESLint 不容许代码中出现未被使用的变量。这是一个好习惯,有利于代码的维护。
咱们来尝试配置 ESLint 的检查规则。以分号和引号举例,如今你做为团队代码规范的指定人,但愿团队成员开发的代码,都是单引号和带分号的。
打开 .eslintrc.js
配置文件,在 rules
中添加相关配置项:
module.exports = { env: { es2021: true, }, extends: 'eslint:recommended', parserOptions: { ecmaVersion: 12, }, rules: { semi: ['error', 'always'], quotes: ['error', 'single'], }, };
而后咱们将 index.js
中的代码改为:
// index.js const name = "axuebin"
执行 eslint
命令以后:
能够看到检查结果以下:
老老实实地按照规范修改代码,使用单引号并将加上分号。固然,若是大家但愿是双引号和不带分号,修改相应的配置便可。
具体各个规则如何配置能够查看:https://eslint.org/docs/rules
执行 eslint xxx --fix
能够自动修复一些代码中的问题,将没法自动修复的问题暴露出来。好比上文中提到的引号和分号的问题,就能够经过 --fix
自动修复,而 no-unused-vars
变量未使用的问题,ESLint 就没法自动修复。
在 init
生成的配置文件中,咱们看到包含这一行代码:
module.exports = { extends: "eslint:recommended" }
这一行代码的意思是,使用 ESLint 的推荐配置。 extends: 'xxx'
就是 继承,当前的配置继承于 xxx
的配置,在此基础上进行扩展。
所以,咱们也可使用任意封装好的配置,能够在 NPM 上或者 GItHub 上搜索 eslint-config
关键词获取,本文咱们将这类封装好的配置称做 “配置集”。比较常见的配置包有如下几个:
简单了解完 ESLint 以后,对于 ESLint 的更多使用细节以及原理,在本篇文章就不展开了,感兴趣的朋友能够在官网详细了解。本文重点仍是在于如何在团队工程化体系中落地 ESLint,这里提几个最佳实践。
对于独立开发者以及业务场景比较简单的小型团队而言,使用现成、完备的第三方配置集是很是高效的,能够较低成本低接入 ESLint 代码检查。
可是,对于中大型团队而言,在实际代码规范落地的过程当中咱们会发现,不可能存在一个可以彻底符合团队风格的三方配置包,咱们仍是会在 extends
三方配置集的基础上,再手动在 rules
配置里加一些自定义的规则。时间长了,有可能 A 应用和 B 应用里的 rules
就不同了,就很难达到统一的目的。
这时候,就须要一个中心化的方式来管理配置包:根据团队代码风格整理(或者基于现有的三方配置集)发布一个配置集,团队统一使用这个包,就能够作到中心化管理和更新。
除此以外,从技术层面考虑,目前一个前端团队的面对的场景可能比较复杂。好比:
以上问题在真实开发中都是存在的,因此在代码规范的工程化方案落地时,一个单一功能的配置集是不够用的,这时候还须要考虑这个配置集如何抽象。
为了解决以上问题,这里提供一种解决方案的思路:
具体拆解来看,就是有一个相似 eslint-config-standard 的基础规则集(包括代码风格、变量相关、ES6 语法等),在此基础之上集成社区的一些插件(Vue/React)等,封装成统一的一个 NPM Package 发布,消费时根据当前应用类型经过不一样路径来 extends 对应的配置集。
这里有一个 Demo,感兴趣的朋友能够看一下:eslint-config-axuebin
ESLint 提供了丰富的配置供开发者选择,可是在复杂的业务场景和特定的技术栈下,这些通用规则是不够用的。ESLint 经过插件的形式赋予了扩展性,开发者能够自定义任意的检查规则,好比 eslint-plugin-vue / eslint-plugin-react 就是 Vue / React 框架中使用的扩展插件,官网也提供了相关文档引导开发者开发一个插件。
通常来讲,咱们也不须要开发插件,但咱们至少须要了解有这么个东西。在作一些团队代码质量检查的时候,咱们可能会有一些特殊的业务逻辑,这时候 ESLint 插件是能够帮助咱们作一些事情。
这里就不展开了,主要就是一些 AST 的用法,照着官方文档就能够上手,或者能够参考现有的一些插件写法。
当有了团队的统一 ESLint 配置集和插件以后,咱们会将它们集成到脚手架中,方便新项目集成和开箱即用。可是对于一些老项目,若是须要手动改造仍是会有一些麻烦的,这时候就能够借助于 CLI 来完成一键升级。
本文结合上文的 Demo eslint-config-axuebin,设计一个简单的 CLI Demo。因为当前配置也比较简单,因此 CLI 只须要作几件简单的事情便可:
.eslintrc.js
文件package.json
的 scripts
中写入 "lint": "eslint src test --fix"
核心代码以下:
const path = require('path'); const fs = require('fs'); const chalk = require('chalk'); const spawn = require('cross-spawn'); const { askForLanguage, askForFrame } = require('./ask'); const { eslintrcConfig, needDeps } = require('./config'); module.exports = async () => { const language = await askForLanguage(); const frame = await askForFrame(); let type = language; if (frame) { type += `/${frame}`; } fs.writeFileSync( path.join(process.cwd(), '.eslintrc.js'), `// Documentation\n// https://github.com/axuebin/eslint-config-axuebin\nmodule.exports = ${JSON.stringify( eslintrcConfig(type), null, 2 )}` ); const deps = needDeps.javascript; if (language === 'typescript') { deps.concat(needDeps.typescript); } if (frame) { deps.concat(needDeps[frame]); } spawn.sync('npm', ['install', ...deps, '--save'], { stdio: 'inherit' }); };
可运行的 CLI Demo 代码见:axb-lint,在项目目录下执行:axblint eslint
便可,如图:
配置了 ESLint 以后,咱们须要让开发者感知到 ESLint 的约束。开发者能够本身运行 eslint 命令来跑代码检查,这不够高效,因此咱们须要一些自动化手段来作这个事情。固然 在开发时,编辑器也有提供相应的功能能够根据当前工做区下的 ESLint 配置文件来检查当前正在编辑的文件,这个不是咱们关心的重点。
通常咱们会在有如下几种方式作 ESLint 检查:
这里提一下 pre-commit 的方案,在每一次本地开发完成提交代码前就作 ESLint 检查,保证云端的代码是统一规范的。
这种方式很是简单,只须要在项目中依赖 husky 和 lint-staged 便可完成。安装好依赖以后,在 package.json 文件加入如下配置便可:
{ "lint-staged": { "*.{js,jsx,ts,tsx}": "eslint --cache --fix" }, "husky": { "hooks": { "pre-commit": "lint-staged" } } }
效果如图所示:
若是代码跑 ESLint 检查抛了 Error 错误,则会中断 commit 流程:
这样就能够确保提交到 GitHub 仓库上的代码是统一规范的。(固然,若是认为将这些配置文件都删了,那也是没办法的)
本文介绍了 ESLint 在中小型前端团队的一些最佳实践的想法,你们能够在此基础上扩展,制订一套完善的 ESLint 工做流,落地到本身团队中。
本文是前端代码规范系列文章的其中一篇,后续还有关于 StyleLint/CommitLint/Prettier 等的文章,而且还有一篇完整的关于前端代码规范工程化实践的文章,敬请期待(也有可能就鸽了)。
更多原创文章欢迎关注公众号「玩相机的程序员」,或者加我微信 xb9207 交流