前端规范(ESLint9+Vue3+husky+commitlint)

1,115 阅读10分钟

背景

必要性

代码风格统一很重要,要是没有统一代码风格我们在提交代码的时候,diff会比较多,我们在多人协作的时候,解决的冲突会骤然变大,带来了业务之外的负担。而且当新人进入的时候,不利于了解代码,降低了开发的效率。

  • diff 导致的问题会变多,代码风险,不利于查看新提交的内容
  • 新人加入需要投入较大的精力来熟悉代码,不利于提高开发效率

如何统一代码风格

使用人工验证工作量太大了,所以我们经常借助工具来完成这类工作,前端主要使用的工具为ESLint、StyleLint,提供了比较全面的配置文件,可以对我们项目的代码风格进行配置。可以有效的提高我们的代码质量和开发效率。

工具枚举

  • VSCode插件:安装编辑器插件,使用插件提高我们的开发效率

    • ESLint
    • StyleLint
    • Prettier
  • VSCode的配置:配置文件,用来存放用户的一些常见配置

    • 工作区的setting.json
    • 用户区的setting.json
  • CSS 格式化

    • StyleLint
  • Git流程规范

    • Husky
    • CommitLint
    • Lint-Stage

使用

ESlint

ESLint 是一款插件化的JavaScript代码静态检查工具,核心理念是通过AST树对进行模式匹配,来进行分析和检查代码安全。

脚手架安装

可以在用脚手架创建项目的时候,默认创建选上ESLint,项目创建完成后会在跟路径下默认创建一个.eslintrc.js文件。 image.png

手动安装

下载eslint,在项目中进行配置。

npm install eslint --save-dev

对eslint 进行初始化,根据下面的选项选择我们当前的项目的风格。

eslint --init

image.png 我们执行过后发现在该路径下生成了一个新的文件:

image.png

文件内的内容如下:

// eslint.config.mjs文件

// 导入了 `globals`全局变量的库模块,该模块提供了一组预定义的全局变量(如 window、document 等),这些变量通常在不同的环境(如浏览器、Node.js)中可用。
// 在 ESLint 配置中,你可以使用这个模块来指定代码所运行的环境,从而定义全局变量。
import globals from 'globals'
//针对 JavaScript 的 ESLint 配置和规则。保持 JavaScript 代码的一致性和质量
import pluginJs from '@eslint/js'
// 导入 `eslint-plugin-vue` 插件,提供了 Vue.js 特有 ESLint 规则。确保 Vue 文件(`.vue` 文件)中的代码符合 Vue.js 的最佳实践和代码风格指南
import pluginVue from 'eslint-plugin-vue'

/** @type {import('eslint').Linter.Config[]} */
export default [
  // 配置ignore文件,过滤dist的文件
  { ignores: ['**/dist/*'] },
  //**文件匹配**:`files` 属性指定了哪些文件类型(JavaScript、Vue 文件等)将应用这些规则
  { files: ['**/*.{js,mjs,cjs,vue}'] },

  //1.  **全局变量**:`languageOptions` 配置了浏览器环境下的全局变量。
  { languageOptions: { globals: globals.browser } },
  // **插件和规则**:
  pluginJs.configs.recommended,
  // 引入`eslint-plugin-vue` 插件的基础规则
  ...pluginVue.configs['flat/essential'],
  {
    rules: {
      indent: ['error', 2], // 缩进使用 2 个空格
      'linebreak-style': ['error', 'unix'], // 使用 Unix 风格的换行符
      quotes: ['error', 'single'], // 使用单引号
      semi: ['error', 'never'], // 语句末尾不加分号
      'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off', // 生产环境中警告 console 使用,开发环境中关闭规则
      'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off', // 生产环境中警告 debugger 使用,开发环境中关闭规则
    },
  },
]

手动配置

相关的依赖包的版本如下:

image.png

ps:node 的版本要求较高,我当前只用的node版本为:v20.15.1

对于package.json中配置相关的脚本

"scripts": {
    "lint": "eslint ",
    "lint:fix": "eslint --fix"
},

prettier

概念

是VSCode的一种插件,它让人又爱又恨,因为他和ESlint 之间是有冲突的,那我们应该如何解决这种冲突呢。

