当下,在项目开发的过程中,前端工程师们越来越离不开构建工具了,可以说构建工具已经成为了前端工程项目的标配。
不过,如今的前端构建工具有很多且更新速度极快,有远古时代的browserify
、grunt
,有传统的Webpack
、Rollup
、Parcel
,也有现代的Esbuild
、Vite
等等,不仅种类繁多,更新也很快。
本文将基于Vite
工具的周边Lint工具链进行讲解,帮助大家了解一下什么是前端Lint,以及如何做好前端Lint工作。
Lint工具链主要从如下两个方面入手:
- 现代化的CSS工程化。
- 现代化的代码风格和质量检查。
一、现代化的CSS工程化
样式方案的意义
对初学者来说,谈到开发前端的样式,首先想到的便是直接写原生 CSS。但时间一长,难免会发现原生 CSS 开发的各种问题。那么,如果我们不用任何 CSS 工程方案,又会出现哪些问题呢?
- 开发体验欠佳。比如原生 CSS 不支持选择器的嵌套:
css
// 选择器只能平铺,不能嵌套
.container .header .nav .title .text {
color: blue;
}
.container .header .nav .box {
color: blue;
border: 1px solid grey;
}
- 样式污染问题。如果出现同样的类名,很容易造成不同的样式互相覆盖和污染。
css
// a.css
.container {
color: red;
}
// b.css
// 很有可能覆盖 a.css 的样式!
.container {
color: blue;
}
- 浏览器兼容 问题。为了兼容不同的浏览器,我们需要对一些属性(如
transition
)加上不同的浏览器前缀,比如-webkit-
、-moz-
、-ms-
、-o-
,意味着开发者要针对同一个样式属性写很多的冗余代码。 4. 打包后的代码体积问题。如果不用任何的 CSS 工程化方案,所有的 CSS 代码都将打包到产物中,即使有部分样式并没有在代码中使用,导致产物体积过大。
针对如上原生 CSS 的痛点,社区中诞生了不少解决方案,常见的有 5 类。
CSS 预处理器
:主流的包括Sass/Scss
、Less
和Stylus
。这些方案各自定义了一套语法,让 CSS 也能使用嵌套规则,甚至能像编程语言一样定义变量、写条件判断和循环语句,大大增强了样式语言的灵活性,解决原生 CSS 的开发体验问题。CSS Modules
:能将 CSS 类名处理成哈希值,这样就可以避免同名的情况下样式污染的问题。- CSS 后处理器
PostCSS
,用来解析和处理 CSS 代码,可以实现的功能非常丰富,比如将px
转换为rem
、根据目标浏览器情况自动加上类似于--moz--
、-o-
的属性前缀等等。 CSS in JS
方案,主流的包括emotion
、styled-components
等等,顾名思义,这类方案可以实现直接在 JS 中写样式代码,基本包含CSS 预处理器
和CSS Modules
的各项优点,非常灵活,解决了开发体验和全局样式污染的问题。- CSS 原子化框架,如
Tailwind CSS
、Windi CSS
,通过类名来指定样式,大大简化了样式写法,提高了样式开发的效率,主要解决了原生 CSS 开发体验的问题。
不过,各种方案没有孰优孰劣,各自解决的方案有重叠的部分,但也有一定的差异,大家可以根据自己项目的痛点来引入。接下来,我们进入实战阶段,在 Vite 中应用上述常见的 CSS 方案。
CSS 预处理器
Vite 本身对 CSS 各种预处理器语言(Sass/Scss
、Less
和Stylus
)做了内置支持。也就是说,即使你不经过任何的配置也可以直接使用各种 CSS 预处理器。我们以 Sass/Scss
为例,来具体感受一下 Vite 的零配置
给我们带来的便利。
由于 Vite 底层会调用 CSS 预处理器的官方库进行编译,而 Vite 为了实现按需加载,并没有内置这些工具库,而是让用户根据需要安装。因此,我们首先安装 Sass 的官方库,安装命令如下:
css
pnpm i sass -D
然后,在上一节初始化后的项目中新建 src/components/Header
目录,并且分别新建index.tsx
和 index.scss
文件,代码如下:
javascript
// index.tsx
import './index.scss';
export function Header() {
return <p className="header">This is Header</p>
};
// index.scss
.header {
color: red;
}
这样就完成了一个最简单的 demo 组件。接着我们在 App.tsx
应用这个组件:
javascript
import { Header } from "./components/Header";
function App() {
return (
<div>
<Header />
</div>
);
}
export default App;
现在你可以执行pnpm run dev
,然后到浏览器上查看效果:

