Éviter les pièges d'un code automatiquement intégré
À propos de l'auteur
Leonardo Losoviz est le créateur de PoP un framework pour la construction de sites Web modulaires basés sur PHP et les guidons, et optimisé par WordPress. Il habite à Kuala…
En savoir plus sur Leonardo
Une utilisation excessive du code CSS ou JS en ligne, par opposition à la fourniture de code via des ressources statiques, peut nuire aux performances du site. Dans cet article, nous allons apprendre à charger du code dynamique via des fichiers statiques, en évitant les inconvénients liés à une surcharge de code en ligne.
L'insertion est le processus consistant à inclure le contenu des fichiers directement dans le document HTML: les fichiers CSS peuvent être insérés dans un élément de style
et les fichiers JavaScript peuvent être insérés dans un script
. element:
En imprimant le code déjà dans la sortie HTML, l'inlining évite les requêtes de blocage du rendu et exécute le code avant le rendu de la page. En tant que tel, il est utile pour améliorer les performances perçues du site (c.-à-d. Le temps nécessaire pour qu'une page devienne utilisable.) Par exemple, nous pouvons utiliser le tampon de données livré immédiatement lors du chargement du site. (environ 14 Ko) pour intégrer les styles critiques y compris les styles de contenu au-dessus du pli (comme avait été créé sur le site précédent de Smashing Magazine ), ainsi que la taille et la largeur des polices et hauteurs pour éviter un re-rendu saccadé de la présentation lorsque le reste des données est fourni.
Toutefois, lorsqu'il est trop utilisé, le code en ligne peut également avoir des effets négatifs sur les performances du site: Comme le code n'est pas en cache, le même le contenu est envoyé au client à plusieurs reprises et il ne peut pas être pré-mis en cache par le biais de Service Workers, ni mis en cache et accessible à partir d'un réseau de distribution de contenu. En outre, les scripts en ligne sont considérés comme non sécurisés lors de la mise en œuvre d'une stratégie de sécurité du contenu (CSP). Il constitue ensuite une stratégie judicieuse pour intégrer les parties critiques de CSS et de JS qui accélèrent le chargement du site, tout en évitant le plus possible sinon.
Dans le but d’éviter l’insertion, dans cet article, nous verrons comment convertir en ligne. code en ressources statiques: au lieu d’imprimer le code dans la sortie HTML, nous l’enregistrons sur le disque (ce qui crée effectivement un fichier statique) et ajoutons la balise ou
correspondante pour charger le fichier.
Commençons. !
Lectures recommandées : La sécurité de WordPress en tant que processus
Quand éviter l'inline
Il n'y a pas de recette magique pour déterminer si un code doit être en ligne ou non, cependant, cela peut être assez évident quand un code ne doit pas être en ligne: quand il implique une grande quantité de code et quand il n'est pas nécessaire immédiatement. Les sites WordPress insèrent les modèles JavaScript pour rendre le Media M anager (accessible sur la page de la médiathèque sous / wp-admin/upload.php
), en train d’imprimer une quantité appréciable de code:

