Thème PrestaShop : passer à Hummingbird sans jQuery, focus accessibilité

Guide pratique pour passer un thème PrestaShop 9.x à Hummingbird en éliminant jQuery : audit modules, remplacement par JS moderne, focus accessibilité, performance (INP) et tests CI.

Deux écrans d'ordinateur montrant du code pour le développement de thèmes PrestaShop.

Table des matières :

  1. Périmètre technique : Hummingbird (PrestaShop 9.x) et stratégie « no jQuery »
  2. Cartographier les dépendances jQuery (thème, modules, overrides) avant de couper
  3. Couper jQuery proprement : désenregistrer, isoler, puis éliminer
  4. Remplacer les patterns jQuery par du JavaScript moderne (vanilla) dans un thème PrestaShop
  5. Accessibilité : focus sur les zones PrestaShop qui cassent le plus vite
  6. Performance : retirer jQuery ne suffit pas, il faut piloter INP et le coût JS total
  7. Outillage de tests : a11y, régressions UI, et déploiement progressif

Périmètre technique : Hummingbird (PrestaShop 9.x) et stratégie « no jQuery »

Sur PrestaShop 9.x (9.1/9.2 au moment d’écrire ces lignes) avec PHP 8.3, « passer à Hummingbird » signifie, dans la pratique, migrer vers un thème front plus moderne que Classic, pensé pour réduire le legacy JavaScript (dont jQuery) et mieux s’aligner sur un build toolchain actuel. Ça ne veut pas dire que votre boutique devient magiquement « jQuery-free » : le cœur et surtout l’écosystème modules continuent d’injecter des scripts, parfois en inline, parfois via addJquery()/registerJavascript().

Le point clé : un objectif « sans jQuery » n’est pas un dogme esthétique, c’est une contrainte d’architecture front. Vous gagnez en surface d’attaque (moins de dépendances), en maintenabilité (moins de plugins implicites et de “magie” autour de $.fn.*) et en performance perçue (moins de JS qui monopolise le main thread). Mais vous devez prévoir une phase de cohabitation : le temps d’éradiquer les dépendances côté modules et de stabiliser les composants interactifs.

Pour cadrer les risques, partez du principe qu’un passage Hummingbird + suppression jQuery est une migration de thème (avec impacts hooks, overrides, assets, régressions UI) avant d’être une « optimisation front ». Concrètement, les régressions les plus coûteuses sont rarement “jQuery a disparu”, mais plutôt :

  • un hook déplacé/supprimé → module non exécuté (tracking, badges, prix…),
  • un changement de markup → sélecteurs CSS/JS de modules cassés,
  • un template rendu différemment → SEO technique (données structurées, balisage des titres, liens de pagination) impacté,
  • une interaction “refaite” → focus, clavier, lecteurs d’écran dégradés.

La checklist d’audit thème/modules/hooks/overrides est un bon point d’entrée pour éviter de casser des pages critiques (panier, checkout, facettes) : Migration PrestaShop : checklist d’audit thème, modules, hooks et overrides. Pour le contexte Hummingbird côté PrestaShop 9, référez-vous aussi à : PrestaShop 9 : nouveautés Symfony 6.4, Hummingbird et API Platform.

Cartographier les dépendances jQuery (thème, modules, overrides) avant de couper

Le problème récurrent n’est pas « jQuery dans le thème », mais jQuery dans les modules : facettes, avis, checkout, tracking, sliders, quickview, etc. La première étape est donc une cartographie factuelle : quelles pages chargent jquery*.js, qui le charge, et qui appelle $() en runtime. Faites-le en staging, avec une config identique à la prod (mêmes modules, mêmes overrides, même cache), idéalement via un environnement Docker fidèle : Staging PrestaShop : créer un environnement Docker fidèle à la production.

Méthode rapide côté navigateur :

  • Onglet Network : filtrer jquery et repérer le referrer (bundle du thème vs module).
  • Onglet Sources : rechercher $(document).ready, $.ajax, $.fn..
  • Onglet Console : activer « pause on exceptions » et simuler la navigation (homepage → catégorie avec facettes → fiche produit → ajout panier → checkout).
  • (Bonus très utile) DevTools → Coverage : repérer les fichiers JS chargés mais très peu exécutés (souvent le signe d’un chargement global inutile via displayHeader).