内容比较简单,如果页面出现红色的文字部分,就说明 scss
文件中的样式已经成功生效。好,现在我们封装一个全局的主题色,新建src/variable.scss
文件,内容如下:
css
// variable.scss
$theme-color: red;
然后,我们在原来 Header 组件的样式中应用这个变量:
css
@import "../../variable";
.header {
color: $theme-color;
}
回到浏览器访问页面,可以看到样式依然生效。你可能会注意到,每次要使用$theme-color
属性的时候我们都需要手动引入variable.scss
文件,那有没有自动引入的方案呢?这就需要在 Vite 中进行一些自定义配置了,在配置文件中增加如下的内容:
javascript
// vite.config.ts
import { normalizePath } from 'vite';
// 如果类型报错,需要安装 @types/node: pnpm i @types/node -D
import path from 'path';
// 全局 scss 文件的路径
// 用 normalizePath 解决 window 下的路径问题
const variablePath = normalizePath(path.resolve('./src/variable.scss'));
export default defineConfig({
// css 相关的配置
css: {
preprocessorOptions: {
scss: {
// additionalData 的内容会在每个 scss 文件的开头自动注入
additionalData: `@import "${variablePath}";`
}
}
}
})
现在你可以直接在文件中使用全局文件的变量,相当于之前手动引入的方式显然方便了许多:
css
.header {
color: $theme-color;
}
同样的,你可以对 less
和stylus
进行一些能力的配置,如果有需要你可以去下面的官方文档中查阅更多的配置项:
CSS Modules
CSS Modules 在 Vite 也是一个开箱即用的能力,Vite 会对后缀带有.module
的样式文件自动应用 CSS Modules。接下来我们通过一个简单的例子来使用这个功能。
首先,将 Header 组件中的index.scss
更名为index.module.scss
,然后稍微改动一下index.tsx
的内容,如下:
javascript
// index.tsx
import styles from './index.module.scss';
export function Header() {
return <p className={styles.header}>This is Header</p>
};
现在打开浏览器,可以看见 p 标签的类名已经被处理成了哈希值的形式:

说明现在 CSS Modules 已经正式生效了!同样的,你也可以在配置文件中的css.modules
选项来配置 CSS Modules 的功能,比如下面这个例子:
arduino
// vite.config.ts
export default {
css: {
modules: {
// 一般我们可以通过 generateScopedName 属性来对生成的类名进行自定义
// 其中,name 表示当前文件名,local 表示类名
generateScopedName: "[name]__[local]___[hash:base64:5]"
},
preprocessorOptions: {
// 省略预处理器配置
}
}
}
再次访问页面,我们可以发现刚才的类名已经变成了我们自定义的形式:

这是一个 CSS Modules 中很常见的配置,对开发时的调试非常有用。其它的一些配置项不太常用,大家可以去这个地址进行查阅。
PostCSS
一般你可以通过 postcss.config.js
来配置 postcss ,不过在 Vite 配置文件中已经提供了 PostCSS 的配置入口,我们可以直接在 Vite 配置文件中进行操作。
首先,我们来安装一个常用的 PostCSS 插件------autoprefixer
:
css
pnpm i autoprefixer -D
这个插件主要用来自动为不同的目标浏览器添加样式前缀,解决的是浏览器兼容性的问题。接下来让我们在 Vite 中接入这个插件:
javascript
// vite.config.ts 增加如下的配置
import autoprefixer from 'autoprefixer';
export default {
css: {
// 进行 PostCSS 配置
postcss: {
plugins: [
autoprefixer({
// 指定目标浏览器
overrideBrowserslist: ['Chrome > 40', 'ff > 31', 'ie 11']
})
]
}
}
}
配置完成后,我们回到 Header 组件的样式文件中添加一个新的 CSS 属性:
xml
.header {
<!-- 前面的样式省略 -->
text-decoration: dashed;
}
你可以执行pnpm run build
命令进行打包,可以看到产物中自动补上了浏览器前缀,如:
xml
._header_kcvt0_1 {
<!-- 前面的样式省略 -->
-webkit-text-decoration: dashed;
-moz-text-decoration: dashed;
text-decoration: dashed;
}
由于有 CSS 代码的 AST (抽象语法树)解析能力,PostCSS 可以做的事情非常多,甚至能实现 CSS 预处理器语法和 CSS Modules,社区当中也有不少的 PostCSS 插件,除了刚刚提到的autoprefixer
插件,常见的插件还包括:
- postcss-pxtorem: 用来将 px 转换为 rem 单位,在适配移动端的场景下很常用。
- postcss-preset-env: 通过它,你可以编写最新的 CSS 语法,不用担心兼容性问题。
- cssnano: 主要用来压缩 CSS 代码,跟常规的代码压缩工具不一样,它能做得更加智能,比如提取一些公共样式进行复用、缩短一些常见的属性值等等。
关于 PostCSS 插件,这里还给大家推荐一个站点:www.postcss.parts/ ,你可以去里面探索更多的内容。
CSS In JS
社区中有两款主流的CSS In JS
方案: styled-components
和emotion
。
对于 CSS In JS 方案,在构建侧我们需要考虑选择器命名问题
、DCE
(Dead Code Elimination 即无用代码删除)、代码压缩
、生成 SourceMap
、服务端渲染(SSR)
等问题,而styled-components
和emotion
已经提供了对应的 babel 插件来解决这些问题,我们在 Vite 中要做的就是集成这些 babel 插件。
具体来说,上述的两种主流 CSS in JS 方案在 Vite 中集成方式如下:
javascript
// vite.config.ts
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [
react({
babel: {
// 加入 babel 插件
// 以下插件包都需要提前安装
// 当然,通过这个配置你也可以添加其它的 Babel 插件
plugins: [
// 适配 styled-component
"babel-plugin-styled-components"
// 适配 emotion
"@emotion/babel-plugin"
]
},
// 注意: 对于 emotion,需要单独加上这个配置
// 通过 `@emotion/react` 包编译 emotion 中的特殊 jsx 语法
jsxImportSource: "@emotion/react"
})
]
})
CSS 原子化框架
在目前的社区当中,CSS 原子化框架主要包括Tailwind CSS
和 Windi CSS
。Windi CSS 作为前者的替换方案,实现了按需生成 CSS 类名的功能,开发环境下的 CSS 产物体积大大减少,速度上比Tailwind CSS v2
快 20~100 倍!当然,Tailwind CSS 在 v3 版本也引入 JIT(即时编译) 的功能,解决了开发环境下 CSS 产物体积庞大的问题。接下来我们将这两个方案分别接入到 Vite 中,在实际的项目中你只需要使用其中一种就可以了。我个人比较喜欢 Windi CSS 本身的attributify
、shortcuts
等独有的特性,因此首先从 windicss 开始说起。
1. Windi CSS 接入
首先安装 windicss
及对应的 Vite 插件:
css
pnpm i windicss vite-plugin-windicss -D
随后我们在配置文件中来使用它:
javascript
// vite.config.ts
import windi from "vite-plugin-windicss";
export default {
plugins: [
// 省略其它插件
windi()
]
}
接着要注意在src/main.tsx
中引入一个必需的 import 语句:
arduino
// main.tsx
// 用来注入 Windi CSS 所需的样式,一定要加上!
import "virtual:windi.css";
这样我们就完成了 Windi CSS 在 Vite 中的接入,接下来我们在 Header 组件中来测试,组件代码修改如下:
javascript
// src/components/Header/index.tsx
import { devDependencies } from "../../../package.json";
export function Header() {
return (
<div className="p-20px text-center">
<h1 className="font-bold text-2xl mb-2">
vite version: {devDependencies.vite}
</h1>
</div>
);
}
启动项目可以看到如下的效果,说明样式已经正常生效:

