《从零开始学习Vite》第四章:自动化代码规范工具的使用

344 阅读11分钟

🍎 系列文章

在系列中,将从零学习Vite,系统梳理 Vite 本身的知识,也包括 Vite 底层所使用的 Esbuild、Rollup 双引擎、Babel 编译工具链、模块规范标准等等构建生态。

《从零开始学习Vite》 第一章:搭建前端项目

《从零开始学习Vite》 第二章:接入 CSS 工程化方案

《从零开始学习Vite》 第三章:静态资源处理

《从零开始学习Vite》第四章:自动化代码规范工具的使用

在上一章中,我们学习了如何加载静态资源和如何在生产环境中对静态资源进行优化。本章,我们将学习前端自动化代码规范工具的使用。

在多人协作的工程项目中,代码规范是非常重要的,它可以统一团队代码风格,避免不同风格的编码混杂在一起难以阅读,在开发阶段可以提前规避一些语法错误,从而有效提高代码质量。包括:ESLintPrettierStylelintCommitlint等主流Lint工具的使用,还会配合huskylint-stagedVSCode插件Vite插件,搭建完整的前端开发和代码提交工作流。

ESLint

初始化

首先我们需要安装ESLint

pnpm add -D eslint

接着利用ESLint官方的Cli进行初始化操作

npx eslint --init

image.png 接着 ESLint 会帮我们自动生成.eslintrc.js配置文件,并用 pnpm 安装了相应的依赖。这里介绍ESLint几个核心的配置项:

1. parser

ESLint底层是使用Espree这个解析器进行AST解析的,目前能够解析大部分ECMAScript规范的语法。比如还不能解析TypeScript,因些需要引入其他的解析器对TypeScript进行解析,社区提供了社区提供了@typescript-eslint/parser这个解决方案,将Typescript代码转换为Espree能够识别的格式,然后 Eslint 再通过Espree进行格式检查,以此兼容了 TypeScript 语法。

2. rules

rules 配置是表示手动调整哪些代码规则,比如 验证您的React组件是否可以通过快速刷新安全地更新

module.exports = {
  // 其他配置省略
  rules: {
    'react-refresh/only-export-components': [
      'warn',
      { allowConstantExport: true },
    ],
  },
}

在 rules 对象中,key 一般为规则名,value 为具体的配置内容,在上述的例子中我们设置为一个数组,数组第一项为规则的 ID,第二项为规则的配置。 你可以设置以下的规则 ID:

  • off或0: 表示关闭规则。
  • warn或1: 表示开启规则,违背规则后只抛出 warning,而不会导致程序退出。
  • error或2: 表示开启规则,违背规则后抛出 error,程序会退出。

具体的规则配置,你可以参考ESLint 官方文档

3. extends

extends 相当于继承另外一份 ESLint 配置,可以配置为一个字符串,也可以配置成一个字符串数组。

主要分如下 3 种情况:

  • 从 ESLint 本身继承;
  • 从 npm 包继承,比如# eslint-config-airbnb
  • 从 ESLint 插件继承;
// .eslintrc.cjs
module.exports = {
// 其他配置省略
    "extends": [
        // 第1种情况
        "eslint:recommended",
        // 第2种情况,一般配置的时候可以省略`eslint-config`
        "airbnb"
        //第3种情况,可以省略包名中的`eslint-plugin`
        //格式一般为:`plugin:${pluginName}/${configName}`
        'plugin:@typescript-eslint/recommended',
        'plugin:react-hooks/recommended',
    ]
}

有了 extends 的配置,我们就不需要手动一一开启了rules,通过 extends 字段即可自动开启插件中的推荐规则: extends:["plugin:@typescript-eslint/recommended"]

4. env

表示运行环境在指定的运行环境中会预设一些全局变量,比如:

// .eslintrc.cjs
env: { browser: true, es2020: true }

指定上述的env配置后便会启用浏览器环境,及启用 es2020。

5. globals

有些全局变量是业务代码引入的第三方库所声明,这里就需要在globals配置中声明全局变量了。 每个全局变量的配置值有 3 种情况:

  • "writable"或者true,表示变量可重写;
  • "readonly"或者false,表示变量不可重写;
  • "off",表示禁用该全局变量; 举例,我们可以在配置文件中声明如下:
// .eslintrc.cjs
module.exports = {
    "globals": {
        //不可重写
        "$":false,
        "jQuery": false
    }
}

Vite 接入 ESLint 插件

