Les développeurs insèrent souvent SVG directement dans JSX. C'est pratique à utiliser, mais cela augmente la taille du bundle JS. Dans un souci d'optimisation, j'ai décidé de trouver une autre façon d'utiliser les icônes SVG sans encombrer le bundle. Nous parlerons des sprites SVG, de ce qu'ils sont, comment les utiliser et quels outils sont disponibles pour travailler avec eux. En commençant par la théorie, nous allons écrire un script qui génère un sprite SVG étape par étape et conclure en discutant des plugins pour et . vite webpack Qu’est-ce que le Sprite SVG ? Un sprite d’image est une collection d’images placées dans une seule image. À son tour, SVG Sprite est une collection de contenu SVG, enveloppé dans , qui est placé dans . <symbol /> <svg /> Par exemple, nous avons une simple icône de stylo SVG : Pour obtenir un sprite SVG, nous allons remplacer la balise par , et l'envelopper avec en externe : <svg /> <symbol /> <svg /> C'est maintenant un sprite SVG, et nous avons une icône à l'intérieur avec . id="icon-pen" Ok, mais nous devrions trouver comment placer cette icône sur notre page HTML. Nous utiliserons la balise avec l'attribut , en spécifiant l'ID de l'icône, et elle dupliquera cet élément dans SVG. <use /> href Jetons un coup d'œil à un exemple du fonctionnement de : <use /> Dans cet exemple, il y a deux cercles. Le premier a un contour bleu et le second est une copie du premier mais avec un remplissage rouge. Revenons à notre sprite SVG. En plus de l'utilisation de , nous obtiendrons ceci : <use /> Ici, nous avons un bouton avec notre icône de stylo. Jusqu'à présent, nous avons utilisé une icône sans son code dans . Si nous avons plus d'un bouton sur la page, cela n'affectera pas plus d'une fois la taille de notre mise en page HTML car toutes les icônes proviendront de notre sprite SVG et seront réutilisables. <button /> Création d'un fichier Sprite SVG Déplaçons notre sprite SVG dans un fichier séparé afin de ne pas avoir à encombrer le fichier . Tout d’abord, créez un fichier et insérez-y un sprite SVG. L'étape suivante consiste à fournir l'accès à l'icône en utilisant l'attribut dans : index.html sprite.svg href <use/> Automatisation de la création de sprites SVG Pour gagner beaucoup de temps sur l'utilisation des icônes, mettons en place une automatisation pour ce processus. Pour accéder facilement aux icônes et les gérer comme nous le souhaitons, il faut les séparer, chacune dans son propre fichier. Tout d’abord, nous devrions mettre toutes les icônes dans le même dossier, par exemple : Maintenant, écrivons un script qui récupère ces fichiers et les combine en un seul sprite SVG. Créez le fichier dans le répertoire racine de votre projet. generateSvgSprite.ts Installez la bibliothèque : globale npm i -D glob Obtenez un tableau de chemins complets pour chaque icône en utilisant : globSync Maintenant, nous allons parcourir chaque chemin de fichier et obtenir le contenu du fichier à l'aide de la bibliothèque intégrée de Node : fs Super, nous avons le code SVG de chaque icône, et maintenant nous pouvons les combiner, mais nous devrions remplacer la balise à l'intérieur de chaque icône par la balise et supprimer les attributs SVG inutiles. svg symbol Nous devrions analyser notre code SVG avec une bibliothèque d'analyseurs HTML pour obtenir sa représentation DOM. J'utiliserai : node-html-parser Nous avons analysé le code SVG et obtenu l'élément SVG comme s'il s'agissait d'un véritable élément HTML. En utilisant le même analyseur, créez un élément vide pour déplacer les enfants de vers : symbol svgElement symbol Après avoir extrait les enfants de , nous devrions également en obtenir les attributs et . En tant , définissons le nom du fichier icône. svgElement id viewBox id Nous avons maintenant un élément qui peut être placé dans un sprite SVG. Il suffit donc de définir la variable avant d'itérer les fichiers, de transformer le en chaîne et de le pousser en : symbol symbols symbolElement symbols La dernière étape consiste à créer le sprite SVG lui-même. Il représente une chaîne avec en « racine » et des symboles comme enfants : svg const svgSprite = `<svg>${symbols.join('')}</svg>`; Et si vous n'envisagez pas d'utiliser les plugins, dont je parlerai ci-dessous, vous devez placer le fichier avec le sprite créé dans un dossier statique. La plupart des bundlers utilisent un dossier : public fs.writeFileSync('public/sprite.svg', svgSprite); Et c'est tout ; le script est prêt à être utilisé : // generateSvgSprite.ts import { globSync } from 'glob'; import fs from 'fs'; import { HTMLElement, parse } from 'node-html-parser'; import path from 'path'; const svgFiles = globSync('src/icons/*.svg'); const symbols: string[] = []; svgFiles.forEach(file => { const code = fs.readFileSync(file, 'utf-8'); const svgElement = parse(code).querySelector('svg') as HTMLElement; const symbolElement = parse('<symbol/>').querySelector('symbol') as HTMLElement; const fileName = path.basename(file, '.svg'); svgElement.childNodes.forEach(child => symbolElement.appendChild(child)); symbolElement.setAttribute('id', fileName); if (svgElement.attributes.viewBox) { symbolElement.setAttribute('viewBox', svgElement.attributes.viewBox); } symbols.push(symbolElement.toString()); }); const svgSprite = `<svg>${symbols.join('')}</svg>`; fs.writeFileSync('public/sprite.svg', svgSprite); Vous pouvez mettre ce script à la racine de votre projet et l'exécuter avec : tsx npx tsx generateSvgSprite.ts En fait, j'utilise ici parce que j'écrivais du code en TypeScript partout, et cette bibliothèque vous permet d'exécuter des scripts de nœuds écrits en TypeScript. Si vous souhaitez utiliser du JavaScript pur, vous pouvez l'exécuter avec : tsx node generateSvgSprite.js Alors, résumons ce que fait le script : Il recherche dans le dossier tous les fichiers . src/icons .svg Il extrait le contenu de chaque icône et en crée un élément de symbole. Il regroupe tous les symboles dans un seul <svg />. Il crée le fichier dans le dossier . sprite.svg public Comment changer les couleurs des icônes Abordons un cas fréquent et important : les couleurs ! Nous avons créé un script dans lequel l'icône va dans un sprite, mais cette icône peut avoir des couleurs différentes tout au long du projet. Nous devons garder à l’esprit que non seulement les éléments peuvent avoir des attributs fill ou Stroke , mais aussi , , et autres. Il existe une fonctionnalité CSS très utile qui nous aidera : . <svg/> path circle line currentcolor Ce mot-clé représente la valeur de la propriété color d'un élément. Par exemple, si on utilise la sur un élément qui a un , alors cet élément aura un fond rouge. color: red background: currentcolor Fondamentalement, nous devons remplacer chaque valeur d'attribut de trait ou de remplissage par la valeur . J'espère que vous ne le voyez pas fait manuellement, hein. Et même écrire du code qui remplacera ou analysera les chaînes SVG n'est pas très efficace par rapport à un outil très utile . currentcolor svgo Il s'agit d'un optimiseur SVG qui peut aider non seulement avec les couleurs, mais également à supprimer les informations redondantes du SVG. Installons : svgo npm i -D svgo a des plugins intégrés, et l'un d'eux est , qui a la propriété . Si nous utilisons cette sortie SVG, elle remplacera les couleurs par . Voici l'utilisation de avec : svgo convertColors currentColor: true currentcolor svgo convertColors import { optimize } from 'svgo'; const output = optimize( '<svg viewBox="0 0 24 24"><path fill="#000" d="m15 5 4 4" /></svg>', { plugins: [ { name: 'convertColors', params: { currentColor: true, }, } ], } ) console.log(output); Et le résultat sera : <svg viewBox="0 0 24 24"><path fill="currentColor" d="m15 5 4 4"/></svg> Ajoutons dans notre script magique que nous avons écrit dans la partie précédente : svgo // generateSvgSprite.ts import { globSync } from 'glob'; import fs from 'fs'; import { HTMLElement, parse } from 'node-html-parser'; import path from 'path'; import { Config as SVGOConfig, optimize } from 'svgo'; // import `optimize` function const svgoConfig: SVGOConfig = { plugins: [ { name: 'convertColors', params: { currentColor: true, }, } ], }; const svgFiles = globSync('src/icons/*.svg'); const symbols: string[] = []; svgFiles.forEach(file => { const code = fs.readFileSync(file, 'utf-8'); const result = optimize(code, svgoConfig).data; // here goes `svgo` magic with optimization const svgElement = parse(result).querySelector('svg') as HTMLElement; const symbolElement = parse('<symbol/>').querySelector('symbol') as HTMLElement; const fileName = path.basename(file, '.svg'); svgElement.childNodes.forEach(child => symbolElement.appendChild(child)); symbolElement.setAttribute('id', fileName); if (svgElement.attributes.viewBox) { symbolElement.setAttribute('viewBox', svgElement.attributes.viewBox); } symbols.push(symbolElement.toString()); }); const svgSprite = `<svg xmlns="http://www.w3.org/2000/svg">${symbols.join('')}</svg>`; fs.writeFileSync('public/sprite.svg', svgSprite); Et exécutez le script : npx tsx generateSvgSprite.ts Par conséquent, le sprite SVG contiendra des icônes avec . Et ces icônes peuvent être utilisées partout dans le projet avec la couleur de votre choix. currentColor Plugins Nous avons un script et nous pouvons l'exécuter quand nous le voulons, mais il est légèrement gênant de l'utiliser manuellement. Je recommande donc quelques plugins capables de visualiser nos fichiers et de générer des sprites SVG en déplacement : .svg (pour les utilisateurs ) vite-plugin-svg-spritemap vite Ceci est mon plugin qui contient essentiellement ce script que nous venons de créer dans cet article. Le plugin a le remplacement activé par défaut, vous pouvez donc configurer le plugin assez facilement. currentColor // vite.config.ts import svgSpritemap from 'vite-plugin-svg-spritemap'; export default defineConfig({ plugins: [ svgSpritemap({ pattern: 'src/icons/*.svg', filename: 'sprite.svg', }), ], }); (pour les utilisateurs ) svg-spritemap-webpack-plugin du webpack J'ai utilisé ce plugin Webpack jusqu'à ce que je passe à Vite. Mais ce plugin reste une bonne solution si vous utilisez Webpack. Vous devez activer manuellement la conversion des couleurs, et cela ressemblera à ceci : // webpack.config.js const SVGSpritemapPlugin = require('svg-spritemap-webpack-plugin'); module.exports = { plugins: [ new SVGSpritemapPlugin('src/icons/*.svg', { output: { svgo: { plugins: [ { name: 'convertColors', params: { currentColor: true, }, }, ], }, filename: 'sprite.svg', }, }), ], } Utilisation dans la mise en page Je vais fournir un exemple dans , mais vous pouvez l'implémenter où vous le souhaitez car il s'agit principalement de HTML. Ainsi, comme nous avons dans notre dossier build, nous pouvons accéder au fichier sprite et créer le composant de base : React sprite.svg Icon const Icon: FC<{ name: string }> = ({ name }) => ( <svg> <use href={`/sprite.svg#${name}`} /> </svg> ); const App = () => { return <Icon name="pen" />; }; Le résultat final Donc, en résumant le tout, pour éviter beaucoup de travail manuel avec les icônes, nous : peut facilement enregistrer et conserver des icônes organisées dans le projet avec des noms souhaitables avoir un script qui combine toutes les icônes en un seul sprite dans un fichier séparé qui réduit la taille du bundle et nous permet d'utiliser ces icônes n'importe où dans le projet avoir un outil utile qui nous aide à garder les icônes désencombrées des attributs inutiles et à changer les couleurs sur le lieu d'utilisation avoir un plugin qui peut regarder nos fichiers d'icônes et générer des sprites en déplacement dans le cadre du processus de construction avoir un composant Icon qui est une cerise sur le gâteau Conclusion L'efficacité du développement ne consiste pas seulement à gagner du temps ; il s'agit de libérer notre potentiel créatif. L'automatisation des tâches essentielles comme la gestion des icônes n'est pas seulement un raccourci ; c'est une passerelle vers une expérience de codage plus fluide et plus percutante. Et en gagnant du temps sur des tâches aussi routinières, vous pouvez vous concentrer sur des tâches plus complexes et évoluer plus rapidement en tant que développeur.