本文へ移動
Laravel Tips

CSS と JavaScript をまとめる(Vite)

CSS と JavaScript を1つにまとめて速く配るための道具 Vite の入れ方、設定、Blade での読みこみ、フォントやテストでの使い方を説明します。

Vite(ヴィート)は、画面まわりの道具です。書きかえたファイルをすぐブラウザへ反映してくれる開発用の機能と、本番へ出すために CSS や JavaScript を1つにまとめる機能(バンドル)を持っています。Laravel には、公式のプラグインと、Blade で読みこむための命令が用意されています。ふつうは、アプリの CSS や JavaScript をまとめるために使います。

インストールと設定#

補足

ここでは、Laravel の Vite プラグインを手で入れて設定する方法を説明します。Laravel のスターターキットには、この準備がもう入っています。Laravel と Vite をいちばん早く始めるには、スターターキットを使います。

Node を入れる#

Vite を動かす前に、Node.js(16 以上)と NPM(JavaScript の部品を入れるための道具)が入っている必要があります。次のコマンドで確かめます。

bash
node -v
npm -v

Node の公式サイトから、画面の案内に従って入れられます。Laravel Sail(Laravel を Docker で動かす道具)を使っているなら、Sail 経由でも動かせます。

bash
./vendor/bin/sail node -v
./vendor/bin/sail npm -v

Vite とプラグインを入れる#

新しい Laravel のアプリには、いちばん上のフォルダに package.json があります。Vite とプラグインに要るものは、もう入っています。次のコマンドで、画面まわりの部品を入れます。

bash
npm install

Vite を設定する#

Vite の設定は、プロジェクトのいちばん上にある vite.config.js に書きます。自由に変えられ、@vitejs/plugin-react・@sveltejs/vite-plugin-svelte・@vitejs/plugin-vue など、ほかのプラグインも足せます。

Laravel のプラグインには、入り口になるファイル(エントリーポイント)を教えます。JavaScript でも CSS でもよく、TypeScript・JSX・TSX・Sass のような、変換が要る言語も使えます。

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

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

SPA(1枚のページの中で画面を切りかえるアプリ。Inertia で作るものも含む)では、CSS を入り口にしないほうがうまく動きます。

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

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

代わりに、CSS は JavaScript から読みこみます。ふつうは resources/js/app.js に書きます。

js
import './bootstrap';
import '../css/app.css'; // この行を足す

入り口は複数にもできます。SSR(下の節で説明します)用の入り口も決められます。

HTTPS の開発サーバーを使う#

手元の開発用のサーバーが HTTPS で動いていると、Vite の開発サーバーにつなげないことがあります。

Laravel Herd や Laravel Valet は、どちらも手元で Laravel を動かす道具です。Herd でサイトを HTTPS にしている場合や、Valet で secure コマンドを実行している場合は、プラグインが、作られた TLS 証明書(HTTPS に要る証明書)を自動で見つけて使います。

サイトのホスト名が、アプリのフォルダ名と違うときは、vite.config.js にホスト名を書きます。

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

export default defineConfig({
    plugins: [
        laravel({
            // ...
            detectTls: 'my-app.test', // この行を足す
        }),
    ],
});

ほかの Web サーバーを使うときは、信頼できる証明書を作り、Vite にその場所を教えます。

js
// ...
import fs from 'fs'; // この行を足す

const host = 'my-app.test'; // この行を足す

export default defineConfig({
    // ...
    server: { // ここから足す
        host,
        hmr: { host },
        https: {
            key: fs.readFileSync(`/path/to/${host}.key`),
            cert: fs.readFileSync(`/path/to/${host}.crt`),
        },
    }, // ここまで
});

信頼できる証明書を作れないときは、@vitejs/plugin-basic-ssl を入れて設定できます。信頼されない証明書を使うと、ブラウザが警告を出します。npm run dev を動かしたときに画面へ出る「Local」のリンクを開き、開発サーバーへの接続を許可してください。

WSL2 の Sail で開発サーバーを動かす#

Windows の WSL2(Windows の中で Linux を動かすしくみ)の上で Laravel Sail を使い、Vite の開発サーバーを動かすときは、ブラウザが開発サーバーとやりとりできるように、vite.config.js に次を足します。

js
// ...

