Using Inertia route globally with SSR

I'm practicing Inertia and Vue and I'm using Laravel Breeze scaffolding with SSR.

I have a Navigation.vue which contains the menu and their route.

Navigation.vue

<script setup>
import NavLink from "@/Components/NavLink.vue"
import { usePage } from "@inertiajs/vue3"

const user = usePage().props.auth.user

const items = [
  {
    label: "Browse",
    url: route("home"),
    active: route().current("home"),
    show: true,
  },
  {
    label: "Recipe of the Day",
    url: route("home"),
    active: route().current("home"),
    show: true,
  },
  {
    label: "Popular Recipes",
    url: route("home"),
    active: route().current("home"),
    show: true,
  },
  {
    label: "Courses",
    url: 'route("home")',
    active: route().current("home"),
    show: true,
  },
  {
    label: "Your recipes",
    url: route("dashboard"),
    active: route().current("dashboard"),
    show: !!user,
  },
  {
    label: "Post a recipe",
    url: route("dashboard"),
    active: false,
    show: true,
  },
]
</script>

<template>
  <template v-for="item in items" :key="item.url">
    <NavLink v-if="item.show" :href="item.url" :active="item.active">{{ item.label }}</NavLink>
  </template>
</template>

After running php artisan inertia:start-ssr, and visit the home page. I got this error.

