ESlint + Stylelint + VSCode + husky 自动格式化代码并提交

1. vscode stylelint插件安装及配置

vscode stylelint插件版本

vscode stylelint插件版本

vscode中配置stylelint和开启自动修复

// \vue-pure-admin\.vscode\settings.json
// 开启stylelint自动修复
"editor.codeActionsOnSave": {
  "source.fixAll": true, // 开启自动修复
  "source.fixAll.stylelint": true, // 开启stylelint自动修复
},
// 关闭编辑器内置样式检查(避免与stylelint冲突)
"css.validate": false,
"less.validate": false,
"scss.validate": false,
// 配置stylelint检查的文件类型范围
"stylelint.validate": ["css", "less", "postcss", "scss", "sass", "vue"],

2. 安装stylelint依赖

pnpm add -D postcss postcss-html postcss-import postcss-scss stylelint stylelint-config-html stylelint-config-rational-order stylelint-config-recommended stylelint-config-standard stylelint-order
  • 依赖简介
  • stylelint ---- 主依赖
  • stylelint-scss ---- stylelint的scss特定linting规则的集合
  • stylelint-config-standard ---- stylelint的标准可共享配置 可以省略
  • stylelint-config-standard-scss ---- 针对scss的标准可共享配置。与stylelint-scss配合使用
  • postcss ---- 用于postcss-html和postcss-scss的支持
  • postcss-html ---- 解析<style>类 vue、html 文件标签中的样式
  • postcss-scss ---- 解析<style lang=“scss”>下的scss样式
  • stylelint-order ---- css属性排序规则插件,强制你按照某个顺序编写 css。例如:先写定位,再写盒模型,再写内容区样式,最后写 CSS3相关属性。
  • stylelint-config-rational-order ---- 针对css属性排序的共享规则配置,避免长串css属性顺序规则书写。与stylelint-order配合使用
  • 扩展
    如何格式化 HTML、Vue(或其他后缀) 文件中的 HTML 代码?

.vue 文件的 HTML 代码可以使用 eslint-plugin-vue 插件来进行格式化:

extends: [
    'plugin:vue/recommended', // 在 .eslintrc.js 文件中加上这一行代码
    '@vue/airbnb',
]

其他的 HTML 文件需要利用 VSCode 自带的格式化。

  • 踩坑

Unknown word (CssSyntaxError) 错误

问题主要是因为 stylelint 升级到 14 大版本造成的。

  • 解决方案一
    安装 stylelint 新的相关依赖:
pnpm add -D stylelint-config-recommended-vue stylelint-config-standard-scss postcss-html postcss-scss

然后修改 .stylelintrc.js 文件的配置项:

extends: [
    'stylelint-config-standard-scss',
    'stylelint-config-recommended-vue'
],
customSyntax: 'postcss-html',
overrides: [
    {
        files: ['**/*.{scss,css,sass}'], // css 相关文件由 postcss-scss 处理
        customSyntax: 'postcss-scss'
    },
]

这样修改以后,就不会再报错了。

如果出现 Cannot find module 'postcss-scss'错误,请将 node_modules package-lock.json 文件删了重新安装。

  • 解决方案二
    第二个解决方案就是将以上三个插件的版本降一个大版本就好了,最后的版本如下:
"stylelint": "^13.13.1",
"stylelint-config-standard": "^22.0.0",
"stylelint-scss": "^3.21.0",

同时需要将 VSCode 的 stylelint 插件降级,现在插件的最新版本是 1.0.3,不支持 stylelint 13 版本。点击插件旁边的小齿轮,再点 Install Another Version

解决方案

,选择其他版本进行安装。

选 0.87.6 版本安装就可以了,这时 css 自动格式化功能恢复正常。

3. 添加stylelint配置文件

