Reputation: 111
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
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
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
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