---
title: "Laravel Viteの使い方｜@viteの書き方と本番ビルドの落とし穴"
url: "https://www.issoh.co.jp/tech/details/3251/"
published: 2024-08-02
updated: 2026-08-30
categories: ["Laravel"]
publisher: "株式会社一創"
---

# Laravel Viteの使い方｜@viteの書き方と本番ビルドの落とし穴

LaravelでViteを使うとき、つまずく場所はだいたい決まっています。`vite.config.js` にどう書くのか、Bladeの `@vite` はどこに置くのか、開発中はどのURLを開けばいいのか、そして `npm run build` したのに本番でCSSが当たらないのはなぜか。この記事では、Laravel 13・laravel-vite-plugin 3.1.3・Vite 8.2.0という2026年8月時点の現行構成にそろえて、設定の最小形から本番デプロイで壊れる典型パターン、Laravel Mixからの移行判断までを順に整理します。

## まとめ

- Laravel Viteとは、Laravelが公式採用したフロントエンドビルドツールViteと、連携用の公式プラグイン `laravel-vite-plugin` を組み合わせた構成を指します。`laravel/framework` 9.19.0以降、新規インストール時の標準です。
- npmの最新版はlaravel-vite-plugin 3.1.3（2026年7月13日公開）で、peerDependenciesはVite 8系（`^8.0.0`）です。
- Laravel Mixは、Laravel 13の公式ドキュメントで「積極的にメンテナンスされていないレガシーパッケージ」と明記されています。新規プロジェクトでMixを選ぶ理由はありません。
- Bladeでは `@vite` を `<head>` 内に1回だけ書きます。開発中にブラウザで開くのはアプリのURLで、Viteの開発サーバ（既定5173番）ではありません。
- 本番でアセットが読み込まれない原因の大半は2つです。`public/build/manifest.json` が無い（ビルド漏れ）か、`public/hot` が消し忘れで残っているかです。

## LaravelがViteを標準採用した経緯とLaravel Mixの現在地

### Vite標準化のバージョン境界と現行の組み合わせ

LaravelがフロントエンドのビルドをMixからViteへ切り替えたのは、`laravel/framework` の9.19.0からです。公式の移行ガイドも「Viteの新しい統合を使うには少なくとも9.19.0へ更新する必要がある」と書いています。

2026年8月時点の現行構成は、npmで公開されているバージョンを基準にすると次のとおりです。

| パッケージ               | 最新版    | 公開日        | 備考               |
| ------------------- | ------ | ---------- | ---------------- |
| vite                | 8.2.0  | 2026-07-30 | 前系列は7.3.6        |
| laravel-vite-plugin | 3.1.3  | 2026-07-13 | peerはvite ^8.0.0 |
| laravel-mix         | 6.0.49 | 2022-06-09 | 4年以上新規公開なし       |

Vite 7以前のまま3.1.3を入れると、npm 7以降では `ERESOLVE` でインストール自体が失敗します（`--legacy-peer-deps` を付けたときだけ警告で通過）。プラグインを上げるならViteも一緒に上げてください。

### Laravel Mixに対する公式の現在の位置づけ

Laravel 13のドキュメントにあるMixのページは、冒頭でこう述べています。「Laravel Mixは、もはや積極的にメンテナンスされていないレガシーパッケージです。モダンな代替としてViteを使用できます」。続けて「新規のLaravelインストールではViteがLaravel Mixを置き換えました」とも書かれています。

つまり「Mixなら公式サポートが受けられる」という説明は、現在の公式見解と食い違います。npmでの最終公開が2022年6月であることも、この位置づけを裏づけています。既存プロジェクトでMixが動いている分にはすぐ壊れませんが、新規に選ぶ対象ではありません。

### PHPアプリにおけるViteの守備範囲

Viteはブラウザへ配信するCSSとJavaScriptをまとめるツールであり、PHPのソースには一切触れません。Laravel側は `@vite` ディレクティブで「開発中はViteの開発サーバを、本番はビルド済みファイルを読み込む」という切り替えを担当します。

Viteを導入してもPHPの実行環境は変わりません。変わるのは `resources` 配下のアセットが `public/build` へ出力される点と、開発中のリロード体験だけです。

## laravel-vite-pluginの導入とvite.config.jsの最小構成

### インストール手順とNode.jsの実際の要件

Laravelのスターターキットを使った場合は `package.json` と `vite.config.js` が最初から用意されているため、`npm install` だけで済みます。既存プロジェクトへ手で入れる場合は次のコマンドです。

