KAKEHASHI Tech Blog

カケハシのEngineer Teamによるブログです。

業務システム SPA のフロントエンド技術選定(2023年版)

本エントリはカケハシ Part 2 Advent Calendar 2023の13日目の記事です。 (Part 1もおもしろい記事がいっぱいあるので、ぜひご覧ください。)

はじめに

こんにちは。カケハシでソフトウェアエンジニアをしている平松です。

今年、新規プロダクト立ち上げの機会があり、その際に行ったフロントエンドの技術選定について紹介したいと思います。

フロントエンドの領域は選択肢が豊富で、変化のスピードも速いため、プロダクトの要件に適した技術を選ぶことはひとつの挑戦です。 実際、フロントエンド技術選定のヒント 【令和五年度版】のアドベントカレンダー記事を読んで、その難しさを改めて感じました。

今回の新規プロダクトは、ユーザがログインして利用するtoBの業務システムです。 私はカケハシでは2度目の新規プロダクト立ち上げですが、前回の経験を活かしつつ、新しいアプローチにも挑戦しています。

この記事では以下を紹介したいと思います。

  • 技術選定
  • テストについて
  • モノレポ、パッケージ分割について

技術選定

早速ですが、選定した技術を紹介します。(テストについては次項に記載します)

SPAアーキテクチャ

  • ベース: React + TypeScript
  • ビルドツール: Vite
    • 最初はNext.jsやRemixといったフレームワークの選択肢も検討しました。しかし、最終的にはフレームワークを採用せず、ビルドツールであるViteを採用することに決めました。これは私たちのプロダクトにおいては、CSR(クライアントサイドレンダリング)で十分であると判断したためです。
    • また、Viteを選んだもうひとつの理由は、そのシンプルさとスピードです。Viteはモダンな開発ツールであり、開発プロセスの高速化を実現します。プロダクトの構成をシンプルに保ちつつ、効率的な開発を目指す私たちのニーズにはぴったり合っていました。
  • ルーティング: React Router
  • APIクライアント: urql
    • バックエンドとのインターフェイスとしてGraphQLを採用しています
    • GraphQLクライアントとしてApollo Clientの採用実績がありましたが、Suspense対応していることを理由にurqlを選定しました
      • 注: Apollo Clientも3.8からSuspense対応しています(技術選定時はSuspense未対応でした)
    • GraphQLの強力なエコシステムの恩恵を受けるため、GraphQL Code Generatorをフル活用しています
      • GraphQLスキーマからさまざまなものを生成しています(tsukiji.graphqlというイベントでLTしました)
  • フォーム: React Hook Form
    • 他プロダクトでも採用実績があり、大きな不満もなかったため採用しました
    • スキーマバリデーションのzodと組み合わせて利用しています
  • UIコンポーネント: Mantine
    • スピード優先ということで、UIコンポーネントライブラリを使うことにしました
    • Chakra UIの採用実績がありましたが、後発のMantineを選択しました。MantineはComboBoxやDatePicker周りのコンポーネントも充実している点は大きなメリットでした。

その他

テストについて

チームのテスト文化の重要性

以前のプロダクト立ち上げで、「後からテストを書く」というアプローチを採用し、その結果としてコードベースが拡大するにつれてテスト追加のコストが上昇してしまいました。この経験から、テストに対するアプローチの重要性を再認識しました。

チーム全体でテストを書く文化が根付くか否かは、初期設計段階での方針決定が鍵となります。 コードが小さいうちから方針を示しておくことで、どのようにテストを書くべきかについての共通認識が形成されます。 前例をコミットしておけば、テストに不慣れなメンバーでも、前例を参考にある程度のテストが書けるようになります。 この点に関して、フロントエンド開発のためのテスト入門の著者の意見に共感しました。

テストの方針と具体的な実装

新規プロダクトにおける基本的なテスト方針として、Testing Trophyを選択しました。これは、フロントエンド開発におけるテストの進め方に関する考え方です。