module.exports = {
  root: true,
  plugins: ["stylelint-order"],
  customSyntax: "postcss-html",
  extends: [
    'stylelint-config-standard-scss',
    'stylelint-config-recommended-vue',
    "stylelint-config-rational-order",
  ],
  ignoreFiles: ["**/*.js", "**/*.jsx", "**/*.tsx", "**/*.ts", "**/*.json"],
  overrides: [
    {
      files: ["**/*.{scss,css,sass}"], // css 相关文件由 postcss-scss 处理
      customSyntax: "postcss-scss"
    },
    {
      files: ["*.vue", "**/*.vue", "*.html", "**/*.html"],
      rules: {
        "keyframes-name-pattern": null,
        "selector-pseudo-class-no-unknown": [
          true,
          {
            ignorePseudoClasses: ["deep", "global"]
          }
        ],
        "selector-pseudo-element-no-unknown": [
          true,
          {
            ignorePseudoElements: ["v-deep", "v-global", "v-slotted"]
          }
        ]
      }
    }
  ],
  rules: {
    "selector-class-pattern": null,
    "selector-pseudo-class-no-unknown": [
      true,
      {
        ignorePseudoClasses: ["global"]
      }
    ],
    "selector-pseudo-element-no-unknown": [
      true,
      {
        ignorePseudoElements: ["v-deep"]
      }
    ],
    "at-rule-no-unknown": [
      true,
      {
        ignoreAtRules: [
          "tailwind",
          "apply",
          "variants",
          "responsive",
          "screen",
          "function",
          "if",
          "each",
          "include",
          "mixin"
        ]
      }
    ],
    "no-empty-source": null,
    "named-grid-areas-no-invalid": null,
    "unicode-bom": "never",
    "no-descending-specificity": null,
    "font-family-no-missing-generic-family-keyword": null,
    "declaration-colon-space-after": "always-single-line",
    "declaration-colon-space-before": "never",
    "rule-empty-line-before": [
      "always",
      {
        ignore: ["after-comment", "first-nested"]
      }
    ],
    "unit-no-unknown": [true, { ignoreUnits: ["rpx"] }],
    "order/order": [
      [
        "dollar-variables",
        "custom-properties",
        "at-rules",
        "declarations",
        {
          type: "at-rule",
          name: "supports"
        },
        {
          type: "at-rule",
          name: "media"
        },
        "rules"
      ],
      { severity: "warning" }
    ],
    "order/properties-order": [
      "position",
      "top",
      "right",
      "bottom",
      "left",
      "z-index",
      "display",
      "justify-content",
      "align-items",
      "float",
      "clear",
      "overflow",
      "overflow-x",
      "overflow-y",
      "margin",
      "margin-top",
      "margin-right",
      "margin-bottom",
      "margin-left",
      "border",
      "border-style",
      "border-width",
      "border-color",
      "border-top",
      "border-top-style",
      "border-top-width",
      "border-top-color",
      "border-right",
      "border-right-style",
      "border-right-width",
      "border-right-color",
      "border-bottom",
      "border-bottom-style",
      "border-bottom-width",
      "border-bottom-color",
      "border-left",
      "border-left-style",
      "border-left-width",
      "border-left-color",
      "border-radius",
      "padding",
      "padding-top",
      "padding-right",
      "padding-bottom",
      "padding-left",
      "width",
      "min-width",
      "max-width",
      "height",
      "min-height",
      "max-height",
      "font-size",
      "font-family",
      "font-weight",
      "text-align",
      "text-justify",
      "text-indent",
      "text-overflow",
      "text-decoration",
      "white-space",
      "color",
      "background",
      "background-position",
      "background-repeat",
      "background-size",
      "background-color",
      "background-clip",
      "opacity",
      "filter",
      "list-style",
      "outline",
      "visibility",
      "box-shadow",
      "text-shadow",
      "resize",
      "transition"
    ]
  }
};

eslint 格式化代码

本文用 Vue 项目做示范。

利用 Vue-CLI 创建项目时要将 ESlint 选上,下载完依赖后,用 VSCode 打开项目。

安装插件 ESLint,然后 File -> Preference-> Settings(如果装了中文插件包应该是 文件 -> 选项 -> 设置),搜索 eslint,点击 Edit in setting.json

Edit in setting.json

将以下选项添加到配置文件

"editor.codeActionsOnSave": {
    "source.fixAll": true,
},
"eslint.validate": [
    "javascript",
    "javascriptreact",
    "typescript",
    "typescriptreact",
],
"eslint.alwaysShowStatus": true,
"stylelint.validate": [
    "css",
    "less",
    "postcss",
    "scss",
    "vue",
    "sass"
]

同时要确保 VSCode 右下角的状态栏 ESlint 是处于工作状态的。如果右下角看不到 Eslint 的标识,请按照上面讲过的步骤打开 setting.json,加上这行代码:

"eslint.alwaysShowStatus": true
Eslint