Méthode plus robuste côté codebase :

  • Grep dans /modules et /themes : \$\(, jQuery, addJquery, jquery-ui, slick, etc.
  • Vérifier les hooks d’injection front (displayHeader, displayFooter, actionFrontControllerSetMedia) et les overrides de FrontController::setMedia() si vous en avez.
  • Documenter page par page quelles dépendances sont réellement nécessaires (pas “installées”, mais utilisées).

Un format simple qui évite de se mentir est un tableau d’inventaire. Exemple minimal (à remplir avec vos IDs d’assets réels) :

Page (php_self) Scripts suspects Source probable Criticité Plan
category jquery, jquery-ui, facetedsearch.js ps_facetedsearch Haute Remplacement AJAX + events
product slick, zoom module slider Moyenne CSS scroll-snap / lib légère
order jquery, validation checkout Critique Coexistence temporaire

C’est ici que l’audit « migration » est utile, parce qu’un override oublié peut réintroduire jQuery sans que le thème le sache. Sur PrestaShop 9.2, le sujet des overrides reste sensible (compatibilité, tests, collisions) : PrestaShop 9.2 : bonnes pratiques d’override et tests de compatibilité.

Couper jQuery proprement : désenregistrer, isoler, puis éliminer

Dans l’idéal, la suppression se fait en deux temps : (1) désenregistrer jQuery là où il est injecté globalement, (2) réintroduire jQuery uniquement sur les pages/modules legacy qui n’ont pas encore été refactorés. Cette stratégie vous évite de bloquer tout le chantier parce qu’un module tiers (que vous ne contrôlez pas) dépend de $.fn.modal ou de $.ajax.

Sur PrestaShop 1.7+ (donc 8/9), les contrôleurs exposent généralement registerJavascript() et, selon version, unregisterJavascript(). Le point d’accroche le moins intrusif est souvent hookActionFrontControllerSetMedia. Exemple minimal dans un module “tech” interne (à adapter selon vos IDs d’assets réels) :

public function hookActionFrontControllerSetMedia(array $params)
{
    $c = $this->context->controller;

    // Désenregistrement global (si supporté par la version)
    if (method_exists($c, 'unregisterJavascript')) {
        $c->unregisterJavascript('jquery');
        $c->unregisterJavascript('jquery-migrate');
    }

    // Ré-activation conditionnelle pour une page/module legacy
    if ($this->context->controller->php_self === 'category') {
        // Exemple: facettes legacy qui requiert encore jQuery
        $c->registerJavascript(
            'vendor-jquery',
            'modules/yourmodule/views/js/jquery.min.js',
            ['position' => 'bottom', 'priority' => 10]
        );
    }
}

Deux détails pratiques qui font gagner du temps en migration :

  • Loggez le “qui casse” : en staging, vous pouvez volontairement retirer jQuery et capturer les erreurs JS (console + monitoring) pour identifier les modules responsables. Ça transforme un ressenti (“ça ne marche plus”) en liste actionnable (“ce module appelle $().something() sur product + category”).
  • Évitez l’effet domino : si vous acceptez une phase de coexistence, imposez une règle stricte : jQuery ne revient que si une dépendance est documentée et planifiée. Sinon, elle revient “temporairement”… pour toujours.

Si vous ne pouvez pas désenregistrer (méthode absente) ou si un module réinjecte après coup, vous êtes dans un cas « cœur + modules indisciplinés ». Deux options réalistes : (a) patcher le module (fork interne) pour remplacer ses patterns jQuery, (b) accepter jQuery mais limiter son périmètre (pages ciblées). La voie (a) est celle qui tient dans la durée, surtout si vous visez des budgets INP stricts — et que, à chaque mise à jour de modules, vous voulez éviter de rejouer la même négociation.

Remplacer les patterns jQuery par du JavaScript moderne (vanilla) dans un thème PrestaShop

Les remplacements sont mécaniques, mais la difficulté est ailleurs : gérer les contenus dynamiques (DOM réinjecté après AJAX, facettes qui rechargent une grille produit, mini-panier mis à jour) sans retomber dans les anti-patterns. Sur PrestaShop, beaucoup d’interactions reposent sur des événements “globaux” (historiquement via jQuery). L’objectif est de basculer vers CustomEvent + délégation d’événements, avec des handlers idempotents (qu’on peut exécuter plusieurs fois sans effets de bord).

Équivalences courantes (vous les verrez partout dans des modules) :

  • $(document).ready(fn) → document.addEventListener('DOMContentLoaded', fn)
  • $('.btn').on('click', fn) → délégation :
document.addEventListener('click', (e) => {
  const btn = e.target.closest('[data-action="add-to-cart"]');
  if (!btn) return;
  e.preventDefault();
  // ...
});
  • $.ajax({ url, method, data }) → fetch(url, { method, body, headers }) avec URLSearchParams ou FormData selon le backend.

Le point crucial en PrestaShop : préserver les contrats d’événements attendus par d’autres briques. Si votre shop (ou vos modules) attend prestashop.emit('updateCart', payload), conservez l’API quand elle existe ; sinon, exposez un fallback standard :

export function emitPS(eventName, detail = {}) {
  if (window.prestashop?.emit) {
    window.prestashop.emit(eventName, detail);
    return;
  }
  document.dispatchEvent(new CustomEvent(eventName, { detail }));
}

Un mini-scénario typique où la migration échoue si on reste “au niveau syntaxe” : vous remplacez $('.js-search-filters input').change(...) par un listener direct sur chaque input. Puis ps_facetedsearch remplace le bloc HTML après une interaction. Résultat : les listeners disparaissent. La solution robuste est la délégation (un seul listener sur un conteneur stable), ou une ré-initialisation déclenchée par événement après rendu (ex. événement “filtersUpdated”).

Côté UI, évitez de remplacer jQuery par « plus de JS ». Beaucoup d’interactions se font aujourd’hui en CSS moderne (menus, accordéons simples, états :focus-visible, :has() selon support) avec une meilleure robustesse. Et pour tout ce qui touche au confort utilisateur : pensez à prefers-reduced-motion (réduire les animations), souvent bénéfique à la fois en accessibilité et en performance. Pour des patterns concrets (et une approche orientée performance), voir : CSS moderne : remplacer JavaScript pour interactions UI et performance.

Accessibilité : focus sur les zones PrestaShop qui cassent le plus vite

L’accessibilité ne se “rajoute” pas après coup : elle découle de la structure HTML, du focus management, et de la cohérence des états (visible/hidden/expanded). Tim Berners-Lee (W3C) résume l’enjeu sans ambiguïté : « The power of the Web is in its universality. Access by everyone regardless of disability is an essential aspect. » (W3C WAI, citation attribuée à Tim Berners-Lee, affichée sur les pages WAI).

Sur un thème PrestaShop, les régressions a11y apparaissent surtout quand on refait les composants interactifs en JS. En France, si vous cherchez un référentiel opérationnel et des tests concrets (y compris sur les composants), le RGAA est une bonne grille de lecture en complément des WCAG : https://accessibilite.numerique.gouv.fr/ (Direction interministérielle du numérique).

Trois zones à traiter en priorité dans un passage à Hummingbird sans jQuery :

1) Navigation (header, menus, dropdowns) : si vous implémentez des menus “riches”, suivez les patterns WAI-ARIA Authoring Practices (APG) et évitez les “menu bars” artificiels si un simple <nav><ul><li><a> suffit. Un dropdown doit avoir un bouton réel (<button>) avec aria-expanded, et les éléments masqués doivent être réellement non focusables (pas juste opacity:0). Référence : https://www.w3.org/WAI/ARIA/apg/.

