How to load icon components asynchronously using `defineAsyncComponent` in `VUE3`
amihhs opened this issue · comments
amihhs commented
const complaintSteps = complaintStepsList.map((v, i) => {
let icon = defineAsyncComponent(() => import(`~icons/step/${i}.vue`))
// let ricon = resolveDynamicComponent(icon)
return {
title: v,
icon,
}
})
...
<component :is="item.icon"></component>
...
error
Uncaught (in promise) TypeError: Failed to resolve module specifier '~icons/step/1.vue'
at App.vue:8
at load (runtime-core.esm-bundler.js:1551)
at setup (runtime-core.esm-bundler.js:1634)
at callWithErrorHandling (runtime-core.esm-bundler.js:6737)
at setupStatefulComponent (runtime-core.esm-bundler.js:6346)
at setupComponent (runtime-core.esm-bundler.js:6302)
at mountComponent (runtime-core.esm-bundler.js:4224)
at processComponent (runtime-core.esm-bundler.js:4199)
at patch (runtime-core.esm-bundler.js:3791)
at mountChildren (runtime-core.esm-bundler.js:3987)
due to vite dynamic-import
limitations, I cannot use variables to load the corresponding icon when there is no clear path.
This is minimal demo :https://github.com/amihhs/unplugin-icons-vue3-test
Joaquín Sánchez commented
@amihhs to get it working we need to resolve the icons on server side via some plugin and so the list is just filled on the server, you only need to add/remove/update icons on the vite config file:
- remove from the svg files all dtd preamble, just keep the svg node
- change
App.vue
to include the list from the server virtual module (see new App.vue bellow) - change the collection resolver path to
'./src/assets/svg'
App.vue:
import stepsList from 'virtual:step-icons'
const steps = stepsList.map(({ title, i }) => {
let icon = defineAsyncComponent(i)
return {
title,
icon,
}
})
let icons = defineAsyncComponent(async() => {
const icon = await import('~icons/step/1')
return icon.default || icon
})
add stepList to vite config file:
const stepsList = [1, 2]
plugin: add it as the first plugin:
{
name: 'step-icons',
enforce: 'pre',
resolveId(id) {
return id.startsWith('virtual:step-icons')
? `${id.slice('virtual:'.length)}.js`
: undefined
},
load(id) {
if (id === 'step-icons.js') {
return `const stepsList = [${stepsList.map((i) => `{ title: ${i}, i: () => import('~icons/step/${i}') }`).join(', ')}];\nexport default stepsList;`
}
},
},
Joaquín Sánchez commented
amihhs commented
right, it will solve my problem. Thank