{} CodeLift

Inertia 系スターターキット(React / Vue)を検証して改良した

公式の laravel/react-starter-kit と laravel/vue-starter-kit を Docker で動かし、本番運用に耐える形へ書き直したフォークを 2 本公開している。テストはどちらも 40 passed → 44 passed / 151 assertions。

公開 2026-04-19 検証 2026-04-19 更新 2026-08-12

検証環境

  • 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-kitlaravel/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 依存が未インストールだと artisanvendor/autoload.php を読めずに落ちる。

なぜ厄介か: エラーメッセージに composer install の文字が一切出ない。初見の開発者は Vite か Wayfinder のバグを疑い、見当違いの方向に時間を溶かす。vendor/autoload.php というパスから「Composer をまだ流していない」と即座に気付けるのは、Laravel に慣れた人だけである。

改修: README に Setup セクションを追加し、composer installnpm 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 で転送している。

関連記事

ライセンス

元サンプル / 改良版とも MIT。検証結果は検証日時点のもの。

この記事を含む比較

関連記事