Laravel9のバージョン9.2からデフォルトのビルドツールがWebpack(Laravel Mix)からViteに変更になりました。Viteはフロントエンドツールとして現在爆発的に人気のあるツールでViteを利用することでフロントエンド開発のスピードを加速させることができます。対象はLaravel、Reactを利用した経験がある人なのでLaravel, Reactについての細かな説明は含まれていません。

先日公開したVue.js版に続き今回はReactを利用して設定を行っていきます。

Laravel + Vite + React環境の構築に興味がある人はぜひ参考にしてください。

Inertiaは利用していません。
fukidashi

Laravelプロジェクトの作成

laravelコマンドを利用してLaravelプロジェクトを作成します。プロジェクト名はlaravel_vite_reactに設定していますが任意の名前をつけてください。


 % laravel new laravel_vite_react

composerコマンドを利用してもプロジェクトを作成することができます。


 % composer create-project laravel/laravel laravel_vite_react

Viteの確認

コマンド実行後に作成されるプロジェクトフォルダに移動するとvite.config.jsファイルが確認できます。vite.config.jsファイルではViteを利用するために必要なlaravel-vite-pluginの設定が行われています。


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,
        }),
    ],
});

inputファイルとしてresourcecs/css/app.cssとresources/js/app.jsファイルが指定されています。app.cssを見ると中身は空ですがapp.jsではbootstrap.jsファイルがimportされています。


import './bootstrap';

bootstrat.jsにはloadshやaxiosのimportなどこれまでのLaravelのバージョンでも利用されてきたコードが記述されています。


import _ from 'lodash';
window._ = _;

/**
 * We'll load the axios HTTP library which allows us to easily issue requests
 * to our Laravel back-end. This library automatically handles sending the
 * CSRF token as a header based on the value of the "XSRF" token cookie.
 */

import axios from 'axios';
window.axios = axios;

window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';

/**
 * Echo exposes an expressive API for subscribing to channels and listening
 * for events that are broadcast by Laravel. Echo and event broadcasting
 * allows your team to easily build robust real-time web applications.
 */

// import Echo from 'laravel-echo';

// import Pusher from 'pusher-js';
// window.Pusher = Pusher;

// window.Echo = new Echo({
//     broadcaster: 'pusher',
//     key: import.meta.env.VITE_PUSHER_APP_KEY,
//     wsHost: import.meta.env.VITE_PUSHER_HOST ?? `ws-${import.meta.env.VITE_PUSHER_APP_CLUSTER}.pusher.com`,
//     wsPort: import.meta.env.VITE_PUSHER_PORT ?? 80,
//     wssPort: import.meta.env.VITE_PUSHER_PORT ?? 443,
//     forceTLS: (import.meta.env.VITE_PUSHER_SCHEME ?? 'https') === 'https',
//     enabledTransports: ['ws', 'wss'],
// });

またpackage.jsonファイルを見るとviteが含まれていることもわかります。scriptsを見るとviteとvite buildも設定されています。開発環境ではnpm run dev, 本番環境ではnpm run buildを実行することができます。


{
    "private": true,
    "scripts": {
        "dev": "vite",
        "build": "vite build"
    },
    "devDependencies": {
        "axios": "^0.27",
        "laravel-vite-plugin": "^0.6.0",
        "lodash": "^4.17.19",
        "postcss": "^8.1.14",
        "vite": "^3.0.0"
    }
}

Viteの設定

確認してきた通りViteはデフォルトから利用できる設定になっていますがReactを利用するためにはいくつか設定が必要となります。

まずViteでReactを利用するために@vitejs/plugin-reactのインストールを行います。


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

@vitejs/plugin-reactのインストールが完了したらvite.config.jsにreact利用するための追加設定を行います。


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

export default defineConfig({
    plugins: [
        react(),
        laravel({
            input: ["resources/css/app.css", "resources/js/app.jsx"],
            refresh: true,
        }),
    ],
});

inputファイルとしてresources/js/app.jsファイルが指定されていますがapp.jsファイルの名前をapp.jsxファイルに変更します。resources¥jsにあるapp.jsファイルもapp.jsxに変更してください。

設定が完了したらnpm run devコマンドを実行します。実行すると”Failed to resolve dependency”のエラーが発生します。http://127.0.0.1:5173/で開発サーバを確認できますがこの理由は後ほどLaravelを起動したい際に利用されることがわかります。