配置完之后,VSCode 会根据你当前项目下的 .eslintrc 文件的规则来验证和格式化代码。

TypeScript

下载插件

pnpm add -D  typescript @typescript-eslint/parser @typescript-eslint/eslint-plugin

在 .eslintrc 配置文件,添加以下两个配置项:

"parser": "@typescript-eslint/parser",
"plugins": [
    "@typescript-eslint"
]

在根目录下的 package.json 文件的 scripts 选项里添加以下配置项:

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

如果你使用 Vue-CLI 创建项目,并且想要格式化 TypeScript 的代码,则需要在 .eslintrc.js 文件添加或修改以下几项:

parser: 'vue-eslint-parser',
plugins: [
    '@typescript-eslint',
],
parserOptions: {
    parser: '@typescript-eslint/parser',
    ecmaVersion: 2020,
}

这样就可以格式化 .js .ts .vue 文件了。

git提交

流程规范配置

依赖 作用描述
husky 操作 git 钩子的工具(在 git xx 之前执行某些命令)
lint-staged 在提交之前进行 eslint 校验,并使用 prettier 格式化本地暂存区的代码
@commitlint/cli 校验 git commit 信息是否符合规范,保证团队的一致性
@commitlint/config-conventional Anglar 的提交规范
commitizen 基于 Node.js 的 git commit 命令行工具,生成标准化的 commit message
cz-git 一款工程性更强,轻量级,高度自定义,标准输出格式的 commitize 适配器

1、husky(操作 git 钩子的工具):

  • 安装
yarn add husky -D
  • 使用(为了添加.husky 文件夹)
// 1、打开package.json文件,在scripts中添加
  "prepare": "husky install"
// 2、添加完成之后,执行如下命令
   npm run-script prepare ".husky"
   npm run prepare

2、lint-staged(本地暂存代码检查工具)

  • 安装
yarn add lint-staged -D

  • 添加 ESlint Hook(在.husky 文件夹下添加 pre-commit 文件):
  • 作用:通过钩子函数,判断提交的代码是否符合规范,并使用 prettier 格式化代码
  • 执行以下命令,在husky文件夹下自动生成pre-commit文件:
npx husky add .husky/pre-commit "npm run lint:lint-staged -c ./.husky/lintstagedrc.js"
  • 新增 根目录/.husky/lintstagedrc.js 文件:
module.exports = {
  "*.{js,jsx,ts,tsx}": ["eslint --fix", "prettier --write"],
  "!(package)*.json": ["prettier --write--parser json"],
  "package.json": ["prettier --write"],
  "*.vue": ["eslint --fix", "prettier --write", "stylelint --fix"],
  "*.{vue,css,scss,postcss,less}": ["stylelint --fix", "prettier --write"],
  "*.md": ["prettier --write"]
};

3、commitlint(commit 信息校验工具,不符合则报错)

  • 安装
yarn add @commitlint/cli @commitlint/config-conventional -D
  • 配置命令(在.husky 文件夹下自动生成 commit-msg 文件,执行如下代码自动生成):
npx husky add .husky/commit-msg 'npx --no-install commitlint --edit "$1"'

4、commitizen(基于 Node.js 的 git commit 命令行工具,生成标准化的 message)

// 安装 commitizen,如此一来可以快速使用 cz 或 git cz 命令进行启动。
yarn add commitizen -D

5、cz-git

  • 指定提交文字规范,一款工程性更强,高度自定义,标准输出格式的 commitizen 适配器
yarn add cz-git -D
  • 配置 package.json:
"config": {
  "commitizen": {
    "path": "node_modules/cz-git"
  }
}

  • 新建 commitlint.config.js 文件:
// @see: https://cz-git.qbenben.com/zh/guide
/** @type {import('cz-git').UserConfig} */

