404 mates.ai
Développement web

Comment Baseline vous aide à expédier moins de JavaScript

Entre "il faut une lib pour ça" et "le navigateur le fait nativement", l'écart se réduit. Un guide pour auditer ses dépendances par clusters et retrouver ce que la plateforme web peut désormais prendre en charge.

Profil éditorial · Développement web

Ninja Span

En bref

  • Dans une app JS de taille moyenne, on trouve souvent entre 60 et 90 KB de dépendances (minifiées et gzippées) que le navigateur peut aujourd'hui gérer nativement.
  • Baseline est un projet du WebDX Community Group qui indique, en trois états (Limited, Newly available, Widely available), à quel point une fonctionnalité web est sûre à utiliser dans les navigateurs majeurs.
  • Le cluster internationalisation (timeago.js, numeral, pluralize, humanize-duration) représente à lui seul environ 14 KB remplaçables par les APIs Intl.* déjà Widely available — à l'exception de Intl.DurationFormat, seulement Newly available.
  • axios et superagent (~17–19 KB gz) sont remplaçables par fetch + AbortController pour les cas simples, mais les intercepteurs, les retries et la progression d'upload restent à implémenter soi-même.
  • Les primitives UI modales, popovers et focus-trap ont des équivalents natifs (<dialog>, Popover API, CSS anchor positioning) souvent plus accessibles que les solutions maison.
Sommaire7 sections

60 à 90 KB de dépendances qui n'ont plus vraiment de raison d'être là

La plupart des équipes installent une dépendance une fois, les tests passent, et personne ne revient dessus. Le problème, c'est que la plateforme web a continué d'avancer. Dans une app JS de taille moyenne, Jad Joubran (consultant JavaScript et web performance) estime qu'on trouve couramment entre 60 et 90 KB minifiés et gzippés de dépendances que le navigateur sait désormais gérer nativement.

Ce n'est pas une question de négligence. C'est que la plupart des équipes n'effectuent pas de ré-audit sur un rythme Baseline, et que la question "est-ce que cette lib fait encore quelque chose que le navigateur ne sait pas faire ?" est rarement posée. npm audit vérifie les failles de sécurité, pas l'obsolescence fonctionnelle.

L'article de Smashing Magazine propose de combler ce manque avec un audit structuré par clusters — parce que les gains tendent à arriver en groupes — accompagné d'un cadre de décision réutilisable.

Ce que "Baseline" signifie concrètement

Baseline est un projet du WebDX Community Group qui classe chaque fonctionnalité web en trois états :

  • Limited availability : pas encore disponible dans tous les moteurs majeurs. Ne pas utiliser sans fallback.
  • Baseline Newly available : disponible dans tous les moteurs majeurs (Chrome, Edge, Firefox, Safari). Fonctionne pour les utilisateurs à jour, mais les appareils plus anciens peuvent ne pas l'avoir.
  • Baseline Widely available : disponible dans tous les moteurs majeurs depuis 30 mois. Utilisable sans réserve dans la grande majorité des cas.

La distinction entre Newly et Widely est le cœur de l'audit : une feature Widely available justifie de supprimer la lib aujourd'hui ; une feature Newly available demande de vérifier son audience ou d'ajouter un feature check.

Pour vérifier le statut d'une feature : webstatus.dev, les badges Baseline sur MDN, ou le package npm web-features.

Un cadre de décision avant de supprimer quoi que ce soit

Avant de toucher à une dépendance, trois questions à poser systématiquement :

  1. Le remplacement est-il Baseline-safe pour mon audience ? Pas dans l'absolu, mais pour les utilisateurs réels de l'app. Un dashboard B2B sur navigateurs récents, c'est différent d'un site public avec une longue traîne d'Android anciens.
  2. Quel est le vrai coût du swap ? Si la feature native nécessite un polyfill plus lourd que la lib supprimée et qu'il est chargé inconditionnellement, le bundle grossit. L'article illustre ce cas avec Intl.DurationFormat.
  3. La feature native couvre-t-elle mon usage réel ? Les libs font souvent plus que leur équivalent natif. axios n'est pas juste fetch avec le JSON auto-parsé — il a des intercepteurs, des retries, de la gestion des erreurs HTTP. Auditer l'usage avant d'assumer que c'est un drop-in replacement.

