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.
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.
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:
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 das symbol
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 von svgElement
in das symbol
zu verschieben:
Nachdem wir untergeordnete Elemente aus svgElement
extrahiert haben, sollten wir auch die Attribute id
und viewBox
daraus erhalten. Als id
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 Variable symbols
, bevor Sie die Dateien iterieren, wandeln Sie das symbolElement
in einen String um und schieben Sie es in symbols
:
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:
src/icons
nach .svg
Dateien.
<svg />.
sprite.svg
im public
Ordner.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.
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', }, }), ], }
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" />; };
Um also viel manuelle Arbeit mit Symbolen zu vermeiden, fassen wir Folgendes zusammen:
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.