使用 husky、commitlint 和 lint-staged 來構建你的前端工做流(vue、react、dva)

引言

發現每次 commit 的時候老是提交完了才發現少了一個分號,或者多了一個 console.log,想起之前看過的項目裏使用了 husky 這個庫,能夠在 commit 以前作代碼校驗,若是代碼有格式問題,就會禁止提交。css

做用

在咱們提交代碼時,先自動幫咱們格式化代碼,而後使用eslint檢查代碼,並自動修復錯誤,在修復不了的時候,報錯給咱們。而且報錯後這次的commit不會提交。前端

關於 commitlint, husky, eslint 的具體信息能夠見官網。

工具

  1. prettier。 一個很流行的代碼格式化工具,你很容易在編輯器找到實現它的各類插件,像vscode,atom,webstom均可以找到。這裏用它在代碼提交前作代碼格式化。
  2. eslint。 代碼檢查工具。eslint也能夠負責一部分代碼格式檢查的工做,可是prettier已經作的很好了,因此我便沒用eslint的代碼格式檢查,只讓其負責代碼錯誤檢查。
  3. lint-staged。在你提交的文件中,執行自定義的指令。don’t let 💩 slip into your codebase. — lint-staged

安裝

安裝eslint

npm i -D eslint babel-eslint eslint-config-airbnb eslint-plugin-import eslint-plugin-jsx-a11y eslint-plugin-react
複製代碼

安裝prettier

npm install --save-dev prettier eslint-plugin-prettier eslint-config-prettier複製代碼

安裝 husky 和 lint-stage

yarn add husky@next  # 安裝最新版,就不用配置 scripts 腳本了
yarn add lint-stage複製代碼

配置

配置 commitlint

commitlint 搭配 husky 的 commit message 鉤子後,每次提交 git 版本信息的時候,會根據配置的規則進行校驗,若不符合規則會 commit 失敗,並提示相應信息。vue

安裝 commitlint 依賴

yarn add @commitlint/{cli,config-conventional}複製代碼

新建 commitlint.config.js 文件

module.exports = {
    extends: ['@commitlint/config-conventional']
};複製代碼

commitlint.config.js 配置文件能夠添加本身的規則,這裏 @commitlint/config-conventional 提供了官方的規則擴展:

build:主要目的是修改項目構建系統(例如 glup,webpack,rollup 的配置等)的提交
ci:主要目的是修改項目繼續集成流程(例如 Travis,Jenkins,GitLab CI,Circle等)的提交
docs:文檔更新
feat:新增功能
merge:分支合併 Merge branch ? of ?
fix:bug 修復
perf:性能, 體驗優化
refactor:重構代碼(既沒有新增功能,也沒有修復 bug)
style:不影響程序邏輯的代碼修改(修改空白字符,格式縮進,補全缺失的分號等,沒有改變代碼邏輯)
test:新增測試用例或是更新現有測試
revert:回滾某個更早以前的提交
chore:不屬於以上類型的其餘類型複製代碼

配置 package.json 文件

添加 husky 字段node

"husky": {
    "hooks": {
      "commit-msg": "commitlint -e $HUSKY_GIT_PARAMS"
    }
  },複製代碼

測試react

git add .
git commit -m "foo: this will fail"複製代碼

image.png

prettier配置

  1. prettier 代碼格式化核心
  2. eslint-plugin-prettier 插件,可讓eslint使用prettier規則進行檢查,並使用--fix選項。像以前的格式不對時,eslint提示的紅線。
  3. eslint-config-prettier 插件,以前說了eslint也會檢查代碼的格式,這個插件就是關閉全部沒必要要或可能跟prettier產生衝突的規則。

eslintrc.json添加以下配置:webpack

{
 "extends": ["airbnb", "plugin:prettier/recommended"],
}複製代碼

這個配置作以下三件事:git

  1. 使eslint-plugin-prettier生效
  2. 不符合prettier/prettier的規則,會報錯。就是以前截圖中的紅線。
  3. 使eslint-config-prettier生效。就是會覆蓋eslint中與prettier衝突的配置。

prettier配置文件

prittier配置文件支持不少種,具體能夠看這裏。我使用的是.prettierrrc格式,由於試過其餘格式,可是隻有.prettierrrc,vscode才能夠識別。 生成配置能夠直接用官網上的try it out,左下角有導出配置。下面這份配置基本上是風格要求的所有了,具體可按照我的愛好進行配置。es6

