tohokuaikiのチラシの裏

技術的ネタとか。

LaravelのInertiaとの連携がいっつもわからなくなるからメモっておく

Inertia.js+Laravel+React…便利ですよね!でも、レールに乗り始めれば早いけど、最初とか途中で「あー、init時に変数渡したい」ってなった時に「…ファイルどれだっけ?」ってなります。

なので、メモです。

結果だけ書くと、

  1. routes/web.php
  2. Controller.php
  3. HandleInertiaRequests.php
  4. resources/views/app.blade.php
  5. resources/js/app.tsx
  6. resources/js/Pages/Default.tsx

Laravelの起点はrouting

何でもそうですよね。RoutingでInertia::render()してたらそこが起点です。

<?php
Route::prefix('/admin')->get('/{operation?}/{target?}/{property?}', function (){
    return Inertia::render('Default', [
        'config' => config('config_to_inertia'),
        'roles' => Role::all(),
    ]);

Controllerもチェック

routingでContollerメソッド指定の場合、メソッドでreturn Inertia::render()している場合もあります。

<?php
    public function access(string $token): InertiaResponse
    {
        return Inertia::render('Default', [
            'config' => [
                'app_name' => config('config_to_inertia'),
            ],
            'fooparam' => $foo_array
        ]);

Bladeファイルの指定

Reactでいうindex.htmlのようなReactの起点となるのは app/Http/Middleware/HandleInertiaRequests.phprouteViewメソッド で指定される。

<?php
    protected $rootView = 'app';

    public function rootView(Request $request)
    {
        $routeName = $request->route()->getName();
        
        if (strpos($routeName, 'admin.') === 0) {
            return 'admin';
        }
        if (strpos($routeName, 'your.route.name') === 0) {
            return 'foo';
        }
        return parent::rootView($request);
    }

この場合、デフォルトでは、appを返すので、resources/views/app.blade.phpが起点となるbladeになる。route名によってbladeを変更できる。

BladeからInertiaへのつなぎこみ

app.blade.phpのこの部分で行う。

        @vite(['resources/js/app.tsx', "resources/js/Pages/{$page['component']}.tsx"])

基本的にInertiaはPageRouter。

配列の1つ目がInertiaをセットアップするtsxで、2つ目が最初に表示されるPageになる。Inertia::render()'Default', [だと、$page['component']Defaultになる。

Inertiaのセットアップ

先ほどの配列の1つ目 resources/js/app.tsxを見ると

import '../css/app.scss';
import './bootstrap';

import { createInertiaApp } from '@inertiajs/react';
import { resolvePageComponent } from 'laravel-vite-plugin/inertia-helpers';
import { createRoot } from 'react-dom/client';

const appName = import.meta.env.VITE_APP_NAME || 'Laravel';

createInertiaApp({
    title: (title) => `${title} - ${appName}`,
    resolve: (name) =>
        resolvePageComponent(
            `./Pages/${name}.tsx`,
            import.meta.glob('./Pages/**/*.tsx'),
        ),
    setup({ el, App, props }) {
        const root = createRoot(el);

        root.render(<App {...props} />);
    },
    progress: {
        color: '#4B5563',
    },
});

となっている。肝心なのは、resolvePageComponentのところ。第一引数には最初のページが入る。これは、最初のInertia::render()'Default', [で決まって、${name}Defaultになる。

第二引数は、どのページを読み込むかの指定。 import.meta.glob('./Pages/**/*.tsx')だと resources/js/Pages/配下の全てのtsxファイルが使える。ただし、ReactのRoutingはまた別途

<BrowserRouter>
        <Routes>
                <Route>

でやる必要がある。