Éviter les pièges du code automatiquement en ligne

Publié: 2022-03-10
Résumé rapide ↬ L'utilisation excessive de code CSS ou JS en ligne, par opposition à la diffusion de code via des ressources statiques, peut nuire aux performances du site. Dans cet article, nous apprendrons plutôt à charger du code dynamique via des fichiers statiques, en évitant les inconvénients d'une trop grande quantité de code en ligne.

L'inlining est le processus d'inclusion du contenu des fichiers directement dans le document HTML : les fichiers CSS peuvent être intégrés à l'intérieur d'un élément de style , et les fichiers JavaScript peuvent être intégrés à l'intérieur d'un élément de script :

 <style> /* CSS contents here */ </style> <script> /* JS contents here */ </script>

En imprimant le code déjà dans la sortie HTML, l'inlining évite les requêtes bloquant le rendu et exécute le code avant que la page ne soit rendue. En tant que tel, il est utile pour améliorer la performance perçue du site (c'est-à-dire le temps qu'il faut pour qu'une page devienne utilisable). les styles critiques, y compris les styles de contenu au-dessus de la ligne de flottaison (comme cela avait été fait sur le site précédent de Smashing Magazine), ainsi que les tailles de police et les largeurs et hauteurs de mise en page pour éviter un nouveau rendu de mise en page saccadé lorsque le reste des données est livré .

Cependant, lorsqu'il est exagéré, le code intégré peut également avoir des effets négatifs sur les performances du site : étant donné que le code ne peut pas être mis en cache, le même contenu est envoyé au client à plusieurs reprises et il ne peut pas être pré-mis en cache via les Service Workers, ou mis en cache et accessible à partir d'un réseau de diffusion de contenu. De plus, les scripts en ligne ne sont pas considérés comme sûrs lors de la mise en œuvre d'une politique de sécurité du contenu (CSP). Ensuite, il est judicieux d'intégrer ces parties critiques de CSS et JS qui accélèrent le chargement du site mais évitent autant que possible autrement.

Dans le but d'éviter l'inlining, dans cet article, nous allons explorer comment convertir le code inline en ressources statiques : au lieu d'imprimer le code dans la sortie HTML, nous l'enregistrons sur le disque (créant ainsi un fichier statique) et ajoutons le <script> correspondant <script> ou <link> pour charger le fichier.

Commençons!

Lecture recommandée : WordPress Security As A Process

Plus après saut! Continuez à lire ci-dessous ↓

Quand éviter l'inlining

Il n'y a pas de recette magique pour établir si du code doit être en ligne ou non, cependant, cela peut être assez évident lorsqu'un code ne doit pas être en ligne : lorsqu'il implique un gros morceau de code et qu'il n'est pas nécessaire immédiatement.

Par exemple, les sites WordPress intègrent les modèles JavaScript pour rendre le gestionnaire de médias (accessible dans la page de la bibliothèque multimédia sous /wp-admin/upload.php ), en imprimant une quantité importante de code :

Une capture d'écran du code source de la page de la médiathèque
Modèles JavaScript intégrés par le gestionnaire de médias WordPress.

Occupant 43 Ko, la taille de ce morceau de code n'est pas négligeable, et puisqu'il se trouve au bas de la page, il n'est pas nécessaire immédiatement. Par conséquent, il serait tout à fait logique de servir ce code via des actifs statiques à la place ou de l'imprimer dans la sortie HTML.

Voyons ensuite comment transformer le code inline en actifs statiques.

Déclenchement de la création de fichiers statiques

Si le contenu (ceux à insérer) provient d'un fichier statique, il n'y a pas grand-chose à faire d'autre que simplement demander ce fichier statique au lieu d'incorporer le code.

