Javascript Responsable : 1ère partie

Publié le , par Fredéric Pineau
Responsable

No Fucking JS Spirit

Préambule

JavaScript Responsable est la formulation de Jeremy Wagner, consultant en web performance du Minnesota, qui est certes moins provocatrice que notre No Fucking JS Spirit mais dont la finalité reste la même : remettre en cause la façon dont nous utilisons JavaScript.

Et là, il s’agit vraiment d’une quête de sens. C’est donc avec la prétention que “coder c’est politique” que nous souhaitions promouvoir en français le message et les bonnes pratiques en terme d’intégration web fournies par cette série d’articles sur le JavaScript Responsable.

Bonne lecture.

Introduction

Selon les chiffres, JavaScript a un impact négatif sur la performance. Si la tendance se confirme, la page moyenne expédiera au moins 400 ko d’ici peu de temps, et cela seulement pour ce qui est transféré. Comme les autres ressources textes, JavaScript est presque toujours donné compressé, mais c’est peut-être bien la seule chose pour laquelle nous obtenons toujours de bons résultats dans son transfert.

Malheureusement, bien que la réduction du temps de transfert des ressources soit un élément important de cette performance, la compression n’a aucun effet sur le temps de traitement d’un script par les navigateurs une fois qu’il est arrivé dans son intégralité. Si un serveur envoie 400 ko de JavaScript compressé, la quantité réelle que les navigateurs doivent traiter après décompression est plus proche d’un mégaoctet. La capacité des appareils à faire face à ces lourds chargements dépend en fait de l’appareil. Beaucoup de choses ont été écrites sur la façon dont les différents appareils traitent beaucoup de JavaScript, mais en vérité, la quantité de temps qu’il faut pour traiter même une quantité insignifiante de celui-ci varie considérablement entre les appareils.

Prenons, par exemple, mon projet jetable, qui expédie environ 23 ko de JavaScript non compressé. Sur un MacBook Pro datant de mi-2017, Chrome charge ce fichier plutôt petit en environ 25 ms. Sur un téléphone Android Nokia 2, cependant, ce chiffre augmente pour atteindre environ 190 ms. Ce n’est pas une quantité de temps insignifiante, mais dans les deux cas, la page devient interactive assez rapidement.

Il est temps de se poser la vraie question : comment pensez-vous que ce petit Nokia 2 fait pour une page de poids moyen ? Il s’étouffe. Même avec une connexion rapide, naviguer sur le Web est un exercice de patience car les pages Web chargées de JavaScript le bloquent durant des périodes de temps considérables.

Performances d'un téléphone Android Nokia 2
Figure 1. Une vue d’ensemble de la chronologie des performances d’un téléphone Android Nokia 2 naviguant sur une page où l’excès de JavaScript monopolise le processus principal.

Bien que les appareils et les réseaux sur lesquels ils naviguent sur le Web s’améliorent grandement, la tendance montre que nous mangeons ces gains. Nous devons utiliser JavaScript de manière responsable ; faire du JavaScript responsable ! Cela commence par la compréhension de ce que nous construisons ainsi que de comment nous le construisons.

L’état d’esprit des “sites” par rapport aux “applications”

La nomenclature peut être étrange dans la mesure où nous identifions parfois vaguement des choses avec des termes qui sont inexacts, et pourtant leur signification est implicitement comprise par tous. Parfois, nous utilisons le terme “abeille” pour signifier également “guêpe”, même si les différences entre abeilles et guêpes sont importantes. Ces différences peuvent vous motiver à faire face à elles différemment. Par exemple, nous voudrions détruire un nid de guêpes, mais comme les abeilles sont des insectes très utiles et vulnérables, nous pourrions choisir de les déplacer.

Nous pouvons être tout aussi rapides et lâches en interchangeant les termes “site web” et “application web”. La différence entre les deux est moins claire que celle entre les guêpes et les abeilles, mais les confondre peut aussi entraîner des résultats douloureux. La douleur vient des moyens que nous nous permettons lorsque quelque chose n’est qu’un “site web” au lieu d’une véritable “application web”. Si vous créez un site Web d’information pour une entreprise, vous êtes moins susceptible de vous appuyer sur un framework puissant pour gérer les changements dans le DOM ou mettre en œuvre un routage côté client, du moins, je l’espère. L’utilisation d’outils si peu adaptés à la tâche serait non seulement préjudiciable pour les personnes qui utilisent ce site, mais également moins productif.

