使用 husky、lint-staged、eslint、prettier、stylelint、tsc 规范代码

2,711 阅读5分钟

目的:

  • 保存时自动 eslint 修正、prettier 格式化、stylelint 格式化
  • 暂存区提交时检测 eslint、stylelint
  • 代码提交时全局检测 ts 规范

vscode 需要安装插件 ESLintPrettier - Code formatterStylelint

自动保存修正格式

添加 vscode 的配置,添加 .Vscode 文件夹,在文件夹下新建 settings.json

{
  "editor.formatOnSave": true,
  "editor.defaultFormatter": "esbenp.prettier-vscode",
  "editor.codeActionsOnSave": {
    "source.fixAll.eslint": true,
    "source.fixAll.stylelint": true
  },
  "stylelint.validate": ["css", "less", "scss", "vue"],
  "[less]": {
    "editor.defaultFormatter": "esbenp.prettier-vscode"
  },
  "[scss]": {
    "editor.defaultFormatter": "esbenp.prettier-vscode"
  },
  "[vue]": {
    "editor.defaultFormatter": "esbenp.prettier-vscode"
  }
}

添加 husky

1. 安装依赖

yarn add @commitlint/cli @commitlint/config-conventional husky lint-staged -D

2. 配置 package.json

 "scripts": {
    "lint": "lint-staged",  //暂存区 lint 检查,配置文件在 .lintstagedrc
    "tsc": "vue-tsc --noEmit --skipLibCheck",  //ts的检查
    "prepare": "husky install"  //安装依赖时下载husky
  }
  "lint-staged": {
    "*.{js,jsx,ts,tsx,vue}": [
      "prettier --write",
      "eslint --fix"
    ],
    "*.{css,less,scss}": "stylelint --fix"
  }
执行一次 yarn prepare ,自动生成 .husky 文件

3. 添加钩子

  • .husky/pre-commit
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"

# lint,检查 eslint、stylelint、ts
yarn lint
echo "---检查开始---"
yarn tsc
echo "---检查结束---"

# 邮箱的检查
# EMAIL=$(git config user.email)
# if [[ ! $EMAIL =~ ^[.[:alnum:]]+@qq\.com$ ]];
# then
#   echo "Your git information is not valid";
#   echo "Please run:"
#   echo '   git config --local user.name "<Your name in qq>"'
#   echo '   git config --local user.email "<Your alias>@qq.com"'
#   exit 1;
# fi;
  • .husky/commit-msg,检查提交信息
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"

npx --no-install commitlint --edit "$1"

4. 添加 commitlint.config.js 配置。使用默认的

module.exports = { extends: ['@commitlint/config-conventional'] }

5.测试,先把 yarn lint yarn tsc 屏蔽掉,然后随意提交代码,commit 信息随便写一个

image.png

添加 eslint、prettier

1. 安装依赖

因为是规范限制而已,建议安装我的指定版本,避免出现一些规则冲突的问题,避免踩坑,可以直接复制到package.json 中,再 yarn

"@typescript-eslint/eslint-plugin": "^6.13.1",
"@typescript-eslint/parser": "^6.13.1",
"eslint": "^8.54.0",
"eslint-config-prettier": "^9.0.0",
"eslint-define-config": "^2.0.0",
"eslint-plugin-import": "^2.29.0",
"eslint-plugin-prettier": "^4.2.1",
"eslint-plugin-simple-import-sort": "^10.0.0",
"prettier": "^2.7.1",

// vue 仅有
"eslint-plugin-vue": "^9.18.1",

// react 仅有
"eslint-plugin-react": "^7.32.2",

2. 添加配置文件 .eslintrc.js

vue 项目:

