Tech & Design LAB

React + Viteで新規プロダクトを開発している話

#フロントエンド #技術選定 #React #Vite
author icon
Posted on
tech

こんにちは、エンジニアの尾島(@daikiojm)です。 最近は「社内にパリピ感が足りない」という課題感から Slack で「おじ卍ドレミ」を名乗っています。

最近開発を進めている新プロダクトで React と Vite の組み合わせを採用したので、技術選定の背景と使用している Vite プラグインについて簡単に紹介します。

これまでの HiCustomer のフロントエンド開発

これまで HiCustomer 社では HiCustomer のフロントエンドを Vue.js を用いて開発を進めてきました。 開発初期から現在まで、フロントエンドのコードベースは次のような変化をしてきました。

Vue.js を使用しながらも TypeScript によってもたらされる方安全の恩恵をより強く受けるため日々環境をアップデートしてきました。

全てはスピードのため

型安全を追求する理由は、一定以上のクオリティを保ったアプリケーションを高速に開発するためだと考えています。 事業のフェーズ、規模などによって開発チームに求められる力は各社様々だと思いますが、現在の HiCustomer のような PMF 前の BtoB プロダクトを開発するスタートアップでは、何よりも開発のスピードが重要だと考えています。

フロントエンドの特性上バックエンドのコードよりもテストが書きづらく、書いたテストのライフサイクルも短くなる傾向にあるため、テストを書くことテストをメンテすることには高いコストを伴います。このように、誤解を恐れずに言えば、テストでアプリケーションの品質を担保することは開発スピードと相反する部分があります。 もちろん、バグが起こると困るクリティカルな箇所ではテストが必要ですが、テストによる品質の担保よりも効率的な方法として TypeScript の型を利用することが挙げられます。

また、また開発中の細かいイテレーションの時間を短縮することも重要だと考えています。バックエンドを含めたアプリケーション全体で見ると、ビルド、デプロイなどの CI/CD 周りの時間などが挙げられますが、今回着目してのはフロントエンドの dev server の起動、HML の速度です。 HiCustomer がこれまで採用していた Vue 2 + TypeScript のアプリケーションでは vue-cli(webpack)では dev server の動作がかなり遅くなっていました。初回の起動は 2 分近くかかっていたほどです。 今回は、ブラウザの ES modules 対応が進んだことや、JavaScript よりも高速なランタイムで実装されたコンパイラが登場したことで注目されている新しい世代のビルドツール導入を検討しました。

作ろうとしているもの

ここで詳細をお伝えできないのはもどかしさがありますが、アプリケーションの要件はざっくり次のとおりです。

また、既存のプロダクト開発と並行して開発をすすめるためリソースに対する制約もありました。開発体制の特徴としては次のとおりです。

選定候補

以下は、大枠のフロントエンドスタックの候補です。TypeScript を使うことは前提と置きつつも、使用するフレームワークやビルドツールは一度 0 ベースで考え直すことにしました。 既存プロダクトと同じ構成を始め、新たに React も視野に入れ、ビルトツールについても一般的に使われており社内でも実績のあるもののほか Vite も候補に入れました。 Vite の対抗馬としてsnowpackwmrなどの webpack と比較して高速なことに強みを持っている他のビルドツールとも比較1しましたが、今後のコミュニティの継続性などを考慮した結果、これらは比較の対象からは外しました。

また、上記に加えフロントエンドエンジニアが UI の設計を行うという制約から高機能な UI コンポーネントフレームワークを合わせて使うことになりました。

が候補として挙がりました。

React

以下の理由から React を採用しました。

基本的に上記で挙げた「スピード」のためであれば、Vue でも React でも良かったというのが正直なところです。既存プロダクトで Vue を採用しており、開発メンバーが慣れているという点でも Vue を選択するというのが第一の選択になるかと思います。特により強い TypeScript の型の恩恵を受けることを重視しているため、Vue 3 を選択したいと考えていました。 しかし、この選定を行った当時では Vuetify の Vue 3 対応があまり進んでおらず、この時点で Vue 3 を採用するのは難しいという判断をしました。 TypeScript との親和性の高さに関しては、Vue 3 + TSX という選択肢もありますが、この組み合わせで運用している人口が圧倒的に少ないため、まだ表面化していないリスクがある可能性があると考え今回は見送りました。

Vite

