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 textuelles courantes telles que les fichiers HTML, CSS et JavaScript, et les envoyer au client où elles pouvaient être décompressées. Résultat : les ressources se chargent plus rapidement sans affecter le comportement prévu d'une page.
Bien que gzip soit très efficace en soi, des améliorations supplémentaires de la compression sur le Web ont été apportées ces dernières années. En 2016, l'algorithme Brotli a été intégré à Chrome, offrant des ratios de compression globalement meilleurs pour les ressources éligibles. À la fin de l'année 2017, tous les navigateurs modernes étaient compatibles avec Brotli, et la compatibilité avec les serveurs a commencé à se répandre. Plus récemment, Chrome a implémenté la compression ZStandard.
Mais notre travail ne s'arrête pas là. L'équipe Chrome s'est efforcée de rendre les dictionnaires partagés utilisables sur le Web. Ils sont désormais disponibles en version d'essai pour Brotli et ZStandard. Les dictionnaires partagés peuvent compléter la compression Brotli et ZStandard pour obtenir des taux de compression nettement plus élevés pour les sites Web qui publient fréquemment du code mis à jour. Dans certains cas, ils peuvent atteindre 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 avec Brotli et ZStandard sur votre site Web.
Présentation des dictionnaires partagés
La compression consiste à trouver 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 améliorer leur efficacité en utilisant un dictionnaire de compression, qui est un ensemble de modèles supplémentaires que ces algorithmes peuvent utiliser lors de la compression. En fait, la grande efficacité de Brotli est obtenue dans une certaine mesure grâce à l'utilisation d'un dictionnaire interne.
Toutefois, vous pouvez utiliser des dictionnaires personnalisés créés par l'utilisateur avec Brotli et ZStandard, qui contiennent 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. Le niveau d'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é: imaginons 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 pèse environ 172 ko non compressée. Lorsqu'il est compressé avec les paramètres par défaut de Brotli, sa taille passe à environ 53 ko. Cela donne un taux de compression d'environ 70 %. Supposons toutefois que vous décidiez de passer à Angular 1.8.3 plus tard. É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 ratio 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. Pour reprendre l'exemple précédent, si vous avez compressé la version 1.8.3 d'Angular à l'aide de la version 1.7.9 comme dictionnaire, la sortie serait un peu supérieure à 4 ko. Cela représente un taux de compression de presque 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.
Cependant, 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, par exemple), mais il était difficile de l'implémenter de manière sécurisée. Cette dernière proposition de compression de dictionnaire partagé répond à ces préoccupations, tout en offrant un avantage substantiel 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 acceptent 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 y répondre.
Lorsque la prise en charge du dictionnaire partagé 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 inclut également le hachage d'un dictionnaire disponible, qui est abordé ci-dessous.
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 se fait dans la pratique dépend de la requête pour une ressource statique ou dynamique.
Compression par dictionnaire partagé pour les ressources statiques
Une ressource de page statique produit toujours la même réponse pour une URL demandée. Les fichiers JavaScript et CSS sont des exemples courants de ressources de page statiques compressables. Ces ressources sont généralement versionnées à des fins de mise en cache, parfois avec un hachage du contenu du fichier dans le nom du fichier (par exemple, styles.abcd1234.css
) ou une autre méthode d'empreinte de la ressource. Ces types de ressources sont particulièrement adaptés à 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 avec une certaine fréquence.
Vous pouvez spécifier un dictionnaire pour une ressource statique en définissant l'en-tête de réponse Use-As-Dictionary
. L'en-tête accepte l'une des quelques paires clé/valeur, mais la seule obligatoire est match
, qui accepte la syntaxe URLPattern
spécifiant le chemin d'accès aux ressources 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 qui correspondent au modèle spécifié. Supposons que votre site Web inclut tous ses styles dans un seul fichier CSS. Par souci de simplicité, supposons que la première version de cette ressource se trouve à /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
.
Au bout d'un certain temps, vous mettez à jour le CSS de votre site Web et en publiez une nouvelle version à 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é en tant que séquence d'octets de champ structurée:
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 de correspondance 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 publiez souvent du nouveau code pour votre site Web, la compression delta peut vous aider à réduire considérablement la taille de vos mises à jour. Cependant, 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 du dictionnaire partagé. Les ressources dynamiques sont celles qui changent en fonction d'un contexte, comme un site d'actualités dont la page principale est mise à jour fréquemment en fonction des actualités, par exemple. Les documents HTML sont souvent des ressources dynamiques. Dans ce cas, le dictionnaire peut contenir la plupart de la structure HTML et du code de modèle communs du site, ce qui permet de compresser les pages en n'envoyant que les parties uniques de chaque page.
En raison de la nature des ressources générées dynamiquement, un dictionnaire doit être chargé sur le client pour être utilisé ultérieurement. Charger un dictionnaire à l'avance signifie que l'application de la compression de dictionnaire partagé aux ressources dynamiques est spéculative. Dans ce cas, l'objectif est que votre site Web génère 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 les conflits de bande passante. La réponse pour le dictionnaire lui-même doit spécifier un en-tête Use-As-Dictionary
et le chemin de ressource dynamique auquel elle s'applique:
Use-As-Dictionary: match="/product/*"
À partir de là, la procédure est largement identique à celle des ressources statiques. Le navigateur verra que le dictionnaire lui-même s'applique aux ressources correspondantes, et il ajoutera un en-tête Available-Dictionary
à la requête avec un hachage du contenu du dictionnaire, à nouveau semblable au flux de ressources statiques expliqué précédemment.
Compresser les ressources statiques au moment de la compilation
Si vous connaissez les bundleurs, vous connaissez peut-être les 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 outils de compilation basés sur Node.js compatibles avec la compression utilisent la bibliothèque Zlib intégrée de Node. Zlib est compatible avec Brotli. Les outils de regroupement 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 outils de compilation compatibles avec l'utilisation de dictionnaires:
CompressionWebpackPlugin
de webpack, via son interfacecompressionOptions
.rollup-plugin-brotli
propose une configurationoptions
qui est transmise directement à Zlib dans Node.js, où des dictionnaires peuvent être spécifiés.- Le plug-in tiers
esbuild-plugin-compress
pour esbuild offre également un accès 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 la ressource. Vous devrez donc analyser le trafic utilisateur et planifier en conséquence. Cherchez un équilibre et générez des ressources qui profitent au maximum au plus grand nombre d'utilisateurs réguliers. Les fournisseurs de CDN testent actuellement la compression de dictionnaire partagée. Aucune implémentation n'est encore disponible pour une utilisation publique, mais nous espérons que cela changera.
Essayez !
L'intégration de la compression du dictionnaire partagé aux fonctionnalités de compression existantes du navigateur peut considérablement améliorer les performances de chargement des sites Web qui publient fréquemment du code de production mis à jour et reçoivent un trafic important de la part des visiteurs réguliers. Si vous souhaitez essayer la compression de dictionnaire partagé, deux options s'offrent à vous:
- Si vous souhaitez simplement tester la compression par dictionnaire partagé par vous-même pour comprendre son fonctionnement, vous pouvez activer la fonctionnalité expérimentale Compression dictionary transport (Transport par dictionnaire de compression) sur la page
chrome://flags
. - Si vous souhaitez tester cette fonctionnalité sur votre site Web de production et voir comment la compression du dictionnaire partagé peut bénéficier à de vrais utilisateurs, inscrivez-vous au test de l'origine pour obtenir un jeton et découvrez comment fonctionne le test de l'origine.
Conclusion
Nous sommes très enthousiastes à l'égard de cette avancée majeure de la technologie de compression sur le Web et de l'accélération qu'elle pourrait apporter aux applications existantes que les utilisateurs utilisent au quotidien. Nous vous invitons à l'essayer et, surtout, à nous faire part de vos commentaires si vous le faites. 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 le fonctionnement de cette fonctionnalité, consultez la vidéo explicative.