module.exports = {
  root: true,
  env: {
    browser: true,
    node: true,
    es6: true,
  },
  parser: "vue-eslint-parser",
  parserOptions: {
    parser: "@typescript-eslint/parser",
    ecmaVersion: 2020,
    sourceType: "module",
    jsxPragma: "React",
    ecmaFeatures: {
      jsx: true,
    },
    project: "./tsconfig.*?.json",
    createDefaultProgram: false,
    extraFileExtensions: [".vue"],
  },
  extends: [
    "plugin:vue/vue3-recommended",
    "plugin:@typescript-eslint/recommended",
    "plugin:prettier/recommended",
  ],
  plugins: [
    "vue",
    "@typescript-eslint",
    "import",
    "eslint-plugin-simple-import-sort", // 自动调整 import 顺序
  ],
  rules: {
    "prettier/prettier": "error",
    "simple-import-sort/imports": "error",
    "simple-import-sort/exports": "error",
    "no-multi-spaces": ["error", { ignoreEOLComments: true }],
    "no-unused-vars": "off",
    "no-case-declarations": "off",
    "no-use-before-define": "off",
    "space-before-function-paren": "off",
    "import/first": "error",
    "import/newline-after-import": "error",
    "import/no-duplicates": "error",
    "@typescript-eslint/no-unused-vars": [
      "error",
      {
        argsIgnorePattern: "^_",
        varsIgnorePattern: "^_",
      },
    ],
    "@typescript-eslint/ban-ts-ignore": "off",
    "@typescript-eslint/ban-ts-comment": "off",
    "@typescript-eslint/ban-types": "off",
    "@typescript-eslint/explicit-function-return-type": "off",
    "@typescript-eslint/no-var-requires": "off",
    "@typescript-eslint/no-empty-function": "off",
    "@typescript-eslint/no-use-before-define": "off",
    "@typescript-eslint/no-non-null-assertion": "off",
    "@typescript-eslint/explicit-module-boundary-types": "off",
    "vue/script-setup-uses-vars": "error",
    "vue/no-reserved-component-names": "off",
    "vue/custom-event-name-casing": "off",
    "vue/attributes-order": "off",
    "vue/one-component-per-file": "off",
    "vue/html-closing-bracket-newline": "off",
    "vue/max-attributes-per-line": "off",
    "vue/multiline-html-element-content-newline": "off",
    "vue/singleline-html-element-content-newline": "off",
    "vue/attribute-hyphenation": "off",
    "vue/require-default-prop": "off",
    "vue/require-explicit-emits": "off",
    "vue/html-self-closing": [
      "error",
      {
        html: {
          void: "always",
          normal: "never",
          component: "always",
        },
        svg: "always",
        math: "always",
      },
    ],
    "vue/multi-word-component-names": "off",
    "@typescript-eslint/no-explicit-any": ["error"], //禁止使用any
    eqeqeq: 2, //必须使用全等
    "max-lines": ["error", 1000], //限制行数 请勿修改 请优化你的代码
    complexity: ["error", 10], // 限制复杂度
    "require-await": "error",
  },
  globals: { defineOptions: "readonly" },
};

react 项目:

module.exports = {
  env: {
    browser: true,
    commonjs: true, // ADD, 支持对commonjs全局变量的识别
    es2021: true,
    node: true,
  },
  extends: [
    "eslint:recommended",
    "plugin:react/recommended",
    "plugin:@typescript-eslint/recommended",
    "plugin:import/recommended", // import 插件规则,可自动合并重复导入
  ],
  parser: "@typescript-eslint/parser",
  parserOptions: {
    ecmaFeatures: {
      jsx: true,
    },
    ecmaVersion: "latest",
  },
  plugins: ["react", "@typescript-eslint", "eslint-plugin-simple-import-sort"],
  rules: {
    "react/jsx-uses-react": "off", // 必须增加对import React from 'react',jsx 的页面已经不再需要引入 React了,所以我们去掉这条 lint 规则
    "react/react-in-jsx-scope": "off", // 同上
    "@typescript-eslint/no-var-requires": "off", // 关闭 禁用使用 require 来定义
    "react/display-name": "off", // 关闭组件定义缺少显示名称
    "simple-import-sort/imports": "error", // import 自动排序,eslint-plugin-simple-import-sort 自动修正
    "simple-import-sort/exports": "error",
    "no-duplicate-imports": ["off", { includeExports: true }], // import不能重复重复,自动合并插件 eslint-plugin-import,添加extends:plugin:import/recommended
    "import/no-unresolved": "off", // 关闭 eslint 无法解析的导入
  },
};

3. 添加文件 eslint 忽略文件 .eslintignore 文件

*.sh
node_modules
*.md
*.woff
*.ttf
.vscode
.idea
dist
/public
/docs
.husky
.local
/bin
Dockerfile
/types

4. 添加配置文件 .prettierrc.js 文件,vscode 记得设置默认的格式化程序为 prettier

module.exports = {
  singleQuote: false,
  trailingComma: 'all',
  printWidth: 80,
  htmlWhitespaceSensitivity: 'ignore',
  endOfLine: 'auto',
  vueIndentScriptAndStyle: false, // 关闭代码前面空一格
};

5. 添加文件 prettier 忽略文件 .prettierignore 文件

