Thèmes

Rendu côté serveur

Les icônes glyphfox sont du simple SVG : elles sont donc rendues côté serveur comme n'importe quel autre balisage. Les points importants sont la provenance des données des icônes, ce qui se passe à l'hydratation, et les modes de rendu qui nécessitent du JavaScript dans le navigateur.

Ce que chaque paquet rend côté serveur

Tous les paquets utilisent le même moteur de rendu : une icône est donc identique, qu'elle ait été rendue par React sur un serveur, par Vue dans le navigateur ou par toSvg dans un script de build. Ce qui diffère, c'est la capacité même du serveur à produire le balisage.

Mode de renduSortie serveurJavaScript dans le navigateur
Composants React, Vue, Svelte et Angularbalisage svg completuniquement pour les morphs et les déclencheurs de clic et d'état
toSvg et renderToStringune chaîne svg complèteaucun
L'élément glyph-foxun élément viderequis : l'icône apparaît lors de la mise à niveau de l'élément
Le runtime data-glyphun <i> viderequis : le runtime le remplace
Classes Tailwind CSSun élément vide stylisé par votre CSSaucun
Sprite SVGun svg avec une référence useaucun

Les particularités de chaque framework sont traitées dans leurs propres guides : la frontière client de l'App Router de Next.js, les plugins dans Nuxt, les layouts dans SvelteKit, les icônes sans JavaScript dans Astro et Qwik, ainsi que SolidStart. Cette page couvre ce qu'ils ont en commun.

Données des icônes sur le serveur

Un composant comme HomeIcon embarque ses propres données et les enregistre à l'exécution de son module : il est donc toujours rendu côté serveur. Tout ce qui désigne une icône par son nom cherche au contraire ce nom dans un registre : Icon name, morphTo, les parties de Fusion, MorphIcon, useMorph, morphStore et l'input name du composant Angular.

Un nom non enregistré est chargé à la demande via un import dynamique. Ce chargement ne démarre que dans le navigateur, après le montage : le serveur rend donc un placeholder de la bonne taille, et rien d'autre :

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>

Enregistrez les noms que vous utilisez dans un module importé à la fois par le point d'entrée serveur et par le point d'entrée client. Les exports de données comme iconSettings sont légers et profitent du tree shaking au même titre que les composants.

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]);

Dans Angular, la même liste est passée à provideGlyphFox({ icons }), qui s'exécute sur le serveur et dans le navigateur (voir le guide Angular).

Quand le serveur en sait plus que le client

Le problème inverse est tout aussi réel. Lorsque le serveur exécute le paquet sans passer par un bundler, comme Node le fait pour les dépendances qui restent externes, importer quoi que ce soit depuis glyphfox/react ou glyphfox/vue évalue tout le point d'entrée, et chacun des 419 modules d'icônes s'enregistre. <Icon name="settings" /> est alors entièrement rendu côté serveur.

Le bundle du navigateur, lui, passe par le tree shaking : settings n'y est donc pas enregistré. Le premier rendu client produit le placeholder vide, le balisage ne correspond plus au HTML du serveur, et le framework signale une incohérence d'hydratation avant que l'icône ne soit chargée de nouveau. Enregistrer explicitement les noms, comme ci-dessus, met les deux côtés d'accord.

Chaînes SVG avec toSvg

En dehors d'un framework à composants, toSvg(spec, props) renvoie le balisage sous forme de chaîne. Il accepte la syntaxe complète des noms et toutes les props communes, n'a aucune dépendance au navigateur et n'effectue aucune entrée/sortie : il fonctionne donc dans les templates serveur, les générateurs de sites statiques, les fonctions serverless et les scripts de build.

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);

Le rendu est rapide, mais les modificateurs, les fusions et le style solid demandent un vrai travail géométrique. Pour les icônes qui reviennent à chaque requête, mettez les chaînes en cache ; le résultat ne dépend que de la spec et des props.

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, importé depuis le point d'entrée principal, charge toutes les icônes, ce qui ne pose pas de problème pour un processus serveur. Lorsque la taille du code compte, par exemple pour des fonctions edge soumises à une limite de taille, utilisez renderToString depuis glyphfox/core avec les données de chaque icône issues de glyphfox/icons/NAME ; le guide sur le tree shaking donne les chiffres.

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

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

Hydratation, morphs et états vivants

Le serveur rend l'état de l'icône au moment du rendu. Les morphs sont calculés dans le navigateur : MorphIcon, morphTo et les hooks ne commencent à animer qu'après l'hydratation, car les effets ne s'exécutent pas sur le serveur. Une icône avec morphTo, trigger="state" et active déjà à true rend sa cible sur le serveur : un menu ouvert dès le départ affiche donc le x dans le HTML.

Les états vivants n'ont besoin d'aucune hydratation. Leur CSS se trouve dans le SVG : une animation mount se lance dès que le navigateur analyse le HTML, et une animation hover fonctionne avant le chargement de tout script. Une animation state déjà active est rendue avec sa classe gf-on et se joue elle aussi directement depuis le HTML. Les clics et les changements d'état ultérieurs nécessitent le framework, car c'est lui qui bascule l'attribut et la classe qui lancent les animations. La règle prefers-reduced-motion est livrée dans la même feuille de style et s'applique aussi au balisage rendu côté serveur.

