Laravel MixをViteに移行した話(Vue2環境)
はじめに
こんにちは。とあるプロジェクトのLaravel Mixでのビルドが3分ほどかかるようになってしまったので、まだプロジェクトが小さいうちにViteに乗り換えようということで今回移行作業を実施しました。同じようにLaravelのプロジェクトでLaravel MixからViteに乗り換えようと考えている人の助けになればと嬉しいです。
バージョン情報
パッケージ名など | Vite移行前 | Vite移行後 |
---|---|---|
Vue | 2.7.14 | 2.7.14 |
inertiajs | 0.x系 | 1系 |
Laravel | 9.52.4 | 9.52.4 |
Laravel Mix | 6.0.49 | - |
Vite | - | 4.1.4 |
実際の作業手順
一つずつ見ていきたいと思います。
1. Inertiaを0.x系から1.0系へアップデートした
今回やりたいこととは直接関係ないかもしれませんが、Inertiaが0.x系から1系へめでたくアップグレードされていました。使い方に大きめの変更があったのでまずInertiaをアップグレードすることにしました。Viteに移行したあと謎のエラーが発生する可能性を減らしたかったので先に不安要素は潰したかったという感じです。
2. Laravel ShiftでVite Converterを実行
Laravel Shiftとは
自動でLaravelのバージョンをあげてくれるすごいやつ。基本有料だけど、「Vite Converter(自動でLaravel MixからViteに移行する上で必要な作業をしてくれる)」は無料で使えたので今回使ってみました。
リポジトリを指定して、Vite Converterを実行すると自動でPRを作成してくれます。PRには下記のように作業内容や注意事項などを記載してくれているので全て目を通すようにしましょう。
Vite はフロントエンド アセットを public/build フォルダーに生成します。このフォルダーは、デフォルトの Laravel プロジェクト内で Git によって追跡されません。そのため、Shift はこのフォルダーを .gitignore ファイルに追加しました。 デプロイを容易にするためなど、プロジェクト内で生成されたフロントエンド アセットを追跡したい場合は、git revert a0000000 を実行してこのコミットを元に戻すことができます。
3. Vite Converterにお願いされた操作をした
Vite converterが作成してくれたPRにコメントで、 yarn install
と composer update
を実行してねと書いてあったので実行しました。
tsconfig.json
のtargetをes5からesnextに変更
4. - "target": "es5",
+ "target": "esnext",
5. 各bladeファイルのアセットの読み込みのコードをviteのものに変更
ViteではLaravel mixとアセットのリンクを発行するコードが異なります。忘れずに全てのbladeファイルをチェックして変更するようにしましょう。
- <link rel="stylesheet" href="{{ asset(mix('css/lp.css') }}">
+ @vite('resources/sass/lp.scss')
6. Inertiaのvueファイルの読み込み部分のコードをViteの書き方に変更
公式ドキュメントのResolving componentsの項に記載があるようにViteの書き方に変更しましょう。
- resolve: (name) => require(`../vue/pages/${name}`),
+ resolve: (name) => {
const pages = import.meta.glob('./Pages/**/*.vue', { eager: true });
return pages[`./Pages/${name}.vue`];
},
7. Viteへの移行にあわせてGitHubActionsのコマンドも修正した
Laravel ShiftのVite Converterがpackage.jsonに記載されているコマンドも変更してくれているので、GitHub Actionsのビルド用のコマンドも書き換えました。
- - run: yarn production
+ - run: yarn build
8-1. public配下に置いた画像はRollupにバンドルさせないようにする
Laravelのpublic配下に設置してある画像があったため、Viteの設定ファイルにそれらはバンドルさせないようにしました。
build: {
rollupOptions: {
// ライブラリにバンドルされるべきではない依存関係を
// 外部化するようにします
external: [
/\/images\/*/,
],
},
},
8-2. yarn run buildと yarn run devどちらでも動作するようimageのパスの書き方を修正した
laravelプロジェクトのpublic配下に /images/logo.svg
を設置した後Vueのtemplateタグ内で <img src="/images/logo.svg" >
と記述し yarn run build
すると画面が表示できなくなり、 <img :src="'/images/logo.svg'" >
とすると動作する現象に出会いました。
試しにVue3の環境で同じコードを実装したら動作したので、Vue2 + Viteの環境でのみ起こる現象っぽかったのですがさっぱり理由がわからずChatGPTに聞いてみたところ、
Vue 3 と Vite の組み合わせでは、この挙動が異なることがあります。Vue 3 では、静的アセットのパスを直接指定しても、Vite が適切に解決してくれるようになっています。
Vite のプラグインである @vitejs/plugin-vue が、Vue 3 のシングルファイルコンポーネント(.vue ファイル)の解析やコンパイルを担当しています。Vue 3 で Vite を使用するとき、このプラグインが Vue のコンポーネント内で静的アセットのパスを検出し、適切に Vite のアセット解決ロジックに渡します。その結果、<img src="/images/logo.svg"> のような記述でも正しく動作するようになります。
ただし、Vue 2 と Vite を組み合わせる場合、@vitejs/plugin-vue のバージョン 1.x を使用します。このバージョンは、Vue 2 のコンポーネント内で静的アセットのパスを適切に解決できない場合があります。このため、Vue 2 と Vite を使用する場合は、<img :src="'/images/logo.svg'"> のように v-bind を使用するか、import 文で画像をインポートしてバインドすることが推奨されます。
Vue 3 と Vite を使用する場合は、<img src="/images/logo.svg"> のような記述で問題なく動作しますが、import 文を使ってアセットをインポートする方法も引き続き利用可能です。どちらの方法を選択しても、Vite はアセットを適切に扱い、期待通りの動作を実現できます。
とのことでした。今は現状のディレクトリ構成を崩したくないので、v-bindを利用する形で対応しました。
以上で作業は終了です!あとはステージング環境で念入りにテストをしたあとさっさとリリースしてしまいましょう。
今後の課題
Vue2からVue3に移行する
Vue2系のプラグインのサポートがいつ終了するか怖いので、なるべく早くVue3への移行を実施する必要があります。機能実装が落ち着いたらやろうかな...
GithubActionsでTypeScriptの型チェックの機構を入れる
Viteはビルドする際にTypeScriptの型チェックをしてくれないみたいでした。そのため、別でCIに型チェックの仕組みを入れる必要があるみたいです。ただ、現状はVue2 + TypeScriptの構成なので、このタイミングで深堀りしないほうがいいと判断しました。一旦Vue3にアップグレードするまではTypeScriptの型チェックは各作業者のエディタと、コードレビューに任せることにしました。
テスト時にViteでビルドをしないでも済むようにする
Laravelの公式ドキュメントに下記のような記載がありました。
LaravelのVite統合は、テストの実行中にアセットを解決しようとするので、Vite開発サーバを実行するか、アセットをビルドする必要があります。
テスト中にViteをモックしたい場合は、LaravelのTestCaseクラスを拡張するすべてのテストで利用できる、withoutViteメソッドを呼び出してください。
とのことなので、余裕ができたらテスト時にViteのビルドをしなくてもいいように設定したいと思います。
まとめ
- 手元での開発環境立ち上げ時間は3分から10秒程度にまで短縮できた
- GitHub Actionsのビルドとデプロイを含めた実行時間が15分から5分にまで短縮できた
移行し終えた感想
今回Vue2からVue3への移行の一歩が踏み出せたというのと、開発・本番用ともにビルドの速度が爆速になりました。Viteの開発用サーバーはホットリロードも標準搭載なので余計な設定をするのに時間がとられず非常に開発者満足度が高くなりました!
Discussion