Entwickler fügen SVG häufig direkt in JSX ein. Dies ist bequem zu verwenden, erhöht jedoch die Größe des JS-Bundles. Im Streben nach Optimierung habe ich beschlossen, eine andere Möglichkeit zu finden, SVG-Symbole zu verwenden, ohne das Paket zu überladen. Wir werden über SVG-Sprites sprechen, was sie sind, wie man sie verwendet und welche Tools für die Arbeit mit ihnen verfügbar sind.
Beginnend mit der Theorie werden wir ein Skript schreiben, das Schritt für Schritt ein SVG-Sprite generiert, und abschließend die Plugins für Vite und Webpack besprechen.
Was ist SVG-Sprite?
Ein Bild-Sprite ist eine Sammlung von Bildern, die in einem einzigen Bild zusammengefasst sind. SVG Sprite wiederum ist eine Sammlung von SVG-Inhalten, verpackt in <symbol />
, die in <svg />
platziert werden.
Wir haben zum Beispiel ein einfaches SVG-Stiftsymbol:
Um ein SVG-Sprite zu erhalten, ersetzen wir das Tag <svg />
durch <symbol />
und umschließen es extern mit <svg />
:
Jetzt ist es ein SVG-Sprite und wir haben darin ein Symbol mit id="icon-pen"
.
Ok, aber wir sollten herausfinden, wie wir dieses Symbol auf unserer HTML-Seite platzieren. Wir verwenden das Tag <use />
mit dem Attribut href
, geben die ID des Symbols an und duplizieren dieses Element innerhalb von SVG.
Schauen wir uns ein Beispiel an, wie <use />
funktioniert:
In diesem Beispiel gibt es zwei Kreise. Das erste hat einen blauen Umriss und das zweite ist ein Duplikat des ersten, jedoch mit einer roten Füllung.
Kommen wir zurück zu unserem SVG-Sprite. Zusammen mit der Verwendung von <use />
erhalten wir Folgendes:
Hier haben wir eine Schaltfläche mit unserem Stiftsymbol.
Bisher haben wir in <button />
ein Symbol ohne Code verwendet. Wenn wir mehr als eine Schaltfläche auf der Seite haben, wirkt sich dies nicht mehr als einmal auf die Größe unseres HTML-Layouts aus, da alle Symbole aus unserem SVG-Sprite stammen und wiederverwendbar sind.
Erstellen einer SVG-Sprite-Datei
Verschieben wir unser SVG-Sprite in eine separate Datei, damit wir die Datei index.html
nicht überladen müssen. Erstellen Sie zunächst eine sprite.svg
Datei und fügen Sie darin ein SVG-Sprite ein. Der nächste Schritt besteht darin, mithilfe des href
Attributs in <use/>
Zugriff auf das Symbol bereitzustellen:
Automatisierung der SVG-Sprite-Erstellung
Um bei der Verwendung von Symbolen viel Zeit zu sparen, richten wir eine Automatisierung für diesen Prozess ein. Um einen einfachen Zugriff auf die Symbole zu erhalten und sie nach unseren Wünschen verwalten zu können, müssen sie getrennt werden, jedes in einer eigenen Datei.
Zuerst sollten wir alle Symbole im selben Ordner ablegen, zum Beispiel:
Schreiben wir nun ein Skript, das diese Dateien erfasst und zu einem einzigen SVG-Sprite zusammenfügt.
Erstellen Sie die Datei
generateSvgSprite.ts
im Stammverzeichnis Ihres Projekts.
Glob- Bibliothek installieren:
npm i -D glob
Rufen Sie mit
globSync
ein Array vollständiger Pfade für jedes Symbol ab:Jetzt werden wir jeden Dateipfad iterieren und den Dateiinhalt mithilfe der integrierten Bibliothek fs von Node abrufen:
Großartig, wir haben den SVG-Code jedes Symbols und können sie jetzt kombinieren, aber wir sollten das
svg
Tag in jedem Symbol durch dassymbol
Tag ersetzen und nutzlose SVG-Attribute entfernen.
Wir sollten unseren SVG-Code mit einer HTML-Parser-Bibliothek analysieren, um seine DOM-Darstellung zu erhalten. Ich werde node-html-parser verwenden:
Wir haben den SVG-Code analysiert und das SVG-Element erhalten, als wäre es ein echtes HTML-Element.
Erstellen Sie mit demselben Parser ein leeres
symbol
, um untergeordnete Elemente vonsvgElement
in dassymbol
zu verschieben:Nachdem wir untergeordnete Elemente aus
svgElement
extrahiert haben, sollten wir auch die Attributeid
undviewBox
daraus erhalten. Alsid
legen wir den Namen der Symboldatei fest.Jetzt haben wir ein
symbol
, das in einem SVG-Sprite platziert werden kann. Definieren Sie also einfach die Variablesymbols
, bevor Sie die Dateien iterieren, wandeln Sie dassymbolElement
in einen String um und schieben Sie es insymbols
:Der letzte Schritt besteht darin, das SVG-Sprite selbst zu erstellen. Es stellt eine Zeichenfolge mit
svg
in „root“ und Symbolen als untergeordneten Elementen dar:const svgSprite = `<svg>${symbols.join('')}</svg>`;
Und wenn Sie nicht erwägen, Plugins zu verwenden, auf die ich weiter unten eingehen werde, müssen Sie die Datei mit dem erstellten Sprite in einem statischen Ordner ablegen. Die meisten Bundler verwenden einen
public
Ordner:fs.writeFileSync('public/sprite.svg', svgSprite);
Und das ist es; Das Skript ist einsatzbereit:
// 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);
Sie können dieses Skript im Stammverzeichnis Ihres Projekts ablegen und es mit tsx ausführen:
npx tsx generateSvgSprite.ts
Eigentlich verwende ich hier tsx , weil ich früher überall Code in TypeScript geschrieben habe und diese Bibliothek es Ihnen ermöglicht, in TypeScript geschriebene Knotenskripte auszuführen. Wenn Sie reines JavaScript verwenden möchten, können Sie es ausführen mit:
node generateSvgSprite.js
Fassen wir also zusammen, was das Skript tut:
- Es durchsucht den Ordner
src/icons
nach.svg
Dateien.
- Es extrahiert den Inhalt jedes Symbols und erstellt daraus ein Symbolelement.
- Es fasst alle Symbole in einem einzigen
<svg />.
- Es erstellt die Datei
sprite.svg
impublic
Ordner.
So ändern Sie die Symbolfarben
Lassen Sie uns einen häufigen und wichtigen Fall behandeln: Farben! Wir haben ein Skript erstellt, in dem das Symbol in ein Sprite eingefügt wird. Dieses Symbol kann jedoch im gesamten Projekt unterschiedliche Farben haben.
Wir sollten bedenken, dass nicht nur <svg/>
Elemente Füll- oder Strichattribute haben können, sondern auch path
, circle
, line
und andere. Es gibt eine sehr nützliche CSS-Funktion, die uns helfen wird – currentcolor .
Dieses Schlüsselwort stellt den Wert der Farbeigenschaft eines Elements dar. Wenn wir beispielsweise die color: red
für ein Element verwenden, das den background: currentcolor
hat, hat dieses Element einen roten Hintergrund.
Grundsätzlich müssen wir jeden Strich- oder Füllattributwert in die currentcolor
ändern. Ich hoffe, Sie sehen nicht, dass es manuell erledigt wird, heh. Und selbst das Schreiben von Code, der SVG-Strings ersetzt oder analysiert, ist im Vergleich zu einem sehr nützlichen Tool, SVGO, nicht sehr effizient.
Dabei handelt es sich um einen SVG-Optimierer, der nicht nur bei den Farben, sondern auch beim Entfernen redundanter Informationen aus SVG helfen kann.
Lassen Sie uns SVGo installieren:
npm i -D svgo
svgo
verfügt über integrierte Plugins, und eines davon ist convertColors
mit der Eigenschaft currentColor: true
. Wenn wir diese SVG-Ausgabe verwenden, werden die Farben durch currentcolor
ersetzt. Hier ist die Verwendung von svgo
zusammen mit 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);
Und die Ausgabe wird sein:
<svg viewBox="0 0 24 24"><path fill="currentColor" d="m15 5 4 4"/></svg>
Fügen wir svgo
zu unserem magischen Skript hinzu, das wir im vorherigen Teil geschrieben haben:
// 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);
Und führen Sie das Skript aus:
npx tsx generateSvgSprite.ts
Infolgedessen enthält das SVG-Sprite Symbole mit currentColor
. Und diese Symbole können überall im Projekt in jeder gewünschten Farbe verwendet werden.
Plugins
Wir haben ein Skript und können es jederzeit ausführen, aber es ist etwas unpraktisch, es manuell zu verwenden. Daher empfehle ich ein paar Plugins, die unsere .svg
Dateien ansehen und unterwegs SVG-Sprites generieren können:
vite-plugin-svg-spritemap (für Vite- Benutzer)
Dies ist mein Plugin, das im Wesentlichen dieses Skript enthält, das wir gerade in diesem Artikel erstellt haben. Für das Plugin ist die
currentColor
Ersetzung standardmäßig aktiviert, sodass Sie das Plugin ganz einfach einrichten können.// vite.config.ts import svgSpritemap from 'vite-plugin-svg-spritemap'; export default defineConfig({ plugins: [ svgSpritemap({ pattern: 'src/icons/*.svg', filename: 'sprite.svg', }), ], });
svg-spritemap-webpack-plugin (für Webpack- Benutzer)
Ich habe dieses Webpack-Plugin verwendet, bis ich zu Vite gewechselt bin. Aber dieses Plugin ist immer noch eine gute Lösung, wenn Sie Webpack verwenden. Sie sollten die Farbkonvertierung manuell aktivieren, dann sieht es so aus:
// 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', }, }), ], }
Verwendung im Layout
Ich werde ein Beispiel in React bereitstellen, aber Sie können es implementieren, wo Sie möchten, da es hauptsächlich um HTML geht. Da wir also sprite.svg
in unserem Build-Ordner haben, können wir auf die Sprite-Datei zugreifen und die grundlegende Icon
Komponente erstellen:
const Icon: FC<{ name: string }> = ({ name }) => ( <svg> <use href={`/sprite.svg#${name}`} /> </svg> ); const App = () => { return <Icon name="pen" />; };
Das Endergebnis
Um also viel manuelle Arbeit mit Symbolen zu vermeiden, fassen wir Folgendes zusammen:
- Sie können Symbole ganz einfach mit gewünschten Namen im Projekt speichern und organisiert aufbewahren
- Wir verfügen über ein Skript, das alle Symbole in einem einzigen Sprite in einer separaten Datei zusammenfasst, wodurch die Bundle-Größe reduziert wird und wir diese Symbole überall im Projekt verwenden können
- Wir verfügen über ein nützliches Tool, das uns hilft, Symbole von unnötigen Attributen zu befreien und die Farben am Verwendungsort zu ändern
- Wir verfügen über ein Plugin, das unsere Symboldateien ansehen und im Rahmen des Build-Prozesses unterwegs Sprites generieren kann
- haben eine Icon-Komponente, die das Sahnehäubchen darstellt
Abschluss
Bei der Effizienz in der Entwicklung geht es nicht nur um Zeitersparnis; Es geht darum, unser kreatives Potenzial freizusetzen. Die Automatisierung wichtiger Aufgaben wie der Verwaltung von Symbolen ist nicht nur eine Abkürzung; Es ist ein Tor zu einem reibungsloseren und wirkungsvolleren Codierungserlebnis. Und Sie sparen Zeit für solche Routineaufgaben, können sich auf komplexere Aufgaben konzentrieren und sich als Entwickler schneller weiterentwickeln.