Réaction du fractionnement du code en 2019

C'est 2019! Tout le monde pense connaître le fractionnement de code. Alors - revérifions!



Que signifie le fractionnement de code?


En bref, le fractionnement de code consiste à ne pas charger tout. Ensuite, vous lisez cette page, vous n'avez pas à charger un site entier. Lorsque vous sélectionnez une seule ligne dans une base de données, vous n'avez pas à tout prendre.
Évident? Le fractionnement de code est également assez évident, pas seulement pour vos données, mais pour votre code.


Qui (quoi?) Fait le fractionnement de code?


React.lazy ? Non - il l'utilise seulement. Le fractionnement du code se fait au niveau du bundler - webpack, parcelle ou simplement votre système de fichiers dans le cas des modules esm "natifs". Le fractionnement de code n'est que des fichiers, des fichiers que vous pouvez charger quelque part "plus tard". Donc - aux questions " Qu'est-ce que le découpage du code? " - la réponse est - un "bundler".


Qui (quoi) utilise le fractionnement de code?


React.lazy utilise. Il suffit d'utiliser le fractionnement de code de votre bundler. J'appelle juste import une fois rendu. Et c'est tout.


Qu'en est-il de React-loadable?


React.lazy remplacé. Et fourni plus de fonctionnalités, comme Suspense pour contrôler l'état de chargement. Donc, utilisez plutôt React.Lazy .


Oui, c'est tout. Merci d'avoir lu et bonne journée.

Pourquoi l'article n'est pas fini?


Et bien. Il y a quelques zones grises sur React.lazy et le fractionnement de code que j'ai oublié de mentionner.


Zone grise 1 - test


Il n'est pas facile de tester React.lazy raison de son asynchroniosité . Ce serait juste "vide", tant qu'il n'est pas encore chargé (même si c'est le cas) - Les Promises et import retours d' import , et les paresseux acceptent, les promesses , qui ont toujours été exécutées dans la case suivante .