```
npm install --save-dev vite laravel-vite-plugin
npm pkg set type="module"
```

2行目を忘れると、Vite設定ファイルの読み込みでESモジュール関連のエラーが出ます。公式の移行ガイドでもこのコマンドが手順に含まれています。

Node.jsのバージョンは注意が必要でした。公式ドキュメントは今も「Node.js (16+)」と書いていますが、この記載は現行パッケージに追いついていません。laravel-vite-plugin 3.1.3とVite 8.2.0はどちらも `engines` に `^20.19.0 || >=22.12.0` を宣言しており、Node 16では `npm install` が EBADENGINE で止まります。実際に必要なのは20.19以上、または22.12以上です。

### エントリポイントの指定方法とSPAでの書き分け

laravel-vite-pluginは、エントリポイントの指定を必須にしています。最小構成は次のとおりです。

```
import { defineConfig } from 'vite';
import laravel from 'laravel-vite-plugin';

export default defineConfig({
    plugins: [
        laravel([
            'resources/css/app.css',
            'resources/js/app.js',
        ]),
    ],
});
```

import元のパッケージ名は `laravel-vite-plugin` です。名前がよく似た `vite-plugin-laravel` は公式のものではないので、コピー元を間違えないよう注意してください。出力先の `build` ディレクトリはプラグインが自動で設定するため、`build.outDir` を手書きする必要はありません。

InertiaなどのSPAを組む場合、公式は「CSSのエントリポイントを持たない構成が最も良く動く」としています。`resources/js/app.js` の側で `import '../css/app.css';` と書き、プラグインにはJSだけを渡してください。

### Blade保存時に自動リロードするrefreshオプション

Bladeで画面を組む従来型の構成では、`refresh` を有効にすると保存時にブラウザが自動更新されます。

```
laravel({
    input: 'resources/js/app.js',
    refresh: true,
})
```

`true` にしたとき監視対象になるのは `app/Livewire`、`app/View/Components`、`lang`、`resources/lang`、`resources/views`、`routes` の各ディレクトリです。`routes` が含まれているのは、Ziggyでルート情報をフロントへ渡す構成を想定しているため。監視対象を絞りたいときは、真偽値の代わりにパスの配列を渡します。

### エイリアス@の既定値と上書き手順

laravel-vite-pluginは `@` を `/resources/js` へ向けるエイリアスを自動で追加します。TypeScriptで `resources/ts` を使うなど別の場所に置きたい場合だけ、`resolve.alias` で上書きしてください。

Mixから移行するときの落とし穴として、エイリアスのパスはスラッシュで始める必要があります。`webpack.mix.js` に `resources/js` と書いていたなら、Vite側では `/resources/js` に直します。

## @viteディレクティブの記述位置と開発時のアクセス先

### @viteの正しい書き方と重複記述の害

Bladeのルートテンプレートの `<head>` 内に、次のように1回だけ書きます。

```
<!DOCTYPE html>
<head>
    {{-- ... --}}

    @vite(['resources/css/app.css', 'resources/js/app.js'])
</head>
```

CSSをJavaScript側でインポートしている構成なら、JSのパスを文字列で1つ渡すだけで足ります。

ときどき見かける誤りが、同じ `@vite` を `<head>` と `<body>` の両方に書いてしまうパターン。同一URLのscriptタグとlinkタグが重複して出力され、開発時には `@vite/client` まわりの警告が増えます。書く場所は `<head>` 内の1か所だけにしてください。

### 開発サーバのポート5173とアプリURLの役割分担

`npm run dev` で起動するViteの開発サーバは、既定でポート5173を使います（Vite公式の `server.port` の既定値）。ただし、そのポートが埋まっていた場合は自動的に次の空きポートへ繰り上がるため、5174や5175になることもあります。番号を固定したいなら `server.strictPort` を `true` にしてください（使用中なら起動せずに終了します）。