Pour le code dynamique, cependant, nous devons planifier comment/quand générer le fichier statique avec son contenu. Par exemple, si le site propose des options de configuration (comme changer le jeu de couleurs ou l'image de fond), quand faut-il générer le fichier contenant les nouvelles valeurs ? Nous avons les possibilités suivantes pour créer les fichiers statiques à partir du code dynamique :

  1. Sur demande
    Lorsqu'un utilisateur accède au contenu pour la première fois.
  2. Sur le changement
    Lorsque la source du code dynamique (par exemple, une valeur de configuration) a changé.

Considérons d'abord sur demande. La première fois qu'un utilisateur accède au site, disons via /index.html , le fichier statique (par exemple header-colors.css ) n'existe pas encore, il doit donc être généré ensuite. La séquence des événements est la suivante :

  1. L'utilisateur demande /index.html ;
  2. Lors du traitement de la requête, le serveur vérifie si le fichier header-colors.css existe. Comme ce n'est pas le cas, il obtient le code source et génère le fichier sur disque ;
  3. Il renvoie une réponse au client, y compris la balise <link rel="stylesheet" type="text/css" href="/staticfiles/header-colors.css">
  4. Le navigateur récupère toutes les ressources incluses dans la page, y compris header-colors.css ;
  5. À ce moment-là, ce fichier existe, il est donc servi.

Cependant, la séquence des événements pourrait également être différente, conduisant à un résultat insatisfaisant. Par exemple:

  1. L'utilisateur demande /index.html ;
  2. Ce fichier est déjà mis en cache par le navigateur (ou un autre proxy, ou via Service Workers), de sorte que la requête n'est jamais envoyée au serveur ;
  3. Le navigateur récupère toutes les ressources incluses dans la page, y compris header-colors.css . Cette image n'est cependant pas mise en cache dans le navigateur, la requête est donc envoyée au serveur ;
  4. Le serveur n'a pas encore généré header-colors.css (par exemple, il vient d'être redémarré) ;
  5. Il retournera un 404.

Alternativement, nous pourrions générer header-colors.css non pas lors de la demande /index.html , mais lors de la demande /header-colors.css lui-même. Cependant, comme ce fichier n'existe pas initialement, la requête est déjà traitée comme un 404. Même si nous pourrions le contourner, modifier les en-têtes pour changer le code d'état en 200 et renvoyer le contenu de l'image, c'est une façon terrible de faire les choses, donc nous n'envisagerons pas cette possibilité (nous sommes bien meilleurs que cela !)

Cela ne laisse qu'une seule option : générer le fichier statique après que sa source ait changé.

Création du fichier statique lorsque la source change

Veuillez noter que nous pouvons créer du code dynamique à partir de sources dépendant de l'utilisateur et du site. Par exemple, si le thème permet de modifier l'image d'arrière-plan du site et que cette option est configurée par l'administrateur du site, le fichier statique peut être généré dans le cadre du processus de déploiement. En revanche, si le site permet à ses utilisateurs de changer l'image de fond de leurs profils, alors le fichier statique doit être généré au moment de l'exécution.

En un mot, nous avons ces deux cas :

  1. Paramétrage utilisateur
    Le processus doit être déclenché lorsque l'utilisateur met à jour une configuration.
  2. Configuration du site
    Le processus doit être déclenché lorsque l'administrateur met à jour une configuration pour le site ou avant de déployer le site.

Si nous considérions les deux cas indépendamment, pour le n° 2, nous pourrions concevoir le processus sur n'importe quelle pile technologique de notre choix. Cependant, nous ne voulons pas implémenter deux solutions différentes, mais une solution unique qui puisse traiter les deux cas. Et parce qu'à partir du #1, le processus de génération du fichier statique doit être déclenché sur le site en cours d'exécution, il est alors impératif de concevoir ce processus autour de la même pile technologique sur laquelle le site s'exécute.

Lors de la conception du processus, notre code devra gérer les circonstances spécifiques de #1 et #2 :

  • Gestion des versions
    Le fichier statique doit être accédé avec un paramètre "version", afin d'invalider le fichier précédent lors de la création d'un nouveau fichier statique. Alors que #2 pourrait simplement avoir le même versioning que le site, #1 doit utiliser une version dynamique pour chaque utilisateur, éventuellement enregistrée dans la base de données.
  • Emplacement du fichier généré
    #2 génère un fichier statique unique pour l'ensemble du site (par exemple /staticfiles/header-colors.css ), tandis que #1 crée un fichier statique pour chaque utilisateur (par exemple /staticfiles/users/leo/header-colors.css ).
  • Événement déclencheur
    Alors que pour #1, le fichier statique doit être exécuté lors de l'exécution, pour #2, il peut également être exécuté dans le cadre d'un processus de construction dans notre environnement de staging.
  • Déploiement et diffusion
    Les fichiers statiques de #2 peuvent être intégrés de manière transparente dans le pack de déploiement du site, sans aucun problème ; les fichiers statiques dans #1, cependant, ne le peuvent pas, donc le processus doit gérer des problèmes supplémentaires, tels que plusieurs serveurs derrière un équilibreur de charge (les fichiers statiques seront-ils créés sur 1 serveur uniquement, ou sur tous, et comment ?).