除了本身的原子化 CSS 能力,Windi CSS 还有一些非常好用的高级功能,在此我给大家推荐自己常用的两个能力: attributify 和 shortcuts。
要开启这两个功能,我们需要在项目根目录新建windi.config.ts
,配置如下:
arduino
import { defineConfig } from "vite-plugin-windicss";
export default defineConfig({
// 开启 attributify
attributify: true,
});
首先我们来看看attributify
,翻译过来就是属性化
,也就是说我们可以用 props 的方式去定义样式属性,如下所示:
ini
<button
bg="blue-400 hover:blue-500 dark:blue-500 dark:hover:blue-600"
text="sm white"
font="mono light"
p="y-2 x-4"
border="2 rounded blue-200"
>
Button
</button>
这样的开发方式不仅省去了繁琐的 className 内容,还加强了语义化,让代码更易维护,大大提升了开发体验。
不过使用attributify
的时候需要注意类型问题,你需要添加types/shim.d.ts
来增加类型声明,以防类型报错:
typescript
import { AttributifyAttributes } from 'windicss/types/jsx';
declare module 'react' {
type HTMLAttributes<T> = AttributifyAttributes;
}
shortcuts
用来封装一系列的原子化能力,尤其是一些常见的类名集合,我们在 windi.config.ts
来配置它:
arduino
//windi.config.ts
import { defineConfig } from "vite-plugin-windicss";
export default defineConfig({
attributify: true,
shortcuts: {
"flex-c": "flex justify-center items-center",
}
});
比如这里封装了flex-c
的类名,接下来我们可以在业务代码直接使用这个类名:
xml
<div className="flex-c"></div>
<!-- 等同于下面这段 -->
<div className="flex justify-center items-center"></div>
如果你也有过 Windi CSS 的开发经历,欢迎把你用到的高级功能分享到评论区,让大家一起来见识见识。
2. Tailwind CSS
接下来我们来接入 Tailwind CSS 方案,为了避免和之前的 Windi CSS 混淆,这里我建议你新起一个 Vite 项目。
小册中对应的 GitHub 代码地址。
首先安装 tailwindcss
及其必要的依赖:
pnpm install -D tailwindcss postcss autoprefixer
然后新建两个配置文件tailwind.config.js
和postcss.config.js
:
java
// tailwind.config.js
module.exports = {
content: [
"./index.html",
"./src/**/*.{vue,js,ts,jsx,tsx}",
],
theme: {
extend: {},
},
plugins: [],
}
// postcss.config.js
// 从中你可以看到,Tailwind CSS 的编译能力是通过 PostCSS 插件实现的
// 而 Vite 本身内置了 PostCSS,因此可以通过 PostCSS 配置接入 Tailwind CSS
// 注意: Vite 配置文件中如果有 PostCSS 配置的情况下会覆盖掉 post.config.js 的内容!
module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
}
接着在项目的入口 CSS 中引入必要的样板代码:
less
@tailwind base;
@tailwind components;
@tailwind utilities;
现在,你就可以在项目中安心地使用 Tailwind 样式了,如下所示:
javascript
// App.tsx
import logo from "./logo.svg";
import "./App.css";
function App() {
return (
<div>
<header className="App-header">
<img src={logo} className="w-20" alt="logo" />
<p className="bg-red-400">Hello Vite + React!</p>
</header>
</div>
);
}
export default App;
当你启动项目之后可以看到 Tailwind CSS 的样式已经正常生效:

小结
OK,本小节的内容到这里就结束了。这一节我们完成了脚手架项目样式部分的搭建,你需要重点掌握前端工程中各种样式方案在 Vite 的接入方法。这些样式方案包括,包括CSS 预处理器
、CSS Modules
、PostCSS
、CSS In JS
和 CSS 原子化框架(Windi CSS)
。与此同时,你应该明白了各种样式方案的含义以及背后所解决的问题。接下来,我们将会进入项目规范搭建的部分,让我们下一节再见!
二、现代化的代码风格和质量检查
在真实的工程项目中,尤其是多人协作的场景下,代码规范就变得非常重要了,它可以用来统一团队代码风格,避免不同风格的代码混杂到一起难以阅读,有效提高代码质量 ,甚至可以将一些语法错误 在开发阶段提前规避掉。但仅有规范本身不够,我们需要自动化的工具 (即Lint 工具
)来保证规范的落地,把代码规范检查(包括自动修复
)这件事情交给机器完成,开发者只需要专注应用逻辑本身。
本节,我们将一起来完成 Lint 工具链在项目中的落地,实现自动化代码规范检查及修复的能力。学完本节内容后,你不仅能熟悉诸如ESLint
、Prettier
、Stylelint
和Commitlint
等诸多主流 Lint 工具的概念和使用,还能配合husky
、lint-staged
、VSCode 插件
和Vite 生态
在项目中集成完整的 Lint 工具链,搭建起完整的前端开发和代码提交工作流,这部分内容虽然和 Vite 没有直接的联系,但也是 Vite 项目搭建中非常重要的一环,是前端工程化的必备知识。
小节示例项目仓库: 点击直达
JS/TS 规范工具: ESLint
简介
ESLint 是在 ECMAScript/JavaScript 代码中识别和报告模式匹配的工具,它的目标是保证代码的一致性和避免错误。
Eslint 是国外的前端大牛Nicholas C. Zakas
在 2013 年发起的一个开源项目,有一本书被誉为前端界的"圣经",叫《JavaScript 高级程序设计》(即红宝书),他正是这本书的作者。
Nicholas
当初做这个开源项目,就是为了打造一款插件化的 JavaScript 代码静态检查工具,通过解析代码的 AST 来分析代码格式,检查代码的风格和质量问题。现在,Eslint 已经成为一个非常成功的开源项目了,基本上属于前端项目中 Lint 工具的标配。
ESLint 的使用并不复杂,主要通过配置文件对各种代码格式的规则(rules
)进行配置,以指定具体的代码规范。目前开源社区也有一些成熟的规范集可供使用,著名的包括Airbnb JavaScript 代码规范、Standard JavaScript 规范、Google JavaScript 规范等等,你可以在项目中直接使用这些成熟的规范,也可以自己定制一套团队独有的代码规范,这在一些大型团队当中还是很常见的。
初始化
接下来我们来利用 ESLint 官方的 cli 在现有的脚手架项目中进行初始化操作,首先我们需要安装 ESLint:
css
pnpm i eslint -D
接着执行 ESLint 的初始化命令,并进行如下的命令行交互:
csharp
npx eslint --init

