前端代码整洁之道:lint 标准化
在新公司的参与的第一个项目就是重构一个内部的管理平台,在第一次看源码的时候就发现各类编码风格都有,已经有着往“屎山”发展的趋势了,所以想着对项目进行编码规范和编码风格做一个统一。统一规范的格式不仅看着舒服了一些,还可以提前检查出一些潜在的问题、增强项目的维护性,何乐而不为呢?这周正好完成了风格规范的统一,下面也借机梳理一下使用到的代码检查工具(简称为 lint 工具)的配置流程,如果想要了解具体的配置项介绍可以参考各个工具的官网
重构的项目主要是 Vue3 相关的技术栈,主要使用到 lint 工具包括:
- Editor Config :解决不同 IDE 编辑器编码风格不统一问题
- Prettier:代码格式化工具
- ESLint:JS / TS 代码检查和修复工具
- StyleLint:CSS 代码检查和格式化工具
Editor Config 和 Prettier 配置
首先是配置 Editor Config ,在项目根目录下新建一个 .editorconfig
文件,配置文件中定义好编码规范可以了使用了,我在项目中使用到的 Editor Config 配置如下,主要定义了字符集、缩进、换行的风格
1# 表示是最顶层的 EditorConfig 配置文件
2root = true
3
4# 表示所有文件适用
5[*]
6charset = utf-8 # 设置文件字符集为 utf-8
7indent_style = space # 缩进风格(tab | space)
8indent_size = 2 # 缩进大小
9end_of_line = lf # 控制换行类型(lf | cr | crlf)
10trim_trailing_whitespace = true # 去除行首的任意空白字符
11insert_final_newline = true # 始终在文件末尾插入一个新行
12
13[*.{yml,yaml,json}]
14indent_style = space
15indent_size = 2
16
17[*.md]
18max_line_length = off
19trim_trailing_whitespace = false
20
21[Makefile]
22indent_style = tab
接下来是 Prettier 配置,首先引入依赖,在项目根目录创建 prettier 配置文件和需要忽略检查的文件
1pnpm i prettier -D # 引入 Prettier 依赖
2
3echo {}> .prettierrc.js # 目录新建 .prettierrc.js 配置文件
4echo > .prettierignore # 新建 .prettierignore 不需要被格式化的文件放在这里
.prettierrc.js
主要是定义与代码风格相关的内容,我习惯于定义好一套比较齐全的配置,便于后期维护,具体配置和介绍如下
1// .prettierrc.js
2module.exports = {
3 // 单行代码超出 100 个字符自动换行
4 printWidth: 100,
5 // 一个 tab 键缩进相当于 2 个空格
6 tabWidth: 2,
7 // 行缩进使用 tab 键代替空格
8 useTabs: false,
9 // 每一条语句后面添加分号
10 semi: true,
11 // 使用单引号
12 singleQuote: false,
13 // 仅仅当必须的时候才会加上双引号
14 quoteProps: 'as-needed',
15 // JSX 中使用单引号
16 jsxSingleQuote: false,
17 // 多行用逗号分隔的句法,未尾添加逗号(符合es5规范)
18 trailingComma: 'es5',
19 // 在括号和对象的文字之间加上一个空格
20 bracketSpacing: true,
21 // 多行的 JSX 对象结尾的 > 放在结尾同一行
22 bracketSameLine: false,
23 // 箭头函数,只有一个参数的时候,也需要括号
24 arrowParens: 'always',
25 // 格式化文档的某一部分,默认为全部
26 rangeStart: 0,
27 rangeEnd: Infinity,
28 // 对于 .vue 文件,缩进 <script> 和 <style> 里的内容
29 vueIndentScriptAndStyle: true,
30 // 不需要写文件开头的 @prettier
31 insertPragma: false,
32 // 不需要在文件开头插入 @prettier
33 requirePragma: false,
34 // 使用默认折行标准
35 proseWrap: 'preserve',
36 // 根据显示样式决定 html 要不要折行
37 htmlWhitespaceSensitivity: 'css',
38 // 换行符使用 lf
39 endOfLine: 'lf',
40}
.prettierignore
主要是定义 prettier 不需要格式化的文件,下面是我用到的配置
1/dist/*
2.local
3.output.js
4/node_modules/**
5
6**/*.svg
7**/*.sh
8
9/public/*
第三步是安装 Prettier 插件,在 VSCode 中 Prettier 插件在项目根目录中有 .editorconfig
文件和.prettierrc.js
文件中的一个时,就会优先读取项目中的配置,如果两个文件都没有的话才会读取 VSCode 的配置
安装好插件后,建议在 VSCode 的配置中开启自动保存、自动格式化相关功能,这样就可以实现实时自动化的效果了,用起来简直不要太爽
1// 自动保存
2"files.autoSave": "onFocusChange",
3// 保存自动格式化
4"editor.formatOnSave": true,
5// 保存自动去除多余空格
6"files.trimTrailingWhitespace": true,
7// 保存自动修复代码错误
8"editor.codeActionsOnSave": {
9 "source.fixAll": true
10},
ESLint 配置
安装 ESLint 最简单的方式其实是执行 eslint --init
命令(需要全局安装 ESLint),然后选择需要的规则、是否使用 TS、使用的框架就好,然后就会自动引入相应的依赖并生成好配置文件了,基本可以说是 “零配置”
但实际应用过程中还是考虑到原项目的情况,我还是手动引入的相关的依赖,主要使用到的依赖包括
- eslint:核心依赖
- vue-eslint-parser:配置解析
.vue
文件的解析器 - eslint-plugin-vue:Vue 官方出品的 ESLint 插件
- typescript-eslint:支持 ts 的 ESLint 插件,主要使用到 plugin 和 parser
第一步先安装依赖
1pnpm i -D eslint vue-eslint-parser eslint-plugin-vue @typescript-eslint/eslint-plugin @typescript-eslint/parser
第二步在根目录新建 .eslintrc.js
, .eslintignore
两个文件,.eslintignore
除外 node_modules,.eslintrc.js
配置内容如下
1module.exports = {
2 root: true,
3 env: {
4 browser: true,
5 node: true,
6 es6: true,
7 },
8 parser: 'vue-eslint-parser',
9 parserOptions: {
10 parser: '@typescript-eslint/parser',
11 ecmaVersion: 2020,
12 sourceType: 'module',
13 jsxPragma: 'React',
14 ecmaFeatures: {
15 jsx: true,
16 },
17 },
18 extends: [
19 'plugin:vue/vue3-recommended',
20 'plugin:@typescript-eslint/recommended',
21 ],
22 rules: {
23 // 关闭不允许使用 any
24 '@typescript-eslint/no-explicit-any': 'off',
25 // 关闭组件必须由多个单词命名
26 'vue/multi-word-component-names': 'off',
27 // 关闭禁止使用 ts 备注
28 '@typescript-eslint/ban-ts-comment': 'off',
29 // 关闭禁止使用非空断言
30 '@typescript-eslint/no-non-null-assertion': 'off',
31 // 可以使用 _ 开头定义不使用的变量
32 '@typescript-eslint/no-unused-vars': [
33 'error',
34 {
35 argsIgnorePattern: '^_',
36 varsIgnorePattern: '^_',
37 },
38 ],
39 'no-unused-vars': [
40 'error',
41 {
42 argsIgnorePattern: '^_',
43 varsIgnorePattern: '^_',
44 },
45 ],
46 },
47}
其中 ESLint 和 Prettier 还会存在冲突,这时候会用到这两个插件,目的就是让 Prettier 的优先级大于 ESLint
eslint-plugin-prettier
将 Prettier 的规则设置到 ESLint 的规则中eslint-config-prettier
关闭 ESLint 中与 Prettier 中会发生冲突的规则
安装命令: pnpm i eslint-plugin-prettier eslint-config-prettier -D
,.eslintrc.js
extends 添加:"plugin:prettier/recommended"
,注意要添加到最后一个,ESLint 的解析顺序是按照从下往上的顺序来加载扩展的
1 extends: [
2 "plugin:vue/vue3-recommended",
3 "plugin:@typescript-eslint/recommended",
4+ "plugin:prettier/recommended",
5 ],
第三步再安装微软官方的 ESLint 插件,关于 ESLint 的配置就算完成了
StyleLint 配置
我在项目中配置的 StyleLint 依赖包括
-
stylelint:核心依赖
-
stylelint-config-standard:官方推荐的代码风格
-
stylelint-config-recommended 和 stylelint-config-recommended-vue:常用的 StyleLint 配置依赖
-
stylelint-config-prettier: 解决 StyleLint 和 Prettier 的冲突问题
-
stylelint-order:强制你按照某个顺序编写 css
由于是 Vue 项目,并且使用到了 less,所以还会使用到两个 PostCSS 依赖
- postcss-html:解析文件中
<style>
标签(vue 文件中使用) - postcss-less:支持解析 less 文件
首先安装相关依赖
1pnpm i -D stylelint stylelint-config-standard stylelint-config-recommended stylelint-config-recommended-vue stylelint-config-prettier stylelint-order postcss-html postcss-less
第二步在项目根目录新建 .stylelintrc.js
和 .stylelintignore
两个文件, .stylelintrc.js
文件中的主要配置如下,我在 rules 配置项中为了兼容老项目的风格,还自定义了一些配置项
1module.exports = {
2 root: true,
3 plugins: ['stylelint-order'],
4 customSyntax: 'postcss-html',
5 rules: {
6 // 百分比声明为数字 rgb(0 0 0 / 0.1)
7 'alpha-value-notation': 'number',
8 // 空规则保持空行间隔
9 'at-rule-empty-line-before': 'never',
10 // 忽略一些关键字规则,主要为了兼容 less 和 tailwind
11 'at-rule-no-unknown': [
12 true,
13 {
14 ignoreAtRules: [
15 'tailwind',
16 'content',
17 'each',
18 'error',
19 'extend',
20 'for',
21 'function',
22 'if',
23 'include',
24 'mixin',
25 'return',
26 'while',
27 ],
28 },
29 ],
30 // 颜色表示方式以逗号分隔:rgb(0, 0, 0)
31 'color-function-notation': 'legacy',
32 // 不允许非法的 hex 颜色表示方式:#fff
33 'color-no-invalid-hex': true,
34 'comment-empty-line-before': 'never',
35 // 不允许多行声明
36 'declaration-colon-newline-after': null,
37 // 每个属性之间没有空行
38 'declaration-empty-line-before': 'never',
39 // 不允许 linear-gradient() 存在不符合标准的方向
40 'function-linear-gradient-no-nonstandard-direction': true,
41 // https://stylelint.io/user-guide/rules/list/no-descending-specificity
42 'no-descending-specificity': null,
43 // 允许空文件
44 'no-empty-source': null,
45 // 结尾允许存在空行
46 'no-missing-end-of-source-newline': null,
47 // 小数必须以 0 开头
48 'number-leading-zero': 'always',
49 // 定义排序规则
50 'order/order': [
51 [
52 'dollar-variables',
53 'custom-properties',
54 'at-rules',
55 'declarations',
56 {
57 type: 'at-rule',
58 name: 'supports',
59 },
60 {
61 type: 'at-rule',
62 name: 'media',
63 },
64 'rules',
65 ],
66 { severity: 'warning' },
67 ],
68 // 允许存在空行
69 'rule-empty-line-before': [
70 'always',
71 {
72 ignore: ['after-comment', 'first-nested'],
73 },
74 ],
75 },
76 extends: ['stylelint-config-standard', 'stylelint-config-prettier'],
77 ignoreFiles: ['**/*.js', '**/*.jsx', '**/*.tsx', '**/*.ts'],
78 overrides: [
79 {
80 files: ['*.vue', '**/*.vue', '*.html', '**/*.html'],
81 extends: ['stylelint-config-recommended'],
82 },
83 {
84 files: ['*.less', '**/*.less'],
85 customSyntax: 'postcss-less',
86 extends: [
87 'stylelint-config-standard',
88 'stylelint-config-recommended-vue',
89 ],
90 },
91 ],
92}
第三步配置 .stylelintignore
需要忽略的文件
/dist/*
/public/*
public/*
第四步安装 StyleLint 插件并且在 VSCode 这开启使用 StyleLint 格式化代码
1// stylelint
2"css.validate": false,
3"less.validate": false,
4"scss.validate": false,
5"stylelint.enable": true,
6"stylelint.validate": ["html", "css", "scss", "less", "vue"],
这个插件现在已经是 v1.2.2 的版本了,已经不支持 StyleLint 13 版本,如果你用的是 StyleLint 13 版本的话,需要将这个插件降级使用。点击插件旁边的小齿轮,再点 Install Another Version
,选择其他版本进行安装选 0.87.6 版本安装就可以了,这时 css 自动格式化功能恢复正常。但是 StyleLint 14 的版本的格式化排序功能还是不能在自动保存时实现,我的解决方案是手动在 StyleLint 配置文件增加详细的 CSS 属性排序,这样就可以舒服的使用 StyleLint 的格式化功能了,具体的排序可以参考
再加上统一的执行命令
上面这一套配置下来就可以顺利的实现保存自动格式化,并且所有人的代码风格都是一致的效果了,最后又朝着“像写诗一样写代码”的目标更近了一步,最后在 package.json
文件中加上统一的全局格式化命令,就可以愉快的使用了
1"scripts": {
2 "lint:eslint": "eslint --cache --max-warnings 0 \"{src,mock, build}/**/*.{vue,ts,tsx}\" --fix",
3 "lint:prettier": "prettier --write \"src/**/*.{js,json,tsx,css,less,scss,vue,html,md}\"",
4 "lint:stylelint": "stylelint --cache --fix \"**/*.{vue,less,postcss,css,scss}\" --cache --cache-location node_modules/.cache/stylelint/",
5}
6