Aller au contenu

Modernisation d’un frontend historique

Pas de TypeScript. Pas de linter. Pas de Sentry. 170 sites l’utilisent chaque jour.

Moderniser progressivement un frontend historique non typé et non supervisé tout en maintenant le produit disponible pour ses utilisateurs.

5 min de lecturePar

Les contraintes héritées étaient réelles

Le frontend CRA hérité utilisait du JavaScript sans TypeScript, ESLint, Prettier, Sentry, système de composants réutilisables ni structure de fonctionnalités cohérente. Il contenait plus de 5 000 lignes de CSS brut, des classes Tailwind remplacées par des styles en ligne, des pages copiées et une arborescence de répertoires plate.

Les problèmes se renforçaient mutuellement. Les modifications d’API atteignaient le navigateur sans retour du compilateur. Les écrans copiés reproduisaient les mêmes erreurs de style. Les erreurs de production arrivaient généralement sous forme de signalements utilisateurs, faute de système de surveillance.

Le coût de maintenance s’est répercuté sur les utilisateurs

L’application desservait toujours 170 sites clients chaque jour. Nous n’avons pas converti V1 sur place ni attendu un remplacement complet. Nous avons maintenu les anciennes routes en fonctionnement et exigé que chaque nouvelle route V2 respecte les nouvelles normes.

L’équipe disposait ainsi d’une règle simple : ne pas étendre les conventions historiques. Transférer la responsabilité lorsqu’une route est reconstruite, puis supprimer l’ancien chemin une fois le nouveau en production.

Créer un périmètre typé

Next.js 15 et TypeScript formaient le nouveau périmètre. Les nouvelles routes utilisaient des définitions de route typées, des clients d’API générés, un traitement partagé des requêtes fetch et des composants appartenant à chaque fonctionnalité. L’équipe n’a pas commencé par convertir tous les fichiers historiques. Elle a cessé d’ajouter des surfaces non typées et transféré la responsabilité vers V2 à mesure que le travail atteignait chaque route.

  • TypeScript et les routes typées rendaient visibles les erreurs de navigation et de forme des API pendant le développement.
  • Les clients générés et un traitement partagé des requêtes fetch ont remplacé les conventions de requête dispersées.
  • Les dossiers de fonctionnalités désignaient clairement les responsables des routes, des Hooks React, des schémas et des tests.
  • Des primitives réutilisables ont remplacé les copies au niveau des pages pour les interactions répétées.

Ajouter des boucles de retour avant de migrer tous les écrans

La modernisation a aussi modifié la détection des échecs et les conditions d’admission des changements. Sentry a ajouté les signalements côté client, serveur et périphérie, ainsi que les limites d’erreur de l’application. Les flux de travail unitaires et navigateur ont reçu des tâches de contrôle obligatoires explicites, tandis que des tests centrés sur le comportement couvraient les parcours à haut risque comme Investor Intake.

Ces contrôles ne réparaient pas automatiquement V1. Ils rendaient chaque route V2 observable et testable avant qu’elle n’assume davantage de responsabilités en production.

Construire le nouveau périmètre autour de l’ancien produit

V2 possédait l’interface globale, l’authentification et chaque fonctionnalité nouvellement migrée. CRA ne restait dans une iframe que pour les routes dont il avait encore la responsabilité. L’article associé sur la migration décrit en détail le pont unique qui coordonnait les communications postMessage, le SSO et le routage.

Pour cet article, le point essentiel est la responsabilité : les nouvelles normes s’appliquaient à la frontière de V2, et chaque migration terminée réduisait la quantité de code qui en était exemptée.

Rendre la responsabilité visible pendant la transition

Les responsabilités étaient suivies explicitement pendant la transition. Navbar, Topbar, Settings, Investor Intake, Authentication et Twilio sont passés à V2. Home, Genius Mode, Deals et Buyers sont restés dans V1 jusqu’à ce que leurs remplacements soient prêts. Les sites clients ont migré par groupes contrôlés au lieu de recevoir toutes les surfaces inachevées en une fois.

Cet inventaire a empêché la réécriture de devenir un projet parallèle indéfini. Une fonctionnalité appartenait encore à V1, était servie par la frontière de compatibilité ou était native dans V2.

La modernisation est une séquence, pas un événement

La bascule finale a supprimé l’iframe, les anciens clients générés et le code du pont, puis nettoyé les routes obsolètes, les tests, les protections d’authentification, le partage du composeur et la structure des composants. La modernisation n’était terminée que lorsque la frontière temporaire pouvait être supprimée.

  • Ne mesurez pas la progression au nombre de nouveaux fichiers créés pour le framework.
  • Mesurez les responsabilités de production transférées et les chemins de compatibilité qui peuvent être supprimés.
  • Maintenez le nouveau code dans les nouvelles normes au lieu d’attendre une conversion parfaite de tout le code.
  • Supprimez l’infrastructure de migration temporaire après le déplacement de la dernière surface qui en dépend.