Espace tutos dev’ & informatique 🐧

Optimiser les scripts polyfills avec l’attribut nomodule

Publié le
Article sur l'optimisation du chargement des polyfills avec l'attribut nomodule

Introduction

Ah les polyfills ! Ils sont probablement le meilleur moyen de rendre son site compatible avec les navigateurs plus anciens sans y perdre la tête.

Ils sont cependant la cause de ralentissements lors du chargement des pages d’un site internet. En effet, ces scripts doivent être téléchargés et exécutés avant tout code maison, ce qui sur une connexion mobile peut demander plusieurs secondes.

Ces ralentissements sont rapportés dans Google PageSpeed Insights par le message « Évitez d’utiliser de l’ancien code JavaScript dans les navigateurs récents » (soit « Avoid serving legacy JavaScript to modern browsers » en anglais).

Dans cet article, nous allons voir une technique pour empêcher les navigateurs modernes de télécharger les scripts polyfills.

L’attribut nomodule, détecteur du support d’ES6

Logo ECMAScript 6
Le JavaScript nouveau est arrivé


En 2015, la spécification ECMAScript6 (appelée aussi ES6, ECMAScript2015 ou ES2015 selon les gouts) a apporté de grands changements au monde du développement web. Avec une nouvelle syntaxe, le support des classes et la séparation des fichiers en modules facilitant la création de projets d’envergure, il devenait possible de coder des applications à architecture complexe en JavaScript.

Il fallait un moyen pour les sites web de faire appel aux fonctionnalités ES6 lorsque les visiteurs utilisaient un navigateur compatible, et d’utiliser en fallback des scripts classiques quand ce n’était pas le cas. La solution, toujours valide à l’heure actuelle, est concise et élégante :

<!-- JavaScript ES6, chargé par les navigateurs récents -->
<script src="modules.js" type="module">
</script>

<!-- JavaScript classique, chargé par les vieux navigateurs -->
<script src="fallback.js" nomodule />
</script>

Les balises <script> des modules ES6 sont affublées de type="module" qui bloque le chargement par les navigateurs anciens.
Les scripts fallback quant à eux présentent l’attribut nomodule qui empêche le chargement par les navigateurs modernes.

Si vous n’en avez jamais rencontré, sachez que ES6 est assez largement utilisé de nos jours, notamment avec les frameworks JavaScript tels que React. Mozilla propose une bonne documentation pour commencer.

Mais inutile d’étudier ES6 pour le moment. Ce qui nous intéresse avant tout, c’est l’attribut nomodule.

Détournement de l’attribut nomodule pour les polyfills

L’optimisation que nous allons faire avec l’attribut nomodule n’a rien à voir avec le support de ES6. Elle peut être appliquée sur tous les sites internet, qu’ils soient basés sur un CMS tel que WordPress, codés en PHP natif ou simplement en HTML + JavaScript.

Nous allons tout simplement appliquer l’attribut nomodule aux scripts polyfills afin qu’ils ne soient chargés que par les vieux navigateurs (ceux ne supportant pas ES6) :

<!-- Polyfill chargé uniquement par les vieux navigateurs -->
<script src="polyfills.js" nomodule>
</script>

Pour s’assurer que tout se passe bien, il est important de savoir quels sont les navigateurs qui chargeront les polyfills possédant cet attribut. Pas de souci de ce côté, il y a une bonne documentation sur le net, comme par exemple le site caniuse.

Support de l'attribut nomodule par les navigateurs
Seuls les navigateurs en rouge chargeront les scripts avec l’attribut nomodule (source : caniuse.com)


Connaitre les versions des navigateurs c’est une chose, mais ça ne donne pas une idée claire de leur ancienneté. Voici un récapitulatif des dates des navigateurs qui téléchargent les scripts dotés de l’attribut nomodule.

