【他のSPAでも】Vue3でアプリ作るならこれを入れろ！2023 ver【使えるよ】

# はじめに

僕は仕事でもプライベートでもVueを一番触っています。フロントエンドの経験が無いときに「何かWebアプリ作ってみるか」と思い立って最初に手をつけたのがVueで、それ以来気に入って使っています。

Vueに限らず、フロントエンド（特にSPA界隈）の技術の発展は凄まじく、便利なツール・ライブラリで溢れています。今回は、「もしこれからVueで何かを作ろう」と思っている人向けに、 **とりあえずこれを入れておけばいいよ** 、というツールチェインを紹介したいと思います。

:::note
あくまで筆者が触ってみたことがあるものから選択しています。フロントエンドは技術の陳腐化も早いのでその点ご承知ください。
:::

# 前提

## Vueのバージョンは3系

さすがに今は3系の時代です。
Vueでわからないことをググると未だに2系の情報が出てきてしまうのがVueの辛いところですが、Composition APIの書き味が素晴らしいので3系一択です。（~~Options API？そんな書き方ありましたね~~）

## TypeScript

JavaScriptに慣れた状態でTypeScriptを書き始めると「一生TSC（コンパイラ）に怒られるしやってらんねー！」となりますが、動かしてからコケるよりも書いているときにコケる方がマシです。ちゃんと`<script setup lang="ts">`で書きましょう。

# 開発環境系

## Vite

https://ja.vitejs.dev/

言わずとしれた超高速ビルドツールです。Vueに限らず様々なフレームワークに対応しています。

:::note info
読み方は「ヴィート」のようです（「バイト」ではない）
:::
開発時はHMRに対応しているため、ソースコードを編集すると即座に反映されるのが気持ちいいです。もうやめられません。

従来はVueのプロジェクトを作成するときはVue CLIというツールがメジャーでしたが、Viteが登場してからはこっちが普及したため、Vue CLIはメンテナンスモードになってしまいました。

https://github.com/vuejs/vue-cli

一方、create-vueという公式ツールが登場しました。こちらはViteをベースにしており、よりVueプロジェクトに適したテンプレートでプロジェクトを作成してくれます。そのため、今後Vue開発を始める際はこちらの **create-vueを使用することを強く推奨** します。

https://github.com/vuejs/create-vue

:::note
このページで紹介するツールのいくつかは、このcreate-vueで作成するときに質問形式で選択することでインストールできます。（下記参照）
- ESLint
- Prettier
- Vue Router
- Pinia
- Vitest
:::


## ESLint

https://eslint.org/

ソースコードに対する構文解析を行ってくれるツールです。

プログラミングを始めた当初はこういった品質向上系のツールの必要性がいまいち感じられませんでしたが、潜在的なバグを防いだり、コードの可読性を高めたりする上で非常に強力なので、今では必須ツールです。

ESLint自体はJavascriptに対する解析ツールなので、例えばTypeScriptの構文やVueの構文に対応しようと思うとそれらに対応したルールを入れる必要があります。このあたりはViteやcreate-vueでよしなにやってくれるのでそれに任せましょう。（もちろん、自分でカスタマイズもできます）

基本的にはコマンドを打つことで指摘事項の一覧化ができますし、物によってはESLintが自動で直してくれるものもあります。VSCodeやWebStormなどのIDEの機能を使ってコーディングの段階で指摘・修正をしておくことがよいでしょう。
また、後述のツールを使ってGitコミット時に自動化したり、CIパイプラインに組み込んでおくことを推奨します。

## Prettier

https://prettier.io/

フォーマッティングを行ってくれるツールです。
最初はESLintとは何が違うんだ？と思っていましたが、こちらはあくまで見た目を綺麗にすることが目的です。

これも使うまでは必要性が感じられませんでしたが、
- 改行の位置
- 演算子前後のスペース
- カンマの自動挿入

などなどが自動で行われるのを体験して、めでたく必須ツールの仲間入りをしました。

可読性ももちろんのこと、複数人で開発するときにGitの差分が生まれにくいのも大きなメリットです。
フォーマットのルールを設定ファイルとして定義できるので、それもGit管理下にしておけば、チーム全体でコーディングルールを統一できます。

## simple-git-hooks

https://github.com/toplenboren/simple-git-hooks

Git hooksに応じてスクリプトを実行することができるようになります。

https://git-scm.com/book/ja/v2/Git-%E3%81%AE%E3%82%AB%E3%82%B9%E3%82%BF%E3%83%9E%E3%82%A4%E3%82%BA-Git-%E3%83%95%E3%83%83%E3%82%AF

導入のメリットとしては、Gitコミット時に前述のESLintやPrettierによる指摘・フォーマットを自動化できるところになります。コマンドを手打ちするのってどうしても億劫だし忘れがちになるので。自動化バンザイ！