Cluster 1 : internationalisation (le gain le plus immédiat)

C'est là que se concentrent le plus de KBs remplaçables sans effort particulier. Le navigateur expose toute une famille d'outils sous le namespace Intl, et plusieurs libs populaires en deviennent inutiles :

LibPoids gzRemplacement natifStatut Baselinetimeago.js1 KBIntl.RelativeTimeFormatWidely availablepluralize2,3 KBIntl.PluralRulesWidely availablenumeral3,9 KBIntl.NumberFormatWidely availablehumanize-duration6,6 KBIntl.DurationFormatNewly availablelist-joining helpersvariableIntl.ListFormatWidely available

Un exemple concret avec Intl.RelativeTimeFormat :

const rtf = new Intl.RelativeTimeFormat("en", { numeric: "auto" });
rtf.format(-1, "day"); // "yesterday"
rtf.format(3, "hour"); // "in 3 hours"

L'option numeric: "auto" donne "yesterday" plutôt que "1 day ago" quand la langue le permet. La seule chose que timeago.js fait en plus : choisir l'unité automatiquement à partir d'un timestamp brut. C'est quelques lignes d'arithmétique à écrire une fois, pas une raison de garder la lib.

Le cas particulier de Intl.DurationFormat : cette API est Baseline Newly available au moment de la publication, pas Widely available. Elle a atterri dans tous les moteurs majeurs en mars 2025 et devrait passer en Widely available en 2027. Pour une app publique avec des appareils anciens, il vaut mieux attendre ou conditionner l'usage à un feature check. Pour un outil interne sur navigateurs modernes, c'est utilisable maintenant.

Au total, si une app utilise les quatre libs ci-dessus, c'est environ 14 KB gzippés de dépendances à supprimer — essentiellement sans compromis pour la majorité des projets.

Cluster 2 : clients HTTP

Ce cluster est plus nuancé. axios (17 KB gz) et superagent (19 KB gz) couvrent des usages que fetch + AbortController — tous deux Widely available — ne couvrent pas toujours d'emblée.

Pour un GET basique, la différence est minime :

// axios
const { data } = await axios.get("/api/users");

// fetch
const res = await fetch("/api/users");
const data = await res.json();

La ligne supplémentaire avec fetch traduit un choix de design : fetch est explicite là où axios était implicite. Pour les timeouts, AbortSignal.timeout() remplace l'option native d'axios :

const res = await fetch("/api/users", {
signal: AbortSignal.timeout(5000),
});

Les cas où fetch ne remplace pas axios :

  • Gestion des erreurs HTTP : une 404 ou 500 est une promesse résolue avec fetch, pas un rejet. Il faut vérifier res.ok manuellement.
  • Intercepteurs : axios permet d'attacher des tokens d'auth ou de gérer les 401 en un seul endroit. Fetch n'a pas d'équivalent natif — il faut wrapper fetch dans une classe ou une fonction.
  • Retries automatiques : fetch ne les gère pas, c'est du code à écrire.
  • Progression d'upload : fetch ne peut pas reporter la progression d'un upload de fichier en temps réel.

L'auteur note qu'il s'appuie lui-même sur une classe custom au-dessus de fetch pour ses cours interactifs, déployée pour des millions d'utilisateurs. Ce n'est pas un obstacle — mais ce n'est pas non plus un swap transparent. Auditer comment le client HTTP est réellement utilisé avant de toucher quoi que ce soit.

Cluster 3 : primitives UI

C'est peut-être le cluster avec les swaps les plus satisfaisants, parce que les alternatives natives sont souvent plus accessibles que ce que les équipes implémentent à la main.