export default defineConfig({
    // ...
    server: { // ここから足す
        hmr: {
            host: 'localhost',
        },
    }, // ここまで
});

開発サーバーが動いていても、ファイルの変更がブラウザに反映されないときは、Vite の server.watch.usePolling オプションの設定も要ることがあります。

スクリプトとスタイルを読みこむ#

入り口を決めたら、アプリのいちばん外側のテンプレートの <head> に、@vite() という Blade のディレクティブ(@ で始まる命令)を書いて読みこみます。

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

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

CSS を JavaScript から読みこむなら、JavaScript の入り口だけを書けば足ります。

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

    @vite('resources/js/app.js')
</head>

@vite は、Vite の開発サーバーが動いていれば、自動で見つけて、画面を書きかえるための部品(Vite クライアント。ファイルを直すとすぐ画面に反映されるしくみ)を入れます。本番用にビルド(ファイルをまとめる作業)したあとは、まとめたファイルを読みこみます。JavaScript から読みこんだ CSS も、いっしょに読みこまれます。まとめたファイルの名前には、版の印(中身が変わるとファイル名も変わるように付ける印)が付いています。

まとめたファイルを置く場所を、@vite の2つ目の引数で指定することもできます。

blade
<!doctype html>
<head>
    {{-- 指定する場所は、公開フォルダからの相対 --}}

    @vite('resources/js/app.js', 'vendor/courier/build')
</head>

中身をそのまま埋めこむ#

ファイルへのリンクではなく、ファイルの中身そのものを、ページに入れたいことがあります。たとえば、PDF を作る道具へ HTML を渡すときです。Vite ファサード(Route::get() のように、クラス名と :: で機能を呼べる窓口)の content メソッドで、中身を出せます。

blade
@use('Illuminate\Support\Facades\Vite')

<!doctype html>
<head>
    {{-- ... --}}

    <style>
        {!! Vite::content('resources/css/app.css') !!}
    </style>
    <script>
        {!! Vite::content('resources/js/app.js') !!}
    </script>
</head>

Vite を動かす#

動かし方は2つあります。1つ目は、dev コマンドで開発サーバーを動かす方法です。手元で作っているあいだに便利で、ファイルの変更を見つけて、開いているブラウザへすぐ反映します。

2つ目は、build コマンドです。アプリのファイルをまとめて版の印を付け、本番へ出す準備をします。

bash
# 開発サーバーを動かす
npm run dev

# 本番用にまとめ、版の印を付ける
npm run build

WSL2 の Sail で開発サーバーを動かすときは、前の節の設定が要ることがあります。

JavaScript を使う#

別名(エイリアス)#

Laravel のプラグインは、@ という別名を、はじめから用意しています。アプリのファイルを読みこむときに便利です。

js
{
    '@' => '/resources/js'
}

@ の別名は、vite.config.js で上書きできます。

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

export default defineConfig({
    plugins: [
        laravel(['resources/ts/app.tsx']),
    ],
    resolve: {
        alias: {
            '@': '/resources/ts',
        },
    },
});

Vue#

画面を Vue(JavaScript の画面づくりの道具)で作るときは、@vitejs/plugin-vue というプラグインも入れます。

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

vite.config.js に、プラグインを足します。Laravel と使うときは、いくつか追加の設定が要ります。

js
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: {
                    // The Vue plugin will re-write asset URLs, when referenced
                    // in Single File Components, to point to the Laravel web
                    // server. Setting this to `null` allows the Laravel plugin
                    // to instead re-write asset URLs to point to the Vite
                    // server instead.
                    base: null,

                    // The Vue plugin will parse absolute URLs and treat them
                    // as absolute paths to files on disk. Setting this to
                    // `false` will leave absolute URLs un-touched so they can
                    // reference assets in the public directory as expected.
                    includeAbsolute: false,
                },
            },
        }),
    ],
});

2つの設定の意味は、次のとおりです。

設定 説明
base: null Vue がファイルの URL を Laravel のサーバーへ向けて書きかえないようにし、Laravel のプラグインが Vite のサーバーへ向けて書きかえられるようにする
includeAbsolute: false / で始まる絶対の URL を、ディスク上のファイルの場所として扱わず、そのままにする。公開フォルダのファイルを、思ったとおりに指せる

補足

Laravel のスターターキットには、Laravel・Vue・Vite の正しい設定が入っています。

