Richard
Richard

Reputation: 111

Vite build and Vue defineAsyncComponent problem

Here is a simple Vue component it will dynamically load separate .vue files based on which component is selected :

<script setup>
import {computed, defineAsyncComponent, ref, watch} from "vue";
import Loading from "@/components/Loading.vue";
import Missing from "@/components/Missing.vue";
import {TwSelect,TwButton} from "vue3-tailwind-components";

const componentList = [
  {label:"One",value:'one.vue'},
  {label:"Two",value:'two.vue'},
  {label:"Three",value:'three.vue'},
]

const dynamicComponent = ref('')


function loadComponent(component) {
  return defineAsyncComponent({
    loader: () => import( /* @vite-ignore */component),
    loadingComponent:Loading,
    delay:2000,
    errorComponent: Missing,
    timeout: 3000
  })
}

const is_selected = computed(()=>{
  return dynamicComponent.value.length>0;
})

const component_with_path = computed(()=>{
  return './dynamic/'+dynamicComponent.value
})



</script>

<template>
 <h2 class="text-2xl">This is the static loader</h2>
  <p>It loads up a dynamic Vue component using defineAsyncComponent</p>
  <tw-select :items="componentList" v-model="dynamicComponent"></tw-select>
<component v-if="is_selected" :is="loadComponent(component_with_path)"></component>

</template>

When I run in dev mode the component_with_path is resolved and the dynamic component loads. How do I configure Vite to build so that the path of the dynamic components are resolved the same way?

please feel free to clone https://github.com/richardhulbert/vite-async.git to see the issue.

Upvotes: 0

Views: 515

Answers (3)

Richard
Richard

Reputation: 111

Thanks to gitsal who gave me a good clue!

"Since componentWithPath is a string, Vite does not treat it as a module path and does not process it correctly"

So needed to make a file let's call it componentMapping

export const componentMapping = {
    'one.vue':()=>import('./components/dynamic/one.vue'),
    'two.vue':()=>import('./components/dynamic/two.vue'),
    'three.vue':()=>import('./components/dynamic/three.vue')
}

I will figure out a way to create this perhaps using import.meta.glob('./components/dynamic/*.vue' )

Then I import this into Loader.vue and change the function to:

function loadComponent(component) {
  const loader = componentMapping[component];
  if (!loader) {
    return Missing;
  }
  return defineAsyncComponent({
    loader,
    loadingComponent:Loading,
    delay:2000,
    errorComponent: Missing,
    timeout: 3000
  })
}

Lastly I only pass the Vue component name (not the path) to the loadComponent function.

What really confused me is that the above code worked when Vite was in dev mode. Now it works in build as well!

Upvotes: 0

gitsal
gitsal

Reputation: 59

To describe your problem more accurately, you are using a relative path like this:


//return a string
const component_with_path = computed(()=>{
  return './dynamic/'+dynamicComponent.value
})

//...

loadComponent(component_with_path)

Since componentWithPath is a string, Vite does not treat it as a module path and does not process it correctly (both in development and build modes).

try:

import { defineAsyncComponent } from 'vue'
const dynamicComponent = defineAsyncComponent(() => import(componentWithPath.value))

//in template 
<component :is="dynamicComponent" />

using import vite will adjuste the path

Upvotes: 0

sara
sara

Reputation: 169

I'm not sure if this is what you mean, but the configuration in vite could look like this:

export default defineConfig({
  plugins: [vue()],
  resolve: {
    alias: {
      '@': path.resolve(__dirname, './src'),
    },
  },
  build: {
    rollupOptions: {
      output: {
        manualChunks(id) {
          if (id.includes('dynamic')) {
            return 'dynamic-components';
          }
        },
      },
    },
  },
});

or just check this out: https://www.npmjs.com/package/vite-plugin-dynamic-import

Upvotes: 0

Related Questions