svg-module icon indicating copy to clipboard operation
svg-module copied to clipboard

Not work on nuxt 3

Open dacoto97 opened this issue 3 years ago • 16 comments

image

dacoto97 avatar Oct 14 '21 15:10 dacoto97

Thanks @dacoto97 for reporting this. We have to support Vite. Maybe we should use packages like https://github.com/visualfanatic/vite-svg or https://github.com/jpkleemans/vite-svg-loader Related to:

  • https://github.com/JetBrains/svg-sprite-loader/issues/434
  • https://github.com/visualfanatic/vue-svg-loader/issues/142

manuelodelain avatar Oct 15 '21 08:10 manuelodelain

Solution:

npm install vite-svg-loader --save-dev
import { defineNuxtConfig } from "nuxt3"
import svgLoader from "vite-svg-loader"

export default defineNuxtConfig({
  vite: {
    plugins: [svgLoader()]
  }
})

dacoto97 avatar Oct 15 '21 14:10 dacoto97

I reopen the issue because we need to add the support for Vite to this module

manuelodelain avatar Oct 15 '21 14:10 manuelodelain

@manuelodelain anything new on this?

niklasfjeldberg avatar Feb 06 '22 11:02 niklasfjeldberg

Hi @niklasfjeldberg Unfortunately not ! I would like to do something really soon but had no time to check Vite / Nuxt3. Any help would be appreciated.

manuelodelain avatar Feb 14 '22 09:02 manuelodelain

@dacoto97

This solution appears to break Nuxt 3's asset resolution eg <img src="~/assets/icons/icon.svg" />

Have you found a workaround for this ?

stuible avatar Oct 13 '22 19:10 stuible

Solution:

npm install vite-svg-loader --save-dev
import { defineNuxtConfig } from "nuxt3"
import svgLoader from "vite-svg-loader"

export default defineNuxtConfig({
  vite: {
    plugins: [svgLoader()]
  }
})

I appreciate you sharing this! However the problem with this solution is that vite-svg-loader does not work with "~" paths, meaning you need to rewrite all your SVG paths to "../assets/icon.svg" pattern. Sounds a bit limiting when you want to keep using location-independent paths in your project

digitalcortex avatar Nov 29 '22 13:11 digitalcortex

In Nuxt 3, you don't need vite-svg-loader, but can instead create a custom component utilizing Vite's glob import:

<template>
  <span v-if="icon" class="h-[1em] w-[1em]" v-html="icon" />
</template>

<script setup lang="ts">
const props = defineProps<{
  name?: string
}>()

// Auto-load icons
const icons = Object.fromEntries(
  Object.entries(import.meta.glob('~/assets/images/*.svg', { as: 'raw' })).map(
    ([key, value]) => {
      const filename = key.split('/').pop()!.split('.').shift()
      return [filename, value]
    },
  ),
)

// Lazily load the icon
const icon = props.name && (await icons?.[props.name]?.())
</script>

johannschopplich avatar Dec 09 '22 13:12 johannschopplich

In Nuxt 3, you don't need vite-svg-loader, but can instead create a custom component utilizing Vite's glob import:

<template>
  <span v-if="icon" class="h-[1em] w-[1em]" v-html="icon" />
</template>

<script setup lang="ts">
const props = defineProps<{
  name?: string
}>()

// Auto-load icons
const icons = Object.fromEntries(
  Object.entries(import.meta.glob('~/assets/images/*.svg', { as: 'raw' })).map(
    ([key, value]) => {
      const filename = key.split('/').pop()!.split('.').shift()
      return [filename, value]
    },
  ),
)

// Lazily load the icon
const icon = props.name && (await icons?.[props.name]?.())
</script>

I wish I knew that before... Although vite-svg-loader offers SVGO optimization, is there any way to use svgo with vite glob import?

digitalcortex avatar Dec 09 '22 14:12 digitalcortex

Nope, no SVGO for now. But I will create a module for that.

johannschopplich avatar Dec 09 '22 14:12 johannschopplich

In Nuxt 3, you don't need vite-svg-loader, but can instead create a custom component utilizing Vite's glob import:

<template>
  <span v-if="icon" class="h-[1em] w-[1em]" v-html="icon" />
</template>

<script setup lang="ts">
const props = defineProps<{
  name?: string
}>()

// Auto-load icons
const icons = Object.fromEntries(
  Object.entries(import.meta.glob('~/assets/images/*.svg', { as: 'raw' })).map(
    ([key, value]) => {
      const filename = key.split('/').pop()!.split('.').shift()
      return [filename, value]
    },
  ),
)

// Lazily load the icon
const icon = props.name && (await icons?.[props.name]?.())
</script>

Your solution is super interesting but I am still a bit confused. Is there a way to avoid the span in this situation and import svg as pure component ? I would like to pass some class to the svg itself and it's kind of annoying having this span wrapping it. Also using v-html can be dangerous in some situation and I would prefer avoiding it but I don't see another way to go with your solution.

BenjaminOddou avatar Jan 28 '23 22:01 BenjaminOddou

@BenjaminOddou You should be able to get rid of the span by generating a VNode.

Something like (untested):

const VNode = () => h('svg', { innerHTML: /* your content */ })

madc avatar Feb 09 '23 12:02 madc

Hello @madc and thank you very much for your response. I finally succeeded to get rid of the span with vite-svg-loader by creating a "SVG component" :

<!-- TheSVG.vue -->
<script setup lang="ts">
const props = defineProps<{ name: string }>()
const icon = defineAsyncComponent(() => import(`../assets/svgs/${props.name}.svg?component`))
</script>

<template>
  <component :is="icon" />
</template>
<!-- SomePage.vue -->
<template>
      <TheSVG id="big-circle" name="big-circle" />
</template>

but I still struggle to interact with inline elements inside svg when they are imported. In a nutshell, I remarked that my inner svg elements aren't accessible onMounted (querySelector returns null after NuxtLink but working on hard reload).

I created a discussion about it here. Don't hesitate to leave a message or suggestion 😃

BenjaminOddou avatar Feb 09 '23 21:02 BenjaminOddou

I defined these two lines in the main.js file

import logo from './public/vite.svg'
       <img src="${logo}" class="logo" alt="Vite logo" />

Then I ran npm run build

and the icon is displayed

sh770 avatar Feb 15 '23 18:02 sh770

I defined these two lines in the main.js file

import logo from './public/vite.svg'
       <img src="${logo}" class="logo" alt="Vite logo" />

Then I ran npm run build

and the icon is displayed

An alternative to this solution that does not throw an error:

// you can get the path or filename from props or whatever
const logo = "/_nuxt/public/logo.svg"
<img :src="`${logo}`" class="logo" alt="Vite logo" />

g-libardi avatar Feb 19 '23 21:02 g-libardi

use vite-svg-loader but don't foget to pass 'raw' as defaultImport

      svgLoader({
        defaultImport: 'raw',
      })

moh1434 avatar Nov 28 '23 12:11 moh1434