Déclencher la création de fichiers statiques [19659017] Si le contenu (celui à aligner) provient d’un fichier statique, il n’ya pas grand chose à faire à part demander simplement ce fichier statique au lieu d’inclure le code.
Pour le code dynamique, il faut cependant planifier comment. / Quand générer le fichier statique avec son contenu. Par exemple, si le site propose des options de configuration (telles que la modification du jeu de couleurs ou de l'image d'arrière-plan), quand le fichier contenant les nouvelles valeurs doit-il être généré? Nous avons les possibilités suivantes pour créer les fichiers statiques à partir du code dynamique:
- Sur demande Lorsqu'un utilisateur accède au contenu pour la première fois:
- Lors du changement Lorsque le code source est source ( 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, par exemple via /index.html
le fichier statique (par exemple header-colors.css
) n'existe pas encore, il doit donc l'être généré alors. La séquence d'événements est la suivante:
- L'utilisateur demande
/index.html
;
- Lors du traitement de la demande, le serveur vérifie si le fichier
header-colors.css
existe. Comme il ne le fait pas, il obtient le code source et génère le fichier sur le disque;
- Il renvoie une réponse au client, y compris tag
- Le navigateur récupère toutes les ressources incluses dans la page, y compris
header-colors.css
;
- À ce moment-là, ce fichier existe et est donc affiché.
Toutefois, la séquence des événements peut également être différente, ce qui conduit à un résultat peu satisfaisant. Par exemple:
- L'utilisateur demande
/index.html
;
- Ce fichier est déjà mis en cache par le navigateur (ou par un autre proxy, ou par l'intermédiaire du Service Workers). La demande n'est donc jamais envoyée à le serveur
- Le navigateur récupère toutes les ressources incluses dans la page, y compris
header-colors.css
. Cependant, cette image n'étant pas cachée dans le navigateur, la demande est envoyée au serveur;
- Le serveur n'a pas encore généré
header-colors.css
(par exemple, il vient d'être redémarré);
- Il retournera un 404.
Sinon, nous pourrions générer header-colors.css
non lorsque vous demandez /index.html
mais lorsque vous demandez / header -colors.css
lui-même. Cependant, comme ce fichier n’existait pas au départ, la demande est déjà traitée comme un 404. Même si nous pouvions le contourner, modifier les en-têtes pour changer le code de statut en 200 et renvoyer le contenu de l’image, c'est une façon terrible de faire les choses, donc nous n'allons pas envisager cette possibilité (nous sommes bien meilleurs que cela!)
Cela ne laisse qu'une option: générer le fichier statique après que sa source ait changé.
Création de la statique Fichier lorsque la source change
Veuillez noter que nous pouvons créer du code dynamique à partir de sources dépendantes 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. D'autre part, si le site permet à ses utilisateurs de modifier l'image d'arrière-plan de leurs profils, le fichier statique doit être généré à l'exécution.
En résumé, nous avons les deux cas suivants:
- User Configuration . ] Le processus doit être déclenché lorsque l'utilisateur met à jour une configuration.
- 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 avons considéré les deux cas indépendamment, pour # 2 nous pourrions concevoir le processus sur n’importe quelle pile de technologie que nous voulions. Cependant, nous ne souhaitons pas implémenter deux solutions différentes, mais une solution unique pouvant traiter les deux cas. Et comme à partir de # 1, le processus de génération du fichier statique doit être déclenché sur le site en cours d'exécution, il est donc impératif de concevoir ce processus autour de la même technologie que celle utilisée par le site.
Lors de la conception du processus, notre code devra pour gérer les circonstances spécifiques des numéros 1 et 2:
- Gestion des versions Vous devez accéder au fichier statique 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.
- L'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
).
- Evénement déclencheur Alors que pour le fichier n ° 1, le fichier statique doit être exécuté à l'exécution, pour le fichier n ° 2, il peut également être exécuté dans le cadre d'un processus de construction de notre environnement intermédiaire.
- Déploiement et distribution [19659027] Les fichiers statiques du n ° 2 peuvent être intégrés de manière transparente à l'ensemble de déploiement du site, sans aucun problème. Toutefois, les fichiers statiques n ° 1 ne le peuvent pas. Le processus doit donc 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 un seul serveur ou sur tous, et comment?). 19659061] Nous allons ensuite concevoir et mettre en œuvre le processus. Pour chaque fichier statique à générer, vous devez 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 exemple d'utilisation pour guider les explications ci-dessous, nous allons générer les fichiers statiques suivants:
-
header-colors.css
avec un style issu des valeurs enregistrées dans la base de données
-
welcomeuser data.js
contenant un objet JSON avec des données utilisateur sous une variable: window.welcomeUserData = {name: "Leo"};
.
Nous décrivons ci-dessous le processus permettant de générer le fichiers statiques pour WordPress, pour lesquels nous devons baser la pile sur les fonctions PHP et WordPress. La fonction permettant de générer les fichiers statiques avant le déploiement peut être déclenchée en chargeant une page spéciale exécutant un shortcode [create_static_files]
comme je l'ai décrit dans un article précédent .
Autres lectures recommandées : Créer un service ouvrier: une étude de cas
Représenter le fichier sous forme d'objet
Nous devons modéliser un fichier sous la forme d'un objet PHP avec toutes les propriétés correspondantes afin de pouvoir le sauvegarder sur le disque à un emplacement spécifique. (par exemple sous / staticfiles /
ou / staticfiles / users / leo /
), et savent comment demander le fichier en conséquence. Pour cela, nous créons une interface Ressource
renvoyant à la fois les métadonnées du fichier (nom du fichier, répertoire, type: "css" ou "js", version et dépendances d'autres ressources) et son contenu. Interface
Ressource {
fonction get_filename ();
fonction get_dir ();
fonction get_type ();
fonction get_version ();
fonction get_dependencies ();
fonction get_content ();
}
Afin de rendre le code maintenable et réutilisable, nous suivons les principes SOLID pour lesquels nous avons défini un schéma d'héritage d'objet pour que les ressources ajoutent progressivement des propriétés, à partir de la classe abstraite ResourceBase
de laquelle hériteront toutes les implémentations de nos ressources:
la classe abstraite ResourceBase implémente Resource {
fonction get_dependencies () {
// Par défaut, un fichier n'a pas de dépendances
retourne un tableau ();
}
}
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 le contrôle de version qui le demandera seront différents selon que le fichier concerne l'utilisateur ou la configuration du site:
la classe abstraite UserResourceBase étend la base de ressources {
fonction get_dir () {
// Un fichier et un dossier différent pour chaque utilisateur
$ user = wp_get_current_user ();
return "/ staticfiles / users / {$ user-> user_login} /";
}
fonction get_version () {
// Sauvegarde la version de la ressource pour l'utilisateur sous ses métadonnées.
// Lorsque le fichier est régénéré, vous devez exécuter `update_user_meta` pour augmenter le numéro de version.
$ user_id = get_current_user_id ();
$ meta_key = "version_ressources _". $ this-> get_filename ();
return get_user_meta ($ user_id, $ meta_key, true);
}
}
la classe abstraite SiteResourceBase étend la base de données {
fonction get_dir () {
// Tous les fichiers sont placés dans le même dossier
renvoyer "/ staticfiles /";
}
fonction get_version () {
// Même versioning que le site, supposé défini sous une constante
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 de fichier, le type de fichier et le code dynamique via la fonction get_content
:
classe HeaderColorsSiteResource étend SiteResourceBase {
fonction get_filename () {
retourne "en-tête-couleurs";
}
fonction get_type () {
renvoyer "css";
}
function get_content () {
retour sprintf (
"
.site-title a {
couleurs;
}
", esc_attr (get_header_textcolor ())
)
}
}
La classe WelcomeUserDataUserResource étend UserResourceBase {
fonction get_filename () {
renvoyer "welcomeuser-data";
}
fonction get_type () {
retourne "js";
}
function get_content () {
$ user = wp_get_current_user ();
retour sprintf (
"window.welcomeUserData =% s;",
json_encode (
tableau (
"name" => $ user-> display_name
)
)
)
}
}
Avec cela, nous avons modélisé le fichier en tant qu'objet PHP. Nous devons ensuite l’enregistrer sur le disque.
Enregistrement du fichier statique sur le disque
L’enregistrement d’un fichier sur le disque peut être facilement effectué à l’aide des fonctions natives fournies par le langage. Dans le cas de PHP, ceci est accompli par la fonction fwrite
. De plus, nous créons une classe d’utilité ResourceUtils
avec des fonctions fournissant le chemin absolu du fichier sur le disque, ainsi que son chemin relatif à la racine du site:
classe ResourceUtils {
fonction statique protégée get_file_relative_path ($ fileObject) {
return $ fileObject-> get_dir (). $ fileObject-> get_filename (). ".". $ fileObject-> get_type ();
}
fonction statique get_file_path ($ fileObject) {
// Notez que nous devons ajouter la constante WP_CONTENT_DIR pour rendre le chemin absolu lors de l'enregistrement du fichier.
return WP_CONTENT_DIR.self :: get_file_relative_path ($ fileObject);
}
}
classe ResourceGenerator {
fonction statique save ($ fileObject) {
$ file_path = ResourceUtils :: get_file_path ($ fileObject);
$ handle = fopen ($ chemin_fichier, "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 tant que paramètre. Le code ci-dessous régénère et enregistre sur le disque les fichiers “header-colors.css” et “welcomeuser-data.js”:
// Lorsque vous avez besoin de régénérer header-colors.css, exécutez:
ResourceGenerator :: save (new HeaderColorsSiteResource ());
// Lorsque vous avez besoin de régénérer welcomeuser-data.js, exécutez:
ResourceGenerator :: save (new WelcomeUserDataUserResource ());
Une fois qu'ils existent, nous pouvons mettre en file d'attente les fichiers à charger via les balises
et
.
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 toute ressource dans WordPress: via fonctions wp_enqueue_script
et wp_enqueue_style
. Ensuite, nous itérons simplement toutes les instances d'objet et utilisons un crochet ou un autre en fonction de leur valeur get_type ()
étant "js"
ou "css"
.
Nous ajoutons d’abord des fonctions utilitaires pour fournir l’URL du fichier et indiquer le type, JS ou CSS:
class ResourceUtils {
// Suite d'en haut ...
fonction statique get_file_url ($ fileObject) {
// Ajoute l'URL du site avant le chemin du fichier
return get_site_url (). self :: get_file_relative_path ($ fileObject);
}
fonction statique is_css ($ fileObject) {
return $ fileObject-> get_type () == "css";
}
fonction statique 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
effectuent la mise en file d'attente, en exécutant les fonctions WordPress correspondantes ( wp_enqueue_script
et wp_enqueue_style
))))
classe ResourceEnqueuer {
protected $ fileObjects;
fonction __construct ($ fileObjects) {
$ this-> fileObjects = $ fileObjects;
}
fonction protégée 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, $ dépendances, $ version);
}
fonction enqueue_scripts () {
$ jsFileObjects = array_map (array (ResourceUtils :: class, 'is_js'), $ this-> fileObjects);
foreach ($ jsFileObjects en tant que $ fileObject) {
list ($ handle, $ url, $ dépendances, $ version) = $ this-> get_file_properties ($ fileObject);
wp_register_script ($ handle, $ url, $ dépendances, $ version);
wp_enqueue_script ($ handle);
}
}
fonction enqueue_styles () {
$ cssFileObjects = array_map (array (ResourceUtils :: class, 'is_css'), $ this-> fileObjects);
foreach ($ cssFileObjects en tant que $ fileObject) {
list ($ handle, $ url, $ dépendances, $ version) = $ this-> get_file_properties ($ fileObject);
wp_register_style ($ handle, $ url, $ dépendances, $ version);
wp_enqueue_style ($ handle);
}
}
}
Enfin, nous instancions un objet de 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 avec les instances d'objet correspondantes pour chaque fichier à mettre en file d'attente
$ fileEnqueuer = new ResourceEnqueuer (
tableau (
nouveau HeaderColorsSiteResource (),
new WelcomeUserDataUserResource ()
)
)
// Ajouter les points d'ancrage WordPress pour mettre les ressources en file d'attente
add_action ('wp_enqueue_scripts', array ($ fileEnqueuer, 'enqueue_scripts'));
add_action ('wp_print_styles', array ($ fileEnqueuer, 'enqueue_styles'));
C’est ça: En cours de mise 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 améliorer encore les performances.
Lectures recommandées : Introduction à la vérification automatique de Plugins WordPress avec PHPUnit
Regroupement de fichiers
Même si HTTP / 2 a réduit le besoin de regrouper des fichiers, le site reste plus rapide car la compression de fichiers (par exemple via GZip) sera plus efficace. et parce que les navigateurs (tels que Chrome) ont un temps système plus important à traiter de nombreuses ressources.
Nous avons désormais 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 fournie 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:
la classe abstraite SiteBundleBase étend SiteResourceBase {
protected $ fileObjects;
fonction __construct ($ fileObjects) {
$ this-> fileObjects = $ fileObjects;
}
function get_content () {
$ content = "";
foreach ($ this-> fileObjects en tant que $ fileObject) {
$ content. = $ fileObject-> get_content (). PHP_EOL;
}
retourne $ contenu;
}
}
Nous pouvons regrouper tous les fichiers dans le fichier bundled-styles.css
en créant une classe pour ce fichier:
class StylesSiteBundle étend SiteBundleBase {
fonction get_filename () {
retourne "bundled-styles";
}
fonction get_type () {
renvoyer "css";
}
}
Enfin, nous mettons simplement en file d'attente ces fichiers groupés, comme auparavant, à la place de toutes les ressources indépendantes. Pour CSS, nous créons un paquet contenant des fichiers header-colors.css
background-image.css
et de font-size.css
pour lesquels nous instancions simplement StylesSiteBundle
avec l'objet PHP pour chacun de ces fichiers (nous pouvons également créer le fichier JS Bundle):
$ fileObjects = array (
// CSS
nouveau HeaderColorsSiteResource (),
new BackgroundImageSiteResource (),
nouvelle FontSizesSiteResource (),
// JS
new WelcomeUserDataUserResource (),
new UserShoppingItemsUserResource ()
)
$ cssFileObjects = array_map (array (ResourceUtils :: class, 'is_css'), $ fileObjects);
$ jsFileObjects = array_map (array (ResourceUtils :: class, 'is_js'), $ fileObjects);
// Utilise cette définition de $ fileEnqueuer au lieu de la précédente
$ fileEnqueuer = new ResourceEnqueuer (
tableau (
nouveau StylesSiteBundle ($ cssFileObjects),
nouveau ScriptsSiteBundle ($ jsFileObjects)
)
)
C’est tout. Nous ne demanderons plus qu'un seul fichier JS et un seul fichier CSS au lieu de plusieurs.
Une dernière amélioration en ce qui concerne les performances perçues consiste à hiérarchiser les actifs, en retardant le chargement des actifs inutiles immédiatement. Nous allons aborder cette question suivante.
async
/ différer
Attributs des ressources JS
Nous pouvons ajouter des attributs async
et différer
du
au
. ] balise, pour modifier le moment où le fichier JavaScript est téléchargé, analysé et exécuté, ainsi que pour attribuer une priorité au code JavaScript critique et appliquer le plus tard possible tout élément non critique au minimum, ce qui réduit le temps de chargement apparent du site.
Pour implémenter cette fonctionnalité, en suivant les principes SOLID, nous devrions créer une nouvelle interface JSResource
(qui hérite de Resource
) contenant des fonctions is_async
et et des fonctions .
. Cependant, cela fermerait la porte aux balises
/index.html
; header-colors.css
existe. Comme il ne le fait pas, il obtient le code source et génère le fichier sur le disque;
header-colors.css
; /index.html
; header-colors.css
. Cependant, cette image n'étant pas cachée dans le navigateur, la demande est envoyée au serveur; header-colors.css
(par exemple, il vient d'être redémarré); /staticfiles/header-colors.css
), tandis que # 1 crée un fichier statique pour chaque utilisateur (par exemple, /staticfiles/users/leo/header-colors.css
). -
header-colors.css
avec un style issu des valeurs enregistrées dans la base de données -
welcomeuser data.js
contenant un objet JSON avec des données utilisateur sous une variable:window.welcomeUserData = {name: "Leo"};
.
[create_static_files]
comme je l'ai décrit dans un article précédent .
Autres lectures recommandées : Créer un service ouvrier: une étude de cas
Représenter le fichier sous forme d'objet
Nous devons modéliser un fichier sous la forme d'un objet PHP avec toutes les propriétés correspondantes afin de pouvoir le sauvegarder sur le disque à un emplacement spécifique. (par exemple sous / staticfiles /
ou / staticfiles / users / leo /
), et savent comment demander le fichier en conséquence. Pour cela, nous créons une interface Ressource
renvoyant à la fois les métadonnées du fichier (nom du fichier, répertoire, type: "css" ou "js", version et dépendances d'autres ressources) et son contenu. Interface
Ressource {
fonction get_filename ();
fonction get_dir ();
fonction get_type ();
fonction get_version ();
fonction get_dependencies ();
fonction get_content ();
}
Afin de rendre le code maintenable et réutilisable, nous suivons les principes SOLID pour lesquels nous avons défini un schéma d'héritage d'objet pour que les ressources ajoutent progressivement des propriétés, à partir de la classe abstraite ResourceBase
de laquelle hériteront toutes les implémentations de nos ressources:
la classe abstraite ResourceBase implémente Resource {
fonction get_dependencies () {
// Par défaut, un fichier n'a pas de dépendances
retourne un tableau ();
}
}
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 le contrôle de version qui le demandera seront différents selon que le fichier concerne l'utilisateur ou la configuration du site:
la classe abstraite UserResourceBase étend la base de ressources {
fonction get_dir () {
// Un fichier et un dossier différent pour chaque utilisateur
$ user = wp_get_current_user ();
return "/ staticfiles / users / {$ user-> user_login} /";
}
fonction get_version () {
// Sauvegarde la version de la ressource pour l'utilisateur sous ses métadonnées.
// Lorsque le fichier est régénéré, vous devez exécuter `update_user_meta` pour augmenter le numéro de version.
$ user_id = get_current_user_id ();
$ meta_key = "version_ressources _". $ this-> get_filename ();
return get_user_meta ($ user_id, $ meta_key, true);
}
}
la classe abstraite SiteResourceBase étend la base de données {
fonction get_dir () {
// Tous les fichiers sont placés dans le même dossier
renvoyer "/ staticfiles /";
}
fonction get_version () {
// Même versioning que le site, supposé défini sous une constante
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 de fichier, le type de fichier et le code dynamique via la fonction get_content
:
classe HeaderColorsSiteResource étend SiteResourceBase {
fonction get_filename () {
retourne "en-tête-couleurs";
}
fonction get_type () {
renvoyer "css";
}
function get_content () {
retour sprintf (
"
.site-title a {
couleurs;
}
", esc_attr (get_header_textcolor ())
)
}
}
La classe WelcomeUserDataUserResource étend UserResourceBase {
fonction get_filename () {
renvoyer "welcomeuser-data";
}
fonction get_type () {
retourne "js";
}
function get_content () {
$ user = wp_get_current_user ();
retour sprintf (
"window.welcomeUserData =% s;",
json_encode (
tableau (
"name" => $ user-> display_name
)
)
)
}
}
Avec cela, nous avons modélisé le fichier en tant qu'objet PHP. Nous devons ensuite l’enregistrer sur le disque.
Enregistrement du fichier statique sur le disque
L’enregistrement d’un fichier sur le disque peut être facilement effectué à l’aide des fonctions natives fournies par le langage. Dans le cas de PHP, ceci est accompli par la fonction fwrite
. De plus, nous créons une classe d’utilité ResourceUtils
avec des fonctions fournissant le chemin absolu du fichier sur le disque, ainsi que son chemin relatif à la racine du site:
classe ResourceUtils {
fonction statique protégée get_file_relative_path ($ fileObject) {
return $ fileObject-> get_dir (). $ fileObject-> get_filename (). ".". $ fileObject-> get_type ();
}
fonction statique get_file_path ($ fileObject) {
// Notez que nous devons ajouter la constante WP_CONTENT_DIR pour rendre le chemin absolu lors de l'enregistrement du fichier.
return WP_CONTENT_DIR.self :: get_file_relative_path ($ fileObject);
}
}
classe ResourceGenerator {
fonction statique save ($ fileObject) {
$ file_path = ResourceUtils :: get_file_path ($ fileObject);
$ handle = fopen ($ chemin_fichier, "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 tant que paramètre. Le code ci-dessous régénère et enregistre sur le disque les fichiers “header-colors.css” et “welcomeuser-data.js”:
// Lorsque vous avez besoin de régénérer header-colors.css, exécutez:
ResourceGenerator :: save (new HeaderColorsSiteResource ());
// Lorsque vous avez besoin de régénérer welcomeuser-data.js, exécutez:
ResourceGenerator :: save (new WelcomeUserDataUserResource ());
Une fois qu'ils existent, nous pouvons mettre en file d'attente les fichiers à charger via les balises
et
.
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 toute ressource dans WordPress: via fonctions wp_enqueue_script
et wp_enqueue_style
. Ensuite, nous itérons simplement toutes les instances d'objet et utilisons un crochet ou un autre en fonction de leur valeur get_type ()
étant "js"
ou "css"
.
Nous ajoutons d’abord des fonctions utilitaires pour fournir l’URL du fichier et indiquer le type, JS ou CSS:
class ResourceUtils {
// Suite d'en haut ...
fonction statique get_file_url ($ fileObject) {
// Ajoute l'URL du site avant le chemin du fichier
return get_site_url (). self :: get_file_relative_path ($ fileObject);
}
fonction statique is_css ($ fileObject) {
return $ fileObject-> get_type () == "css";
}
fonction statique 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
effectuent la mise en file d'attente, en exécutant les fonctions WordPress correspondantes ( wp_enqueue_script
et wp_enqueue_style
))))
classe ResourceEnqueuer {
protected $ fileObjects;
fonction __construct ($ fileObjects) {
$ this-> fileObjects = $ fileObjects;
}
fonction protégée 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, $ dépendances, $ version);
}
fonction enqueue_scripts () {
$ jsFileObjects = array_map (array (ResourceUtils :: class, 'is_js'), $ this-> fileObjects);
foreach ($ jsFileObjects en tant que $ fileObject) {
list ($ handle, $ url, $ dépendances, $ version) = $ this-> get_file_properties ($ fileObject);
wp_register_script ($ handle, $ url, $ dépendances, $ version);
wp_enqueue_script ($ handle);
}
}
fonction enqueue_styles () {
$ cssFileObjects = array_map (array (ResourceUtils :: class, 'is_css'), $ this-> fileObjects);
foreach ($ cssFileObjects en tant que $ fileObject) {
list ($ handle, $ url, $ dépendances, $ version) = $ this-> get_file_properties ($ fileObject);
wp_register_style ($ handle, $ url, $ dépendances, $ version);
wp_enqueue_style ($ handle);
}
}
}
Enfin, nous instancions un objet de 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 avec les instances d'objet correspondantes pour chaque fichier à mettre en file d'attente
$ fileEnqueuer = new ResourceEnqueuer (
tableau (
nouveau HeaderColorsSiteResource (),
new WelcomeUserDataUserResource ()
)
)
// Ajouter les points d'ancrage WordPress pour mettre les ressources en file d'attente
add_action ('wp_enqueue_scripts', array ($ fileEnqueuer, 'enqueue_scripts'));
add_action ('wp_print_styles', array ($ fileEnqueuer, 'enqueue_styles'));
C’est ça: En cours de mise 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 améliorer encore les performances.
Lectures recommandées : Introduction à la vérification automatique de Plugins WordPress avec PHPUnit
Regroupement de fichiers
Même si HTTP / 2 a réduit le besoin de regrouper des fichiers, le site reste plus rapide car la compression de fichiers (par exemple via GZip) sera plus efficace. et parce que les navigateurs (tels que Chrome) ont un temps système plus important à traiter de nombreuses ressources.
Nous avons désormais 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 fournie 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:
la classe abstraite SiteBundleBase étend SiteResourceBase {
protected $ fileObjects;
fonction __construct ($ fileObjects) {
$ this-> fileObjects = $ fileObjects;
}
function get_content () {
$ content = "";
foreach ($ this-> fileObjects en tant que $ fileObject) {
$ content. = $ fileObject-> get_content (). PHP_EOL;
}
retourne $ contenu;
}
}
Nous pouvons regrouper tous les fichiers dans le fichier bundled-styles.css
en créant une classe pour ce fichier:
class StylesSiteBundle étend SiteBundleBase {
fonction get_filename () {
retourne "bundled-styles";
}
fonction get_type () {
renvoyer "css";
}
}
Enfin, nous mettons simplement en file d'attente ces fichiers groupés, comme auparavant, à la place de toutes les ressources indépendantes. Pour CSS, nous créons un paquet contenant des fichiers header-colors.css
background-image.css
et de font-size.css
pour lesquels nous instancions simplement StylesSiteBundle
avec l'objet PHP pour chacun de ces fichiers (nous pouvons également créer le fichier JS Bundle):
$ fileObjects = array (
// CSS
nouveau HeaderColorsSiteResource (),
new BackgroundImageSiteResource (),
nouvelle FontSizesSiteResource (),
// JS
new WelcomeUserDataUserResource (),
new UserShoppingItemsUserResource ()
)
$ cssFileObjects = array_map (array (ResourceUtils :: class, 'is_css'), $ fileObjects);
$ jsFileObjects = array_map (array (ResourceUtils :: class, 'is_js'), $ fileObjects);
// Utilise cette définition de $ fileEnqueuer au lieu de la précédente
$ fileEnqueuer = new ResourceEnqueuer (
tableau (
nouveau StylesSiteBundle ($ cssFileObjects),
nouveau ScriptsSiteBundle ($ jsFileObjects)
)
)
C’est tout. Nous ne demanderons plus qu'un seul fichier JS et un seul fichier CSS au lieu de plusieurs.
Une dernière amélioration en ce qui concerne les performances perçues consiste à hiérarchiser les actifs, en retardant le chargement des actifs inutiles immédiatement. Nous allons aborder cette question suivante.
async
/ différer
Attributs des ressources JS
Nous pouvons ajouter des attributs async
et différer
du au
. ] balise, pour modifier le moment où le fichier JavaScript est téléchargé, analysé et exécuté, ainsi que pour attribuer une priorité au code JavaScript critique et appliquer le plus tard possible tout élément non critique au minimum, ce qui réduit le temps de chargement apparent du site.
Pour implémenter cette fonctionnalité, en suivant les principes SOLID, nous devrions créer une nouvelle interface JSResource
(qui hérite de Resource
) contenant des fonctions is_async
et et des fonctions
.
. Cependant, cela fermerait la porte aux balises