Define global component in InertiaJS with Vue 3
Asked Answered
Q

3

7

I'm trying to build an application on Laravel 8.38 - InertiaJS 0.8.4 I'm using Vue 3 as my frontend stack.

I've multiple layouts which I need to register globally as Vue Component, so that I can use it in my application anywhere. I'm unable to do so, my code:

import { createApp, h } from 'vue';
import { App as InertiaApp, plugin as InertiaPlugin } from '@inertiajs/inertia-vue3';

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

const app = createApp({
    render: () =>
        h(InertiaApp, {
            initialPage: JSON.parse(el.dataset.page),
            resolveComponent: (name) => require(`./../Pages/${name}`).default,
        }),
})
    .mixin({ methods: { route } })
    .use(InertiaPlugin);

app.component('app-market', () => import('./../layouts/AppMarketLayout')); //trying to import layout

app.mount(el);

And inside the page I'm trying to call this layout component:

<template>
    <div>
        <app-market-layout></app-market-layout>
    </div>
</template>

Unable to fetch, no errors in console.

Quadrangular answered 15/5, 2021 at 7:13 Comment(1)
You've registered an app-market component, but your markup uses app-market-layout.Shandashandee
C
2

In Inertia JS, importing components globally is the same as using a normal Vue configuration.

In your app.js file, you need to import the component(either inline or at the top of the file), then add the component before mounting the vue instance. You can either do this as a mixin, or as a component.

So, in your case, the configuration should look like the below:

import { createApp, h } from 'vue';
import { App as InertiaApp, plugin as InertiaPlugin } from '@inertiajs/inertia-vue3';

//Import the component:
import AppMarket from "./../layouts/AppMarketLayout"; 

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

const app = createApp({
    render: () =>
        h(InertiaApp, {
            initialPage: JSON.parse(el.dataset.page),
            resolveComponent: (name) => require(`./../Pages/${name}`).default,
        }),
})
    .mixin({ methods: { route } })
    .mixin({ components: { AppMarket } }) // << Then tell the inertia 
             // instance to use the component. 
             // You can also add this to the other mixin declaration
    .use(InertiaPlugin)
    .mount(el);

Then, in your template, you can use the component like this:

<template>
    <app-market>
    </app-market>
</template>

I noticed in your original post you are trying to use the component as app-market-layout. You must import the component with that name if you plan to do that.

The configuration would look like this in app.js:

import { createApp, h } from 'vue';
import { App as InertiaApp, plugin as InertiaPlugin } from '@inertiajs/inertia-vue3';

//Import the component: Notice the component name change.
import AppMarketLayout from "./../layouts/AppMarketLayout"; 

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

const app = createApp({
    render: () =>
        h(InertiaApp, {
            initialPage: JSON.parse(el.dataset.page),
            resolveComponent: (name) => require(`./../Pages/${name}`).default,
        }),
})
    .mixin({ methods: { route } })
    .mixin({ components: { AppMarketLayout } }) // << Here the component name has Layout
    .use(InertiaPlugin)
   
    .mount(el);

Then in your template:

<template>
    <app-market-layout>
    </app-market-layout>
</template>
Cowgirl answered 7/12, 2021 at 19:38 Comment(0)
P
1

I was having 2 layouts for backend(admin-panel) and frontend(website), achieved as follows. Using inertia default middleware file.

project/app/Http/Middleware/HandleInertiaRequests.php

class HandleInertiaRequests extends Middleware
{
    protected $rootView = 'app';

    public function rootView(Request $request)
    {
        if ($request->segment(1) == 'admin') {
            return 'admin';
        }

        return parent::rootView($request);
    }

    public function version(Request $request)
    {
        return parent::version($request);
    }

    public function share(Request $request)
    {
        return array_merge(parent::share($request), [
            //
        ]);
    }
}

project/resources/js/Shared/Frontend/Layouts/Layout.vue

<template>

    <Header />

    <slot />

    <Footer />

</template>

<script>
    import Header from '../Partials/Header'
    import Footer from '../Partials/Footer'
    export default {
        components: {
            Header,
            Footer
        },

        name: "FrontendLayout"
    }
</script>

project/resources/js/Pages/Frontend/Auth/Login.vue

<template>
    ...
</template>

<script>
    import Layout from '@/js/Shared/Frontend/Layouts/Layout';
    export default {
        
        layout: Layout,

        metaInfo: { title: 'Login' },

        data() {
            return {
                form: this.$inertia.form({
                    'email': '',
                    'password': '',
                    'remember': false
                })
            }
        },

        methods: {
            submit() {
                this.form.post(route('login.store'))
            }
        }
    }
</script>
Pippas answered 17/10, 2021 at 20:37 Comment(0)
O
1

In latest Inertia, Just import the 'Link' component and added .component("Link", Link) between .use() and .mount()

import { createApp, h } from 'vue';
import {createInertiaApp, Link} from '@inertiajs/inertia-vue3';
import { InertiaProgress } from '@inertiajs/progress'

createInertiaApp({
    resolve: name => {
        const pages = import.meta.glob('./Pages/**/*.vue', { eager: true })
        return pages[`./Pages/${name}.vue`]
    },
    setup({ el, App, props, plugin }) {
        createApp({ render: () => h(App, props) })
            .use(plugin)
            .component("Link", Link)
            .mount(el)
    },
});
Obryant answered 22/4, 2024 at 20:29 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.