question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

How to have a dynamic import SVG component

See original GitHub issue

Hello,

I have an issue when building the Vue (2.7) app:

[plugin:vite:dynamic-import-vars] invalid import “/icons/${this.name}.svg?raw”. Variable absolute imports are not supported, imports must start with ./ in the static part of the import. For example: import(./foo/${bar}.js).

We’re using this component everywhere in our application. SwIcon.vue :

<template lang="pug">
  div
    span.block(
      :class="[styleClass, sizeClass]"
      :style="{strokeLinecap: 'round', strokeLinejoin: 'round'}"
      @click="$emit('click')"
      v-html="svgRawContent"
    )
</template>

<script>
export default {
  name: 'SwIcon',
  props: {
    name: {
      type: String,
      default: '',
    },
    unstyled: {
      type: Boolean,
      default: false,
    },
    size: {
      type: String,
      default: 'w-6 h-6',
    },
  },
  data () {
    return {
      svgRawContent: '',
    };
  },
  computed: {
    sizeClass () {
      return this.size;
    },
    styleClass () {
      return this.unstyled ? '' : 'fill-none stroke-current stroke-2';
    },
  },
  // Todo: Replace by Suspense or something else when upgrading to Vue 3 to avoid async lifecycle method
  async mounted () {
    const svgObject = await import(`/icons/${this.name}.svg?raw`);
    this.svgRawContent = svgObject.default;
  },
};
</script>

Like you can see, we have this import await import(`/icons/${this.name}.svg?raw`); which is working good in development.

I guess the problem comes from the fact that during the build phase, since it is dynamic, it is not able to bundle the svg since it does not know them.

But then, how can I keep a similar component and make it work? Even if it has to bundle the whole icon’s folder, it’s not a big deal if it’s lazy loaded.

Thanks in advance, I appreciate it ❤️

PS: I have already check #24, but I don’t understand well for my case 😕

Issue Analytics

  • State:closed
  • Created a year ago
  • Comments:8 (3 by maintainers)

github_iconTop GitHub Comments

1reaction
adrianriverscommented, Sep 16, 2022

I’m using this code to render icons from a subfolder dynamically

<template>
  <IconComponent  :viewBox="viewBox" />
</template>

<script setup lang="ts">
import type { Component } from 'vue'
import { IconName } from '@/types/IconName'

export interface IconProps {
  name: IconName
  fill?: Color
  viewBox?: string | null
}

const props = withDefaults(defineProps<IconProps>(), {
  fill: 'default',
  viewBox: null,
})

const { loader } = createIconMap().get(props.name) ?? {}
const IconComponent = loader ? defineAsyncComponent(loader) : null

function getIconNameFromPath(path: string) {
  const pathSplit = path.split('/')
  const filename = pathSplit[pathSplit.length - 1] || ''
  const iconName = filename.replace('.svg', '')

  return iconName
}

function createIconMap() { 
  const importGlob = import.meta.glob('@/assets/icons/**/*.svg')
  const iconMap = new Map<string, { loader: () => Promise<Component> }>([])

  for (const path in importGlob) {
    const iconName = getIconNameFromPath(path)
    iconMap.set(iconName, { loader: importGlob[path] })
  }

  return iconMap
}
</script>

Sorry I haven’t worked much with Vue 2 but I’m sure something for Vue 2 could be adapted from the code above.

0reactions
jpkleemanscommented, Sep 7, 2022

Can you try to use defineAsyncComponent to see if that works?

import { defineAsyncComponent } from 'vue'

export default {
  mounted () {
    const svgObject = defineAsyncComponent(() => import(`/icons/${this.name}.svg?raw`))
  }
}
Read more comments on GitHub >

github_iconTop Results From Across the Web

How to dynamically import SVG and render it inline
You can make use of ref and ReactComponent named export when importing SVG file. Note that it has to be ref in order...
Read more >
React, dynamically importing SVG's | by Eric Khoury | Medium
Here's what I want to achieve: Import all SVG's from a folder at runtime, i.e based on props; Render the SVG as a...
Read more >
How can we dynamically import svg files? · Issue #19 - GitHub
Put in assets/icons all the svg that you will use. Create a file index.js and import and export the svg. // src/assets/icons/index.js import...
Read more >
Using React.lazy() to dynamically import svg files as ... - Reddit
My attempt in making that simpler is the following component with all svg files in a different folder: import React, { Suspense }...
Read more >
react-dynamic-svg-import - CodeSandbox
react-dynamic-svg-import. 1. Embed Fork Create Sandbox Sign in. Sandbox Info. react-dynamic-svg-import. react. svg. dynamic.
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found