Up and running with the new Inertia.js Vue 3 adapter

Published on Oct 8, 2020

If you're like me and you're into the #goatStack, you might have heard that Inertia.js tagged the first release of their Vue 3 adapater. You can check out the Release notes here.

Now that it's out, you probably want to get in there and give it a try. This post will help you get up and running now, so let's get started.

note for the sake of this post, I will not be focusing on anything outside of getting Inertia JS running.

Getting started

Let's start by getting a brand new Laravel app created

1$ laravel new inertia-vue3

The first thing we're going to do is update the package.json file to include the latest version of Laravel Mix, which at the time of writing was 6.0.0-beta.7. If you check out the project on Github you will see a upgrade.md file on master branch. This file has a list of changes that have been introduced since V5.

Okay, so your package.json should look like this.

 1{
2 "private"true,
3 "scripts": {
4 "dev": "npx mix",
5 "development": "npx mix",
6 "watch": "npx mix watch",
7 "hot": "npx mix watch --hot",
8 "prod": "npx mix --production",
9 "production": "npx mix --production"
10 },
11 "devDependencies": {
12 "@inertiajs/inertia": "^0.4.0",
13 "@inertiajs/inertia-vue3": "^0.1.0",
14 "@vue/compiler-sfc": "^3.0.0",
15 "axios": "^0.20.0",
16 "laravel-mix": "^6.0.0-beta.7",
17 "postcss": "^8.1.1",
18 "vue": "^3.0.0",
19 "vue-loader": "^16.0.0-beta.8"
20 }
21}

so let's make some changes. Change your devDependencies

 1{
2 "private"true,
3 "scripts": {
4 "dev": "npx mix",
5 "development": "npx mix",
6 "watch": "npx mix watch",
7 "hot": "npx mix hot",
8 "prod": "npx mix --production",
9 "production": "npx mix --production"
10 },
11 "devDependencies": {
12 "@inertiajs/inertia": "^0.4.0",
13 "@inertiajs/inertia-vue3": "^0.1.0",
14 "axios": "^0.20.0",
15 "laravel-mix": "^6.0.0-beta.5",
16 "vue": "^3.0.0"
17 }
18}

You can see we changed the "scripts" object, that's because the new Mix uses npx commands. Next, let's install our dependencies.

1$ npm i // or yarn install

Next, let's jump into our webpack.mix.js file, by default in Laravel 8 it looks like this.

1const mix = require('laravel-mix');
 2 
 3/*
4 |--------------------------------------------------------------------------
5 | Mix Asset Management
6 |--------------------------------------------------------------------------
7 |
8 | Mix provides a clean, fluent API for defining some Webpack build steps
9 | for your Laravel applications. By default, we are compiling the CSS
10 | file for the application as well as bundling up all the JS files.
11 |
12 */
13 
14mix.js('resources/js/app.js', 'public/js')
15 .postCss('resources/css/app.css', 'public/css', [
16 //
17 ]);

Now, let's make some changes.

1const mix = require("laravel-mix");
2const path = require("path");
 3 
 4/*
5 |--------------------------------------------------------------------------
6 | Mix Asset Management
7 |--------------------------------------------------------------------------
8 |
9 | Mix provides a clean, fluent API for defining some Webpack build steps
10 | for your Laravel applications. By default, we are compiling the CSS
11 | file for the application as well as bundling up all the JS files.
12 |
13 */
14 
15mix.postCss("resources/css/app.css", "public/css", [
16 //
17])
18 .js("resources/js/app.js", "public/js")
19 .vue({ version: 3 });
20 
21// New Alias plugin
22mix.alias({
23 "@": path.resolve("resources/js"),
24});

Things to note. Mix now has the method .vue() for, you guessed it compiling vue. You can see we're also passing in an object telling it what version of vue we are working with which is Vue 3.

now if you run npm run dev you should see this happen.

1> npx mix
 2 
3 Additional dependencies must be installed. This will only take a moment.
 4 
5 Running: npm install @vue/compiler-sfc vue-loader@^16.0.0-beta.8 --save-dev --production=false
 6 
 7 
8 Okay, done. The following packages have been installed and saved to your package.json dependencies list:
 9 
10 - @vue/compiler-sfc
11 
12 - vue-loader@^16.0.0-beta.8
13 
14 Finished. Please run Mix again.

So let's run npm run dev again.

you should see this.

 1 
 2 
3 Laravel Mix v6
 4 
 5 
6 Compiled Successfully in 1140ms
 7┌───────────────────────────────────┬─────────┐
8 File Size
 9├───────────────────────────────────┼─────────┤
10 /js/app.js 594 KiB 
11├───────────────────────────────────┼─────────┤
12 /css/app.css 1 bytes 
13└───────────────────────────────────┴─────────┘

awesome, now let's configure our app.js to use the new Inertia.

