まえがき
現在、業務でtoB向けサービスの開発を行なっています。
このプロジェクトのフロントエンドはReact+typescriptで構築されており、ビルド基盤はcreate-react-app(CRA)を利用しています。
この度、このプロジェクトのビルド基盤をCRAからViteへ移行したため、その記録を書いていきます。
Viteとは
公式サイトより
Vite(フランス語で「素早い」という意味の単語で /vit/ ヴィートのように発音)は、現代の Web プロジェクトのために、より速く無駄のない開発体験を提供することを目的としたビルドツールです。2 つの主要な部分で構成されています:
- 非常に高速な Hot Module Replacement (HMR) など、ネイティブ ES モジュールを利用した豊富な機能拡張を提供する開発サーバ。
- Rollup でコードをバンドルするビルドコマンド。プロダクション用に高度に最適化された静的アセットを出力するように事前に設定されています。
CRAを使用している場合、コード量が増加するにつれてビルド時間も増加してしまうという問題点があります。
Viteであればその問題点を解消できる(コード量が増えても高速でビルドできる)ので、開発効率を高めるためにも移行を決定しました。
プロジェクトについて
モノレポで開発を行なっています。
ディレクトリ構成は以下の通りです。
project
┣━ client … フロントエンド
┣━ server … bff
┣━ hasura … バックエンド(データベース)
┗━ sharedTypes … フロントエンド、バックエンドの両方で使用する型を置いておくディレクトリ
Viteへの移行は、client
ディレクトリで行いました。
バージョンは以下の通りです。
- react: 17.0.2
- typescript: 4.1.2
- vite: 2.9.5
移行にあたってやったこと
パッケージの整理
必要なパッケージ
vite
@vitejs/plugin-react
この2つをインストールするために、
yarn add -D vite @vitejs/plugin-react
を実行します。
不要になるパッケージ
react-scripts
これを削除するために、yarn remove react-scripts
を実行します。
package.jsonのscriptsの修正
package.jsonのscriptsを以下のように修正しました。
- "start": "react-scripts start",
- "build": "react-scripts build",
- "test": "react-scripts test",
- "eject": "react-scripts eject",
+ "start": "vite",
+ "build": "tsc && vite build",
このプロジェクトがモノレポであるが故に、scriptsを後に修正する必要があるとは、今はまだ知る由もなかった…
vite.config.tsの作成
client
の直下(package.json
やtsconfig.json
と同じ階層)に、vite.config.ts
ファイルを作成します。
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import path from 'path';
export default defineConfig({
server: {
host: true,
open: true,
},
resolve: {
alias: {
src: path.resolve(__dirname, './src/'),
},
},
build: {
outDir: 'build',
},
plugins: [react()],
});
- server.host
こちらのDiscussionsによると、ファイルシステムを外部に公開するために必要なようです(曖昧)。 - server.open
trueにしておくと、サーバーを起動した時に自動でブラウザを開いてくれるようになります。 - resolve.alias
絶対パスを使用するために設定しました(曖昧)。 - build.outDir
ビルドされたファイルを出力するディレクトリ名を設定する項目です。
CRAでのビルドファイルの出力先がbuild
であるため、それに合わせてbuild
に設定しました。
(Viteでのビルドファイルの出力先は、デフォルトではdist
)
index.htmlの修正
client/public
にあるindex.html
を、client
直下に移動します。
そして、index.html
にscriptタグを追加します。
<body>
<noscript>JavaScriptを有効にしてください</noscript>
<div id="root"></div>
+ <script type="module" src="/src/index.tsx"></script>
</body>
また、<link />
タグのhref
から%PUBLIC_URL%
を削除します。
- <link rel="icon" href="%PUBLIC_URL%/favicon.svg" type="image/svg+xml" />
- <link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
+ <link rel="icon" href="/favicon.svg" type="image/svg+xml" />
+ <link rel="manifest" href="/manifest.json" />
環境変数の変更
CRAの場合はREACT_APP_
で始まる環境変数を使用していましたが、ViteではVITE_
で始まる環境変数を使用するため、変更します。
- REACT_APP_XXXXXX=hoge
+ VITE_XXXXXX=hoge
そして、環境変数の読み込み方法も変わります。
CRAの場合はprocess.env
でしたが、Viteではimport.meta.env
で読み込みを行うため、書き換えます。
- process.env.REACT_APP_XXXXXX
+ import.meta.env.VITE_XXXXXX
env.d.tsの作成
自分が定義した環境変数を読み込む際にtypescriptに自動補完してもらうために、client/src
に、env.d.ts
を作成します。
interface ImportMetaEnv {
readonly VITE_XXXXXX: string
// その他の環境変数...
}
interface ImportMeta {
readonly env: ImportMetaEnv
}
tsconfig.jsonの修正
tsconfig.json
のcompilerOptions.types
にvite/client
を追加します。
"types": ["vite/client"]
.svg
や.png
などのアセットをインポートする箇所でts2307エラーが発生していたのですが、これを追加したら直りました。
終了! と思いきや
これにて移行作業は終了です。yarn start
をして、動作を確認していきます。
ローカルの開発環境では問題なく動きました。
次に、client
ディレクトリをビルドして動作を確認します。
するとどうでしょう。ビルド時にエラーが出ました。
エラーの原因
エラーメッセージは
TS2307: Cannot find module 'sharedTypes/hoge/fuga' or its corresponding type declarations.
と、sharedTypes
ディレクトリからのインポート部分で発生していました。tsエラーですね。
sharedTypes
はビルドせずにclient
のビルドのみを行ったため、tsc
がsharedTypes
を見つけられなかったのが原因のようです。
エラーの修正
package.json
のビルドコマンドからtsc
を削除します。
"start": "vite",
- "build": "tsc && vite build",
+ "build": "vite build",
ビルド時のエラーは出なくなりますが、これだとtsc
による型チェックが行われなくて困ってしまいます。
ですので、ビルド時ではなく開発中に型チェックを行ってもらえるようにします。
npm-run-all
というパッケージ(コマンドラインツール)を使用するため、まずyarn add -D npm-run-all
を実行してパッケージを追加します。
そして、start
コマンドを以下のように修正します。
- "start": "vite",
+ "dev": "vite",
+ "type-check": "tsc --noEmit",
+ "start": "run-p \"dev\" \"type-check --watch\"",
(run-p
は、複数のコマンドを並列実行するためのコマンドであるnpm-run-all --parallel
のショートカットです)
これで、ローカルのサーバーを起動した際にtsc
の型チェックが行われるようになりました。
今度こそ終了!
再びビルドを行うと、今度はエラーも出ず、無事にビルドが完了しました。
デプロイされたものも問題なく動いているようですので、今度こそ晴れて終了です!
あとがき
移行作業にあたって、以下のサイト・記事を参考にしました。