以下の理由から Vite を採用しました。

Vite のドキュメント Why Vite を見て分かる通り dev server、ビルド速度が遅いという課題を解決することをモチベーションとしています。 詳しいベンチマークなどは割愛しますが、圧倒的な速さです。「Vite」はフランス語で早いという意味らしいです。

Vite + React の環境構築については公式ドキュメントに加えて以下の記事が参考になりました。

https://tech.recruit-mp.co.jp/front-end/post-21250/

Vite で使用しているプラグイン

ここからは、React + Vite でアプリケーションを構築する上で使用しているプラグインを紹介します。

@vitejs/plugin-react

@vitejs/plugin-reactは Vite 公式の React サポートプラグインで、以下の機能に対応しています。

以前まで @vitejs/plugin-react-refresh というプラグインでしたが、vite-react-jsxというプラグインがサポートしていた機能性も取り込んでリネームされているようです。3

@vitejs/plugin-legacy

@vitejs/plugin-react も Vite 公式のプラグインで、IE などのレガシーブラウザ向けのビルドを提供します。

vite-tsconfig-paths

vite-tsconfig-paths は TypeScript 側で設定したパスエイリアスを Vite 側の設定に反映させるプラグインです。 例えば、tsconfig.json に次のようなパスエイリアが設定されているとします。

{
  "compilerOptions": {
    "baseUrl": "./",
    "target": "ESNext",
    "lib": ["DOM", "DOM.Iterable", "ESNext"],
    "allowJs": false,
    "skipLibCheck": false,
    "esModuleInterop": false,
    "allowSyntheticDefaultImports": true,
    "strict": true,
    "forceConsistentCasingInFileNames": true,
    "module": "ESNext",
    "moduleResolution": "Node",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "noEmit": true,
    "jsx": "react-jsx",
    "paths": {
      "@/*": ["src/*"]
    }
  },
  "include": ["./src/**/*"]
}

プラグインを使用しない場合の設定:

// vite.config.ts
import path from 'path';
import { defineConfig } from 'vite';

export default defineConfig({
  resolve: {
    alias: [
      {
        find: '@/',
        replacement: `${path.resolve(__dirname, 'src')}/`,
      },
    ],
  },
});

プラグインを使用する場合の設定:

// vite.config.ts
import { defineConfig } from 'vite';
import tsconfigPaths from 'vite-tsconfig-paths';

export default defineConfig({
  plugins: [tsconfigPaths()],
});

vite-plugin-env-compatible

vite-plugin-env-compatible はアプリケーションコード内で process.env.XXX の形式で環境変数を読み込めるようにするためのプラグインです。

プラグインを使用しない場合の設定:

// vite.config.ts
import { ConfigEnv, defineConfig, loadEnv, UserConfigExport } from 'vite';

export default ({ mode }: ConfigEnv): UserConfigExport => {
  const env = loadEnv(mode, process.cwd());
  process.env = { ...process.env, ...env };

  // https://github.com/vitejs/vite/issues/1149#issuecomment-857686209
  // expose .env as process.env instead of import.meta since jest does not import meta yet
  const envWithProcessPrefix = Object.entries(env).reduce(
    (prev, [key, val]) => {
      return {
        ...prev,
        [`${process.env}.${key}`]: `"${val}"`,
      };
    },
    {}
  );

  return defineConfig({
    define: envWithProcessPrefix,
  });
};

プラグインを使用する場合の設定:

// vite.config.ts
import { defineConfig } from 'vite';
import env from 'vite-plugin-env-compatible';

export default defineConfig({
  plugins: [env()],
});

おわりに

今回は、HiCustomer の新プロダクトに採用した React + Vite の組み合わせを紹介しました。シンプルな React の SPA を開発する機会があれば、DX 爆上がりなので Vite おすすめです。

突然ですが、HiCustomer では一緒にプロダクト開発する仲間を募集しています! この記事内ではプロダクトについての詳細は省いていますが、カジュアル面談の場で詳しい説明も可能です。正社員、副業問わず募集しているので、まずはカジュアル面談からお気軽にお声掛けください!!

HiCustomer 採用ページ

author icon
エンジニア

常に変化を求めています。Node.js が好きで、HiCustomer のプロダクトチームではフロントエンドを担当しています。 趣味は slack に治安の悪い絵文字を追加することです。