Les outils de développement Chrome ont l'onglet Audit. Sur celui-ci est un outil appelé Lighthouse, qui sert à analyser la qualité de l'application Web.
J'ai récemment décidé de tester une application et j'ai été horrifié par les résultats. Immédiatement dans plusieurs sections, l'évaluation était dans la zone rouge. J'ai commencé à étudier ce qui n'allait pas avec ma candidature. Et j'ai trouvé une grande liste de recommandations très utiles dans les résultats de l'analyse, les ai respectées et j'ai obtenu 500 points. En conséquence, l'application a commencé à fonctionner beaucoup plus rapidement et j'ai révisé plusieurs concepts concernant la méthode de création d'applications. Et dans cet article, je veux partager les solutions les plus intéressantes auxquelles je suis parvenu.
Si vous n'avez pas la possibilité d'installer Chrome, vous pouvez installer lighthouse à partir de npm et l'utiliser avec la console.
Dans l'article, je n'ai pas comparé chaque recommandation avec une section spécifique; au lieu de cela, j'ai divisé les sections en solutions que j'ai appliquées et que Ligthouse aimait. Ce n'est pas tout ce qu'il recommande, c'est seulement le plus intéressant. Les recommandations restantes sont très simples, et comme le SEO sont depuis longtemps familiers à tout le monde.
Performances
Sélection du serveur
C'est le conseil le plus courant, mais c'est celui-ci qui est le fondement de toute productivité. Heureusement, trouver une bonne solution est simple, c'est n'importe quel centre de données de niveau 3 ou 4. Ce statut lui-même ne dit rien sur la vitesse, il dit que les propriétaires ont pris soin de la qualité.
Initialisation de l'application
Une fois, il n'y avait que du HTML dans les navigateurs. Puis vint le javascript et la logique métier. Aujourd'hui, il y a tellement de logique sur le client que le HTML ne peut pas y faire face et n'est plus nécessaire. Mais, parce que le navigateur ne peut pas démarrer le chargement à partir du fichier JavaScript, nous devrons placer un petit morceau de html pour lancer notre application.
Idéalement, cela devrait ressembler à ceci:
<!DOCTYPE html> <html lang="ru"> <head> <title> </title> <link rel="manifest" href="./manifest.webmanifest"> <link rel="shortcut icon" href="content/images/favicon.ico" type="image/x-icon"> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" charset="utf-8"/> <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> <meta name="viewport" content="width=device-width" /> <meta name="theme-color" content="#425566"> <meta name="Description" content=" "> </head> <body> <div id="loader"> loading </div> <script async> </script> </body> </html>
Il ne doit y avoir aucun contenu, seulement le code nécessaire pour initialiser l'application, qui chargera l'application elle-même et le contenu.
Cet article ne considère pas l'optimisation pour les bots, mais je dirai qu'il est plus facile d'attraper un bot spécifique et de donner ce dont un bot a besoin. Le robot Google lui-même comprendra tout, du contenu qui sera chargé plus tard.
Utiliser l'écran de démarrage
Nous sommes tous habitués aux écrans de démarrage lors du chargement dans les applications mobiles, et même lors du chargement du système d'exploitation, mais peu de gens utilisent les écrans de démarrage dans une application Web. C'est ce que nous placerons dans le bloc du chargeur afin que l'utilisateur ne s'ennuie pas pendant le chargement de l'application elle-même.
En tant qu'écran de démarrage, en option, vous pouvez utiliser une animation CSS ou simplement une image, comme cela se fait sur les téléphones mobiles. La seule condition est qu'il soit très léger.
Qu'obtenons-nous? Les utilisateurs avec un Internet lent recevront instantanément une réaction du site, ils n'admireront pas l'écran blanc et se demanderont si le site fonctionne du tout ou non. Les utilisateurs avec Internet rapide ne le verront probablement même pas, mais même ils ont des retards sur Internet.
Comme exemple intéressant d'utilisation des
écrans de démarrage, je vais vous donner le site de la
station d'accueil , où une belle vague orne un très long chargement du site. En fait, c'est ainsi que les personnes ayant un Internet lent verront votre application.
Et immédiatement, je m'empresse de déranger ceux qui pensent que éclabousser un écran peut tromper Lighthouse et placer une application lourde derrière. Il voit tout et ne vous donnera pas une bonne note pour une application lourde.
Initialisation de l'application
Maintenant que nous distrayons l'attention de l'utilisateur avec des images, il est temps de télécharger l'application. Pour ce faire, nous insérons le script suivant dans le bloc de script.
En quoi cela consiste-t-il:
- Connexion PWA - nous considérerons dans la section correspondante ci-dessous. Vous devez le connecter dès que possible, car il est possible que pwa dispose déjà de tout le nécessaire pour que le site fonctionne et il n'y aura plus de requêtes vers le serveur.
- Connecter les styles - connectez les styles selon vos besoins. Idéalement, ce code ne devrait pas exister du tout et les styles devraient connecter vos composants selon les besoins.
- Connecter les scripts - connectez le programme. Il ne doit comprendre que deux de ces scripts. Tous les autres scripts (cartes, analyses, bibliothèques) qui n'affectent pas l'affichage du premier écran (pas la page entière) sont chargés après avoir dessiné le premier écran de l'application. Le composant d'analyse doit déjà charger l'analyse après le chargement du programme. La qualité de l'analyse ne sera pas affectée par cela, et les systèmes d'analyse prennent en charge le chargement après le téléchargement du programme. Les cartes ne doivent être immergées qu'après que l'utilisateur les a numérisées et qu'elles ont touché l'écran. Avec des bibliothèques tierces requises pour que des composants spécifiques fonctionnent de la même manière.
En conséquence, en modifiant un peu les priorités, nous obtenons un rendu rapide de l'application. Ainsi, les utilisateurs et les robots de recherche sont satisfaits de la vitesse et, en même temps, ne violent pas l'analyse.
Chargement et rendu paresseux
Un paramètre très important est la rapidité avec laquelle le premier écran est dessiné et l'utilisateur peut commencer à interagir avec cette page. Et ici, il vaut la peine d'utiliser les optimisations suivantes:
1. Rendu paresseux. Il est nécessaire de dessiner uniquement la partie de la page où l'utilisateur regarde, et le rendu des composants lourds ou des images doit déjà être fait lorsque l'utilisateur y a sauté.
Une bonne solution ici est les composants lazy-block et lazy-img:
<div> <p></p> <lazy-img src="..."/> </div> <lazy-block> </lazy-block> <lazy-block> </lazy-block> <lazy-block> </lazy-block>
Le fait est qu'ils surveilleront le défilement de l'utilisateur et si le composant tombe dans la zone d'écran, il sera dessiné. Cela peut être comparé à la technique du défilement virtuel (
exemple ) qui est familière à tout le monde sur les murs des réseaux sociaux. Nous pouvons faire défiler pour toujours, mais ils ne ralentissent jamais.
Mais n'oubliez pas Google Bot, qui voit le spa, mais ne fait pas défiler la page entière. Par conséquent, si vous n'y prenez pas garde, il ne verra pas votre contenu.
2. Si l'un des composants utilise une dépendance externe, il devra le charger lui-même si nécessaire. Par exemple, il peut s'agir d'un bloc avec des cartes, des graphiques ou des graphiques 3D. Et récemment, un moyen de le faire dans JS a été très simple:
class Demo { constructor() { this.init(); } private async init() { const module = await import('./external.mjs');
En conséquence, l'utilisateur ne charge que ce dont il a besoin, ce qui économise considérablement les ressources utilisateur et serveur.
Minimisation des offres groupées
Et ... oui, vous n'y avez pas pensé, il ne s'agit pas de minification dans Terser (UglifyJS), mais de donner uniquement ce dont il a besoin à un navigateur spécifique.
Le fait est que les navigateurs évoluent constamment, ils ont une nouvelle API, les développeurs commencent à l'utiliser et pour la compatibilité avec les navigateurs plus anciens, ils connectent les polyfills et les transpilers. En conséquence, le problème se pose que les utilisateurs avec les derniers navigateurs, qui sont environ 80%, obtiennent du code conçu pour les utilisateurs d'IE11, transpilé et avec des polyfichiers.
Le problème avec ce code est qu'il contient beaucoup de texte supplémentaire, et ses performances sont 3 fois moins (selon mes estimations subjectives) que l'original. Il est beaucoup plus logique de créer plusieurs bundles pour différentes versions de navigateurs. Un bundle avec le code ES2017 pour Chrome 73 avec un minimum de polyfichiers, un bundle avec ES5 pour IE11 avec un minimum de polyfichiers, etc.
J'ai écrit sur la façon de collecter des ensembles de différentes versions à la fois dans un
article précédent . Et pour sélectionner la bonne version dans le navigateur, nous modifions légèrement le script de connexion du programme:
var esVersion = ".es2017"; try{ eval('"use strict"; class foo {}'); }catch(e){ esVersion = ".es5"; } [ "./scripts/polyfills" + esVersion + ".min.js", "./scripts/main" + esVersion + ".min.js" ].forEach(function(url){ const script = document.createElement("script"); script.src = url; script.async = false; document.head.appendChild(script); });
En conséquence, les utilisateurs de navigateurs modernes recevront le programme le plus léger et le plus productif, et les utilisateurs d'IE11 obtiendront ce qu'ils méritent.
Minimisation du code
Un problème très populaire est lorsque les développeurs commencent à connecter tout ce sur quoi leurs yeux tombent. Par conséquent, vous pouvez parfois regarder des programmes qui pèsent de 5 à 15 Mo ou plus. Par conséquent, le choix des bibliothèques doit être abordé avec sagesse.
Au lieu de cadres lourds comme Angular ou React, il est préférable de choisir leurs homologues plus légers: vue, préaction, mithril, etc. Ils ne sont en aucun cas inférieurs à leurs homologues éminents, mais les économies sur la taille du paquet peuvent être plusieurs fois.
Évitez d'utiliser des bibliothèques lourdes. Au lieu d'utiliser des bibliothèques telles que jquery, lodash, moment, rxjs et toute autre dans une taille réduite> 100 Ko, essayez d'étudier les algorithmes plus en profondeur et de trouver une solution dans JS natif. En règle générale, vous pouvez écrire plus simplement sur un script natif et vous débarrasser des fortes dépendances inutiles.
Minification d'image
Tous les développeurs frontaux connaissent probablement le format d'image webp et connaissent également la nécessité de réduire les images à la taille d'affichage requise. Mais pour une raison quelconque, presque tous les développeurs l'ignorent. Et la raison à cela, à mon avis, est extrêmement simple, les gens ne comprennent pas comment cela est fait et appliqué dans différents navigateurs.
Par conséquent, je vais donner ici une recette très simple pour résoudre tous les problèmes avec les images. Cette recette est
basée sur l'outil de conversion et de traitement d'image Sharp . Il se distingue par un pipeline très réfléchi, grâce auquel la vitesse de traitement de l'image est 30 à 40 fois supérieure à celle des analogues. Et le temps d'assemblage lui-même de centaines d'images provenant d'énormes sources de différentes tailles et formats est comparable à la vitesse d'assemblage d'un frontend moderne.
Pour utiliser Sharp, vous devez écrire un script, je l'utilise en conjonction avec glob pour rechercher récursivement des images dans le répertoire avec les images source, et je cache le script lui-même de l'utilitaire pour exécuter des tâches de gulp. Un exemple de mon montage:
gulp.task('core-min-images', async () => { const fs = require('fs'); const path = require('path'); const glob = require('glob'); const sharp = require('sharp');
En conséquence, nous obtenons des images optimisées pour différentes tailles d'écran et différents navigateurs à partir de chaque image source de grande taille. Maintenant, nous devons apprendre à les utiliser. Ici aussi, tout est simple, si auparavant nous écrivions comme ceci:
<img src="sample.jpg"/>
Maintenant, nous devons écrire comme ceci:
<picture> <source srcset="img/sample-480w.webp" type="image/webp"> <source srcset="img/sample-480w.jpg" type="image/jpeg"> <img src="img/sample-480w.jpg" alt=" !"> </picture>
Et puis le navigateur lui-même choisira le format le plus pratique pour lui. Vous pouvez également ajouter cette option avec des images réactives:
<picture> <source srcset="img/sample-480w.webp, img/sample-960w.webp 2x" type="image/webp"> <source srcset="img/sample-480w.jpg, img/sample-960w.webp 2x" type="image/jpeg"> <img src="img/sample-480w.jpg" alt=" !"> </picture>
Et compte tenu du fait qu'il est désormais possible de générer des images au stade de l'assemblage de l'application, il s'avère que toutes les images auront le même ensemble de formats et de résolutions, ce qui signifie que nous pouvons unifier cette logique et la cacher derrière un composant, par exemple le même
<lazy-img src="img/sample.jpg">
.
Minification du style
Téléchargez uniquement les styles qui utilisent vos composants. Idéalement, lorsque les styles sont liés aux composants et ne sont intégrés dans la maison que lorsque le composant lui-même est dessiné.
Minimisez les noms de classe. La longueur des sélecteurs imbriqués ou BEM dans les styles a un effet néfaste sur la taille de votre application. Actuellement, il regorge d'outils qui ne génèrent pas de styles avec des sélecteurs uniques: JSS, composants stylisés, modules CSS.
Minification à domicile
Nous connaissons tous le html, mais peu ont pensé que ce n'était qu'une simple abstraction sur un arbre d'objets très complexes. La chaîne d'héritage de l'élément div est la suivante:
HTMLDivElement -> HTMLElement -> Element -> Node -> EventTarget
Et chaque objet de cette chaîne possède 10 à 100 propriétés et méthodes qui consomment beaucoup de mémoire. Et toute cette richesse doit être prise en compte par le moteur DOM pour construire l'image que l'on voit. Par conséquent, essayez de ne pas utiliser d'éléments en excès dans la maison.
Réduisez le HTML. Supprimez tout ce que vous utilisez pour formater le HTML au moment de la rédaction. Le fait est que les espaces utilisés lors de l'écriture de code dans le navigateur se transforment également en objets à la maison:
TextNode -> Node -> EventTarget
Supprimer les commentaires. Ils font également partie du foyer et consomment beaucoup de ressources:
Comment -> CharacterData -> Node -> EventTarget
L'utilisation de moteurs de modèle jsx peut être une bonne pratique. Le fait est que lors de sa compilation, il se transforme en code js natif qui ne génère pas d'espaces, de commentaires et ne se trompe jamais en ouvrant et en fermant des balises.
La mauvaise pratique, je dirais même un cauchemar, c'est
facebook.com . Voici les fragments html:
Extrait de page HTML <div class=""> <div class="_42ef"> <div class="_25-w"> <div class="_17pg"> <div class="_1rwk"> <form class=" _129h"> <div class=" _3d2q _65tb _7c_r _4w79"> <div class="_5rp7"> <div class="_1p1t"> <div class="_1p1v" id="placeholder-77m1n" style="white-space: pre-wrap;"> ... </div> </div> </div> </div> <ul class="_1obb"> ...li... </ul> </form> </div> </div> </div> </div> </div> <div> <div> <div class="_3nd0"> <div class="_1mwp navigationFocus _395 _4c_p _5bu_ _34nd _21mu _5yk1" role="presentation" style="" id="js_u"> <div class="_5yk2" tabindex="-1"> <div class="_5rp7"> <div class="_1p1t" style=""> <div class="_1p1v" id="placeholder-6t6up" style="white-space: pre-wrap;"> ? </div> </div> <div class="_5rpb"> <div aria-autocomplete="list" aria-controls="js_1" aria-describedby="placeholder-6t6up" aria-multiline="true" class="notranslate _5rpu" contenteditable="true" data-testid="status-attachment-mentions-input" role="textbox" spellcheck="true" style="outline: none; user-select: text; white-space: pre-wrap; overflow-wrap: break-word;"> <div data-contents="true"> <div class="" data-block="true" data-editor="6t6up" data-offset-key="6b02n-0-0"> <div data-offset-key="6b02n-0-0" class="_1mf _1mj"> <span data-offset-key="6b02n-0-0"> <br data-text="true"> </span> </div> </div> </div> </div> </div> </div> </div> </div> </div> </div> </div>
Comme vous pouvez le voir, une imbrication de dix éléments est utilisée, mais cette imbrication ne fait aucun travail. Le premier fragment n'affiche que le texte «Ecrire un commentaire ...» et les icônes, le second «Quoi de neuf?». À la suite d'une telle utilisation non rationnelle du DOM, toutes les performances du moteur de modélisation React sont tout simplement annulées, et le site devient l'un des plus lents que je connaisse.
Progressive Web App
Fichier manifeste
PWA vous permet d'utiliser votre application Web comme une application native. Lorsque vous activez la prise en charge sur le site, le bouton pour installer votre site sur l'appareil (Windows, Android, iOS) apparaît dans le menu du navigateur, après quoi il commence à se comporter comme natif et fonctionne hors ligne, et tout cela contourne les magasins d'applications.
L'activation du support PWA sur le site est en fait très simple. Il suffit d'inclure un lien vers le fichier manifeste dans la page html. Le fichier manifeste peut être généré sur
pwabuilder.com .
Je ne m'arrêterai pas en détail sur le processus de connexion, car Cette section est digne d'un grand article séparé, et sur le hub il y en a déjà de très bons.
Travailleur de service
La configuration PWA ne se termine pas lors de la connexion du fichier manifeste, il est également nécessaire de connecter le ServiceWorker, qui sera responsable de travailler hors ligne.
Un exemple de code peut être trouvé sur
pwabuilder.com :
Comme vous pouvez le voir dans le code, toutes les réponses du serveur sont mises en cache, mais le cache n'est pas utilisé en ligne. Et ils commencent à être utilisés lorsque la connexion au serveur a disparu. Ainsi, l'utilisateur naviguant sur le site peut ne pas remarquer la disparition à court terme d'Internet, et même si Internet a disparu depuis longtemps, l'utilisateur a toujours la possibilité de se déplacer dans les données déjà mises en cache.
Le script ci-dessus est simple, mais ne convient qu'aux pages de destination et n'est qu'un point de départ pour écrire un travailleur pour une application Web plus sérieuse. Mais plus à ce sujet dans la deuxième partie de cet article. De plus, la technologie est pratique en ce qu'elle ne rompt pas le travail dans les anciens navigateurs, c'est-à-dire dans les navigateurs de niveau IE11, vous n'avez pas besoin de réécrire la logique, le mode hors ligne ne fonctionnera tout simplement pas.
Accessibilité
Exactitude des attributs pour les personnes ayant des besoins spéciaux
Il y a très peu de personnes en parfaite santé, mais malheureusement, il y a beaucoup de personnes en mauvaise santé, y compris la vision. Et pour que ces personnes utilisent plus facilement votre application Web, il suffit de suivre des règles assez simples:
- Utilisez suffisamment de couleurs contrastées. Selon les statistiques du ministère de la Santé, 20% des personnes ont des problèmes de vision. Un mauvais contraste ne fait que compliquer la vie et les personnes en bonne santé augmentent la fatigue.
- Organisez le tabindex. Vous permet d'utiliser le site sans souris ni appareils tactiles. Une bonne disposition des transitions à l'aide du clavier simplifie considérablement le processus de remplissage des formulaires.
- Attribut Aria-label sur les liens. Permet aux lecteurs d'écran de lire du texte à l'intérieur d'un attribut.
- L'attribut alt dans les images. Similaire à la précédente. De plus, il affichera du texte s'il n'est pas possible de télécharger l'image.
- La langue du document. Marquez la balise html avec l'attribut avec langue lang = "code de langue". Cela aidera les outils auxiliaires à s'installer correctement pour le travail.
Comme vous pouvez le voir, les exigences sont en fait peu nombreuses et simples à respecter. Mais pour une raison quelconque, la plupart des développeurs ignorent ces règles, même lorsqu'il s'agit de sites spécialisés pour les personnes ayant des besoins spéciaux.
Meilleures pratiques
Séparez l'application frontale de l'application serveur
Tout d'abord, si vous restituez encore du code HTML sur le serveur, arrêtez déjà de le faire.
Le transfert du processus de rendu au client de deux ordres de grandeur réduit la charge sur le serveur et, par conséquent, le coût de prise en charge de l'application serveur. Et les clients reçoivent une application qui réagit instantanément à leurs actions.Ensuite, séparez votre application SPA cliente de l'application principale. Vous ne tenez pas ensemble l'application serveur et l'application Windows, l'application Android et l'application iOS. L'application Web est donc depuis longtemps une application autonome qui peut fonctionner sans serveur et même hors ligne. L'erreur la plus populaire que je vois est lorsqu'un framework back-end comme Spring ou Asp.Net est engagé dans la distribution de statiques, y compris l'application SPA assemblée. Il est temps de cesser de faire cela et de supprimer la statique et le SPA dans un microservice séparé et de le cacher derrière un serveur Web spécialisé pour distribuer la statique, par exemple nginx.
En conséquence, chaque technologie fera ce qu'elle devrait faire et elle le fait le mieux. Nginx distribuera la statique avec les en-têtes corrects et la vitesse maximale, l'application serveur préparera les données pour le client, l'appareil client collectera tout ensemble et les affichera à l'utilisateur.Configuration du serveur proxy, HTTP / 2, gzip, cache
Votre application dorsale ne doit pas communiquer directement avec le client, il est préférable de la cacher derrière des portes spécialisées, par exemple, le serveur proxy Nginx. Et sur celui-ci, vous pouvez déjà configurer tout ce qui est nécessaire pour une communication confortable entre l'appareil client et le serveur.- SSL. SSL , , , Nginx. Nginx Asp.Net Core , .
- GZIP . .
- Cache . Get, Head , .
- .
Encore une fois, en raison du fait que cette partie mérite un article séparé, je ne décris pas en détail le processus de configuration complet, mais je recommande un site pour générer la configuration nginx nginxconfig.io .SEO
Créez des balises META en html et utilisez le balisage sémantique
Tout le monde le sait déjà et, en règle générale, il l'utilise. Par conséquent, pour y remédier, il suffit de regarder la liste des commentaires de Lighthouse et de la corriger.La fin
À première vue, il peut sembler que beaucoup d'informations sont écrites ici, ce qui est difficile à observer, mais en fait ce n'est pas le cas. Toutes ces informations reflètent l'état actuel du développement frontal et le respect de toutes ces règles ne prend presque pas de temps.Cet article ne décrit pas comment optimiser la zone d'administration, le formulaire et les autres entreprises, mais ce sera la deuxième partie.