## lint-staged

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

Gitのステージング対象のファイルに対して任意のコマンドを実行できるようになります。

前述のsimple-git-hooksと何が違うんだ、という話ですが、simple-git-hooksはあくまでGitのコミット時やプッシュ時というタイミングに応じて発火するだけであり、コマンドの対象ファイルを絞るのはまた別の話です。例えばフォーマットに関して言えば、「変更対象のファイルにのみ」実行したいとなると、「変更対象のファイル」を抜き出す必要があります。lint-stagedを使用すると、不要なファイルに対してコマンドを実行することを防ぐことができます。

# Vueのエコシステム系

## Vue Router（Vue限定）

https://router.vuejs.org/

ルーティング処理を担ってくれるライブラリです。

そもそもSPAのSは**Single**のSなので、厳密に言えば「ルーティング処理」というものは存在しないのでは？という感じもしなくはないです。
・・・が、現実としてSPAのSingleは「サーバ側がホストする`index.html`が一つ」という意味のSingleとなっています。というわけで、SPAといいながらも複数の画面を用意しておきたいアプリがほとんどになるのではないでしょうか。

Vue Routerは、（従来のMPAよろしく）URLと表示する画面とをマッピングしてくれます。マッピングだけでなく、
- クエリパラメータ
- パスパラメータ
- 画面遷移
- ナビゲーションガード

などの機能も提供してくれるので、**ペラ一枚のアプリでも無い限りは**入れておいたほうが無難です。

:::note info
ナビゲーションガードとは、画面遷移のたびに実行される前処理（後処理も書けます）を指します。
例えば特定の画面は認証済みでないと表示できない、といったときに使用します。
非常に便利なのでぜひ使いこなせるようになっておきましょう！

