Vite + Vitest の環境に husky を導入してみた

Vite + Vitest の環境に husky を導入する手順等についてハンズオン形式で実践して整理した際の記事です。
2024.04.30

はじめに

こんにちは。アノテーションの及川です。

前回ご紹介したこちらの記事の続きとして、Vite + Vitest の環境に husky を導入してみたので、その実施手順を整理しました。

husky の概要

  • Git フックを簡単に管理できる仕組み(ツール)
  • Git フックとは、git commitgit push などが発生したときに自動的に実行されるスクリプトのこと
  • husky を導入することで、ソースコードをコミットやプッシュする前に自動的にテストを実行する他、コードの内容が実行された際にエラーになりそうな部分を未然に指摘したり、ソースコードのインデントなどのフォーマットを整えたりすることが可能

想定される使用例(参考)

husky を使用するとコードの品質を保つため、下記のようなことが実現できます。

  1. 開発者がコードの変更をステージングし、コミットしようとする
  2. Husky がコミットする前に実行する pre-commit フックをトリガーして、lint-staged が実行される
  3. lint-staged がステージングされたファイルに対してリント(バグに繋がりやすい記述などの確認)やその他のチェックを行う
  4. すべてのチェックが通過(Pass)すれば、コミットは成功
  5. チェックに失敗するとコミットは中断され、開発者は問題を修正して再度コミットを行う(手順1.から実施)

husky 導入の補足

前述にもちらっと記載しましたが、husky の設定および検証を行う上で必要な、JavaScript(または、TypeScript) コードの構文エラーやスタイル違反を検出し、修正するための静的コード解析ツールである、ESLint と、コードのフォーマットを統一し、読みやすく整形するためのコードフォーマッターである Prettier を並行して設定します。

ESlint の設定

ESlint のインストール

下記コマンドで ESlint をインストールしてください。

% npm i -D eslint

ESlint 初期化

下記のように、ESlint の初期化を行ってください。

最後に "Successfully~" の文言が表示されれば OK です。

(例として、今回の検証では下記のように設定していいます。下記の例を参考にご自身の開発環境に合わせて設定をお試しください。)

% npx eslint --init
You can also run this command directly using 'npm init @eslint/config'.
? How would you like to use ESLint? …
  To check syntax only
❯ To check syntax and find problems
  To check syntax, find problems, and enforce code style

% npx eslint --init
You can also run this command directly using 'npm init @eslint/config'.
✔ How would you like to use ESLint? · problems
? What type of modules does your project use? …
❯ JavaScript modules (import/export)
  CommonJS (require/exports)
  None of these

% npx eslint --init
You can also run this command directly using 'npm init @eslint/config'.
✔ How would you like to use ESLint? · problems
✔ What type of modules does your project use? · esm
? Which framework does your project use? …
❯ React
  Vue.js
  None of these

% npx eslint --init
You can also run this command directly using 'npm init @eslint/config'.
✔ How would you like to use ESLint? · problems
✔ What type of modules does your project use? · esm
✔ Which framework does your project use? · react
? Does your project use TypeScript? …
  No
❯ Yes

% npx eslint --init
You can also run this command directly using 'npm init @eslint/config'.
✔ How would you like to use ESLint? · problems
✔ What type of modules does your project use? · esm
✔ Which framework does your project use? · react
✔ Does your project use TypeScript? · typescript
? Where does your code run? …  (Press <space> to select, <a> to toggle all, <i> to invert selection)
✔ Browser
  Node

% npx eslint --init
You can also run this command directly using 'npm init @eslint/config'.
✔ How would you like to use ESLint? · problems
✔ What type of modules does your project use? · esm
✔ Which framework does your project use? · react
✔ Does your project use TypeScript? · typescript
✔ Where does your code run? · browser
The config that you've selected requires the following dependencies:

eslint, globals, @eslint/js, typescript-eslint, eslint-plugin-react
? Would you like to install them now? › No / Yes

% npx eslint --init
You can also run this command directly using 'npm init @eslint/config'.
✔ How would you like to use ESLint? · problems
✔ What type of modules does your project use? · esm
✔ Which framework does your project use? · react
✔ Does your project use TypeScript? · typescript
✔ Where does your code run? · browser
The config that you've selected requires the following dependencies:

eslint, globals, @eslint/js, typescript-eslint, eslint-plugin-react
✔ Would you like to install them now? · No / Yes
? Which package manager do you want to use? …
❯ npm
  yarn
  pnpm
  bun

% npx eslint --init
You can also run this command directly using 'npm init @eslint/config'.
✔ How would you like to use ESLint? · problems
✔ What type of modules does your project use? · esm
✔ Which framework does your project use? · react
✔ Does your project use TypeScript? · typescript
✔ Where does your code run? · browser
The config that you've selected requires the following dependencies:

eslint, globals, @eslint/js, typescript-eslint, eslint-plugin-react
✔ Would you like to install them now? · No / Yes
✔ Which package manager do you want to use? · npm
☕️Installing...

added 61 packages, changed 10 packages, and audited 396 packages in 5s

141 packages are looking for funding
  run `npm fund` for details

