Aujourd'hui, nous publions la deuxième partie de la traduction du matériel, qui est consacrée à l'utilisation des modules JS dans la production.

→ Au fait, voici la
première partie de l' article.
Importation dynamique
L'un des inconvénients de l'utilisation d'expressions d'importation réelles pour séparer le code et charger les modules est que la tâche de travailler avec des navigateurs qui ne prennent pas en charge les modules incombe au développeur.
Et si vous souhaitez utiliser des commandes dynamiques
import()
pour organiser le chargement de code paresseux, vous devrez, entre autres, faire face au fait que certains navigateurs, bien que, très certainement,
les modules de support , ne prennent toujours
pas en charge les commandes dynamiques import () (Edge 16–18, Firefox 60–66, Safari 11, Chrome 61–63).
Heureusement, ce problème nous aidera à résoudre un
polyfill petit (environ 400 octets) et extrĂŞmement rapide.
L'ajout de ce polyfill à un projet Web est très simple. Il vous suffit de l'importer et de l'initialiser au point d'entrée principal de l'application (avant d'appeler l'une des commandes
import()
du code):
import dynamicImportPolyfill from 'dynamic-import-polyfill';
Et la dernière chose à faire pour que ce schéma fonctionne, est de dire à Rollup qu'il doit renommer les commandes dynamic
import()
qui apparaissent dans le code en utilisant le nom que vous
choisissez (via l'option
output.dynamicImportFunction ). Un polyfill qui implémente la fonction d'importation dynamique utilise le nom
__import__
par défaut, mais il peut être
personnalisé .
La raison pour laquelle vous devez renommer
import()
expressions
import()
est que l'
import
est, en JavaScript, un mot-clé. Cela signifie qu'il est impossible, par polyfill, d'organiser le remplacement de la commande standard
import()
par une commande du mĂŞme nom. Si vous essayez de faire cela, une erreur de syntaxe se produira.
Mais c'est très bien que Rollup renomme les commandes lors de la construction du projet, car cela signifie que vous pouvez utiliser des commandes standard dans le code source. De plus, à l'avenir, lorsque le polyfill ne sera plus nécessaire, le code source du projet n'aura pas à être réécrit, changeant pour
import
ce qui était précédemment nommé d'une manière ou d'une autre.
Chargement efficace de JavaScript
Chaque fois que vous utilisez la séparation de code, cela ne fait pas de mal d'organiser le préchargement de tous les modules dont vous savez qu'ils seront chargés très prochainement (par exemple, ce sont tous les modules dans l'arborescence des dépendances du module principal, qui est le point d'entrée du projet).
Mais lorsque nous chargeons de vrais modules JavaScript (via
<script type="module">
puis via les commandes d'
import
correspondantes), nous devons utiliser l'attribut
modulepreload au lieu du
préchargement habituel, qui est destiné uniquement aux scripts classiques.
<link rel="modulepreload" href="/modules/main.XXXX.mjs"> <link rel="modulepreload" href="/modules/npm.pkg-one.XXXX.mjs"> <link rel="modulepreload" href="/modules/npm.pkg-two.XXXX.mjs"> <link rel="modulepreload" href="/modules/npm.pkg-three.XXXX.mjs"> <!-- ... --> <script type="module" src="/modules/main.XXXX.mjs"></script>
En fait, la
modulepreload
est nettement meilleure que le mécanisme de
preload
traditionnel dans la précharge de vrais modules. Le fait est que lorsque vous l'utilisez, ce n'est pas seulement que le fichier est téléchargé. De plus, il démarre immédiatement, en dehors du thread principal, l'analyse et la compilation du script. Un
preload
régulier ne peut pas faire cela car il ne sait pas, lors du préchargement, si le fichier sera utilisé comme module ou comme script normal.
Cela signifie que le chargement des modules Ă l'aide de l'attribut
modulepreload
souvent plus rapide et que lorsque les modules sont initialisés, il est moins susceptible de créer une charge excessive sur le thread principal, ce qui provoque des problèmes d'interface.
Création d'une liste de modules pour le préchargement
Le fragment d'entrée dans l'objet
bundle Rollup contient une liste complète des importations dans leurs arborescences de dépendances statiques. Par conséquent, dans le hook Rollup
generateBundle , il est facile d'obtenir une liste de fichiers qui doivent être préchargés.
Bien que des plugins puissent être trouvés dans npm pour générer des listes de préchargement de module, la création d'une liste similaire pour chaque point d'entrée dans l'arborescence des dépendances ne nécessite que quelques lignes de code. Par conséquent, je préfère créer ces listes manuellement, en utilisant quelque chose comme ce code:
{ generateBundle(options, bundle) {
Voici, par exemple, comment j'ai créé une
liste de
chargement de
module pour
philipwalton.com et pour mon
application de démonstration , dont nous parlerons ci-dessous.
Veuillez noter que bien que l'attribut
modulepreload
nettement meilleur que le
preload
classique pour le chargement des scripts de module, il a la pire prise en charge du navigateur (actuellement, seul Chrome le prend en charge). Si une partie importante de votre trafic ne provient pas de Chrome, dans votre cas, il peut ĂŞtre judicieux d'utiliser la
preload
régulière au lieu de la
preload
du
preload
.
Concernant l'utilisation de la
preload
, je voudrais vous avertir de quelque chose. Le fait est que lors du chargement de scripts Ă l'aide du
preload
, contrairement au
modulepreload
, ces scripts n'entrent pas dans la carte du module du navigateur. Cela signifie qu'il est possible que les demandes de préchargement puissent être exécutées plusieurs fois (par exemple, si le module importe le fichier avant que le navigateur ait fini de le précharger).
Pourquoi déployer de vrais modules en production?
Si vous utilisez déjà un bundler comme
webpack , ainsi que si vous utilisez déjà le fractionnement de code et le préchargement des fichiers correspondants (similaire à ce que je viens de dire), alors vous vous demandez peut-être si vous devez passer à une stratégie concentré sur l'utilisation de vrais modules. Il y a plusieurs raisons qui me font croire que vous devriez envisager de passer aux modules. De plus, je pense qu'il est préférable de convertir un projet en modules réels que d'utiliser des scripts classiques avec leur propre code conçu pour charger des modules.
▍ Réduire la quantité totale de code
Si le projet utilise de vrais modules, les utilisateurs de navigateurs modernes n'auront pas à télécharger de code supplémentaire conçu pour charger des modules ou pour gérer les dépendances. Par exemple, lorsque vous utilisez de vrais modules, vous n'aurez pas besoin de charger
les mécanismes d'exécution et le manifeste du webpack .
▍ Code de précharge amélioré
Comme mentionné dans la section précédente, l'utilisation de l'attribut
modulepreload
permet de charger du code, de l'
modulepreload
et de le compiler en dehors du thread principal. Tout le reste, par rapport Ă l'attribut de
preload
, reste le même. Cela signifie que grâce au
modulepreload
pages deviennent interactives plus rapidement, et cela réduit la probabilité de bloquer le flux principal pendant l'interaction avec l'utilisateur.
Par conséquent, quelle que soit la taille du code d'application divisé en fragments, il sera beaucoup plus productif de télécharger ces fragments à l'aide des commandes d'importation et de l'attribut
modulepreload
que de les charger Ă l'aide de la balise de
script
habituelle et de l'attribut de
preload
habituel (surtout si les balises correspondantes sont générées dynamiquement et ajouté au DOM lors de l'exécution).
En d'autres termes, un bundle de cumul de code de projet, composé de 20 fragments de module, se chargera plus rapidement qu'un bundle du même projet, composé de 20 fragments de script classiques préparés par webpack (non pas à cause de l'utilisation de webpack, mais parce que que ce ne sont pas de vrais modules).
▍ Améliorer l'orientation future du code
De nombreuses nouvelles fonctionnalités des navigateurs sont basées sur des modules et non sur des scripts classiques. Cela signifie que si vous prévoyez d'utiliser ces fonctionnalités, votre code doit être présenté sous la forme de vrais modules. Cela ne devrait pas être quelque chose de transpilé dans ES5 et chargé avec les moyens de la balise de
script
classique (c'est le problème que j'ai écrit lorsque j'ai essayé d'utiliser l'
API expérimentale de
stockage KV ).
Voici quelques-unes des nouvelles fonctionnalités de navigateur les plus intéressantes qui se concentrent exclusivement sur les modules:
Prise en charge du navigateur hérité
À l'échelle mondiale,
plus de 83% des navigateurs prennent en charge les modules JavaScript (y compris l'importation dynamique), par conséquent, la plupart des utilisateurs pourront travailler avec un projet qui est passé à des modules sans aucun effort particulier de la part des développeurs de ce projet.
Dans le cas des navigateurs qui prennent en charge les modules mais ne prennent pas en charge l'importation dynamique, il est recommandé d'utiliser le
polyfill dynamic-import-polyfill décrit ci-dessus. Puisqu'il est très petit et, si possible, utilise la méthode standard
import()
navigateur
import()
, l'utilisation de ce polyfill n'a presque aucun effet sur la taille ou les performances du projet.
Si nous parlons de navigateurs qui ne supportent absolument pas les modules, alors, pour organiser le travail avec eux, vous pouvez utiliser le
modèle module / nomodule .
â–ŤExemple de fonctionnement
Puisqu'il est toujours plus facile de parler de compatibilité entre navigateurs que de la réaliser, j'ai créé une
application de démonstration qui utilise les technologies décrites ci-dessus.
Cette application fonctionne dans les navigateurs comme Edge 18 et Firefox ESR, qui ne prennent pas en charge
import()
commandes d'
import()
dynamique
import()
. De plus, il fonctionne dans des navigateurs comme Internet Explorer 11, qui ne prennent pas en charge les modules.
Afin de montrer que la stratégie discutée ici convient non seulement aux projets simples, j'ai utilisé de nombreuses fonctionnalités dans cette application qui sont nécessaires aujourd'hui dans les grands projets:
- Transformation de code Ă l'aide de Babel (y compris JSX).
- Dépendances CommonJS (par exemple react et react-dom).
- Dépendances CSS.
- Hachage de ressources
- Séparation de code
- Importation dynamique (avec un repli comme polyfill).
- Implémentation du modèle module / nomodule.
Le code du projet peut être trouvé sur
GitHub (c'est-à -dire que vous pouvez bifurquer le référentiel et construire le projet vous-même), la version de démonstration est hébergée sur
Glitch , ce qui vous permet de l'expérimenter.
La chose la plus importante dans le projet de démonstration est la
configuration Rollup , car elle détermine la façon dont les modules résultants sont créés.
Résumé
J'espère que ce matériel vous a convaincu non seulement de la possibilité de déployer des modules JavaScript standard en production, mais aussi qu'il peut vraiment améliorer le temps de chargement du site et ses performances.
Voici un bref aperçu des étapes à suivre pour implémenter les modules dans le projet:
- Utilisez un bundler, parmi les formats de sortie pris en charge par lesquels il existe des modules ES2015.
- Approchez de manière agressive la séparation du code (si possible, jusqu'à l'allocation des dépendances de
node_modules
en fragments séparés). - Préchargez tous les modules qui se trouvent dans votre arborescence de dépendances statiques (en utilisant
modulepreload
). - Utilisez polyfill pour les navigateurs qui ne prennent pas en charge
import()
instructions import()
dynamiques. - Utilisez le modèle de module / nomodule pour organiser le travail avec les navigateurs qui ne prennent pas en charge les modules.
Si vous utilisez déjà Rollup pour construire le projet, je voudrais que vous essayiez de ce dont je parlais ici et que vous alliez déployer de vrais modules en production (en utilisant des techniques de séparation de code et d'importation dynamique). Si vous le faites,
faites-moi savoir comment vous allez. Je suis intéressé à connaître les problèmes et les cas réussis d'introduction de modules.
Il est très clair que les modules sont l’avenir de JavaScript. J'aimerais voir, et de préférence bientôt, comment les outils que nous utilisons et les bibliothèques auxiliaires adoptent cette technologie. J'espère que ce matériel pourra au moins aider un peu ce processus.
Chers lecteurs! Utilisez-vous des modules JS en production?
