前端项目工程化之 vue 项目中添加 git hooks (优雅的 git commit 以及 eslint 和 stylelint 自动修复代码样式)

项目基本依赖:”vue-cli”:”3.5.3” “core-js”: “^2.6.5” “vue”: “^2.6.10” “babel-eslint”: “^10.0.1”
“eslint”: “^5.16.0”
“eslint-plugin-vue”: “^5.0.0”
编辑器:vscode

使用效果

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

使用步骤

注意:使用前确保 vue.config.js 里的 lintOnSave 已设置为 true

1.安装以下依赖

1
npm i -D @commitlint/cli@8.1.0 @commitlint/config-conventional@8.1.0 commitizen@4.0.3 cz-conventional-changelog@3.0.2 cz-customizable@6.2.0 husky@3.0.2 lint-staged@8.1.5

2.package.json 文件中添加以下配置

1
2
"scripts": {
3
  "serve": "vue-cli-service serve",
4
  "build": "vue-cli-service build",
5
  "lint": "vue-cli-service lint",
6
  "commit": "git-cz"
7
},
8
"husky": {
9
  "hooks": {
10
    "pre-commit": "lint-staged",
11
    "commit-msg": "commitlint -E HUSKY_GIT_PARAMS"
12
  }
13
},
14
"config": {
15
  "commitizen": {
16
    "path": "node_modules/cz-customizable"
17
  }
18
},
19
"lint-staged": {
20
  "src/**/*.{js,vue}": [
21
    "vue-cli-service lint",
22
    "git add"
23
  ]
24
},

上面 package.json 配置说明(不要复制下面 json,json 不支持注释)

1
2
"scripts": {
3
  "serve": "vue-cli-service serve",
4
  "build": "vue-cli-service build",
5
  "lint": "vue-cli-service lint",// vue-cli 自带的lint检查
6
  "commit": "git-cz"  // 提交命令
7
},
8
"husky": {
9
  "hooks": {
10
    "pre-commit": "lint-staged", //git commit 执行这个命令,这个命令再调起 lint-staged
11
    "commit-msg": "commitlint -E HUSKY_GIT_PARAMS" //提交检查
12
  }
13
},
14
"config": {
15
  "commitizen": {
16
    "path": "node_modules/cz-customizable"  //定制项目的提交说明
17
  }
18
},
19
"lint-staged": {
20
    // 检查文件
21
  "src/**/*.{js,vue}": [
22
23
    "vue-cli-service lint",// 提交之前检查并修复代码
24
25
    "git add"
26
  ]
27
},

3.在项目根目录下新建 commitlint.config.js 文件配置如下

1
module.exports = {
2
  extends: ["@commitlint/config-conventional"],
3
  rules: {
4
    // 提交主题类型
5
    "type-enum": [
6
      2,
7
      "always",
8
      [
9
        "feat",
10
        "perf",
11
        "fix",
12
        "docs",
13
        "style",
14
        "refactor",
15
        "test",
16
        "chore",
17
        "revert",
18
        "build",
19
        "ci"
20
      ] // 主题含义见 /.cz-config.js
21
    ],
22
    "subject-full-stop": [0, "never"], // 主题句号
23
    "subject-case": [0, "never"] // 主题案例
24
  }
25
};

4.在项目根目录下新建 .cz-config.js 文件配置如下(注意:不要省略文件名前的点 “ . “)

