unplugin / unplugin-icons

🤹 Access thousands of icons as components on-demand universally.

Home Page:https://www.npmjs.com/package/unplugin-icons

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

How to load icon components asynchronously using `defineAsyncComponent` in `VUE3`

amihhs opened this issue · comments

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

@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;`
        }
      },
    },

imagen

right, it will solve my problem. Thank