年前的最后一个礼拜,由于所负责项目的暂停版本排期,于是乎有几天的空闲的时间,就想着把项目的代码质量搞上去。背景是,半年前我开始负责这个项目的前端开发,发现当时代码质量不理想,就想着做一些事情,把之前的代码规范下,也为了后面自己开发更顺利。

  1. 代码质量-1
  2. 代码质量-2
  3. 代码质量-3

技术栈:

  • Vue 2.6.10
  • Vue-Router 3.0.6
  • Vuex 3.1.0·
  • @vue/cli-service 4.4.4
  • webpack 4.0.0

本文主要介绍,如何使用 ESLint + Prettier + Husky + Lint-staged 在开发过程中保证代码质量

1. ESLint

ESLint是一个可检查并修复JavaScript代码的工具

1.1 安装依赖

以下依赖会在项目创建阶段,自己选择安装

1
2
3
4
eslint
babel-eslint
eslint-plugin-vue
@vue/cli-plugin-eslint

1.2 配置ESLint

  • 添加 .eslintrc 到根目录
    eslint-config-vue
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    module.exports = {
    root: true,
    parserOptions: {
    parser: 'babel-eslint',
    sourceType: 'module'
    },
    env: {
    browser: true,
    node: true,
    es6: true,
    },
    extends: ['plugin:vue/recommended', 'eslint:recommended'],

    // add your custom rules here
    //it is base on https://github.com/vuejs/eslint-config-vue
    rules: {
    "vue/max-attributes-per-line": [2, {
    "singleline": 10,
    "multiline": {
    "max": 1,
    "allowFirstLine": false
    }
    }],
    "vue/singleline-html-element-content-newline": "off",
    "vue/multiline-html-element-content-newline":"off",
    "vue/name-property-casing": ["error", "PascalCase"],
    "vue/no-v-html": "off",
    'accessor-pairs': 2,
    'arrow-spacing': [2, {
    'before': true,
    'after': true
    }],
    'block-spacing': [2, 'always'],
    'brace-style': [2, '1tbs', {
    'allowSingleLine': true
    }],
    'camelcase': [0, {
    'properties': 'always'
    }],
    'comma-dangle': [2, 'never'],
    'comma-spacing': [2, {
    'before': false,
    'after': true
    }],
    'comma-style': [2, 'last'],
    'constructor-super': 2,
    'curly': [2, 'multi-line'],
    'dot-location': [2, 'property'],
    'eol-last': 2,
    'eqeqeq': ["error", "always", {"null": "ignore"}],
    'generator-star-spacing': [2, {
    'before': true,
    'after': true
    }],
    'handle-callback-err': [2, '^(err|error)$'],
    'indent': [2, 2, {
    'SwitchCase': 1
    }],
    'jsx-quotes': [2, 'prefer-single'],
    'key-spacing': [2, {
    'beforeColon': false,
    'afterColon': true
    }],
    'keyword-spacing': [2, {
    'before': true,
    'after': true
    }],
    'new-cap': [2, {
    'newIsCap': true,
    'capIsNew': false
    }],
    'new-parens': 2,
    'no-array-constructor': 2,
    'no-caller': 2,
    'no-console': 'off',
    'no-class-assign': 2,
    'no-cond-assign': 2,
    'no-const-assign': 2,
    'no-control-regex': 0,
    'no-delete-var': 2,
    'no-dupe-args': 2,
    'no-dupe-class-members': 2,
    'no-dupe-keys': 2,
    'no-duplicate-case': 2,
    'no-empty-character-class': 2,
    'no-empty-pattern': 2,
    'no-eval': 2,
    'no-ex-assign': 2,
    'no-extend-native': 2,
    'no-extra-bind': 2,
    'no-extra-boolean-cast': 2,
    'no-extra-parens': [2, 'functions'],
    'no-fallthrough': 2,
    'no-floating-decimal': 2,
    'no-func-assign': 2,
    'no-implied-eval': 2,
    'no-inner-declarations': [2, 'functions'],
    'no-invalid-regexp': 2,
    'no-irregular-whitespace': 2,
    'no-iterator': 2,
    'no-label-var': 2,
    'no-labels': [2, {
    'allowLoop': false,
    'allowSwitch': false
    }],
    'no-lone-blocks': 2,
    'no-mixed-spaces-and-tabs': 2,
    'no-multi-spaces': 2,
    'no-multi-str': 2,
    'no-multiple-empty-lines': [2, {
    'max': 1
    }],
    'no-native-reassign': 2,
    'no-negated-in-lhs': 2,
    'no-new-object': 2,
    'no-new-require': 2,
    'no-new-symbol': 2,
    'no-new-wrappers': 2,
    'no-obj-calls': 2,
    'no-octal': 2,
    'no-octal-escape': 2,
    'no-path-concat': 2,
    'no-proto': 2,
    'no-redeclare': 2,
    'no-regex-spaces': 2,
    'no-return-assign': [2, 'except-parens'],
    'no-self-assign': 2,
    'no-self-compare': 2,
    'no-sequences': 2,
    'no-shadow-restricted-names': 2,
    'no-spaced-func': 2,
    'no-sparse-arrays': 2,
    'no-this-before-super': 2,
    'no-throw-literal': 2,
    'no-trailing-spaces': 2,
    'no-undef': 2,
    'no-undef-init': 2,
    'no-unexpected-multiline': 2,
    'no-unmodified-loop-condition': 2,
    'no-unneeded-ternary': [2, {
    'defaultAssignment': false
    }],
    'no-unreachable': 2,
    'no-unsafe-finally': 2,
    'no-unused-vars': [2, {
    'vars': 'all',
    'args': 'none'
    }],
    'no-useless-call': 2,
    'no-useless-computed-key': 2,
    'no-useless-constructor': 2,
    'no-useless-escape': 0,
    'no-whitespace-before-property': 2,
    'no-with': 2,
    'one-var': [2, {
    'initialized': 'never'
    }],
    'operator-linebreak': [2, 'after', {
    'overrides': {
    '?': 'before',
    ':': 'before'
    }
    }],
    'padded-blocks': [2, 'never'],
    'quotes': [2, 'single', {
    'avoidEscape': true,
    'allowTemplateLiterals': true
    }],
    'semi': [2, 'always'],
    'semi-spacing': [2, {
    'before': false,
    'after': true
    }],
    'space-before-blocks': [2, 'always'],
    'space-before-function-paren': [2, 'never'],
    'space-in-parens': [2, 'never'],
    'space-infix-ops': 2,
    'space-unary-ops': [2, {
    'words': true,
    'nonwords': false
    }],
    'spaced-comment': [2, 'always', {
    'markers': ['global', 'globals', 'eslint', 'eslint-disable', '*package', '!', ',']
    }],
    'template-curly-spacing': [2, 'never'],
    'use-isnan': 2,
    'valid-typeof': 2,
    'wrap-iife': [2, 'any'],
    'yield-star-spacing': [2, 'both'],
    'yoda': [2, 'never'],
    'prefer-const': 2,
    'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0,
    'object-curly-spacing': [2, 'always', {
    objectsInObjects: false
    }],
    'array-bracket-spacing': [2, 'never']
    }
    }

    1.3 添加 .eslintignore 到根目录

    忽略 lint 的文件
    1
    2
    node_modules
    dist

