laravel + inertia + react のbootcampを見る (その1: セットアップまで)


これは chirper というアプリケーションを作成する例である。簡易ツイッター的なものだ。BladeInertiaの2つから選択できる。Laravelの初心者はBladeからやった方がいいかもしれない、が、ここではInertiaを取り上げる。

Inertiaとは何なのかという説明は敢えてしないが、Laravelの機能をふんだんに使いつつvueやらreactやらを使う(それも非同期で)というものになっている。まあ何を言っているのかとかいうのはともあれ使ってみよう。

Projectを開始する

https://bootcamp.laravel.com/inertia/installation

まず、いきなりだがここでの読者の想定は先述したようにある程度Laravelでのアプリケーション開発の経験がある人を対象にしているから、使い出しまでの細かい説明は行わない。

そして、上記の記事ではcomposerでprojectを作成し、artisan serveで確認しているものと、docker(sail)で行うものとあるが。ここではdocker + laravel sail一択とする。しがたってコマンド等は全てsailで表記するが、経験があれば別段nativeのserveとかその辺でも動かせると思うし、別にdockerを使う必要もないかもしれない。

projectを作る

https://bootcamp.laravel.com/inertia/installation#installation-via-docker

Installation via Dockerを参照。

とりあえずmysqlだけあればいいので以下のようなコマンドを展開する

curl -s "https://laravel.build/chirper?with=mysql" | bash

システムに合わせて最適なバージョンが選択されると思うが、ここではlaravel10が入る(2023/8/4)。projectが展開されると chirper というディレクトリが作成されるからcdしておく。

sailをupする前に

適当なgitレポジトリにつっこんでおく事を想定する。

その際、.env.exampleと.envでちょっと設定が変わっているから、開発版

DB_CONNECTION=mysql
DB_HOST=mysql
DB_PORT=3306
DB_DATABASE=example
DB_USERNAME=sail
DB_PASSWORD=password

とかのDB設定にしておくといいかも。あと、どっちにしてもwebアプリとして開発するパターンがほとんどなので

APP_NAME=Chirper
APP_ENV=local
APP_KEY=
APP_DEBUG=true
APP_URL=http://localhost
APP_PORT=8000

こんな感じでAPP_PORTも設定しておくといいかもしれない。そうすればそのポートで待ち受けるようになる(localhost:8000とか)
これはdocker-compose.ymlで参照されるから、そこに設定がある。あと、APP_NAMEも変更した。

sail upする

./vendor/bin/sail up

あるいはsail up -dオプション

migrate可能な事(ようするにDBと通信できているか)を確認しておく

% ./vendor/bin/sail artisan migrate

   INFO  Preparing database.

  Creating migration table ......................................... 37ms DONE

   INFO  Running migrations.

  2014_10_12_000000_create_users_table ............................. 63ms DONE
  2014_10_12_100000_create_password_reset_tokens_table ............. 86ms DONE
  2019_08_19_000000_create_failed_jobs_table ....................... 57ms DONE
  2019_12_14_000001_create_personal_access_tokens_table ............ 89ms DONE

cloneした場合はartisan key:generateとかも必要かもしれない。

いずれにせよ、これでlaravelのトップが見えてくるはずだ


Laravel v10.17.1 (PHP v8.2.7)

laravel breezeのセットアップ

Laravel Breezeは、Laravelの認証機能(ログイン、登録、パスワードリセット、メール確認、パスワード確認)をシンプルに実装したテンプレート一式である。実際ここまでは、まだBladeに行く事も可能であるが、ここではinertiaとreactで実装するので、そちらの方向に向かっていく事にする。

composer require laravel/breeze --dev

を入力してみる。以下はsailでの出力である。

% ./vendor/bin/sail composer require laravel/breeze --dev
./composer.json has been updated
Running composer update laravel/breeze
Loading composer repositories with package information
Updating dependencies
Nothing to modify in lock file
Installing dependencies from lock file (including require-dev)
Package operations: 1 install, 0 updates, 0 removals
  - Downloading laravel/breeze (v1.22.0)
  - Installing laravel/breeze (v1.22.0): Extracting archive
