git hookを使ってVue.jsプロジェクトをコミット前にLintする

2020.02.01

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

はじめに

こんにちは!馬場@岡山オフィスです。

最近、業務でVue.jsに触れる機会に恵まれTypeScriptとあわせて鋭意勉強中です。

Linterに怒られながら構文とともにお作法的なものも身につけたいと思いeslintを導入していますが、今回はより効率よく作業するためにコミット前に自動でLintする設定を入れていきたいと思います。

Vueプロジェクトの作成

Vue CLI v4.1.2
? Please pick a preset: Manually select features
? Check the features needed for your project: Babel, TS, Router, Vuex, Linter
? Use class-style component syntax? No
? Use Babel alongside TypeScript (required for modern mode, auto-detected polyfills, transpiling JSX)? Yes
? Use history mode for router? (Requires proper server setup for index fallback in production) Yes
? Pick a linter / formatter config: Airbnb
? Pick additional lint features: (Press <space> to select, <a> to toggle all, <i> to invert selection)Lint on save
? Where do you prefer placing config for Babel, ESLint, etc.? In dedicated config files
? Save this as a preset for future projects? No

Pick additional lint featuresではLint and fix on commitのチェックを外します。チェックするとpre-commit hookでyorkieが使われる設定になりますが、メンテナンスが止まっているため派生元であるhuskyを使用します。

huskyのインストール

huskyをインストールしてpackage.jsonに設定を追加します。今回はhooksにpre-commitの設定のみ追加しましたが、"pre-push": "npm test"を追加してプッシュ前にテストを実行するなど様々なgit hookを簡単に使うことができます。

yarn add -D husky

package.json

{
  "name": "test",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "serve": "vue-cli-service serve",
    "build": "vue-cli-service build",
    "lint": "vue-cli-service lint"
  },
  "husky": {
    "hooks": {
      "pre-commit": "vue-cli-service lint && git add ."
    }
  },
  "dependencies": {
    "core-js": "^3.4.4",
    "vue": "^2.6.10",
    "vue-router": "^3.1.3",
    "vuex": "^3.1.2"
  },
  "devDependencies": {
    "@vue/cli-plugin-babel": "^4.1.0",
    "@vue/cli-plugin-eslint": "^4.1.0",
    "@vue/cli-plugin-router": "^4.1.0",
    "@vue/cli-plugin-typescript": "^4.1.0",
    "@vue/cli-plugin-vuex": "^4.1.0",
    "@vue/cli-service": "^4.1.0",
    "@vue/eslint-config-airbnb": "^4.0.0",
    "@vue/eslint-config-typescript": "^4.0.0",
    "eslint": "^5.16.0",
    "eslint-plugin-vue": "^5.0.0",
    "husky": "^4.2.1",
    "typescript": "~3.5.3",
    "vue-template-compiler": "^2.6.10"
  }
}

eslintでエラーがでている状態でコミットしてみます。

$ git commit -am"husky hook test"                                                                                                                                                  
husky > pre-commit (node v12.14.1)
The following files have been auto-fixed:

  src/components/HelloWorld.vue

自動で修正されます。次に自動修正できないエラーを含んでいる場合にどうなるか試してみます。

$ git commit -am"husky hook test"                                                                                                                                                 
husky > pre-commit (node v12.14.1)
error: Parsing error: ',' expected at src/components/HelloWorld.vue:43:1:
  41 |   props: {
  42 |     msg: String,
> 43 | });
     | ^
  44 | </script>
  45 |
  46 | <!-- Add "scoped" attribute to limit CSS to this component only -->


1 error found.
husky > pre-commit hook failed (add --no-verify to bypass)

エラーメッセージが表示されコミットが中止されました。よさそうです?

lint-stagedのインストール

lint-stagedはステージングされているファイルに対して様々なオプションを指定してLintを実行できるnpmパッケージです。Vue CLIのドキュメントでもyorkieが実行するスクリプトとしてlint-stagedが使用されています。

yarn add -D lint-staged

package.json

{
  "name": "test",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "serve": "vue-cli-service serve",
    "build": "vue-cli-service build",
    "lint": "vue-cli-service lint"
  },
  "husky": {
    "hooks": {
      "pre-commit": "lint-staged"
    }
  },
  "lint-staged": {
    "*.{ts,vue}": [
      "vue-cli-service lint",
      "git add"
    ]
  },
  "dependencies": {
    "core-js": "^3.4.4",
    "vue": "^2.6.10",
    "vue-router": "^3.1.3",
    "vuex": "^3.1.2"
  },
  "devDependencies": {
    "@vue/cli-plugin-babel": "^4.1.0",
    "@vue/cli-plugin-eslint": "^4.1.0",
    "@vue/cli-plugin-router": "^4.1.0",
    "@vue/cli-plugin-typescript": "^4.1.0",
    "@vue/cli-plugin-vuex": "^4.1.0",
    "@vue/cli-service": "^4.1.0",
    "@vue/eslint-config-airbnb": "^4.0.0",
    "@vue/eslint-config-typescript": "^4.0.0",
    "eslint": "^5.16.0",
    "eslint-plugin-vue": "^5.0.0",
    "husky": "^4.2.1",
    "lint-staged": "^10.0.7",
    "typescript": "~3.5.3",
    "vue-template-compiler": "^2.6.10"
  }
}

lint-stagedのオプションにtsファイルとvueファイルを対象にするオプションを設定しました。さっそく試してみます。

$ git commit -am"lint-staged hook test"                                                                                                                                            
husky > pre-commit (node v12.14.1)
⚠ Some of your tasks use `git add` command. Please remove it from the config since all modifications made by tasks will be automatically added to the git commit index.

  ✔ Preparing...
  ✔ Running tasks...
  ✔ Applying modifications...
  ✔ Cleaning up...
[master 374768c] lint-staged hook test
 1 file changed, 1 insertion(+), 1 deletion(-)

よさそうです。ただgit add commandは不要だから取り除いてねと警告がでています。親切ですね。取り除きましょう。

"lint-staged": {
    "*.{ts,vue}": [
      "vue-cli-service lint"
    ]
  },
}

もう一度やってみます。

$ git commit -am"lint-staged hook test"                                                                                                                                    
husky > pre-commit (node v12.14.1)
  ✔ Preparing...
  ✔ Running tasks...
  ✔ Applying modifications...
  ✔ Cleaning up...
[master 932e45a] lint-staged hook test
 1 file changed, 1 insertion(+), 1 deletion(-)

うまくいきました!警告も消えています? 自動修復できないエラーがある場合も試してみます。

$ git commit -am"lint-staged hook test"                                                                                                                                        
husky > pre-commit (node v12.14.1)
  ✔ Preparing...
  ❯ Running tasks...
    ❯ Running tasks for *.{ts,vue}
      ✖ vue-cli-service lint
  ↓ Applying modifications... [skipped]
    → Skipped because of errors from tasks.
  ✔ Reverting to original state...
  ✔ Cleaning up...



✖ vue-cli-service found some errors. Please fix them and try committing again.
error: Parsing error: ',' expected at src/components/HelloWorld.vue:44:1:
42 |     msg: String,
43 |
> 44 | });
   | ^
45 | </script>
46 |
47 | <!-- Add "scoped" attribute to limit CSS to this component only -->


1 error found.
husky > pre-commit hook failed (add --no-verify to bypass)

よさそう!

おわりに

初歩的なことですが長い記事になってしまいました。まとめてみると簡単な手順なのですが、実際にやってみるといくつか躓いたところがあり意外に時間がかかりました。

この記事がどなたかのお役に立てば幸いです。