{
  "printWidth": 120, // 一行最大多少字符
  "tabWidth": 2, // tab佔用的字符數
  "useTabs": false, // 是否使用tab代替空格
  "semi": true, // 是否每句後都加分號
  "singleQuote": true, // 是否使用單引號
  "jsxSingleQuote": false, // jsx是否使用單引號
  "trailingComma": "all", // 數組尾逗號。
  "bracketSpacing": false, // {foo: xx}仍是{ foo: xx }
  "jsxBracketSameLine": false, //看官網
  "arrowParens": "always" //剪頭函數參數是否使用()
}複製代碼

配置eslint鉤子

.eslintrc.js

*vue開啓eslint基本上不用配置,react能夠配置本身的github

module.exports = {
  parser: 'babel-eslint',
  plugins: ['react'],
  root: true,
  env: {
    browser: true,
    node: true,
    es6: true
  },
  parserOptions: {
    ecmaVersion: 6,
    sourceType: 'module'
  },
  globals: {
    document: true,
    localStorage: true,
    window: true,
    process: true,
    console: true,
    navigator: true,
    fetch: true,
    URL: true
  },
  rules: {
    'no-console': 'off',
    'no-alert': 0, //禁止使用alert confirm prompt
    'no-var': 0, //禁用var,用let和const代替
    'no-catch-shadow': 2, //禁止catch子句參數與外部做用域變量同名
    'default-case': 2, //switch語句最後必須有default
    'dot-notation': [0, { allowKeywords: true }], //避免沒必要要的方括號
    'no-constant-condition': 2, //禁止在條件中使用常量表達式 if(true) if(1)
    'no-dupe-args': 2, //函數參數不能重複
    'no-inline-comments': 0, //禁止行內備註
    'no-unreachable': 2, //不能有沒法執行的代碼
    'no-unused-vars': [2, { vars: 'all', args: 'after-used' }], //不能有聲明後未被使用的變量或參數
    'no-unused-expressions': 2, //禁止無用的表達式 | 短路求值和三目運算都容許 0 | 2 都不容許
    // 'no-unused-expressions': [
    //   2,
    //   { allowShortCircuit: false, allowTernary: true },
    // ], // 容許三目,不容許短路:
    'no-mixed-spaces-and-tabs': [2, false], //禁止混用tab和空格
    'linebreak-style': [0, 'windows'], //換行風格
    'no-multiple-empty-lines': [1, { max: 2 }], //空行最多不能超過2行
    'no-extra-semi': 2, //禁止多餘的冒號
    'no-debugger': 2, //禁止使用debugger
    // 'space-before-function-paren': [2, { anonymous: 'never', named: 'never' }], // 函數名後面加空格
    // 'space-before-function-paren': ['error', 'always'],
    // or
    'space-before-function-paren': [
      'error',
      {
        anonymous: 'always',
        named: 'always',
        asyncArrow: 'always'
      }
    ],
    'eol-last': 0, //文件以單一的換行符結束
    // eqeqeq: true, //必須使用全等 若是是true,則要求在全部的比較時使用===和!==
    // eqnull: true, // 若是是true,則容許使用== null
    'lines-around-comment': 0, //行前/行後備注
    'operator-linebreak': [2, 'after'], //換行時運算符在行尾仍是行首
    'prefer-const': 0, //首選const
    quotes: [1, 'single'], //引號類型 `` "" ''
    'id-match': 0, //命名檢測
    'array-bracket-spacing': [2, 'always'], // 指定數組的元素之間要以空格隔開(,後面), never參數:[ 以前和 ] 以後不能帶空格,always參數:[ 以前和 ] 以後必須帶空格
    quotes: [2, 'single'], // 所有單引號
    // 數組和對象鍵值對最後一個逗號, never參數:不能帶末尾的逗號, always參數:必須帶末尾的逗號,
    // always-multiline:多行模式必須帶逗號,單行模式不能帶逗號
    'comma-dangle': [2, 'never'],
    'computed-property-spacing': [2, 'never'], // 以方括號取對象屬性時,[ 後面和 ] 前面是否須要空格, 可選參數 never, always
    semi: [2, 'never'], //語句強制分號結尾  不要分號
    'eol-last': 2, // 文件末尾強制換行
    'semi-spacing': [0, { before: false, after: true }], //分號先後空格
    'arrow-body-style': 0, // 不由止箭頭函數直接return對象
    strict: 2, //使用嚴格模式
    'use-isnan': 2, //禁止比較時使用NaN,只能用isNaN()
    'valid-typeof': 2, //必須使用合法的typeof的值
    'space-in-parens': [0, 'always'],
    'template-curly-spacing': [2, 'always'],
    'array-bracket-spacing': [2, 'always'],
    'object-curly-spacing': [2, 'always'],
    'computed-property-spacing': [2, 'always'],
    'no-multiple-empty-lines': [2, { max: 1, maxEOF: 0, maxBOF: 0 }],
    quotes: [1, 'single', 'avoid-escape'],
    'no-use-before-define': [2, { functions: false }],
    semi: [0, 'never'],
    'prefer-const': 1,
    'react/prefer-es6-class': 0,
    'react/jsx-filename-extension': 0,
    'react/jsx-curly-spacing': [2, 'always'],
    'react/jsx-indent': [2, 2],
    'react/prop-types': [1],
    'react/no-array-index-key': [1],
    'class-methods-use-this': 'off',
    'no-undef': [1],
    'no-case-declarations': [1],
    'no-return-assign': [1],
    'no-param-reassign': [1],
    'no-shadow': [1],
    camelcase: [1],
    'no-unused-vars': 'off',
    'no-underscore-dangle': [0, 'always']
  }
}
複製代碼

