Understanding The Flow Between Adonis, Inertia, and Vue 3

In this lesson, we'll be inspecting the request flow from Adonis through Inertia and to Vue for both initial and subsequent requests.

Published
Jul 02, 22
Duration
6m 59s

Developer, dog lover, and burrito eater. Currently teaching AdonisJS, a fully featured NodeJS framework, and running Adocasts where I post new lessons weekly. Professionally, I work with JavaScript, .Net C#, and SQL Server.

Adocasts

Burlington, KY

Before we delve too deeply into using InertiaJS it’s important to understand the flow that’s happening when a request is made. So, let’s take a moment to understand where AdonisJS ends, where InertiaJS takes over, and what’s passed along to VueJS.

Remember our Vue application is a single-page application (SPA).

The Inertia Render

First let’s tackle the question, “what is inertia.render doing?” The answer to this question is two-fold depending on whether it’s handling an initial request or subsequent page requests.

The Initial Request

When we make our first page request into our Vue SPA, the inertia.render call will include our application’s Edge file, which looks like the below.

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <link rel="icon" type="image/png" href="/favicon.ico">

  @entryPointStyles('app')
  @entryPointScripts('app')

  <title>adonis-inertia-example</title>
</head>
<body>
  @inertia()
</body>
</html>
Copied!
  • resources
  • views
  • app.edge

If you’re familiar with Edge, the only thing unfamiliar with the above should be @inertia(). In essence, this Edge component is dropping the markup for our Vue application on the page. It doesn’t initialize anything with Vue, it merely drops the div element that will house our Vue app.

<div id="app" data-page="{ "component": "Home", props: { "testing": "This is a test" }, ... }"></div>
Copied!

The data-page attribute contains information for the initial state of our Vue app.

  • Component: The initial page component to display

  • Props: Data provided to inertia.render which will be passed to our page component as props.

  • Url: The current route’s url

  • Version: The current version for our application, this comes from our manifest file.

So, in essence, for initial requests, inertia.render will return back the following HTML as it’s response:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <link rel="icon" type="image/png" href="/favicon.ico">

  <link rel="stylesheet" href="<http://localhost:8080/assets/app.css>">
  <script src="<http://localhost:8080/assets/app.js>" defer=""></script>

  <title>adonis-inertia-example</title>
</head>
<body>
  <div id="app" data-page="{ "component": "Home", props: { "testing": "This is a test" }, ... }"></div>
</body>
</html>
Copied!

In terms of rendering, this is all that’s done on the server-side. Our Vue application isn’t actually instantiated until our app.js script is loaded in and our createApp is called.

import '../css/app.css'
import { createApp, h } from 'vue'
import { createInertiaApp } from '@inertiajs/inertia-vue3'

createInertiaApp({
  resolve: name => require(`./Pages/${name}`),
  setup({ el, App, props, plugin }) {
    createApp({ render: () => h(App, props) })
      .use(plugin)
      .mount(el)
  },
})
Copied!
  • resources
  • js
  • app.js

After our Vue application is instantiated everything else, including traveling to other pages is all done on the client-side; apart from grabbing information from Adonis for our routes.

Client-Side Routing

Inertia serves as our client-side router. Similar to Vue Router, Inertia will wrap our application with an inertia component. This component allows us to easily change pages within our Vue app without needing to re-instantiate our Vue app.

It works in tandem with a special Link component. In order to traverse from one page to another, we must use this Link component. Otherwise, the page change will be treated as an initial request and our Vue app will need to be re-instantiated, wasting time and resources for our users.

When we visit another page using this Link component, the component will kick off a GET request to Adonis for the desired route. This is where we meet inertia.render once more, this time for a subsequent request. It’ll pick up on this using content negotiation and instead of returning back HTML markup will return back a JSON response containing the same information provided within the data-page attribute on our initial request.

{
  "component":"Home",
  "version":"e77ee25438e9f73dc55c00b5e3ee4e15",
  "props": { "testing": "This is a test" },
  "url":"/1/dashboard"
}
Copied!

Inertia’s Link component is rather powerful. In this lesson, we’re merely going to take a look at how to use it to get from one page to another. In this section, we’ll be making a login page to serve as our second page.

First, though, let’s learn how to use the Link component on our home page.

<template>
  <div>
    <Link href="/login">Login</Link> <!-- 👈 use it -->
    <h1>Testing, {{ testing }}</h1>
  </div>
</template>

<script>
  import { Link } from '@inertiajs/inertia-vue3'. // 👈 import it

  export default {
    props: {
      testing: String
    },

    components: {
      Link // 👈 define it
    }
  }
</script>
Copied!
  1. First, import it from @inertiajs/inertia-vue3.

  2. Next, define it as a component, when necessary.

  3. Lastly, use it! Note that href is used to specify the path to go to.

Login Page

Next, let’s add our login page so we have an actual page to link to. First, let’s define the route in Adonis.

Route.get('/login', async ({ inertia }) => {
  return inertia.render('Auth/Login')
})
Copied!
  • start
  • routes.ts

We’ll be putting our authentication-specific pages inside an Auth folder. So, let’s create our page component at resources/js/Pages/Auth/Login.vue.

<template>
  <div>
    <Link href="/home">Go Home</Link>
    <h1>Login</h1>
  </div>
</template>

<script setup>
  import { Link } from '@inertiajs/inertia-vue3'
</script>
Copied!

Note that since we’re using a setup script here, we don’t need to define the component as we did on our home page.

Testing It Out

With that in place, you should be good to go ahead and test it out! Boot up your server with npm run dev and click between the home and login pages. You should notice within your developer tool’s inspector that after the initial request, the HTML structure remains the same and only the application’s contents are swapped out.

Additionally, if you inspect the Network tab, you should see a GET request go off every time you swap between pages to capture information for that specific page.

Join The Discussion! (4 Comments)

Please sign in or sign up for free to join in on the dicussion.

  1. Anonymous (EmuSarena790)
    Commented 1 year ago

    Unfortunately I get the following error the moment I introduce the Link component:

    VueCompilerError: Invalid end tag.

    0

    Please sign in or sign up for free to reply

    1. Commented 1 year ago

      Sounds like you might have a missing or misspelled end tag, either for the link component or some other element on your page. I'd try double-checking your end tags to ensure one isn't missing or misspelled.

      Even if it only happens when you introduce the link component, it could be a missing end tag for an immediate parent or sibling element.

      0

      Please sign in or sign up for free to reply

      1. Commented 4 months ago

        I had the same issue but managed to work it out by cross referencing the docs. Link is capitalised in the import but not in the template. Make sure you're using <Link> and not <link>. The code snippet should read

        <Link href="/home">Go Home</Link>

        (I realise this a year old, but just in case anyone else runs into the same issue!)

        2

        Please sign in or sign up for free to reply

        1. Commented 4 months ago

          Thank you for the heads-up, I really appreciate it!

          I've got the code blocks above updated to use <Link> instead of <link>.

          0

          Please sign in or sign up for free to reply