module.exports = {
  ignores: [commit => commit === "init"],
  extends: ["@commitlint/config-conventional"],
  rules: {
    // @see: https://commitlint.js.org/#/reference-rules
    "body-leading-blank": [2, "always"],
    "footer-leading-blank": [1, "always"],
    "header-max-length": [2, "always", 108],
    "subject-empty": [2, "never"],
    "type-empty": [2, "never"],
    "subject-case": [0],
    "type-enum": [
      2,
      "always",
      [
        "feat",
        "fix",
        "docs",
        "style",
        "refactor",
        "perf",
        "test",
        "build",
        "ci",
        "chore",
        "revert",
        "wip",
        "workflow",
        "types",
        "release"
      ]
    ]
  },
  prompt: {
    messages: {
      type: "选择你要提交的类型 :",
      scope: "选择一个提交范围(可选):",
      customScope: "请输入自定义的提交范围 :",
      subject: "填写简短精炼的变更描述 :\n",
      body: '填写更加详细的变更描述(可选)。使用 "|" 换行 :\n',
      markBreaking: "是否有任何重大变更(添加“!“在头部中)(可选)?",
      breaking: '列举非兼容性重大的变更(可选)。使用 "|" 换行 :\n',
      footerPrefixsSelect: "选择关联issue前缀(可选):",
      customFooterPrefixs: "输入自定义issue前缀 :",
      footer: "列举关联issue (可选) 例如: #31, #I3244 :\n",
      generatingByAI: "正在自动生成提交主题...",
      generatedSelectByAI: "自动生成的主题中选择适合者",
      confirmCommit: "是否提交或修改commit ?"
    },
    types: [
      { value: "feat: 新增", name: "新增:   🚀  新增功能", emoji: "🚀" },
      { value: "fix: 修复", name: "修复:   🧩  修复缺陷", emoji: "🧩" },
      { value: "docs: 文档", name: "文档:   📚  文档变更", emoji: "📚" },
      { value: "style: 格式", name: "格式:   🎨  代码格式(不影响功能,例如空格、分号等格式修正)", emoji: "🎨" },
      { value: "refactor: 重构", name: "重构:   ♻️   代码重构(不包括 bug 修复、功能新增)", emoji: "♻️" },
      { value: "perf: 性能", name: "性能:   ⚡️  性能优化", emoji: "⚡️" },
      { value: "test: 测试", name: "测试:   ✅  添加疏漏测试或已有测试改动", emoji: "✅" },
      { value: "build: 打包", name: "打包:   🔨  项目打包部署上线", emoji: "🔨" },
      { value: "ci: 集成", name: "集成:   🎡  修改 CI 配置、脚本", emoji: "🎡" },
      { value: "chore: 构建", name: "构建:   📦️  构建流程、外部依赖变更(如升级 npm 包、修改 webpack 配置等)", emoji: "📦️" },
      { value: "revert: 回退", name: "回退:   ⏪️  回滚 commit", emoji: "⏪️" }
    ],
    useEmoji: true,
    themeColorCode: "",
    scopes: [],
    allowCustomScopes: true,
    allowEmptyScopes: true,
    customScopesAlign: "bottom",
    customScopesAlias: "custom",
    emptyScopesAlias: "empty",
    upperCaseSubject: false,
    allowBreakingChanges: ["feat", "fix"],
    breaklineNumber: 100,
    breaklineChar: "|",
    skipQuestions: [],
    issuePrefixs: [{ value: "closed", name: "closed:   ISSUES has been processed" }],
    customIssuePrefixsAlign: "top",
    emptyIssuePrefixsAlias: "skip",
    customIssuePrefixsAlias: "custom",
    allowCustomIssuePrefixs: true,
    allowEmptyIssuePrefixs: true,
    confirmColorize: true,
    maxHeaderLength: Infinity,
    maxSubjectLength: Infinity,
    minSubjectLength: 0,
    scopeOverrides: undefined,
    defaultBody: "",
    defaultIssues: "",
    defaultScope: "",
    defaultSubject: ""
  }
};

 

6、配置 package.json 命令


    "lint:eslint": "eslint --cache --max-warnings 0  \"{src,mock,build}/**/*.{vue,js,ts,tsx}\" --fix",
    "lint:prettier": "prettier --write  \"src/**/*.{js,ts,json,tsx,css,less,scss,vue,html,md}\"",
    "lint:stylelint": "stylelint --cache --fix \"**/*.{vue,css,scss,postcss,less}\" --cache --cache-location node_modules/.cache/stylelint/",
    "lint:format": "prettier --write --loglevel warn \"src/**/*.{js,ts,json,tsx,css,less,vue,html,md}\"",
    "lint": "yarn lint:eslint && yarn lint:prettier && yarn lint:stylelint",
    "lint:lint-staged": "lint-staged",
    "prepare": "husky install",
    "release": "standard-version",
    "commit": "git pull && git add -A && git-cz && git push"

7、配置完成,提交代码

yarn commit

🚀 上效果