React#

画面を React(JavaScript の画面づくりの道具)で作るときは、@vitejs/plugin-react を入れます。

bash
npm install --save-dev @vitejs/plugin-react

vite.config.js に、プラグインを足します。

js
import { defineConfig } from 'vite';
import laravel from 'laravel-vite-plugin';
import react from '@vitejs/plugin-react';

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

JSX(JavaScript の中に HTML のような書き方をする記法)を含むファイルは、拡張子を .jsx か .tsx にします。入り口の名前も、必要なら直します。

さらに、いつもの @vite といっしょに、@viteReactRefresh というディレクティブも書きます。

blade
@viteReactRefresh
@vite('resources/js/app.jsx')

@viteReactRefresh は、@vite より前に書かなければなりません。

補足

Laravel のスターターキットには、Laravel・React・Vite の正しい設定が入っています。

Svelte#

画面を Svelte(JavaScript の画面づくりの道具)で作るときは、@sveltejs/vite-plugin-svelte を入れます。

bash
npm install --save-dev @sveltejs/vite-plugin-svelte

vite.config.js に、プラグインを足します。

js
import { svelte } from '@sveltejs/vite-plugin-svelte';
import laravel from 'laravel-vite-plugin';
import { defineConfig } from 'vite';

export default defineConfig({
  plugins: [
    laravel({
      input: ['resources/js/app.ts'],
      ssr: 'resources/js/ssr.ts',
      refresh: true,
    }),
    svelte(),
  ],
});

補足

Laravel のスターターキットには、Laravel・Svelte・Vite の正しい設定が入っています。

Inertia#

Laravel の Vite プラグインには、Inertia(Laravel と JavaScript の画面づくりをつなぐ道具)のページ部品を見つける resolvePageComponent という関数があります。次は Vue 3 で使う例ですが、React や Svelte でも使えます。

js
import { createApp, h } from 'vue';
import { createInertiaApp } from '@inertiajs/vue3';
import { resolvePageComponent } from 'laravel-vite-plugin/inertia-helpers';

createInertiaApp({
  resolve: (name) => resolvePageComponent(`./Pages/${name}.vue`, import.meta.glob('./Pages/**/*.vue')),
  setup({ el, App, props, plugin }) {
    createApp({ render: () => h(App, props) })
      .use(plugin)
      .mount(el)
  },
});

Inertia で、Vite のコード分割(ファイルを小さく分けて、要るときに読みこむしくみ)を使うなら、下の「ファイルの先読み」を設定するのがおすすめです。

補足

Laravel のスターターキットには、Laravel・Inertia・Vite の正しい設定が入っています。

URL の扱い#

Vite を使うとき、HTML・CSS・JavaScript の中でファイルを指すには、気をつけることがあります。

まず、/taylor.png のような絶対のパスで指したファイルは、Vite がまとめません。そのため、公開フォルダに置いておく必要があります。CSS だけの入り口(CSS のファイルをそのまま入り口にしたもの)では、絶対のパスを使わないでください。開発中、ブラウザはそのファイルを公開フォルダではなく、CSS を配っている Vite の開発サーバーへ探しにいくからです。

相対のパス(../ などで、いま書いているファイルから見た場所を示すもの)で指したファイルは、書かれているファイルから見た場所として扱われます。Vite が、パスの書きかえ・版の印付け・まとめをしてくれます。

次のフォルダ構成で考えます。

text
public/
  taylor.png
resources/
  js/
    Pages/
      Welcome.vue
  images/
    abigail.png

絶対と相対の扱いの違いは、次のとおりです。

html
<!-- This asset is not handled by Vite and will not be included in the build -->
<img src="/taylor.png">

<!-- This asset will be re-written, versioned, and bundled by Vite -->
<img src="../../images/abigail.png">

スタイルシートを使う#

補足

Laravel のスターターキットには、Tailwind(CSS の道具)と Vite の正しい設定が入っています。スターターキットを使わずに Tailwind を使うなら、Tailwind の公式の Laravel 向けの案内を見てください。

Laravel のアプリには、はじめから Tailwind と、正しく設定された vite.config.js が入っています。ですから、Vite の開発サーバーを動かすか、dev という Composer コマンド(Laravel と Vite の両方の開発サーバーを動かす)を実行するだけで始められます。