Logo Internet ExplorerLogo MsEdgeLogo FirefoxLogo ChromeLogo SafariLogo AppleLogo Android
Tous
≤ 2015
≤ 15
≤ 2017
≤ 59
≤ 2018
≤ 60
≤ 2017
≤ 10.1
≤ 2017
≤ 10.3
≤ 2017
≤ 4.4.4
≤ 2016
Détails des années des navigateurs chargeant les scripts nomodule

 

Faut-il polyfiller pour tous les anciens navigateurs ?

Les navigateurs web qui ne sont pas liés au système d’exploitation (Chrome, Firefox) sont souvent plus à jour que ceux qui en font partie (Safari macOS + iOS). Il est en effet plus facile pour l’utilisateur de mettre à jour son logiciel de navigation plutôt que son appareil en entier.

On aura donc tendance à polyfiller pour les vieux navigateurs intégrés (Internet Explorer, Edge, Safari) en se souciant moins des versions particulières des navigateurs externes (Chrome 60 par exemple). Cette approche n’est pas idéale si un site doit supporter parfaitement tous les vieux navigateurs, mais si la demande consiste à supporter les navigateurs récents ainsi que Edge et IE11, alors l’utilisation de nomodule est très efficace.

Exemple pratique : polyfiller la fonction fetch()

En Javascript la fonction fetch() est un peu la version récente des requêtes AJAX XmlHttpRequest. Elle permet d’effectuer des requêtes asynchrones depuis le navigateur vers le serveur, et de récupérer la réponse :

fetch("ajaxlogin.php", {
  method : "POST",
  headers: {
    "Content-Type": "application/json"
  },
  body : JSON.stringify({ login : "nom", pass : "mdp" })
})
.then(function(response){ console.log(response) })
.catch(function(error){ console.log(error) }); 

Les appels à la fonction fetch() sont plus lisibles que l’utilisation de XmlHttpRequest, et ne nécessitent pas le chargement d’une librairie tierce comme jQuery. L’utilisation de cette fonction plutôt que du AJAX oldschool est recommandée.

Le seul problème, c’est que cette fonction n’est disponible que dans les navigateurs qui supportent ES6. Exit donc Internet Explorer et les anciens Edge, comme l’indique la documentation sur le support de fetch(). Plus précisemment, la fonction est absente chez :

  • Tous les Internet Explorer, et Edge jusqu’à la version 13, incluse
  • Firefox jusqu’à la version 39, et Chrome jusqu’à 41
  • Safari jusqu’à macOS 10, et iOS 10.2

Plusieurs polyfills existent pour cette fonction, dont celui-ci recommandé par Mozilla.

Comment utiliser le polyfill sans ralentir le chargement du site dans les navigateurs les plus récents ? On peut faire appel à l’attribut nomodule ! Une comparaison du support de la fonction fetch() avec le tableau du support de nomodule nous indique que les versions sont compatibles.

Tout ce que nous avons à faire est d’ajouter l’attribut nomodule et le tour est joué :

<!-- Polyfill fetch() uniquement sur les vieux navigateurs -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/fetch/3.6.2/fetch.min.js" nomodule>
</script>

Note : pour utiliser pleinement fetch(), il faudra de la même façon polyfiller les Promise

Conclusion

Vous savez maintenant charger des polyfills pour les anciens navigateurs sans impacter les navigateurs récents. Un plus non-négligeable si votre site doit supporter de vieilles machines tout en ayant un score élevé dans Google PageSpeed Insights !

Il faut tout de même faire attention aux versions. On a vite fait de placer nomodule à chaque fois que l’on utilise un polyfill, et on finit par se retrouver avec des navigateurs ni-anciens ni-récents qui ne disposent pas de la fonctionnalité souhaitée mais ne sont pas non plus polyfillés, ce qui cause des erreurs inattendues.

Comme d’habitude, si vous avez besoin d’une assistance pour optimiser votre site internet en conservant sa compatibilité, n’hésitez pas à me contacter.

Bon code à vous, à la prochaine.

Partagez cet article  =>