もうね、なんか大変だったので記事にとっておく。
参考にしたのは、Laravelの公式の方じゃなくてInertiajsの方
バージョンとか環境周りとか
このあたり重要。鳥獣用。OSはWindows11です。
バージョン
wsl --version WSL バージョン: 2.2.4.0 カーネル バージョン: 5.15.153.1-2 WSLg バージョン: 1.0.61 MSRDC バージョン: 1.2.5326 Direct3D バージョン: 1.611.1-81528511 DXCore バージョン: 10.0.26091.1-240325-1447.ge-release Windows バージョン: 10.0.22631.3737
使っているLinuxイメージは Ubuntu-24.04で、Dockerで使っているライブラリ情報は以下の通り
Ubuntu-24.04 > Docker version 26.1.4, build 5650f9b
ライブラリ | バージョン |
---|---|
PHP | 8.3.7 |
Laravel | 11.9 |
React | 18.3.1 |
inertiajs | 0.11.1 |
DB | 11.4.2-MariaDB-ubu2404 |
Docker
$ tree . ├── docker │ ├── app │ │ └── Dockerfile │ ├── compose.yaml │ └── mariadb │ ├── Dockerfile │ └── my.cnf └── src └── laravel
name: inertia_demo services: laravel: container_name: laravel build: dockerfile: ./app/Dockerfile context: . tags: - "mylaravel:inertia_demo" image: "mylaravel:inertia_demo" environment: DB_HOST: mariadb DB_USERNAME: docker DB_PASSWORD: passwd DB_DATABASE: inertia_demo volumes: - type: bind source: ../src/laravel target: /app ports: - "18000:8000" - "5173:5173" command: mariadb: container_name: mariadb build: dockerfile: ./mariadb/Dockerfile context: . environment: MARIADB_ROOT_PASSWORD: passwd MARIADB_USER: docker MARIADB_PASSWORD: passwd MARIADB_DATABASE: inertia_demo volumes: - type: volume source: mariadb target: /var/lib/mysql - type: bind source: ./mariadb target: /docker-entrypoint-initdb.d volumes: mariadb:
FROM bitnami/laravel:11.1.1
FROM --platform=linux/amd64 mariadb:latest COPY ./mariadb/my.cnf /etc/my.cnf RUN chmod 644 /etc/my.cnf
Inertiajsが動くまで
Docker起動の時にLaravelが遅くなって困ったので注意
当初、Windows11のデスクトップにフォルダを作成して、wslからは cd /mnt/c/Users/itoh/Desktop/inertia_demo/docker とか作ってdocker compose upしてたらLaravelがすんげーおもくなった。dockerの起動やbindマウントはwsl内の記述にして、laravelなどのコードを触るときはwsl内のファイルをWindowsから \wsl.localhost\Ubuntu-24.04\home\t-ito\inertia_demo とかで覗きに行くようにしよう。
compose.yamlの場所が
ダメなパターン:C:\Users\itoh\Desktop\inertia_demo\docker\compose.yaml
良いパターン: \wsl.localhost\Ubuntu-24.04\home\t-ito\inertia_demo\docker\compose.yaml
bitnami/laravel のクセ
以下は、今回使ったDockerのbitnami/laravelについて。
起動スクリプトでartisan serveが実行される。
このDockerイメージを使うと、Laravelのインストールとartisan serveはDockerを起動した時点で既に行われているので、ポートフォワードした http://localhost:18000 にアクセスすればLaravelのトップページが見られる。
しかも、laravelの.envを編集した時に自動でartisan serveを再読み込み実行してくれる。
しかし当然、次回にdockerを再起動させるとインストール作業はされずにartisan serveされるが、このartisan serveがコケるとコンテナが起動しない。コンテナの/appディレクトリが空の時のみにLaravelのインストールがされるので、artisan serveが上がって来なかったら./src/laravelは別のディレクトリ名にして別の場所にbindマウントさせた上で./src/laravelディレクトリを改めて作ったうえでdocker compose upする必要がある。
したがって、「LaravelがWindows11だとおせー」とか言って、DockerでLaravelが重すぎたのでvendorとstorageをマウントしないことで解決した気がする #Docker - Qiitaにあるようにvendor / storage をbindマウントではなくvolumeマウントして解決しようとすると、「./src/laravaelにstorageやvendorがあるから、Laravelはインストールしないよ」ってbitnamiが判断してしまってartisan serveが起動せずにコンテナが上がってこないというハメになる。*1
composer や artisanコマンドで作るファイルがWSL側ではrootオーナーになってしまう。
docker内でartisanコマンドでScaffoldを作っていくと、WSL側から見たときにrootになってしまう。
じゃあ、ユーザー情報とグループ情報をWSLと同一にしてしまえばと
- type: bind source: /etc/passwd target: /etc/passwd read_only: true - type: bind source: /etc/group target: /etc/group read_only: true
とかすると、bitnamiユーザーがいないということで chown: invalid user: 'bitnami:bitnami' が失敗してコンテナが起動しない。さらに言うと、chown bitnamiしてるってことは、WSLのitohユーザーでは編集できない。しゃーないので、起動後にWSL側から sudo chown -R itoh. laravel
している。このあたり、なんとかならんかな…
LaravelでInertiajs(React)を動かすまで
ここから本番、前振り長い。長いけど、この前提をしっかりやんないとどっかでコケる。というか、もう最近の開発って前提長ないすか?Oracle VirtualBox+LAMP + Sambaだとこのあたり手間だけど難しくないのになーって思います。まぁいいや。
inertia-laravelのインストール
Dockerコンテナに docker container exec -ti laravel bash
で接続して
# composer require inertiajs/inertia-laravel
MiddleWareの生成と登録
# ./artisan inertia:middleware
INFO Middleware [app/Http/Middleware/HandleInertiaRequests.php] created successfully.
で、Laravel11ではMiddlewareは./bootstrap/app.phpを
<?php use Illuminate\Foundation\Application; use Illuminate\Foundation\Configuration\Exceptions; use Illuminate\Foundation\Configuration\Middleware; use App\Http\Middleware\HandleInertiaRequests; return Application::configure(basePath: dirname(__DIR__)) ->withRouting( web: __DIR__.'/../routes/web.php', commands: __DIR__.'/../routes/console.php', health: '/up', ) ->withMiddleware(function (Middleware $middleware) { $middleware->web(append: [ HandleInertiaRequests::class, ]); }) ->withExceptions(function (Exceptions $exceptions) { // })->create();
Viewの作成
さきほどのMiddlewareの app/Http/Middleware/HandleInertiaRequests.php には
<?php protected $rootView = 'app';
という記述があったので、resources/views/app.blade.phpにInertiaの起点となるViewを作成する。
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title>Vite DEMO Top</title> <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0" /> @viteReactRefresh @vite(['resources/css/app.css', 'resources/js/app.jsx']) @inertiaHead </head> <body> @inertia </body> </html>
resources/js/app.jsだったのをReactなのでjsxにして、@viteReactRefreshを付け加えた。
Routing
Routeを routes/web.php に一番簡単に作る。
<?php use Illuminate\Support\Facades\Route; use Inertia\Inertia; Route::get('/', function () { return Inertia::render('hello-world'); });
Reactをインストールして、Inertiajsの起点スクリプトを作る
npm install -D react react-dom @inertiajs/react @vitejs/plugin-react
先ほどの app.blade.phpには、@vite(['resources/css/app.css', 'resources/js/app.jsx'])
とあったので、resources/js/app.jsx を記述する。
import React from 'react' import {createRoot} from 'react-dom/client' import {createInertiaApp } from '@inertiajs/react' import {resolvePageComponent} from 'laravel-vite-plugin/inertia-helpers' createInertiaApp({ // Below you can see that we are going to get all React components from resources/js/Pages folder resolve: (name) => resolvePageComponent(`./Pages/${name}.jsx`,import.meta.glob('./Pages/**/*.jsx')), setup({ el, App, props }) { createRoot(el).render(<App {...props} />) }, })
Reactのページを作る
さきほどの、app.blade.phpには、 return Inertia::render('hello-world');
とあったので、hello-worldのページを作る。ファイルは、resources/js/Pages/hello-world.jsx
export default function HelloWorld() { return ( <div> <p>Hello World!</p> </div> ); }
npm run devでトランスパイル…なんだけど
Laravel11では、webpack/mixではなくてViteでトランスパイルする。package.josnにそう書いてある。
{ "private": true, "type": "module", "scripts": { "dev": "vite", "build": "vite build" },
ということで、vite.config.js を調整
vite.config.jsの沼
デフォルトのままのvite.config.jsだとLaravelトップの http://localhost:18000/ にアクセスしても何も表示されない。
HTMLをChrome Developer toolsで見てみると
<html><head> <meta charset="utf-8"> <title>Vite DEMO Top</title> <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0"> <script type="module"> import RefreshRuntime from 'http://[::1]:5173/@react-refresh' RefreshRuntime.injectIntoGlobalHook(window) window.$RefreshReg$ = () => {} window.$RefreshSig$ = () => (type) => type window.__vite_plugin_react_preamble_installed__ = true </script> <script type="module" src="http://[::1]:5173/@vite/client"></script> <link rel="stylesheet" href="http://[::1]:5173/resources/css/app.css"> <script type="module" src="http://[::1]:5173/resources/js/app.jsx"></script> </head> <body> <div id="app" data-page="{省略}"></div> <deepl-input-controller></deepl-input-controller> </body></html>
とかなってる。
http://[::1]:5173/@vite/client
とかなんじゃい?とソースコードを眺めてると、public/hot から取得してる模様。しかし、これがどこからきてるかよくわからない…そもそも、http://localhost:5173にアクセスしてもERR_EMPTY_RESPONSEでエラー表示。どうも serverのhost指定でnpmの立てるHTTPサーバーが制限されている模様。ということでvite.config.jsを次のように変えてみると、
/// これはうまくいかないvite.config.js import { defineConfig } from 'vite'; import laravel from 'laravel-vite-plugin'; import react from '@vitejs/plugin-react'; export default defineConfig({ plugins: [ react(), // React plugin that we installed for vite.js laravel({ input: ['resources/css/app.css', 'resources/js/app.js'], refresh: true, }), ], server: { host: true, } });
http://localhost:5173/@vite/client にアクセスするとレスポンスがあった!!!…が404 forbidden…Docker内部から curl http://localhost:5173/@vite/client するとJavaScriptが取れてる!!!そのあとだとホストのWindows11ブラウザからアクセスしてもJavaScript見えてるじゃーーん!!!やったーー!!!…って、全然こんなの解決になってないわー。そもそも、http://localhost:18000/ にアクセスして得られるスクリプトタグのURLは <script type="module" src="http://[::]:5173/@vite/client"></script>
と相変わらずだし。
で、こちらのページを見ると、解決方法が書いてあった。
qiita.com
server.hmr.host: localhost
をつける
import { defineConfig } from 'vite'; import laravel from 'laravel-vite-plugin'; import react from '@vitejs/plugin-react'; export default defineConfig({ plugins: [ react(), // React plugin that we installed for vite.js laravel({ input: ['resources/css/app.css', 'resources/js/app.jsx'], refresh: true, }), ], server: { host: true, hmr: { host: 'localhost', }, }, });
ここまで。なんか公式のドキュメント通りやっても通らずにすごい大変だった…npm installのところはあのパッケージでいいのかは