[Navigation Guards（VueRouterドキュメント）](https://router.vuejs.org/guide/advanced/navigation-guards.html)
:::


## Pinia（Vue限定）

https://pinia.vuejs.org/

SPAでは状態（ステート）は基本的にクライアントサイドで管理します。
VueではProps Down/Emit Upの原則に則ることで、親子関係のデータの伝搬を実現します。しかし、この方法では水平方向のコンポーネント間での情報のやり取りをスムーズに行うことができません。（例：ある画面の入力項目を別の画面で参照したい、など）

もちろん、共通的な親コンポーネントまで遡ってから目的のコンポーネントまでさらにバケツリレーを行うことも考えられなくないですが、こういうケースでは状態管理ライブラリを使用することが一般的です。

Vueに状態管理ライブラリとして広く普及しているのがこちらのPiniaになります。
ストアの定義も参照もシンプルなので、癖がなく使えることがメリットです。

Piniaが登場したときはOption Storeという記法のみがサポートされていましたが、現在はscript setupと同等の書き味ができるSetup Storeという記法もサポートされています。後者の方がより直感的に書けるので、僕は基本的にSetup Storeで記述します。

__Option Store__

```js
export const useCounterStore = defineStore('counter', {
  state: () => ({ count: 0, name: 'Eduardo' }),
  getters: {
    doubleCount: (state) => state.count * 2,
  },
  actions: {
    increment() {
      this.count++
    },
  },
})
```

__Setup Store__

```js
export const useCounterStore = defineStore('counter', () => {
  const count = ref(0)
  const name = ref('Eduardo')
  const doubleCount = computed(() => count.value * 2)
  function increment() {
    count.value++
  }

  return { count, name, doubleCount, increment }
})
```

# バリデーション系

## zod

https://github.com/colinhacks/zod

TypeScript界隈でとりあえず使っとけ（筆者調べ）と言われるバリデーションライブラリです。
入力フォームで
- 名前はアルファベットのみ
- 年齢は20から60の間
- 郵便番号は数値7桁
- 「メールマガジンを希望する」にチェックをいれた人だけメールアドレスは必須

のような単項目・相関チェックの両方を宣言的に定義し、バリデーションを行うことができます。
ここでいう「宣言的」とは、各項目が満たすべき条件を簡潔に分かりやすく書ける、という意味で使っています。
開発者が書きたいのは「項目が満たすべきルール」であって、「そのルール通りかどうかを検証するロジック」では無いはずです！

```ts
const User = z.object({
  username: z.string(),
  age: z.number().min(20).max(60),
});
```

このようにルールを直感的に書けるうれしさを感じられるのがzodです。

## VeeValidate（Vue限定）

https://vee-validate.logaretm.com/

zodはあくまでJS/TSの世界で利用されるバリデーションライブラリで、実際にVueの世界で使うとなると接続するライブラリがあると便利です。
VeeValidateは、（zodに限らず）フォームに入力されたデータをバリデーションルールに基づいて評価し、そのフィードバックを提供してくれるライブラリです。
エラーメッセージをリアクティブに返してくれるので、Vueのデータバインディングと組み合わせることでフォーム部品のコーディングが効率化されます。

```ts
const { handleSubmit } = useForm({validationSchema: toTypedSchema(User)});

const { value, errorMessage } = useField('username');

const onSubmit = handleSubmit((values) => console.log(values));
```

上記のように書くと、
- `value`にはユーザ名が入る
- ユーザ名に対するバリデーションエラーメッセージは`errorMessage`に格納される
- `onSubmit`を実行すると、「バリデーションがすべてpassしたときのみ」コンソールにフォームの内容が出力される

といったことを実現できます。
特徴として、`useForm`したスキーマの一つ一つを`useField`で参照するのですが、`useForm`時の効果は子コンポーネントにまで及びます。すなわち、
- 親コンポーネントで`useForm`
- 子コンポーネント（フォーム部品など）で`useField`

という風に責務をわけることで、子コンポーネント側の汎用性を上げることが可能です。
このあたりは公式ドキュメントのベストプラクティスにも掲載されているので参照ください。

https://vee-validate.logaretm.com/v4/guide/composition-api/caveats/


# テスト系

## Vitest

https://vitest.dev/

Vite環境におけるテストツールです。名前の通り、Viteと非常に相性がいいです。（というかViteのコアメンバーが作っている）

正直他のテストツールを試さずにこのツールを使用しているのでこれ以外の選択肢を知らないのですが、Viteにネイティブに対応しているだけあって、導入の容易さと実行速度に不満は全くありません。

テストコード自体はJestと互換性を持たせているため、Jestに慣れている人ならすぐ書き始められると思います。もし「こういうことがしたいんだけどな〜」ということがあっても、Jestは超メジャーなのでググればすぐに解決方法が得られるところもGoodです。

## Testing Library

https://testing-library.com/

SPAはコンポーネント指向であることが多いため、単体テストもコンポーネント単位で行いところです。
ただ、従来のテストツールだけではDOMも絡めた実際の操作に則したテストが行いづらいところがありました。
Testing Libraryを使えば、コンポーネントが何を描画したか、どのようなイベント（クリックイベント、キーイベント）に対して反応したかを検証することができます。

Testing Libraryが優秀なので、単体テストといいながらも、ある程度の大きさのインテグレーションテストまでVitest+Testing Libraryで済ませてしまうことが可能です。
とあるプロジェクトでは、入力フォーム画面という単位で、その画面のフォームにさまざまな値を入力し、バリデーションエラーメッセージの表示内容や、バリデーションエラーがある場合は次の画面に進むボタンが非活性になることなどを検証していました。

ReactにおけるTesting Libraryを使ったテストプラクティスは、同じアドベントカレンダーの下記記事にもまとめられておりますので、ぜひご覧ください。

https://qiita.com/t-kurasawa/items/950a0f4ccf57312d6430

## MSW

https://mswjs.io/

SPAから外部のAPIサーバにリクエストを送る処理を書くことはしょっちゅうありますが、そのAPIサーバをモック化したい場合に便利なのがこちらのライブラリです。

実際のAPIサーバのレスポンスを使うのはもっと後の工程として、開発中はいろいろなバリエーションのレスポンスに対して動作を確認したいはずなので、APIサーバ（というかレスポンス）をモック化することはよくあると思います。
ただ、APIサーバそのものをモック化するのは骨が折れますし、SPA側のInfra層をモック化するとなるとDIなどの仕組み作りが必要になります。

MSWを使えば、ブラウザのサービスワーカーを使ってHTTPリクエストを監視してインターセプトするので、SPAからは本当に外部のAPIサーバにリクエストを送信しているように書くことができます。
一方で、どのようなリクエストに対してどのようなレスポンスを返すか、といった定義は同じプロジェクトのソースコード内に記述できるので、メンテもしやすく開発者間での共有も容易です。

とりあえず書いてみたコードの動作を確認したいときやフィージビリティ検証にも有用なので、とりあえず入れておけば間違いないライブラリになっています。

ちなみに、ブラウザ上だけでなくNodeサーバ上でも動作します。そのため、Nodeアプリケーションから外部サーバへのリクエストに対するモックレスポンスも作成できます。


# まとめ

執筆開始時はcreate-vueで何を入れてくれるのかをよく知らなかったのですが（自分はViteのテンプレートから書くことが多かった）、ここで紹介する予定だったライブラリのほとんどを入れてくれるらしく、あまりこの記事の意義が無くなってしまった気もします。ぐぬぬ・・・

とはいえ、ここで書いたものは本当にいろいろなプロダクトにそのまま使えるものなので、まだ使ったことがないものがある場合は、ぜひ試してみてください。