1import { createApp, h } from "vue";
2import { app, plugin } from "@inertiajs/inertia-vue3";
 3 
4const el = document.getElementById("app");
 5 
 6createApp({
7 render: () =>
8 h(app, {
9 initialPage: JSON.parse(el.dataset.page),
10 resolveComponent: (name) =>
11 import(`@/Pages/${name}`).then((module) => module.default),
12 }),
13})
14 .use(plugin)
15 .mount(el);

Inertia expects there to be a resources/js/Pages folder where all your Inertia views will be, so let's create that folder, and add a couple of pages to test it out.

Make 3 pages in resources/js/Pages. Create a Home.vue, Blog.vue and Contact.vue file.

In Home.vue add the following.

 1//Home.vue
 2<template>
3 <h1>Hello from Inertia Vue 3</h1>
4 <inertia-link href="/contact">Contact</inertia-link>
5 <inertia-link href="/blog">Blog</inertia-link>
 6</template>
 7 
 8<script>
9export default {};
10</script>

In Blog.vue add the following.

 1//Blog.vue
 2<template>
3 <h1>Hello from Inertia Vue 3</h1>
4 <inertia-link href="/">Home</inertia-link>
5 <inertia-link href="/contact">Contact</inertia-link>
 6</template>
 7 
 8<script>
9export default {};
10</script>

In Home.vue add the following.

 1//Contact.vue
 2<template>
3 <h1>Hello from Inertia Vue 3</h1>
4 <inertia-link href="/">Home</inertia-link>
5 <inertia-link href="/blog">Blog</inertia-link>
 6</template>
 7 
 8<script>
9export default {};
10</script>

Once you've done run npm run dev one more time. If all goes well you should have this output.

 1 
2 Laravel Mix v6
 3 
 4 
5 Compiled Successfully in 1203ms
 6┌───────────────────────────────────┬──────────┐
7 File Size
 8├───────────────────────────────────┼──────────┤
9 /js/app.js 1.13 MiB 
10├───────────────────────────────────┼──────────┤
11 js/resources_js_Pages_Contact_vu… 9.7 KiB
12├───────────────────────────────────┼──────────┤
13 js/resources_js_Pages_Blog_vue.j… 9.58 KiB 
14├───────────────────────────────────┼──────────┤
15 js/resources_js_Pages_Home_vue.j… 9.57 KiB 
16├───────────────────────────────────┼──────────┤
17 /css/app.css 1 bytes
18└───────────────────────────────────┴──────────┘

Okay now we have the frontend set up, let's take care of getting the server requirements for Inertia set up. Run the following.

1$ composer require inertiajs/inertia-laravel

Next create three controllers.

1$ php artisan make:controller HomeController
2$ php artisan make:controller BlogController
3$ php artisan make:controller ContactController

Now in our routes/web.php add this

 1<?php
 2 
 3 
4use App\Http\Controllers\BlogController;
5use App\Http\Controllers\ContactController;
6use App\Http\Controllers\HomeController;
7use Illuminate\Support\Facades\Route;
 8 
9Route::get('/', [HomeController::class, 'index']);
10Route::get('/blog', [BlogController::class, 'index']);
11Route::get('/contact', [ContactController::class, 'index']);

In each controller, we're going to have the exact same index function return an Inertia rendered view.

 1<?php
 2 
3namespace App\Http\Controllers;
 4 
5use Illuminate\Http\Request;
6use Inertia\Inertia;
 7 
8class HomeController extends Controller
 9{
10 public function index()
11 {
12 return Inertia::render('Home');
13 }
14}
 1<?php
 2 
3namespace App\Http\Controllers;
 4 
5use Illuminate\Http\Request;
6use Inertia\Inertia;
 7 
8class BlogController extends Controller
 9{
10 public function index()
11 {
12 return Inertia::render('Blog');
13 }
14}
 1<?php
 2 
3namespace App\Http\Controllers;
 4 
5use Illuminate\Http\Request;
6use Inertia\Inertia;
 7 
8class ContactController extends Controller
 9{
10 public function index()
11 {
12 return Inertia::render('Contact');
13 }
14}

Finally, let's make an app.blade.php in the root of resources/views. This is what Inertia expects by default.

1<!DOCTYPE html>
2<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
 3 
 4<head>
5 <meta charset="utf-8">
6 <meta name="viewport" content="width=device-width, initial-scale=1">
 7 
8 <title>Laravel</title>
9 <link rel="stylesheet" href="{{ mix('css/app.css') }}">
10</head>
11 
12<body>
13 @inertia
14 <script src="{{ mix('js/app.js') }}"></script>
15</body>
16 
17</html>

We are simply including our css, js and the @inerta directive. Once you've done this you should be able to visit your app and see a page like this.

image

Now you can click around from your home page, to your blog page and contact page.

If you'd like the source code for the project above, you can find it here.

Happy coding!