Published on

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

Author
  • Name
    Yaz Jallad
    Author bio

    Full stack developer with a passion for everything Laravel. Currently building ContestKit, and GotLead.

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

$ 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.

{
    "private": true,
    "scripts": {
        "dev": "npx mix",
        "development": "npx mix",
        "watch": "npx mix watch",
        "hot": "npx mix watch --hot",
        "prod": "npx mix --production",
        "production": "npx mix --production"
    },
    "devDependencies": {
        "@inertiajs/inertia": "^0.4.0",
        "@inertiajs/inertia-vue3": "^0.1.0",
        "@vue/compiler-sfc": "^3.0.0",
        "axios": "^0.20.0",
        "laravel-mix": "^6.0.0-beta.7",
        "postcss": "^8.1.1",
        "vue": "^3.0.0",
        "vue-loader": "^16.0.0-beta.8"
    }
}

so let's make some changes. Change your devDependencies

{
    "private": true,
    "scripts": {
        "dev": "npx mix",
        "development": "npx mix",
        "watch": "npx mix watch",
        "hot": "npx mix hot",
        "prod": "npx mix --production",
        "production": "npx mix --production"
    },
    "devDependencies": {
        "@inertiajs/inertia": "^0.4.0",
        "@inertiajs/inertia-vue3": "^0.1.0",
        "axios": "^0.20.0",
        "laravel-mix": "^6.0.0-beta.5",
        "vue": "^3.0.0"
    }
}

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

$ npm i // or yarn install

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

const mix = require('laravel-mix');

/*
 |--------------------------------------------------------------------------
 | Mix Asset Management
 |--------------------------------------------------------------------------
 |
 | Mix provides a clean, fluent API for defining some Webpack build steps
 | for your Laravel applications. By default, we are compiling the CSS
 | file for the application as well as bundling up all the JS files.
 |
 */

mix.js('resources/js/app.js', 'public/js')
    .postCss('resources/css/app.css', 'public/css', [
        //
    ]);

Now, let's make some changes.

const mix = require("laravel-mix");
const path = require("path");

/*
 |--------------------------------------------------------------------------
 | Mix Asset Management
 |--------------------------------------------------------------------------
 |
 | Mix provides a clean, fluent API for defining some Webpack build steps
 | for your Laravel applications. By default, we are compiling the CSS
 | file for the application as well as bundling up all the JS files.
 |
 */

mix.postCss("resources/css/app.css", "public/css", [
    //
])
    .js("resources/js/app.js", "public/js")
    .vue({ version: 3 });

// New Alias plugin
mix.alias({
    "@": path.resolve("resources/js"),
});

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.

> npx mix

        Additional dependencies must be installed. This will only take a moment.
 
        Running: npm install @vue/compiler-sfc [email protected]^16.0.0-beta.8 --save-dev --production=false


        Okay, done. The following packages have been installed and saved to your package.json dependencies list:
 
        - @vue/compiler-sfc
 
        - [email protected]^16.0.0-beta.8
 
        Finished. Please run Mix again.

So let's run npm run dev again.

you should see this.


                    
   Laravel Mix v6   
                    

✔ Compiled Successfully in 1140ms
┌───────────────────────────────────┬─────────┐
│ File                              │ Size    │
├───────────────────────────────────┼─────────┤
│ /js/app.js                        │ 594 KiB │
├───────────────────────────────────┼─────────┤
│ /css/app.css                      │ 1 bytes │
└───────────────────────────────────┴─────────┘

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

import { createApp, h } from "vue";
import { app, plugin } from "@inertiajs/inertia-vue3";

const el = document.getElementById("app");

createApp({
    render: () =>
        h(app, {
            initialPage: JSON.parse(el.dataset.page),
            resolveComponent: (name) =>
                import(`@/Pages/${name}`).then((module) => module.default),
        }),
})
    .use(plugin)
    .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.

//Home.vue
<template>
    <h1>Hello from Inertia Vue 3</h1>
    <inertia-link href="/contact">Contact</inertia-link>
    <inertia-link href="/blog">Blog</inertia-link>
</template>

<script>
export default {};
</script>

In Blog.vue add the following.

//Blog.vue
<template>
    <h1>Hello from Inertia Vue 3</h1>
    <inertia-link href="/">Home</inertia-link>
    <inertia-link href="/contact">Contact</inertia-link>
</template>

<script>
export default {};
</script>

In Home.vue add the following.

//Contact.vue
<template>
    <h1>Hello from Inertia Vue 3</h1>
    <inertia-link href="/">Home</inertia-link>
    <inertia-link href="/blog">Blog</inertia-link>
</template>

<script>
export default {};
</script>

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

                    
   Laravel Mix v6   
                    

✔ Compiled Successfully in 1203ms
┌───────────────────────────────────┬──────────┐
│ File                              │ Size     │
├───────────────────────────────────┼──────────┤
│ /js/app.js                        │ 1.13 MiB │
├───────────────────────────────────┼──────────┤
│ js/resources_js_Pages_Contact_vu… │ 9.7 KiB  │
├───────────────────────────────────┼──────────┤
│ js/resources_js_Pages_Blog_vue.j… │ 9.58 KiB │
├───────────────────────────────────┼──────────┤
│ js/resources_js_Pages_Home_vue.j… │ 9.57 KiB │
├───────────────────────────────────┼──────────┤
│ /css/app.css                      │ 1 bytes  │
└───────────────────────────────────┴──────────┘

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

$ composer require inertiajs/inertia-laravel

Next create three controllers.

$ php artisan make:controller HomeController
$ php artisan make:controller BlogController
$ php artisan make:controller ContactController

Now in our routes/web.php add this

<?php


use App\Http\Controllers\BlogController;
use App\Http\Controllers\ContactController;
use App\Http\Controllers\HomeController;
use Illuminate\Support\Facades\Route;

Route::get('/', [HomeController::class, 'index']);
Route::get('/blog', [BlogController::class, 'index']);
Route::get('/contact', [ContactController::class, 'index']);

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

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Inertia\Inertia;

class HomeController extends Controller
{
    public function index()
    {
        return Inertia::render('Home');
    }
}

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Inertia\Inertia;

class BlogController extends Controller
{
    public function index()
    {
        return Inertia::render('Blog');
    }
}
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Inertia\Inertia;

class ContactController extends Controller
{
    public function index()
    {
        return Inertia::render('Contact');
    }
}

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

<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">

<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">

    <title>Laravel</title>
    <link rel="stylesheet" href="{{ mix('css/app.css') }}">
</head>

<body>
    @inertia
    <script src="{{ mix('js/app.js') }}"></script>
</body>

</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!