2. Prettier

Prettier是一个代码格式化工具,可以让我们在开发过程中快速格式化代码。

2.1 安装Prettier

1
npm install --save-dev --save-exact prettier

2.2 生成一个空的配置文件

1
2
# 生成空的配置文件
echo {}> .prettierrc.json

2.3 创建一个 .prettierignore 文件

1
2
3
4
5
6
# Ignore artifacts:
build
coverage

# Ignore all HTML files:
*.html

3. Husky

Husky是一个 Git 的钩子,可以在我们进行 commit 或者 push 等操作时,运行一些其它命令(比如 npm run lint

3.1. 安装 Husky

1
npm npm install husky -D

3.2. 添加 scripts

1
2
3
4
5
6
7
8
9
# 1. 在 package.json 文件中添加 scripts 
"scripts": {
# ...
"prepare": "husky install"
# ...
}

# 2. 运行命令
npm run prepare

3.3. 添加 hook

注意:这里的 npm test 就是你最终要运行的钩子命令,一般就是 npm run lint ,新版本的 vue cli 使用的是 @vue/cli,对应的 lint 命令为 vue-cli-service lint,在执行前请运行 npx browserslist@latest --update-db 来更新 browserslist 配置。

1
2
npx husky add .husky/pre-commit "npm test" # npm test ==> npm run lint
git add .husky/pre-commit

3.4. 添加一个 commit

1
2
git commit -m "Keep calm and commit"
# `npm test` will run every time you commit

最终 husky 会在根目录下生成一个 .husky/ 文件夹,里面就是对应的配置

4. Lint-staged

Lint-staged可以让我们只校验添加到 git 暂存区中的代码,不会对当前项目所有代码进行Lint,节省了不少时间。

4.1. 安装 lint-staged

1
npx mrm@2 lint-staged

4.2. 运行完毕

  • 会在 .husky/pre-commit 文件中添加一行 npx lint-staged
  • 会在 package.json 文件中添加一行配置
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    // 这是默认配置
    "lint-staged": {
    "*.{js,vue}": "eslint --cache --fix",
    "*.{js,css,md}": "prettier --write"
    },

    // 建议改成
    "lint-staged": {
    "src/**/*.{js,vue}": [
    "npm run lint"
    ],
    "*.{js,css,md}": "prettier --write"
    },