Photo by "My Life Through A Lens" on Unsplash
Creating Laravel + Vue + Inertia project
A little step-by-step guide
Update. Code snippets updated to use Inertia.js 1.0.
Recently, I've been learning what's new in the Laravel world, and I've got pretty excited about Laravel, Vue.js and Inertia.js combo.
Really, it combines the smoothness of single-page applications (SPA) and SEO friendliness of traditional server-rendered websites.
However, it's not trivial to set it up from scratch - you have to check the docs of all three technologies. So, I've made a little step-by-step guide for myself and made sure that it works.
Hopefully, it'll be useful for you, too.
And if you are impatient, like me, you can grab the working project template from GitHub.
OK, let's get started!
Create new Laravel project
# Create a project
cd ~/projects
laravel new ssr
cd ssr
# Serve the application on the PHP development server
# Keep it running in a separate terminal session
php artisan serve
# Test it by opening http://127.0.0.1:8000/ in the browser
Install and configure the server-side Inertia
Install the Inertia server-side package:
composer require inertiajs/inertia-laravel
Setup the root template,
resources/views/app.blade.php
that will be loaded on the first page visit:<!DOCTYPE html> <html lang="{{ str_replace('_', '-', app()->getLocale()) }}"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> @vite('resources/js/app.js') @inertiaHead </head> <body> @inertia </body> </html>
Create the Inertia middleware that will process AJAX loading of the pages:
php artisan inertia:middleware
Register the
HandleInertiaRequests
middleware in yourApp\Http\Kernel
, as the last item in your web middleware group:'web' => [ // ... \App\Http\Middleware\HandleInertiaRequests::class, ],
Replace the home page route in the
routes/web.php
with the code that renders a Vue template (we’ll implement theHome
component in a minute):Route::get('/', function () { return inertia('Home'); });
Remove the
resources/views/welcome.blade.php
.
Install and configure the client-side Inertia, Vue3 and Tailwind
Install the required Node packages:
npm install vue @inertiajs/vue3 npm install --dev @vitejs/plugin-vue tailwindcss autoprefixer
Update your main JavaScript file,
resources/js/app.js
, to boot your Inertia app:import './bootstrap'; import '../css/app.css'; 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) }, })
In
vite.config.js
, configure Vite to handle Vue templates:import { defineConfig } from 'vite'; import laravel from 'laravel-vite-plugin'; import vue from '@vitejs/plugin-vue'; export default defineConfig({ plugins: [ laravel({ input: 'resources/js/app.js', refresh: true, }), vue({ template: { transformAssetUrls: { base: null, includeAbsolute: false, }, }, }), ], });
Add
postcss.config.cjs
to enable Tailwind CSS post processing:module.exports = { plugins: { tailwindcss: {}, autoprefixer: {}, }, }
Create
tailwind.config.js
to specify directories that should be handled by Tailwind CSS:module.exports = { content: [ "./resources/**/*.blade.php", "./resources/**/*.js", "./resources/**/*.vue", ], }
Add Tailwind CSS styles to your main CSS file,
resources/css/app.css
:@tailwind base; @tailwind components; @tailwind utilities;
Create the
resources/js/Pages/Home.vue
component:<script setup> import { Head } from '@inertiajs/vue3'; </script> <template> <Head> <title>Hello, world!</title> </Head> <main class="fixed inset-0 grid place-items-center"> <h1 class="text-2xl">Hello, world!</h1> </main> </template>
Build the JavaScript and CSS assets:
# Keep it running in a separate terminal session npm run dev
If you use PHPStorm, add
jsconfig.json
to help resolvingimport ... '@...'
statements:{ "compilerOptions": { "baseUrl": ".", "paths": { "@/*": ["resources/js/*"] } }, "exclude": ["node_modules", "public"] }