How to add inline SVGs in a nuxt3 vite project
Asked Answered
B

5

6

Hi have been having troubling importing inline svgs into my nuxt3 vite project. Any advice would be much appreciated.

i found this works <img src="~/assets/images/icons/push-icon-chatops.svg" /> however i need an inline item. so i would do something like this <div v-html="rawNuxtLogo" /> and doing something like this(require doesnt work in vite) .

setup(props) {
        const currentIcon = computed(() => {
            return defineAsyncComponent(() =>
                import(`~/assets/images/icons/push-icon-chatops.svg'?inline`)
            );
        }).value;

        return {
            currentIcon,
        };
    },

however i found that vite does imports weirdly and the result is either the url string showing in the v-html or a object that doesnt read

i am trying to use this plugin with no success.

https://github.com/nuxt-community/svg-module

Byelaw answered 1/10, 2022 at 9:49 Comment(2)
Does this answer your question? How to include inline .svg in Nuxt applicationOpen
@Open so that was one of the items i looked at. require doesnt work in vite so i had to do that dynamic import bit, however it doesnt seem to workByelaw
B
9

so its seems that vite is actually not compatiable with the @nuxtjs/svg plugin. so the answer is to rather install a vite specific plugin in this case i installed vite plugin then do this

vite: {
    plugins: [
        svgLoader()
    ]
},
Byelaw answered 1/10, 2022 at 11:41 Comment(1)
Could have given a try to nuxt-svgo but overall, a Vite plugin is also what I achieved for a friend few months ago and it works great! Please accept your answer when you will be able to.Mundane
A
3

For TS Nuxt 3 projects it would be like this.

nuxt.config.ts file:

import svgLoader from 'vite-svg-loader'

export default defineNuxtConfig({
  // Rest of your config.
  vite: {
    plugins: [
      svgLoader({
       // Your settings.
      }),
    ],
  },
})

Example for a component:

<template>
  <div>
    <ArrowLeft />
  </div>
</template>

<script setup lang="ts">
import ArrowLeft from '../assets/svg/arrow-left.svg?component'
</script>

Note that the ?component in the end is important, otherwise TS will complain.

Plugin Documentation: vite-svg-loader

Anthodium answered 9/3, 2023 at 23:7 Comment(3)
how change size when using this?Diphenylhydantoin
@AlauddinAfifCassandra - if you mean the actual size of the SVG on the screen, that is done in the HTML/CSS. This answer only has to do with how you load the SVG file.Anthodium
How would this work for dynamic imports? I have <component :is="icon" /> in template and then icon.value = import(`~/assets/icons/${props.name}.svg`) and I am getting Uncaught (in promise) TypeError: Failed to resolve module specifier '~/assets/icons/arrow-up.svg'Ingenuous
C
2

Inline Svg images in nuxt 3, without using any library, such as vite-svg-loader or nuxt-svgo.

    <template>
        <span v-html="icon" />
    </template>

    <script lang="ts" setup>
       import { filename } from 'pathe/utils';
      
       const props = defineProps<{
            icon: string;
        }>();
    
       // Auto-load icons as raw
       const glob = import.meta.glob('~/assets/*.svg', { as: 'raw' });
       const images = Object.fromEntries(
       Object.entries(glob)
         .map(([key, value]: [string, any]) => [filename(key), value]))
    
       // Lazily load the icon
       const icon = props.icon && (await images?.[props.icon]?.());
    </script>
Configurationism answered 2/11, 2023 at 8:23 Comment(1)
it's always advisable to put the actual content, instead of a link to the answers(s). A link might not exist sin future.Incendiarism
S
1

This solution worked for me to import it dynamically, using vite-svg-loader:

<template>
  <component :is="icon" />
</template>

<script setup>
import { defineAsyncComponent } from 'vue'

const props = defineProps({
  name: {
    type: String,
    default: 'logo'
  }
})

const icons = import.meta.glob(`@/**/*.svg`)

const icon = computed(() => {
  return defineAsyncComponent(() => {
    return icons[`/assets/images/icons/${props.name}.svg`]()
  })
})

</script>
Sadiesadira answered 20/3 at 15:17 Comment(0)
W
0

Working without any additional module

<script lang="ts" setup>
import { onMounted } from 'vue'

const props = defineProps<{ url: string }>()
const svgString = ref('')

onMounted(() => {
  fetch(props.url)
    .then(response => response.text())
    .then((svg) => {
      const parser = new DOMParser()
      const doc = parser.parseFromString(svg, 'image/svg+xml')
      const svgElement = doc.documentElement
      const svgContainer = document.createElement('div')
      svgContainer.appendChild(svgElement)
      svgString.value = svgContainer.innerHTML
    })
  })
</script>
<template>
  <div v-html="svgString" />
</template>
Weighin answered 24/9 at 18:7 Comment(3)
Making a call + using non-sanitized flow tho. Lots of overhead for the client-side for no obvious benefit IMO.Mundane
Yes, for in-place assets probably the SVG loader is better, but if you need to load the images from a provider and need to use different colors on them you don't have a lot of options. You can use dompurify (or similar node module) for sanitizingWeighin
Yeah, I tend to use Iconify for any local projects nowadays. If you need to stream and inject those into your projects, that's probably the way indeed. Not optimal for sure but dirty workaround that could make the job.Mundane

© 2022 - 2024 — McMap. All rights reserved.