以下は、具体的なテストに関する技術とツールの概要です。

  • モック: Mock Service Worker(MSW)
    • GraphQL APIリクエストのモックにMock Service Worker(MSW)を利用し、ローカル開発、コンポーネントのインテグレーションテスト、Storybook、ブラウザ操作テストなどで活用しています
  • コンポーネントカタログ: Storybook
  • Visual Regression Testing: reg-suit + storycap
  • テストランナー: Jest
  • コンポーネントテスト: React Testing Library
  • E2Eテスト: Playwright

MSWの幅広い活用

新規プロダクトでは、MSWを広範に活用しています。 MSWは、Storybook、Jest、Playwrightと組み合わせて、さまざま状況で効果的に利用されています。

以下の点がMSWの気に入っているところです。

  • ネットワークレイヤーでモックするため、より本物に近い形でテストできる
  • ローカル開発、テスト、Storybookで、同じ記法でモックを書くことができる

このように大変便利なMSWですが、単純に利用するだけではモックデータの用意と管理が大変です。 そこで、私たちは自動生成を活用しています。 GraphQLスキーマから次のようなコードを自動生成することで、効率的にそして型安全にモックを扱っています。

カケハシの別のチームの話ですがこちらも合わせてどうぞ。

モノレポ、パッケージ分割について

新規プロダクトでは、pnpm workspaceとTurborepoによるモノレポ構成を導入しています。 pnpm workspaceは複数のパッケージを管理し、依存関係を効果的に管理します。 Turborepoは、モノレポ内の各パッケージに対するタスク実行を簡便にし、開発プロセスを迅速かつ効率的にします。

総じて、pnpm workspaceとTurborepoの組み合わせは、モノレポでの開発を素早く効率的にします。 共通の依存関係管理とタスク実行の最適化により、大規模プロジェクトでも優れた開発体験が得られます。

また、今回のプロダクトでは、パッケージ分割を積極的に利用する方針をとっています。 背景として、前回のプロダクトで、ディレクトリ間の依存関係に制約を入れるため、ESLintなどの設定を入れていたのですが、メンテナンスコストが大きいなと感じていました。 モジュールごとにパッケージ分割し、package.jsonのdependencies/devDependenciesで依存関係を管理することで、設定がシンプルになりました。

以下に、モノレポで管理しているフロントエンドに関係するパッケージ一覧を抜粋してきました。

# モノレポルート
├── apps
│   └── frontend      # SPAアプリケーションパッケージ
└── packages
   ├── bff
   │   └── faker      # BFF GraphQLモックデータ用factory関数パッケージ
   ├── branded-type   # Branded Typeパッケージ
   ├── e2e            # E2Eテスト(Playwright)パッケージ
   ├── eslint-config  # ベースのESLint設定パッケージ
   ├── frontend
   │   ├── auth       # 認証関連パッケージ
   │   ├── features   # 各機能パッケージ
   │   ├── graphql    # GraphQL関連(client-preset)パッケージ
   │   ├── mock       # MSWモックハンドラーパッケージ
   │   ├── test-utils # テストユーティリティパッケージ
   │   ├── ui         # 共通UIコンポーネントパッケージ
   │   ├── user       # ユーザ関連パッケージ
   │   └── utils      # ユーティリティ関数パッケージ
   └── tsconfig       # ベースのtsconfig設定パッケージ

各パッケージの詳細な説明は省きますが、apps, packages配下を見れば、フロントエンドアプリケーションの構成がざっくり把握できるのは大きなメリットかなと思います。

(実際にはバックエンドサービスのパッケージもモノレポで一緒に管理しています)

おわりに

新しく立ち上げた業務システムSPAのフロントエンドについて、簡単に紹介しました。 他にもおもしろいチャレンジをしているので別記事で紹介していければと思います。

明日は同じチームメンバーの種岡さんの記事です。お楽しみに!

最後まで読んでいただきありがとうございました。