Daniel Kelly
Lead Instructor @ Vue School
Full Stack developer (10 years)
Husband and Father
Vue,
Inertia,
Laravel
Our story begins with two strangers
Our story begins with two strangers
Vs.
Our story begins with two strangers
Vs.
- Uses JavaScript
- Client-Side Rendering
- SPA Magic
- SFC-Powered Templating
- Uses PHP
- Server-Side Rendering
- Classic MPA
- Blade-Powered Templating
It all started when Laravel wanted to build modern, dynamic,
Single-Page Applications
This is when their paths crossed
Laravel sought a partner to collaborate with in achieving this goal.
Vue sparked Laravel's curiosity
In perfect sync, they weave magic
To work harmoniously together, they tried various techniques
Laravel Blade hosting the whole Vue instance
- Vue serves as the core application.
- Vue consumes Laravel APIs.
- Vue Router manages client-side navigation
Option 1
Decoupled Vue.js and Laravel Integration
- Vue serves as the core application.
- Vue consumes Laravel APIs.
- Vue Router manages client-side navigation
Option 2
Decoupled Nuxt.js and Laravel Integration
Option 3
- Nuxt serves as the core application.
- Nuxt consumes Laravel APIs.
- Nuxt handles client and server routing.
The Laravel Backends for Vue.js 3 Course
Laravel Blade hosting Vue SFCs
- Laravel serves as the core application.
- Data passed to Vue components via Laravel from the server.
- Laravel manages server-side navigation
Option 4
Each method, while effective, presented distinct challenges
Each method, while effective, presented distinct challenges
- Vue navigation overhead
- Giving up Laravel routing
- Laravel APIs for Vue
- SSR Complexity
- Global components bloat
- Shipping the component renderer to the browser
So what's a girl to do?
Is it time for Laravel and Vue to break up?
Inertia steps in
And changes everything!
Inertia who?
Inertia is
Not a Framework
Inertia is
The Modern Monolith
Inertia is
The Modern Monolith
- It serves as a smart approach to SPA development
- Enables developers to build modern single-page Vue, React, and Svelte apps using classic server-side routing and controllers.
- Designed for Laravel, Ruby on Rails, and Django developers.
Inertia is
The Modern Monolith
Build single-page apps,
without
building an API.
class UsersController
{
public function index()
{
$users = User::active()->orderByName()->get(['id', 'name', 'email']);
return Inertia::render('Users', [ 'users' => $users ]);
}
}
<!-- Pages/Users.vue -->
<script setup>
defineProps({ users: Array })
</script>
<template>
<div v-for="user in users" :key="user.id">
<p> {{ user.name }} </p>
</div>
</template>
But how is Inertia doing it?
https://vueschoo.io
Initial Visit
https://vueschoo.io
🌐
Server
Request
Initial Visit
https://vueschoo.io
🌐
Server
Request
Initial Visit
HTML
Response
https://vueschoo.io
🌐
Server
Request
Initial Visit
<html>
<head>
<title>VueSchool</title>
<link href="/css/app.css" rel="stylesheet">
<script src="/js/app.js" defer></script>
</head>
<body>
<div
id="app"
data-page='{"component":"Home","props":{"greet": "true"}'
></div>
</body>
</html>
🔎
The returned HTML contains a root div with data-page attribute
HTML
Response
https://vueschoo.io
🌐
Server
Request
Initial Visit
Response
<div
id="app"
data-page='{"component":"Home","props":{"greet": "true"}}'
></div>
HTML
Client
// Home.vue
<template>
<h1 v-if="greet"> Welcome to VueSchool </h1>
</template>
<script setup>
defineProps(['greet'])
</script>
Welcome To VueSchool
Inertia
https://vueschoo.io
Courses
👆
Client-Side Navigation
https://vueschoo.io
Courses
👆
Client-Side Navigation
🌐
Server
XHR Request
X-Inertia: true
Headers
https://vueschoo.io
Courses
👆
Client-Side Navigation
🌐
Server
XHR Request
X-Inertia: true
Headers
Inertia
https://vueschoo.io
Courses
👆
Client-Side Navigation
🌐
Server
XHR Request
X-Inertia: true
Headers
JSON Response
JSON
https://vueschoo.io
Courses
👆
Client-Side Navigation
🌐
Server
XHR Request
X-Inertia: true
Headers
JSON Response
JSON
RESPONSE
HTTP/1.1 200 OK
Content-Type: application/json
Vary: Accept
X-Inertia: true
{
"component": "Courses",
"props": {
"coursesList": [{}]
},
"url": "/courses",
"version": "version_number"
}
🔎
The returned JSON contains an encoded page object.
https://vueschoo.io
Client-Side Navigation
🌐
Server
XHR Request
X-Inertia: true
Headers
JSON Response
JSON
{
"component": "Courses",
"props": {
"coursesList": [{}]
},
"url": "/courses",
"version": "version_number"
}
// Courses.vue
<template>
<h1> Courses </h1>
<ul> <li v-for="course in courses"> course.name </li> </ul>
</template>
<script setup>
defineProps(['courses'])
</script>
Inertia
Courses
<a href="/courses">courses</a>
Courses
👆
https://vueschoo.io
<router-link to="/courses">courses</router-link>
import { Link } from '@inertiajs/vue3'
<Link href="/courses">Courses</Link>
Courses
👆
https://vueschoo.io
- Lightweight wrapper around a standard anchor tag.
- It intercepts the click event and prevents full page reloads.
Connects the Vue front-end with the Laravel backend.
You get to use Vue components with Laravel server-side routing
Smooth sailing for Laravel developers who uses Vue
No need for Laravel APIs
SPA Haven
Routing
No need for Vue Router to handle client-side routing
Route::get('/courses', function () {
return Inertia::render('Courses', [
'canView' => Route::has('subscribed'),
'coursesData' => data
]);
})->name('courses');
You can create Laravel web routes and use Inertia::render to render the corresponding page
Routing
Route::get('/courses', function () {
return Inertia::render('Courses', [
'canView' => Route::has('subscribed'),
'coursesData' => data
]);
})->name('courses');
This will render the Courses.vue component
from the '~/resources/js/Pages/' directory
Routing
/* ~/routes/web.php */
Route::get('/courses', [CoursesController::class, 'index'])->name('courses');
We can also use controllers
/* ~/app/Http/Controllers/CoursesController.php */
use Inertia\Inertia;
public function index() {
return Inertia::render('Courses', [
'canView' => Route::has('subscribed'),
'coursesData' => data
]);
}
Authentication
You get to keep you server-side Laravel authentication system 😎
Server-Side Rendeirng
Inertia supports Server-Side Rendering
Inertia supports Server-Side Rendering
Can easily setup Inertia with SSR with Laravel Breeze and JetStream
php artisan breeze:install react --ssr
php artisan breeze:install vue --ssr
Server-Side Rendeirng
Sharing Data
use Inertia\Inertia;
// Synchronously...
Inertia::share('appName', config('app.name'));
The Inertia::share feature allows for global data sharing. This means that the specified data will be included in every request's response.
use Inertia\Inertia;
use App\Models\Cart;
// Lazy...
Inertia::share('shoppingCart', fn () => auth()->user()
? Cart::where('user_id', auth()->user()->id)->get()
: null
);
Accessing Shared Data
Shared data will be available in usePage().props
// useShoppingCart() composable
import { computed } from "vue";
import { usePage } from "@inertiajs/vue3";
export function useShoppingCart() {
const page = usePage();
return computed(() => page.props.shoppingCart);
}
<script setup>
import { useShoppingCart } from "../Composables/useUser";
const shoppingCart = useShoppingCart();
</script>
<template>
<ul>
<li v-for="cartItem in shoppingCart.items">{{ cartItem.name }}</li>
</ul>
</template>
SEO - <Head>
Inertia provides helper component for the page meta
<Head>
<title>VueSchool</title>
<meta name="description" content="Awesome learning experience">
</Head>
<Link>
<Link href="/logout"
method="post"
as="button"
type="button"
>
Logout
</Link>
// Renders as...
<button type="button">Logout</button>
Can be displayed as any HTML element using the as attribute
<Link>
<Link href="/logout"
method="post"
as="button"
type="button"
>
Logout
</Link>
// Renders as...
<button type="button">Logout</button>
Can send POST/PUT/PATCH/DELETE requests using the method attribute
<Link>
<Link href="/endpoint"
method="post"
:data="{ foo: bar }"
>
Save
</Link>
When making POST or PUT requests, you can add additional data to the request using the data attribute.
<Link>
<Link href="/endpoint"
method="post"
:data="{ foo: bar }"
:headers="{ foo: bar }"
>
Save
</Link>
The headers attribute allows you to add custom headers to an Inertia link
Forms
<script setup>
import { useForm } from '@inertiajs/vue3'
const form = useForm({
email: null,
})
</script>
<template>
<form @submit.prevent="form.post('/newsletter')">
<input type="text" v-model="form.email">
<div v-if="form.errors.email">{{ form.errors.email }}</div>
<button type="submit" :disabled="form.processing">Subscribe</button>
</form>
</template>
Inertia includes a form helper designed to help reduce the amount of boilerplate code needed for handling typical form submissions.
Forms
<script setup>
import { useForm } from '@inertiajs/vue3'
const form = useForm({
email: null,
})
</script>
<template>
<form @submit.prevent="form.post('/newsletter')">
<input type="text" v-model="form.email">
<div v-if="form.errors.email">{{ form.errors.email }}</div>
<button type="submit" :disabled="form.processing">Subscribe</button>
</form>
</template>
To submit the form, you may use the get, post, put, patch and delete methods.
Validation
<script setup>
import { useForm } from '@inertiajs/vue3'
const form = useForm({
email: null,
})
</script>
<template>
<form @submit.prevent="form.post('/newsletter')">
<input type="text" v-model="form.email">
<div v-if="form.errors.email">{{ form.errors.email }}</div>
<button type="submit" :disabled="form.processing">Subscribe</button>
</form>
</template>
If there are form validation errors, they are available via the errors property.
Remembering State
<script setup>
import { useForm } from '@inertiajs/vue3'
const form = useForm('uniqueId', {
email: null,
})
</script>
By providing a unique ID to the useForm helper,
the form data and errors will automatically be remembered
if the user navigates away
CSRF protection
When using Inertia with Laravel, you get CSRF protection out of the box. no additional configuration is required
File Upload
<script setup>
import { useForm } from '@inertiajs/vue3'
const form = useForm({
avatar: null,
})
</script>
<template>
<form @submit.prevent="form.post('/avatars')">
<input type="file" @input="form.avatar = $event.target.files[0]" />
<progress v-if="form.progress" :value="form.progress.percentage" max="100">
{{ form.progress.percentage }}%
</progress>
<button type="submit">Submit</button>
</form>
</template>
When making Inertia requests that include files, Inertia will automatically convert the request data into a FormData object.
File Upload
<script setup>
import { useForm } from '@inertiajs/vue3'
const form = useForm({
avatar: null,
})
</script>
<template>
<form @submit.prevent="form.post('/avatars')">
<input type="file" @input="form.avatar = $event.target.files[0]" />
<progress v-if="form.progress" :value="form.progress.percentage" max="100">
{{ form.progress.percentage }}%
</progress>
<button type="submit">Submit</button>
</form>
</template>
The form helper provides easy access to the current upload progress
Partial Reloads
import { router } from '@inertiajs/vue3'
router.reload({ only: ['courses'] })
When re-requesting the same page, you can selectively reload specific properties without altering surrounding data.
Partial Reloads
import { router } from '@inertiajs/vue3'
router.reload({ only: ['courses'] })
In this example, only the 'courses' prop will be updated when the page is reloaded.
This is thanks to the 'only' property.
Partial Reloads
import { router } from '@inertiajs/vue3'
router.visit('/endpoint', {
only: ['courses'],
})
You can also do partial visits to other urls and only update specific page props.
Partial Reloads
import { Link } from '@inertiajs/vue3'
<Link href="/courses?free=true" :only="['courses']">Show Free Courses</Link>
The 'only' option is also available as a prop to the <Link> component.
Inertia, Vue, and Laravel collaborated seamlessly, enabling the creation of single-page, dynamic, server-side driven apps.
It still got so many more features to explore
inertiajs.com
But, it's not the only way to do it
But before I go!
vue.school/masterclass
Grab Some Swag 🤗
Mostafa Said
Thanks
@Moose_Said
For developing much of this talk
danielkelly_io
I'll tweet out the slides after this
Thank you 🙏
Go code awesome things!
(with Vue and Laravel 😉)
Vue, Inertia and Laravel
By Daniel Kelly
Vue, Inertia and Laravel
- 593