接着 ESLint 会帮我们自动生成.eslintrc.js
配置文件。需要注意的是,在上述初始化流程中我们并没有用 npm 安装依赖,需要进行手动安装:
java
pnpm i eslint-plugin-react@latest @typescript-eslint/eslint-plugin@latest @typescript-eslint/parser@latest -D
核心配置解读
大家初次接触配置文件可能会有点不太理解,接下来我来为你介绍一下几个核心的配置项,你可以对照目前生成的.eslintrc.js
一起学习。
1. parser - 解析器
ESLint 底层默认使用 Espree来进行 AST 解析,这个解析器目前已经基于 Acron
来实现,虽然说 Acron
目前能够解析绝大多数的 ECMAScript 规范的语法,但还是不支持 TypeScript ,因此需要引入其他的解析器完成 TS 的解析。
社区提供了@typescript-eslint/parser
这个解决方案,专门为了 TypeScript 的解析而诞生,将 TS
代码转换为 Espree
能够识别的格式(即 Estree 格式),然后在 Eslint 下通过Espree
进行格式检查, 以此兼容了 TypeScript 语法。
2. parserOptions - 解析器选项
这个配置可以对上述的解析器进行能力定制,默认情况下 ESLint 支持 ES5 语法,你可以配置这个选项,具体内容如下:
- ecmaVersion: 这个配置和
Acron
的 ecmaVersion 是兼容的,可以配置ES + 数字
(如 ES6)或者ES + 年份
(如 ES2015),也可以直接配置为latest
,启用最新的 ES 语法。 - sourceType: 默认为
script
,如果使用 ES Module 则应设置为module
- ecmaFeatures: 为一个对象,表示想使用的额外语言特性,如开启
jsx
。
3. rules - 具体代码规则
rules
配置即代表在 ESLint 中手动调整哪些代码规则,比如禁止在 if 语句中使用赋值语句
这条规则可以像如下的方式配置:
java
// .eslintrc.js
module.exports = {
// 其它配置省略
rules: {
// key 为规则名,value 配置内容
"no-cond-assign": ["error", "always"]
}
}
在 rules 对象中,key
一般为规则名
,value
为具体的配置内容,在上述的例子中我们设置为一个数组,数组第一项为规则的 ID
,第二项为规则的配置
。
这里重点说一说规则的 ID,它的语法对所有规则都适用,你可以设置以下的值:
off
或0
: 表示关闭规则。warn
或1
: 表示开启规则,不过违背规则后只抛出 warning,而不会导致程序退出。error
或2
: 表示开启规则,不过违背规则后抛出 error,程序会退出。
具体的规则配置可能会不一样,有的是一个字符串,有的可以配置一个对象,你可以参考 ESLint 官方文档。
当然,你也能直接将 rules
对象的 value
配置成 ID,如: "no-cond-assign": "error"
。
4. plugins
上面提到过 ESLint 的 parser 基于Acorn
实现,不能直接解析 TypeScript,需要我们指定 parser 选项为@typescript-eslint/parser
才能兼容 TS 的解析。同理,ESLint 本身也没有内置 TypeScript 的代码规则,这个时候 ESLint 的插件系统就派上用场了。我们需要通过添加 ESLint 插件来增加一些特定的规则,比如添加@typescript-eslint/eslint-plugin
来拓展一些关于 TS 代码的规则,如下代码所示:
java
// .eslintrc.js
module.exports = {
// 添加 TS 规则,可省略`eslint-plugin`
plugins: ['@typescript-eslint']
}
值得注意的是,添加插件后只是拓展了 ESLint 本身的规则集,但 ESLint 默认并没有开启这些规则的校验!如果要开启或者调整这些规则,你需要在 rules 中进行配置,如:
java
// .eslintrc.js
module.exports = {
// 开启一些 TS 规则
rules: {
'@typescript-eslint/ban-ts-comment': 'error',
'@typescript-eslint/no-explicit-any': 'warn',
}
}
5. extends - 继承配置
extends 相当于继承
另外一份 ESLint 配置,可以配置为一个字符串,也可以配置成一个字符串数组。主要分如下 3 种情况:
- 从 ESLint 本身继承;
- 从类似
eslint-config-xxx
的 npm 包继承; - 从 ESLint 插件继承。
java
// .eslintrc.js
module.exports = {
"extends": [
// 第1种情况
"eslint:recommended",
// 第2种情况,一般配置的时候可以省略 `eslint-config`
"standard"
// 第3种情况,可以省略包名中的 `eslint-plugin`
// 格式一般为: `plugin:${pluginName}/${configName}`
"plugin:react/recommended"
"plugin:@typescript-eslint/recommended",
]
}
有了 extends 的配置,对于之前所说的 ESLint 插件中的繁多配置,我们就不需要手动一一开启了,通过 extends 字段即可自动开启插件中的推荐规则:
perl
extends: ["plugin:@typescript-eslint/recommended"]
6. env 和 globals
这两个配置分别表示运行环境
和全局变量
,在指定的运行环境中会预设一些全局变量,比如:
arduino
// .eslint.js
module.export = {
"env": {
"browser": "true",
"node": "true"
}
}
指定上述的 env
配置后便会启用浏览器和 Node.js 环境,这两个环境中的一些全局变量(如 window
、global
等)会同时启用。
有些全局变量是业务代码引入的第三方库所声明,这里就需要在globals
配置中声明全局变量了。每个全局变量的配置值有 3 种情况:
"writable"
或者true
,表示变量可重写;"readonly"
或者false
,表示变量不可重写;"off"
,表示禁用该全局变量。
那jquery
举例,我们可以在配置文件中声明如下:
java
// .eslintrc.js
module.exports = {
"globals": {
// 不可重写
"$": false,
"jQuery": false
}
}
相信有了上述核心配置部分的讲解,你再回头看看初始化生成的 ESLint 配置文件,你也能很好地理解各个配置项的含义了。
与 Prettier 强强联合
虽然 ESLint 本身具备自动格式化代码的功能(eslint --fix
),但术业有专攻,ESLint 的主要优势在于代码的风格检查并给出提示
,而在代码格式化这一块 Prettier 做的更加专业,因此我们经常将 ESLint 结合 Prettier 一起使用。
首先我们来安装一下 Prettier:
css
pnpm i prettier -D
在项目根目录新建.prettierrc.js
配置文件,填写如下的配置内容:
java
// .prettierrc.js
module.exports = {
printWidth: 80, //一行的字符数,如果超过会进行换行,默认为80
tabWidth: 2, // 一个 tab 代表几个空格数,默认为 2 个
useTabs: false, //是否使用 tab 进行缩进,默认为false,表示用空格进行缩减
singleQuote: true, // 字符串是否使用单引号,默认为 false,使用双引号
semi: true, // 行尾是否使用分号,默认为true
trailingComma: "none", // 是否使用尾逗号
bracketSpacing: true // 对象大括号直接是否有空格,默认为 true,效果:{ a: 1 }
};
接下来我们将Prettier
集成到现有的ESLint
工具中,首先安装两个工具包:
arduino
pnpm i eslint-config-prettier eslint-plugin-prettier -D
其中eslint-config-prettier
用来覆盖 ESLint 本身的规则配置,而eslint-plugin-prettier
则是用于让 Prettier 来接管eslint --fix
即修复代码的能力。
在 .eslintrc.js
配置文件中接入 prettier 的相关工具链,最终的配置代码如下所示,你可以直接粘贴过去:
java
// .eslintrc.js
module.exports = {
env: {
browser: true,
es2021: true
},
extends: [
"eslint:recommended",
"plugin:react/recommended",
"plugin:@typescript-eslint/recommended",
// 1. 接入 prettier 的规则
"prettier",
"plugin:prettier/recommended"
],
parser: "@typescript-eslint/parser",
parserOptions: {
ecmaFeatures: {
jsx: true
},
ecmaVersion: "latest",
sourceType: "module"
},
// 2. 加入 prettier 的 eslint 插件
plugins: ["react", "@typescript-eslint", "prettier"],
rules: {
// 3. 注意要加上这一句,开启 prettier 自动修复的功能
"prettier/prettier": "error",
quotes: ["error", "single"],
semi: ["error", "always"],
"react/react-in-jsx-scope": "off"
}
};
OK,现在我们回到项目中来见证一下ESLint + Prettier
强强联合的威力,在 package.json
中定义一个脚本:
json
{
"scripts": {
// 省略已有 script
"lint:script": "eslint --ext .js,.jsx,.ts,.tsx --fix --quiet ./src",
}
}
接下来在命令行终端执行:
arduino
pnpm run lint:script
这样我们就完成了 ESLint 的规则检查
以及 Prettier 的自动修复
。不过每次执行这个命令未免会有些繁琐,我们可以在VSCode
中安装ESLint
和Prettier
这两个插件,并且在设置区中开启Format On Save
:

