
Project Log: building a quiz app in Laravel + Vue + Inertia
Introduction
Laravel and Vue are objectively cool together (literally theyre 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. Dont take this as the official way to do anything. If it is its only by accident.
Whats 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 were going to create a new Laravel project from the command line using composer.
In your terminal, navigate to the directory where youd 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 youll 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 didnt realize from Inertias 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 dont have to! (youre welcome).
Server Side
First we need to install Inertia using composer.
composer require inertiajs/inertia-laravel
Then in our app.blade.php
well 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 well add our middleware. First we have to install it:
php artisan inertia:middleware
Then, within our bootstrap
directory, well find our app.php
file and add the following to set up the Inertia middleware (dont 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. Well install it using npm:
npm install @inertiajs/vue3
Well 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 well add a resolve portion, which instructs Inertia where to find your Vue pages and what to do with them:
// Viteresolve: name => { const pages = import.meta.glob('./Pages/**/*.vue', { eager: true }) return pages[`./Pages/${name}.vue`]},
Note that this means youll 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 Ive 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>
Youll 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 thats it! If you follow these steps you should have a working boilerplate.
I hope you enjoyed! Let me know in the comments what youre building with Laravel and Vue!!
Resources
Inertia docs: https://inertiajs.com/">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">https://www.fadocodecamp.com/posts/setting-up-laravel-vue-and-inertia