Inertia.js + Vue 3 w PHP - Nowoczesne SPA bez API
Czym jest Inertia.js?
Inertia.js to protokół pozwalający na budowanie Single Page Applications (SPA) w sposób, który eliminuje konieczność pisania dedykowanego API. Zamiast tradycyjnego podejścia REST/GraphQL API + frontend framework, Inertia działa jako "most" między serwerem PHP a frontendem Vue/React/Svelte.
Dlaczego Inertia.js?
Kluczowe zalety
- Brak potrzeby API - serwer zwraca dane bezpośrednio do komponentów Vue
- Natywne routowanie - używasz routingu PHP zamiast Vue Router
- Server-side rendering opcjonalnie - łatwa migracja do SSR
- Zachowanie stanu - automatyczne zarządzanie historią przeglądarki
- Płynne przejścia - doświadczenie jak w natywnej SPA
Jak działa protokół Inertia.js?
Protokół Inertia definiuje sposób komunikacji między serwerem a klientem poprzez specjalne nagłówki HTTP i format danych JSON.
Żądania Inertia
Gdy użytkownik klika w link lub przesyła formularz, Inertia wysyła żądanie AJAX z nagłówkiem X-Inertia: true
. Serwer rozpoznaje to i zwraca dane w specjalnym formacie JSON zamiast pełnego HTML.
Odpowiedzi serwera
{
"component": "Home/Index",
"props": {
"user": {
"id": 1,
"name": "Jan Kowalski",
"email": "jan@example.com"
},
"posts": [
{"id": 1, "title": "Pierwszy post"},
{"id": 2, "title": "Drugi post"}
]
},
"url": "/dashboard",
"version": "1.0"
}
Pierwsze załadowanie
Przy pierwszym wejściu na stronę (bez nagłówka X-Inertia), serwer zwraca pełny HTML z zainicjalizowaną aplikacją Vue. Dane strony są przekazywane jako JSON w znaczniku data-page
.
Integracja z Laravelem vs własny framework
Laravel posiada gotową paczkę do Inertia, która znacznie upraszcza integrację. W kursie PHP 8.4 implementujemy własną, pełną integrację Inertia.js, co pozwala zrozumieć dokładnie jak działa protokół pod spodem.
Laravel (gotowe rozwiązanie)
<?php
// W kontrolerze Laravel
use Inertia\Inertia;
class DashboardController extends Controller
{
public function index()
{
return Inertia::render('Dashboard/Index', [
'stats' => [
'users' => User::count(),
'posts' => Post::count(),
]
]);
}
}
Własny framework (nasza implementacja)
<?php
// Implementujemy od zera
class Inertia
{
private array $sharedData = [];
public function share(string|array $key, mixed $value = null): void
{
if (is_array($key)) {
$this->sharedData = array_merge($this->sharedData, $key);
} else {
$this->sharedData[$key] = $value;
}
}
public function render(string $component, array $props = []): ResponseInterface
{
$page = [
'component' => $component,
'props' => array_merge($this->sharedData, $props),
'url' => $_SERVER['REQUEST_URI'],
'version' => '1.0',
];
return $this->responseFactory->createResponse($page);
}
}
Implementacja ResponseFactory
ResponseFactory decyduje, czy zwrócić odpowiedź JSON (dla żądań Inertia) czy pełny HTML (dla pierwszego załadowania).
<?php
class ResponseFactory
{
public function createResponse(array $page): ResponseInterface
{
// Sprawdź czy to żądanie Inertia
if ($this->isInertiaRequest()) {
return $this->createInertiaResponse($page);
}
// Pierwsze załadowanie - zwróć pełny HTML
return $this->createHtmlResponse($page);
}
private function isInertiaRequest(): bool
{
return isset($_SERVER['HTTP_X_INERTIA'])
&& $_SERVER['HTTP_X_INERTIA'] === 'true';
}
private function createInertiaResponse(array $page): ResponseInterface
{
return new JsonResponse($page, 200, [
'X-Inertia' => 'true',
'Vary' => 'Accept',
]);
}
private function createHtmlResponse(array $page): ResponseInterface
{
$html = view('app', [
'page' => json_encode($page)
]);
return new Response($html);
}
}
InertiaMiddleware - obsługa protokołu
Middleware Inertia odpowiada za przygotowanie środowiska dla żądań Inertia, w tym ustawienie głównego widoku i danych współdzielonych.
<?php
class InertiaMiddleware implements MiddlewareInterface
{
public function process(
ServerRequestInterface $request,
RequestHandlerInterface $handler
): ResponseInterface {
// Ustaw root view dla Inertia
app(Inertia::class)->withRootView('inertia');
// Współdziel dane dostępne w każdym komponencie
app(Inertia::class)->share([
'auth' => [
'user' => auth()->user(),
],
'flash' => [
'success' => session('success'),
'error' => session('error'),
],
]);
return $handler->handle($request);
}
}
Root View - punkt wejścia aplikacji
Root view to główny widok Blade, który ładuje aplikację Vue i inicjalizuje Inertia.
<!DOCTYPE html>
<html lang="pl">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
@inertiaHead
@vite('resources/js/app.js')
</head>
<body>
@inertia
</body>
</html>
Dyrektywy Blade dla Inertia
@inertiaHead - nagłówki strony
<?php
class InertiaHeadDirective extends Directive
{
public function compile(string $template): string
{
return str_replace(
'@inertiaHead',
'<?php echo app(Inertia::class)->head(); ?>',
$template
);
}
}
@inertia - kontener aplikacji
<?php
class InertiaDirective extends Directive
{
public function compile(string $template): string
{
$replacement = '<div id="app" data-page=\'<?php echo json_encode($page); ?>\'></div>';
return str_replace('@inertia', $replacement, $template);
}
}
Integracja z Vite
Vite to nowoczesny bundler oferujący szybkie ładowanie modułów i efektywną kompilację. Dyrektywa @vite
w Blade automatycznie ładuje zasoby w odpowiednim trybie (development/production).
Konfiguracja vite.config.js
import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';
export default defineConfig({
plugins: [vue()],
build: {
manifest: true,
outDir: 'public/build',
rollupOptions: {
input: 'resources/js/app.js',
},
},
server: {
host: 'localhost',
port: 5173,
hmr: {
host: 'localhost',
},
},
});
Konfiguracja Vue 3 z Inertia
app.js - inicjalizacja aplikacji
import { createApp, h } from 'vue'
import { createInertiaApp } from '@inertiajs/vue3'
createInertiaApp({
resolve: name => {
const pages = import.meta.glob('./Pages/**/*.vue', { eager: true })
return pages[`./Pages/${name}.vue`]
},
setup({ el, App, props, plugin }) {
createApp({ render: () => h(App, props) })
.use(plugin)
.mount(el)
},
})
Formularze w Inertia - useForm
Hook useForm
zapewnia wygodne API do obsługi formularzy z automatyczną walidacją błędów.
<script setup>
import { useForm } from '@inertiajs/vue3'
const form = useForm({
name: '',
email: '',
password: '',
})
const submit = () => {
form.post('/register', {
onSuccess: () => form.reset(),
onError: () => {
// Błędy automatycznie dostępne w form.errors
}
})
}
</script>
<template>
<form @submit.prevent="submit">
<div >
<label>Imię</label>
<input v-model="form.name" type="text" >
<div v-if="form.errors.name" >
{{ form.errors.name }}
</div>
</div>
<div >
<label>Email</label>
<input v-model="form.email" type="email" >
<div v-if="form.errors.email" >
{{ form.errors.email }}
</div>
</div>
<div >
<label>Hasło</label>
<input v-model="form.password" type="password" >
<div v-if="form.errors.password" >
{{ form.errors.password }}
</div>
</div>
<button type="submit" :disabled="form.processing" >
<span v-if="form.processing">Przetwarzanie...</span>
<span v-else>Zarejestruj</span>
</button>
</form>
</template>
Vue 3 Composition API - przegląd
W kursie wykorzystujemy nowoczesne Composition API z składnią <script setup>
, która jest prostsza i bardziej zwięzła niż Options API.
Reactive state
<script setup>
import { ref, reactive, computed } from 'vue'
// ref - dla prostych wartości
const count = ref(0)
const increment = () => count.value++
// reactive - dla obiektów
const state = reactive({
user: null,
loading: false
})
// computed - obliczane wartości
const doubleCount = computed(() => count.value * 2)
</script>
Najlepsze praktyki przy korzystaniu z Inertia.js + vue3
- Używaj
shared data
dla danych dostępnych globalnie (user, flash messages) - Lazy load komponentów Vue dla lepszej wydajności
- Wykorzystuj TypeScript dla type safety
- Stosuj Composition API + script setup dla czystszego kodu
- Pamiętaj o responsywności - testuj na mobile
🎓 Zbuduj SPA z Inertia.js od zera!
W kursie PHP 8.4 implementujesz pełną integrację Inertia.js z własnym frameworkiem PHP - od ResponseFactory i middleware, przez dyrektywy Blade (@inertia, @vite), aż po zaawansowane komponenty Vue 3 z Composition API. Poznasz protokół Inertia od podszewki i zbudujesz nowoczesną SPA bez pisania API.