Generating optimized autoload files
> Illuminate\Foundation\ComposerScripts::postAutoloadDump
> @php artisan package:discover --ansi

   INFO  Discovering packages.

  laravel/breeze ........................................................ DONE
  laravel/sail .......................................................... DONE
  laravel/sanctum ....................................................... DONE
  laravel/tinker ........................................................ DONE
  nesbot/carbon ......................................................... DONE
  nunomaduro/collision .................................................. DONE
  nunomaduro/termwind ................................................... DONE
  spatie/laravel-ignition ............................................... DONE

82 packages you are using are looking for funding.
Use the `composer fund` command to find out more!
> @php artisan vendor:publish --tag=laravel-assets --ansi --force

   INFO  No publishable resources for tag [laravel-assets].

No security vulnerability advisories found
Using version ^1.22 for laravel/breeze

そしたら続いて以下のコマンドを入力する

php artisan breeze:install react

以下はsailでの出力

% ./vendor/bin/sail artisan breeze:install react
./composer.json has been updated
Running composer update inertiajs/inertia-laravel laravel/sanctum tightenco/ziggy
Loading composer repositories with package information
Updating dependencies
Lock file operations: 2 installs, 0 updates, 0 removals
  - Locking inertiajs/inertia-laravel (v0.6.9)
  - Locking tightenco/ziggy (v1.6.0)
Writing lock file
Installing dependencies from lock file (including require-dev)
Package operations: 2 installs, 0 updates, 0 removals
  - Downloading inertiajs/inertia-laravel (v0.6.9)
  - Downloading tightenco/ziggy (v1.6.0)
 0/2 [>---------------------------]   0%
 2/2 [============================] 100%
  - Installing inertiajs/inertia-laravel (v0.6.9): Extracting archive
  - Installing tightenco/ziggy (v1.6.0): Extracting archive
 0/2 [>---------------------------]   0%
 2/2 [============================] 100%
Generating optimized autoload files
> Illuminate\Foundation\ComposerScripts::postAutoloadDump
> @php artisan package:discover --ansi

   INFO  Discovering packages.

  inertiajs/inertia-laravel ............................................. DONE
  laravel/breeze ........................................................ DONE
  laravel/sail .......................................................... DONE
  laravel/sanctum ....................................................... DONE
  laravel/tinker ........................................................ DONE
  nesbot/carbon ......................................................... DONE
  nunomaduro/collision .................................................. DONE
  nunomaduro/termwind ................................................... DONE
  spatie/laravel-ignition ............................................... DONE
  tightenco/ziggy ....................................................... DONE

83 packages you are using are looking for funding.
Use the `composer fund` command to find out more!
> @php artisan vendor:publish --tag=laravel-assets --ansi --force

   INFO  No publishable resources for tag [laravel-assets].

No security vulnerability advisories found

   INFO  Installing and building Node dependencies.


added 173 packages, and audited 174 packages in 19s

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

found 0 vulnerabilities
npm notice
npm notice New minor version of npm available! 9.7.1 -> 9.8.1
npm notice Changelog: https://github.com/npm/cli/releases/tag/v9.8.1
npm notice Run npm install -g npm@9.8.1 to update!
npm notice

> build
> vite build