Le balisage est déterministe. Les classes d'animation, les identifiants de masque et les classes de morph sont dérivés d'un hachage de leur contenu, et non de compteurs ou de valeurs aléatoires : le serveur et le navigateur produisent donc les mêmes attributs, et les identifiants ne provoquent jamais d'incohérence d'hydratation.

Le web component sur les pages rendues côté serveur

L'élément glyph-fox se dessine dans un shadow root lorsque son script s'exécute. Il n'utilise pas le shadow DOM déclaratif : le HTML du serveur contient donc un élément vide, sans taille, et la ligne qui l'entoure bouge lorsque l'icône apparaît. Réservez l'espace jusqu'à ce que l'élément soit défini :

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

Pour les icônes au-dessus de la ligne de flottaison, rendez côté serveur du SVG inline avec un composant ou toSvg, et réservez l'élément aux parties de la page qui changent côté client. Le guide des web components décrit l'élément en détail.

E-mails

Le rendu côté serveur aboutit souvent à un template d'e-mail, et c'est le seul cas où les chaînes SVG ne servent à rien : de nombreux clients de messagerie n'affichent ni le SVG inline ni les images SVG. Utilisez plutôt des fichiers PNG dans ce cas. L'explorateur d'icônes permet de télécharger n'importe quelle icône en PNG, à la taille voulue, avec votre couleur et votre épaisseur.

Options de toSvg

toSvg et renderToString acceptent les mêmes props que les composants, sous forme de simples options.

OptionTypePar défautDescription
sizenumber, string24Largeur et hauteur ; les nombres sont en pixels.
colorstringcurrentColorCouleur principale.
secondaryColorstringcolorCouleur du calque duotone et du remplissage plein.
secondaryOpacitynumber0.3 / 1Opacité du calque duotone ou du remplissage plein.
weightnumber2Trait de 1 à 3 sur la grille de 24, avec compensation optique en dessous de 24 px.
absoluteWeightbooleanfalseGarde le trait à weight pixels quelle que soit la taille.
cornersround, sharproundJointures et extrémités arrondies ou vives.
variantoutline, duotone, solidoutlineAxe de style ; solid vient des formes fermées.
rotatenumber0Rotation en degrés.
flipXbooleanfalseMiroir horizontal.
flipYbooleanfalseMiroir vertical.
mirrorRtlbooleanfalseMiroir dans les mises en page de droite à gauche.
animatedraw, pop, wiggle, spin, pulse, bounce, shakeaucunPréréglage d'état vivant.
triggermount, hover, click, statemountMoment où l'animation ou le morph se joue.
activebooleanfalseL'état pour le déclencheur state.
durationnumber (ms)selon le préréglageDurée de l'animation ou du morph.
delaynumber (ms)0Délai de l'animation ou du morph.
loopboolean, numberfalseRépète à l'infini ou un certain nombre de fois (spin et pulse bouclent par défaut).
modifierplus, minus, check, x, alert, lock, clock, sync, arrow-up, arrow-down, dotaucunBadge avec espace de découpe automatique.
modifierCornertop-left, top-right, bottom-left, bottom-rightbottom-rightCoin du badge.
morphToname, dataaucunCible du morph ; le déclencheur décide quand elle s'affiche.
titlestringaucunNom accessible : title, role img et aria-label.
decorativebooleantrue sans titleMasque l'icône aux technologies d'assistance.

Pièges courants

Icônes vides dans le HTML du serveur
Sur le serveur, une icône rendue par son nom mais jamais enregistrée produit un svg vide avec la classe glyphfox-empty. Enregistrez les noms, ou importez le composant de cette icône.
Avertissements d'incohérence d'hydratation
Si le serveur rend un nom dont le navigateur ne dispose pas encore, le balisage diffère lors du premier rendu client. Les causes habituelles sont l'import côté serveur, sans bundler, d'un point d'entrée complet et les noms issus de données. Enregistrez les noms dans du code partagé.
Icônes qui dépendent du navigateur
Une icône choisie d'après localStorage, le schéma de couleurs ou la taille de la fenêtre ne peut pas correspondre côté serveur. Rendez une icône neutre sur le serveur et changez-la après le montage, ou lisez la valeur depuis un cookie accessible au serveur.
Décalage de mise en page dû à l'élément
Un glyph-fox non défini n'a pas de taille. Réservez l'espace avec :not(:defined) ou rendez du SVG inline sur le serveur.
Cibles de morph dans les builds de production
Dans un build de production Vite, les noms ni importés ni enregistrés restent vides dans le navigateur, car le chargeur à la demande situé dans node_modules n'est pas transformé. Le rendu côté serveur ne masque pas ce problème ; enregistrer les noms corrige les deux côtés.

Questions fréquentes

Les composants React fonctionnent-ils dans les React Server Components ?

Pas directement : ils utilisent des hooks et ont donc besoin d'une frontière client. Dans un Server Component, vous pouvez rendre la sortie de toSvg ou de renderToString avec dangerouslySetInnerHTML, sans livrer de JavaScript pour l'icône. Le guide Next.js présente les deux approches.

Pourquoi mon icône est-elle vide dans le HTML du serveur ?

Elle est rendue par son nom, via Icon, morphTo, Fusion ou MorphIcon, et ses données n'étaient pas enregistrées au moment du rendu serveur. Appelez registerIcons avec les exports de données dans un module importé par les deux points d'entrée.

Icônes de ce guide