Check rapide (très révélateur) : faites un parcours clavier uniquement (Tab/Shift+Tab/Entrée/Espace/Echap). Si vous ne pouvez pas atteindre les sous-catégories, ou si le focus “disparaît”, la nav est à reprendre. Ajoutez aussi un lien d’évitement (“Aller au contenu”) en haut de page : c’est simple, et ça améliore immédiatement l’expérience sur les longs headers.

2) Facettes / filtres (ex. ps_facetedsearch) : le rechargement partiel doit annoncer un changement de contenu via une zone aria-live="polite" (ex. “24 produits affichés”). Sans ça, vous créez un UI “silencieux” pour lecteurs d’écran. Attention aussi au focus : après un refresh AJAX, ne renvoyez pas le focus en haut de page ; conservez-le sur le contrôle actionné.

Un pattern efficace en e-commerce : placer le aria-live près du titre de la liste produit et mettre à jour un texte court (nombre de résultats + catégorie). Ça aide aussi certains utilisateurs mobiles qui “perdent le contexte” après un re-render.

3) Panier / checkout : les erreurs de formulaire doivent être reliées au champ (aria-describedby), et les messages doivent être dans le flux DOM (pas uniquement dans une toast). Les composants modaux (ex. login popup, CGV) sont un nid à bugs : il faut piéger le focus à l’intérieur, fermer au clavier (Esc), et restaurer le focus sur l’élément déclencheur. Si vous utilisez <dialog>, testez les comportements mobiles et prévoyez une alternative si le support est incomplet (référence : MDN https://developer.mozilla.org/docs/Web/HTML/Element/dialog).

Pour cadrer votre définition de “done”, alignez-vous sur WCAG 2.2 (W3C) et mappez vos composants sur des critères concrets (focus visible, erreurs, navigation, changement de contexte, etc.) : https://www.w3.org/TR/WCAG22/. En 2026, ce n’est pas un “nice to have” : en Europe, l’European Accessibility Act est applicable depuis le 28 juin 2025 et beaucoup de parcours e-commerce (création de compte, paiement, SAV) peuvent entrer dans le champ selon l’organisation et le marché visé. L’intérêt pratique : une démarche a11y sérieuse réduit aussi les risques de régressions UX lors d’une migration de thème, parce qu’elle impose des règles stables (labels, focus, états).

Performance : retirer jQuery ne suffit pas, il faut piloter INP et le coût JS total

Supprimer jQuery ne fait pas gagner une seconde à lui seul. Le gain réel est indirect : moins de dépendances implicites, moins de listeners globaux, moins de code legacy qui se déclenche sur chaque interaction. C’est particulièrement pertinent avec INP (Interaction to Next Paint), qui mesure la réactivité globale aux interactions. web.dev (Google) définit le scope ainsi : « Interaction to Next Paint (INP) is a Core Web Vitals metric that assesses a page’s overall responsiveness to user interactions. » (source : https://web.dev/inp/).

Sur PrestaShop, le coût JS est souvent dominé par :

  • modules tiers qui chargent un bundle sur toutes les pages (mauvaise utilisation de displayHeader),
  • scripts de tracking (souvent injectés en inline, sans defer, et parfois multipliés par tags),
  • carrousels et “quickview” lourds,
  • reflows causés par des manipulations DOM non batchées (lecture/écriture alternées : layout thrashing),
  • “features” invisibles mais coûteuses (listeners scroll, timers, observers mal nettoyés).

Votre objectif « Hummingbird sans jQuery » doit donc inclure des règles simples : (1) JS par page (conditionnel), (2) defer/type="module" quand possible, (3) réduction des DOM mutations, (4) suppression des effets non essentiels.

Une approche opérationnelle (facile à suivre en équipe) est de définir un mini-budget par type de page :

  • Home / catégorie : JS minimal, car c’est souvent du trafic SEO.
  • Produit : JS autorisé, mais seulement si ça sert conversion (images, variations, panier).
  • Checkout : priorité absolue à la robustesse + accessibilité ; toute librairie “cosmétique” est suspecte.

Le caching et la concaténation natifs restent utiles mais ne règlent pas l’architecture front : PrestaShop : optimiser performance via cache Smarty, CCC et CDN et, côté infra, si vous poussez fort les assets statiques, choisissez un CDN en connaissance de cause : Comparatif CDN pour accélérer les assets PrestaShop.

Dernier point : ne confondez pas “front rapide” et “TTFB bas”. Les migrations de thème déclenchent souvent des régressions back (hooks plus lourds, templates plus bavards, surcharges de requêtes). Gardez un diagnostic séparé TTFB vs rendu : PrestaShop lent : diagnostic TTFB, bots et optimisation serveur.

Outillage de tests : a11y, régressions UI, et déploiement progressif

Sans tests, une migration Hummingbird + suppression jQuery est un pari. En 2026, le minimum viable côté qualité front, c’est : (1) E2E sur les parcours business (recherche → produit → panier → paiement), (2) audit a11y automatisé, (3) budget de perf (Lighthouse/INP) en CI.

Axe-core est la base la plus répandue pour l’automatisation (https://github.com/dequelabs/axe-core) ; Pa11y est pratique en CI pour des checks simples (https://github.com/pa11y/pa11y). Gardez néanmoins une règle simple : l’a11y automatisée détecte une partie des problèmes (labels, rôles, contrastes parfois), mais pas les erreurs d’expérience (ordre de focus, logique des composants, annonces live pertinentes). Prévoyez donc un test manuel court et systématique sur les pages critiques (header, facettes, mini-panier, checkout).

Concrètement : utilisez Playwright ou Cypress pour vos flows, et branchez axe sur les pages sensibles. Exemple (Playwright + axe) : vous bloquez la PR si vous introduisez un aria-* invalide, un champ sans label, ou un contraste catastrophique. Ajoutez aussi un test de non-régression “DOM” (ex. présence de data-action="add-to-cart", structure du mini-panier) car beaucoup de modules ciblent ces sélecteurs : ce n’est pas “élégant”, mais c’est réaliste dans l’écosystème PrestaShop.

Pour industrialiser, intégrez ces checks dans votre pipeline de livraison. Le site a déjà un article orienté CI/CD PrestaShop, utile pour structurer un workflow avec environnements éphémères : PrestaShop CI/CD : générer des démos à la demande en minutes. Et si vous déployez progressivement (feature flag par thème, split trafic), gardez un plan de rollback simple : la migration de thème est l’un des rares changements capables de casser simultanément UX, SEO technique (rendu HTML) et conversion.

Enfin, ne sous-estimez pas la sécurité : moins de JS tiers, c’est aussi moins de risques de supply chain et d’injections. Sans tomber dans la parano, un scan “boîte noire” régulier permet de repérer des injections et surfaces inutiles exposées : Wapiti : scanner open source de vulnérabilites web en boîte noire. Le résultat attendu d’un chantier « Hummingbird sans jQuery, focus accessibilité », ce n’est pas une page plus “propre” dans l’absolu : c’est un front plus prévisible, testable, et conforme (a11y + Core Web Vitals) malgré la réalité d’un écosystème modules hétérogène.


À lire aussi