我正在参加「掘金·启航计划」
demo 仓库地址:github.com/cheerioInf/…
为什么需要 Lint
工具链?
- 统一的代码风格:尤其是在多人合作的情景下,每个开发者都有自己的代码偏好,这可能导致整体项目代码风格混乱杂糅,难以阅读,
Lint
工具可以统一代码风格,如缩进、命名风格、空格使用、每行最大字数等。 - 错误检查和预防:可以讲一些语法错误在开发阶段提前规避掉,还可以检测未使用的变量、使用未声明的变量等。
这两方面都能帮助我们提高整个项目等代码质量,提高项目的可维护性。
本次分享我们将围绕 ESLint
、Prettier
、StyleLint
、commitLint
等主流 Lint
工具展开,配合 husky
、lint-staged
、VSCode
插件、Vite
生态搭建完整的 lint
工具链。
JS/TS 规范工具:ESLint
ESLint is a tool for identifying and reporting on patterns found in ECMAScript/JavaScript code, with the goal of making code more consistent and avoiding bugs.
ESLint
是在 ECMAScript/JavaScript
代码中识别和报告模式匹配的工具,它的目标是保证代码的一致性和避免错误。
使用 ESLint
并不复杂,ESLint
是完全可插入的,主要通过配置文件对各种代码格式的规则 rules
进行配置,我们可以使用开源社区的一些成熟规范集,如 谷歌 JS 规范、standard JS、Airbnb 规范 等,也可以定制一套团队独有的代码规范。
初始化
通过 ESLint
官方的 cli
在**现有的脚手架项目(确保已经有一个 package.json
文件)**中进行初始化,首先安装 ESLint
:
pnpm i eslint -D
接着执行 ESLint
的初始化命令:
npx eslint --init
- How would you like to use ESLint?
- To check syntax only => 检查语法,如缺少分好、不正确的标识符等。
- To check syntax and find problems => 检查语法、并发现错误,包括未使用的变量、使用未声明的变量等。
- ✅ To check syntax, find problems, and enforce code style => 检查语法、发现错误,强制执行代码风格。
- What type of modules does your project use?
- ✅ Javascript module (import/export) => 选择
ESM
规范。 - CommonJS (require/exports) => 选择
CJS
规范。
- ✅ Javascript module (import/export) => 选择
- Which framework does your project use?
- ✅ React
- Vue
- None of these
- Where does your code run?
- ✅ Browser
- Node
- How would you like to define a style for your project?
- Use a popular style guide => 选择一些现有的
ESLint
规范。 - ✅ Answer questions about your style => 通过回答问题确定自己的风格。
- Use a popular style guide => 选择一些现有的
- What format do you want your config file to be in?
- ✅ Javascript
- YAML
- JSON
之后在根目录会生产 .eslintrc.cjs
文件,如下所示:
module.exports = {
// 运行环境,环境并不互斥,可以一次定义多个环境
"env": {
"browser": true,
"es2021": true
},
// 继承
"extends": [
"eslint:recommended", // eslint 推荐规则
"plugin:@typescript-eslint/recommended", // ts 推荐规则
"plugin:react/recommended" // react 推荐规则
],
// 解析器
"parser": "@typescript-eslint/parser",
// 解析器配置
"parserOptions": {
"ecmaVersion": "latest",
"sourceType": "module" // 默认为 script,使用 esm 时需要设置为 module
},
// 插件
"plugins": [
"@typescript-eslint", // 添加 ts 的相关规则支持
"react" // 添加 react 的相关规则支持
],
// 规则
"rules": {
"indent": [
"error",
"tab"
],
"linebreak-style": [
"error",
"unix"
],
"quotes": [
"error",
"double"
],
"semi": [
"error",
"always"
]
}
};
我们来了解一下这个配置文件里面会出现的几个字段。
配置解读
parser 解析器
ESLint
底层默认使用 Espree
来进行 AST
解析,其基于 Acron
来实现,不支持 TypeScript
,因此需要引入其他的解析器完成 TS
的解析。
社区提供了 @typescript-eslint/parser
,将 TS
代码转化为 Espree
能识别的格式,然后在 ESLint
下检查。
parserOptions 解析器配置
解析器格外配置,包含如 esmaVersion
、sourceType
、ecmaFeatures
等。
rules 代码规则
在 rules
对象中,key
一般为规则名,value
为具体的配置内容。
其中,off
表示关闭规则,warn
表示开启规则作为警告,违背规则后抛出 warning
,不会导致程序退出,error
表示开启规则,违背规则后抛出错误,并退出程序。
plugins 插件
和上面提到的 ESLint
的默认 parser
espree
不能直接解析 TypeScript
一样,ESLint
本身没有内置 TS
的代码规则,我们就需要添加插件来增加特定的规则,比如 @typescript-eslint/eslint-plugin
。
引入后并没有默认开启这些规则,同样也需要我们去 rules
里面添加规则设置。
extends 继承
extends
相当于是继承另一份 ESLint
配置,主要为三种情况:
- 从
ESLint
本身继承:eslint:recommend
- 从第三方包继承
- 从插件中继承:
plugin:react/recommended
env 和 globals
这两个配置分别代表运行环境和全局变量。JavaScript
生态有多种运行时、版本、扩展和框架。其中每一个都可以有不同的支持语法和全局变量,我们可以指定项目的运行环境:
module.export = {
"env": {
"browser": "true",
"node": "true"
}
}
指定之后便会启用浏览器和 Node.js
环境,这两个环境中的一些全局变量如 window
、global
会同时启用。
有些全局变量是第三方库所声明,这里就需要在 globals
配置中声明全局变量:
writable
表示变量可重写readonly
表示变量不可重写off
表示禁用该全局变量
以 jquery
为例:
module.exports = {
"globals": {
// 不可重写
"$": false,
"jQuery": false
}
}
代码格式化工具:Prettier
虽然 ESLint
本身具备自动化修复的功能,但术业有专攻, ESLint
的主要优势在于代码风格的检查并给出提示,而在代码格式化层面,Prettier
更加专业,因此我们经常讲 ESLint
结合 Prettier
一起使用。
基础用法
首先安装 prettier
:
pnpm i prettier -D
之后在根目录创建配置文件 .prettierrc.js
,填入以下内容:
module.exports = {
printWidth: 80, //一行的字符数,如果超过会进行换行,默认为80
tabWidth: 2, // 一个 tab 代表几个空格数,默认为 2 个
useTabs: true, //是否使用 tab 进行缩进,默认为false,表示用空格进行缩减
singleQuote: false, // 字符串是否使用单引号,默认为 false,使用双引号
semi: true, // 行尾是否使用分号,默认为true
trailingComma: "none", // 是否使用尾逗号
bracketSpacing: true // 对象大括号直接是否有空格,默认为 true,效果:{ a: 1 }
};
之后我们讲 prettier
集成到现有的 ESLint
工具中,首先安装两个包:
pnpm i eslint-config-prettier eslint-plugin-prettier -D
eslint-config-prettier
用来覆盖 ESLint
本身的规则配置,eslint-plugin-prettier
用来让 prettier
接管 eslint --fix
修复代码的能力。
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/recommended",
"plugin:react/recommended",
"prettier",
"plugin:prettier/recommended"
],
在 extends
里面加入 prettier
以及 plugin:prettier/recommended
扩展。
"plugins": [
"@typescript-eslint",
"react",
"prettier"
],
在 plugins
中加入 prettier
插件。
"rules": {
"prettier/prettier": "error",
// ...
}
在 rules
加入"prettier/prettier": "error"
开启 prettier
自动修复功能。
最后我们在 package.json
中定义脚本:
{
"scripts": {
"lint:script": "eslint --ext .js,.jsx,.ts,.tsx --fix --quiet ./src",
}
}
之后在终端运行:
pnpm run lint:script
即可完成 ESLint
的规则检查以及 Prettier
的自动修复。
我们还需要在 rules
里面补充一个规则,防止我们在 jsx
文件中每次都要引入 react
:
rules: {
// ...
"react/react-in-jsx-scope": "off"
}
我们还可以在 VSCode
中安装 ESLint
和 Prettier
插件,在设置中开启 Format On Save
:
即可开启保存自动格式化功能。
在 vite 中接入 ESLint
我们也可以将 ESLint
接入 vite
,在开发阶段进行 ESLint
扫描,将规范问题和源文件定位以命令行的形式展现出来。
首先安装 vite-plugin-eslint
插件:
pnpm i vite-plugin-eslint -D
之后我们在 vite.config.ts
中接入插件:
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
import viteEslint from "vite-plugin-eslint";
// https://vitejs.dev/config/
export default defineConfig({
plugins: [react(), viteEslint()]
});
就完成了我们的配置。该插件会启动另外一个进程来进行 ESLint
的扫描工作,因此不会影响到项目的启动速度。
样式规范工具:Stylelint
一个强大的 CSS 规范工具,可帮助您避免错误并强制执行约定。
通过该样式规范工具,可以帮助解决常见的如重复的选择器、禁止使用指定的单位等等。
同样 Stylelint
在规范检查方面做的足够专业,而在代码格式化方面,我们依然需要 Prettier
的帮助。
首先,我们安装 Stylelint
及其相关的工具:
pnpm i stylelint stylelint-prettier stylelint-config-prettier stylelint-config-recess-order stylelint-config-standard stylelint-config-standard-scss -D
之后我们新建 .stylelintrc.js
配置文件:
module.exports = {
// 注册 stylelint 的 prettier 插件
plugins: ['stylelint-prettier'],
// 继承一系列规则集合
extends: [
// standard 规则集合
'stylelint-config-standard',
// standard 规则集合的 scss 版本
'stylelint-config-standard-scss',
// 样式属性顺序规则
'stylelint-config-recess-order',
// 接入 Prettier 规则
'stylelint-config-prettier',
'stylelint-prettier/recommended'
],
// 配置 rules
rules: {
// 开启 Prettier 自动格式化功能
'prettier/prettier': true
}
};
之后我们在添加脚本命令:
{
"scripts": {
// 整合 lint 命令
"lint": "npm run lint:script && npm run lint:style",
"lint:script": "eslint --ext .js,.jsx,.ts,.tsx --fix --quiet ./src",
// stylelint 命令
"lint:style": "stylelint --fix \"src/**/*.{css,scss}\""
}
}
之后执行 pnpm run lint:style
即可完成对样式代码的规范检查和自动格式化。
也可以安装 VSCode
中 Stylelint
插件,实现在开发阶段感知问题,提前修复。
同样也可以在 vite
中接入 Styleint
,在命令行体现规范问题,定位源文件。
pnpm i vite-plugin-stylelint -D
import viteStylelint from "vite-plugin-stylelint";
export default defineConfig({
plugins: [
// ...
viteStylelint({
// 排除检查
exclude: ["node_modules/**", "dist/**"]
})
]
});
Husky、lint-staged 的 git 提交工作流
Husky
上面我们配置的 ESLint
、StyleLint
都只是将问题暴露,我们还需要实现在代码提交的时候,进行拦截检查,只有通过代码规范检查才允许正常提交代码,否则还是可能会导致线上代码出现不符合规定的情况。
社区中已经有对应的工具 Husky
来帮助我们解决这个问题了。
首先我们安装一下 Husky
:
pnpm i husky -D
初始化 Husky
(前提是你的项目得是一个 git
仓库):
npx husky install
添加启动脚本:
{
"scripts": {
// 会在安装 npm 依赖后自动执行
"prepare": "husky install"
}
}
添加 husky
钩子:
npx husky add .husky/pre-commit "npm run lint"
该命令会在 .husky
目录下创建 pre-commit
文件,里面存放了在 git commit
前要执行的脚本,这里是在 git commit
前,对代码规范 lint
进行检查,检查通过之后才会提交代码。
lint-staged
如果我们仅仅只使用 husky
的话,npm run lint
是对仓库中的代码进行全量检查,也就意味着,当项目逐渐庞大起来,即使有很多文件并没有改动,但是每次提交时还是会进行规范化检查,就会增加提交的时间。
而 lint-staged
工具就是用来解决该问题的,可以实现只对暂存区的代码进行规范化检查,大大提高了提交代码的效率。
首先安装 lint-staged
:
pnpm i lint-staged -D
之后在 package.json
中加入:
"lint-staged": {
"**/*.{js,jsx,tsx,ts}": [
"npm run lint:script",
"git add ."
],
"**/*.{scss}": [
"npm run lint:style",
"git add ."
]
},
最后,在 husky
的 pre-commit
中将原来的 npm run lint
脚本改为:
npx --no -- lint-staged
提交规范工具:commitlint
除了代码规范之外,代码提交信息规范也不可忽略。commitlint
能够帮助我们解决这个问题。
首先安装 commitlint
及其相关工具:
pnpm i commitlint @commitlint/cli @commitlint/config-conventional -D
然后我们新建 .commitlintrc.cjs
配置文件:
module.exports = {
extends: ["@commitlint/config-conventional"]
};
一般来讲我们直接继承 commitlint/config-conventional
的规则就行了。
其提交信息由两部分组成:
// type 指提交的类型
// subject 指提交的摘要信息
<type>: <subject>
常用的 type
值包括如下:
feat
:添加新功能。fix
:修复 Bug。chore
:一些不影响功能的更改。docs
:专指文档的修改。perf
:性能方面的优化。refactor
:代码重构。test
:添加一些测试代码等等。
最后我们将 commit-lint
集成到 husky
当中:
npx husky add .husky/commit-msg "npx --no-install commitlint -e $HUSKY_GIT_PARAMS"
我们随便输入一个 commit
信息,进行测试:
会发现已经拦截成功了。
原文链接:https://juejin.cn/post/7247715962379173949 作者:cheerioInf