Aujourd’hui le but du jeu est d’avoir un composant Vue à la fois flexible et complet pour charger des icônes en SVG :
- Simplifie l’ajout de nouvelles icônes
- Ne crée pas de requête HTTP supplémentaires
- Optimise le code SVG
- Conserve la flexibilité des composants Vue
- S’adapte visuellement au contexte
👉 Voici un dépôt d’exemple créé avec Vue CLI : https://github.com/nicooprat/icon.vue
La première étape consiste à ajouter un loader Webpack qui permet d’importer des SVG et de les traiter comme des composants Vue avec le plugin vue-svg-loader
(documentation), permettant aussi d’optimiser le code au passage.
Attention toutefois aux options de SVGO par défaut, notamment la suppression de l’attribut viewbox
qui peut poser des problèmes en terme de responsive par exemple.
Une fois installé il suffit de configurer vue.config.js
:
module.exports = {
chainWebpack: (config) => {
const svgRule = config.module.rule('svg')
svgRule.uses.clear() // Use inline SVG by default, add ?external to the URL if you want external loading
// See: https://vue-svg-loader.js.org/faq.html#how-to-use-both-inline-and-external-svgs
svgRule
.oneOf('external')
.resourceQuery(/external/)
.use('file-loader')
.loader('file-loader')
.options({
name: 'assets/[name].[hash:8].[ext]',
})
.end()
.end()
.oneOf('inline')
.use('vue-svg-loader')
.loader('vue-svg-loader')
.options({
svgo: {
// Options: https://github.com/svg/svgo/blob/master/.svgo.yml
plugins: [{ removeViewBox: false }, { prefixIds: true }, { removeXMLNS: true }]
}
})
},
}
Grâce au plugin babel-plugin-wildcard
(documentation) l’import des icônes se fait simplement de cette manière :
import * as Icons from '../assets/icons'
Si ESlint n’apprécie pas, vous pouvez précéder l’import de cette ligne :
// eslint-disable-next-line import/no-unresolved, import/no-extraneous-dependencies
Il suffira par la suite d’ajouter des fichiers SVG dans ce dossier. Ce plugin Webpack peut poser des problèmes de mise en cache, le plus simple est donc d’ajouter ce script au package.json
à utiliser en cas de problème :
"scripts": {
"clear:babel-cache": "rimraf -rf ./node_modules/.cache/babel-loader/*"
}
On peut ensuite inclure dynamiquement le code SVG de l’icône demandée :
<template>
<component :is="icon"/>
</template>
Et appeler notre icône ailleurs dans l’app de cette façon :
<Icon icon="help"/>
Bien sûr il est toujours possible, comme n’importe quel composant Vue, de transmettre (et potentiellement de surcharger) des attributs :
<Icon icon="help" class="red" width="16" height="16"/>
Il peut être utile d’ajouter ce style pour que l’icône soit de la même couleur que le texte courant (bien penser à l’attribut scoped
) :
<style scoped>
path {
fill: currentColor;
}
</style>
On peut aussi ajouter la propriété install
à notre composant Icon pour l’instancier globalement plus facilement :
export default {
...
install(Vue) {
Vue.component(this.name, this)
},
}
Il ne reste qu’à ajouter à notre main.js
:
import Icon from '@/components/Icon.vue'
Vue.use(Icon)
Updates
Ressources d’icônes
Voici quelques sets d’icônes propres et cohérents que je recommande. Pensez à respecter les accords de license ;)