解决冲突

最新版本的eslit和preitter不再是冲突的,所以我们可以使用不用做额外的处理,但是我们可以对我们当下的风格进行定义。

// prettier.config.js
/**
 * @type {import('prettier').Config}
 * @see https://www.prettier.cn/docs/options.html
 */
export default {
  trailingComma: "all",
  singleQuote: true,
  semi: false,
  printWidth: 80,
  arrowParens: "always",
  proseWrap: "always",
  endOfLine: "lf",
  experimentalTernaries: false,
  tabWidth: 2,
  useTabs: false,
  quoteProps: "consistent",
  jsxSingleQuote: false,
  bracketSpacing: true,
  bracketSameLine: false,
  jsxBracketSameLine: false,
  vueIndentScriptAndStyle: false,
  singleAttributePerLine: false,
};

同时需要依赖插件进行相关的配置:

// .vscode/settings.json
   {
 "eslint.validate": [
   "javascript",
   "vue",
   "vue-html",
   "typescript",
   "typescriptreact",
   "html",
   "css",
   "scss",
   "less",
   "json",
   "jsonc",
   "json5",
   "markdown"
 ],
 "editor.codeActionsOnSave": {
   "source.fixAll.eslint": true
 }
}

最终配置

// 导入了 `globals`全局变量的库模块,该模块提供了一组预定义的全局变量(如 window、document 等),这些变量通常在不同的环境(如浏览器、Node.js)中可用。
// 在 ESLint 配置中,你可以使用这个模块来指定代码所运行的环境,从而定义全局变量。
import globals from 'globals'
//针对 JavaScript 的 ESLint 配置和规则。保持 JavaScript 代码的一致性和质量
import pluginJs from '@eslint/js'
// 导入 `eslint-plugin-vue` 插件,提供了 Vue.js 特有 ESLint 规则。确保 Vue 文件(`.vue` 文件)中的代码符合 Vue.js 的最佳实践和代码风格指南
import pluginVue from 'eslint-plugin-vue'
// import eslintConfigPrettier from "eslint-plugin-prettier/recommended";

export default [
 { ignores: ['**/dist/*','./eslint.config.mjs','./vue.config.js'] },
 //**文件匹配**:`files` 属性指定了哪些文件类型(JavaScript、Vue 文件等)将应用这些规则
 { files: ['**/*.{js,mjs,cjs,vue}'] },

 //1.  **全局变量**:`languageOptions` 配置了浏览器环境下的全局变量。
 { languageOptions: { globals: { ...globals.browser, ...globals.node } } }, // 解决node 相关的udf报错
 // **插件和规则**:
 pluginJs.configs.recommended,
 // 引入`eslint-plugin-vue` 插件的基础规则
 ...pluginVue.configs['flat/essential'],

 {
   rules: {
     indent: ['error', 2], // 缩进使用 2 个空格
     'vue/multi-word-component-names':'off',
     // 'linebreak-style': ['error', 'unix'], // 使用 Unix 风格的换行符
     quotes: ['error', 'single'], // 使用单引号
     semi: ['error', 'never'], // 语句末尾不加分号
     'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off', // 生产环境中警告 console 使用,开发环境中关闭规则
     'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off', // 生产环境中警告 debugger 使用,开发环境中关闭规则
   },
 },
]

styleLint

主要针对我们写的一些样式文件,进行统一的格式化,但是当前的项目样式变化比较多,所以经过取舍,不再在项目中引入styleLint,后续有时间再研究这里

git

husky

husky: 用来管理git 的生命周期,commitlint用来管理提交代码相关的规范

npm install -D husky 

我们需要初始化一个个husky的文件,执行如下的命令:

npx husky-init

初始化husky 文件,然后我们会生成如下目录:

image.png

我们的预期是在提交代码执行一遍eslint,我们进行操作的package.json文件内容如下:

"scripts": {
   "lint": "eslint ",
   "lint:fix": "eslint --fix"
},

image.png

我们在.husky/pre-commit的文件内容如下:

#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
npm run lint

Commitlint