Attention cependant lorsque nous construisons une application web. Nous installons des packages qui introduisent des centaines, voire des milliers, de dépendances, dont nous ne sommes même pas certains qu’elles soient sûres. Nous sommes également en train d’écrire des configurations compliquées pour des module bundlers. Dans cet environnement de développement frénétique, il faut des connaissances et de la vigilance pour s’assurer que ce qui est construit est rapide et accessible. Si vous en doutez, lancez npm ls –prod dans le répertoire racine de votre projet et voyez si vous reconnaissez tout ce qui est dans cette liste. Même si c’est le cas, cela ne tient pas compte des scripts tiers – dont je suis sûr que votre site en possède au moins quelques-uns.

Ce que nous avons tendance à oublier, c’est que l’environnement occupé par les sites Web et les applications Web est le même. Tous deux sont soumis aux mêmes pressions environnementales imposé par l’important éventail de réseaux et d’appareils. Ces contraintes ne disparaissent pas soudainement lorsque nous décidons d’appeler ce que nous construisons des “applications”, et les téléphones de nos utilisateurs n’acquièrent pas de nouveaux pouvoirs magiques lorsque nous le faisons.

Il est de notre responsabilité d’estimer qui utilise ce que nous faisons et d’accepter que les conditions par lesquelles ils accèdent à Internet peuvent être différentes de ce que nous avons supposé. Nous avons besoin de connaître le but que nous essayons de servir, et ce n’est qu’à ce moment-là que nous pourrons construire quelque chose qui sert admirablement ce but, même si cela n’est pas excitant à construire.

Cela signifie que nous devons réévaluer notre dépendance à l’égard de JavaScript et la façon dont son utilisation – en particulier l’exclusion du HTML et du CSS – peut nous inciter à adopter des modèles non viables qui nuisent aux performances et à l’accessibilité.

NDT : Bref faire du JavaScript Responsable et appliquer le No Fucking JS Spirit.

Ne laissez pas les frameworks vous forcer à adopter des modèles non viables

J’ai été le témoin de certaines découvertes étranges dans le code source lorsque je travaillais avec des équipes dépendantes des frameworks afin d’être très productives. L’une des caractéristiques communes à bon nombre d’entre eux est qu’il en résulte souvent une accessibilité et des modèles de rendement médiocres. Prenons l’exemple de ce composant React ci-dessous :


import React, { Component } from "react";
import { validateEmail } from "helpers/validation";

class SignupForm extends Component {
   constructor (props) {
      super(props);

      this.handleSubmit = this.handleSubmit.bind(this);
      this.updateEmail = this.updateEmail.bind(this);
      this.state.email = "";
   }

   updateEmail (event) {
      this.setState({
         email: event.target.value
      });
   }

   handleSubmit () {
      // If the email checks out, submit
      if (validateEmail(this.state.email)) {
      // ...
      }
   }

   render () {
      return (
         Enter your email:
         Sign Up
      );
   }
}

Il y a ici d’importants problèmes d’accessibilité :

  1. Un formulaire qui n’utilise pas un élément <form> n’est pas un formulaire. En effet, vous pourriez spécifier role= “form” dans le parent <div>, mais si vous construisez un formulaire – et cela y ressemble – utilisez un élément <form> avec les attributs action et method appropriés. L’attribut action est crucial, car il garantit que le formulaire fera toujours quelque chose en l’absence de JavaScript – à condition que le composant soit rendu par le serveur, bien sûr.
  2. Un <span> ne remplace pas un élément <label>, qui offre des avantages d’accessibilité que le <span> ne possède pas.
  3. Si on a l’intention de faire quelque chose côté client avant de soumettre un formulaire, alors on devrait déplacer l’action liée au gestionnaire onClick de l’élément <button> vers le gestionnaire onSubmit de l’élément <form>.
  4. D’ailleurs, pourquoi utiliser JavaScript pour valider une adresse email alors que HTML5 offre des contrôles de validation de formulaire dans presque tous les navigateurs depuis IE 10 ? Il est possible ici de se fier au navigateur et d’utiliser un type d’input approprié, ainsi que l’attribut required, mais il faut un peu de savoir-faire pour que cela fonctionne correctement avec la synthèse vocale.
  5. Bien qu’il ne s’agisse pas d’un problème d’accessibilité, ce composant ne repose sur aucune méthode de phase ou de cycle de vie, ce qui signifie qu’il peut être refactorisé en un composant fonctionnel sans phases, qui utilise considérablement moins de JavaScript qu’un composant React à part entière.

Sachant ces choses, nous pouvons refactoriser ce composant :


import React from "react";

const SignupForm = props => {
   const handleSubmit = event => {
      // Needed in case we're sending data to the server XHR-style
      // (but will still work if server-rendered with JS disabled).
      event.preventDefault();

      // Carry on...
   };

   return (
      <form method="POST" action="/signup" onSubmit={handleSubmit}>
         <label for="email" class="email-label">Enter your email:</label>
         <input type="email" id="email" required />
         <button>Sign Up</button>
      </form>
   );
};