1
module.exports = {
2
  // 修改主题选择
3
  types: [
4
    { value: "build", name: "build:  构建打包" },
5
    { value: "feat", name: "feat:  添加新功能" },
6
    { value: "fix", name: "fix:  Bug修复" },
7
    {
8
      value: "docs",
9
      name: "docs:  变更的只有文档,比如README.md等"
10
    },
11
    {
12
      value: "style",
13
      name: "style:  空格, 分号等格式修复(注意不是 css 修改)"
14
    },
15
    { value: "ci", name: "ci   ci配置,脚本文件等更新" },
16
    {
17
      value: "refactor",
18
      name: "refactor:  代码重构(即不是新增功能,也不是修改bug的代码变动)"
19
    },
20
    { value: "test", name: "test:  添加一个测试,包括单元测试、集成测试等" },
21
    { value: "perf", name: "perf:  优化相关,比如提升性能、体验" },
22
    { value: "chore", name: "chore:  改变构建流程、或者增加依赖库、工具等" },
23
    { value: "revert", name: "revert:  代码回退" }
24
  ],
25
26
  // 修改文件范围选择
27
  // scopes: [
28
  //   { name: 'components' },
29
  //   { name: 'assets' },
30
  //   { name: 'views' },
31
  //   { name: 'api' },
32
  //   { name: 'utils' },
33
  //   { name: 'other' },
34
  // ],
35
36
  // 选择对应的主题后的选择
37
  // scopeOverrides: {
38
  //   fix: [
39
  //     { name: 'merge' },
40
  //     { name: 'style' },
41
  //     { name: 'e2eTest' },
42
  //     { name: 'unitTest' }
43
  //   ]
44
  // },
45
46
  // 构建对话
47
  messages: {
48
    type: "选择一种你的提交类型(必选):",
49
    scope: "选择一个更改范围(可选):",
50
    // used if allowCustomScopes is true
51
    customScope: "自定义更改范围(可选):",
52
    subject: "短说明(必填):\n",
53
    body: '长说明,使用"|"换行(可选):\n',
54
    breaking: "非兼容性说明 (可选):\n",
55
    footer: "关联关闭的issue,例如:#31, #34(可选):\n",
56
    confirmCommit: "确定提交说明?"
57
  },
58
  // 是否允许自定义更改范围
59
  allowCustomScopes: true,
60
  // 允许中断的改变
61
  allowBreakingChanges: ["feat", "fix"],
62
  // 修改主题描述字数限制
63
  subjectLimit: 100,
64
  // 选择跳过的步骤(不用填,不用选,直接跳过)
65
  skipQuestions: ["body", "breaking", "footer"]
66
};

5.在项目根目录下新建 .eslintrc.js 文件配置如下(自己可以参考官网修改)

eslint 中文网 http://eslint.cn/docs/rules/

eslint-config-vue 配置 https://github.com/vuejs/eslint-config-vue/blob/master/index.js

1
module.exports = {
2
  root: true,
3
  parserOptions: {
4
    parser: "babel-eslint",
5
    sourceType: "module"
6
  },
7
  env: {
8
    browser: true,
9
    node: true,
10
    es6: true
11
  },
12
  extends: ["plugin:vue/recommended", "eslint:recommended"],
13
14
  // add your custom rules here
15
  //it is base on https://github.com/vuejs/eslint-config-vue
16
  rules: {
17
    "vue/max-attributes-per-line": [
18
      2,
19
      {
20
        singleline: 10,
21
        multiline: {
22
          max: 1,
23
          allowFirstLine: false
24
        }
25
      }
26
    ],
27
    "vue/singleline-html-element-content-newline": "off",
28
    "vue/multiline-html-element-content-newline": "off",
29
    "vue/name-property-casing": ["error", "PascalCase"],
30
    "vue/no-v-html": "off",
31
    "accessor-pairs": 2,
32
    "vue/html-self-closing": "off",
33
    "arrow-spacing": [
34
      2,
35
      {
36
        before: true,
37
        after: true
38
      }
39
    ],
40
    "block-spacing": [2, "always"],
41
    "brace-style": [
42
      2,
43
      "1tbs",
44
      {
45
        allowSingleLine: true
46
      }
47
    ],
48
    camelcase: [
49
      0,
50
      {
51
        properties: "always"
52
      }
53
    ],
54
    "no-undef": 2,
55
    "no-undef-init": 2,
56
    "no-unreachable": 2,
57
    "no-unsafe-finally": 2,
58
    "no-unused-vars": [
59
      2,
60
      {
61
        vars: "all",
62
        args: "none"
63
      }
64
    ],
65
    quotes: [
66
      2,
67
      "single",
68
      {
69
        avoidEscape: true,
70
        allowTemplateLiterals: true
71
      }
72
    ],
73
    semi: [2, "never"],
74
    "semi-spacing": [
75
      2,
76
      {
77
        before: false,
78
        after: true
79
      }
80
    ],
81
    "space-before-blocks": [2, "always"],
82
83
    "spaced-comment": [
84
      2,
85
      "always",
86
      {
87
        markers: [
88
          "global",
89
          "globals",
90
          "eslint",
91
          "eslint-disable",
92
          "*package",
93
          "!",
94
          ","
95
        ]
96
      }
97
    ],
98
    "template-curly-spacing": [2, "never"],
99
100
    "no-debugger": process.env.NODE_ENV === "production" ? 2 : 0,
101
    "object-curly-spacing": [
102
      2,
103
      "always",
104
      {
105
        objectsInObjects: false
106
      }
107
    ],
108
    "array-bracket-spacing": [2, "never"]
109
  }
110
};

