Search code examples
layoutlaravel-8inertiajslaravel-jetstream

Laravel jetstream inertia persistent layout


In a fresh laravel installation i'm trying to make layout persistent following the inertia doc https://inertiajs.com/pages

app.js

require('./bootstrap');

// Import modules...
import { createApp, h } from 'vue';
import { App as InertiaApp, plugin as InertiaPlugin } from '@inertiajs/inertia-vue3';
import { InertiaProgress } from '@inertiajs/progress';
import AppLayout from '@/Layouts/AppLayout';

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

createApp({
    render: () =>
        h(InertiaApp, {
            initialPage: JSON.parse(el.dataset.page),
            resolveComponent: name => import(`./Pages/${name}`)
              .then(({ default: page }) => {
                if (page.layout === undefined) {
                  page.layout = AppLayout
                }
                return page
              }),
        }),
})
    .mixin({ methods: { route } })
    .use(InertiaPlugin)
    .mount(el);

InertiaProgress.init({ color: '#4B5563' });

Dashboard.vue (here i replace the default app-layout wrapper by div)

<template>
    <div>
        <template #header>
            <h2 class="font-semibold text-xl text-gray-800 leading-tight">
                Dashboard
            </h2>
        </template>

        <div class="py-12">
            <div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
                <div class="bg-white overflow-hidden shadow-xl sm:rounded-lg">
                    <welcome />
                </div>
            </div>
        </div>
    </div>
</template>

<script>
    import Welcome from '@/Jetstream/Welcome'

    export default {
        components: {
            Welcome,
        },
    }
</script>

While compiling i get this error :

Error: Codegen node is missing for element/if/for node. Apply appropriate transforms first.

I can't figure out what that means. Is there a reason why the default laravel app with jetstream and inertia doesn't use persistent layout?


Solution

  • If the header slot is in AppLayout aka the persistent one, you cannot use this way (because there is no slot yet? I don't know but I know persistent layouts do mount after child components, this can be the culprit). As a solution, create another layout, ie PageLayout, with named slots and use that layout to build your dashboard and other pages:

    AppLayout.vue

    <template>
        <div>Persistent stuff...</div>
        <slot />
        <div>Persistent stuff...</div>
    </template>
    

    PageLayout.vue

    <template>
        <slot name="header" />
        <slot name="content" />
        <div>PageLayout stuff...</div>
    </template>
    

    Dashboard.vue

    <template>
        <PageLayout>
            <template #header>
                <h1>Dashboard</h1>
            </template>
            <template #content>
                <p>Welcome user!</p>
            </template>
        </PageLayout>
    </template>
    
    <script>
    import AppLayout from 'AppLayout'
    import PageLayout from 'PageLayout'
    
    export default {
        layout: AppLayout, // Persistent layout
        components: {
            PageLayout // Regular layout
        }
    </script>
    

    There is an ongoing discussion here: https://github.com/inertiajs/inertia/issues/171