found 0 vulnerabilities
Successfully created /Users/anote.taro/dev/Introduction-to-React-Testing-with-Vitest/vitest-setup-test/eslint.config.js file.

ESlint の公式ドキュメントにも使用方法について記載がされておりますので、適宜ご参照ください。

Prettier の設定

Prettier のインストール

下記コマンドで Prettier をインストールしてください。

% npm i -D prettier

Prettier 設定ファイルの作成

prettier.config.js ファイルを作成してください。

% touch prettier.config.js

作成したら、お好みで下記のような設定ファイルを作成してください。

/** @type {import("prettier").Config} */
const config = {
  trailingComma: 'es5',
  tabWidth: 2,
  semi: false,
  singleQuote: true,
}

export default config

下記、Prettier 公式ドキュメントにも記載例があるので、参考情報として適宜ご参照ください。

Git の設定

プロジェクト配下で git が初期化されていなければ後述の設定を行ってください。

GitHub (リモート)リポジトリの作成

詳細な手順は本記事では割愛致しますが、下記の公式ドキュメントなどを参考に作成してください。

ローカル環境の Git の初期化設定

下記のコマンド例や公式ドキュメントを参考に、ローカル環境にて Git の初期化を実施してください。

% git init
% git branch -M main
% git remote add origin git@github.com:<user名>/<リポジトリ名>.git # 前述の GitHub リポジトリ名を参照して入力してください。
% git remote -v # (任意) push or pull する GitHub リモートリポジトリが設定されているかを確認できます。

husky の設定

husky のインストール

下記のコマンドで、husky をインストールします。

% npm i -D husky

husky の初期化

下記のコマンドで、husky を初期化します。

% npx husky init

lint-staged のインストール

git commitgit push を実行する前に ESlint や Prettier を実行するために必要な lint-staged をインストールします。

% npm i -D lint-staged

packgae.json の編集

lint-staged の設定を加えます。

また、プッシュ前(pre-push)に テストを実行させたいので scripts を下記のように変更します。

"scripts": {
  "test": "vitest --run"
},
"lint-staged": {
  "*.{js,jsx,ts,tsx}": [
    "eslint --fix",
    "prettier --write"
  ]
}

pre-commit の編集

pre-commit ファイルに下記を追記してください。

npx lint-staged

pre-push の作成

% touch .husky/pre-push で pre-push ファイルを作成して下記を追記してください。

npm run test

husky の実行テスト

適当にファイルを編集する

husky の動作確認を行うため、前回のブログで検証用に作成した下記ファイルを一部変更します。

  • src/components/Input/TextInput.test.tsx
import React from 'react'
import { render, screen } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import TextInput from './TextInput'

~~ 中略 ~~

test('TextInput Event Test 2', async () => { //  'TextInput Event Test 1' → 'TextInput Event Test 2' に変更

~~ 後略 ~~~

git commit コマンドまで実施してみる

git commit まで実施してみると、husky(lint-staged)が正常に動作していることが確認できました。

% git add .
% git commit -m "テストタイトルを1から2に修正"
✔ Preparing lint-staged...
✔ Running tasks for staged files...
✔ Applying modifications from tasks...
✔ Cleaning up temporary files...
[main 65bacbf] テストタイトルを1から2に修正
 1 file changed, 1 insertion(+), 1 deletion(-)

git push コマンドで GitHub リポジトリに変更内容をプッシュする

git push コマンドを実行すると、Vitest のテストが実行されていることも確認することができます。

% git push origin main

> vitest-setup-test@0.0.0 test
> vitest --run

 RUN  v1.4.0 /Users/anote.taro/dev/Introduction-to-React-Testing-with-Vitest/vitest-setup-test

 ✓ src/components/Input/TextInput.test.tsx (2)
   ✓ TextInput Component test
   ✓ TextInput Event Test 4

 Test Files  1 passed (1)
      Tests  2 passed (2)
   Start at  20:39:30
   Duration  586ms (transform 149ms, setup 131ms, collect 173ms, tests 45ms, environment 95ms, prepare 50ms)

Enumerating objects: 11, done.
Counting objects: 100% (11/11), done.
Delta compression using up to 8 threads
Compressing objects: 100% (6/6), done.
Writing objects: 100% (6/6), 551 bytes | 551.00 KiB/s, done.
Total 6 (delta 3), reused 0 (delta 0), pack-reused 0
remote: Resolving deltas: 100% (3/3), completed with 3 local objects.
To github.com:<user名>/<リポジトリ名>.git
   a613e55..65bacbf  main -> main

まとめ

Vite + Vitest の環境に husky を導入するまでのハンズオンの過程を記載しました。

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

アノテーション株式会社について

アノテーション株式会社はクラスメソッドグループのオペレーション専門特化企業です。サポート・運用・開発保守・情シス・バックオフィスの専門チームが、最新 IT テクノロジー、高い技術力、蓄積されたノウハウをフル活用し、お客様の課題解決を行っています。当社は様々な職種でメンバーを募集しています。「オペレーション・エクセレンス」と「らしく働く、らしく生きる」を共に実現するカルチャー・しくみ・働き方にご興味がある方は、アノテーション株式会社 採用サイトをぜひご覧ください。

参考資料