-
Notifications
You must be signed in to change notification settings - Fork 87
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Dynamically refer to an icon #51
Comments
You can use dynamic components. Simply change |
If I print the value by putting It works fine when |
Hi, thanks for help guys! I managed to fix it by added default to the end of method: |
Well, you were quicker than me! Althought, thinking about it, you should use dynamic imports to enjoy the *magic* of code splitting: <template>
<component :is="dynamicIcon"/>
</template>
<script>
export default {
name: 'DynamicIcon',
props: {
icon: {
type: String,
required: true,
},
},
computed: {
dynamicIcon () {
return () => import(
/* webpackChunkName: "icons" */
/* webpackMode: "lazy-once" */
`./icons/${this.icon}.svg`
)
},
},
}
</script> Take notice that this only works if you do the Then you can reuse the component above throughout your project, allowing you to add multiple dynamic icons to the same component (and not rely on multiple computed properties): <template>
<div>
<DynamicIcon icon="icon-one"/>
<DynamicIcon icon="icon-two"/>
<DynamicIcon icon="icon-three"/>
</div>
</template>
<script>
import DynamicIcon from './DynamicIcon.vue'
export default {
name: 'IconList',
components: {
DynamicIcon,
},
}
</script> |
Thanks for this explanation! Is there a way to customize where the .js files that get produced are placed? All the .js files that get made for each svg are placed in the root of the webpack output directory, which makes that root output directory cluttered. Can it be configured to put them in another directory, like to take an options item like other loaders do, something like
So then all icons that vue-svg-loader operates on will be placed in that one directory. Could this feature be added? |
@rightaway I am currently working on a Babel plugin that would allow you to transform one import statement, for example: import icons from '@/assets/icons';
console.log(icons); // { SomeIcon: 'component declaration', AnotherIcon: '...' } ... into multiple statements: import SomeIcon from '@/assets/icons/some-icon.svg';
import AnotherIcon from '@/assets/icons/another_icon.svg';
const icons = { SomeIcon, AnotherIcon };
console.log(icons); It would scan the That plugin would also allow simplify multiple imports: import MyIcon from '@/assets/icons/my-icon.svg';
import SomeOtherIcon from '@/assets/icons/some_other-icon.svg';
import AnotherIcon from '@/assets/icons/anotherIcon.svg'; ... into a single one:
It has some other features like dynamic imports, custom icon and import name formatter, and ability to group webpack chunks into groups, so your app would make less requests to async SVG components. Would that plugin help you in any way? I am finishing the code and tests, so it should be available really soon. |
@visualfanatic This looks great but we're currently not using babel since we're only supporting latest browsers. The solution @henriqemalheiros described above works almost perfectly for our use case, downloading the files only as necessary. It makes a request for each separate file, which isn't so bad since we're using HTTP2 and once the file is downloaded once it can be cached. The only missing piece is that all the generated .js files are placed in the root webpack output directory. If some way could be added to specify a file pattern for the output files (as I've described in my last comment) so that we could customize the directory and file name then it would be perfect! |
@rightaway you can already do that, actually: return () => import(
/* webpackChunkName: "icons/icon-[request]" */
`./icons/${this.icon}.svg`
) The The extension on the chunk name could be annoying. Is possible to remove it by adding |
@henriqemalheiros I've tried the example as you've written it and for some reason it's still putting those files in the root output directory rather than in an Though would it be possible though to implement it as
So that it can be specified it in the webpack config file. Otherwise this particular path is hidden in the file containing the import while all other paths related to deployment are in the webpack config. And also having |
To clarify, when it loads the file the URL it loads is A bigger issue is because the name So there needs to be a request to the server every time which would return a If I take out the So the names that webpack generates by default for these svg files are great, I just need to instruct it to put the files in |
@rightaway please, check your Webpack configuration. I made a simple repo that does what you're asking: a separated chunk for each dynamically imported SVG with a hashed filename on a separated distribution folder. Just clone the repo, run As regards to adding |
Hi, I'm using this method with Nuxt, thanks @henriqemalheiros for this simple repo/demo. I tried the Nuxt solution provided in the 63 issue by @DigiSplit but it doesn't work with dynamic loading.
If somebody could help me with that or point me to the right direction it would be great. i already spent days on this without luck :/ |
@henriqemalheiros In this example you gave above <template>
<component :is="dynamicIcon"/>
</template>
<script>
export default {
name: 'DynamicIcon',
props: {
icon: {
type: String,
required: true,
},
},
computed: {
dynamicIcon () {
return () => import(
/* webpackChunkName: "icons" */
/* webpackMode: "lazy-once" */
`./icons/${this.icon}.svg`
)
},
},
}
</script> Is it possible to dynamically change the <template>
<DynamicIcon :icon="icon"/>
<template>
<script>
export default {
data() {
return {
icon: "myicon1"
}
},
methods: {
changeIcon() {
this.icon = "myicon2"
}
}
}
</script> |
The dynamic switching works for me with |
@rightaway This happens because the nature of require (synchronous) and import (asynchronous) it's different. Require in commonJs synchronously retrieve the exports from another module, import instead relies on Promise internally. To have a fully reactive computed property, in the case you are referring to, you need to make somehow the compute property aware of the change in the props. This is easily achieved just referencing the props before the return call. Important, this technique will make re-compute the computed property every time the props changes (be aware of the behavior before implementing it, it opens up "mutation" on the computed property). In order to achieve a fully dynamic reactive behavior, change your example in the following way:
|
same here, adding |
When I was using svgs as images and using
require
, I was able to dynamically require images. So I could have a folder of 1000 images and I wouldn't have to require them each by hand. In the component template I had<img :src=iconPath(dynamicValue)>
.iconPath
is a method on a vue component like thisEvery svg file in
./icons
would get included in my webpack bundle automatically, and then based on the value ofdynamicValue
, the correct image would appear in the component template.I can't find a way to do it with vue-svg-loader without having to specify all the files themselves in some kind of
icons/index.js
file that has all the icons exported, so I can doimport { MyIcon } from './icons'
. Would there be a way to make it work like that?The text was updated successfully, but these errors were encountered: