Before we get started building our application we need to setup our development environment. At the time of this writing we’ll be installing laravel 9, Vue 3 and Inertia JS. Assuming you have composer and node js already installed on your system, you may proceed with these steps.
Create Laravel Project
To create a fresh new laravel project, open up your terminal window and type in the following:
composer create-project --prefer-dist laravel/laravel budget-app
Install Dependencies
Once that is done, we have to install the dependencies that we need inorder to run inertiajs
composer require inertiajs/inertia-laravel
Creating the Inertia middleware is the next step. This handles the requests and also helps us to share data with all our Vue views, similar to View::share()
.
php artisan inertia:middleware
The following file HandleInertiaRequests.php
is created inside app/Http/Middleware
folder. The followig middleware will need to be added to the web
middleware group inside app/Http/Kernel.php
:
'web' => [
// ...
\App\Http\Middleware\HandleInertiaRequests::class,
],
Now the Inertia JS on the client side needs to be setup. We’re using Vue 3, so we’ll install Inertia alongside with the Vue 3 adapter:
npm install @inertiajs/inertia @inertiajs/inertia-vue3
Let’s now install the inertia progress bar which gives us a visual on the loading of a page.
npm install @inertiajs/progress
Inertia uses Laravel’s routes, so we won’t need to use a client side router, but to make use of Laravel’s web.php
routes, we have to pass them to the DOM somehow. The easiest way to do it to use Ziggy.
composer require tightenco/ziggy
Now we can use the @routes
blade directive inside our blade template to expose the web.php
routes to the client side.
Install Tailwind CSS
We’ll be using Tailwind CSS for styling our web application and thi sis the easiest to setup.
npm install -D tailwindcss postcss autoprefixer
Create tailwind config file:
npx tailwindcss init
Open up tailwind.config.js and enter the following code:
module.exports = {
content: [
'./resources/**/*.blade.php',
'./resources/**/*.js',
'./resources/**/*.vue',
],
theme: {
extend: {},
},
plugins: [],
}
The code is to tell tailwind JIT what clases that we’ll use in our templates and generate them.
We also have to add the Tailwind’s directives to resources/css/app.css
:
@tailwind base;
@tailwind components;
@tailwind utilities;
Lastly we require Tailwind into webpack.mix.js
which uses Laravel Mix to build our assets.
mix.js('resources/js/app.js', 'public/js')
.extract()
.vue()
.postCss('resources/css/app.css', 'public/css', [
require("tailwindcss"),
])
.version();
Install Vue JS 3
We will be using Vue JS 3 so to install it run the following command:
npm install vue@next
With Vue 3 it has 2 different API styles, Composite API and Options API. What are the differences between these two styles? With Composition API, we define a component’s logic using imported API functions. In SFCs, Composition API is typically used with <script setup>
. With Options API, we define a component’s logic using an object of options such as data
, methods
, and mounted
. Properties defined by options are exposed on this
inside functions, which points to the component instance. You can find out more here with examples.
Setup the Root Blade Template
Now we have to setup our blade template app.blade.php to allow inertiajs to be executed. You may need to rename the blade template from welcome.blade.php to app.blade.php. This file is located in the resources/views folder
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
@routes
<link href="{{ mix('/css/app.css') }}" rel="stylesheet" />
<script src="{{ mix('/js/manifest.js') }}" defer></script>
<script src="{{ mix('/js/vendor.js') }}" defer></script>
<script src="{{ mix('/js/app.js') }}" defer></script>
@inertiaHead
</head>
<body>
@inertia
</body>
</html>
From the code above you’ll see that there is no title tag, as the title tag needs to be dynamic so we add the @inertiaHead directive.
We have added the @routes
directive to pass the Laravel’s routes in the document’s <head>
.
In the <body> we only use the @inertia directive. This directive is used to pass the data-page attribute to the div element that is rendered.
Setup app.js
import { createApp, h } from 'vue'
import { createInertiaApp, Link, Head } from '@inertiajs/inertia-vue3'
import Layout from "./Shared/Layout"
import route from "ziggy-js";
import { InertiaProgress } from '@inertiajs/progress'
const app = createInertiaApp({
resolve: async name => {
let page = (await import(`./Pages/${name}`)).default;
if (page.layout === undefined) {
page.layout = Layout;
}
return page;
},
setup({ el, App, props, plugin }) {
const VueApp = createApp({ render: () => h(App, props) })
.use(plugin)
.mixin({ methods: { route } })
.component("Link", Link)
.component("Head", Head)
.mount(el)
},
})
InertiaProgress.init({
color: 'red',
showSpinner: true,
})
What does this is to import Vue, Inertia, Inertia Progress and Ziggy and then create the Inertia App. We’re also passing the Link
and Head
components as globals because we’re going to use them a lot. Inertia will load our pages from the Pages
.