Publié le 23 novembre 2024
Le développement basé sur des modules offre de réels avantages en termes de mise en cache, ce qui vous permet de réduire le nombre d'octets que vous devez envoyer à vos utilisateurs. La granularité plus fine du code aide également à gérer le chargement, en vous permettant de hiérarchiser le code critique de votre application.
Toutefois, les dépendances de module introduisent un problème de chargement, car le navigateur doit attendre que le module se charge avant de déterminer ses dépendances. Pour contourner ce problème, vous pouvez précharger les dépendances afin que le navigateur connaisse tous les fichiers à l'avance et puisse maintenir la connexion active.
<link rel="preload">
<link rel="preload">
permet de demander des ressources de manière déclarative à l'avance, avant que le navigateur n'en ait besoin.
<head>
<link rel="preload" as="style" href="critical-styles.css">
<link rel="preload" as="font" crossorigin type="font/woff2" href="myfont.woff2">
</head>
Cela fonctionne particulièrement bien avec des ressources telles que les polices, qui sont souvent masquées dans des fichiers CSS, parfois sur plusieurs niveaux. Dans ce cas, le navigateur doit attendre plusieurs aller-retour avant de découvrir qu'il doit récupérer un fichier de police volumineux, alors qu'il aurait pu utiliser ce temps pour lancer le téléchargement et profiter de la bande passante complète de la connexion.
<link rel="preload">
et son équivalent d'en-tête HTTP permettent de signaler immédiatement au navigateur les fichiers critiques qui seront nécessaires dans le cadre de la navigation en cours. Lorsque le navigateur voit le préchargement, il lance un téléchargement prioritaire pour la ressource, de sorte qu'au moment où elle est réellement nécessaire, elle est déjà extraite ou partiellement disponible. Toutefois, cela ne fonctionne pas pour les modules.
Pourquoi <link rel="preload">
ne fonctionne-t-il pas pour les modules ?
C'est là que les choses deviennent délicates. Il existe plusieurs modes d'identifiants pour les ressources. Pour obtenir un cache hit, ils doivent correspondre, sinon vous finirez par récupérer la ressource deux fois. Inutile de dire que la double récupération est mauvaise, car elle gaspille la bande passante de l'utilisateur et le fait attendre plus longtemps, sans raison valable.
Pour les balises <script>
et <link>
, vous pouvez définir le mode d'identifiants avec l'attribut crossorigin
. Toutefois, il s'avère qu'un <script type="module">
sans attribut crossorigin
indique un mode d'identifiants omit
, qui n'existe pas pour <link rel="preload">
. Cela signifie que vous devrez remplacer l'attribut crossorigin
dans vos <script>
et <link>
par l'une des autres valeurs. Vous ne pourrez peut-être pas le faire facilement si ce que vous essayez de précharger est une dépendance d'autres modules.
De plus, l'extraction du fichier n'est que la première étape de l'exécution du code.
Le navigateur doit d'abord l'analyser et le compiler. Idéalement, cela doit également se produire à l'avance, de sorte que lorsque le module est nécessaire, le code soit prêt à s'exécuter. Toutefois, V8 (moteur JavaScript de Chrome) analyse et compile les modules différemment des autres JavaScript. <link rel="preload">
ne fournit aucun moyen d'indiquer que le fichier en cours de chargement est un module. Le navigateur ne peut donc que charger le fichier et le placer dans le cache. Une fois le script chargé à l'aide d'une balise <script type="module">
(ou chargé par un autre module), le navigateur analyse et compile le code en tant que module JavaScript.
<link rel="modulepreload">
n'est-il que <link rel="preload">
pour les modules ?
En résumé, oui. En disposant d'un type link
spécifique pour le préchargement des modules, nous pouvons écrire du code HTML simple sans nous soucier du mode d'identifiants que nous utilisons. Les valeurs par défaut fonctionnent.
<head>
<link rel="modulepreload" href="super-critical-stuff.mjs">
</head>
[...]
<script type="module" src="super-critical-stuff.mjs">
Étant donné que le navigateur sait maintenant que ce que vous préchargez est un module, il peut être intelligent et analyser et compiler le module dès qu'il a terminé la récupération, au lieu d'attendre qu'il essaie de s'exécuter.
Mais qu'en est-il des dépendances des modules ?
C'est amusant que vous posiez cette question. Cet article n'aborde pas la récursion.
La spécification <link rel="modulepreload">
permet en fait de charger facultativement non seulement le module demandé, mais également l'ensemble de son arborescence de dépendances. Les navigateurs n'ont pas besoin de le faire, mais ils peuvent le faire.
Quelle est la meilleure solution multinavigateur pour précharger un module et son arbre de dépendances, car vous aurez besoin de l'arbre de dépendances complet pour exécuter l'application ?
Les navigateurs qui choisissent de précharger les dépendances de manière récursive doivent disposer d'une déduplication robuste des modules. En règle générale, il est donc recommandé de déclarer le module et la liste plate de ses dépendances, et de faire confiance au navigateur pour qu'il n'extraie pas le même module deux fois.
<head>
<!-- dog.js imports dog-head.js, which in turn imports
dog-head-mouth.js, which imports dog-head-mouth-tongue.js. -->
<link rel="modulepreload" href="dog-head-mouth-tongue.mjs">
<link rel="modulepreload" href="dog-head-mouth.mjs">
<link rel="modulepreload" href="dog-head.mjs">
<link rel="modulepreload" href="dog.mjs">
</head>
Le préchargement de modules améliore-t-il les performances ?
Le préchargement peut aider à maximiser l'utilisation de la bande passante en indiquant au navigateur ce qu'il doit extraire afin qu'il ne soit pas bloqué sans rien à faire pendant ces longs aller-retours. Si vous testez des modules et que vous rencontrez des problèmes de performances en raison d'arbres de dépendances profonds, la création d'une liste plate de préchargements peut vous aider.
Toutefois, les performances des modules sont toujours en cours d'élaboration. Veillez donc à examiner attentivement ce qui se passe dans votre application avec les outils pour les développeurs et envisagez de regrouper votre application en plusieurs blocs en attendant. Cependant, de nombreux travaux sur les modules sont en cours dans Chrome. Nous nous rapprochons donc de la fin de l'utilisation des bundles.