bash
composer run dev

アプリの CSS は、resources/css/app.css に書きます。

フォントを使う#

Laravel の Vite プラグインを使うと、フォントを自分のサーバーから、軽くした形で配れます。フォントを設定すると、プラグインは次のことをします。

  • 必要なフォントのファイルを見つけて、Vite のファイルとして出す
  • フォントの CSS を作る
  • フォントの一覧(マニフェスト)を書く

この一覧は、Blade の @fonts ディレクティブが使います。

フォントを設定するには、laravel-vite-plugin/fonts から、提供元ごとの関数を読みこみ、Laravel プラグインの fonts に並べます。

js
import { defineConfig } from 'vite';
import laravel from 'laravel-vite-plugin';
import { google } from 'laravel-vite-plugin/fonts';

export default defineConfig({
    plugins: [
        laravel({
            input: 'resources/js/app.js',
            fonts: [
                google('Inter', {
                    alias: 'sans',
                    weights: [400, 500, 600, 700],
                    styles: ['normal', 'italic'],
                    subsets: ['latin'],
                    display: 'swap',
                    preload: [
                        { weight: 400 },
                        { weight: 700 },
                    ],
                    fallbacks: ['system-ui', 'sans-serif'],
                }),
            ],
        }),
    ],
});

この例では、Inter というフォントを、sans という別名で使えます。プラグインは、--font-sans という CSS の変数と、作ったフォントの並びを適用する .font-sans というクラスを作ります。

フォントの提供元#

Laravel の Vite プラグインには、Google Fonts・Bunny Fonts・Fontsource・手元のフォント用の関数が入っています。

js
import { defineConfig } from 'vite';
import laravel from 'laravel-vite-plugin';
import { bunny, fontsource, google, local } from 'laravel-vite-plugin/fonts';

export default defineConfig({
    plugins: [
        laravel({
            input: 'resources/js/app.js',
            fonts: [
                google('Inter', { alias: 'sans' }),
                bunny('Figtree', { alias: 'body' }),
                fontsource('JetBrains Mono', { alias: 'mono' }),
                local('Brand Sans', {
                    alias: 'brand',
                    src: 'resources/fonts/brand-sans',
                }),
            ],
        }),
    ],
});
関数 説明
google Google Fonts のフォントを使う
bunny Bunny Fonts のフォントを使う
fontsource 入れた Fontsource のパッケージから、フォントを読む
local 手元のフォントのファイルを使う

fontsource は、入っている Fontsource のパッケージからフォントを読みます。パッケージの名前は、ふつうフォントの名前から決まります(JetBrains Mono なら @fontsource/jetbrains-mono)。違う名前のパッケージを使うときは、package オプションで教えます。

手元のフォント#

手元のフォントを使うときは、src オプションに、フォントのファイル1つ・フォルダ・グロブ(* で複数のファイルを指す書き方)のどれかを書けます。プラグインが、使えるフォントのファイルを見つけ、ファイル名から、太さと形(斜めかどうか)を推しはかります。

js
local('Brand Sans', {
    alias: 'brand',
    src: 'resources/fonts/brand-sans/*.woff2',
})

使える種類を細かく決めたいときは、variants オプションで、1つずつ書きます。

js
local('Brand Sans', {
    alias: 'brand',
    variants: [
        { src: 'resources/fonts/BrandSans-Regular.woff2', weight: 400 },
        { src: 'resources/fonts/BrandSans-Italic.woff2', weight: 400, style: 'italic' },
        { src: ['resources/fonts/BrandSans-Bold.woff2', 'resources/fonts/BrandSans-Bold.ttf'], weight: 700 },
    ],
})

フォントのオプション#

提供元によって、フォントの CSS を調整する、次のオプションが使えます。

オプション 説明
alias Blade の @fonts で使う名前。省略すると、フォントの名前から作る
variable 作られる CSS の変数。省略すると --font-{alias}
weights 取ってくる太さ。ネットのフォントと Fontsource 用。省略すると [400]
styles 取ってくる形。ネットのフォントと Fontsource 用。省略すると ['normal']
subsets 取ってくる文字の範囲。ネットのフォントと Fontsource 用。省略すると ['latin']
display font-display(読みこみ中の見え方)の値。省略すると swap
preload 先読みする WOFF2 のフォント。true・false・{ weight, style } の配列
fallbacks 代わりに使うフォントを、フォントの並びの後ろへ足す
optimizedFallbacks fontaine パッケージ(入れるかは自由)で、大きさをそろえた代わりのフォントを作ろうとする。省略すると true

