Project Log: building a quiz app in Laravel + Vue + Inertia

Table of contents

Introduction
Laravel and Vue are objectively cool together (literally they’re complementary colors!), and they are the combination we use in some of our projects at work, so I decided it would be fun to get more comfortable with how they operate together.
Thus, I decided to start a project using them, along with Inertia. Disclaimer: I do not know what I am doing. Don’t take this as the official way to do anything. If it is it’s only by accident.
What’s the project?
I am going to build a language quiz app eventually, probably for Latin. To start with it will be a simple vocabulary list that will be searchable and sortable. The goal is to eventually draw in Latin vocabulary from an API and then select words randomly or chosen intentionally from that list to turn into a vocabulary quiz. But I have yet to find an accessible Latin vocabulary a API. Hehe.
Setting up
Laravel
To start this setup section we’re going to create a new Laravel project from the command line using composer.
In your terminal, navigate to the directory where you’d like to create a new project and then type:
composer create-project laravel/laravel name-of-my-project
That will create a Laravel project for you inside your chosen directory. Then you can open that up either through your Finder or by (my favorite way to do it) cd name-of-my-project
and then code .
to open up a new VSCode window in your new project directory.
Vue
From there you’ll want to install Vue into your project via the Vite Vuejs plugin:
npm install --save-dev @vitejs/plugin-vue
Next navigate to your vite.config.js
file and make sure you add the following code to setup your project to use Laravel and Vue together:
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'], // entrypoint for the app
refresh: true,
}),
vue()
],
});
Inertia
At first I got confused because I didn’t realize from Inertia’s website that I had to include it both on the client and the server side - I thought it was an either-or kind of thing! Thusly, stuff was broken for a long time, until I figured it out - and now you don’t have to! (you’re welcome).
Server Side
First we need to install Inertia using composer.
composer require inertiajs/inertia-laravel
Then in our app.blade.php
we’ll include @inertiaHead
beneath our @vite
directive, and @inertia
within the body
of our template, where our app will be rendered.
Note that in the root template that we need to only specify @inertia
inside of the <body>
tag, we do NOT need to include an id=”app”
(I wasted quite a bit of time on this mistake!)
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0" />
@vite(['resources/js/app.js'])
@inertiaHead
</head>
<body>
@inertia
</body>
</html>
By default the root template is named app.blade.php
- so I left it as it was.
Middleware
Next we’ll add our middleware. First we have to install it:
php artisan inertia:middleware
Then, within our bootstrap
directory, we’ll find our app.php
file and add the following to set up the Inertia middleware (don’t forget to import HandleInertiaRequests
with use
!):
use App\Http\Middleware\HandleInertiaRequests;
->withMiddleware(function (Middleware $middleware) {
$middleware->web(append: [
HandleInertiaRequests::class,
]);
})
Client Side
Finally we set up the client side of Inertia. We’ll install it using npm:
npm install @inertiajs/vue3
We’ll inititalize the Vue app within the app.js
file.
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 our vite.config.js
file we’ll add a resolve portion, which instructs Inertia where to find your Vue pages and what to do with them:
// Vite
resolve: name => {
const pages = import.meta.glob('./Pages/**/*.vue', { eager: true })
return pages[`./Pages/${name}.vue`]
},
Note that this means you’ll have to put your Vue pages inside your Pages
directory in order to have them be registered in Inertia. If you prefer a different directory, change the config.
How do we actually see one of our Vue pages rendered in the browser? Below, I have a random counter example (yeah I know! soooooo original…) that I’ve named Counter.vue
and placed in the Pages
directory.
<script setup>
import { ref } from 'vue'
const counter = ref(0)
</script>
<template>
<button
type="button"
@click="counter++"
>
Counter is: {{ counter }}
</button>
</template>
You’ll need to register your route in the web.php
file - to refer to your main page, use ‘/’
- then refer to your Vue component by its name - no need to append .vue
to the end of refer to the Pages
directory. Our Inertia config took care of those details.
Route::get('/', function () {
return inertia('Counter'); // or whatever name you choose! Don't need to specify that it is in the Pages directory
});
Navigate to wherever your server is running (default I believe is http://127.0.0.1:8000
) and bask in the glory of a Counter button that can increment, rendered by Vue, Inertia, and Laravel.
And that’s it! If you follow these steps you should have a working boilerplate.
I hope you enjoyed! Let me know in the comments what you’re building with Laravel and Vue!!
Resources
Inertia docs: https://inertiajs.com/
Nice step through of how to set up Laravel/Inertia/Vue that I drew from for my project: https://www.fadocodecamp.com/posts/setting-up-laravel-vue-and-inertia
Subscribe to my newsletter
Read articles from Madeline Caples directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by

Madeline Caples
Madeline Caples
I'm a frontend developer at Fuego Leads where I build cool stuff using Vue. I've worked there since April 2023. On Hashnode, I like to write about machine learning and other software engineering topics.