Inertia.js для PHP: полное руководство с примерами

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Inertia.js для PHP: полное руководство с примерами

1. Что это и зачем нужна

Inertia.js — это не фреймворк и не библиотека для создания SPA (Single Page Application) в классическом понимании. Это скорее «мост» или «адаптер», который позволяет создавать современные одностраничные приложения, используя классический серверный фреймворк (в нашем случае Laravel на PHP) и любой современный фронтенд-фреймворк (React, Vue.js или Svelte) без необходимости писать отдельный REST API.

Главная проблема, которую решает Inertia.js — это отказ от традиционного подхода «сервер рендерит HTML» или «сервер отдаёт JSON, а фронтенд сам решает, что рисовать». Вместо этого Inertia предлагает третий путь: вы пишете контроллеры на PHP как обычно, но вместо возврата Blade-шаблона или JSON-ответа, вы возвращаете Inertia-ответ с данными и именем компонента. Inertia на клиенте (JavaScript) перехватывает этот ответ, находит нужный компонент (React/Vue) и рендерит его, подставляя полученные данные. Навигация между страницами происходит без полной перезагрузки, как в SPA, но весь роутинг и бизнес-логика остаются на сервере.

Зачем это нужно? Во-первых, это резко упрощает архитектуру: вам не нужно поддерживать два отдельных приложения (бэкенд API и фронтенд SPA) с дублированием логики авторизации и валидации. Во-вторых, это сохраняет все преимущества Laravel (ORM Eloquent, Blade-компоненты для писем, Artisan, middleware) и все преимущества React/Vue (реактивность, компонентный подход, огромная экосистема). В-третьих, это даёт отличный Developer Experience (DX): вы работаете в одном репозитории, используете один роутер (Laravel), а Inertia прозрачно управляет состоянием приложения на клиенте.

2. Установка

Установка состоит из двух частей: серверной (PHP) и клиентской (JavaScript). Предполагается, что у вас уже установлен Laravel (версия 8, 9, 10 или 11).

Шаг 1: Установка серверного пакета (PHP)

Выполните в терминале в корне вашего Laravel-проекта:

composer require inertiajs/inertia-laravel

Шаг 2: Установка клиентского адаптера (JavaScript)

Выберите ваш фронтенд-фреймворк и выполните соответствующую команду:

Для React:

npm install @inertiajs/react react react-dom

Для Vue 3:

npm install @inertiajs/vue3 vue

Для Svelte:

npm install @inertiajs/svelte svelte

Шаг 3: Публикация конфигурации (опционально)

php artisan vendor:publish --provider="Inertia\ServiceProvider"

Шаг 4: Настройка корневого шаблона

Создайте файл resources/views/app.blade.php со следующим содержимым:

<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>@yield('title', config('app.name'))</title>
    @viteReactRefresh
    @vite(['resources/js/app.jsx'])
    @inertiaHead
</head>
<body>
    @inertia
</body>
</html>

Директива @inertia — это место, куда Inertia будет вставлять ваше приложение. @inertiaHead — для управления заголовками из компонентов.

Шаг 5: Настройка Vite (если используете Vite)

В файле vite.config.js добавьте плагин для React или Vue:

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

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

3. Быстрый старт — минимальный рабочий пример

Создадим простую страницу «О нас».

Шаг 1: Контроллер

Создайте контроллер app/Http/Controllers/PageController.php:

<?php

namespace App\Http\Controllers;

use Inertia\Inertia;

class PageController extends Controller
{
    public function about()
    {
        return Inertia::render('About', [
            'companyName' => 'PythonLib',
            'year' => date('Y'),
        ]);
    }
}

Шаг 2: Роут

Добавьте в routes/web.php:

use App\Http\Controllers\PageController;

Route::get('/about', [PageController::class, 'about']);

Шаг 3: Компонент React

Создайте файл resources/js/Pages/About.jsx:

import React from 'react';
import { Head } from '@inertiajs/react';

export default function About({ companyName, year }) {
    return (
        <>
            <Head title="О нас" />
            <div className="container mx-auto p-8">
                <h1 className="text-3xl font-bold">О компании {companyName}</h1>
                <p className="mt-4 text-gray-600">Год основания: {year}</p>
            </div>
        </>
    );
}

Шаг 4: Точка входа

Файл resources/js/app.jsx:

import React from 'react';
import { createInertiaApp } from '@inertiajs/react';
import { createRoot } from 'react-dom/client';

createInertiaApp({
    resolve: name => {
        const pages = import.meta.glob('./Pages/**/*.jsx', { eager: true });
        return pages[`./Pages/${name}.jsx`];
    },
    setup({ el, App, props }) {
        createRoot(el).render(<App {...props} />);
    },
});

