Themen

Serverseitiges Rendering

glyphfox-Icons sind einfaches SVG und werden daher auf dem Server wie jedes andere Markup gerendert. Entscheidend sind die Details: woher die Icon-Daten kommen, was bei der Hydration passiert und welche Arten des Renderings JavaScript im Browser benötigen.

Was jedes Paket auf dem Server rendert

Alle Pakete verwenden denselben Renderer, daher sieht ein Icon immer gleich aus, unabhängig davon, ob es von React auf einem Server, von Vue im Browser oder von toSvg in einem Build-Skript gerendert wurde. Der Unterschied liegt darin, ob der Server das Markup überhaupt erzeugen kann.

Art des RenderingsAusgabe auf dem ServerJavaScript im Browser
Komponenten für React, Vue, Svelte und Angularvollständiges svg-Markupnur für Morphs sowie Klick- und Zustands-Auslöser
toSvg und renderToStringein vollständiger svg-Stringnicht erforderlich
Das glyph-fox-Elementein leeres Elementerforderlich: Das Icon erscheint beim Upgrade des Elements
Die data-glyph-Runtimeein leeres <i>erforderlich: Die Runtime ersetzt es
Tailwind-CSS-Klassenein leeres Element, das Ihr CSS gestaltetnicht erforderlich
SVG-Spriteein svg mit einer use-Referenznicht erforderlich

Framework-spezifische Details stehen in eigenen Leitfäden: die Client-Boundary im App Router von Next.js, Plugins in Nuxt, Layouts in SvelteKit, Icons ohne JavaScript in Astro und Qwik sowie SolidStart. Diese Seite behandelt, was allen gemeinsam ist.

Icon-Daten auf dem Server

Eine Komponente wie HomeIcon bringt ihre eigenen Daten mit und registriert sie, sobald ihr Modul ausgeführt wird, daher wird sie auf dem Server immer gerendert. Alles, was ein Icon über seinen Namen anspricht, schlägt den Namen dagegen in einer Registry nach: Icon name, morphTo, die Teile von Fusion, MorphIcon, useMorph, morphStore und der name-Input der Angular-Komponente.

Ein nicht registrierter Name wird bei Bedarf über einen dynamischen Import nachgeladen. Dieses Laden beginnt erst im Browser, nach dem Mounten, daher rendert der Server einen Platzhalter in der richtigen Größe und sonst nichts:

server output
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none"
  stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"
  class="glyphfox glyphfox-empty" aria-hidden="true"></svg>

Registrieren Sie die verwendeten Namen in einem Modul, das sowohl der Server- als auch der Client-Einstiegspunkt importieren. Die Daten-Exports wie iconSettings sind klein und wie die Komponenten tree-shakable.

icons.js
import { registerIcons } from 'glyphfox/react'; // or glyphfox/vue, glyphfox/svelte
import { iconSettings, iconFile, iconCloud, iconLock, iconX } from 'glyphfox';

// Names used through Icon, morphTo, Fusion and MorphIcon.
registerIcons([iconSettings, iconFile, iconCloud, iconLock, iconX]);

In Angular geht dieselbe Liste an provideGlyphFox({ icons }), das auf dem Server und im Browser läuft; siehe den Angular-Leitfaden.

Wenn der Server mehr weiß als der Client

Das umgekehrte Problem ist ebenso real. Führt der Server das Paket ungebündelt aus, wie es Node bei extern bleibenden Abhängigkeiten tut, wertet jeder Import aus glyphfox/react oder glyphfox/vue den gesamten Einstiegspunkt aus, und jedes der 419 Icon-Module registriert sich selbst. <Icon name="settings" /> wird dann auf dem Server vollständig gerendert.

Das Browser-Bundle durchläuft Tree-Shaking, daher ist settings dort nicht registriert. Das erste Rendern im Client erzeugt den leeren Platzhalter, das Markup stimmt nicht mehr mit dem Server-HTML überein, und das Framework meldet einen Hydration-Mismatch, bevor das Icon erneut geladen wird. Werden die Namen wie oben explizit registriert, stimmen beide Seiten überein.

SVG-Strings mit toSvg

Außerhalb eines Komponenten-Frameworks gibt toSvg(spec, props) das Markup als String zurück. Die Funktion akzeptiert die vollständige Namenssyntax und alle gemeinsamen Props, hat keine Browser-Abhängigkeiten und führt kein I/O aus, deshalb funktioniert sie in Server-Templates, Static-Site-Generatoren, Serverless-Funktionen und Build-Skripten.

