Parcel から Vite へ: 100K LOC の移行に関する短編
3 つのフロントエンドプロジェクトを Parcel から Vite に移行しましたが、そのプロセスは… 滞りなく進みました。
背景
私たちは Logto で 3 つの主要なフロントエンドプロジェクトを持っています: サインイン エクスペリエンス、コンソール、およびライブ プレビューです。これらのプロジェクトはすべて TypeScript、React、および SASS モジュールで構築されており、合計で約 100K 行のコードを持っています。
私たちは、Parcel のシンプルさとゼロ構成のセットアップを気に入っていました。Parcel を使って新しいプロジェクトをセットアップするのがいかに簡単であるかに驚いた日をまだ覚えています。parcel index.html
を実行するだけで、必要な依存関係がすべてインストールされ、プロジェクトが実行されるのです。「経験豊富な」開発者であれば、Gulp や Webpack を使ってセットアップしていた昔と比較して同じように感じるかもしれません。Parcel はまるで魔法の杖のようでした。
Parcel のシンプルさは、時には気まぐれなこともありましたが、私たちがそれに長く固執していた主な理由です。例えば:
- Parcel がプロジェクトをバンドルできないことがありました。これは、実際には存在するチャンクファイルを見つけられなかったためです。
- Monorepo 設定で動作させるには一部のハック的な構成が必要でした。
- MDX 3 をネイティブにサ ポートしていないため、カスタムのトランスフォーマーを作成する必要がありました。
- 手動チャンクをサポートしておらず(この記事を書いている時点では、手動チャンク機能はまだ実験段階です)、たいていの場合これで十分ですが、時にはこれが必要になることもあります。
それでは、なぜ何か別のものに移行することを決めたのでしょうか?
- 我々は 2023 年 6 月にリリースされた Parcel 2.9.3 で立ち往生していました。その後、新しいバージョンがリリースされるたびにアップグレードを試みましたが、常にビルドエラーで失敗していました。
- Parcel の最新バージョンは 2024 年 2 月にリリースされた 2.12.0 でしたが、ほぼ毎日のようにコミットが行われているにもかかわらず、その後新しいリリースはありませんでした。
誰かがParcel が死んでいるかどうかを尋ねるディスカッションを開いてさえいました。公式の回答は「いいえ、Parcel はまだ生きている。ただし、大規模なリファクタリングに取り組んでおり、マイナーリリースの時間がない状態です。」というものでした。私たちにとってこれは「アヒルの死」と同じようなものです: 私たちが使用できる最新バージョンは 1 年以上前のものであり、次のバージョンがいつリリースされるのかもわかりません。それは死んでいるように見え、死んでいるように振る舞っているため、私たちにとっては死んでいるのです。
なぜ Vite?
私たちは Vitest から Vite を知りました。数か月前、Jest の ESM サポート (テスト時) に疲れて何か新しいものを試したいと思いました。Vitest はネイティブの ESM サポートと Jest 互換性で私たちの心をつかみました。これは驚くべき開発者体験であり、Vite によって支えられています。
現状
プロジェクトによって設定が異なるかもしれませんが、通常、Vite エコシステムが成長しているため、プラグインの代替を見つけることができます。移行時の私たちのセットアップは次のとおりです:
- Monorepo: 私たちは monorepo を管理するために PNPM (v9) ワークスペースを使用しています。
- モジュール: すべてのプロジェクトで ESM モジュールを使用しています。
- TypeScript: すべてのプロジェクトでパスエイリアスを使用して TypeScript (v5.5.3) を使用しています。
- React: すべてのフロントエンドプロジェクトで React (v18.3.1) を使用しています。
- スタイリング: スタイリングには SASS モジュールを使用しています。
- SVG: SVG を React コンポーネントとして使用しています。
- MDX: GitHub Flavored Markdown や Mermaid のサポート付きで MDX を使用しています。
- 遅延読み込み: ページやコンポーネントをいくつか遅延読み込みする必要があります。
- 圧縮: 本番ビルド用に圧縮されたアセット (gzip と brotli) を生成します。
移行について
最初に新しい Vite プロジェクトを作成し、それがどのように動作するかを確認することで、移行を始めました。プロセスはスムーズで、実際の移行には数日しかかかりませんでした。
即時サポート
Vite は monorepo、ESM、TypeScript、React、SASS を即時サポートしており、必要なプラグインや設定をインストールするだけで動作させることができました。
パスエイリアス
Vite にはパスエイリアスのサポートが組み込まれています。例えば、私たちの tsconfig.json
では次のようになっています:
私たちの vite.config.ts
でも同じ解決法を追加するだけです:
代替パスはプロジェクトルートに対して相対的であるため、絶対パスである必要があることに注意してください。代わりに、vite-tsconfig-paths プラグインを使用して、tsconfig.json
からパスエイリアスを読み取ることもできます。
React Fast Refresh と HMR
Vite には HMR のサポートが組み込まれていますが、React Fast Refresh を有効にするにはプラグインをインストールする必要があります。Vite チームが提供する @vitejs/plugin-react プラグインを使用しました。このプラグインは Fast Refresh のような React 機能を良好にサポートしています:
SVG を React コンポーネントとして使用する
vite-plugin-svgr プラグインを使用して、SVG を React コンポーネントに変換します。Vite 設定にプラグインを追加するだけで簡単です:
ただし、SVG を React コンポーネントに変換する条件を指定しなかったため、すべてのインポートが変換されました。このプラグインはより良いデフォルト設定を提供しています:.svg?react
拡張子でインポートされた SVG のみを変換します。私たちはインポートをそれに応じて更新しました。
SASS モジュール
Vite には SASS モジュールのサポートが組み込まれていますが、1 つだけ注意が必要な点があります:クラス名のフォーマット方法です。クラス名が一貫していない場合、ユーザーや私たちの統合テストにとって厄介になることがあります。vite.config.ts
の 1 行の設定でこの問題を解決できます:
ところで、Parcel と Vite は SASS ファイルのインポート方法に違いがあります:
* as
構文は Vite でも機能しますが、styles
オブジェクトに動的キーを使用してアクセスするとモジュール化されたクラス名が失われます。例えば: