Closed MuzafferDede closed 2 years ago
Hello! I was trying to do something similar and after several ideas that occurred to me, I managed to do it this way:
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 add from './add.svg'
import multiply from './multiply.svg'
// etc
export { add, multiply, // etc }
2. In path `src/components`, create component `Icon.vue`:
// src/components/Icon.vue
3. Use it!
IMPORTANT NOTE: If your `svg` has a name in `kebab-case` (i. e `"heart-pulse.svg"`), when you use the `icon` component, the prop name must be in `snake_case` (i. e `"heart_pulse"`)
Haha, i end up almost the same way... the down side of this is that we have to include all svg files even we don't use them on the current page. well, for now this is the way i guess. Cheers!
@MuzafferDede you could use something like this to support lazy loading:
<template>
<component :is="currentIcon" />
</template>
<script>
export default {
data () {
return {
currentIcon: null
}
},
async created () {
this.currentIcon = await import('./assets/Bananas.svg')
}
}
</script>
@MuzafferDede you could use something like this to support lazy loading:
This still does not work. Have you tried?
Guys, you may try this plugin:
https://github.com/rollup/plugins/tree/master/packages/dynamic-import-vars
It works well on localdev, but I haven't figured out how to use it on production.
@MuzafferDede you could use something like this to support lazy loading:
This still does not work. Have you tried?
Yes, it works for me (using vite v2.4.4)
@jpkleemans
i get Cannot convert object to primitive value
when i use your suggestion.
I come out with this which works
import { defineAsyncComponent } from 'vue'
export default {
props: {
name: {
type: String,
default: undefined,
},
},
computed: {
currentIcon() {
return defineAsyncComponent(() => import(`../../assets/icons/svg/${this.name}.svg`))
},
},
};
@MuzafferDede ah, that's an even better solution!
Have some solution for vue-2?
You can do it with Vue 2 thanks to the @vue/composition-api
package 👍
import { defineAsyncComponent } from '@vue/composition-api';
For those wanting to use <script setup>
you can do this. This worked for me on Nuxt3.
<template>
<component :is="icon"/>
</template>
<script lang="ts" setup>
const props = defineProps({
name: {
type: String,
required: true
},
});
const icon = defineAsyncComponent(() => import(`../../assets/icons/${props.name}.svg`));
</script>
how could you make it work to have a :src instead of an :is ?
Just to be clear, if I use defineAsyncComponent
, is that going to try to load everything via URL then? Or will it figure it out at build time?
I wanted to retain the component
style where the SVG's are actually inlined
I think I found the best beautiful solution :) Vite docs: https://vitejs.dev/guide/features.html#glob-import
Template:
<component :is="icon" :class="className" />
Script:
import { defineAsyncComponent } from 'vue'
export default {
props: {
name: {
type: String,
required: true
}
},
data() {
return {
icons: import.meta.glob(`./**/*.svg`)
}
},
computed: {
icon() {
return defineAsyncComponent(() => this.icons[`./${this.name}.svg`]())
},
}
}
This is not a real dynamic import : import.meta.glob('./**/*.svg')
clearly say "I will import ALL icons according the glob pattern", and that is not what we want in real dynamic import.
This is not a real dynamic import :
import.meta.glob('./**/*.svg')
clearly say "I will import ALL icons according the glob pattern", and that is not what we want in real dynamic import.
Please write documentation from my link :)
I am not sure if this loader supports this:
and then we can use as
Currently console output as