そして、ブラウザで開くのはこのURLではありません。開くのはLaravelアプリのURL、`php artisan serve` なら8000番、HerdやValetを使っているならそのホスト名です。Herd側で`.test`が解決される経路とHTTPS化の前提は、[Laravel Herdの構成とPHPバージョン切替の解説](https://www.issoh.co.jp/tech/details/17145/)で扱っています。Bladeが返したHTMLの `@vite` が開発サーバを検出し、HMR用のクライアントスクリプトを差し込む流れだからです。

5173番を直接開いた場合は、プラグインに同梱された案内ページが返ります。laravel-vite-pluginのソースでは、リクエストURLが `/index.html` のときに `dev-server-index.html` を読み込み、`{{ APP_URL }}` を実際の値へ置換して返す処理が入っています。表示されるのは「これはVite開発サーバです」という趣旨の説明と、設定済みの `APP_URL` の値。そこに出ているURLを開き直せば、アプリの画面にたどり着けます。

11.x系以降のアプリケーションスケルトンには `composer run dev` が同梱されています。公式ドキュメントは「LaravelとViteの開発サーバを両方起動する」と説明しますが、11.xの `composer.json` の実体は `concurrently` による4プロセス（`serve`、`queue:listen`、`pail`、`npm run dev`）の並走です。

```
composer run dev
```

### Blade専用の静的アセットを扱うassetsオプション

Bladeテンプレートからしか参照しない画像は、JavaScriptを経由しないためVite側が存在を認識できません。laravel-vite-pluginの3系では、`assets` オプションで対象を宣言する方式が導入されました。

```
laravel({
    input: 'resources/js/app.js',
    assets: ['resources/images/**', 'resources/fonts/**'],
})
```

これで `npm run build` の対象に含まれ、Blade側から `Vite::asset('resources/images/logo.png')` でバージョン付きURLを取得できます。3系より前は `import.meta.glob` をエントリポイントへ書く必要がありました。

フォントは同じグロブ指定ではなく別系統です。3.0.3以降、`laravel-vite-plugin/fonts` から `google()` などのプロバイダ関数をimportして `fonts` オプションへ渡す方式が追加され、Blade側は `@fonts` ディレクティブで受け取ります。

## VueとReactを組み合わせるときの追加設定

### Vueで必須のtransformAssetUrls設定

Vueを使う場合は、まずプラグインを追加します。

```
npm install --save-dev @vitejs/plugin-vue
```

ただし、そのまま並べるだけでは不十分でした。次の2つのオプションが要ります。

```
import { defineConfig } from 'vite';
import laravel from 'laravel-vite-plugin';
import vue from '@vitejs/plugin-vue';

export default defineConfig({
    plugins: [
        laravel(['resources/js/app.js']),
        vue({
            template: {
                transformAssetUrls: {
                    base: null,
                    includeAbsolute: false,
                },
            },
        }),
    ],
});
```

公式のコードコメントによれば、Vueプラグインは単一ファイルコンポーネント内のアセットURLをLaravelのWebサーバ向きに書き換えます。`base: null` はこれを止め、Laravel側のプラグインにVite開発サーバ向きの書き換えを任せる指定です。`includeAbsolute: false` は絶対URLをそのまま残し、`public` ディレクトリのファイルを期待どおり参照できるようにします。

### Reactプラグインの選択とVite 8での注意点

Reactの場合は `@vitejs/plugin-react` を追加し、`laravel()` と並べるだけで動きます。ただしプラグイン側の世代交代が進んでおり、選定基準はバージョンによって変わりました。詳細は[@vitejs/plugin-react とは？v6（Vite 8・Babel廃止）の導入設定と plugin-react-swc との違い](https://www.issoh.co.jp/tech/details/2680/)にまとめています。

Inertiaで一体化するか、APIとSPAに分けるかから迷っている場合は、[LaravelとReactの連携ガイド](https://www.issoh.co.jp/tech/details/2906/)で構成別の判断材料を整理しています。

## 本番ビルドとデプロイで壊れる典型パターン

### npm run buildの出力先とmanifest.jsonの実パス

本番用のビルドは `npm run build` です。出力先はLaravel側の既定で決まっており、フレームワークのソース（`Illuminate\Foundation\Vite`）ではビルドディレクトリが `build`、マニフェストのファイル名が `manifest.json` と定義されています。実体のパスは `public/build/manifest.json` です。

デプロイ時に `public/build` をまるごと転送しているか、あるいはデプロイ先でビルドを実行しているかを、まず確認してください。`.gitignore` に `public/build` を入れたまま「リポジトリを配置するだけ」のデプロイをしていると、この段階で必ず失敗します。

### Vite manifest not foundの原因切り分け

本番で画面を開いたときに出る「Vite manifest not found at:」という例外は、上のマニフェストファイルが見つからなかったという意味です。

フロント資産ではなくサーバ側のキャッシュが原因で反映されないときは、[Laravelのキャッシュクリア｜cache:clearとoptimize:clearの違いと本番デプロイの手順](https://www.issoh.co.jp/tech/details/17121/)で系統ごとの切り分け方を確認してください。

まずエラーメッセージに続くパスを読み、想定どおり `public/build/manifest.json` を指しているか確認します。次に、そのファイルがサーバ上に実在するかを見ます。ここまでで大半は解決するはず。それでも出るならWebサーバの実行ユーザに読み取り権限があるかを疑ってください。なお例外クラスの `ViteManifestNotFoundException` は `ViteException` を継承したまま非推奨（deprecated）になっており、ソース上も `ViteException` を使うよう指示されています。捕捉するなら `ViteException` 側に寄せます。

### publicディレクトリに残ったhotファイルによる白画面

マニフェストは正しいのに本番でアセットが読み込まれない、という場合はこちらを疑ってください。`npm run dev` を実行すると、Laravelは `public` 直下に `hot` というファイルを作ります。フレームワークのソースでも、hotファイルの位置は `public_path('/hot')` と定義されています。

このファイルが存在する間、`@vite` は「開発サーバが動いている」と判断し、本番環境であってもローカルの開発サーバのURLを出力し続けます。結果として、外部からアクセスしたユーザーにはCSSもJSも読み込まれない画面が返ります。デプロイ手順に削除を組み込んでおくのが確実です。

```
rm -f public/hot
```

### CDN配信時のASSET\_URL指定

ビルド成果物をアプリ本体とは別ドメイン（CDNなど）へ置く場合は、`.env` に `ASSET_URL` を設定します。設定するとアセットのURLがその値で前置きされ、`https://cdn.example.com/build/assets/app.9dce8d17.js` のような形になります。ただしコード中に絶対URLで書いたパスはVite側で書き換えられないため、前置きの対象にもなりません。

## SSRとテスト実行時のVite設定

### SSRエントリポイントの指定とビルドコマンド

LaravelでサーバサイドレンダリングをするときのViteの役割は、SSR用エントリポイントを別途ビルドすることです。Node側のサーバ実装を自分で書き起こす必要はありません。`resources/js/ssr.js` を作り、プラグインに渡します。

```
laravel({
    input: 'resources/js/app.js',
    ssr: 'resources/js/ssr.js',
}),
```

ビルドスクリプトはSSR分を追加した形にしておきましょう。`"build": "vite build && vite build --ssr"` と書いておけば、SSR側のビルド漏れを防げます。生成物は `bootstrap/ssr/ssr.js` に出力され、`node bootstrap/ssr/ssr.js` で起動します。

### Inertia利用時のSSRサーバ起動

InertiaでSSRを組んでいる場合は、Node.jsのコマンドを直接叩く代わりにArtisanコマンドが使えます。

```
php artisan inertia:start-ssr
```

プロセス管理をSupervisorなどに任せるとき、この形のほうがLaravel側の設定と揃えやすくなります。なおLaravelのスターターキットには、Inertia SSRとViteの設定が最初から含まれています。スターターキットの選択肢は2026年に変わったので、新規構築なら[Laravel Breeze・Jetstreamはなぜ非推奨に？スターターキットへの移行と代替案](https://www.issoh.co.jp/tech/details/10351/)で現行の選び方を確認してください。

### テストでViteを無効化するwithoutVite

FeatureテストでBladeを描画すると、Laravelはアセットの解決を試みます。ビルドも開発サーバも無い状態でテストを回せば、ここでマニフェスト由来の例外が出るわけです。回避するにはテスト内で `$this->withoutVite();` を呼びます。全テストで無効化したい場合は、基底の `TestCase` の `setUp` で呼んでおけば済みます。

フロント側のユニットテストをVitestで書いているなら、実行環境の設定は別途必要。[Vitest 4の新機能と移行ガイド](https://www.issoh.co.jp/tech/details/9465/)にブラウザモードの正式化を含めた変更点をまとめています。

## Laravel MixからViteへ移行する手順と判断基準

### 移行時に書き換える4か所

公式の移行ガイドに沿うと、実作業は次の4か所に集約されます。

- **package.jsonのscripts**：`mix` 系のスクリプト群を `"dev": "vite"` と `"build": "vite build"` の2つに置き換えます。
- **JavaScriptのモジュール形式**：ViteはESモジュールのみを扱うため、`require()` をすべて `import` へ書き換えます。ここが移行作業の実質的な山場です。
- **環境変数の接頭辞**：`.env` でフロントへ露出させている変数を `MIX_` から `VITE_` へ変更します。参照側も `import.meta.env.VITE_XXX` の形になります。
- **エイリアスのパス**：先述のとおり、スラッシュ始まりに直します。

### 移行を急がなくてよい場合の条件

稼働中のプロジェクトでMixが問題なく動いており、フロントの変更頻度が低いなら、移行を今すぐ行う必要はありません。Mixは非推奨扱いですが即座に動かなくなるものではなく、移行作業の中心である `require()` の書き換えは、コードベースが大きいほど回帰リスクを伴うからです。

逆に、Node.jsのメジャー更新でwebpackまわりのビルドが通らなくなり始めているなら、そこが実質的な期限です。ビルドが壊れてから移行すると、修復と移行を同時に進めることになります。フロントのライブラリを頻繁に追加・更新するプロジェクトでも前倒しの価値があります。Mixは公式ドキュメントから実質的に切り離されており、詰まったときに参照できる一次情報が減り続けるからです。

## SailやDocker環境でHMRが効かないときの設定

### WSL2上のSailで指定するhmr.host

Laravel SailをWSL2で動かしている場合、ブラウザから開発サーバへの接続がうまくいかず、HMRが効かないことがあります。公式ドキュメントが案内している対処は、HMRのホストを明示することです。

```
export default defineConfig({
    // ... plugins などは既存のまま
    server: {
        hmr: {
            host: 'localhost',
        },
    },
});
```

### ファイル変更が検知されない場合のポーリング設定

上の設定を入れても保存が反映されないときは、コンテナ内のファイル監視がホスト側の変更を拾えていない可能性があります。この場合はViteの `server.watch.usePolling` を有効にします。

```
server: {
    watch: {
        usePolling: true,
    },
},
```

ポーリングは常時ファイルを走査するためCPU使用率が上がります。`ignored` で `node_modules` や `vendor` を除外し、監視対象を絞ったうえで使ってください。

## よくある質問

### Viteの開発サーバのポートを5173に固定できますか？

できます。`server.strictPort` を `true` にすると、5173が使用中のときに次のポートへ繰り上がらず、その場で終了します。既定の `false` のままだと自動で空きポートを探すため、複数プロジェクトを並行して立ち上げているとポート番号が変動します。

### 画面ごとにエントリポイントを分けられますか？

分けられます。laravel-vite-pluginは複数のエントリポイント指定に対応しており、`laravel([...])` に配列で列挙したうえで、Blade側の `@vite` でも必要なものだけを配列で指定します。管理画面と公開画面でJavaScriptを分離したい場合はこの形です。

### .envの値をJavaScript側から読めますか？

読めますが、接頭辞が `VITE_` のものに限られます。`.env` に `VITE_SENTRY_DSN_PUBLIC=http://example.com` のように書き、JavaScript側では `import.meta.env.VITE_SENTRY_DSN_PUBLIC` で参照します。接頭辞のない変数はビルド結果に含まれません。逆に言えば、`VITE_` を付けた値はブラウザから見えるので、秘匿情報を入れてはいけません。

### webpack.mix.jsの設定はそのまま移せますか？

そのままは移せません。公式の移行ガイド自体が冒頭で「Sassのコンパイルなど、Mixのすべてのユースケースを網羅していない」と断っています。エントリポイントとエイリアスは対応関係が明確ですが、Mix独自のメソッドで組んだ処理はVite側のプラグインで組み直す前提で見積もってください。

### 本番環境でもViteの開発サーバを動かす必要がありますか？

不要です。`npm run dev` はローカル開発用で、本番に必要なのは `npm run build` が生成した `public/build` 配下の成果物だけです。

## 関連記事

- [Laravel Breeze・Jetstreamはなぜ非推奨に？スターターキット（React/Vue/Livewire）への移行と代替案](https://www.issoh.co.jp/tech/details/10351/)
- [LaravelとReactの連携ガイド｜環境構築・SPA・認証・デプロイと選び方](https://www.issoh.co.jp/tech/details/2906/)
- [@vitejs/plugin-react とは？v6（Vite 8・Babel廃止）の導入設定と plugin-react-swc との違い](https://www.issoh.co.jp/tech/details/2680/)
- [Viteを使ったReactプロジェクトのセットアップ方法を徹底解説](https://www.issoh.co.jp/tech/details/3587/)
- [Vitest 4の新機能と移行ガイド｜ブラウザモード正式化・VRT・最新バージョン](https://www.issoh.co.jp/tech/details/9465/)

---

出典: [Laravel Viteの使い方｜@viteの書き方と本番ビルドの落とし穴](<https://www.issoh.co.jp/tech/details/3251/>)（株式会社一創）