% npm run dev

> dev
> vite

Failed to resolve dependency: react/jsx-runtime, present in 'optimizeDeps.include'
Failed to resolve dependency: react/jsx-dev-runtime, present in 'optimizeDeps.include'
Failed to resolve dependency: react, present in 'optimizeDeps.include'

  VITE v3.1.3  ready in 611 ms

  ➜  Local:   http://127.0.0.1:5173/
  ➜  Network: use --host to expose

  LARAVEL v9.30.1  plugin v0.6.0

エラーを解消するためにはreactとreact-domをインストールする必要があります。


 % npm install react react-dom --save-dev

added 4 packages, and audited 96 packages in 1s

10 packages are looking for funding
  run `npm fund` for details

found 0 vulnerabilities

再度npm run devコマンドを実行すると先ほど出力されていた”Failed to resolve dependency”のエラーメッセージが消えます。

インストール直後のpackage.jsonファイルは以下のようになっています。


{
    "private": true,
    "scripts": {
        "dev": "vite",
        "build": "vite build"
    },
    "devDependencies": {
        "@vitejs/plugin-react": "^2.1.0",
        "axios": "^0.27",
        "laravel-vite-plugin": "^0.6.0",
        "lodash": "^4.17.19",
        "postcss": "^8.1.14",
        "react": "^18.2.0",
        "react-dom": "^18.2.0",
        "vite": "^3.0.0"
    }
}

app.jsxファイルの読み込み

Reactを利用するためにwelcome.blade.phpファイルでJavaScriptを読み込む必要があります。またReactを利用するためにはマウントポイントが必要となります。Reactではブラウザが受け取ったJavaScriptファイルを利用してブラウザ上でコンテンツを作成しマウントポイントにコンテンツを挿入することでページが表示されます。JavaScriptの読み込みは@vite Directiveを利用します。マウントポイントはdiv要素のid属性にappを設定します。appという名前は任意です。後ほどapp.jsxファイルの中で”app”を設定する箇所があります。設定後のwelcome.blade.phpファイルは以下の通りです。


<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">

        <title>Laravel Vite Vue.js 3</title>
        @viteReactRefresh
        @vite(['resources/css/app.css', 'resources/js/app.jsx'])
    </head>
    <body>
        <div id="app"></div>
    </body>
</html>

