12

In the previous way of setting up inertia in a laravel app, I could tweak the resolve property in the `createInertiaApp function from:

{
   ...,
   resolve: name => import("./Pages/${name}"),
   ...
}

To

{
   ...,
   resolve: name => {
    const page = require("./Pages/${name}").default
    if(!page.layout) {
     page.layout = DefaultLayoutFile
    }
   },
   ...
}

To allow me manually pass a default layout file to be used in pages.

But with Vite becoming the default asset bundler and according to the docs, I must use a resolvePageComponent function which takes in import.meta.glob as a second argument to instruct Vite which files to bundle.

Problem here is the import gets returned from this resolvePageComponent so I cannot access the default object like I normally will from a require function.

So I have not been able to attach a default layout file to imported pages.

Has anyone been able to find a workaround for this?

Karl Hill
  • 12,937
  • 5
  • 58
  • 95
Willower
  • 1,099
  • 8
  • 22

5 Answers5

30

Assuming you imported your default layout file like this (remember to not use @ in imports anymore as only relative paths work for static analysis reasons):

import DefaultLayoutFile from './Layouts/DefaultLayoutFile.vue'

You can use the following code to get default layout working with Inertia and Vite:

  resolve: (name) => {
    const page = resolvePageComponent(
      `./Pages/${name}.vue`,
      import.meta.glob("./Pages/**/*.vue")
    );
    page.then((module) => {
      module.default.layout = module.default.layout || DefaultLayoutFile;
    });
    return page;
  },

[UPDATE 2022-08-01]

Since this is still receiving views, I though it would be useful to show how to get the @ working in imports in Vite.

Require path below your imports in vite.config.js

import { defineConfig } from 'vite';
import laravel from 'laravel-vite-plugin';
import vue from '@vitejs/plugin-vue';
const path = require('path')

And then add resolve into your config below:

export default defineConfig({
  resolve:{
    alias:{
      '@' : path.resolve(__dirname, './src')
    },
  },
})

Now @ will point to your Laravel root and you can import components dynamically from anywhere:

For example import LayoutTop from '@/Layouts/LayoutTop.vue' will now point to /resources/js/Layouts/LayoutTop.vue

Remember that Vite needs the .vue extension when importing Vue SFC files.

Jure Srpcic
  • 612
  • 1
  • 7
  • 11
  • I've refactored this a bit to use async/await which makes the resolve function look a lot shorter (3 lines). – PieterJan Aug 23 '22 at 17:35
  • how is your code? @PieterJan – Ricardo Sawir Aug 31 '22 at 10:22
  • I tried this with Svelte and it's not working. – Lucas Sep 15 '22 at 23:10
  • 1
    It's worth to mention that _"... the Laravel Vite plugin automatically adds an @ alias for your /resources/js directory."_. See [here](https://github.com/laravel/vite-plugin/blob/main/UPGRADE.md#importing-your-css-from-your-javascript-entry-points) – Marco Nov 15 '22 at 15:45
6

The async await version of the accepted answer

resolve: async name => {
    const page = await resolvePageComponent(`./Pages/${name}.vue`, import.meta.glob("./Pages/**/*.vue"));
    page.default.layout ??= DefaultLayoutFile;
    return page;
  },
residualflash
  • 94
  • 1
  • 3
1

@residualflash Adding condition works as well:

resolve: async name => {
 const page = await resolvePageComponent(`./Pages/${name}.vue`, import.meta.glob("./Pages/**/*.vue"));
 if (name.startsWith('Auth/')){
  page.default.layout ??= AuthLayoutFile;
 }else{
  page.default.layout ??= DefaultLayoutFile;
 }
 return page;
},
Mel
  • 858
  • 8
  • 15
1

For Default Persistent Layout in Laravel+ Vue3 + Inertia + Vite Setup(Laravel 9 and above)

// resources\js\app.js

import { createApp, h } from 'vue'
import { createInertiaApp } from '@inertiajs/vue3'

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)
      .mount(el)
  },
})

Change to

import { createApp, h } from 'vue'
import { createInertiaApp } from '@inertiajs/vue3'

// import your default layout.vue,@~resources\js
import Layout from '@/Layouts/Front/Layout.vue'

createInertiaApp({
  resolve: name => {
    const pages = import.meta.glob('./Pages/**/*.vue', { eager: true })

    // New code added
    let page = pages[`./Pages/${name}.vue`].default
    
    if(!page.layout){
      page.layout=Layout;
    }
    // OR
    // page.layout??=Layout;

    return pages[`./Pages/${name}.vue`]
  },
  setup({ el, App, props, plugin }) {
    createApp({ render: () => h(App, props) })
      .use(plugin)
      .mount(el)
  },
})

For Default Persistent Layout in Laravel+ Vue3 + Inertia + Webpack Setup(Laravel 8 and below)

// resources\js\app.js

createInertiaApp({
  resolve: name => require(`./Pages/${name}`),
})

Change to

// import your default layout.vue
import Layout from './Layouts/Front/Layout.vue'
createInertiaApp({
  resolve: name => {
  let page=require(`./Pages/${name}`).default;

    if(!page.layout){
      page.layout=Layout;
    }
    // OR
    // page.layout??=Layout;

    return page;
 },
})
0

This worked from me using the vite with inertia preset

import { createApp, h } from 'vue'
import { createInertiaApp } from '@inertiajs/inertia-vue3'
import { resolvePageComponent } from 'vite-plugin-laravel/inertia'
import DefaultLayout from '@/views/layouts/default.vue'
import SimpleLayout from '@/views/layouts/simple.vue'
import UserLayout from '@/views/layouts/user.vue'

createInertiaApp({
    resolve: (name) => {
        const page = resolvePageComponent(
            name,
            import.meta.glob('../views/pages/**/*.vue'),
            DefaultLayout
        );

        page.then((module) => {
            if (name.startsWith('auth.')) module.layout = SimpleLayout;
            if (name.startsWith('user.')) module.layout = [DefaultLayout, UserLayout];
        });

        return page
    },
    setup({ el, app, props, plugin }) {
        createApp({ render: () => h(app, props) })
            .use(plugin)
            .mount(el)
    },
})
  • I believe `module.__file` won't be available in production, I ran into that issue a few weeks back. Better to check if `name` includes `'/auth/'` instead. Granted, that issue did occur when using Laravel Mix, not Vite. – Alex Sep 21 '22 at 19:22
  • Your right i had to refactor it to work in production. I set the default layout in resolvePageComponent and then conditionally changed the layout based on the name. – Jordan Bain Sep 27 '22 at 17:24