6.在项目根目录下新建 update.sh 文件配置如下

1
#!/usr/bin/env bash
2
3
success="更新成功"
4
fail="更新失败"
5
6
# 确保脚本抛出遇到的错误
7
set -e
8
9
# 参数检验
10
if [ $# -gt 0 ] ; then
11
    echo fail: $fail;
12
    exit 1
13
fi
14
15
git add .
16
npm  run commit
17
# 捕获异常
18
if  [ $? = 0 ] ; then
19
    git  push       # 确保执行过默认分支操作 git push -u origin master 或者 git push -u origin dev 等
20
    echo success:$success
21
else
22
    echo fail: $fail;
23
    exit 1
24
fi

6.使用

项目根目录下启动 git-bash (vscode 默认 bash 改成 git-bash)
运行以下命令,
对于可选的项目直接按 enter 键跳过

1
./update.sh

7.项目添加配置 Stylelint

公司项目使用的 scss ,下面以 scss 为例

a.安装以下包

stylelint: 必须安装

stylelint-config-standard: 是官方推荐的插件

stylelint-order: 是规范样式的顺序的

stylelint-scss:stylelint 的 SCSS 特定 linting 规则的集合

1
npm i stylelint stylelint-config-standard stylelint-order stylelint-scss -D

b. 在项目根目录下新建.stylelintrc 文件(或其他支持的文件格式)

更多配置请查看官网

1
{
2
  "defaultSeverity": "error",
3
  "extends": ["stylelint-config-standard"],
4
  "plugins": ["stylelint-scss", "stylelint-order"],
5
  "rules": {
6
    "order/order": [
7
      "declarations",
8
      "custom-properties",
9
      "dollar-variables",
10
      "rules",
11
      "at-rules"
12
    ],
13
    "order/properties-order": [
14
      "position",
15
      "top",
16
      "right",
17
      "bottom",
18
      "left",
19
      "float"
20
    ],
21
    "media-feature-name-no-vendor-prefix": true,
22
    "at-rule-no-vendor-prefix": true,
23
    "selector-no-vendor-prefix": true,
24
    "property-no-vendor-prefix": true,
25
    "value-no-vendor-prefix": true,
26
    "rule-empty-line-before": null,
27
    "no-missing-end-of-source-newline": null,
28
    "selector-pseudo-class-no-unknown": null,
29
    "font-family-no-missing-generic-family-keyword": null,
30
    "no-descending-specificity": null,
31
    "declaration-empty-line-before": null,
32
    "declaration-block-trailing-semicolon": null,
33
    "selector-combinator-space-before": null,
34
    "selector-combinator-space-after": null,
35
    "block-closing-brace-newline-before": null,
36
    "at-rule-no-unknown": null,
37
    "property-case": null,
38
    "property-no-unknown": null
39
  }
40
}

c. 在项目根目录下新建.stylelintignore 文件 (默认忽略 node_modules 文件夹)

1
*.min.css
2
3
# 其他类型文件
4
*.js
5
*.jpg
6
*.woff
7
8
# 测试和打包目录
9
/test/
10
/dist/

d.配置 package.json

“scripts” 字段下添加 stylelint 命令

1
{
2
  "scripts": {
3
    "serve": "vue-cli-service serve",
4
    "build": "vue-cli-service build",
5
    "dev": "vue-cli-service serve",
6
    "build:prod": "vue-cli-service build --mode production",
7
    "build:dev": "vue-cli-service build --mode dev",
8
    "changelog": "conventional-changelog -p angular -i CHANGELOG.md -w -r 0",
9
    "lint": "vue-cli-service lint",
10
    "stylelint": "stylelint **/*.{html,vue,css,sass,scss} --fix",
11
    "commit": "git-cz"
12
  }
13
}

“lint-staged” 字段改为如下

1
{
2
  "lint-staged": {
3
    "src/**/*.{js,vue}": ["npm run lint", "git add"],
4
    "**/*.{html,vue,css,sass,scss}": ["npm run stylelint", "git add"]
5
  }
6
}

e.使用,同上

运行

1
./update.sh

参考链接

1.https://github.com/okonet/lint-staged

2.https://github.com/typicode/husky

3.https://github.com/conventional-changelog/commitlint

4.https://blog.csdn.net/weixin_33890526/article/details/91393527

5.https://juejin.im/post/5afc5242f265da0b7f44bee4#heading-9

6.https://segmentfault.com/a/1190000009546913

7.https://juejin.im/post/5c31c9a16fb9a049f8197000