Les cibles :

  • Modals (ex. a11y-dialog, 1,8 KB gz) → élément <dialog>
  • Tooltips/popovers (ex. tippy.js, 14 KB gz, qui embarque Popper) → Popover API
  • focus-trap (6,6 KB gz) → comportement natif de <dialog>
  • body-scroll-lock (1,3 KB gz) → comportement natif de <dialog>

L'élément <dialog> (Widely available) règle d'un coup les problèmes d'accessibilité classiques des modals : piégeage du focus dans la modale, fermeture sur Escape, restauration du focus vers l'élément précédent, rendu au-dessus du reste. Ce sont exactement les cas que les libs comme a11y-dialog ou focus-trap existaient pour résoudre.

<dialog id="confirm">
<form method="dialog">
<p>Delete this file?</p>
<button value="cancel">Cancel</button>
<button value="delete">Delete</button>
</form>
</dialog>

const dialog = document.querySelector("#confirm");
dialog.showModal();

Le formulaire avec method="dialog" permet à chaque bouton de fermer la modale en retournant sa valeur — sans JavaScript supplémentaire pour gérer la fermeture.

Pour les popovers et tooltips, la Popover API et le CSS anchor positioning prennent en charge le positionnement que Popper (embarqué dans tippy.js) gérait auparavant. L'article signale ces features comme les équivalents natifs, sans préciser leur statut Baseline exact — il convient de le vérifier sur webstatus.dev avant de supprimer tippy.js sur un projet à audience large.

À vérifier avant d'adopter

L'article de Smashing Magazine est bien documenté et honnête sur ses propres limites, mais quelques points méritent un regard critique avant de lancer l'audit sur un projet en production :

  • Le statut Baseline n'est indiqué que pour certaines features : Intl.DurationFormat est explicitement signalé Newly available, mais le statut de la Popover API ou du CSS anchor positioning n'est pas précisé dans le texte. Ces features sont plus récentes — vérifier leur statut réel sur webstatus.dev pour chaque audience cible.
  • Les 60–90 KB sont une estimation sur un profil type : votre package.json peut s'en éloigner significativement selon les libs utilisées. L'audit par clusters reste pertinent, mais le chiffre ne vaut que comme ordre de grandeur.
  • Le framework de l'app n'est pas abordé : les implications peuvent différer si la lib est consommée via un framework qui optimise ou tree-shake déjà certaines dépendances.

Source : Jad Joubran, How Baseline Can Help You Ship Less JavaScript, Smashing Magazine, 7 août 2026 — lire l'article

Lecture 404 Mates

Le principal apport de cet article pour les builders et les agences, c'est de formaliser une pratique qui n'existe presque jamais : l'audit de dépendances sur un critère fonctionnel, pas seulement sécuritaire. La plupart des équipes ont un process pour npm audit, aucune n'a de process pour "est-ce que cette lib est devenue redondante avec la plateforme ?"

Concrètement, le cluster internationalisation est actionnable immédiatement sur la quasi-totalité des projets : Intl.RelativeTimeFormat, Intl.NumberFormat, Intl.ListFormat et Intl.PluralRules sont Widely available, et les libs correspondantes (timeago.js, numeral, pluralize) traînent dans beaucoup de codebases sans qu'on les remarque. C'est le type de gain qui n'allonge pas le temps de dev et qui réduit la surface de maintenance.

Le cluster HTTP clients est celui qui demande le plus de discernement. La décision de remplacer axios dépend directement de l'usage réel — et c'est exactement le cas où une agence qui livre des projets récurrents aurait intérêt à documenter son propre wrapper fetch une fois pour toutes, plutôt que de réinstaller axios par défaut sur chaque nouveau projet.

Le cluster UI est intéressant aussi sur l'axe accessibilité : <dialog> natif étant Widely available, il n'y a plus vraiment d'argument pour shipper focus-trap ou body-scroll-lock dans un projet qui utilise des modals standard. C'est du code en moins à maintenir, et un comportement accessible par défaut — ce qui a une valeur directe pour les agences qui doivent livrer des projets conformes RGAA/WCAG sans overhead.

Poursuivez votre lecture

Tout afficher