husky鉤子pre-commit配置

react配置package.json

"husky": {
    "hooks": {
      "commit-msg": "commitlint -e $HUSKY_GIT_PARAMS",
      "pre-commit": "lint-staged", // pre-commit,提交前的鉤子
      "pre-add": "lint-staged",
      "pre-push": "lint-staged"
    }
  },
  "lint-staged": {
    // 此處能夠配置文件夾和文件類型的範圍
    "src/**/*.{jsx,txs,ts,js,json,css,md}": [
      "prettier --write", // 先使用prettier進行格式化
      "eslint --fix", // 再使用eslint進行自動修復
      "git add" // 全部經過的話執行git
    ]
  }複製代碼

vue配置package.json

"gitHooks": {
    "commit-msg": "commitlint -e $HUSKY_GIT_PARAMS",
    "pre-commit": "lint-staged"
  },
  "lint-staged": {
    "*.js": [
      "vue-cli-service lint",
      "git add"
    ],
    "*.vue": [
      "vue-cli-service lint",
      "git add"
    ]
  }複製代碼

husky會在你提交前,調用pre-commit鉤子,執行lint-staged,若是代碼不符合prettier配置的規則,會進行格式化;而後再用eslint的規則進行檢查,若是有不符合規則且沒法自動修復的,就會中止這次提交。若是都經過了就會講代碼添加到stage,而後commitweb

*若是想跳過校驗

使用 --no-verify 指令能夠跳過檢驗規則

git add . && git commit --no-verify -m "代碼規範強制提交測試"複製代碼

補充說明

關於前端工程打包對每個開發人員都不可避免,發佈線上頻繁的build,是很浪費時間的,那麼如何避免重複的操做?

其實gitHooks也能夠幫咱們作到好比咱們作以下配置:

"gitHooks": {
    ......,
    "pre-push": "yarn run build && git add . && git commit -am 'prod build'"
  },
  "lint-staged": {......}複製代碼

這樣就完美解決了咱們的顧慮,固然此方法也存在必定的缺陷。例如:

  1. 多人開發須要處理每次build帶來的衝突;
  2. 每次push都會伴隨一次build產生;
  3. 發佈上線發現靜態資源不是最新的(解決這一類問題有不少辦法,好比出一個公共接口每次發佈上線手動刷新咱們的靜態資源等等。)

針對build工程發佈上線本節咱們簡單介紹一下,後續會爲你們詳細普及,敬請關注哦!

總結

有人說前端攻城獅是世界上最奇怪的動物,提交代碼時用 prettier 把代碼排版的很美觀,但部署上線時又使用 uglify 把代碼壓縮的連親媽都不認了,事實是,若是咱們寫出來的代碼原本就很醜陋,就根本不須要用 uglify。但願讀到這裏的你能把 Lint 工做流打磨到極致,把更多時間專一在解決真正的問題上,成爲真正高效的工程師

相關文章
相關標籤/搜索