Concevons et mettons en œuvre le processus ensuite. Pour chaque fichier statique à générer, nous devons créer un objet contenant les métadonnées du fichier, calculer son contenu à partir des sources dynamiques et enfin enregistrer le fichier statique sur le disque. Comme cas d'utilisation pour guider les explications ci-dessous, nous allons générer les fichiers statiques suivants :

  1. header-colors.css , avec un peu de style à partir des valeurs enregistrées dans la base de données
  2. welcomeuser-data.js , contenant un objet JSON avec des données utilisateur sous une variable : window.welcomeUserData = {name: "Leo"}; .

Ci-dessous, je décrirai le processus de génération des fichiers statiques pour WordPress, pour lequel nous devons baser la pile sur les fonctions PHP et WordPress. La fonction pour générer les fichiers statiques avant le déploiement peut être déclenchée en chargeant une page spéciale exécutant le shortcode [create_static_files] comme je l'ai décrit dans un article précédent.

Lectures complémentaires recommandées : Making A Service Worker : A Case Study

Représentation du fichier en tant qu'objet

Nous devons modéliser un fichier en tant qu'objet PHP avec toutes les propriétés correspondantes, afin que nous puissions à la fois enregistrer le fichier sur le disque à un emplacement spécifique (par exemple, sous /staticfiles/ ou /staticfiles/users/leo/ ), et savoir comment demander le fichier en conséquence. Pour cela, nous créons une interface Resource renvoyant à la fois les métadonnées du fichier (nom du fichier, répertoire, type : « css » ou « js », version, et dépendances sur d'autres ressources) et son contenu.

 interface Resource { function get_filename(); function get_dir(); function get_type(); function get_version(); function get_dependencies(); function get_content(); }