/dist/*
.local
.output.js
/node_modules/**

**/*.svg
**/*.sh

/public/*

至此,您保存文件的时候应该会自动修正 eslint,并且按照 prettier 格式保存 执行yarn lint 时会检测 暂存区文件的 eslint、stylelint

添加 stylelint

使用 less 的请安装

yarn add -D less less-loader

使用 scss 的请安装

yarn add -D sass sass-loader

1. 安装依赖

同样建议使用我踩过坑的版本

"stylelint": "^13.2.1",
"stylelint-config-clean-order": "^2.1.0",
"stylelint-config-prettier": "^8.0.1",
"stylelint-config-standard": "^20.0.0",
"stylelint-prettier": "^1.1.2",

2. 添加 stylelint.config.js 配置文件

module.exports = {
  processors: [],
  extends: [
    "stylelint-config-standard",
    "stylelint-prettier/recommended",
    "stylelint-config-prettier",
    "stylelint-config-clean-order",
  ],
  rules: {
    "prettier/prettier": true,
    "at-rule-no-unknown": null,
    "no-empty-source": null,
    "unit-no-unknown": null,
    "no-descending-specificity": null,
    "selector-pseudo-class-no-unknown": null,
    "declaration-block-no-duplicate-properties": null,
    "selector-type-no-unknown": null,
    "block-no-empty": null,
    "font-family-no-missing-generic-family-keyword": null,
    "declaration-block-no-shorthand-property-overrides": null,
  },
};

3. 添加 .stylelintignore 忽略文件

/dist/*
/public/*
public/*
*.js
*.ts
*.png
*.jpg
*.webp
*.ttf
*.woff

至此,当您保存有样式的文件的时候,会自动帮您格式化样式,在提交代码时会检查eslint、stylelint、commit信息了。

添加 tsc 的检查

前面在 pre-commit 已经设置了 tsc 检查,在代码提交时会自动全局检测,这个我暂时并不知道如何能够只检测暂存区的ts规范,现在做的是全局检测,这里是针对vue项目的。tsc 的检查一般用脚手架创建时就会生成。

1. 配置别名

vite.config.ts

import { fileURLToPath, URL } from "node:url"; // 如果报错请安装 @types/node

 resolve: {
    alias: {
      "@": fileURLToPath(new URL("./src", import.meta.url)),
      "#": fileURLToPath(new URL("./types", import.meta.url)),
    },
  },

2. 安装依赖

一般使用 cli 安装 ts 版本的这里无需安装,只需要修改配置文件

yarn add vue-tsc -D
yarn add @vue/cli-plugin-typescript -D

3. tsconfig.json 配置 vue:

{
  "compilerOptions": {
    "target": "esnext",
    "module": "esnext",
    "moduleResolution": "node",
    "useDefineForClassFields": true,
    "strict": true,
    "noLib": false,
    "forceConsistentCasingInFileNames": true,
    "allowSyntheticDefaultImports": true,
    "strictFunctionTypes": false,
    "jsx": "preserve",
    "baseUrl": ".",
    "allowJs": true,
    "sourceMap": true,
    "esModuleInterop": true,
    "resolveJsonModule": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "experimentalDecorators": true,
    "lib": ["dom", "esnext"],
    "noImplicitAny": false,
    "skipLibCheck": true,
    "types": [],
    "removeComments": true,
    "paths": {
      "@/*": ["src/*"],
      "/#/*": ["types/*"]
    }
  },
  // 针对 vue 跟 react 这里需要调整一下
  "include": [
    "src/**/*.ts",
    "src/**/*.d.ts",
    "src/**/*.tsx",
    "src/**/*.vue",
    "types/**/*.d.ts",
    "types/**/*.ts",
    "build/**/*.ts",
    "build/**/*.d.ts",
    "mock/**/*.ts",
    "vite.config.ts"
  ],
  "exclude": ["node_modules", "tests/server/**/*.ts", "dist", "**/*.js"]
}

react:

{
  "compilerOptions": {
    "target": "esnext",
    "module": "esnext",
    "moduleResolution": "node",
    "useDefineForClassFields": true,
    "strict": true,
    "noLib": false,
    "forceConsistentCasingInFileNames": true,
    "allowSyntheticDefaultImports": true,
    "strictFunctionTypes": false,
    "jsx": "preserve",
    "baseUrl": ".",
    "allowJs": true,
    "sourceMap": true,
    "esModuleInterop": true,
    "resolveJsonModule": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "experimentalDecorators": true,
    "lib": ["dom", "esnext"],
    "noImplicitAny": false,
    "skipLibCheck": true,
    "types": [],
    "removeComments": true,
    "paths": {
      "@/*": ["src/*"],
      "/#/*": ["types/*"]
    },
    "noEmit": true,
    "allowImportingTsExtensions": true
  },
  "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
  "exclude": ["node_modules"]
}

4. 添加 tsc 命令

package.json

"tsc": "vue-tsc --noEmit --skipLibCheck",

总结:现在我们已经做到在保存时自动 eslint 修正、prettier 格式化、stylelint 格式化 暂存区提交时检测 eslint、stylelint,全局检测ts规范。 项目地址