我是如何在项目中使用 Lint 工具链的?

我正在参加「掘金·启航计划」

demo 仓库地址:github.com/cheerioInf/…

为什么需要 Lint 工具链?

  1. 统一的代码风格:尤其是在多人合作的情景下,每个开发者都有自己的代码偏好,这可能导致整体项目代码风格混乱杂糅,难以阅读,Lint 工具可以统一代码风格,如缩进、命名风格、空格使用、每行最大字数等。
  2. 错误检查和预防:可以讲一些语法错误在开发阶段提前规避掉,还可以检测未使用的变量、使用未声明的变量等。

这两方面都能帮助我们提高整个项目等代码质量,提高项目的可维护性。

本次分享我们将围绕 ESLintPrettierStyleLintcommitLint 等主流 Lint 工具展开,配合 huskylint-stagedVSCode 插件、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 JSAirbnb 规范 等,也可以定制一套团队独有的代码规范。

初始化

通过 ESLint 官方的 cli 在**现有的脚手架项目(确保已经有一个 package.json 文件)**中进行初始化,首先安装 ESLint

pnpm i eslint -D

接着执行 ESLint 的初始化命令:

npx eslint --init

我是如何在项目中使用 Lint 工具链的?

  • 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 规范。
  • 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 => 通过回答问题确定自己的风格。
  • 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 解析器配置

解析器格外配置,包含如 esmaVersionsourceTypeecmaFeatures 等。

rules 代码规则

rules 对象中,key 一般为规则名,value 为具体的配置内容。

其中,off 表示关闭规则,warn 表示开启规则作为警告,违背规则后抛出 warning,不会导致程序退出,error 表示开启规则,违背规则后抛出错误,并退出程序。

plugins 插件

和上面提到的 ESLint 的默认 parser espree 不能直接解析 TypeScript 一样,ESLint 本身没有内置 TS 的代码规则,我们就需要添加插件来增加特定的规则,比如 @typescript-eslint/eslint-plugin

引入后并没有默认开启这些规则,同样也需要我们去 rules 里面添加规则设置。

extends 继承

extends 相当于是继承另一份 ESLint 配置,主要为三种情况:

  1. ESLint 本身继承:eslint:recommend
  2. 从第三方包继承
  3. 从插件中继承:plugin:react/recommended

env 和 globals

这两个配置分别代表运行环境和全局变量。JavaScript 生态有多种运行时、版本、扩展和框架。其中每一个都可以有不同的支持语法和全局变量,我们可以指定项目的运行环境:

module.export = {
  "env": {
    "browser": "true",
    "node": "true"
  }
}

指定之后便会启用浏览器和 Node.js 环境,这两个环境中的一些全局变量如 windowglobal 会同时启用。

有些全局变量是第三方库所声明,这里就需要在 globals 配置中声明全局变量:

  1. writable 表示变量可重写
  2. readonly 表示变量不可重写
  3. 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

我是如何在项目中使用 Lint 工具链的?

rules: {
  // ...
  "react/react-in-jsx-scope": "off"
}

我们还可以在 VSCode 中安装 ESLintPrettier 插件,在设置中开启 Format On Save

我是如何在项目中使用 Lint 工具链的?

即可开启保存自动格式化功能。

在 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 即可完成对样式代码的规范检查和自动格式化。

也可以安装 VSCodeStylelint 插件,实现在开发阶段感知问题,提前修复。

同样也可以在 vite 中接入 Styleint,在命令行体现规范问题,定位源文件。

pnpm i vite-plugin-stylelint -D
import viteStylelint from "vite-plugin-stylelint";

export default defineConfig({
	plugins: [
    // ...
		viteStylelint({
      // 排除检查
			exclude: ["node_modules/**", "dist/**"]
		})
	]
});

我是如何在项目中使用 Lint 工具链的?

Husky、lint-staged 的 git 提交工作流

Husky

上面我们配置的 ESLintStyleLint 都只是将问题暴露,我们还需要实现在代码提交的时候,进行拦截检查,只有通过代码规范检查才允许正常提交代码,否则还是可能会导致线上代码出现不符合规定的情况。

社区中已经有对应的工具 Husky 来帮助我们解决这个问题了。

首先我们安装一下 Husky

pnpm i husky -D

初始化 Husky(前提是你的项目得是一个 git 仓库):

我是如何在项目中使用 Lint 工具链的?

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 ."
  ]
},

最后,在 huskypre-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 信息,进行测试:

我是如何在项目中使用 Lint 工具链的?

会发现已经拦截成功了。

原文链接:https://juejin.cn/post/7247715962379173949 作者:cheerioInf

(0)
上一篇 2023年6月24日 上午11:06
下一篇 2023年6月25日 上午10:00

相关推荐

发表回复

登录后才能评论