接下来在你按Ctrl + S
保存代码的时候,Prettier 便会自动帮忙修复代码格式。
在 Vite 中接入 ESLint
除了安装编辑器插件,我们也可以通过 Vite 插件的方式在开发阶段进行 ESLint 扫描,以命令行的方式展示出代码中的规范问题,并能够直接定位到原文件。
首先我们安装 Vite 中的 ESLint 插件:
css
pnpm i vite-plugin-eslint -D
然后在 vite.config.ts
中接入:
javascript
// vite.config.ts
import viteEslint from 'vite-plugin-eslint';
// 具体配置
{
plugins: [
// 省略其它插件
viteEslint(),
]
}
现在你可以试着重新启动项目, ESLint 的错误已经能够及时显示到命令行窗口中了。

由于这个插件采用另一个进程来运行 ESLint 的扫描工作,因此不会影响 Vite 项目的启动速度,这个大家不用担心。
样式规范工具: Stylelint
接下来我们进入Stylelint
的部分,先来看看官方的定义:
Stylelint,一个强大的现代化样式 Lint 工具,用来帮助你避免语法错误和统一代码风格。
Stylelint 主要专注于样式代码的规范检查,内置了 170 多个 CSS 书写规则 ,支持 CSS 预处理器 (如 Sass、Less),提供插件化机制 以供开发者扩展规则,已经被 Google、Github 等大型团队投入使用。与 ESLint 类似,在规范检查方面,Stylelint 已经做的足够专业,而在代码格式化方面,我们仍然需要结合 Prettier 一起来使用。
首先让我们来安装 Stylelint 以及相应的工具套件:
arduino
pnpm i stylelint stylelint-prettier stylelint-config-prettier stylelint-config-recess-order stylelint-config-standard stylelint-config-standard-scss -D
然后,我们在 Stylelint 的配置文件.stylelintrc.js
中一一使用这些工具套件:
java
// .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
}
};
可以发现 Stylelint 的配置文件和 ESLint 还是非常相似的,常用的plugins
、extends
和rules
属性在 ESLint 同样存在,并且与 ESLint 中这三个属性的功能也基本相同。不过需要强调的是在 Stylelint 中 rules 的配置会和 ESLint 有些区别,对于每个具体的 rule 会有三种配置方式:
null
,表示关闭规则。- 一个简单值(如 true,字符串,根据不同规则有所不同),表示开启规则,但并不做过多的定制。
- 一个数组,包含两个元素,即
[简单值,自定义配置]
,第一个元素通常为一个简单值,第二个元素用来进行更精细化的规则配置。
接下来我们将 Stylelint 集成到项目中,回到 package.json
中,增加如下的 scripts
配置:
json
{
"scripts": {
// 整合 lint 命令
"lint": "npm run lint:script && npm run lint:style",
// stylelint 命令
"lint:style": "stylelint --fix "src/**/*.{css,scss}""
}
}
执行pnpm run lint:style
即可完成样式代码的规范检查和自动格式化。当然,你也可以在 VSCode 中安装Stylelint
插件,这样能够在开发阶段即时感知到代码格式问题,提前进行修复。
当然,我们也可以直接在 Vite 中集成 Stylelint。社区中提供了 Stylelint 的 Vite 插件,实现在项目开发阶段提前暴露出样式代码的规范问题。我们来安装一下这个插件:
bash
# Vite 2.x
pnpm i @amatlash/vite-plugin-stylelint -D
# Vite 3.x 及以后的版本
pnpm i vite-plugin-stylelint -D
然后在 Vite 配置文件中添加如下的内容:
javascript
import viteStylelint from '@amatlash/vite-plugin-stylelint';
// 注意: Vite 3.x 以及以后的版本需要引入 vite-plugin-stylelint
// 具体配置
{
plugins: [
// 省略其它插件
viteStylelint({
// 对某些文件排除检查
exclude: /windicss|node_modules/
}),
]
}
接下来,你就可以在命令行界面看到对应的 Stylelint 提示了:

