Publié le 6 mars 2024
La compression des données est une technique d'optimisation des performances éprouvée qui réduit la taille des ressources de page éligibles. Pendant un certain temps, il était courant d'utiliser principalement gzip sur les serveurs Web pour compresser les ressources de page courantes basées sur du texte, telles que les fichiers HTML, CSS et JavaScript, et de les envoyer au client où elles pouvaient être décompressées. Le résultat est un temps de chargement plus rapide pour les ressources sans affecter le comportement prévu d'une page.
Bien que gzip soit très efficace en soi, des améliorations supplémentaires en matière de compression sur le Web ont été réalisées ces dernières années. En 2016, l'algorithme Brotli a été déployé dans Chrome, offrant de meilleurs taux de compression globaux pour les ressources éligibles. Fin 2017, tous les navigateurs modernes étaient compatibles avec Brotli, et la prise en charge des serveurs a commencé à se généraliser. Plus récemment, Chrome a déployé la compression ZStandard.
Mais le travail ne s'arrête pas là. L'équipe Chrome s'est efforcée de rendre les dictionnaires partagés utilisables sur le Web, qui sont désormais disponibles dans un essai Origin Trial pour Brotli et ZStandard. Les dictionnaires partagés peuvent compléter la compression Brotli et ZStandard pour offrir des taux de compression nettement plus élevés pour les sites Web qui déploient fréquemment du code mis à jour, et peuvent, dans certains cas, offrir des taux de compression de 90% ou plus. Cet article explique plus en détail le fonctionnement des dictionnaires partagés et comment vous pouvez vous inscrire aux essais d'origine pour les utiliser pour Brotli et ZStandard sur votre site Web. Vous pouvez aussi regarder cette vidéo :
Présentation des dictionnaires partagés
La compression est un processus qui consiste à rechercher des séquences redondantes dans une entrée et à utiliser ces informations pour créer une sortie beaucoup plus petite, qui peut être inversée ultérieurement. La compression fonctionne bien sur le Web, car elle réduit considérablement les temps de chargement des ressources. Brotli et ZStandard peuvent encore accroître leur efficacité en utilisant un dictionnaire de compression, qui est une collection de modèles supplémentaires que ces algorithmes peuvent utiliser lors de la compression. En fait, la haute efficacité de Brotli est obtenue dans une certaine mesure grâce à l'utilisation d'un dictionnaire interne.
Toutefois, des dictionnaires personnalisés , gérés par l'utilisateur, peuvent être utilisés avec Brotli et ZStandard et contenir des modèles spécifiques à des ressources particulières. En pratique, un dictionnaire personnalisé est un fichier externe qui peut être appliqué à n'importe quelle entrée. Les dictionnaires peuvent être très spécifiques au code de production d'une application, ou à n'importe quel contenu. L'applicabilité d'un dictionnaire donné à son entrée peut avoir un impact important sur l'efficacité globale de la compression. Les dictionnaires très similaires au contenu d'une entrée génèrent des sorties avec des taux de compression plus élevés que les dictionnaires dont le contenu est générique ou différent.
Voici un exemple de l'efficacité d'un dictionnaire de compression personnalisé : supposons que votre site Web utilise le framework Angular et que la version actuelle que vous utilisez est la version 1.7.9. Cette version du framework Angular est d'environ 172 Kio non compressée. Lorsqu'elle est compressée avec les paramètres par défaut de Brotli, sa taille devient d'environ 53 Kio. Cela donne un taux de compression de près de 70 %. Toutefois, supposons que vous décidiez de passer à Angular 1.8.3 ultérieurement. Étant donné que cette version d'Angular est à peu près de la même taille que la version 1.7.9, vous pouvez vous attendre à un taux de compression à peu près identique à celui de la version précédente.
C'est là qu'un dictionnaire personnalisé peut s'avérer utile en utilisant un processus appelé compression delta , qui consiste à utiliser un dictionnaire d'une version précédente d'une ressource pour compresser une version ultérieure. En reprenant l'exemple précédent, si vous compressiez la version 1.8.3 d'Angular à l'aide de la version 1.7.9 comme dictionnaire, la sortie ne dépasserait pas 4 Kio. Cela représente un taux de compression de près de 98%. Il est clair que les dictionnaires de compression peuvent avoir un impact important sur les performances de chargement, et leur efficacité a déjà été constatée dans des applications réelles.
Toutefois, il est difficile de faire fonctionner ce flux sur le Web. Le problème est que, si vous utilisez un dictionnaire pour compresser une ressource, vous avez besoin de ce même dictionnaire pour la décompresser. Ce flux a déjà été tenté sur le Web (SDCH), mais il était difficile à implémenter en toute sécurité. Cette dernière proposition de compression par dictionnaire partagé répond à ces préoccupations tout en offrant un avantage considérable pour les ressources statiques et dynamiques.
Comment Chrome annonce la prise en charge des dictionnaires partagés
Tous les navigateurs annoncent les algorithmes de compression qu'ils prennent en charge via l'en-tête de requête Accept-Encoding. Le contenu de l'en-tête est une liste d'encodages compatibles séparés par une virgule :
Accept-Encoding: gzip, br, zstd
Cet en-tête Accept-Encoding indique que le navigateur qui demande la ressource est compatible avec les algorithmes de compression gzip, Brotli et ZStandard. Un serveur Web qui répond à la requête peut ensuite décider de l'algorithme à utiliser pour répondre à la requête.
Lorsque la prise en charge des dictionnaires partagés est activée et qu'un dictionnaire pertinent est disponible pour une ressource, des jetons supplémentaires sont ajoutés à l'en-tête Accept-Encoding. Ces jetons sont br-d pour Brotli et zstd-d pour ZStandard. Chrome inclura également le hachage d'un dictionnaire disponible, qui est abordé ensuite.
Accept-Encoding: gzip, br, zstd, br-d, zstd-d
Available-Dictionary: :pZGm1Av0IEBKARczz7exkNYsZb8LzaMrV7J32a2fFG4=:
Si un serveur Web est configuré pour reconnaître ce jeton et qu'il reconnaît le dictionnaire, il peut répondre à cette requête avec une ressource compressée à l'aide du dictionnaire pour l'encodage applicable. La manière dont cela est réalisé en pratique dépend du fait que la requête concerne une ressource statique ou dynamique.
Compression par dictionnaire partagé pour les ressources statiques
Une ressource de page statique est une ressource qui produit toujours la même réponse pour une URL demandée. Les exemples courants de ressources de page statiques compressibles sont les fichiers JavaScript et CSS. Ces ressources sont généralement versionnées à des fins de mise en cache d'une manière ou d'une autre, parfois avec un hachage du contenu du fichier dans le nom de fichier (par exemple, styles.abcd1234.css) ou une autre méthode d'empreinte de la ressource. Ces types de ressources sont un excellent candidat pour la compression delta fournie par les dictionnaires partagés, car les ressources statiques sont souvent mises en cache pendant de longues périodes et ont tendance à être mises à jour fréquemment.
Un dictionnaire peut être spécifié pour une ressource statique en définissant l'en-tête de réponse Use-As-Dictionary. L'en-tête prend l'une des paires clé/valeur, mais la seule obligatoire est match, qui accepte la syntaxe URLPattern spécifiant le chemin de la ressource où le dictionnaire doit être utilisé :
Use-As-Dictionary: match="/dist/styles.*.css"
Considérez l'en-tête Use-As-Dictionary comme un mécanisme qui s'applique aux futures versions d'une ressource correspondant au modèle spécifié. Supposons que votre site Web envoie tous ses styles dans un seul fichier CSS. Par souci de simplicité, supposons que la première version de cette ressource se trouve à l'adresse /dist/styles.v1.css et qu'elle est envoyée avec un en-tête de réponse Use-As-Dictionary contenant une valeur match de /dist/styles.*.css.
Après un certain temps, vous mettez à jour le CSS de votre site Web et envoyez une nouvelle version située à l'adresse /dist/styles.v2.css. Étant donné que la valeur match utilisée dans l'en-tête de réponse Use-As-Dictionary de la version précédente s'applique à cette requête, le navigateur envoie un en-tête Available-Dictionary contenant un hachage du dictionnaire encodé sous forme de séquence d'octets de champ structuré :
Accept-Encoding: gzip, br, zstd, br-d, zstd-d
Available-Dictionary: :pZGm1Av0IEBKARczz7exkNYsZb8LzaMrV7J32a2fFG4=:
À ce stade, il appartient au serveur de configurer la compression de son côté pour s'assurer que le dictionnaire correspondant est utilisé. La ressource compressée avec ce dictionnaire est ensuite envoyée, et le dictionnaire disponible dans le cache du navigateur de l'utilisateur est utilisé pour la décompresser.
Si vous déployez souvent du nouveau code pour votre site Web, la compression delta peut être très utile. Toutefois, le processus est flexible. Si le navigateur ne détermine pas qu'un dictionnaire est disponible dans le cache du navigateur de l'utilisateur, il ne spécifie pas les jetons br-d ou zstd-d supplémentaires dans l'en-tête Accept-Encoding. Dans ce cas, le flux de compression standard s'applique.
Compression par dictionnaire partagé pour les ressources dynamiques
Les ressources dynamiques peuvent également bénéficier de la compression par dictionnaire partagé. Les ressources dynamiques sont celles qui changent en fonction d'un contexte, par exemple un site Web d'actualités dont la page principale est mise à jour fréquemment à mesure que les informations sont publiées. Les documents HTML sont souvent des ressources dynamiques. Dans ce cas, le dictionnaire peut contenir la majeure partie de la structure HTML et du code de modèle courants du site, ce qui permet de compresser les pages où seules les parties uniques de chaque page sont envoyées.
En raison de la nature des ressources générées dynamiquement, un dictionnaire doit être chargé sur le client pour une utilisation ultérieure. Le chargement d'un dictionnaire à l'avance signifie que l'application de la compression par dictionnaire partagé aux ressources dynamiques est spéculative. Dans ce cas, l'espoir est que votre site Web reçoive suffisamment de trafic pour que le coût du dictionnaire puisse être amorti sur un grand nombre de navigations. Si vous décidez de l'essayer, la première étape consiste à spécifier l'emplacement du dictionnaire à l'aide d'un élément <link> dans le code HTML de votre page :
<link rel="dictionary" href="/dictionary.dat">
Lorsque Chrome rencontre cet élément <link>, il peut récupérer le dictionnaire une fois la page inactive, et à faible priorité afin d'éviter la contention de bande passante. La réponse du dictionnaire lui-même doit spécifier un en-tête Use-As-Dictionary et indiquer le chemin de la ressource dynamique à laquelle il s'applique :
Use-As-Dictionary: match="/product/*"
À partir de là, le flux est en grande partie le même que pour les ressources statiques. Le navigateur voit que le dictionnaire lui-même s'applique aux ressources correspondantes, et il joint un en-tête Available-Dictionary à la requête avec un hachage du contenu du dictionnaire, comme pour le flux de ressources statiques expliqué précédemment.
Compresser les ressources statiques au moment de la compilation
Si vous connaissez les bundlers, vous connaissez peut-être différents plug-ins qui peuvent compresser les ressources au moment de la compilation, puis diffuser ces ressources compressées. Par exemple, Apache vous permet d'utiliser des directives pour diffuser ces ressources précompressées au moment de la requête.
La plupart des bundlers basés sur Node.js qui prennent en charge la compression utilisent la bibliothèque Zlib intégrée de Node. Zlib est compatible avec Brotli, et les bundlers qui l'utilisent proposent généralement une interface permettant de transmettre des options directement à Zlib, qui prend en charge la compression assistée par dictionnaire. Voici quelques bundlers qui prennent en charge l'utilisation de dictionnaires :
CompressionWebpackPluginde webpack, via son interfacecompressionOptions.rollup-plugin-brotlipropose une configurationoptionsqui passe directement à Zlib dans Node.js, où les dictionnaires peuvent être spécifiés.- Le plug-in tiers
esbuild-plugin-compresspour esbuild permet également d'accéder aux options Zlib dans Node.js.
Notez que les dictionnaires disponibles pour une version donnée d'une ressource peuvent utiliser l'une des versions précédentes de cette ressource. Vous devrez donc analyser le trafic utilisateur et planifier en conséquence. Recherchez un équilibre et générez des ressources qui profitent au plus grand nombre d'utilisateurs récurrents possible. Les fournisseurs de CDN testent actuellement la compression par dictionnaire partagé. Aucune implémentation n'est encore disponible pour le public, mais cela devrait changer.
Essayez !
L'intégration de la compression par dictionnaire partagé aux fonctionnalités de compression existantes du navigateur peut améliorer considérablement les performances de chargement des sites Web qui déploient fréquemment du code de production mis à jour et qui reçoivent un trafic important de visiteurs récurrents. Si vous souhaitez essayer la compression par dictionnaire partagé, deux options s'offrent à vous :
- Si vous souhaitez simplement tester la compression par dictionnaire partagé pour vous familiariser avec son fonctionnement, vous pouvez activer la fonctionnalité expérimentale Compression par dictionnaire pour le transport sur la page
chrome://flags. - Si vous souhaitez essayer cette fonctionnalité sur votre site Web de production et voir comment la compression par dictionnaire partagé peut profiter aux utilisateurs réels, inscrivez-vous à l'essai d'origine pour obtenir un jeton et découvrez comment fonctionnent les essais d'origine.
Conclusion
Nous sommes très enthousiastes à propos de cette avancée majeure dans la technologie de compression sur le Web et de la rapidité qu'elle pourrait apporter aux applications existantes que les utilisateurs utilisent quotidiennement. Nous vous encourageons à l'essayer et, surtout, nous voulons connaître votre avis. Si vous trouvez un bug, signalez-le sur crbug.com. Pour obtenir des ressources et des outils supplémentaires, consultez use-as-dictionary.com. Enfin, si vous souhaitez en savoir plus sur son fonctionnement, l'explication est une bonne prochaine étape.