Afin de rendre le code maintenable et réutilisable, nous suivons les principes SOLID, pour lesquels nous définissons un schéma d'héritage d'objet pour les ressources afin d'ajouter progressivement des propriétés, à partir de la classe abstraite ResourceBase dont toutes nos implémentations Resource hériteront :

 abstract class ResourceBase implements Resource { function get_dependencies() { // By default, a file has no dependencies return array(); } }

Après SOLID, nous créons des sous-classes chaque fois que les propriétés diffèrent. Comme indiqué précédemment, l'emplacement du fichier statique généré et la version pour le demander seront différents selon le fichier concernant la configuration de l'utilisateur ou du site :

 abstract class UserResourceBase extends ResourceBase { function get_dir() { // A different file and folder for each user $user = wp_get_current_user(); return "/staticfiles/users/{$user->user_login}/"; } function get_version() { // Save the resource version for the user under her meta data. // When the file is regenerated, must execute `update_user_meta` to increase the version number $user_id = get_current_user_id(); $meta_key = "resource_version_".$this->get_filename(); return get_user_meta($user_id, $meta_key, true); } } abstract class SiteResourceBase extends ResourceBase { function get_dir() { // All files are placed in the same folder return "/staticfiles/"; } function get_version() { // Same versioning as the site, assumed defined under a constant return SITE_VERSION; } }

Enfin, au dernier niveau, nous implémentons les objets pour les fichiers que nous voulons générer, en ajoutant le nom du fichier, le type de fichier et le code dynamique via la fonction get_content :

 class HeaderColorsSiteResource extends SiteResourceBase { function get_filename() { return "header-colors"; } function get_type() { return "css"; } function get_content() { return sprintf( " .site-title a { color: #%s; } ", esc_attr(get_header_textcolor()) ); } } class WelcomeUserDataUserResource extends UserResourceBase { function get_filename() { return "welcomeuser-data"; } function get_type() { return "js"; } function get_content() { $user = wp_get_current_user(); return sprintf( "window.welcomeUserData = %s;", json_encode( array( "name" => $user->display_name ) ) ); } }

Avec cela, nous avons modélisé le fichier comme un objet PHP. Ensuite, nous devons l'enregistrer sur le disque.

Enregistrement du fichier statique sur le disque

L'enregistrement d'un fichier sur le disque peut être facilement réalisé grâce aux fonctions natives fournies par le langage. Dans le cas de PHP, cela se fait via la fonction fwrite . De plus, nous créons une classe utilitaire ResourceUtils avec des fonctions fournissant le chemin absolu vers le fichier sur disque, ainsi que son chemin relatif à la racine du site :

 class ResourceUtils { protected static function get_file_relative_path($fileObject) { return $fileObject->get_dir().$fileObject->get_filename().".".$fileObject->get_type(); } static function get_file_path($fileObject) { // Notice that we must add constant WP_CONTENT_DIR to make the path absolute when saving the file return WP_CONTENT_DIR.self::get_file_relative_path($fileObject); } } class ResourceGenerator { static function save($fileObject) { $file_path = ResourceUtils::get_file_path($fileObject); $handle = fopen($file_path, "wb"); $numbytes = fwrite($handle, $fileObject->get_content()); fclose($handle); } }

Ensuite, chaque fois que la source change et que le fichier statique doit être régénéré, nous exécutons ResourceGenerator::save en passant l'objet représentant le fichier en paramètre. Le code ci-dessous régénère et enregistre sur disque les fichiers "header-colors.css" et "welcomeuser-data.js":

 // When need to regenerate header-colors.css, execute: ResourceGenerator::save(new HeaderColorsSiteResource()); // When need to regenerate welcomeuser-data.js, execute: ResourceGenerator::save(new WelcomeUserDataUserResource());

Une fois qu'ils existent, nous pouvons mettre en file d'attente les fichiers à charger via les balises <script> et <link> .

Mise en file d'attente des fichiers statiques

La mise en file d'attente des fichiers statiques n'est pas différente de la mise en file d'attente de n'importe quelle ressource dans WordPress : via les fonctions wp_enqueue_script et wp_enqueue_style . Ensuite, nous itérons simplement toutes les instances d'objet et utilisons un hook ou l'autre selon que leur valeur get_type() est "js" ou "css" .

Nous ajoutons d'abord des fonctions utilitaires pour fournir l'URL du fichier et indiquer que le type est JS ou CSS :

 class ResourceUtils { // Continued from above... static function get_file_url($fileObject) { // Add the site URL before the file path return get_site_url().self::get_file_relative_path($fileObject); } static function is_css($fileObject) { return $fileObject->get_type() == "css"; } static function is_js($fileObject) { return $fileObject->get_type() == "js"; } }

Une instance de la classe ResourceEnqueuer contiendra tous les fichiers qui doivent être chargés ; lorsqu'elles sont appelées, ses fonctions enqueue_scripts et enqueue_styles feront la mise en file d'attente, en exécutant les fonctions WordPress correspondantes ( wp_enqueue_script et wp_enqueue_style respectivement) :

 class ResourceEnqueuer { protected $fileObjects; function __construct($fileObjects) { $this->fileObjects = $fileObjects; } protected function get_file_properties($fileObject) { $handle = $fileObject->get_filename(); $url = ResourceUtils::get_file_url($fileObject); $dependencies = $fileObject->get_dependencies(); $version = $fileObject->get_version(); return array($handle, $url, $dependencies, $version); } function enqueue_scripts() { $jsFileObjects = array_map(array(ResourceUtils::class, 'is_js'), $this->fileObjects); foreach ($jsFileObjects as $fileObject) { list($handle, $url, $dependencies, $version) = $this->get_file_properties($fileObject); wp_register_script($handle, $url, $dependencies, $version); wp_enqueue_script($handle); } } function enqueue_styles() { $cssFileObjects = array_map(array(ResourceUtils::class, 'is_css'), $this->fileObjects); foreach ($cssFileObjects as $fileObject) { list($handle, $url, $dependencies, $version) = $this->get_file_properties($fileObject); wp_register_style($handle, $url, $dependencies, $version); wp_enqueue_style($handle); } } }

Enfin, nous instancions un objet de la classe ResourceEnqueuer avec une liste des objets PHP représentant chaque fichier, et ajoutons un hook WordPress pour exécuter la mise en file d'attente :

 // Initialize with the corresponding object instances for each file to enqueue $fileEnqueuer = new ResourceEnqueuer( array( new HeaderColorsSiteResource(), new WelcomeUserDataUserResource() ) ); // Add the WordPress hooks to enqueue the resources add_action('wp_enqueue_scripts', array($fileEnqueuer, 'enqueue_scripts')); add_action('wp_print_styles', array($fileEnqueuer, 'enqueue_styles'));

C'est tout : Etant mis en file d'attente, les fichiers statiques seront demandés lors du chargement du site dans le client. Nous avons réussi à éviter d'imprimer du code en ligne et de charger des ressources statiques à la place.

Ensuite, nous pouvons appliquer plusieurs améliorations pour des gains de performances supplémentaires.

Lecture recommandée : Une introduction aux tests automatisés des plugins WordPress avec PHPUnit

Regrouper des fichiers ensemble

Même si HTTP/2 a réduit le besoin de regrouper des fichiers, il rend toujours le site plus rapide, car la compression des fichiers (par exemple via GZip) sera plus efficace, et parce que les navigateurs (tels que Chrome) ont une plus grande surcharge de traitement de nombreuses ressources .

À ce jour, nous avons modélisé un fichier en tant qu'objet PHP, ce qui nous permet de traiter cet objet comme une entrée pour d'autres processus. En particulier, nous pouvons répéter le même processus ci-dessus pour regrouper tous les fichiers du même type et servir la version groupée au lieu de tous les fichiers indépendants. Pour cela, nous créons une fonction get_content qui extrait simplement le contenu de chaque ressource sous $fileObjects , et l'imprime à nouveau, produisant l'agrégation de tout le contenu de toutes les ressources :

 abstract class SiteBundleBase extends SiteResourceBase { protected $fileObjects; function __construct($fileObjects) { $this->fileObjects = $fileObjects; } function get_content() { $content = ""; foreach ($this->fileObjects as $fileObject) { $content .= $fileObject->get_content().PHP_EOL; } return $content; } }

Nous pouvons regrouper tous les fichiers dans le fichier bundled-styles.css en créant une classe pour ce fichier :

 class StylesSiteBundle extends SiteBundleBase { function get_filename() { return "bundled-styles"; } function get_type() { return "css"; } }

Enfin, nous mettons simplement ces fichiers groupés en file d'attente, comme auparavant, au lieu de toutes les ressources indépendantes. Pour CSS, on crée un bundle contenant les fichiers header-colors.css , background-image.css et font-sizes.css , pour lequel on instancie simplement StylesSiteBundle avec l'objet PHP pour chacun de ces fichiers (et de même on peut créer le JS fichier bundle):

 $fileObjects = array( // CSS new HeaderColorsSiteResource(), new BackgroundImageSiteResource(), new FontSizesSiteResource(), // JS new WelcomeUserDataUserResource(), new UserShoppingItemsUserResource() ); $cssFileObjects = array_map(array(ResourceUtils::class, 'is_css'), $fileObjects); $jsFileObjects = array_map(array(ResourceUtils::class, 'is_js'), $fileObjects); // Use this definition of $fileEnqueuer instead of the previous one $fileEnqueuer = new ResourceEnqueuer( array( new StylesSiteBundle($cssFileObjects), new ScriptsSiteBundle($jsFileObjects) ) );

C'est ça. Maintenant, nous ne demanderons qu'un seul fichier JS et un seul fichier CSS au lieu de plusieurs.

Une dernière amélioration des performances perçues consiste à hiérarchiser les actifs, en retardant le chargement des actifs qui ne sont pas nécessaires immédiatement. Abordons cela ensuite.

async / defer Attributs pour les ressources JS

Nous pouvons ajouter des attributs async et defer à la <script> , pour modifier le moment où le fichier JavaScript est téléchargé, analysé et exécuté, afin de donner la priorité au JavaScript critique et de pousser tout ce qui n'est pas critique le plus tard possible, diminuant ainsi le chargement apparent du site temps.

Pour implémenter cette fonctionnalité, en suivant les principes SOLID, nous devons créer une nouvelle interface JSResource (qui hérite de Resource ) contenant les fonctions is_async et is_defer . Cependant, cela fermerait la porte aux balises <style> supportant éventuellement ces attributs également. Donc, avec l'adaptabilité à l'esprit, nous adoptons une approche plus ouverte : nous ajoutons simplement une méthode générique get_attributes à l'interface Resource afin de la garder flexible pour l'ajouter à n'importe quel attribut (déjà existant ou encore à inventer) pour les deux <script> balises <script> et <link> :

 interface Resource { // Continued from above... function get_attributes(); } abstract class ResourceBase implements Resource { // Continued from above... function get_attributes() { // By default, no extra attributes return ''; } }

WordPress n'offre pas un moyen facile d'ajouter des attributs supplémentaires aux ressources mises en file d'attente, nous le faisons donc de manière plutôt hacky, en ajoutant un crochet qui remplace une chaîne à l'intérieur de la balise via la fonction add_script_tag_attributes :

 class ResourceEnqueuerUtils { protected static tag_attributes = array(); static function add_tag_attributes($handle, $attributes) { self::tag_attributes[$handle] = $attributes; } static function add_script_tag_attributes($tag, $handle, $src) { if ($attributes = self::tag_attributes[$handle]) { $tag = str_replace( " src='${src}'>", " src='${src}' ".$attributes.">", $tag ); } return $tag; } } // Initize by connecting to the WordPress hook add_filter( 'script_loader_tag', array(ResourceEnqueuerUtils::class, 'add_script_tag_attributes'), PHP_INT_MAX, 3 );

Nous ajoutons les attributs d'une ressource lors de la création de l'instance d'objet correspondante :

 abstract class ResourceBase implements Resource { // Continued from above... function __construct() { ResourceEnqueuerUtils::add_tag_attributes($this->get_filename(), $this->get_attributes()); } }

Enfin, si la ressource welcomeuser-data.js n'a pas besoin d'être exécutée immédiatement, nous pouvons alors la définir comme defer :

 class WelcomeUserDataUserResource extends UserResourceBase { // Continued from above... function get_attributes() { return "defer='defer'"; } }

Parce qu'il est chargé en différé, un script se chargera plus tard, avançant le moment où l'utilisateur peut interagir avec le site. Concernant les gains de performances, nous sommes tous prêts maintenant !

Il reste un problème à résoudre avant de pouvoir se détendre : que se passe-t-il lorsque le site est hébergé sur plusieurs serveurs ?

Gérer plusieurs serveurs derrière un équilibreur de charge

Si notre site est hébergé sur plusieurs sites derrière un équilibreur de charge, et qu'un fichier dépendant de la configuration de l'utilisateur est régénéré, le serveur traitant la requête doit, d'une manière ou d'une autre, télécharger le fichier statique régénéré sur tous les autres serveurs ; sinon, les autres serveurs serviront une version obsolète de ce fichier à partir de ce moment. Comment faisons-nous cela? Faire communiquer les serveurs entre eux n'est pas seulement complexe, mais peut finalement s'avérer irréalisable : que se passe-t-il si le site fonctionne sur des centaines de serveurs, de différentes régions ? De toute évidence, ce n'est pas une option.

La solution que j'ai proposée consiste à ajouter un niveau d'indirection : au lieu de demander les fichiers statiques à partir de l'URL du site, ils sont demandés à partir d'un emplacement dans le cloud, par exemple à partir d'un compartiment AWS S3. Ensuite, lors de la régénération du fichier, le serveur téléchargera immédiatement le nouveau fichier sur S3 et le servira à partir de là. La mise en œuvre de cette solution est expliquée dans mon article précédent Partage de données entre plusieurs serveurs via AWS S3.

Conclusion

Dans cet article, nous avons considéré que l'inlining de code JS et CSS n'est pas toujours idéal, car le code doit être envoyé à plusieurs reprises au client, ce qui peut avoir un impact sur les performances si la quantité de code est importante. Nous avons vu, à titre d'exemple, comment WordPress charge 43 Ko de scripts pour imprimer le Media Manager, qui sont de purs modèles JavaScript et pourraient parfaitement être chargés en tant que ressources statiques.

Par conséquent, nous avons conçu un moyen de rendre le site Web plus rapide en transformant le code dynamique JS et CSS en ligne en ressources statiques, ce qui peut améliorer la mise en cache à plusieurs niveaux (dans le client, Service Workers, CDN), permet de regrouper davantage tous les fichiers ensemble en une seule ressource JS/CSS afin d'améliorer le rapport lors de la compression de la sortie (comme via GZip) et d'éviter une surcharge dans les navigateurs du traitement simultané de plusieurs ressources (comme dans Chrome), et permet en outre d'ajouter des attributs async ou defer à la <script> pour accélérer l'interactivité de l'utilisateur, améliorant ainsi le temps de chargement apparent du site.

Comme effet secondaire bénéfique, le fractionnement du code en ressources statiques permet également au code d'être plus lisible, traitant des unités de code au lieu de gros blobs de HTML, ce qui peut conduire à une meilleure maintenance du projet.

La solution que nous avons développée a été réalisée en PHP et comprend quelques morceaux de code spécifiques pour WordPress, cependant, le code lui-même est extrêmement simple, à peine quelques interfaces définissant des propriétés et des objets implémentant ces propriétés selon les principes SOLID, et une fonction pour enregistrer un fichier sur disque. C'est à peu près tout. Le résultat final est propre et compact, simple à recréer pour n'importe quel autre langage et plate-forme, et facile à introduire dans un projet existant, offrant des gains de performances faciles.