Husky + lint-staged 的 Git 提交工作流集成
提交前的代码 Lint 检查
在上文中我们提到了安装 ESLint
、Prettier
和Stylelint
的 VSCode 插件或者 Vite 插件,在开发阶段提前规避掉代码格式的问题,但实际上这也只是将问题提前暴露,并不能保证规范问题能完全被解决,还是可能导致线上的代码出现不符合规范的情况。那么如何来避免这类问题呢?
我们可以在代码提交的时候进行卡点检查,也就是拦截 git commit
命令,进行代码格式检查,只有确保通过格式检查才允许正常提交代码。社区中已经有了对应的工具------Husky
来完成这件事情,让我们来安装一下这个工具:
css
pnpm i husky -D
值得提醒的是,有很多人推荐在package.json
中配置 husky 的钩子:
json
// package.json
{
"husky": {
"pre-commit": "npm run lint"
}
}
这种做法在 Husky 4.x
及以下版本没问题,而在最新版本(7.x 版本)中是无效的!在新版 Husky 版本中,我们需要做如下的事情:
- 初始化 Husky:
npx husky install
,并将husky install
作为项目启动前脚本,如:
json
{
"scripts": {
// 会在安装 npm 依赖后自动执行
"prepare": "husky install"
}
}
- 添加 Husky 钩子,在终端执行如下命令:
sql
npx husky add .husky/pre-commit "npm run lint"
接着你将会在项目根目录的.husky
目录中看到名为pre-commit
的文件,里面包含了 git commit
前要执行的脚本。现在,当你执行 git commit
的时候,会首先执行 npm run lint
脚本,通过 Lint 检查后才会正式提交代码记录。
不过,刚才我们直接在 Husky 的钩子中执行 npm run lint
,这会产生一个额外的问题: Husky 中每次执行npm run lint
都对仓库中的代码进行全量检查,也就是说,即使某些文件并没有改动,也会走一次 Lint 检查,当项目代码越来越多的时候,提交的过程会越来越慢,影响开发体验。
而lint-staged
就是用来解决上述全量扫描问题的,可以实现只对存入暂存区
的文件进行 Lint 检查,大大提高了提交代码的效率。首先,让我们安装一下对应的 npm 包:
css
pnpm i -D lint-staged
然后在 package.json
中添加如下的配置:
json
{
"lint-staged": {
"**/*.{js,jsx,tsx,ts}": [
"npm run lint:script",
"git add ."
],
"**/*.{scss}": [
"npm run lint:style",
"git add ."
]
}
}
接下来我们需要在 Husky 中应用lint-stage
,回到.husky/pre-commit
脚本中,将原来的npm run lint
换成如下脚本:
css
npx --no -- lint-staged
如此一来,我们便实现了提交代码时的增量 Lint 检查
。
提交时的 commit 信息规范
除了代码规范检查之后,Git 提交信息的规范也是不容忽视的一个环节,规范的 commit 信息能够方便团队协作和问题定位。首先我们来安装一下需要的工具库,执行如下的命令:
bash
pnpm i commitlint @commitlint/cli @commitlint/config-conventional -D
接下来新建.commitlintrc.js
:
ini
// .commitlintrc.js
module.exports = {
extends: ["@commitlint/config-conventional"]
};
一般我们直接使用@commitlint/config-conventional
规范集就可以了,它所规定的 commit 信息一般由两个部分: type
和 subject
组成,结构如下:
go
// type 指提交的类型
// subject 指提交的摘要信息
<type>: <subject>
常用的 type
值包括如下:
feat
: 添加新功能。fix
: 修复 Bug。chore
: 一些不影响功能的更改。docs
: 专指文档的修改。perf
: 性能方面的优化。refactor
: 代码重构。test
: 添加一些测试代码等等。
接下来我们将commitlint
的功能集成到 Husky 的钩子当中,在终端执行如下命令即可:
bash
npx husky add .husky/commit-msg "npx --no-install commitlint -e $HUSKY_GIT_PARAMS"
你可以发现在.husky
目录下多出了commit-msg
脚本文件,表示commitlint
命令已经成功接入到 husky 的钩子当中。现在我们可以尝试对代码进行提交,假如输入一个错误的 commit 信息,commitlint 会自动抛出错误并退出:

至此,我们便完成了 Git 提交信息的卡点扫描和规范检查。
小结
恭喜你,学完了本节的内容。本小节你应该了解前端的自动化代码规范工具的使用 以及在 Vite 中的接入方法。
我主要给你介绍了 3 个方面的自动化代码规范工具:
- JavaScript/TypeScript 规范。主流的 Lint 工具包括
Eslint
、Prettier
; - 样式开发规范。主流的 Lint 工具包括
Stylelint
、Prettier
; - Git 提交规范。主流的 Lint 工具包括
Commitlint
。
我们可以通过编辑器的插件或者 Vite 插件在开发阶段暴露出规范问题,但也无法保证这类问题在开发时完全被解决掉,因此我们尝试在代码提交阶段来解决这个问题,通过Husky
+lint-staged
成功地拦截 git commit
过程,只有在各项 Lint 检查通过后才能正常提交代码,这样就有效提高了线上代码和 Git 提交信息的质量。