php artisan serveコマンドを実行してLaravelの開発サーバを起動します。


 % php artisan serve

   INFO  Server running on [http://127.0.0.1:8000].  

  Press Ctrl+C to stop the server

ブラウザ上には何も表示されませんがブラウザのデベロッパーツールの要素を確認します。先ほどViteを起動した時に確認したポート番号でapp.cssとapp.jsxファイルにアクセスしていることがわかります。

welcome.blade.phpファイルの要素の確認
welcome.blade.phpファイルの要素の確認

@viteディレクティブによってapp.jsxファイルが読み込まれることがわかったのでapp.jsxファイルにReactのコードを記述します。


import "./bootstrap";

import ReactDOM from "react-dom/client";

function App() {
    return <h1>Hello World</h1>;
}

const root = ReactDOM.createRoot(document.getElementById("app"));
root.render(<App />);

ブラウザでlocalhost:8000にアクセスするとapp.jsxファイルで設定した”Hello World”が表示されます。

Hello Worldの表示
Hello Worldの表示

app.jsxファイルのコードを変更すると変更した内容は自動で反映されます。app.cssファイルにスタイルの設定を追加しても自動でブラウザに反映されます。

CSSファイルによるスタイルの適用
CSSファイルによるスタイルの適用

npm run devを起動していない場合はどうなるかを確認するためにnpm run devを停止します。viteの開発サーバが起動していない場ので下記のエラー画面が表示されます。Reactを利用して開発を進める際にはnpm run devを必ず実行しておく必要があります。

npm run devコマンドを実行していない場合のエラー
npm run devコマンドを実行していない場合のエラー

ここまでの設定でLaravel+Vite+Reactの開発環境は構築できました。

コンポーネントの作成

Counterコンポーネントを作成して別ファイルで作成したコンポーネントを利用(import)してもReactが問題なく動作するか確認を行います。jsフォルダの下にcomponentsフォルダを作成し、Counter.jsxファイルを作成します。


import { useState } from "react";

const Counter = () => {
    const [count, setCount] = useState(0);

    const addCount = () => {
        setCount((count) => count + 1);
    };

    return (
        <>
            <h2>Counter</h2>
            <p>Count:{count}</p>
            <button onClick={addCount}>Add</button>
        </>
    );
};

export default Counter;

作成したCounter.jsxファイルをapp.jsファイルでimortします。


import "./bootstrap";

import ReactDOM from "react-dom/client";
import Counter from "./components/Counter";

function App() {
    return (
        <>
            <h1>Hello World</h1>
            <Counter />
        </>
    );
}

const root = ReactDOM.createRoot(document.getElementById("app"));
root.render(<App />);

作成後ブラウザを確認するとカウンターが表示され”Add”ボタンをクリックするとカウント数が上がることが確認できます。別ファイルで作成したコンポーネントも問題なく動作することが確認できました。

カウンターコンポーネントの動作確認
カウンターコンポーネントの動作確認

ビルドコマンドの実行

npm run devコマンドはなく本番用のnpm run buildコマンドを実行します。publicフォルダの中にbuildフォルダが作成されmanifest.jsonファイル、さらにcssとJavaScriptファイルが作成されビルドされたファイルが保存されます。


 % npm run build

> build
> vite build

vite v3.1.3 building for production...
✓ 85 modules transformed.
public/build/manifest.json             0.25 KiB
public/build/assets/app.6fe91e6c.css   0.03 KiB / gzip: 0.05 KiB
public/build/assets/app.5523826a.js    230.84 KiB / gzip: 77.87 KiB

php artisan serveコマンドでLaravelの開発サーバを起動します。ブラウザのデベロッパーツールの要素を確認します。先ほどまではnpm run devコマンドを実行時のhttp://127.0.0.1:5174/ではなくpubicフォルダのassetsフォルダのビルド後のファイルが設定されていることがわかります。

npm run buildコマンド実行後
npm run buildコマンド実行後

npm run devを実行するとpublicフォルダにhotという名前のファイルが作成されViteの開発サーバのURLが記述されています。npm run devを終了すると消えます。npm run buildの時はhotファイルが作成されることはなくこのファイルが存在することで開発環境か本番環境かを判断しているようです。

画像の表示

Reactコンポーネントで画像を表示する方法を確認していきます。

app.jsxファイルに画像を設定するためにresourcesフォルダの下にimagesフォルダを作成してlog-with-shadow.pngを保存します。

画像はimportして利用することができます。


import "./bootstrap";

import ReactDOM from "react-dom/client";
import Counter from "./components/Counter";
import Logo from "../images/logo-with-shadow.png";

function App() {
    return (
        <>
            <h1>Hello World</h1>
            <img src={Logo} />
            <Counter />
        </>
    );
}

const root = ReactDOM.createRoot(document.getElementById("app"));
root.render(<App />);

importした画像の表示
importした画像の表示

importではなくimgのsrc属性にパスの設定を行う場合はpublicフォルダに画像を移動させ以下のように設定を行います。


<img src="/logo-with-shadow.png" />

importで設定した場合にnpm run buildを利用してビルドを行うpublic/build/assetsの下にlogo-with-shadowファイルが作成されます。


 % npm run build

> build
> vite build

vite v3.1.3 building for production...
✓ 86 modules transformed.
public/build/assets/logo-with-shadow.51249ca9.png   65.58 KiB
public/build/manifest.json                          0.47 KiB
public/build/assets/app.6fe91e6c.css                0.03 KiB / gzip: 0.05 KiB
public/build/assets/app.a8cb604a.js  

publicフォルダに画像を保存しsrc属性にパスを設定した場合はpublic/build/assetsの下に画像ファイルが作成されることはありません。


 % npm run build

> build
> vite build

vite v3.1.3 building for production...
✓ 85 modules transformed.
public/build/manifest.json             0.25 KiB
public/build/assets/app.6fe91e6c.css   0.03 KiB / gzip: 0.05 KiB
public/build/assets/app.7c424ab6.js    230.88 KiB / gzip: 77.90 KiB

importを利用するかpulbicフォルダに保存してパスを保存するかによって画像の扱い方が変わります。