Le contexte

Le lecteur d'annales de baccalaureat.sn repose sur @react-pdf-viewer, monté en îlot React dans une page Twig. En reconstruisant la feature, j'ai enchaîné trois bugs distincts qui se masquaient l'un l'autre — chaque correctif révélait le suivant. Récit dans l'ordre du diagnostic.

Bug 1 — Le viewer qui refuse de démarrer : versions pdfjs-dist

Premier symptôme, dès le montage : erreur de worker et viewer vide. La cause était dans le package.json : @react-pdf-viewer/core déclare une plage stricte de versions compatibles de pdfjs-dist, et npm avait résolu une version plus récente que ce que la lib supportait.

npm ls pdfjs-dist
# └── pdfjs-dist@3.11.174   ← installé
# @react-pdf-viewer/core requiert ^2.16.105 || ^3.0.279 (API compatible)

pdf.js casse régulièrement son API interne entre versions mineures — la plage déclarée par le viewer n'est pas décorative. Correctif : épingler une version testée compatible.

npm install pdfjs-dist@3.4.120 --save-exact

Le --save-exact est volontaire : pas de ^ qui laisserait npm re-dériver vers une version incompatible au prochain install.

Bug 2 — Parfait en local, mort en prod : le worker sur CDN

Viewer fonctionnel en local... et page blanche en production. La différence : le worker pdf.js était chargé depuis unpkg.

// AVANT : dépendance runtime à un CDN externe
const WORKER_URL = 'https://unpkg.com/pdfjs-dist@3.4.120/build/pdf.worker.min.js';

En prod, entre la Content-Security-Policy du site et les aléas du CDN, le worker ne se chargeait pas — et sans worker, pdf.js ne rend rien. La solution robuste : servir le worker soi-même, depuis ses propres assets, avec Vite qui résout l'URL au build :

// APRÈS : le worker est un asset local, hashé et servi par mon propre domaine
import workerUrl from 'pdfjs-dist/build/pdf.worker.min.js?url';

<Worker workerUrl={workerUrl}>
    <Viewer fileUrl={pdfUrl} />
</Worker>

Le suffixe ?url demande à Vite de traiter le fichier comme un asset et d'en renvoyer l'URL finale. Plus de CDN tiers dans la boucle : même origine, même cache, même politique de sécurité que le reste du site.

Bug 3 — Une seule page visible, document décalé : l'overflow parent

Dernier bug, le plus sournois : le PDF s'affiche enfin, mais une seule page, impossible de défiler, et le document apparaissait décalé dans son cadre. Aucune erreur console. Le coupable n'était pas dans le viewer — il était dans mon CSS :

/* AVANT : le conteneur de la page, écrit des semaines plus tôt */
.lecteur-container {
    overflow: hidden;   /* posé « pour la propreté » du layout */
    height: 80vh;
}

@react-pdf-viewer gère son propre conteneur de scroll virtuel : il rend les pages au fur et à mesure du défilement. Un overflow: hidden sur un parent coupe ce mécanisme — le viewer croit que rien ne défile, donc ne rend jamais les pages suivantes. Correctif : retirer tout overflow: hidden des ancêtres du viewer et lui donner une hauteur explicite, puis le laisser gérer son scroll interne.

/* APRÈS : le viewer est seul maître de son défilement */
.lecteur-container {
    height: 80vh;
    /* plus d'overflow: hidden ici ni sur aucun parent du viewer */
}

Ce que je retiens

  • Les plages de versions de pdfjs-dist déclarées par @react-pdf-viewer sont strictes pour de bonnes raisons — épingler avec --save-exact évite les régressions silencieuses.
  • Un worker chargé depuis un CDN tiers est une dépendance runtime cachée : en prod, CSP et disponibilité du CDN deviennent VOS problèmes. L'import Vite ?url ramène tout en local.
  • Quand un composant à scroll virtuel ne rend qu'une partie de son contenu sans erreur, chercher un overflow: hidden chez ses ancêtres avant de suspecter la lib.
  • Trois bugs imbriqués = corriger dans l'ordre où ils se révèlent, un à la fois, en validant chaque étape — jamais les trois en parallèle.