概要
Laravelで開発していたAltaryを、Inertia.js導入で高速化しました。
その経緯と、実際の導入手順をまとめます。
経緯
- マネージャーから「サイトを高速化したい」という要望があった
- 当初は完全SPA化も検討した
- ただ、移行コストが大きく、認証/セキュリティ再設計の不安があった
- 調査の結果、Laravelの強みを活かしつつSPA体験を得られるInertia.jsが最適と判断
Inertia.js とは
- LaravelなどのサーバーサイドとReact/Vue/Svelteを「SPAの体験」でつなぐライブラリ
- APIを別途作らずに、サーバー側でページを返しつつ、クライアントサイド遷移を実現
- Laravel公式ドキュメントでも、Inertiaは推奨フロントエンド構成の一つとして紹介されている
※参考(Laravel 12.x公式): https://laravel.com/docs/12.x/frontend#inertia
Inertiaのメリット
Laravelの従来構成、完全SPA構成、Inertia構成の違いをざっくり比較すると以下の通りです。
| 構成 | 長所 | 短所 |
|---|---|---|
| Laravel(従来) | サーバー側で完結し、認証・CSRF・バリデーションが素直に使える | 画面遷移ごとにリロードが発生しやすい |
| Laravel(完全SPA) | 画面遷移が最速で、フロント表現の自由度が高い | API設計が必須で、認証/セキュリティの実装が複雑になりやすい |
| Laravel + Inertia | 既存の認証・セキュリティを活かしつつSPA体験を得られる | SPAほどの自由度はないため、設計に工夫が必要 |
つまり、Inertiaを使うメリットは「Laravelの強み(認証・セキュリティ・バリデーション)を保ったまま、 SPAの体験を得られること」にあります。
※ ただし、完全にフロント主導で複雑な状態管理が必要な場合(例:リアルタイムダッシュボード等)は、完全SPAが適するケースもあります。
導入の全体像
大まかな流れは以下です。
- Inertia.jsをプロジェクトに導入
- Inertiaのエントリーポイントを整備(
createInertiaApp) - 既存BladeページをInertiaページへ段階的に移行
- ナビゲーションを
Link/router.visitに置き換え - フォーム・CSRF・セッション周りを確認
1. Inertia.js導入(Laravel + React例)
最小構成なら以下が出発点になります。
composer require inertiajs/inertia-laravel
npm install @inertiajs/react
resources/js/app.jsx などに createInertiaApp を設定します。
createInertiaApp({
title: title => title ? `${title} - Altary` : 'Altary',
resolve: name => {
const pages = import.meta.glob('./src/pages/**/*.tsx', { eager: true })
let component = pages[`./src/pages/${name}.tsx`]
if (!component) {
component = pages[`./src/pages/${name}/index.tsx`]
}
if (!component) {
throw new Error(`Page ${name} not found`)
}
return component
},
setup({ el, App, props }) {
const root = createRoot(el)
root.render(<App {...props} />)
},
})
ポイントは index.tsx も拾えるようにしておくこと。
移行フェーズで pages/foo/index.tsx が増えるので、この形が扱いやすいです。
2. BladeからInertiaへ置き換え
コントローラの return view(...) を Inertia::render(...) に変えていきます。
// 旧: Blade
return view('pages.public_page', $data);
// 新: Inertia
return \Inertia\Inertia::render('public-page/index', [
'user' => $user,
'csrfToken' => csrf_token(),
]);
propsはできるだけ明示的に渡すのがポイントです。
実案件でも、
view('pages.***') を Inertia::render('***') に置換しつつ、
csrfToken や user など必要な値だけを渡す形に整理すると安全です。
3. 旧「window.renderX」方式を廃止
Blade+JSでやっていた window.renderX のような初期化関数は、
Inertiaページの通常コンポーネントに置き換えます。
// 旧: window.renderX で初期化
declare global {
interface Window {
renderDashboard: (el: HTMLElement, data?: Props) => void;
}
}
window.renderDashboard = (el: HTMLElement, data?: Props) => {
if (!el) return;
const root = createRoot(el);
root.render(
<AppProviders>
<Dashboard {...data} />
</AppProviders>
);
};
// 新: Inertiaページとして通常のコンポーネント化
const DashboardPageComponent: React.FC<Props> = (props) => {
return (
<>
<Head title="管理画面 - サンプル" />
<AppProviders>
<Dashboard {...props} />
</AppProviders>
</>
);
};
これにより ページごとの初期化コードが不要になります。
実際の移行でも、各ページをこの形にそろえると保守が楽になります。
4. SPAナビゲーションへ切り替え
リンクは<a>ではなく InertiaのLinkを使用します。
import { Link } from '@inertiajs/react';
<Link href="/app">管理画面</Link>
JSでの遷移も window.location.href から router.visit へ移行します。
import { router } from '@inertiajs/react';
router.visit('/app');
これだけで、ページ遷移時のリロードがなくなります。
実際の移行でも、
<a> から Link への一括置換で遷移が安定します。
5. フォームとCSRF対応
Inertia環境でもCSRFは重要です。
従来の meta[name="csrf-token"] を活かして fetch へ付与します。
const token =
csrfToken ||
document.querySelector('meta[name="csrf-token"]')?.getAttribute('content') ||
'';
await fetch('/account/update', {
method: 'POST',
headers: {
'X-CSRF-TOKEN': token,
'X-Requested-With': 'XMLHttpRequest',
'Accept': 'application/json',
},
body: formData,
credentials: 'same-origin',
});
既存のAPI/フォームを壊さないためにも、CSRFをpropsで渡す or metaで拾うの二段構えはおすすめです。
実案件でも、
csrfToken をprops優先→meta fallbackの形にしておくと安心です。
高速化の成果
- ページ遷移の体感が軽くなり、リロード待ちがほぼなくなった
- 初回ロード以降の画面切り替えがスムーズになった
- 導入後にユーザーから「表示が速くなった」という反応が得られた
まとめ
- 完全SPA化はコストとリスクが大きいので、Inertiaは現実的な選択肢
- Laravelの認証・セキュリティを活かしつつSPA体験を得られる
- 導入は「ページ単位の段階移行」が安全で進めやすい
出典
- Laravel 12.x公式 https://laravel.com/docs/12.x/frontend#inertia
- Inertia.js公式 https://inertiajs.com/