How to add inline SVGs in a nuxt3 vite project

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

Upvotes: 6

Views: 12354

Answers (5)

cstuncsik
cstuncsik

Reputation: 2786

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>

Upvotes: 0

coeurofbear
coeurofbear

Reputation: 11

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>

Upvotes: 1

Manos
Manos

Reputation: 141

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>

Upvotes: 2

Leopold Kristjansson
Leopold Kristjansson

Reputation: 2784

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

Upvotes: 3

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()
    ]
},

Upvotes: 9

Related Questions