Non seulement ce composant est maintenant plus accessible, mais il utilise aussi moins de JavaScript. Dans un monde qui se noie dans JavaScript en supprimer des lignes devrait être considéré comme thérapeutique. Le navigateur nous donne gratuitement beaucoup de choses, nous devrions essayer d’en profiter le plus souvent possible.

Cela ne veut pas dire que les modèles non accessibles ne se produisent seulement lorsque les frameworks sont utilisés, mais plutôt qu’une préférence exclusive pour JavaScript fera apparaître tôt ou tard des lacunes dans notre compréhension du HTML et du CSS. Ces lacunes dans nos connaissances entraîneront la plupart du temps des erreurs dont nous n’avons même pas conscience. Les frameworks peuvent être des outils utiles qui augmentent notre productivité, mais la formation continue dans les technologies Web de base est essentielle pour créer des expériences utilisables, peu importe les outils que nous choisissons d’utiliser.

Faites confiance aux plateformes web et vous irez plus loin, rapidement

Tant qu’on en est au frameworks, il faut dire que les plateformes web sont elles-mêmes des formidables frameworks. Comme nous l’avons vu plus haut, nous sommes mieux lotis lorsque nous pouvons nous fier à des modèles de balisage et à des fonctions de navigation établis. L’alternative est de les réinventer, et de subir tous les inévitables problèmes de telles entreprises, ou pire : supposer simplement que l’auteur de chaque package JavaScript que nous installons a résolu le problème de manière compréhensible et réfléchie.

Les single page applications

L’un des compromis que les développeurs sont prompts à faire est d’adopter le modèle single page application (SPA), même s’il n’est pas adapté au projet. Oui, vous obtenez de meilleures performances perçues avec le routage côté client d’un SPA, mais que perdez-vous ? La fonction de navigation du navigateur – bien que synchrone – offre une foule d’avantages. Le premier d’entre eux est que l’historique est géré selon une spécification complexe. Les utilisateurs sans JavaScript – que ce soit par leur propre choix ou non – ne perdront pas complètement l’accès. Pour que les SPAs restent disponibles quand JavaScript ne l’est pas, le rendu côté serveur devient soudainement une chose que vous devez considérer.

Client side rendering vs Server side rendering
Figure 2. Comparaison d’un exemple de chargement d’une application sur une connexion lente. L’application de gauche dépend entièrement de JavaScript pour rendre une page. L’application de droite rend une réponse sur le serveur, mais utilise ensuite l’hydratation des objets côté client pour attacher les composants au balisage existant rendu par le serveur.

L’accessibilité est également compromise si un routeur côté client ne fait pas connaître aux gens quel contenu de la page a changé. Cela peut laisser de côté ceux qui dépendent de la technologie d’assistance pour comprendre les changements qui se sont produits sur la page.

Et puis il y a notre vieil ennemi juré : la surchage. Certains routeurs côté client sont très petits, mais lorsque vous démarrez avec React, un routeur compatible et peut-être même un outil de gestion d’état, vous acceptez qu’il y a une certaine quantité de code que vous ne pourrez jamais optimiser – environ 135 ko dans ce cas. Pensez soigneusement à ce que vous construisez et si un routeur côté client vaut les compromis que vous ferez inévitablement. En général il vaut mieux s’en passer.

Si la performance de navigation perçue vous préoccupe, vous pouvez en théorie vous appuyer sur rel=prefetch pour télécharger des ressources de la même origine. Ceci a un effet spectaculaire sur l’amélioration des performances de chargement perçues des pages puisque le document est immédiatement disponible dans le cache. Les pré-téléchargements étant effectués avec une faible priorité, ils sont également moins susceptibles d’avoir à faire face à des ressources critiques pour la bande passante.

Figure 3. Le HTML pour l’écriture/URL est pré-téléchargé sur la page initiale. Lorsque l’écriture/URL est demandée par l’utilisateur, le HTML correspondant est chargé instantanément à partir du cache du navigateur.

Le principal inconvénient de la pré-extraction de liens est que vous devez être conscient qu’elle peut être potentiellement un gaspillage. Quicklink, un tout petit script de pré-extraction de liens de Google, atténue quelque peu ce problème en vérifiant si le client actuel est sur une connexion lente – ou si le mode d’économie de données est activé – et évite par défaut de pré-extraire les liens sur les origines croisées.

