J'ai rencontré le fractionnement de code il y a très longtemps, en 2008, lorsque Yandex était un peu suspendu, et les scripts Yandex.Direct connectés de manière synchrone au site ont simplement tué ce site. En général, il était normal à cette époque que vos «scripts» soient 10 fichiers que vous connectez dans le seul ordre correct, ce qui (avec différé) fonctionne toujours très bien.
Ensuite, j'ai commencé à travailler activement avec les cartes, et elles sont toujours connectées en tant que scripts externes, bien sûr paresseux. Ensuite, en tant que membre de l'équipe Yandex.Mart, j'ai activement utilisé la fonction d' arborescence ymodules sur le client, qui a fourni le fractionnement de code parfait.
Et puis je suis allé à webpack
et React
, au pays des idiots effrayés qui regardaient require.ensure
comme un bélier à une nouvelle porte, et le font toujours.
Le fractionnement de code n'est pas une fonctionnalité sensationnelle, c'est un must have. La SSR
n'interférerait toujours pas ...

Petite introduction
De nos jours, lorsque les bundles grossissent chaque jour, le fractionnement de code devient plus important que jamais. Au tout début, les gens sont sortis de cette situation simplement en créant des points d’entrée distincts pour chaque page de leur application, ce qui est généralement bien, mais cela ne fonctionnera pas pour SPA.
Puis est venue la fonction require.ensure
, aujourd'hui connue sous le nom d' dynamic import
(juste importation), à travers laquelle vous pouvez simplement demander un module, que vous recevrez un peu plus tard.
La première bibliothèque sur ce cas pour React était téléchargeable , le battage médiatique autour duquel je ne suis toujours pas très clair et qui est déjà mort (il a juste cessé de plaire à l'auteur).
React.lazy
et les composants chargeables (juste @loadable
) seront le choix plus ou moins «officiel», et le choix entre eux est évident:
- React.lazy est complètement incapable de SSR (Server Side Rendering), du mot en général. Même dans les tests, il tombera sans danses spéciales avec un tambourin, comme les "promesses synchrones".
- Un SSR chargeable peut, et tout en prenant en charge Suspense, n'est pas pire que React.Lazy.
En particulier, loadable prend en charge de magnifiques wrappers pour le chargement des bibliothèques (loadable.lib, vous pouvez prendre moment.js dans React renderProp), et aide le webpack côté serveur à collecter une liste des scripts, styles et ressources utilisés pour la prélecture (ce que webpack lui-même ne connaît pas vraiment). En général, lisez la documentation officielle .
SSR
En général, tout le problème est dans le SSR. Pour CSR (Client Side Render), React.lazy ou un petit script de 10 lignes conviendra - ce sera certainement suffisant, et cela n'a aucun sens de connecter une grande bibliothèque externe. Mais sur le serveur, cela ne sera pas suffisant. Et si vous n'avez pas vraiment besoin d'un SSR, vous pouvez ignorer la lecture. Vous n'avez aucun problème qui doit être résolu longtemps et durement.
La RSS est une douleur. Je (en quelque sorte) est l'un des mainteneurs des composants chargeables et c'est juste horrible combien de bogues sortent de différents endroits. Et à chaque mise à jour, le webpack vole encore plus.
SSR + CSS
CSS est une source encore plus importante de problèmes avec les SSR.
Si vous avez des composants stylés - cela ne fait pas trop mal - ils sont livrés avec un transform-stream
qui ajoutera lui-même ce qui est nécessaire au code final. L'essentiel est qu'il doit y avoir une version de SC partout, sinon le focus ne fonctionnera pas - une version de SC ne pourra rien dire d'autre sur elle-même, et SC aime se multiplier (vérifiez votre bundle). Pour être honnête, c'est précisément à cause de cette limitation que la mise au point échoue généralement.
L'émotion C est plus simple - leur adaptateur de styled
crache simplement <style>
devant le composant lui-même, et le problème est résolu. Simple, bon marché et joyeux. En principe, il est très convivial pour les mobiles et optimise considérablement la toute première vue. Mais gâche un peu la seconde. Et personnellement, ma conscience ne me permet pas d'insérer des styles comme ça.
Avec le CSS ordinaire (y compris celui obtenu à partir de diverses bibliothèques CSS-in-JS avec une magie différente), c'est encore plus facile - il y a des informations à leur sujet dans la colonne webpack, et il est "connu" quel CSS doit être connecté.
Ordre de connexion
Ici, le chien s'est enterré. Quand dois-je me connecter?
Le fractionnement de code convivial SSR signifie qu'avant d'appeler ReactDOM.hydrate
vous devez télécharger tous les "composants" qui sont déjà présents dans la réponse du serveur, mais les scripts actuellement chargés sur le client ne peuvent pas se le permettre.
Par conséquent, toutes les bibliothèques offrent un certain rappel qui sera appelé lorsque tout-tout-ce qui doit être chargé, et vous pouvez démarrer le cerveau . C'est le sens du travail des bibliothèques de découpage de codes SSR.
JS peut être chargé à tout moment, et généralement leur liste est ajoutée à la fin du HTML, mais CSS, pour qu'il n'y ait pas de FOUC, doit être ajouté au début.
Toutes les bibliothèques peuvent le faire pour l'ancien renderToString
, et toutes les bibliothèques ne peuvent pas le faire pour renderToNodeStream
.
Peu importe si vous n'avez que JS (cela ne se produit pas) ou SC / Emotion (qui s'ajoutera). Mais - si vous avez "juste CSS" - c'est tout. Soit ils seront à la fin, soit ils devront utiliser renderToString
, ou une autre mise en mémoire tampon, qui fournira un retard TTFB (Time To First Byte) et réduira légèrement le sentiment d'avoir ce SSR en général.
Et bien sûr - tout cela est lié au webpack et d'aucune autre manière. Par conséquent, avec tout le respect que je dois à Greg, l'auteur des composants chargeables, je propose d'envisager d'autres options.
Ensuite, un programme en trois parties, dont l'idée principale est de faire quelque chose qui n'est pas tué et ne dépend pas du bundler.
1. Composant importé par React
React-Imported-Component n'est pas un mauvais "chargeur", avec une interface plus ou moins standard, très similaire aux composants chargeables, qui peuvent SSR pour tout ce qui bouge.
L'idée est très simple.
Pas besoin d' stats.json
, de s'adapter à l'optimisation du webpack (concaténation ou code commun) - il vous suffit de faire correspondre le "label" d'une importation dans la clé du tableau et d'importer à nouveau. Comment cela sera effectué dans le cadre d'un bundle spécifique, combien de fichiers seront réellement téléchargés et d'où n'est pas son problème.
Moins - le début du chargement des morceaux "utilisés" se produit après le chargement du paquet principal, qui stocke le mappage, qui est un peu "plus tard" que dans le cas des composants chargeables, qui ajouteront ces informations directement au HTML.
Oui, avec CCS, cela ne fonctionne en aucune façon à partir du mot.
2. styles utilisés
Mais les styles utilisés ne fonctionnent qu'avec CSS, mais de la même manière que les composants importés par réaction.
- analyse tous les css (dans le répertoire de construction)
- se souvient où la classe est définie
- analyse la sortie renderToNodeStream (ou la réponse
renderToString
) - trouve class = 'XXX', correspond au fichier et le recrache dans la réponse du serveur.
- (enfin, puis téléporte tous ces styles à la tête pour ne pas casser l'hydrate). Les composants de style fonctionnent de la même façon.
Il n'y a pas de retard TTBT, il n'est pas lié au bundler - un conte de fées. Fonctionne comme une montre si les styles sont bien écrits.
React-import-component + used-styles + parcel working example.
Ce n'est pas le bonus le plus évident - sur le serveur, les deux bibliothèques feront "tout ce qui est nécessaire" pendant le démarrage, jusqu'à ce que le serveur express puisse recevoir le premier client, et seront complètement synchronisées à la fois sur le serveur et pendant les tests.
3. composant réactif pré-rendu
Et la bibliothèque ferme le trio de tête, qui fait une "réhydratation partielle" , et le fait de manière si grand-père que je me le demande tout de suite. Elle ajoute vraiment des "divas".
- sur le serveur:
- enveloppe un morceau de bois dans une div avec un "id célèbre"
- sur le client:
- le constructeur du composant trouve sa propre div
- copie son innerHTML avant que React ne le prenne.
- utilise ce code HTML jusqu'à ce que le client soit prêt à l'
hydrate
- techniquement, cela permet d'utiliser le SSR hybride (Rendertron)
const AsyncLoadedComponent = loadable(() => import('./deferredComponent')); const AsyncLoadedComponent = imported(() => import('./deferredComponent')); <PrerenderedComponent live={AsyncLoadedComponent.preload()} // when Promise got resolve - component will go "live" > <AsyncLoadedComponent /> // meanwhile you will see "preexisting" content </PrerenderedComponent>
Ce focus ne fonctionne pas avec les composants chargeables, car il ne revient pas d'une promesse de préchargement . Ceci est particulièrement important pour les bibliothèques comme react-snap (et autres "prerender") qui ont du "contenu" mais qui ne sont pas passées par un "vrai" SSR.

Du point de vue du code, c'est 10 lignes, plus un peu plus pour obtenir des UID SSR-CSR stables en tenant compte de l'ordre aléatoire de chargement et d'exécution du code.
Bonus:
- vous n'avez pas à attendre le «chargement de tous les scripts» avant de démarrer le cerveau - les cerveaux démarreront dès qu'ils seront prêts
- vous n'avez pas du tout à charger de cerveaux, laissant des données SSR (s'il n'y a pas de version SSR, les cerveaux seront toujours chargés). Tout comme au temps jQuery.
- Vous pouvez également implémenter la mise en cache de flux de grands blocs de rendu (théoriquement compatibles avec la suspension) - à nouveau en utilisant le flux de transformation.
- et sérialiser / désérialiser l'état vers / depuis HTML, comme lors de jQuery
En principe, la sérialisation et la désérialisation étaient l'idée principale de créer une bibliothèque pour résoudre le problème de duplication de l'état (photo de l'article sur la SSR). Caching est arrivé plus tard.

Total
Au total, trois approches peuvent changer votre vision de la SSR et du fractionnement de code. Le premier fonctionne avec le découpage de code JS et ne casse pas. Le second fonctionne avec le fractionnement de code CSS et ne se casse pas. Le troisième fonctionne au niveau HTML en simplifiant et en accélérant certains processus, et là encore, il ne casse pas.
Liens vers les bibliothèques:
Articles (en anglais)