Теперь перейдите по адресу /about — вы увидите страницу, отрендеренную React, но данные пришли из PHP-контроллера.

4. Основные методы/функции/классы

4.1. Inertia::render()

Сигнатура: Inertia::render(string $component, array $props = []): \Inertia\Response

Что делает: Основной метод для возврата Inertia-ответа. Принимает имя компонента (без расширения) и массив данных (props), которые будут переданы на фронтенд.

Пример:

return Inertia::render('Users/Index', [
    'users' => User::all(),
    'filters' => request()->only(['search', 'role']),
]);

4.2. Inertia::location()

Сигнатура: Inertia::location(string $url): \Symfony\Component\HttpFoundation\RedirectResponse

Что делает: Выполняет полную переадресацию браузера (не SPA-навигацию). Используется для редиректов на внешние сайты или для выхода из приложения Inertia (например, при logout).

Пример:

return Inertia::location('https://example.com/external-page');

4.3. Inertia::share()

Сигнатура: Inertia::share(string|array $key, mixed $value = null): void

Что делает: Позволяет передавать данные (например, текущего пользователя, настройки) во все компоненты глобально, без необходимости передавать их в каждом render().

Пример (в AppServiceProvider::boot()):

Inertia::share('auth.user', function () {
    return auth()->user() ? [
        'id' => auth()->user()->id,
        'name' => auth()->user()->name,
        'email' => auth()->user()->email,
    ] : null;
});

// Или массивом:
Inertia::share([
    'appName' => config('app.name'),
    'flash' => function () {
        return [
            'success' => session('success'),
            'error' => session('error'),
        ];
    },
]);

4.4. Inertia::getShared()

Сигнатура: Inertia::getShared(string|null $key = null): mixed

Что делает: Позволяет получить ранее переданные через share() глобальные данные. Если ключ не указан, возвращает все данные.

Пример:

$user = Inertia::getShared('auth.user');
$allShared = Inertia::getShared();

4.5. Inertia::lazy()

Сигнатура: Inertia::lazy(\Closure|callable $callback): \Inertia\LazyProp

Что делает: Позволяет отложить загрузку «тяжёлых» данных. Данные будут запрошены только тогда, когда компонент их явно запросит (через специальный запрос на сервер). Критически важно для производительности больших страниц.

Пример:

return Inertia::render('Dashboard', [
    'userCount' => User::count(), // всегда загружается
    'recentPosts' => Inertia::lazy(fn () => Post::latest()->take(10)->get()), // загружается лениво
]);

4.6. Inertia::always()

Сигнатура: Inertia::always(string $key, \Closure|callable $callback): void

Что делает: Похож на share(), но данные вычисляются каждый раз при запросе, а не кешируются. Полезно для данных, которые могут меняться между запросами (например, количество уведомлений).

Пример:

Inertia::always('notificationsCount', function () {
    return auth()->user()?->unreadNotifications()->count() ?? 0;
});

4.7. Inertia::version()

Сигнатура: Inertia::version(string $version): void

Что делает: Устанавливает версию ассетов (CSS/JS). Когда версия меняется, Inertia автоматически выполняет полную перезагрузку страницы, чтобы избежать ошибок из-за несоответствия кода.

Пример (в AppServiceProvider):

Inertia::version(fn () => md5_file(public_path('mix-manifest.json'))); // для Laravel Mix
// или для Vite:
Inertia::version(fn () => filemtime(public_path('build/manifest.json')));

4.8. Inertia::getVersion()

Сигнатура: Inertia::getVersion(): string|null

Что делает: Возвращает текущую версию ассетов, установленную через version().

Пример:

$currentVersion = Inertia::getVersion(); // 'a1b2c3d4...'

5. Реальный практический пример (CRUD для постов блога)

Создадим полноценный CRUD для постов с пагинацией, поиском и flash-сообщениями.

Контроллер: app/Http/Controllers/PostController.php

<?php

namespace App\Http\Controllers;

use App\Models\Post;
use Illuminate\Http\Request;
use Inertia\Inertia;

class PostController extends Controller
{
    public function index(Request $request)
    {
        $query = Post::query();

        // Поиск по заголовку
        if ($search = $request->input('search')) {
            $query->where('title', 'like', "%{$search}%");
        }

        $posts = $query->orderBy('created_at', 'desc')
                       ->paginate(10)
                       ->withQueryString(); // сохраняем параметры запроса в пагинации

        return Inertia::render('Posts/Index', [
            'posts' => $posts,
            'filters' => $request->only(['search']),
        ]);
    }

    public function create()
    {
        return Inertia::render('Posts/Create');
    }                    

Рекомендаций