Inertia 系スターターキット(React / Vue)を検証して改良した
公式の laravel/react-starter-kit と laravel/vue-starter-kit を Docker で動かし、本番運用に耐える形へ書き直したフォークを 2 本公開している。テストはどちらも 40 passed → 44 passed / 151 assertions。
検証環境
- PHP 8.5.5
- Laravel 13.x
- Node 22.22.2
- Frontend React 19 / Vue 3 + Inertia
- Tests (both forks) 40 → 44 passed / 151 assertions
- OS Docker Desktop (php:8.5-cli-bookworm)
公式の laravel/react-starter-kit と laravel/vue-starter-kit を Docker で動かし、本番運用に耐える形へ書き直したフォークを 2 本公開している。テストはどちらも 40 passed → 44 passed / 151 assertions。
本記事は Inertia 層に固有の論点に絞る。React と Vue をまとめて 1 本で扱うのは、検証した結果、固有 findings が両者で完全に同一だったためである(詳細は末尾)。
backend 改修 6 件は React / Vue / Livewire で共通なので pillar に集約している:
→ Laravel スターターキット共通 backend を本番化する 6 つの改修
対象の公式サンプル
| React 版 | Vue 版 | |
|---|---|---|
| 公式 URL | laravel/react-starter-kit | laravel/vue-starter-kit |
| 改良版 fork | codelift-dev/react-starter-kit | codelift-dev/vue-starter-kit |
| フロント | React 19 + TypeScript + shadcn/ui | Vue 3 Composition API + TypeScript + shadcn-vue |
| 共通 | Laravel 13 + Inertia + Fortify、MIT / MIT | |
| 上流 commit | laravel/react-starter-kit 検証時点 |
laravel/vue-starter-kit@1233a92 |
| 検証日 | 2026-04-19 | 2026-04-19 |
| テスト | 40 → 44 passed / 151 | 40 → 44 passed / 151 |
検証環境
Docker Desktop、PHP 8.5.5 / Laravel 13.x / Node 22.22.2。pillar と共通。
git clone https://github.com/codelift-dev/react-starter-kit.git # または vue-starter-kit
cd react-starter-kit
git checkout improvements
docker compose -f codelift/docker-compose.yml build
docker compose -f codelift/docker-compose.yml run --rm app
A. composer install 前に npm run build すると不可解に失敗する
Inertia 系(React / Vue)に固有。Livewire 版では起きない。
症状: clone 直後に npm run build を先に走らせると、Vite ビルドが落ちる。
require(.../vendor/autoload.php): Failed to open stream: No such file or directory
in artisan on line 10
原因: vite.config.ts の @laravel/vite-plugin-wayfinder プラグインが、ビルド中に php artisan wayfinder:generate を shell out する。Wayfinder は Laravel のルート定義から TypeScript の型付きルートヘルパーを生成する仕組みで、そのためにビルド時に artisan を起動する。Composer 依存が未インストールだと artisan が vendor/autoload.php を読めずに落ちる。
なぜ厄介か: エラーメッセージに composer install の文字が一切出ない。初見の開発者は Vite か Wayfinder のバグを疑い、見当違いの方向に時間を溶かす。vendor/autoload.php というパスから「Composer をまだ流していない」と即座に気付けるのは、Laravel に慣れた人だけである。
改修: README に Setup セクションを追加し、composer install → npm run build の順を明示。Wayfinder がビルド時に artisan を呼ぶ事実も併記して、なぜこの順序なのかを理解できるようにした。
React 版・Vue 版とも同一の修正が入る。
Inertia の初期 state と CSP
Inertia はサーバー側ルーティングとフロントのコンポーネントを繋ぐ。ページ遷移ごとにサーバーが JSON の page object を返し、クライアントが描画する。初回ロードでは、その page object を HTML に載せる必要がある。
出力はこうなる。
<script data-page="app" type="application/json">{...}</script>
<div id="app"></div>
type="application/json" のデータブロックなので、ブラウザは実行せず script-src の対象外である。Inertia が CSP の障壁になることはない。
この improvements ブランチでは CSP 自体を導入する(pillar finding D)が、script-src に 'unsafe-inline' を残す保守的な設定にとどめている。撤廃した csp-nonce ブランチと解説は別記事にある。
→ Inertia の CSP は nonce 化できる(本体の改造は不要)
訂正 (2026-07-23): 本節は当初「Inertia は初期 props を inline script に埋めるため、nonce 化には
HandleInertiaRequestsなどの改造が必要」と書いていた。実装を読まずに推測した誤りで、上記の通り訂正した。
React と Vue でこの点に差はあるか
無い。フロント層は React 19 の JSX + hooks と Vue 3 の SFC + ref / computed で書き味が大きく違い、UI ライブラリも shadcn/ui と shadcn-vue に分かれる。しかし Inertia の出力する HTML は同一で、page object の載せ方も上記のデータブロックで変わらない。
production hardening の観点では、フロントフレームワークの違いは影響しない。 これが本記事を 1 本にまとめた根拠でもある。
J. 設定エンドポイントのレート制限が password だけ
routes/settings.php は、明示的な throttle ミドルウェアを password 更新ルートにしか付けていない。
Route::patch('settings/profile', ...)->name('profile.update'); // throttle なし
Route::delete('settings/profile', ...)->name('profile.destroy'); // throttle なし
Route::put('settings/password', ...)->middleware('throttle:6,1')...; // throttle あり
セッションが乗っ取られた場合、profile の連続書き換えやアカウント連続削除試行が、グローバルデフォルトの範囲で通ってしまう。
改修: React / Vue 版は設定変更が PATCH / DELETE という HTTP verb で素直に表現されているので、ルート定義に throttle を足すだけで済む。
- Route::patch('settings/profile', ...)->name('profile.update');
+ Route::patch('settings/profile', ...)->middleware('throttle:10,1')->name('profile.update');
- Route::delete('settings/profile', ...)->name('profile.destroy');
+ Route::delete('settings/profile', ...)->middleware('throttle:3,1')->name('profile.destroy');
アカウント削除は terminal な操作なので 3 回 / 分と厳しめに絞った。
Livewire 版ではこの修正が使えない。 Route::livewire 経由のコンポーネント内 AJAX なので、ルートに throttle を掛けても意図した単位にならない。詳細は Livewire 記事。
改良版の commit 構成
両フォークとも improvements ブランチに 8 commits(README Setup〔A〕/ .env〔B〕/ timezone〔C〕/ forceScheme〔E〕/ SetSecurityHeaders〔D〕/ rate limiter〔G〕/ auth log〔I〕/ settings throttle〔J〕)。B・C・D・E・G・I は pillar 記事、A・J が本記事の出典。
React 版にはさらに csp-nonce ブランチがあり、そちらは 48 passed / 164 assertions。
before / after(Inertia 固有部分)
| 観点 | 公式版 | 改良版 |
|---|---|---|
php artisan test |
40 passed / 136 assertions | 44 passed / 151 assertions |
| ビルド順序のドキュメント | なし | README に明記 |
| settings endpoints の throttle | password のみ | profile update / destroy にも |
共通 backend 6 件の before / after は pillar 記事を参照。
テスト再実行 (2026-07-23): 上の数値は 4 月の検証時のものなので、Docker で両フォークの
improvementsを実際に流し直した。react / vue とも 44 passed (151 assertions) で一致。React のcsp-nonceブランチも 48 passed (164 assertions) を再現した。
どのケースで向くか
laravel/react-starter-kitまたはlaravel/vue-starter-kitをテンプレに本番プロダクトを立ち上げる予定- React か Vue か検討中 → backend 化コストは同一。本記事の findings も同一。フロントの好み・採用市場・shadcn/ui か shadcn-vue かで決めるのが合理的。詳細は3 種比較記事
再現と取り込み
git clone https://github.com/codelift-dev/react-starter-kit.git # または vue-starter-kit
cd react-starter-kit
git diff origin/main improvements -- . ':!codelift'
この記事について(2026-07-23 統合)
本記事はもともと React 版と Vue 版で別々の 2 記事だった。統合した理由を書いておく。
検証を終えてみると、Inertia 固有の findings は A と J の 2 件で、どちらも React と Vue で完全に同一だった。テスト結果も 44 passed / 151 assertions で一致し、Vue 記事の独自内容はリポジトリ URL と commit ハッシュだけになっていた。当時は「fork が別リポジトリだから記事も分けるべき」と考えて 2 本にし、Vue 記事にはわざわざ「なぜ別記事なのか」という弁明の節まで置いていた。
弁明が必要な時点で分けるべきではなかった。 内容が同じ 2 ページより、両方を扱う 1 ページのほうが読む側にとって有用である。fork は 2 本のまま、記事を 1 本にした。
旧 URL は本記事へ 301 で転送している。
関連記事
- pillar: Laravel スターターキット共通 backend を本番化する 6 つの改修
- Livewire 版 — Inertia を使わないので構造が違う
- Inertia の CSP は nonce 化できる
- 比較: React / Vue / Livewire 比較
ライセンス
元サンプル / 改良版とも MIT。検証結果は検証日時点のもの。
この記事を含む比較
関連記事
- Livewire スターターキットを検証して改良した 公式の laravel/livewire-starter-kit(Livewire v4 + Flux + Alpine)を Docker で動かし、本番運用に耐える形に書き直したフォークを公開する。テストは公式版の 33 passed をベースに 37 passed / 92 assertions(2026-07-23 に Docker で再実行し一致を確認)。本記事は Livewire 固有の論点に絞る — 3 つのスターターキットの中で Livewire は最も ba…
- Laravel スターターキット共通 backend を本番化する 6 つの改修 Laravel 公式のスターターキット(React / Vue / Livewire)は、フロントエンド層こそ違うものの backend は同一の Laravel + Fortify コード を共有している。そのため、本番運用に向けた hardening も 3 つで共通する部分が大半を占める。本記事はその共通部分 — CodeLift が 3 つの fork すべてに適用した backend 改修 — を 1 か所にまとめた pillar(土台)記事である。
- Inertia の CSP は nonce 化できる(本体の改造は不要) Laravel + Inertia のアプリで Content-Security-Policy から 'unsafe-inline' を外そうとすると、「Inertia が初期 props を inline script に埋めるので無理」「Inertia 本体か HandleInertiaRequests を改造するしかない」という話に行き着くことが多い。