Les service workers sont également extrêmement bénéfiques à la performance perçue par les utilisateurs qui reviennent sur le site, que nous utilisions le routage côté client ou non, à condition que vous connaissiez les ficelles du métier. Lorsque nous précachons les itinéraires avec un service worker, nous obtenons la plupart des avantages de la pré-extraction de liens, mais avec un degré de contrôle beaucoup plus grand sur les demandes et les réponses. Que vous considériez votre site comme une “application” ou non, l’ajout d’un service worker est probablement l’une des utilisations les plus responsables de JavaScript qui existe aujourd’hui.

JavaScript n’est pas la solution à vos problèmes de mise en page

Si nous installons un package pour résoudre un problème de mise en page, procédons avec précaution et demandons-nous “qu’est-ce que j’essaie d’accomplir ? CSS est conçu pour faire ce travail et ne nécessite aucune abstraction pour être utilisé efficacement. La plupart des problèmes de mise en page que les packages JavaScript tentent de résoudre, comme le placement, l’alignement et le dimensionnement des boîtes, la gestion des débordements de texte et même des systèmes de mise en page entiers, peuvent maintenant être résolus avec CSS. Les moteurs de mise en page modernes comme Flexbox et Grid sont suffisamment bien supportés pour que nous n’ayons pas besoin de démarrer un projet avec un framework de mise en page. CSS est le framework. Lorsque nous avons des requêtes de fonctionnalités, l’amélioration progressive des mises en page pour adopter de nouveaux moteurs de mise en page n’est tout à coup pas si difficile.


/* Your mobile-first, non-CSS grid styles goes here */

/* The @supports rule below is ignored by browsers that don't
    support CSS grid, _or_ don't support @supports. */

@supports (display: grid) {
   /* Larger screen layout */
   @media (min-width: 40em) {
      /* Your progressively enhanced grid layout styles go here */

   }
}

L’utilisation de solutions JavaScript pour les problèmes de mise en page et de présentation n’est pas nouvelle. C’est ce que nous avons fait lorsque nous nous sommes menti à nous-mêmes en 2009 quand chaque site web devait être vu sur IE6 exactement comme il l’était sur les navigateurs les plus performants de l’époque. Si nous continuons à développer des sites Web pour qu’ils soient identiques dans tous les navigateurs en 2019, nous devrions réévaluer nos objectifs de développement. Il y aura toujours des navigateurs que nous devrons prendre en charge et qui ne pourront pas faire tout ce que ces navigateurs modernes et toujours plus écologiques peuvent faire. La parité visuelle totale sur toutes les plates-formes n’est pas seulement une quête vaine, c’est l’ennemi principal de l’amélioration progressive.

 

Je ne suis pas ici pour tuer JavaScript

Ne vous méprenez pas, je n’ai aucune mauvaise intention envers JavaScript. Il m’a offert une carrière et – pour être honnête avec moi-même – une source de plaisir depuis plus d’une décennie. Comme dans toute longue relation, plus je passe de temps avec JavaScript, plus j’en apprends sur lui. C’est un langage mature, riche en fonctionnalités, qui ne fait que s’améliorer d’année en année.

Pourtant, il y a des moments où nous sommes en désaccord. Je critique JavaScript. Ou peut-être plus exactement, je critique la façon dont nous avons développé une tendance à le considérer comme un premier recours à la construction pour le web. Tandis que je démonte encore un autre bundle un peu comme une boule de guirlandes de Noël emmêlées, il est devenu clair que le web est saoul de JavaScript. Nous l’utilisons pour presque tout, même lorsque l’occasion ne l’exige pas. Parfois, je me demande à quel point la gueule de bois sera vicieuse.

Dans une série d’articles sur le JavaScript Responsable à suivre, je donnerai des conseils plus pratiques pour endiguer le trop-plein de JavaScript et comment nous pouvons nous y prendre pour que ce que nous construisons pour le web soit utilisable – ou du moins plus utilisable – partout et pour tout le monde. Certains de ces conseils seront préventifs. Certaines seront des mesures d’atténuation du type “guérir le mal par le mal”. Dans un cas comme dans l’autre, les résultats seront, espérons-le, les mêmes. Je crois que nous aimons tous le Web et que nous voulons faire ce qu’il faut, mais je veux que nous réfléchissions à la manière de le rendre plus résistant et plus inclusif pour tous.

NDT : Suite de Javascript Responsable bientôt sur le blog d’artwaï.

Jeremy Wagner
Jeremy Wagner est un consultant en web performance qui fait de son mieux pour rendre le web plus rapide. Il est également l'auteur de The WebP Manual, sur le Smashing Magazine.

Un coup de fil ?

Composez votre numéro de téléphone ;
par exemple : 0612314567.

La mise en relation est
automatique et gratuite !