最適化した代わりのフォントには、fontaine パッケージが要ります。はじめは入っていないので、使いたいときは、開発用として入れます。

bash
npm install --save-dev fontaine

fontaine が入っていないときや、フォントのファイルを読めないときは、そのフォントの最適化した代わりを作らずに、fallbacks で決めたフォントを使いつづけます。

手元のフォントは、上で説明した src か variants から探します。weights・styles・subsets は使いません。

Blade とルートで使う#

Blade だけで使うファイルを Vite に任せる#

JavaScript や CSS の中で指したファイルは、Vite が自動で処理して、版の印を付けます。Blade だけで作るアプリで、Blade のテンプレートの中だけで指す静的なファイルも、Vite に処理させられます。

そのためには、プラグインの assets オプションに、ファイルを書いて、Vite に教えます。これは、Vite::asset で直接指したい静的なファイル向けです。フォントの CSS や先読みのリンクを作らせたいときは、前の節の fonts オプションを使います。

たとえば、resources/images の画像と resources/fonts のフォントを、全部処理させたいときは、次のように書きます。

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

npm run build を動かすと、これらのファイルが処理されます。Blade のテンプレートでは、Vite::asset メソッドで、版の印が付いた URL を取り出せます。

blade
<img src="{{ Vite::asset('resources/images/logo.png') }}">

補足

Laravel の Vite プラグインのバージョン 3 より前は、静的なファイルを、入り口の中で import.meta.glob を使って読みこむ必要がありました。Vite 8 の変更のため、assets オプションができました。

保存したら画面を更新する#

Blade で、サーバー側で画面を作るアプリでは、ビューのファイルを直したときに、ブラウザを自動で再読みこみさせると、作業が楽になります。refresh オプションを true にします。

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

export default defineConfig({
    plugins: [
        laravel({
            // ...
            refresh: true,
        }),
    ],
});

refresh が true で、npm run dev を動かしているあいだは、次のフォルダのファイルを保存すると、ブラウザがページ全体を読みこみなおします。

  • app/Livewire/**
  • app/View/Components/**
  • lang/**
  • resources/lang/**
  • resources/views/**
  • routes/**

routes/** を見ているのは、Ziggy(JavaScript からルートのリンクを作る道具)を使う場合のためです。

この決まりの場所が合わないときは、見る場所の一覧を自分で書けます。

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

export default defineConfig({
    plugins: [
        laravel({
            // ...
            refresh: ['resources/views/**'],
        }),
    ],
});

この機能は、vite-plugin-full-reload というパッケージを使っていて、細かい調整もできます。必要なら、config を渡します。

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

export default defineConfig({
    plugins: [
        laravel({
            // ...
            refresh: [{
                paths: ['path/to/watch/**'],
                config: { delay: 300 }
            }],
        }),
    ],
});

Blade で使う別名#

JavaScript では、よく使うフォルダに別名(JavaScript の節の「別名」)を付けることが多いです。Blade でも、Illuminate\Support\Facades\Vite の macro メソッドで、別名を作れます。マクロ(あとから足す、自分用のメソッド)は、サービスプロバイダの boot メソッドで決めるのがふつうです。

php
/**
 * Bootstrap any application services.
 */
public function boot(): void
{
    Vite::macro('image', fn (string $asset) => $this->asset("resources/images/{$asset}"));
}

決めたあとは、テンプレートで呼べます。たとえば、上の image で、resources/images/logo.png を指せます。

blade
<img src="{{ Vite::image('logo.png') }}" alt="Laravel Logo">

ファイルの先読み#

Vite のコード分割を使った SPA では、ページを移るたびに、必要なファイルを取りにいきます。そのせいで、画面の表示が遅れることがあります。Laravel には、最初にページを読みこんだときに、JavaScript と CSS のファイルを先に取っておく機能があります。

サービスプロバイダの boot メソッドで、Vite::prefetch を呼びます。

php
<?php

namespace App\Providers;

use Illuminate\Support\Facades\Vite;
use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
    /**
     * Register any application services.
     */
    public function register(): void
    {
        // ...
    }

    /**
     * Bootstrap any application services.
     */
    public function boot(): void
    {
        Vite::prefetch(concurrency: 3);
    }
}

この例では、ページを読みこむたびに、最大 3 つまでのファイルを同時に取っておきます。数は調整できます。数を決めずに、全部を一度に取りにいかせることもできます。

php
/**
 * Bootstrap any application services.
 */
public function boot(): void
{
    Vite::prefetch();
}

はじめは、ページの load イベント(ページの読みこみが終わったときに起きる知らせ)が起きたときに、先読みが始まります。始める時を変えたいときは、Vite が待つイベントの名前を決められます。

php
/**
 * Bootstrap any application services.
 */
public function boot(): void
{
    Vite::prefetch(event: 'vite:prefetch');
}

こうすると、window オブジェクトに vite:prefetch イベントを自分で送ったときに、先読みが始まります。たとえば、ページを読みこんでから3秒後に始めるには、次のように書きます。

html
<script>
    addEventListener('load', () => setTimeout(() => {
        dispatchEvent(new Event('vite:prefetch'))
    }, 3000))
</script>

別のドメインから配る(ベース URL)#

Vite でまとめたファイルを、CDN(世界中のサーバーから速く配るサービス)のように、アプリとは別のドメインから配るときは、.env に ASSET_URL を書きます。

ini
ASSET_URL=https://cdn.example.com

決めると、書きかえられたファイルの URL の前に、その値が付きます。

text
https://cdn.example.com/build/assets/app.9dce8d17.js

なお、前の「URL の扱い」のとおり、絶対の URL は Vite が書きかえないので、前には付きません。

環境変数#

.env で、名前の頭に VITE_ を付けた環境変数(環境ごとに変える設定値)は、JavaScript の中に入れられます。

ini
VITE_SENTRY_DSN_PUBLIC=http://example.com

入れた値は、import.meta.env から読めます。

js
import.meta.env.VITE_SENTRY_DSN_PUBLIC

テストで Vite を止める#

Laravel の Vite は、テストを動かしているときも、ファイルを探そうとします。そのため、Vite の開発サーバーを動かすか、ファイルをビルドしておく必要があります。

テストのあいだ、Vite をにせものに置きかえたいときは、withoutVite メソッドを呼びます。Laravel の TestCase を引きつぐテストで使えます。

Pest の場合は、次のとおりです。

php
test('without vite example', function () {
    $this->withoutVite();

    // ...
});

PHPUnit の場合は、次のとおりです。

php
use Tests\TestCase;

class ExampleTest extends TestCase
{
    public function test_without_vite_example(): void
    {
        $this->withoutVite();

        // ...
    }
}

すべてのテストで止めたいときは、土台になる TestCase クラスの setUp メソッドで withoutVite を呼びます。

php
<?php

namespace Tests;

use Illuminate\Foundation\Testing\TestCase as BaseTestCase;

abstract class TestCase extends BaseTestCase
{
    // ここから足す
    protected function setUp(): void
    {
        parent::setUp();

        $this->withoutVite();
    }
    // ここまで
}

SSR(サーバー側で画面を作る)#

Laravel の Vite プラグインを使うと、SSR(サーバー側で、JavaScript の画面をあらかじめ HTML にして返すしくみ)を、かんたんに始められます。まず、resources/js/ssr.js に SSR の入り口を作り、プラグインの設定に書きます。

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

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

SSR の入り口のビルドを忘れないように、package.json の build スクリプトを、SSR のビルドもする形に変えておくのがおすすめです。

json
"scripts": {
     "dev": "vite",
     "build": "vite build && vite build --ssr"
}

そのあと、次のコマンドで、ビルドと SSR サーバーの起動ができます。

bash
npm run build
node bootstrap/ssr/ssr.js

Inertia の SSR を使うなら、代わりに inertia:start-ssr という Artisan コマンドで、SSR サーバーを起動できます。

bash
php artisan inertia:start-ssr

補足

Laravel のスターターキットには、Laravel・Inertia の SSR・Vite の正しい設定が入っています。

script と style のタグの属性#

CSP の nonce#