server.js
import express from 'express';
import { toSvg } from 'glyphfox';

const app = express();

app.get('/', (req, res) => {
  res.send(`<!doctype html>
<title>Files</title>
<ul>
  <li>${toSvg('file+check', { size: 18 })} report.pdf</li>
  <li>${toSvg('cloud&lock:overlap', { size: 18, title: 'Encrypted backup' })} backup.zip</li>
</ul>`);
});

app.listen(3000);

Das Rendern ist schnell, aber Modifier, Fusionen und der Solid-Stil leisten echte Geometriearbeit. Cachen Sie die Strings für Icons, die sich bei jeder Anfrage wiederholen; die Ausgabe hängt nur von der Spec und den Props ab.

icon.js
import { toSvg } from 'glyphfox';

const cache = new Map();

export function icon(spec, props = {}) {
  const key = spec + JSON.stringify(props);
  let svg = cache.get(key);
  if (svg === undefined) {
    svg = toSvg(spec, props);
    cache.set(key, svg);
  }
  return svg;
}

toSvg aus dem Haupteinstiegspunkt lädt alle Icons, was für einen Serverprozess unproblematisch ist. Wo die Codegröße zählt, etwa bei Edge Functions mit Größenlimit, verwenden Sie renderToString aus glyphfox/core mit den Daten jedes Icons aus glyphfox/icons/NAME; die Zahlen finden Sie im Leitfaden zum Tree-Shaking.

edge.js
import { renderToString } from 'glyphfox/core';
import download from 'glyphfox/icons/download';

export const downloadIcon = renderToString(download, { size: 18 });

Hydration, Morphs und lebendige Zustände

Der Server rendert den Zustand, den ein Icon zum Zeitpunkt des Renderns hat. Morphs werden im Browser berechnet: MorphIcon, morphTo und die Hooks beginnen erst nach der Hydration zu animieren, weil Effekte auf dem Server nicht laufen. Ein Icon mit morphTo und trigger="state", bei dem active bereits true ist, rendert auf dem Server sein Ziel, ein anfangs geöffnetes Menü zeigt also schon im HTML das x.

Lebendige Zustände brauchen überhaupt keine Hydration. Ihr CSS steckt im SVG, daher wird eine mount-Animation abgespielt, sobald der Browser das HTML parst, und eine hover-Animation funktioniert, bevor irgendein Skript geladen ist. Eine bereits aktive state-Animation wird mit ihrer Klasse gf-on gerendert und läuft ebenfalls direkt aus dem HTML. Klicks und spätere Zustandsänderungen benötigen das Framework, weil es das Attribut und die Klasse umschaltet, mit denen die Animationen starten. Die Regel für prefers-reduced-motion steht im selben Stylesheet und gilt auch für Server-Markup.

Das Markup ist deterministisch. Animationsklassen, Masken-IDs und Morph-Klassen sind Hashes ihres Inhalts, keine Zähler oder Zufallswerte. Server und Browser erzeugen daher dieselben Attribute, und IDs verursachen nie einen Hydration-Mismatch.

Die Web Component auf serverseitig gerenderten Seiten

Das glyph-fox-Element zeichnet in einen Shadow-Root, sobald sein Skript läuft. Es nutzt kein deklaratives Shadow-DOM, daher enthält das Server-HTML ein leeres Element ohne Größe, und die umgebende Zeile verschiebt sich, wenn das Icon erscheint. Reservieren Sie den Platz, bis das Element definiert ist:

app.css
glyph-fox:not(:defined) {
  display: inline-block;
  width: 24px;
  height: 24px;
  vertical-align: middle;
}

Rendern Sie Icons im sofort sichtbaren Bereich der Seite serverseitig als Inline-SVG, mit einer Komponente oder toSvg, und verwenden Sie das Element für Seitenbereiche, die sich im Client ändern. Der Leitfaden zu Web Components behandelt das Element im Detail.

E-Mails

Serverseitiges Rendering mündet oft in ein E-Mail-Template, und genau dort helfen SVG-Strings nicht: Viele E-Mail-Clients zeigen weder Inline-SVG noch SVG-Bilder an. Verwenden Sie dort PNG-Dateien. Im Icon-Browser laden Sie jedes Icon als PNG in der benötigten Größe herunter, mit Ihrer Farbe und Strichstärke.

Optionen für toSvg

toSvg und renderToString nehmen dieselben Props wie die Komponenten entgegen, als einfache Optionen.

