Laravel MixからViteへ移行する前に知っておきたいこと
概要
Laravel 9.19 以降、フロントエンドのビルドツールの標準は Laravel Mix(webpack ベース)から Vite へと切り替わりました。新規プロジェクトでは laravel/vite-plugin が同梱され、vite.config.js が最初から用意されています。
一方で、Laravel 8 以前から稼働している既存プロジェクトには、まだ webpack.mix.js が残っているものが少なくありません。「新しいから」「速いから」という理由だけで移行に踏み切ると、Blade テンプレートの書き換え漏れや、require ベースのコードが動かないといった落とし穴に足を取られます。
この記事は、移行手順そのものよりも「移行を判断する前に知っておくべき差分と前提」を整理する考察です。手を動かす前の見取り図として使ってください。
環境
想定する構成は以下です(バージョンは代表的なものを例示)。
- PHP 8.1 以上
- Laravel 9 / 10 系
- Node.js 18 以上(Vite 5 系は Node 18+ を要求)
- 移行元:
laravel-mix+webpack - 移行先:
vite+laravel/vite-plugin
発生しがちな問題
Laravel Mix から Vite へ移す際、単純にパッケージを入れ替えるだけでは以下のような症状に遭遇します。
-
本番ビルドで CSS/JS が読み込まれない — Blade 側が
mix()ヘルパーのままになっている -
require()を含む JS がエラーになる — Vite は ESM 前提で、CommonJS のrequireをそのまま解釈しない - 静的アセットのパスがずれる — 画像やフォントの参照方法が Mix と Vite で異なる
-
環境変数が
undefinedになる —MIX_プレフィックスは Vite では読まれない
原因
根本的な違いは「Mix は webpack のラッパー、Vite は別アーキテクチャ」という点にあります。
- 開発時の仕組みが違う: Mix(webpack)は開発時も全体をバンドルしますが、Vite は開発時にネイティブ ESM を利用してオンデマンドで配信します。これが「速い」と言われる理由ですが、裏を返すと ブラウザに ESM を直接投げる前提であり、CommonJS 資産との相性が変わります。
-
マニフェストの位置と形式が違う: Mix は
public/mix-manifest.json、Vite はpublic/build/manifest.json(laravel/vite-plugin経由)を生成します。参照ヘルパーもmix()から@vite()ディレクティブへ変わります。 -
環境変数のプレフィックスが違う: Mix は
MIX_、Vite はVITE_を公開対象とします。
対応方法
1. Blade の参照を書き換える
mix() ヘルパーを @vite ディレクティブに置き換えます。
{{-- Before: Laravel Mix --}}
<link rel="stylesheet" href="{{ mix('css/app.css') }}">
<script src="{{ mix('js/app.js') }}" defer></script>
{{-- After: Vite --}}
@vite(['resources/css/app.css', 'resources/js/app.js'])
@vite は開発時には Vite dev server を、本番時には manifest.json を見てハッシュ付きの実ファイルを解決します。1 つのディレクティブで両対応するのがポイントです。
2. vite.config.js を用意する
import { defineConfig } from 'vite';
import laravel from 'laravel-vite-plugin';
export default defineConfig({
plugins: [
laravel({
input: ['resources/css/app.css', 'resources/js/app.js'],
refresh: true,
}),
],
});
refresh: true を付けると、Blade や routes を編集したときにブラウザが自動リロードされます(Mix の BrowserSync 相当)。
3. require を import に直す
// Before (CommonJS / Mix でも動いていた)
require('./bootstrap');
window.Alpine = require('alpinejs');
// After (ESM / Vite 前提)
import './bootstrap';
import Alpine from 'alpinejs';
window.Alpine = Alpine;
ここが移行で最も工数を食う部分です。プロジェクト内の require を機械的に置換できるとは限らず、動的 require を使っている箇所は個別対応が必要になります。
4. 静的アセットの参照を直す
Vite では JS/CSS から参照する画像などは相対パスを import するか、public/ に置いて絶対パスで参照します。
/* Vite: ビルド対象に含めたいアセットは相対参照 */
.hero {
background-image: url('../images/hero.png');
}
resources/ 配下から参照するとハッシュ付きで最適化され、public/ 直下に置いたものはそのまま配信される、という住み分けを意識します。
5. 環境変数のプレフィックスを直す
- MIX_PUSHER_APP_KEY=xxxxx
+ VITE_PUSHER_APP_KEY=xxxxx
JS 側の参照も process.env.MIX_* から import.meta.env.VITE_* へ変わります。
// Before
const key = process.env.MIX_PUSHER_APP_KEY;
// After
const key = import.meta.env.VITE_PUSHER_APP_KEY;
6. package.json のスクリプトを差し替える
"scripts": {
- "dev": "mix",
- "watch": "mix watch",
- "prod": "mix --production"
+ "dev": "vite",
+ "build": "vite build"
}
確認方法
-
npm run devで dev server が立ち上がり、@viteディレクティブが dev server の URL を出力しているか(HTML ソースを確認) -
npm run build後にpublic/build/manifest.jsonが生成されているか - 本番相当ビルドでページを開き、CSS/JS が 404 になっていないか(ネットワークタブで確認)
-
import.meta.env.VITE_*がブラウザ側で期待値になっているか
注意点
移行前に確認しておくと事故が減るポイントを挙げます。
-
本番デプロイで
npm run buildが走る前提になっているか。Mix 時代の CI/CD がそのままmix --productionを叩いていると、Vite に変えた瞬間ビルド成果物が生成されません。デプロイパイプラインの見直しは移行とセットです。 -
SSR やレガシーブラウザ対応の要件があるか。Vite は最新ブラウザを前提とするため、古いブラウザを切れない要件がある場合は
@vitejs/plugin-legacyなどの追加検討が必要です。 -
requireの使用箇所が多いレガシー資産では工数が読みにくい。「入れ替えるだけ」ではなく「ESM 化のリファクタリング」として工数を見積もるべきです。 - 移行しない選択肢も常にテーブルに残す。Laravel Mix は現在もメンテナンスが継続されており、「動いていて、フロントの改修頻度が低い」プロジェクトを急いで移行する費用対効果は低い場合があります。移行は目的ではなく手段です。
まとめ
Laravel Mix → Vite 移行は、単なるツールの置き換えではなく CommonJS → ESM というアーキテクチャの前提変更を伴います。
- Blade の
mix()→@vite -
require→import -
MIX_→VITE_ - デプロイパイプラインの
npm run build対応
このあたりを事前に棚卸しし、特に require の使用状況とデプロイフローを確認してから着手するのが安全です。「速いから移行する」ではなく「このプロジェクトにとって今移行する価値があるか」を先に問うのが、遠回りに見えて一番の近道です。