Unhandled error during execution of setup function at
ReferenceError: route is not defined
at setup (file:///path/to/project-name/bootstrap/ssr/assets/MainLayout-ba921e9b.js:163:14)

I checked the documentation and saw that we can use the route globally but I'm not sure how to add this to my app.js and ssr.js

app.config.globalProperties.$route = route

<Link :href="$route('users.create')">Create User</Link>

My app.js

import "./bootstrap"
import "../css/app.css"

import { createApp, h } from "vue"
import { createInertiaApp } from "@inertiajs/vue3"
import { resolvePageComponent } from "laravel-vite-plugin/inertia-helpers"
import { ZiggyVue } from "../../vendor/tightenco/ziggy/dist/vue.m"

const appName = window.document.getElementsByTagName("title")[0]?.innerText || "Laravel"

createInertiaApp({
  title: (title) => `${title} - ${appName}`,
  resolve: (name) => resolvePageComponent(`./Pages/${name}.vue`, import.meta.glob("./Pages/**/*.vue")),
  setup({ el, App, props, plugin }) {
    // eslint-disable-next-line vue/component-api-style
    return createApp({ render: () => h(App, props) })
      .use(plugin)
      .use(ZiggyVue, Ziggy)
      .mount(el)
  },
  progress: {
    color: "#4B5563",
  },
})

Found this discussion but it's a little different from my app.js

Tried to update my app.js to use the app.config.globalProperties.$route = route but I still got the error.

import "./bootstrap"
import "../css/app.css"

import { createApp, h } from "vue"
import { createInertiaApp } from "@inertiajs/vue3"
import { resolvePageComponent } from "laravel-vite-plugin/inertia-helpers"
import { ZiggyVue } from "../../vendor/tightenco/ziggy/dist/vue.m"

const appName = window.document.getElementsByTagName("title")[0]?.innerText || "Laravel"

createInertiaApp({
  title: (title) => `${title} - ${appName}`,
  resolve: (name) => resolvePageComponent(`./Pages/${name}.vue`, import.meta.glob("./Pages/**/*.vue")),
  setup({ el, App, props, plugin }) {
    // eslint-disable-next-line vue/component-api-style
    return createApp({ render: () => h(App, props) })
      .config.globalProperties.$route = route // added this line
      .use(plugin)
      .use(ZiggyVue, Ziggy)
      .mount(el)
  },
  progress: {
    color: "#4B5563",
  },
})

The error after running php artisan inertia:start-ssr:

Unhandled error during execution of setup function 
  at <Navigation>                                                                      
ReferenceError: $route is not defined                                                  
    at setup (file:///C:/path/to/project-name/bootstrap/ssr/assets/MainLayout-1b40f506.js:163:14)  

Is this something to do with the route() or do I have a wrong implementation of the items in my Navigation.vue?

whoami (Daryl)
whoami (Daryl)
0
6
1032
Haz
Haz
Moderator

Hey,

Your app.js looks fine. Can you share your ssr.js and HandleInertiaRequests.php please? For reference, here are mine:

import { createSSRApp, h } from "vue";
import createServer from "@inertiajs/vue3/server";
import { renderToString } from "@vue/server-renderer";
import { createInertiaApp } from "@inertiajs/vue3";
import { resolvePageComponent } from "laravel-vite-plugin/inertia-helpers";
import { ZiggyVue } from "../../vendor/tightenco/ziggy/dist/vue.m";

createServer((page) =>
    createInertiaApp({
        page,
        render: renderToString,
        title: (title) => "Laravel",
        resolve: (name) => resolvePageComponent(`./Pages/${name}.vue`, import.meta.glob("./Pages/**/*.vue")),
        setup({ App, props, plugin }) {
            return createSSRApp({ render: () => h(App, props) })
                .use(plugin)
                .use(ZiggyVue, {
                    ...page.props.ziggy,
                    location: new URL(page.props.ziggy.location),
                });
        },
    })
);
    /**
     * Defines the props that are shared by default.
     *
     * @see https://inertiajs.com/shared-data
     */
    public function share(Request $request): array
    {
        return array_merge(parent::share($request), [
            // ...
            
            'ziggy' => function () use ($request) {
                return array_merge((new Ziggy)->toArray(), [
                    'location' => $request->url(),
                ]);
            },
        ]);
    }
whoami (Daryl)
whoami (Daryl)

Hey, sure.

My ssr.js:

import { createSSRApp, h } from "vue"
import { renderToString } from "@vue/server-renderer"
import { createInertiaApp } from "@inertiajs/vue3"
import createServer from "@inertiajs/vue3/server"
import { resolvePageComponent } from "laravel-vite-plugin/inertia-helpers"
import { ZiggyVue } from "../../vendor/tightenco/ziggy/dist/vue.m"

const appName = "Laravel"

createServer((page) =>
  createInertiaApp({
    page,
    render: renderToString,
    title: (title) => `${title} - ${appName}`,
    resolve: (name) => resolvePageComponent(`./Pages/${name}.vue`, import.meta.glob("./Pages/**/*.vue")),
    setup({ App, props, plugin }) {
      return createSSRApp({ render: () => h(App, props) })
        .use(plugin)
        .use(ZiggyVue, {
          ...page.props.ziggy,
          location: new URL(page.props.ziggy.location),
        })
    },
  })
)

My HandleInertiaRequests.php (slightly modified)

/**
 * Define the props that are shared by default.
 *
 * @return array<string, mixed>
 */
public function share(Request $request): array
{
    return array_merge(parent::share($request), [
        'auth' => [
            'user' => fn () => $request->user()
            ? $request->user()
            : null,
        ],
        'ziggy' => function () use ($request) {
            return array_merge((new Ziggy)->toArray(), [
                'location' => $request->url(),
            ]);
        },
    ]);
}
Haz
Haz
Moderator

Hey,

You mentioned you slightly modified something. Did you run npm build again?

    "scripts": {
        "dev": "vite",
        "build": "vite build && vite build --ssr"
    },

I would also remove this line:

app.config.globalProperties.$route = route

You shouldn't need to do that for it to work. Let's keep it simple so we can get it working. I'm not seeing anything else that jumps out at me.

I'm practicing Inertia and Vue and I'm using Laravel Breeze scaffolding with SSR.

Are you able to share the repository so I can take a closer look?

whoami (Daryl)
whoami (Daryl)

Yes, actually it's public. Here's the repository

Haz
Haz
Moderator
Solution

Hey,

Thanks! I found the issue. You need to install Ziggy on the client side and generate the routes.

  1. npm i ziggy-js

  2. php artisan ziggy:generate

  3. npm run build

  4. php artisan inertia:start-ssr

Hope this helps.

whoami (Daryl)
whoami (Daryl)

Hey,

It worked! thank you very much! I thought ziggy-js is not needed because the routes are exposed already.