CSP(Content Security Policy。ページが読みこんでよいものを制限して、攻撃を防ぐしくみ)の一部として、script や style のタグに nonce 属性(その場かぎりの合言葉)を付けたいときは、自分で作ったミドルウェア(リクエストが処理に届く前に、間に入って確かめる処理)の中で、useCspNonce メソッドを使います。nonce は、自動で作ることも、自分で決めることもできます。

php
<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Vite;
use Symfony\Component\HttpFoundation\Response;

class AddContentSecurityPolicyHeaders
{
    /**
     * Handle an incoming request.
     *
     * @param  \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response)  $next
     */
    public function handle(Request $request, Closure $next): Response
    {
        Vite::useCspNonce();

        return $next($request)->withHeaders([
            'Content-Security-Policy' => "script-src 'nonce-".Vite::cspNonce()."'",
        ]);
    }
}

useCspNonce を呼ぶと、Laravel が作る、すべての script と style のタグに、nonce 属性が自動で付きます。

ほかの場所でも nonce が要るとき(たとえば、スターターキットに入っている、Ziggy の @route ディレクティブ)は、cspNonce メソッドで取り出せます。

blade
@routes(nonce: Vite::cspNonce())

すでに使いたい nonce があるなら、useCspNonce に渡します。

php
Vite::useCspNonce($nonce);

SRI(ファイルが書きかえられていないかの確認)#

Vite の一覧(マニフェスト)に、ファイルの integrity(ファイルの中身から作った確認用の値)があると、Laravel は、作る script と style のタグに integrity 属性を自動で付けます。ファイルが書きかえられていないことを、ブラウザに確かめさせるためです(Subresource Integrity)。Vite は、はじめは integrity を一覧に入れません。vite-plugin-manifest-sri という NPM のプラグインを入れると、入るようになります。

bash
npm install --save-dev vite-plugin-manifest-sri

vite.config.js で、プラグインを使います。

js
import { defineConfig } from 'vite';
import laravel from 'laravel-vite-plugin';
import manifestSRI from 'vite-plugin-manifest-sri'; // この行を足す

export default defineConfig({
    plugins: [
        laravel({
            // ...
        }),
        manifestSRI(), // この行を足す
    ],
});

必要なら、integrity を探す、一覧の中のキーの名前を変えられます。

php
use Illuminate\Support\Facades\Vite;

Vite::useIntegrityKey('custom-integrity-key');

この自動の検出を、完全に止めたいときは、useIntegrityKey に false を渡します。

php
Vite::useIntegrityKey(false);

そのほかの属性#

script や style のタグに、data-turbo-track のような別の属性を足したいときは、useScriptTagAttributes と useStyleTagAttributes を使います。サービスプロバイダから呼ぶのがふつうです。

php
use Illuminate\Support\Facades\Vite;

Vite::useScriptTagAttributes([
    'data-turbo-track' => 'reload', // 属性に値を指定する
    'async' => true, // 値のない属性を指定する
    'integrity' => false, // 付くはずの属性を外す
]);

Vite::useStyleTagAttributes([
    'data-turbo-track' => 'reload',
]);

条件で付けたいときは、関数を渡せます。関数は、ファイルの元の場所・URL・一覧のチャンク(まとまり)・一覧の全体を受け取ります。

php
use Illuminate\Support\Facades\Vite;

Vite::useScriptTagAttributes(fn (string $src, string $url, array|null $chunk, array|null $manifest) => [
    'data-turbo-track' => $src === 'resources/js/app.js' ? 'reload' : false,
]);

Vite::useStyleTagAttributes(fn (string $src, string $url, array|null $chunk, array|null $manifest) => [
    'data-turbo-track' => $chunk && $chunk['isEntry'] ? 'reload' : false,
]);

注意

Vite の開発サーバーが動いているあいだは、$chunk と $manifest は null になります。

細かく変える#

Laravel の Vite プラグインは、たいていのアプリに合う決まりで動きます。でも、動きを変えたいことがあります。そのために、@vite の代わりに使える、次のメソッドがあります。

blade
<!doctype html>
<head>
    {{-- ... --}}

    {{
        Vite::useHotFile(storage_path('vite.hot')) // "hot" ファイルの場所を変える
            ->useBuildDirectory('bundle') // ビルドしたものを置くフォルダを変える
            ->useManifestFilename('assets.json') // 一覧のファイル名を変える
            ->withEntryPoints(['resources/js/app.js']) // 入り口を指定する
            ->createAssetPathsUsing(function (string $path, ?bool $secure) { // ビルドしたファイルの URL の作り方を変える
                return "https://cdn.example.com/{$path}";
            })
    }}