vite v4.4.8 building for production...
✓ 217 modules transformed.
public/build/manifest.json                                      6.75 kB │ gzip:  0.80 kB
public/build/assets/app-719ee526.css                           29.89 kB │ gzip:  5.80 kB
public/build/assets/InputLabel-f2ea45d1.js                      0.21 kB │ gzip:  0.18 kB
public/build/assets/TextInput-e7b330e7.js                       0.48 kB │ gzip:  0.33 kB
public/build/assets/GuestLayout-44108184.js                     0.50 kB │ gzip:  0.32 kB
public/build/assets/PrimaryButton-0d68d1ff.js                   0.50 kB │ gzip:  0.34 kB
public/build/assets/Dashboard-8e530bd5.js                       0.65 kB │ gzip:  0.37 kB
public/build/assets/ForgotPassword-4b0e9a33.js                  1.14 kB │ gzip:  0.64 kB
public/build/assets/Edit-8c868c75.js                            1.14 kB │ gzip:  0.52 kB
public/build/assets/ConfirmPassword-30bae1b5.js                 1.19 kB │ gzip:  0.64 kB
public/build/assets/VerifyEmail-9cc6c6f8.js                     1.25 kB │ gzip:  0.69 kB
public/build/assets/ResetPassword-ebc284e8.js                   1.78 kB │ gzip:  0.70 kB
public/build/assets/Login-1056b871.js                           2.11 kB │ gzip:  0.94 kB
public/build/assets/UpdateProfileInformationForm-5a9adf8d.js    2.29 kB │ gzip:  1.00 kB
public/build/assets/Register-522f8f02.js                        2.30 kB │ gzip:  0.84 kB
public/build/assets/UpdatePasswordForm-c33224ca.js              2.34 kB │ gzip:  0.86 kB
public/build/assets/ApplicationLogo-129c0e69.js                 3.12 kB │ gzip:  1.33 kB
public/build/assets/AuthenticatedLayout-aa6a8e79.js             5.78 kB │ gzip:  1.86 kB
public/build/assets/transition-ecfd9599.js                     13.29 kB │ gzip:  5.16 kB
public/build/assets/Welcome-ad683f6d.js                        15.88 kB │ gzip:  4.44 kB
public/build/assets/DeleteUserForm-44deb104.js                 27.32 kB │ gzip:  9.76 kB
public/build/assets/app-f89f8aba.js                           247.66 kB │ gzip: 82.14 kB
✓ built in 4.39s


   INFO  Breeze scaffolding installed successfully.

さて、これでbreeze + reactでlaravelの画面が書き変わっている。確認してみよう。


このようにログインやら登録やらのリンクが貼りこまれている。


ログイン画面

ログインを押すとこのような認証フォームが描画されるはずだ。これはreact(とtailwind cssとか)で記述されている。実態はresources/js/Pages/Auth/Login.jsxである

import { useEffect } from 'react';
import Checkbox from '@/Components/Checkbox';
import GuestLayout from '@/Layouts/GuestLayout';
import InputError from '@/Components/InputError';
import InputLabel from '@/Components/InputLabel';
import PrimaryButton from '@/Components/PrimaryButton';
import TextInput from '@/Components/TextInput';
import { Head, Link, useForm } from '@inertiajs/react';

export default function Login({ status, canResetPassword }) {
    const { data, setData, post, processing, errors, reset } = useForm({
        email: '',
        password: '',
        remember: false,
    });

    useEffect(() => {
        return () => {
            reset('password');
        };
    }, []);

    const submit = (e) => {
        e.preventDefault();

        post(route('login'));
    };

    return (
        <GuestLayout>
            <Head title="Log in" />

            {status && <div className="mb-4 font-medium text-sm text-green-600">{status}</div>}

            <form onSubmit={submit}>
                <div>
                    <InputLabel htmlFor="email" value="Email" />

                    <TextInput
                        id="email"
                        type="email"
                        name="email"
                        value={data.email}
                        className="mt-1 block w-full"
                        autoComplete="username"
                        isFocused={true}
                        onChange={(e) => setData('email', e.target.value)}
                    />

                    <InputError message={errors.email} className="mt-2" />
                </div>

                <div className="mt-4">
                    <InputLabel htmlFor="password" value="Password" />

                    <TextInput
                        id="password"
                        type="password"
                        name="password"
                        value={data.password}
                        className="mt-1 block w-full"
                        autoComplete="current-password"
                        onChange={(e) => setData('password', e.target.value)}
                    />

                    <InputError message={errors.password} className="mt-2" />
                </div>

                <div className="block mt-4">
                    <label className="flex items-center">
                        <Checkbox
                            name="remember"
                            checked={data.remember}
                            onChange={(e) => setData('remember', e.target.checked)}
                        />
                        <span className="ml-2 text-sm text-gray-600">Remember me</span>
                    </label>
                </div>

                <div className="flex items-center justify-end mt-4">
                    {canResetPassword && (
                        <Link
                            href={route('password.request')}
                            className="underline text-sm text-gray-600 hover:text-gray-900 rounded-md focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500"
                        >
                            Forgot your password?
                        </Link>
                    )}

                    <PrimaryButton className="ml-4" disabled={processing}>
                        Log in
                    </PrimaryButton>
                </div>
            </form>
        </GuestLayout>
    );
}