Solution proposée? Vous ne le croiriez pas, mais la solution proposée est d'utiliser des éléments synchrones - Voir la demande de pull . Alors - permet de rendre nos imports SYNCHRONES !!! (pour corriger le problème paresseux pour les tests, ou tout autre cas côté serveur)


 const LazyText = lazy(() => ({ then(cb) { cb({default: Text}); // this is "sync" thenable }, })); const root = ReactTestRenderer.create( <Suspense fallback={<Text text="Loading..." />}> <LazyText text="Hi" /> // this lazy is not very lazy </Suspense>, ); 

Il n'est pas difficile de convertir la fonction d'importation en une table synchrone mémorisée.


 const syncImport = (importFn) => { let preloaded = undefined; const promise = importFn().then(module => preloaded = module); // ^ "auto" import and "cache" promise return () => preloaded ? { then: () => preloaded } : promise; // ^ return sync thenable then possible } const lazyImport = isNode ? syncImport : a => a; // ^ sync for node, async for browser const LazyComponent = React.lazy(lazyImport(() => import('./file')); 

Zone grise 2 - SSR


Si vous n'avez PAS besoin de SSR - veuillez continuer à lire l'article!

React.lazy est React.lazy SSR. Mais cela nécessite Suspense pour fonctionner, et Suspense n'est PAS convivial côté serveur .


Il existe 2 solutions:


  • Remplacez Suspense par Fragment, en vous moquant par exemple. Ensuite, utilisez la version modifiée de l' import avec synchronous then pour que les paresseux se comportent également de manière synchrone.
     import React from 'react'; const realLazy = React.lazy; React.lazy = importer => realLazy(syncImport(importer)); React.Suspense = React.Fragment; // :P // ^ React SSR just got fixed :D 

C'est une bonne option, mais ce ne serait pas tout à fait convivial pour le client. Pourquoi? Définissons la 2ème solution possible:


  • Utilisez une bibliothèque spécialisée pour suivre les scripts, les morceaux et les styles utilisés, et chargez-les côté client (en particulier les styles!) Avant l'hydratation React. Ou bien - vous rendriez des trous vides au lieu de vos composants divisés en code. Encore une fois - vous n'avez pas chargé le code que vous venez de fractionner, vous ne pouvez donc pas rendre ce que vous voulez.

Voici les bibliothèques de fractionnement de code


  • Composant universel - la bibliothèque la plus ancienne et toujours maintenable. Il a "inventé" le fractionnement de code en termes de - enseigné Webpack à diviser le code.
  • React-loadable - très populaire, mais une bibliothèque non entretenue. Faire cracher du code est une chose populaire. Les problèmes sont clos, il n'y a donc pas de communauté autour.
  • Composants chargeables - une bibliothèque complète de fonctionnalités, c'est un plaisir à utiliser, avec la communauté la plus active autour.
  • Composant importé - une bibliothèque unique, non liée à Webpack, c'est-à-dire capable de gérer des colis ou des esm.
  • Composant React-async - bibliothèque déjà morte (mais populaire), qui a eu un impact significatif sur tout ce qui concerne le fractionnement de code, la traversée d'arbre React personnalisée et la SSR.
  • Une autre bibliothèque - il y avait beaucoup de bibliothèques, dont beaucoup n'ont pas survécu à l'évolution de Webpack ou de React 16 - je ne les ai pas répertoriées ici, mais si vous connaissez un bon candidat - juste DM moi.

Quelle bibliothèque choisir?


C'est facile - pas réactif - il est lourd, non entretenu et obsolète, même s'il est toujours très populaire. (et merci d'avoir popularisé le fractionnement de code, encore une fois)


Composants chargeables - pourrait être un très bon choix. Il est très bien écrit, activement entretenu et prend tout en charge. Prise en charge des «importations dynamiques complètes», vous permettant d'importer des fichiers en fonction des accessoires fournis, mais donc non typables. Prend en charge Suspense, pourrait donc remplacer React.lazy.


Composant universel - en fait «inventeurs» d'importations dynamiques complètes - ils l'ont implémenté dans Webpack. Et bien d'autres choses à bas niveau - ils l'ont fait. Je dirais - cette bibliothèque est un peu hardcore et un peu moins conviviale. La documentation des composants chargeables est imbattable. Cela vaut la peine sinon d'utiliser cette bibliothèque, alors lisez la documentation - il y a tellement de détails que vous devez savoir ...


Composant importé par React - est un peu étrange. Il est indépendant du bundler, donc il ne casserait jamais (il n'y a rien à casser), fonctionnerait avec Webpack 5 et 55, mais cela a un coût. Alors que les bibliothèques précédentes pendant la SSR ajouteraient tous les scripts utilisés au corps de la page, et vous pourrez charger tous les scripts en parallèle - les noms de fichiers importés ne sont pas connus, et appellera les «importations» d'origine (c'est pourquoi le bundle indépendant) pour charger des morceaux utilisés, mais capable de faire un appel uniquement depuis l'intérieur du paquet principal - de sorte que tous les scripts supplémentaires ne seront chargés qu'après le téléchargement et l'exécution du principal. Ne prend pas en charge les importations dynamiques complètes, comme React.lazy et, par conséquent, typable. Prend également en charge Suspense. Utilise des éléments synchrones sur SSR. Il a également une approche absolument différente pour CSS et un support parfait de rendu de flux.


Il n'y a aucune différence de qualité ou de popularité entre les bibliothèques répertoriées, et nous sommes tous de bons amis - alors choisissez par votre cœur.


Zone grise 3 - rendu hybride


La RSS est une bonne chose, mais, vous savez, difficile. Les petits projets peuvent vouloir avoir un SSR - il y a beaucoup de raisons de l'avoir - mais ils peuvent ne pas vouloir le configurer et le maintenir.


La SSR pourrait être vraiment, vraiment difficile. Essayez Razzle ou optez pour Next.js si vous voulez une victoire rapide.

Donc, la solution la plus simple pour SSR, en particulier pour le SPA simple, serait la pré-rendu. Comme ouvrir votre SPA dans un navigateur et cliquer sur le bouton "Enregistrer". Comme:


  • React-snap - utilise un marionnettiste (alias Chrome sans tête) pour afficher votre page dans un "navigateur" et enregistre un résultat sous forme de page HTML statique.
  • Rendertron - qui fait de même, mais d'une manière différente ( cloud ).

La pré-rendu est "SSR" sans "Serveur". C'est SSR en utilisant un client. Magique! Et travailler hors de la boîte ... ... ... mais pas pour cracher du code.
Donc - vous venez de rendre votre page dans un navigateur, d'enregistrer du HTML et de demander le même chargement. Mais le code spécifique côté serveur (pour collecter tous les morceaux utilisés) n'a pas été utilisé, car il n'y a pas de serveur!



Dans la partie précédente, j'ai souligné les bibliothèques qui sont liées au webpack en termes de collecte d'informations sur les morceaux utilisés - elles ne pouvaient pas du tout gérer le rendu hybride.


La version 2 des composants chargeables (incompatible avec la version 5 actuelle) a été partiellement prise en charge par react-snap. Le soutien a disparu.

Le composant importé par React pourrait gérer ce cas, tant qu'il n'est pas lié au bundler / côté, il n'y a donc pas de différence pour SSR ou hybride, mais uniquement pour react-snap, tant qu'il prend en charge "l'hydratation de l'état", contrairement à rendertron.


Cette capacité de réagir-importé-composant a été trouvée lors de la rédaction de cet article, elle n'était pas connue auparavant - voir l' exemple . C'est assez simple.

Et ici, vous devez utiliser une autre solution, qui est juste perpendiculaire à toutes les autres bibliothèques.


Composant pré-rendu React


Cette bibliothèque a été créée pour une hydratation partielle et pourrait réhydrater partiellement votre application, en gardant le reste encore déshydraté. Et cela fonctionne pour les moteurs de rendu SSR et hybrides sans aucune différence.
L'idée est simple:


  • pendant SSR - rendre le composant, enveloppé avec un <div />
  • sur le client - trouvez ce div et utilisez innerHTML jusqu'à ce que Component soit prêt à remplacer le HTML mort.
  • vous n'avez pas besoin de charger et d'attendre un morceau avec un composant fractionné avant d' hydrate pour ne PAS rendre un trou blanc à la place de celui - ci - utilisez simplement du HTML pré-rendu, qui est absolument égal à celui qu'un vrai composant rendrait, et qui existe déjà - il est livré avec une réponse serveur (ou hydrid).

C'est pourquoi nous devons attendre que tous les morceaux soient chargés avant de s'hydrater - pour correspondre au HTML rendu par le serveur. C'est pourquoi nous pourrions utiliser des morceaux de HTML rendus par le serveur jusqu'à ce que le client ne soit pas prêt - il est égal à celui que nous allons seulement produire.

 import {PrerenderedComponent} from 'react-prerendered-component'; const importer = memoizeOne(() => import('./Component')); // ^ it's very important to keep the "one" promise const Component = React.lazy(importer); // or use any other library with ".prefetch" support // all libraries has it (more or less) const App = () => ( <PrerenderedComponent live={importer()}> {/* ^ shall return the same promise */ } <Component /> {/* ^ would be rendered when a component goes "live" */ } </PrerenderedComponent> ); 

Vous pouvez lire un autre article sur cette technologie . Mais principal ici - il résout le "Flash Of Unloaded Content" dans un autre, pas commun pour les bibliothèques de fractionnement de code . Soyez ouvert à de nouvelles solutions.


TLDR?


  • n'utilisez pas réactif-chargeable, il n'ajouterait aucune valeur valable
  • React.lazy est bon, mais trop simple pour le moment.
  • La SSR est une chose difficile, et vous devez le savoir
  • Le rendu hybride piloté par des marionnettistes est une chose. Parfois, chose encore plus difficile.

Source: https://habr.com/ru/post/fr444402/


All Articles