我们除了安装编辑器插件外,也可以通过 Vite 插件的方式在开发阶段进行 ESLint 扫描,通过命令行的方式展示不符合规范问题,并能够直接定位到原文件。 安装 ESLint 插件

pnpm add -D vite-plugin-eslint

然后在vite.config.ts中接入:

// vite.config.ts
import viteEslint from "vite-plugin-eslint";

{
    plugins: [
    //省略其它插件
        viteEslint(),
    ]
}

image.png

Prettier

只要提到 ESLint,就不得不说 Prettier 了,虽然 ESLint 具备自动格式化代码的功能(eslint--fix),但ESLint 的主要优势在于代码的风格检查并给出提示,而 Prettier 在代码格式化这一块做的更加专业,所以我们都会将 ESLint 和 Prettier 一起使用。 先来安装 Prettier

pnpm add -D prettier

在项目根目录新建 .prettierrc 配置文件,填写如下的配置内容:

{
  // 箭头函数参数周围加上括号
  "arrowParens": "always",
  // 大括号与代码在同一行
  "bracketSameLine": true,
  // 对象大括号直接是否有空格,默认为true,效果:{ a: 1 }
  "bracketSpacing": true,
  // 分号结尾
  "semi": true,
  // 不使用实验性三元表达式
  "experimentalTernaries": false,
  // 使用单引号
  "singleQuote": true,
  // JSX属性值使用单引号
  "jsxSingleQuote": true,
  // 保留引号样式
  "quoteProps": "preserve",
  // 是否使用尾逗号
  "trailingComma": "none",
  // 不强制单个属性换行
  "singleAttributePerLine": false,
  // HTML空格敏感性为css
  "htmlWhitespaceSensitivity": "css",
  // 文本不换行
  "proseWrap": "never",
  // 不插入格式化标记
  "insertPragma": false,
  // 一行的字符数,如果超过会进行换行,默认为80
  "printWidth": 100,
  // 不要求格式化标记
  "requirePragma": false,
  // 是否使用tab进行缩进,默认为false,表示用空格进行缩减
  "useTabs": true,
  // 嵌入语言格式自动
  "embeddedLanguageFormatting": "auto",
  // 一个tab代表几个空格数,默认为2"tabWidth": 2
}

接着我们将Prettier集成到ESLint中,首先安装两个工具包:

pnpm add -D eslint-config-prettier eslint-plugin-prettier

eslint-config-prettier覆盖 ESLint 本身的规则配置,eslint-plugin-prettier用于让 Prettier 来接管ESLint 自动格式化代码的功能( eslint--fix )。

在.eslintrc.cjs配置文件中接入 prettier 的相关工具链,最终的配置代码如下所示,

module.exports = {
    root: true,
    env: { browser: true, es2020: true },
    extends: [
        "eslint:recommended",
        "plugin:@typescript-eslint/recommended",
        "plugin:react-hooks/recommended",
        "plugin:prettier/recommended",
        "plugin:react/recommended",
        "prettier"
    ],
    ignorePatterns: ["dist", ".eslintrc.cjs"],
    parser: "@typescript-eslint/parser",
    plugins: ["react-refresh", "prettier"],
    rules: {
        "react-refresh/only-export-components": ["warn", { allowConstantExport: true }],
        "prettier/prettier": "error",
        quotes: ["error", "double"],
        semi: ["error", "always"],
        "react/react-in-jsx-scope": "off",
        "@typescript-eslint/no-explicit-any": "error"
    }
};

在package.json中定义一个脚本:

{
    "scripts": {
        "lint:fix": "eslint --ext .js,.jsx,.ts,.tsx --fix --quiet ./src",
    }
}

在命令行终端执行:

pnpm lint:fix

这样就完成了ESLint的规则检查Prettier的自动修复。不过每次执行这个命令就太繁琐了,我们可以在VSCode中安装ESLintPrettier这两个插件,并且在设置区中开启Format On Save:

image.png 然后在根目录下创建.vscode/settings.json,添加如下配置:

{
    // =======================下面是配置prettier格式化的setting===================
    // 指定哪些文件不参与搜索
    "search.exclude": {
      "**/node_modules": true,
      "dist": true,
      "build": true,
      "yarn.lock": true
    },
    // 保存自动格式化
    "editor.formatOnSave": true,
    "[javascript]": {
      "editor.defaultFormatter": "esbenp.prettier-vscode"
    },
    "[javascriptreact]": {
      "editor.defaultFormatter": "esbenp.prettier-vscode"
    },
    "[typescript]": {
      "editor.defaultFormatter": "esbenp.prettier-vscode"
    },
    "[typescriptreact]": {
      "editor.defaultFormatter": "esbenp.prettier-vscode"
    },
    "[json]": {
      "editor.defaultFormatter": "esbenp.prettier-vscode"
    },
    "[html]": {
      "editor.defaultFormatter": "esbenp.prettier-vscode"
    },
    "[markdown]": {
      "editor.defaultFormatter": "esbenp.prettier-vscode"
    },
    "[css]": {
      "editor.defaultFormatter": "esbenp.prettier-vscode"
    },
    "[less]": {
      "editor.defaultFormatter": "esbenp.prettier-vscode"
    },
    "[scss]": {
      "editor.defaultFormatter": "esbenp.prettier-vscode"
    },
  // ==========================prettier===============================
  // ========================eslint===================================
  "eslint.validate": ["javascript", "javascriptreact", "typescript", "typescriptreact"],
  "typescript.tsdk": "./node_modules/typescript/lib", // 代替 vscode 的 ts 语法智能提示
  // 保存自动修复
  "editor.codeActionsOnSave": {
    "source.fixAll.eslint": "explicit",
  }
  // ============================eslint=====================================
}

当你按Ctrl + S保存代码的时候,自动格式化和自动修复。

Stylelint

Stylelint 是一个强大、先进的 CSS 代码检查器(linter),可以帮助你规避 CSS 代码中的错误并保持一致的编码风格。拥有超过 100 条内置规则 来检查最新的 CSS 语法和功能,支持CSS预处理器(如 Sass、Less),提供插件化机制以供开发者扩展规则,与 ESLint 类似,在规范检查方面,Stylelint 已经做的非常强大和专业,而在代码格式化方面,我们还是建议使用格式化工具 Prettier。代码检查工具和格式化工具是互相补充的,能够辅助你编写一致且正确的代码。

首先安装 Stylelint 以及相应的工具插件:

pnpm add -D stylelint stylelint-config-prettier stylelint-config-rational-order stylelint-config-standard stylelint-config-standard-scss stylelint-prettier

接着,在根路径添加 Stylelint 的配置文件.stylelintrc.js

// .stylelintrc.js
module.exports = {
    plugins: [
        //  用于提示我们写的矛盾样式
        "stylelint-declaration-block-no-ignored-properties",
            // 解决stylelint与prettier冲突
        "stylelint-prettier"
    ],
    // 从标准配置中继承规则
    extends: [
        // standard 规则集合
        "stylelint-config-standard",
        // standard规则集合的scss版本
        "stylelint-config-standard-scss",
        // 样式属性顺序规则
        "stylelint-config-rational-order",
        // 接入 Prettier 规则
        "prettier"
    ],

    // 规则配置
    rules: {
        // 禁用注释前的空行规则
        "comment-empty-line-before": null,
        // 禁用声明前的空行规则
        "declaration-empty-line-before": null,
        // 指定函数名的大小写为小写
        "function-name-case": "lower",
        // 禁用选择器特异性递减规则
        "no-descending-specificity": null,
        // 禁用无效的双斜杠注释规则
        "no-invalid-double-slash-comments": null,
        // 指定规则前需要空行
        "rule-empty-line-before": null,
        // 开启 Prettier 自动格式化功能
        "prettier/prettier": true,
        //  用于提示我们写的矛盾样式
        "plugin/declaration-block-no-ignored-properties": true
    }
};

在package.json中定义脚本:

"scripts": {
    // 整合lint命令
    "lint": "pnpm lint:fix && pnpm lint:style",
    // stylelint命令
    "lint:style": "stylelint --config .stylelintrc.cjs src/**/*.{less,css,scss}"
}

执行 pnpm lint:style 就可以完成样式代码的规范检查和自动格式化。也可以在 VSCode 中安装Stylelint插件,这样在开发阶段就可以感知到代码格式问题,提前进行修复。

image.png 并且在 .vscode/settings.json 中增加以下代码:

// ========================stylelint==============================
  // 使用 stylelint 自身的校验即可, 关闭vscode验证
  "css.validate": false,
  "less.validate": false,
  "scss.validate": false,
  "stylelint.validate": ["css", "less", "sass", "scss"]
// ============================stylelint===================================

Vite 接入 Stylelint 插件

实现在项目开发阶段提前暴露出样式代码的规范问题,安装一下这个插件:

pnpm add -D vite-plugin-stylelint

然后在 Vite 配置文件中添加如下的内容:

import stylelint from "vite-plugin-stylelint";
//具体配置{
plugins: [
//省略其它插件
    stylelint({ fix: true })
]}

Husky + lint-staged 的 Git 提交工作流集成

提交前的代码 Lint 检查

我们可以在代码提交的时候进行卡点检查,也就是拦截git commit命令,进行代码格式检查,只有确保通过格式检查才允许正常提交代码。这项工作交给 Husky 来完成,我们来安装一下这个工具:

pnpm add -D husky

启用husky,执行如下命令会自动在package中增加命令

npx husky install

husky prepare 命令,自动加入,有时候也没法自动加入,手动写也是可以的

{
  "scripts": {
    "prepare": "husky install"
  }
}

修改.husky/pre-commit脚本的内容,将.husky/pre-commit脚本的内容改为npm run lint

当你执行 git commit 的时候,会首先执行npm run lint脚本,通过 Lint 检查后才会正式提交代码记录。不过,这会产生一个额外的问题: Husky 中每次执行npm run lint都对仓库中的代码进行全量检查,即使一些文件并没有改动,也会走一遍 Lint 检查,当项目代码越来越多的时候,提交的过程会越来越慢,影响开发效率和体验。而lint-staged就是用来解决上述全量扫描问题的,可以实现只对存入暂存区的文件进行 Lint 检查,大大提高了提交代码的效率。

首先,我们来安装这个工具:

pnpm add -D lint-staged

在 package.json 中添加以下代码

{
  "husky": {
    "hooks": {
      "pre-commit": "lint-staged",
    }
  },
  "lint-staged": {
    "*.{ts,tsx,js}": [
      "eslint --config .eslintrc.cjs"
    ],
    "*.{css,less,scss}": [
      "stylelint --config .stylelintrc.cjs"
    ],
    "*.{ts,tsx,js,json,html,yml,css,less,scss,md}": [
      "prettier --write"
    ]
  },
}

修改.husky/pre-commit脚本的内容,将.husky/pre-commit脚本的内容改为npx lint-staged

通过上面的步骤,就完成了 lint-staged 的配置,这个时候再进行 git 提交时,将只检查暂存区(staged)的文件,不会检查项目所有文件,加快了每次提交 lint 检查的速度,同时也不会被历史遗留问题影响。通过这样的约束让我们定义的规则规范大家都能去遵守,共同维护代码的质量。

image.png

提交时的 commit 信息规范

除了代码规范检查之后,Git 提交信息的规范也是不容忽视的一个环节,规范的 commit信息能够方便团队协作和问题定位。commitlint 可以帮助我们进行 git commit 时的 message 格式是否符合规范,安装一下需要的工具库:

pnpm add -D commitlint @commitlint/cli @commitlint/config-conventional

根目录下新增配置文件.commitlintrc.cjs

module.exports = {
    extends: ["@commitlint/config-conventional"],
    rules: {
        "type-enum": [
            2,
            "always",
            [
                "build",
                "ci",
                "chore",
                "docs",
                "feat",
                "fix",
                "perf",
                "refactor",
                "revert",
                "style",
                "test",
                "addLog"
            ]
        ]
    }
};

@commitlint/config-conventional 这是一个规范配置,标识采用什么规范来执行消息校验, 这个默认是Angular的提交规范,它所规定的commit 信息一般由两个部分:typesubject组成,结构如下:

// type指提交的类型
// subject指提交的摘要信息
<type>: <subject>

常用的type值包括如下:

  • feat:添加新功能。
  • fix:修复 Bug。
  • chore:一些不影响功能的更改。
  • docs:文档的修改。
  • perf:性能方面的优化。
  • refactor:代码重构。
  • test:添加一些测试代码。
  • ci:持续集成

接着在package.json 的 husky 配置,增加一个钩子

"husky": {
    "hooks": {
        "pre-commit": "lint-staged",
        "commit-msg": "commitlint --config .commitlintrc.js -E HUSKY_GIT_PARAMS"
    }
},

现在我们可以尝试对代码进行提交,假如输入一个错误的commit 信息,commitlint 会自动抛出错误并退出

image.png 至此,我们便完成了 Git 提交信息的卡点扫描和规范检查。

代码仓库

vettel-2024/vite-course: 从零开始Vite学习之旅 (github.com)