もちろん、これはここを書き換えただけで反映されるものではない、たとえばLog in のところを以下のように書き換えてみよう。

<PrimaryButton className="ml-4" disabled={processing}>
    ログイン
</PrimaryButton>

これだけでは何も起きない。npm run buildする必要がある

% ./vendor/bin/sail npm run build

> build
> vite build

vite v4.4.8 building for production...
✓ 217 modules transformed.
public/build/manifest.json                                      6.75 kB │ gzip:  0.81 kB
public/build/assets/app-719ee526.css                           29.89 kB │ gzip:  5.80 kB
public/build/assets/InputLabel-cc46406f.js                      0.21 kB │ gzip:  0.18 kB
public/build/assets/TextInput-ee89aca1.js                       0.48 kB │ gzip:  0.34 kB
public/build/assets/GuestLayout-2b290bdb.js                     0.50 kB │ gzip:  0.32 kB
public/build/assets/PrimaryButton-5d500b20.js                   0.50 kB │ gzip:  0.34 kB
public/build/assets/Dashboard-3a6532cd.js                       0.65 kB │ gzip:  0.38 kB
public/build/assets/ForgotPassword-f3867354.js                  1.14 kB │ gzip:  0.64 kB
public/build/assets/Edit-ee2edd03.js                            1.14 kB │ gzip:  0.52 kB
public/build/assets/ConfirmPassword-ad923438.js                 1.19 kB │ gzip:  0.64 kB
public/build/assets/VerifyEmail-dc4cb09a.js                     1.25 kB │ gzip:  0.69 kB
public/build/assets/ResetPassword-ab6d2221.js                   1.78 kB │ gzip:  0.70 kB
public/build/assets/Login-1bca5ec2.js                           2.11 kB │ gzip:  0.97 kB
public/build/assets/UpdateProfileInformationForm-92a1bb0f.js    2.29 kB │ gzip:  1.00 kB
public/build/assets/Register-8018aaba.js                        2.30 kB │ gzip:  0.84 kB
public/build/assets/UpdatePasswordForm-aaa65a0a.js              2.34 kB │ gzip:  0.86 kB
public/build/assets/ApplicationLogo-3e2530be.js                 3.12 kB │ gzip:  1.32 kB
public/build/assets/AuthenticatedLayout-376e8b9b.js             5.78 kB │ gzip:  1.86 kB
public/build/assets/transition-5d54f17e.js                     13.29 kB │ gzip:  5.17 kB
public/build/assets/Welcome-9d0bcab8.js                        15.88 kB │ gzip:  4.44 kB
public/build/assets/DeleteUserForm-cedfa812.js                 27.32 kB │ gzip:  9.76 kB
public/build/assets/app-1fb36539.js                           247.66 kB │ gzip: 82.14 kB
✓ built in 4.36s


ボタン表記が「ログイン」となった

ホットリロード

ただ、これだとかなり開発が面倒くさいので、ホットリロードを行うようにする。これはvite.config.jsで行う

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

const host = 'localhost';

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

サーバーがlocalhostじゃなかったらもちろんlocalhost以外にするんだけども、これでnpm run devすると

  VITE v4.4.8  ready in 580 ms

こんな感じで待ち受けるようになるから先程のログインフォームなんかを書き換えてただしくホットリロードできるか確認する。

前段階完了

webプログラミングはセットアップが結構面倒くさいのが難点ではあるが、ここまでやってようやくプログラミングに入っていく事ができる。次回以降は実際にこのbootcampのコード記述していく。(要するにchirper を作る)

に続く

この記事が気に入ったらサポートをしてみませんか?