Commitlint 检查您的提交消息是否符合 Conventional commit format。-- Commitlint 官网 我们先安装一个相关的依赖,安装的内容如下:

 npm install -D @commitlint/cli @commitlint/config-conventional

根目录创建 commitlint.config.cjs 配置文件,我们在配置文件,写入相关的配置:

module.exports = {
  // 继承的规则
  extends: ["@commitlint/config-conventional"],
  // @see: https://commitlint.js.org/#/reference-rules
  rules: {
    "subject-case": [0], // subject大小写不做校验

    // 类型枚举,git提交type必须是以下类型
    "type-enum": [
      2,
      "always",
      [
    'feat', // 新增功能
        'fix', // 修复缺陷
        'docs', // 文档变更
        'style', // 代码格式(不影响功能,例如空格、分号等格式修正)
        'refactor', // 代码重构(不包括 bug 修复、功能新增)
        'perf', // 性能优化
        'test', // 添加疏漏测试或已有测试改动
        'build', // 构建流程、外部依赖变更(如升级 npm 包、修改 webpack 配置等)
        'ci', // 修改 CI 配置、脚本
        'revert', // 回滚 commit
        'chore', // 对构建过程或辅助工具和库的更改(不影响源文件、测试用例)
      ],
    ],
  },
};

添加提交信息校验钩子

执行下面命令生成 commint-msg 钩子用于 git 提交信息校验

npx husky add .husky/commit-msg "npx --no -- commitlint --edit $1"

文件变成上面的样子:

image.png

文件内容如下:

#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"

npx --no -- commitlint --edit 

Commitizen & cz-git

  • commitizen: 基于Node.js的 git commit 命令行工具,辅助生成标准化规范化的 commit message。--官方文档
  • cz-git: 一款工程性更强,轻量级,高度自定义,标准输出格式的 commitizen 适配器

Commitizen & cz-git 安装

npm install -D commitizen cz-git

修改 package.json 指定使用的适配器

  "config": {
    "commitizen": {
      "path": "node_modules/cz-git"
    }
  },

cz-git 与 commitlint 进行联动给予校验信息,所以可以编写于 commitlint 配置文件之中

module.exports = {
  // 继承的规则
  extends: ['@commitlint/config-conventional'],
  // @see: https://commitlint.js.org/#/reference-rules
  rules: {
    'subject-case': [0], // subject大小写不做校验

    // 类型枚举,git提交type必须是以下类型
    'type-enum': [
      2,
      'always',
      [
        'feat', // 新增功能
        'fix', // 修复缺陷
        'docs', // 文档变更
        'style', // 代码格式(不影响功能,例如空格、分号等格式修正)
        'refactor', // 代码重构(不包括 bug 修复、功能新增)
        'perf', // 性能优化
        'test', // 添加疏漏测试或已有测试改动
        'build', // 构建流程、外部依赖变更(如升级 npm 包、修改 webpack 配置等)
        'ci', // 修改 CI 配置、脚本
        'revert', // 回滚 commit
        'chore', // 对构建过程或辅助工具和库的更改(不影响源文件、测试用例)
      ],
    ],
  },
  prompt: {
    messages: {
      type: '选择你要提交的类型 :',
      scope: '选择一个提交范围(可选):',
      customScope: '请输入自定义的提交范围 :',
      subject: '填写简短精炼的变更描述 :\n',
      body: '填写更加详细的变更描述(可选)。使用 "|" 换行 :\n',
      breaking: '列举非兼容性重大的变更(可选)。使用 "|" 换行 :\n',
      footerPrefixesSelect: '选择关联issue前缀(可选):',
      customFooterPrefix: '输入自定义issue前缀 :',
      footer: '列举关联issue (可选) 例如: #31, #I3244 :\n',
      generatingByAI: '正在通过 AI 生成你的提交简短描述...',
      generatedSelectByAI: '选择一个 AI 生成的简短描述:',
      confirmCommit: '是否提交或修改commit ?',
    },
    // prettier-ignore
    types: [
      { value: 'feat',     name: '特性:     ✨  新增功能', emoji: ':sparkles:' },
      { value: 'fix',      name: '修复:     🐛  修复缺陷', emoji: ':bug:' },
      { value: 'docs',     name: '文档:     📝  文档变更', emoji: ':memo:' },
      { value: 'style',    name: '格式:     💄  代码格式(不影响功能,例如空格、分号等格式修正)', emoji: ':lipstick:' },
      { value: 'refactor', name: '重构:     ♻️  代码重构(不包括 bug 修复、功能新增)', emoji: ':recycle:' },
      { value: 'perf',     name: '性能:     ⚡️  性能优化', emoji: ':zap:' },
      { value: 'test',     name: '测试:     ✅  添加疏漏测试或已有测试改动', emoji: ':white_check_mark:'},
      { value: 'build',    name: '构建:     📦️  构建流程、外部依赖变更(如升级 npm 包、修改 vite 配置等)', emoji: ':package:'},
      { value: 'ci',       name: '集成:     🎡  修改 CI 配置、脚本',  emoji: ':ferris_wheel:'},
      { value: 'revert',   name: '回退:     ⏪️  回滚 commit',emoji: ':rewind:'},
      { value: 'chore',    name: '其他:     🔨  对构建过程或辅助工具和库的更改(不影响源文件、测试用例)', emoji: ':hammer:'},
    ],
    useEmoji: true,
    emojiAlign: 'center',
    useAI: false,
    aiNumber: 1,
    themeColorCode: '',
    scopes: [],
    allowCustomScopes: true,
    allowEmptyScopes: true,
    customScopesAlign: 'bottom',
    customScopesAlias: 'custom',
    emptyScopesAlias: 'empty',
    upperCaseSubject: false,
    markBreakingChangeMode: false,
    allowBreakingChanges: ['feat', 'fix'],
    breaklineNumber: 100,
    breaklineChar: '|',
    skipQuestions: [],
    issuePrefixes: [{ value: 'closed', name: 'closed:   ISSUES has been processed' }],
    customIssuePrefixAlign: 'top',
    emptyIssuePrefixAlias: 'skip',
    customIssuePrefixAlias: 'custom',
    allowCustomIssuePrefix: true,
    allowEmptyIssuePrefix: true,
    confirmColorize: true,
    maxHeaderLength: Infinity,
    maxSubjectLength: Infinity,
    minSubjectLength: 0,
    scopeOverrides: undefined,
    defaultBody: '',
    defaultIssues: '',
    defaultScope: '',
    defaultSubject: '',
  }
}

添加提交指令

package.json 添加 commit 指令

"scripts": { "commit": "git-cz" }

提交代码的时候我们执行的顺序如下

git add .
npm run commit

我们执行了如下的命令会出现下面的交互,我们按照交互进行执行: image.png

后记

由于elint9版本过高,对于Vue的兼容性还是不是很好,很多问题在社区上没有很好的节点,综上所述,决定将eslint的版本降低到8.57.0,下面详细说一下降低版本后的操作

降低eslint的版本

"eslint": "^8.57.0",

额外安装进行内容的转译

"@babel/eslint-parser": "^7.25.9",

elint 的配置文件修改成.eslintrc.js,文档的内容如下:

module.exports = {
  parser: 'vue-eslint-parser',
  'env': {
    'browser': true,
    'es6': true,
    'node': true
  },
  'extends': ['eslint:recommended','plugin:vue/vue3-essential', 'plugin:vue/vue3-essential'],
  'parserOptions': {
    'ecmaVersion': 2020,
    'sourceType': 'module'
  },
  'rules': {
    // 缩进
    'indent': [
      'error',
      2 //我的是编辑器自动格式化,不是使用tabs,而是四个空格
    ],
    // 引号
    'quotes': [
      1,
      'single'
    ],
    'vue/multi-word-component-names':'off',
    'no-unused-vars': [2, {
      // 允许声明未使用变量
      'vars': 'local',
      // 参数不检查
      'args': 'none'
    }],
    // 最大空行100
    'no-multiple-empty-lines': [0, { 'max': 100 }],
    'no-mixed-spaces-and-tabs': [0],
    // vue/multi-word-component-names
    'no-console': 'off',
    //未定义变量不能使用
    'no-undef': 0,
    //一行结束后面不要有空格
    'no-trailing-spaces': 1,
    //this别名
    'consistent-this': [2, 'that'],
  }
};