OptionTypStandardBeschreibung
sizenumber, string24Breite und Höhe; Zahlen sind Pixel.
colorstringcurrentColorHauptfarbe.
secondaryColorstringcolorFarbe der Duotone-Ebene und der Solid-Füllung.
secondaryOpacitynumber0.3 / 1Deckkraft der Duotone-Ebene oder der Solid-Füllung.
weightnumber2Strichstärke von 1 bis 3 im 24er-Raster, unter 24 px optisch ausgeglichen.
absoluteWeightbooleanfalseHält den Strich bei jeder Größe auf weight Pixeln.
cornersround, sharproundAbgerundete oder spitze Verbindungen und Enden.
variantoutline, duotone, solidoutlineStilachse; solid entsteht aus den geschlossenen Formen.
rotatenumber0Drehung in Grad.
flipXbooleanfalseHorizontal spiegeln.
flipYbooleanfalseVertikal spiegeln.
mirrorRtlbooleanfalseIn Layouts von rechts nach links spiegeln.
animatedraw, pop, wiggle, spin, pulse, bounce, shakekeinerVoreinstellung für den lebendigen Zustand.
triggermount, hover, click, statemountWann die Animation oder der Morph abläuft.
activebooleanfalseDer Zustand für den Auslöser state.
durationnumber (ms)je nach VoreinstellungDauer der Animation oder des Morphs.
delaynumber (ms)0Verzögerung der Animation oder des Morphs.
loopboolean, numberfalseEndlos oder eine bestimmte Anzahl von Malen wiederholen (spin und pulse laufen standardmäßig in Schleife).
modifierplus, minus, check, x, alert, lock, clock, sync, arrow-up, arrow-down, dotkeinerBadge mit automatischer Aussparung.
modifierCornertop-left, top-right, bottom-left, bottom-rightbottom-rightEcke des Badges.
morphToname, datakeinerZiel des Morphs; der Auslöser bestimmt, wann es erscheint.
titlestringkeinerZugänglicher Name: title, role img und aria-label.
decorativebooleantrue ohne titleVerbirgt das Icon vor assistiven Technologien.

Stolperfallen

Leere Icons im Server-HTML
Ein per Name gerendertes Icon, das nie registriert wurde, ist auf dem Server ein leeres svg mit der Klasse glyphfox-empty. Registrieren Sie die Namen, oder importieren Sie die Komponente für dieses Icon.
Warnungen zu Hydration-Mismatches
Rendert der Server einen Namen, den der Browser noch nicht hat, unterscheidet sich das Markup beim ersten Rendern im Client. Typische Ursachen sind ein ungebündelter Server-Import eines ganzen Einstiegspunkts und Namen, die aus Daten stammen. Registrieren Sie die Namen in gemeinsam genutztem Code.
Icons, die vom Browser abhängen
Ein Icon, das anhand von localStorage, dem Farbschema oder der Fenstergröße gewählt wird, kann auf dem Server nicht übereinstimmen. Rendern Sie auf dem Server ein neutrales Icon und wechseln Sie nach dem Mounten, oder lesen Sie den Wert aus einem Cookie, das der Server sehen kann.
Layoutverschiebung durch das Element
Ein nicht definiertes glyph-fox hat keine Größe. Reservieren Sie den Platz mit :not(:defined), oder rendern Sie Inline-SVG auf dem Server.
Morph-Ziele in Produktions-Builds
In einem Produktions-Build mit Vite bleiben Namen, die weder importiert noch registriert sind, im Browser leer, weil der Loader für das Nachladen bei Bedarf innerhalb von node_modules nicht transformiert wird. Serverseitiges Rendering verdeckt das nicht; das Registrieren der Namen behebt das Problem auf beiden Seiten.

Häufige Fragen

Funktionieren die React-Komponenten in React Server Components?

Nicht direkt: Sie verwenden Hooks und brauchen daher eine Client-Boundary. In einer Server Component können Sie die Ausgabe von toSvg oder renderToString mit dangerouslySetInnerHTML rendern und liefern für das Icon kein JavaScript aus. Der Next.js-Leitfaden zeigt beides.

Warum ist mein Icon im Server-HTML leer?

Es wird per Name gerendert, über Icon, morphTo, Fusion oder MorphIcon, und seine Daten waren beim Rendern auf dem Server nicht registriert. Rufen Sie registerIcons mit den Daten-Exports in einem Modul auf, das beide Einstiegspunkte importieren.

Icons in diesem Leitfaden