</head>
メソッド 説明
useHotFile 「hot」ファイルの場所を変える
useBuildDirectory ビルドしたものを置くフォルダを変える
useManifestFilename 一覧のファイル名を変える
withEntryPoints 入り口を指定する
createAssetPathsUsing ビルドしたファイルの URL の作り方を変える

vite.config.js にも、同じ設定を書きます。

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

export default defineConfig({
    plugins: [
        laravel({
            hotFile: 'storage/vite.hot', // "hot" ファイルの場所を変える
            buildDirectory: 'bundle', // ビルドしたものを置くフォルダを変える
            input: ['resources/js/app.js'], // 入り口を指定する
        }),
    ],
    build: {
      manifest: 'assets.json', // 一覧のファイル名を変える
    },
});

開発サーバーの CORS#

Vite の開発サーバーからファイルを取るときに、ブラウザで CORS(別のドメインのものを読みこんでよいかの決まり)の問題が出たら、使っているドメインを、開発サーバーに許す必要があります。Vite と Laravel のプラグインは、次の場所からのアクセスを、はじめから許します。

  • ::1
  • 127.0.0.1
  • localhost
  • *.test
  • *.localhost
  • プロジェクトの .env の APP_URL

自分のドメインを許すいちばん簡単な方法は、APP_URL を、ブラウザで開いているドメインに合わせることです。たとえば、https://my-app.laravel を開いているなら、.env を次のようにします。

ini
APP_URL=https://my-app.laravel

複数のドメインを許したいなど、細かく決めたいときは、Vite の CORS の設定を使います。たとえば、vite.config.js の server.cors.origin に、複数を書けます。

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

export default defineConfig({
    plugins: [
        laravel({
            input: 'resources/js/app.js',
            refresh: true,
        }),
    ],
    server: {  // ここから足す
        cors: {
            origin: [
                'https://backend.laravel',
                'http://admin.laravel:8566',
            ],
        },
    },  // ここまで
});

正規表現(文字の並びのパターン)も書けます。たとえば、*.laravel のように、あるドメインの末尾が同じものを、全部許せます。

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

export default defineConfig({
    plugins: [
        laravel({
            input: 'resources/js/app.js',
            refresh: true,
        }),
    ],
    server: {  // ここから足す
        cors: {
            origin: [
                // Supports: SCHEME://DOMAIN.laravel[:PORT]
                /^https?:\/\/.*\.laravel(:\d+)?$/,
            ],
        },
    },  // ここまで
});

開発サーバーの URL を直す#

Vite のプラグインには、/ で始まる URL は、必ず Vite の開発サーバーを指すと考えるものがあります。でも、Laravel と組み合わせると、そうはなりません。

たとえば、vite-imagetools というプラグインは、Vite がファイルを配っているあいだ、次のような URL を出します。

html
<img src="/@imagetools/f0b2f404b13f052c604e632f2fb60381bf61a520">

このプラグインは、/@imagetools で始まる URL を、Vite が受け取って処理すると考えています。そう考えるプラグインを使うときは、URL を自分で直す必要があります。vite.config.js の transformOnServe オプションで直せます。

この例では、作られたコードの中の /@imagetools すべての前に、開発サーバーの URL を付けます。

js
import { defineConfig } from 'vite';
import laravel from 'laravel-vite-plugin';
import { imagetools } from 'vite-imagetools';

export default defineConfig({
    plugins: [
        laravel({
            // ...
            transformOnServe: (code, devServerUrl) => code.replaceAll('/@imagetools', devServerUrl+'/@imagetools'),
        }),
        imagetools(),
    ],
});

これで、Vite がファイルを配っているあいだ、開発サーバーを指す URL が出ます。

html
<!-- 直す前 -->
<img src="/@imagetools/f0b2f404b13f052c604e632f2fb60381bf61a520">

<!-- 直したあと -->
<img src="http://[::1]:5173/@imagetools/f0b2f404b13f052c604e632f2fb60381bf61a520">

関連するページ#

公式ドキュメント(英語)

2026年10月5日時点の内容をもとに、日本語でまとめています。

ページの一覧