JSJS Memo🎙️ Coach

Flexbox Vs css Grid

Flexbox est un modèle de disposition unidimensionnelle. C'est-à-dire qu'il peut gérer une seule dimension à la fois : soit en colonne soit en ligne. Ce modèle va permettre de distribuer l'espace entre des objets d'une interface ainsi que de les aligner.

CSS Grid layout

Le module CSS Grid layout (modèle de disposition en grille) qui permet la manipulation d'éléments dans une grille à deux dimensions. Les grilles peuvent être utilisées pour agencer des pages entières ou de petits éléments d'interface.

Contrairement à Flexbox, la grille n'a pas de structure de contenu. Les éléments « enfants » d'un conteneur en grille peuvent être positionnés afin qu'ils se chevauchent ou qu'ils se comportent comme des éléments positionnés.

  • La disposition/mise en page (ou layout en anglais) CSS avec Grid est un système Ă  deux dimensions : il peut gĂ©rer en mĂŞme temps la disposition des colonnes et des lignes. Ce qui n'est pas le cas avec l'utilisation de Flexbox qui lui est fondamentalement un système Ă  une dimension : soit en colonne soit en ligne mais pas les deux Ă  la fois.
  • D'autre part choisir l'un ou l'autre c'est choisir une approche. Opter pour CSS-Grid, c'est choisir la disposition de nos diffĂ©rents blocs (ou layout-first). Si on choisit l'approche Flexbox, on opte pour la disposition de notre contenu (content-first).
  • Flexbox est le plus appropriĂ© pour la disposition des Ă©lĂ©ments au sein des composants d'une application car ses derniers suivent la plupart du temps une certaine linĂ©aritĂ©. CSS-Grid quant Ă  lui se destine Ă  la disposition d'une mise en page Ă  plus grande Ă©chelle des composants eux-mĂŞmes prĂ©sents dans la page.
  • Mais alors si les cas d'utilisations semblent diffĂ©rents, on peut se poser la question suivante : peut-on les combiner ? La rĂ©ponse est oui. Par exemple, on peut facilement incorporer un composant Flexbox (disposition des Ă©lĂ©ments d'une navbar) au sein mĂŞme d'un composant CSS-Grid (voir image ci-dessous).

SSR Vs CSR

Rendu côté client

Avec le Client Side Rendering, le serveur joue un rôle très limité. Lorsque l'utilisateur ouvre une page, le serveur renvoie essentiellement une page HTML presque vide ainsi que les fichiers JavaScript de l'application.

Le navigateur doit alors télécharger le JavaScript et l'exécuter ensuite de construire l'interface et effectuer les appels API et afficher le résultat

Concrètement, l'utilisateur attend que tout ce travail soit réalisé dans son navigateur avant de voir le contenu réel. C'est pour cela qu'historiquement certaines applications React donnaient l'impression d'afficher une page blanche pendant quelques instants avant que le contenu n'apparaisse.

On relève donc 2 problèmes majeurs.

  • pas de HTML donc des mauvais rĂ©sultats SEO(Notre page ne contient au premier rendu qu'un placeholder. Les robots des moteurs de recherche ne lisent donc aucun contenu sur la page.)
  • Temps de chargement initial Ă©levĂ©(pendant que le navigateur tĂ©lĂ©charge puis exĂ©cute le JavaScript, l'utilisateur ne voit qu'une page blanche. )

Rendu côté serveur

Avec le SSR, sa philosophie est différente. Lorsque l'utilisateur demande une page, le serveur génère déjà le contenu HTML complet avant de l'envoyer au navigateur. C'est -à -dire que lorsque le navigateur reçoit la réponse, il peut afficher immédiatement le contenu.

L'utilisateur voit donc : le titre les données les textes les images qui sont beaucoup plus rapidement.

Ensuite, React télécharge le JavaScript nécessaire pour rendre la page interactive. On appelle cette étape l'hydratation.

L'intérêt principal est que l'utilisateur voit quelque chose très rapidement et que les moteurs de recherche reçoivent directement le contenu de la page.

SSG

Le SSG est différent : la page est générée au moment du build. C'est très performant, car elle peut être servie directement depuis un CDN. Je l'utiliserais pour une page marketing, une documentation ou un article qui change rarement.

ISR

L'ISR est un compromis intéressant. On garde les bénéfices du statique, mais Next.js peut régénérer la page après un certain délai. Par exemple, pour un catalogue produit ou une page de contenu qui change plusieurs fois par jour. Cela évite de tout reconstruire à chaque mise à jour.

NEXT JS VS REACT

Pour moi, React est principalement une bibliothèque d'interface utilisateur alors que Next.js est un framework d'architecture.

Avec React va souvent se concentrer sur les composants, la gestion d'état, les hooks et l'expérience utilisateur.

Avec Next.js doit en plus maîtriser les problématiques de rendu, de cache, de SEO,, de stratégie CDN et d'observabilité.

Par exemple, lorsqu'un utilisateur consulte une page produit, je dois réfléchir à plusieurs questions.

Est-ce que la page doit être générée statiquement ? Est-ce que les données doivent être mises à jour toutes les minutes ? Est-ce que je peux utiliser un Server Component ? Quelle stratégie de cache est la plus adaptée ? Comment optimiser le LCP ?

Ces problématiques n'existent pas vraiment dans une SPA React classique. C'est pour cela que je considère que Next.js est davantage un sujet d'architecture que simplement un framework front-end.

NEXT JS

NextJS est un framework React qui apporte nativement des fonctionnalités essentielles comme le routage, le rendu serveur, l'optimisation des performances, le SEO, le streaming et les React Server Components.

Je l'utilise lorsqu'un produit a des enjeux de visibilité, de performance ou d'expérience utilisateur.

Sur mes projets comme Junior & Cie, il nous a permis de bénéficier du SSR, d'améliorer le référencement et de construire une architecture plus robuste et maintenable.

Pour moi, l'intérêt principal de Next.js est qu'il permet de se concentrer sur les besoins métier plutôt que de reconstruire soi-même toute l'infrastructure autour de React.

Hydratation

L'hydratation consiste à rendre une page interactive après son affichage. Le serveur génère d'abord le HTML. L'utilisateur peut déjà voir la page. Ensuite React télécharge le JavaScript nécessaire et rattache les événements aux éléments affichés.

Par exemple un bouton est visible immédiatement mais il ne devient réellement cliquable qu'après l'hydratation.

L'un des objectifs modernes de Next.js est de réduire la quantité de JavaScript à hydrater. Moins on hydrate, plus l'application est rapide.

Pourquoi moins on hydrate, plus la performance?

Parce que l'hydratation est une opération coûteuse pour le navigateur. Quand une page Next.js est rendue côté serveur, le navigateur reçoit déjà le HTML. Ce HTML peut être affiché immédiatement. Mais ce HTML est uniquement statique. Pour qu'il devienne interactif (boutons, formulaires, événements...), React doit hydrater la page. Cette hydratation comporte plusieurs étapes :

  • TĂ©lĂ©charger le bundle JavaScript.
  • Parser le JavaScript.
  • L'exĂ©cuter.
  • RecrĂ©er l'arbre React.
  • Comparer cet arbre avec le DOM dĂ©jĂ  affichĂ©.
  • Attacher tous les Ă©vĂ©nements (onClick, onChange, etc.).

Toutes ces étapes utilisent du CPU. Plus il y a de composants à hydrater, plus le navigateur travaille.

Hydration Mismatch

Lorsque le HTML généré côté serveur est différent du HTML généré côté client.

Exemple new Date() côté server affiche 10:00:00 mais client 10:00:01 React détecte une divergence. Erreur d'hydratation.

Mobile First

Le Mobile First est un principe de conception qui permet de concevoir une interface utilisateur en priorité pour les petits écrans, tels que les smartphones, puis d'adapter aux écrans plus grands, tels que les tablettes et les pc. En utilisant le des unités relatives comme %, em(unité de mesure longueur des espaces), ou rem(root em) pour la mise en page et la typographie. ou utilisation Flexbox ou Grid CSS pour créer des grilles qui s'adaptent à différentes tailles d'écran.

Next 12

  • Des performances encore meilleures: les builds et refresh encore plus rapides.

Après avoir implémenté Webpack 5 dans sa version 11, l'équipe de Next.js investi encore plus sur l'amélioration des temps de builds et de rafraîchissement. Le compilateur [Speedy Web Compiler](https://swc.rs/) (SWC), développé en Rust, permet de créer les pages statiques au moment de la commande build plus rapidement que dans la version 11 de Next JS. La compilation qui permet de mettre à jour une page en local lorsque le code est modifié et accélérée également puisque le rendu s'affiche plus vite.

Cette fonctionnalité est disponible en option sur Next.js 12 en l'activant dans votre fichier de configuration [next.config.js](http://next.config.js)

  • Des images compressĂ©es avec AVIF

Grâce au compresseur AVIF, la balise Image de NextJS est capable de compresser les images et réduire leur taille de 20% par rapport au format WebP. Cette fonctionnalité est optionnelle et doit être activée en utilisant la propriété images.formats dans le fichier [next.config.js](http://next.config.js):

  • L'arrivĂ©e des Middlewares

Un middleware est une fonction qui se place à l'entrée et la sortie du serveur web, interceptant les requêtes entrantes et les réponses sortantes afin d'appliquer une logique sur ces éléments. Juqsu'à la version 12, NextJS était dépourvu d'une fonctionnalité de Middleware. Les développeurs étaient obligés de l'implémenter manuellement pour chaque route API. Pour utiliser les middlewares dans Next.js, créez un fichier _middleware.js dans le répertoire pages

Next.js 13

  • New app Directory et layouts

Le répertoire app/ peut coexister avec le répertoire pages existant pour une adoption progressive. Bien que l'utilisateur n'ait pas besoin d'utiliser le répertoire app/ lors de la mise à niveau vers Next.js 13, les bases sont posées pour construire des interfaces complexes tout en envoyant moins de JavaScript. Layout

Le répertoire app/ facilite la mise en page d'interfaces complexes qui maintiennent l'état entre les navigations, évitent les réexpositions fastidieuses et permettent des modèles de routage avancés. Il est possible d'associer du code d'application aux routes, comme des composants, des tests et des styles. La création de routes dans le répertoire app/ nécessite un seul fichier, page.js

  • [Server Components](https://nextjs.org/blog/next-13#server-components) (composant de server)

Server component utilise le serveur et le client, ce qui permet de créer des applications rapides et hautement interactives. En utilisant Server component,c'est possible de réduire la quantité de JavaScript envoyée au client, ce qui permet un chargement initial plus rapide des pages. Lorsqu'une route est chargée, le moteur d'exécution Next.js et React, dont la taille est prévisible et peut être mise en cache, est chargé. La taille de ce moteur d'exécution n'augmente pas à mesure que votre application se développe. En outre, le moteur d'exécution est chargé de manière asynchrone, ce qui permet d'améliorer progressivement le HTML du serveur sur le client.

  • Streaming

Grâce aux composants de serveur et aux dispositions imbriquées de Next.js, il est possible de rendre instantanément les parties de la page qui ne requièrent pas spécifiquement de données, et d'afficher un état de chargement pour les parties de la page qui récupèrent des données. Avec cette approche, l'utilisateur n'a pas besoin d'attendre le chargement de la page entière avant de pouvoir commencer à interagir avec elle

  • [Data Fetching](https://nextjs.org/blog/next-13#data-fetching)

Next.js 14

  • forms et mutation

Avec Next.js 14, ils simplifient l'expérience des développeurs dans la création de mutations de données et Amélioration l'expérience de l'utilisateur lorsqu'il dispose d'une connexion réseau lente ou lorsqu'il soumet un formulaire à partir d'un appareil moins puissant.

  • Server Actions

Avec server actions, on n'a pas besoin de créer manuellement une route API ?on pourra définir une fonction qui s'exécute en toute sécurité sur le serveur, appelée directement à partir de vos composants React.

Use client

Cette directive est utilisée pour indiquer que certains composants ou parties du code doivent être exécutés côté client uniquement. Elle permet de s'assurer que certains comportements interactifs, dépendants du navigateur ou des APIs web spécifiques au client, sont traités au bon endroit.

Avantages :

  • Gestion de l'Ă©tat et des effets (hooks React) : use client permet l'utilisation de hooks comme useState ou useEffect, qui ne peuvent pas fonctionner cĂ´tĂ© serveur. Cela est essentiel pour gĂ©rer des interactions et des mises Ă  jour d'UI basĂ©es sur des Ă©vĂ©nements utilisateur.
  • InteropĂ©rabilitĂ© avec des bibliothèques du client : Certaines bibliothèques (comme des animations ou des graphiques interactifs) nĂ©cessitent d'ĂŞtre exĂ©cutĂ©es cĂ´tĂ© client, car elles dĂ©pendent du DOM ou d'Ă©lĂ©ments spĂ©cifiques au navigateur.
  • Optimisation du rendu : Avec use client, ces composants seront chargĂ©s seulement au moment nĂ©cessaire, rĂ©duisant la charge initiale du serveur.

Pourquoi ne faut-il pas mettre "use client" partout ?

on n'utilise pas use client partout car cela annule une partie des bénéfices du framework. Quand un composant devient Client Component, tous ses enfants deviennent eux aussi clients. et la totalité de l'application était hydratée côté client. Dans ce cas, on perd : la réduction du bundle, les gains des Server Components, les optimisations du rendu serveur.

Je préfère isoler l'interactivité au niveau le plus bas possible. Par exemple, une page catalogue peut rester serveur tandis que le filtre de recherche devient client.

Use server

Cette directive est de la stratégie de rendu côté serveur (SSR) dans Next.js. Elle permet de spécifier que certains composants ou morceaux de logique sont exécutés côté serveur.

Avantages :

  • Accès aux donnĂ©es cĂ´tĂ© serveur : use server est utile pour rĂ©cupĂ©rer des donnĂ©es sensibles ou spĂ©cifiques au serveur (comme une base de donnĂ©es ou des API sĂ©curisĂ©es). Cela permet de sĂ©curiser la logique mĂ©tier ou la gestion des donnĂ©es.
  • Optimisation des performances : En sĂ©parant les composants qui peuvent ĂŞtre rendus cĂ´tĂ© serveur, on peut diminuer la quantitĂ© de JavaScript envoyĂ©e au client, rĂ©duisant ainsi le temps de chargement initial et amĂ©liorant l'expĂ©rience utilisateur.
  • Simplification du code cĂ´tĂ© serveur : Au lieu d'avoir Ă  gĂ©rer manuellement ce qui doit ĂŞtre rendu cĂ´tĂ© client ou serveur, la directive use server permet d'indiquer explicitement que ce code ne sera jamais envoyĂ© au client. Cela clarifie les responsabilitĂ©s entre les deux cĂ´tĂ©s de l'application.

Next.js 15

  • Support React 19: Next.js 15 introduit le support de React 19 (version RC puis stable). Cela permet de commencer Ă  utiliser les nouvelles fonctionnalitĂ©s de React 19
  • Async Request APIs (changement "breaking"): Les API qui dĂ©pendent de la requĂŞte (comme cookies, headers, params, searchParams, draftMode) deviennent asynchrones. Il faudra les awaiter dans certains composants/layouts/routes.
  • Nouvelle sĂ©mantique de cache ("Caching Semantics"): Par dĂ©faut, beaucoup de choses ne sont plus mises en cache automatiquement : fetch dans certains contextes, handlers GET, navigation client. Tu peux toujours activer le cache ("force-static", staleTimes etc.) mais le comportement par dĂ©faut est plus strict
  • Turbopack Dev stable: L'outil de build / bundler "Turbopack" (successeur rapide/plus moderne) est dĂ©sormais stable en mode dĂ©veloppement : startup plus rapide, Fast Refresh plus performant, builds initiaux plus efficaces.

Autre reponses de nouvelle next15

Next.js 15, je vois trois évolutions importantes.

  • La première concerne l'alignement avec React 19, sur les nouveaux hooks comme useActionState, useOptimistic ou useFormStatus, qui simplifient la gestion des formulaires et des Server Actions.
  • La deuxième concerne l'Ă©volution des APIs dynamiques, comme headers(), cookies() ou searchParams, qui deviennent asynchrones afin de mieux s'intĂ©grer au modèle de rendu de React.
  • Next.js 15 continue d'amĂ©liorer les performances et les mĂ©canismes de cache en laissant davantage le dĂ©veloppeur choisir sa stratĂ©gie de mise en cache.

Hooks sur Server Component

  • On peut utiliser useState, useEffect ? Non — car ces hooks nĂ©cessitent du code client.
  • On peut utiliser useMemo, useCallback ? Oui, s'ils ne dĂ©pendent pas du cycle de vie du client.
  • En pratique, les Server Components sont souvent de simples fonctions asynchrones qui font du fetch et renvoient du JSX.

Props to Server component

Pour passer des props, c'est comme n'importe quel composant React.

  • les props doivent ĂŞtre sĂ©rialisables (pas de fonctions ni de window par exemple, Map, Date sans formatage) ;

Pourquoi on doit sérialiser les props?

Les props doivent être sérialisables parce qu'un Server Component et un Client Component ne s'exécutent pas dans le même environnement. Next.js doit transporter les données du serveur vers le navigateur via un protocole réseau. Pour cela, les données doivent pouvoir être converties dans un format échangeable. Les objets simples, tableaux, chaînes et nombres fonctionnent parfaitement. Mais, les fonctions, instances de classes ou certains objets complexes ne peuvent pas être correctement sérialisés. Si on tente de les transmettre, Next.js génère une erreur car il est incapable de reconstruire fidèlement ces objets côté client. C'est une contrainte fondamentale du modèle Server Components et elle pousse à mieux séparer la logique serveur de l'interface utilisateur.

  • si tu passes un Client Component en prop (children par exemple), Next.js gère le rendu mixte automatiquement.

Props entre le serveur et le client

Next.js utilise un protocole de sérialisation basé sur React Flight.

  • Les objets doivent ĂŞtre JSON-sĂ©rialisables(objets simples, tableaux, chaĂ®nes, nombres, boolĂ©ens).
  • Les rĂ©fĂ©rences de composants clients sont envoyĂ©es comme des "points de montage" pour React cĂ´tĂ© client.
  • Les promesses (fetch) sont rĂ©solues cĂ´tĂ© serveur avant envoi au client (sauf si utilisĂ©es avec Suspense pour streaming).

React Flight

React Flight est le protocole utilisé par React pour faire communiquer les Server Components avec le navigateur.

Lorsque l'on utilise l'App Router dans Next.js, les Server Components ne sont pas envoyés au navigateur sous forme de JavaScript.

À la place, React exécute ces composants sur le serveur puis produit un flux de données appelé React Flight Payload.

Le navigateur reçoit ce flux et React reconstruit l'arbre de composants.

C'est ce mécanisme qui permet d'utiliser les Server Components sans envoyer leur JavaScript au client.

Pourquoi React a-t-il créé React Flight ?

L'objectif est de réduire la quantité de JavaScript envoyée au navigateur.

Avant les Server Components, tout composant React devait être téléchargé, exécuté et hydraté côté client.

Avec React Flight :

  • les composants serveur restent sur le serveur
  • seul le rĂ©sultat est envoyĂ©
  • le navigateur reçoit beaucoup moins de JavaScript.

Cela améliore les performances, notamment sur les appareils mobiles.

Comment ça marche (vue simplifiée)

  • Rendu cĂ´tĂ© serveur : React exĂ©cute tes Server Components et produit un payload Flight (pas de JS client pour ces composants).
  • Manifests & rĂ©fĂ©rences : le bundler gĂ©nère un client manifest qui mappe les Client Components Ă  leurs chunks. Le payload Flight contient des rĂ©fĂ©rences vers ces modules + les props sĂ©rialisĂ©es.
  • Transport : le payload est streamĂ© au navigateur (souvent text/x-component). Next.js, par exemple, insère des blocs (tu peux voir des self.__next_f.push(...) en dev).
  • Reconstitution cĂ´tĂ© client : React reçoit le flux Flight, reconstruit l'arbre, puis charge/hydrate seulement les Client Components rĂ©fĂ©rencĂ©s. RĂ©sultat : moins de JS Ă  tĂ©lĂ©charger, meilleur TTFB, et data-fetching cĂ´tĂ© serveur.

Prenons un exemple sur Junior & Cie

Imaginons une page de réservation. On a : une Page ReservationPage qui a Header, VoyageInfo, PassengerForm, Footer

Le PassengerForm est interactif.

Les autres composants affichent uniquement des données.

Le serveur exécute : Header, VoyageInfo, Footer. Il ne les transforme pas en JavaScript.

Il produit un Flight Payload.

Donc React Flight envoie du HTML ?

Non. C'est une confusion fréquente.

Le HTML est envoyé grâce au rendu serveur.

React Flight, lui, envoie un flux décrivant l'arbre des composants React. Ce n'est ni du HTML ni du JSON classique.

C'est un protocole propre Ă  React qui indique :

  • quels composants afficher ;
  • quelles props transmettre ;
  • quels composants client charger.

Ensuite React utilise ce flux pour reconstruire correctement l'arbre côté navigateur.

Quel est le lien entre React Flight et les Server Components ?

Les Server Components reposent entièrement sur React Flight.

Sans React Flight, React ne saurait pas transmettre le résultat du rendu serveur au navigateur.

On peut voir React Flight comme le "langage" utilisé entre le serveur React et le client React.

Est-ce que vous avez manipulé React Flight directement ?

Non. Et c'est normal.

React Flight est un mécanisme interne de React.

Sur Junior & Cie, j'utilisais les Server Components de l'App Router.

C'est Next.js qui s'occupait automatiquement de produire et d'envoyer le Flight Payload.

En tant que développeur, je n'avais pas besoin d'interagir directement avec ce protocole.

Mais, comprendre son fonctionnement m'aide Ă  mieux choisir entre Server Components et Client Components.

Sérialisation des promesses

React Flight supporte les promesses :

  • Si ton composant retourne await fetch(), la promesse est rĂ©solue cĂ´tĂ© serveur avant envoi.
  • Si tu utilises Suspense, la promesse peut ĂŞtre "streamĂ©e" : la page se charge partiellement puis s'hydrate quand la promesse se rĂ©sout.

Sérialisation des donnees

Une donnée sérialisable est une donnée qui peut être convertie en texte puis reconstruite de l'autre côté. exemple objet en typescript transforme en json et reconstruite dans le navigateur.

function non Sérialisable

Une fonction n'est pas sérialisable parce qu'elle représente du comportement, pas de la donnée. Entre un Server Component et un Client Component, je ne dois pas passer une fonction métier en prop. Je passe les données nécessaires, puis je recrée le comportement côté client si le composant est interactif.

Classe non sérialisable

Une instance de classe contient des méthodes, un prototype et parfois une logique interne.

Une classe n'est pas vraiment sérialisable car la sérialisation conserve les données mais pas le prototype ni les méthodes. Donc je préfère passer des DTO simples entre serveur et client.

Rendre les données sérialisables

  • Fonctions → utiliser des Server Actions ou dĂ©clarer la fonction dans un Client Component. Next sĂ©rialise une rĂ©fĂ©rence spĂ©ciale qui reste exĂ©cutable cĂ´tĂ© serveur.
  • Date → passer une chaĂ®ne ISO (date.toISOString()) puis retransformer cĂ´tĂ© client.
  • Map / Set → les convertir en objet ou tableau avant de les passer
  • Plusieurs comportements âžś passer une "intention" sĂ©rialisable et router la logique cĂ´tĂ© client/serveur selon le besoin.

Stratégie Cache

  • Par dĂ©faut, un fetch() dans un Server Component est mis en cache et revalidĂ© selon les headers HTTP.
  • Tu peux dĂ©sactiver ou personnaliser le cache avec l'option { cache: "no-store" } ou { next: { revalidate: 60 } } dans fetch().

J'utilise les stratégies de cache en fonction de fréquences de mise à jour des données

Comment gérer le cache

Avec l'App Router, je peux contrôler le cache directement au niveau des appels fetch. Si une donnée peut être réutilisée pendant une heure, je peux utiliser une stratégie de revalidation. Si elle doit être toujours fraîche, je force le rendu dynamique.

Il existe plusieurs niveaux ou je jouions sur :

  • Request Memoization: MĂŞme requĂŞte dans un mĂŞme rendu.
  • Full Route Cache: Cache du rendu complet.
  • Router Cache Cache cĂ´tĂ© navigateur.
  • Full Route Cache
  • Data Cache
  • CDN Cache
  • revalidate
  • revalidateTag
  • cache()

Fetching des données

Je commence par distinguer les données publiques, semi-dynamiques et utilisateur.

Pour des contenus publics comme une liste de vidéos, je peux utiliser du cache avec revalidate.

Pour des données très dynamiques ou personnalisées, comme les favoris utilisateur, je désactive le cache avec no-store.

Pour des données partagées dans plusieurs pages, j'utilise des tags de cache avec revalidateTag.

L'idée est de ne pas appliquer une stratégie unique partout. Chaque donnée a son rythme de mise à jour.

Force-cache Vs no-store Vs revalidate

  • force-cache demande Ă  Next.js de rĂ©utiliser la rĂ©ponse en cache. C'est adaptĂ© Ă  des donnĂ©es qui changent peu, comme une page de prĂ©sentation ou une liste de contenus rarement modifiĂ©e.
  • no-store dĂ©sactive le cache. Chaque requĂŞte rĂ©cupère des donnĂ©es fraĂ®ches. Je l'utiliserais pour des informations très dynamiques ou personnalisĂ©es, comme un espace utilisateur ou des disponibilitĂ©s en temps rĂ©el.
  • revalidate est un compromis. La donnĂ©e est mise en cache mais rĂ©gĂ©nĂ©rĂ©e après une durĂ©e dĂ©finie. C'est un bon choix pour des contenus publics qui Ă©voluent rĂ©gulièrement, par exemple des actualitĂ©s ou certaines pages de Junior & Cie.

Le choix dépend toujours de la nature de la donnée.

use cache

use cache permet de mettre explicitement en cache certaines opérations côté serveur.

use cache: private

Cache spécifique à un utilisateur.

use cache: remote

Cache partagé entre instances.

Streaming / Server

  • Grâce Ă  React Suspense, tu peux streamer une partie de la page dès que les donnĂ©es sont prĂŞtes.
  • Cela rĂ©duit le TTFB et amĂ©liore l'UX sur les pages qui doivent charger beaucoup de donnĂ©es.

Préfetch / Server avant navigation

Next.js précharge automatiquement les pages et leurs données quand un \<Link> devient visible dans le viewport.

Cela signifie que la page est souvent prête côté serveur avant même le clic de l'utilisateur → navigation très rapide.

App Router

L'App Router est une nouvelle manière de structurer les routes dans Next.js (dans un dossier app/) qui apporte plusieurs nouveautés :

  • support intĂ©grĂ© des layouts hiĂ©rarchiques (tu peux avoir des layouts imbriquĂ©s) ;
  • support des React Server Components, qui permettent de rendre une partie du composant cĂ´tĂ© serveur pour allĂ©ger le code client ;
  • streaming des composants (React suspense) ;
  • donnĂ©es fetchĂ©es directement dans les composants de page/serveur avec des fonctions async sans avoir Ă  utiliser getStaticProps ou getServerSideProps comme dans l'ancien système.

Pages Router Vs App Router

Le Pages Router était principalement construit autour des pages.

Le chargement des données reposait sur :

  • getServerSideProps
  • getStaticProps
  • getInitialProps

L'App Router repose sur React Server Components.

La récupération de données devient beaucoup plus simple..

Cela simplifie le code et réduit la séparation artificielle entre chargement de données et rendu.

Server Actions

Le Server Actions est une fonctionnalité qui permet d'exécuter du code côté serveur déclenché depuis le client (par exemple via un formulaire) sans avoir besoin d'une API route séparée.

Pourquoi on pousse autant les Server Actions ?

Parce qu'elles réduisent énormément la complexité applicative.

Avant :

  • formulaire(client)
  • appel fetch
  • route API
  • validation
  • gestion erreur

Aujourd'hui :

  • Client
  • Server Action
  • Service
  • Base de donnĂ©es

Le formulaire peut appeler directement une fonction serveur.

Cela rapproche énormément le code métier du composant qui l'utilise.

Pour des cas simples, cela réduit beaucoup le code boilerplate.

Je continue cependant à utiliser des APIs dédiées lorsque plusieurs consommateurs existent, par exemple mobile, partenaires ou microservices.

Comment server Actions dans vos missions ?

Je n'ai pas eu l'occasion de mettre en place massivement des Server Actions en production sur mes projets, car les architectures sur lesquelles j'ai travaillé étaient déjà structurées autour d'APIs REST ou GraphQL exposées par des backends dédiés.

Par exemple :

Chez OUIGO, le backend était en .NET avec des APIs REST et GraphQL.

Chez La Poste, on avait un backend NestJS/Fastify exposant des APIs REST.

Sur Junior & Cie, on avait également des APIs REST et GraphQL Node.js.

Dans ce contexte, le frontend Next.js consommait ces APIs et les mutations passaient par ces couches backend.

Mais, j'ai étudié et réalisé plusieurs POC avec les Server Actions pour comprendre leur intérêt et leurs limites.

Intérêts Server Action

Ce qui m'a marqué, c'est la réduction du code "boilerplate". Sur un formulaire classique React, on crée généralement un formulaire, un handler, un appel fetch, une API route, des validations et la gestion des erreurs. Avec les Server Actions, une partie de cette mécanique disparaît.

Par exemple, sur un side project où je testais un formulaire d'inscription utilisateur avec Next.js 15, j'ai pu directement appeler une Server Action depuis le formulaire sans créer d'endpoint intermédiaire.

J'ai trouvé que cela rendait le code plus lisible car la logique métier restait proche du composant qui l'utilise.

J'ai également apprécié le fait que certaines validations restent naturellement côté serveur, ce qui réduit le risque d'exposer des traitements sensibles dans le navigateur.

Limites Server Action

J'ai rapidement constaté que les Server Actions ne remplacent pas toutes les APIs.

Dès qu'on a plusieurs consommateurs, par exemple une application mobile React Native, un partenaire externe ou plusieurs frontaux, il devient difficile de tout faire reposer sur des Server Actions.

Dans ce cas, une API REST ou GraphQL reste plus adaptée parce qu'elle peut être consommée par différents clients.

J'ai aussi constaté qu'il fallait bien comprendre les mécanismes de cache et de revalidation. Une Server Action qui modifie une donnée doit souvent être accompagnée d'une stratégie claire d'invalidation du cache pour éviter d'afficher des informations obsolètes.

Comment sécuriser une Server Action ?

Une erreur fréquente est de croire qu'une Server Action est automatiquement sécurisée.

Elle s'exécute côté serveur mais doit toujours :

  • vĂ©rifier l'authentification
  • vĂ©rifier les permissions
  • valider les entrĂ©es

Pourquoi server action utiliser plutĂ´t qu'une API REST classique ?

Les deux répondent à des besoins différents.

Une API REST est idéale lorsqu'elle doit être consommée par plusieurs clients :

  • Web
  • Mobile
  • TV
  • Applications partenaires

Mais , lorsqu'une mutation est exclusivement utilisée par le front Next.js, la Server Action simplifie énormément l'architecture. Avec server Action, il n'y a plus d'endpoint REST intermédiaire.

La logique reste côté serveur.

Le navigateur ne connaît jamais les secrets ou les tokens internes ou les accès BDD. Cela réduit également le code à maintenir.

Dans quel cas tu ne choisirais PAS une Server Action ?

Je ne l'utiliserais pas si plusieurs consommateurs doivent appeler la même logique métier.

Par exemple une application mobile, Smart TV, API publique

Dans ce cas, la logique métier doit rester dans un backend dédié.

La Server Action peut éventuellement appeler ce backend.

Je ne mélange jamais logique métier et couche de présentation.

À quoi servent-elles réellement ou avantage ?

Une Server Action permet d'effectuer une mutation, mais son intérêt va au-delà.

Son premier avantage est de rapprocher la logique métier du composant qui l'utilise.

Par exemple, lorsqu'un utilisateur ajoute une vidéo à ses favoris, je peux appeler directement une Server Action depuis mon formulaire, sans exposer un endpoint REST spécifique.

Deuxième avantage, la sécurité.

Le code de la Server Action s'exécute exclusivement sur le serveur. Les secrets, les tokens, les accès aux bases de données ou aux services internes ne quittent jamais le serveur.

Troisième avantage, l'intégration avec Next.js.

Après une mutation, je peux invalider très simplement le cache avec revalidateTag ou revalidatePath, pour que l'interface affiche immédiatement les données mises à jour.

Mais, je ne remplacerais pas toutes les APIs REST par des Server Actions.

Si la logique métier est consommée par une application mobile, une télévision connectée ou d'autres clients, je conserverais un backend indépendant. La Server Action jouerait alors simplement le rôle de passerelle.

Partial Prerendering

Partial Prerendering permet de mélanger statique et dynamique dans une même route : la partie statique est pré-rendu (rapide), les zones dynamiques ("trous") arrivent ensuite en streaming. Idéal pour des pages personnalisées qui doivent rester ultra-perf.

Problème resolver PPR

Pour moi, le problème que résout le PPR est le dilemme entre page statique et page dynamique. Historiquement, il fallait choisir entre la vitesse du statique et la flexibilité du dynamique. Le Partial Prerendering permet de combiner les deux dans une même page. Les parties stables sont servies instantanément depuis le cache, tandis que les parties dynamiques sont streamées progressivement. C'est particulièrement pertinent sur des applications comme l'e-commerce, le voyage ou les plateformes de réservation où une page contient à la fois du contenu éditorial et des données temps réel. Cette approche améliore la perception de performance sans sacrifier la fraîcheur des données.

Implémentation avec mission PPR

Sur Junior & Cie, qui était mon deuxième projet chez OUIGO, on est sur Next.js 14. J'ai donc eu l'occasion de travailler dans un contexte Next.js moderne, avec les problématiques de rendu, de performance, de structuration des pages et d'expérience utilisateur.

Mais, concernant le Partial Prerendering, je préfère être précis : je ne l'ai pas utilisé comme fonctionnalité centrale en production. À ma connaissance, sur Next.js 14, le PPR était encore une fonctionnalité expérimentale, donc ce n'était pas forcément un choix stable pour un parcours métier critique comme Junior & Cie.

Par contre, le besoin métier se prêtait bien au raisonnement derrière le PPR : certaines parties de la page étaient plutôt statiques, comme les contenus d'information, les règles d'éligibilité ou les éléments éditoriaux, tandis que d'autres parties étaient dynamiques, comme les disponibilités, les tarifs, les données voyageur ou les contrôles métier.

Autre implémentation PPR

Pour être transparent, je ne l'ai pas encore utilisé en production dans mes missions actuelles puisque mes projets récents sont principalement sur React, React Native et Angular.

Mais, j'ai étudié le mécanisme dans Next.js et réalisé quelques expérimentations pour comprendre son intérêt dans les applications à fort trafic.

Ce qui m'intéresse dans le Partial Prerendering, c'est qu'il cherche à combiner les avantages du statique et du dynamique.

Historiquement, on avait souvent un choix Ă  faire :

soit une page entièrement statique, très rapide ;

soit une page dynamique, plus flexible mais potentiellement plus lente.

Avec le PPR, une partie de la page peut être générée immédiatement et servie depuis le cache, tandis que certaines zones dynamiques sont chargées séparément grâce à Suspense et au streaming.

Exemple Prenons une fiche produit.

Le titre, les photos, la description ou les caractéristiques changent peu.

Ces éléments peuvent être pré-rendus et servis instantanément.

Mais, le stock disponible, le prix promotionnel du moment ou les recommandations personnalisées sont des données plus dynamiques.

Avec le PPR, ces parties peuvent arriver quelques millisecondes plus tard sans bloquer l'affichage initial de la page.

Conclusion

Je n'ai pas encore de retour d'expérience production sur PPR, mais je comprends bien la philosophie. Pour moi, ce n'est pas une fonctionnalité isolée de Next.js. C'est l'aboutissement de plusieurs concepts introduits ces dernières années : Server Components, Streaming SSR, Suspense et stratégies de cache. L'objectif reste toujours le même : afficher le contenu utile le plus vite possible tout en conservant la flexibilité des données dynamiques.

Comment avez-vous configuré le fallback ?

Sur un projet Next.js, je configure le fallback avec des Suspense boundaries. L'idée n'est pas de mettre un seul fallback global sur toute la page, mais de découper la page par zones fonctionnelles.

Par exemple, sur une page type Junior & Cie, je laisserais le contenu stable s'afficher directement : titre, description, conditions générales, informations éditoriales. Ensuite, pour les blocs dynamiques comme les disponibilités, les tarifs ou les informations liées à l'utilisateur, j'ajouterais un Suspense autour de chaque bloc.

Le fallback serait un skeleton proche du rendu final. Par exemple, pour une liste de trajets, je ne mettrais pas juste "Chargement…". Je mettrais un skeleton qui reprend la structure d'une carte trajet : origine, destination, horaire, prix, bouton. Comme ça, l'utilisateur comprend que le contenu arrive et la page ne saute pas brutalement quand les données sont chargées.

J'évite aussi les fallbacks trop grands ou trop génériques, car ils peuvent dégrader la perception utilisateur. L'objectif est que chaque bloc puisse charger indépendamment sans bloquer toute la page.

Donc pour moi, configurer un fallback, ce n'est pas seulement mettre un loader. C'est une décision UX et performance : il faut choisir où placer les boundaries, quel contenu peut arriver plus tard, et comment éviter les effets de page blanche ou de layout shift.

PPR s'appuie sur quoi ?

Il combine plusieurs concepts :

  • Server Components : Permettent de rendre certaines parties cĂ´tĂ© serveur.
  • Suspense: Permet de dĂ©finir pour afficher un placeholder.
  • Streaming Permet d'envoyer les morceaux progressivement.
  • Cache Next.js: Permet de prĂ©-rendre les parties statiques.

Pourquoi Vercel pousse autant cette approche ?

Parce qu'ils ont constaté que la majorité des pages web sont hybrides.

Très peu de pages sont : totalement statiques, totalement dynamiques

Streaming

Streaming, l'idée c'est qu'au lieu d'attendre toutes les données, le serveur envoie la page par morceaux (chunks) dès que chaque partie est prête, ce qui réduit fortement le TTFB/perceived latency.

Dans Next.js : basé sur React Suspense + fichiers loading.tsx par segment. Tu peux aussi poser tes propres \<Suspense> pour un contrôle fin

Pour tester Unitaires : j'appelle directement le route handler (GET()/POST()), je lis le flux via res.body.getReader() et je vérifie ordre des chunks, contenu, fermeture.

Intégration : même appel avec un Request réel, j'asserte status, headers (content-type), et que j'obtiens plus d'un chunk (stream réel, pas bufferisé).

E2E (Playwright) : sur une page avec Suspense, je vérifie que le fallback apparaît d'abord puis que les sections streamées deviennent visibles progressivement.

Streaming SSR

Avant React 18, le serveur devait généralement attendre que toute la page soit prête avant d'envoyer la réponse. Avec le streaming, le serveur peut envoyer progressivement le contenu.

Exemple d'une page produit : Le header est disponible immédiatement.

Les recommandations nécessitent un appel API plus lent.

Au lieu d'attendre les recommandations, Next.js affiche directement le header puis injecte le reste lorsqu'il est prĂŞt.

L'utilisateur commence Ă  interagir plus rapidement.

Sur des applications riches en données, le gain de perception est très important.

SSR classique Vs Streaming SSR

SSR classique : Tout doit être terminé avant d'envoyer la réponse. (fetch 1, 2, 3, Render, reponses)

Streaming : L'utilisateur voit progressivement arriver le contenu.(Header envoyé, Fetch 1 terminé → rendu, Fetch 2 terminé → rendu, etc)

Suspense

Suspense c'est permet d'entourer une UI potentiellement asynchrone, afficher un fallback (squelette/spinner) pendant l'attente, puis remplacer par le vrai contenu une fois prêt. Parfait pour délimiter ce qui peut streamer.

Suspense et Streaming

Suspense est le mécanisme qui permet à React de savoir ce qui peut être envoyé maintenant ou plus tard.

Sans Suspense : tout attend.

Avec Suspense : React peut streamer chaque bloc indépendamment.

Donc : Streaming \= transport et Suspense \= orchestration

Suspense Vs Loading

loading.tsx est une convention Next.js au niveau d'un segment de route. Il permet d'afficher automatiquement un état de chargement pendant que la route se charge.

Suspense est plus granulaire. Je peux l'utiliser autour d'un bloc précis, par exemple les recommandations ou un carrousel.

Donc loading.tsx est utile pour le chargement global d'une page ou d'un segment. Suspense est utile pour découper la page et streamer progressivement certains blocs.

Suspense Vs spinner

Parce que le spinner ne montre aucun progrès. L'utilisateur attend sans savoir ce qui se passe.

Avec Suspense, la page se construit progressivement. Les zones déjà disponibles restent interactives. L'use perçoit une application rapide.

MĂŞme si le temps total est identique, la perception utilisateur est largement meilleure.

C'est pour cette raison que je privilégie les skeletons ou le streaming.

Server component

Quand utiliser un Server Component ?

Avec l'App Router, je pars du principe qu'un composant est serveur par défaut. Je ne le transforme en Client Component que s'il a réellement besoin d'interactivité côté navigateur.

Un Server Component est très intéressant dès qu'on affiche de la donnée, par exemple une liste de produits, une page détail, une page d'article ou un récapitulatif. Comme le composant s'exécute côté serveur, il peut récupérer directement les données et envoyer au navigateur uniquement le résultat rendu. Cela réduit le JavaScript envoyé au client, donc améliore le temps de chargement et les Core Web Vitals.

À l'inverse, si j'ai besoin d'un useState, d'un useEffect, d'un événement utilisateur ou d'un composant très interactif, je passe en Client Component avec "use client".

Ce que j'essaie d'éviter, c'est de mettre "use client" trop haut dans l'arbre React. Si on le met sur une page complète, on perd une partie des bénéfices de Next.js. Je préfère isoler l'interactivité dans de petits composants clients, par exemple un bouton, un formulaire ou un filtre, tout en gardant le reste de la page côté serveur.

Pourquoi on utilise ou avantage server component?

Pendant des années, React a poussé le rendu côté client.

Le problème est que chaque composant devait être téléchargé, interprété puis exécuté par le navigateur.

Sur une application importante, cela représente plusieurs centaines de kilo-octets ou mégaoctets de JavaScript.

Les Server Components changent complètement cette approche.

Le composant est exécuté sur le serveur et seul le résultat est envoyé au navigateur.

Concrètement, une liste de produits qui nécessitait auparavant :

  • un bundle React
  • un hook useEffect
  • un appel API

peut maintenant être rendue directement sur le serveur. Le navigateur reçoit uniquement le HTML généré. Le résultat est une meilleure performance, particulièrement sur mobile ou réseaux lents.

Comment utilisez-vous les Server Components et client server

Sur Junior & Cie, on a utilisé les Server Components principalement pour les pages de consultation.

Par exemple :

  • page dĂ©tail d'un trajet
  • contenu CMS
  • FAQ
  • CGV

Ces pages avaient plusieurs caractéristiques :

  • SEO important
  • peu d'interactivitĂ©
  • donnĂ©es rĂ©cupĂ©rĂ©es depuis des APIs

Dans ce contexte, il n'était pas nécessaire d'envoyer du JavaScript au navigateur.

On faisait directement les appels GraphQL ou REST dans le composant serveur.

Cela permettait :

  • rĂ©duction du bundle JavaScript
  • meilleur LCP
  • amĂ©lioration du SEO
  • rendu plus rapide

Mais, dès qu'il y avait :

  • formulaire
  • gestion d'Ă©tat
  • interaction utilisateur

On bascule sur un Client Component avec "use client".

Je considère que le Server Component doit être le choix par défaut et le Client Component l'exception lorsqu'une interaction est nécessaire.

Pourquoi ne pas tout mettre en Client Component ?

Parce que cela reviendrait quasiment au fonctionnement historique de React SPA.

Le navigateur devrait :

  • tĂ©lĂ©charger le JS
  • parser le JS
  • exĂ©cuter le JS
  • hydrater la page

avant d'afficher réellement l'interface.

Sur un site média comme france.tv, cela dégrade :

  • LCP
  • TBT
  • INP
  • consommation CPU mobile

Avec les Server Components :

  • le HTML est gĂ©nĂ©rĂ© sur le serveur
  • aucune hydratation inutile
  • moins de bundle
  • meilleur SEO

On a observé une réduction importante du JavaScript envoyé aux utilisateurs.

Server Component Payload

Après rendu des Server Components, React envoie au client un payload spécial (appelé RSC payload ou React Flight), qui décrit l'arbre rendu et contient des pointeurs vers les Client Components à hydrater. Ce n'est pas du JSON brut.

Dans Next.js : ce payload est mis en cache côté serveur (Full Route Cache) et côté client (Router Cache) pour accélérer les navigations. À l'arrivée, il sert à reconcilier l'UI sans retélécharger tout.

Détail "bas niveau" : lors des navigations, on peut voir une réponse réseau au type text/x-component ; c'est le flux RSC/Flight.

Server Functions

C'est une fonction exécutée sur le serveur qu'on déclenche depuis un formulaire ou un composant client. Elles reçoit ou renvoit des données sérialisables, s'intègrent au cache de Next (peuvent renvoyer l'UI mise à jour en un aller-retour), et utilisent la directive "use server"

RSC ou Client

Je pars d'une règle simple : tant que le composant n'a pas besoin du navigateur, il reste côté serveur.

Le composant qui affiche une liste, un titre, un détail produit, une page article ou des données déjà connues côté serveur n'a pas besoin d'être client. Le garder côté serveur permet de réduire le JavaScript envoyé au navigateur.

Mais, dès qu'il y a une interaction utilisateur, comme ouvrir une modale, gérer un formulaire, écouter un clic, utiliser le localStorage ou manipuler l'état local, alors le composant devient client.

La difficulté, c'est de bien placer la frontière. Si on met "use client" sur un composant parent trop haut, tous ses enfants deviennent clients aussi. On peut donc dégrader les performances sans s'en rendre compte.

WebSockets server

Les Server Components sont stateless. Pour du temps réel, il faut :

  • soit utiliser un Client Component qui se connecte au WebSocket ;
  • soit utiliser des Server Actions combinĂ©es Ă  un mĂ©canisme de revalidation ou un router.refresh() dĂ©clenchĂ© rĂ©gulièrement.

Pages Router / App Router

Il est possible d'utiliser les deux dans le même projet, mais cela peut entraîner des complexités. Par exemple, tu pourrais avoir certaines pages sous pages/ qui utilisent getStaticProps/getServerSideProps, et d'autres sous app/ qui utilisent layouts, etc.

Avantages : tu peux migrer progressivement ; utiliser l'ancien pour ce qui est stable, et le nouveau pour les nouvelles parties.

Inconvénients : la cohérence peut être plus difficile, gestion de l'état partagé, des styles, de l'auth, etc. Tu dois bien comprendre les frontières.

Optimiser les performances

  • Favoriser les Server Components quand possible pour rĂ©duire le bundle client.
  • Mettre en cache les fetchs ou utiliser les capacitĂ©s de Next.js pour le caching automatique.
  • Utiliser le lazy-loading / dynamic imports pour les composants très lourds ou rarement utilisĂ©s.
  • Ne pas surcharger le code client avec des librairies inutiles ; externaliser les dĂ©pendances, tree-shaking.
  • Optimiser les images avec le composant next/image.
  • Minimiser les re-rendus inutiles, profiter des layouts pour isoler les parties statiques vs dynamiques.
  • Utiliser les fichiers loading, not-found, et les suspense pour amĂ©liorer UX.

On a optimisé sur quatre axes :

  • architecture de rendu (RSC + BFF + Streaming/Suspense) pour rĂ©duire le JS et amĂ©liorer TTFB/SEO ;

React Server Components (RSC): Quoi : data-fetching et rendu côté serveur. Comment : pages/containers en RSC, widgets interactifs en Client Components au plus bas de l'arbre. Pourquoi : moins de JS expédié, TTFB et SEO meilleurs, secrets non exposés.

BFF entre front et SI: Quoi : agrégation/normalisation côté back. Comment : RSC appellent le BFF (jamais le client), endpoints "spécifiques UI" pour éviter le sur-fetch. Pourquoi : moins d'allers-retours, payloads plus petits, règles de sécurité centralisées.

Streaming + Suspense: Quoi : rendu progressif par section.

  • donnĂ©es & cache (revalidate par tags, pagination par curseur, sur-fetch Ă©vitĂ©) ;

Politique de cache Next: Comment : fetch(..., { next: { revalidate: X, tags: [...] } }) pour le semi-statique, cache: "no-store" pour le temps réel. Plus : revalidateTag('mouvements') après mutation via Server Actions → rafraîchissement précis.

Pagination par curseur: Comment : cursor stable (ex. (date,id)), pas d'offset. Pourquoi : évite doublons/sauts si les données bougent.

  • budget front (code-splitting, Tailwind purge, images optimisĂ©es, virtualisation) ;

router.refresh

C'est une méthode du hook useRouter (à importer depuis next/navigation) utilisable uniquement dans un Client Component.

Elle rafraîchit la route courante : nouvelle requête au serveur, re-fetch des données, et re-rendu des Server Components.

Quand l'utiliser ?

  • Après une mutation (ex. Server Action ou formulaire) pour rĂ©afficher la liste mise Ă  jour.
  • Après un changement de session/cookie (login/logout) pour faire reflĂ©ter l'UI courante.
  • Quand tu veux forcer une route Ă  ignorer son cache cĂ´tĂ© client et demander un nouveau payload au serveur.

Refresh Vs revalidatePath Vs revalidateTag

  • revalidatePath() / revalidateTag() (appelĂ©s cĂ´tĂ© serveur : Server Action, Route Handler) invalident le cache (Data Cache / Full Route Cache).
  • router.refresh() (appelĂ© cĂ´tĂ© client) invalide le Router Cache client pour la route actuelle et dĂ©clenche une nouvelle requĂŞte pour obtenir le rendu mis Ă  jour.
  • En pratique : souvent on combine : Server Action → revalidatePath("/liste") puis, cĂ´tĂ© client, router.refresh() si on se trouve sur cette route et qu'on veut voir l'UI se mettre Ă  jour immĂ©diatement.

RevalidatePath Vs revalidateTag

RevalidatePath invalide une route précise.

Exemple : après modification d'un profil utilisateur, tu veux rafraîchir la page : revalidatePath('/account/profile');

revalidateTag invalide toutes les données associées à un tag de cache.Toutes les données mises en cache avec le tag products doivent être invalidées, peu importe les pages qui les utilisent. C'est très utile quand une même donnée est utilisée dans plusieurs pages.

Donc:

revalidatePath \= je rafraîchis une page ou une route.

revalidateTag \= je rafraîchis une famille de données.

RSC + Redux

Les Server Components ne conservent pas d'état entre deux requêtes (ils sont stateless).

  • Redux est conçu pour gĂ©rer un store cĂ´tĂ© client.
  • Si tu initialises un store dans un Server Component, il sera recréé Ă  chaque requĂŞte et ne conservera rien cĂ´tĂ© client.

Comment partager un état global Redux

  • CrĂ©er un Provider Redux dans un Client Component.
  • L'utiliser dans un layout.js pour englober les pages.
  • Tout le rendu client peut utiliser useSelector / useDispatch.

Comment passer des données fetchées dans un Server Component au store Redux client ?

  • On peut prĂ©charger les donnĂ©es dans le Server Component, puis les passer au Provider via des props.
  • Notre Provider peut alors hydrater le store initial avec ces donnĂ©es.

Dispatch directement dans un Server Component

  • Les dispatchs Redux doivent se faire cĂ´tĂ© client.
  • Si tu veux dĂ©clencher une action après une requĂŞte serveur, il vaut mieux hydrater l'Ă©tat initial et laisser le client gĂ©rer l'action.

Comment rafraîchir les données du store après une action

  • Utiliser une Server Action ou une API Route pour mettre Ă  jour le backend.
  • Une fois terminĂ©, appeler router.refresh() (de next/navigation) dans un Client Component pour re-fetcher les Server Components et rĂ©hydrater le store avec des donnĂ©es fraĂ®ches.

LCP / CLS / INP

  • LCP (Largest Contentful Paint) : temps pour afficher l'Ă©lĂ©ment principal (souvent image "hero" ou gros titre). Cible : ≤ 2,5 s au p75.
  • CLS (Cumulative Layout Shift) : stabilitĂ© visuelle (score sans unitĂ©). Cible : ≤ 0,1 au p75.
  • INP (Interaction to Next Paint) : rĂ©activitĂ© globale aux interactions (remplace FID depuis 03/2024). Cible : ≤ 200 ms au p75.

On suit p75 mobile/desktop par route avec des objectifs : LCP ≤ 2,5 s, CLS ≤ 0,1, INP ≤ 200 ms.

Comment on s'en est servi pour optimiser

LCP — accélérer l'élément principal

  • RSC + BFF pour rĂ©duire le JS client et le temps rĂ©seau ; streaming pour afficher plus tĂ´t.
  • next/image avec priority/sizes sur le visuel "hero", prĂ©connect au domaine d'assets.
  • DĂ©caler les libs lourdes en dynamic(..., { ssr: false }).
  • Cache/revalidate adaptĂ© cĂ´tĂ© serveur (Ă©viter requĂŞtes inutiles). (Guide LCP + dĂ©finitions officielles.)

CLS — stabilité visuelle

  • RĂ©server les dimensions (images, iframes) / aspect-ratio, skeletons plutĂ´t que contenu injectĂ© tard.
  • Fonts optimisĂ©es (pas de "flash" qui reflow : font-display/optimize).
  • Éviter d'insĂ©rer des bannières/consents au-dessus du contenu. (Guides CLS & optimisations.)

INP — réactivité aux clics/touches

  • Moins de JS cĂ´tĂ© client (RSC), handlers courts + pas de gros recalculs synchrones.
  • useTransition pour MAJ non urgentes, debounce sur inputs, virtualisation des grandes listes.
  • PrĂ©-charger au survol (link prefetch), Ă©viter les "long tasks" > 50 ms. (Definition INP.

Résumé

On a instrumenté les Core Web Vitals via useReportWebVitals et un endpoint RUM. On a activé l'attribution pour identifier l'élément LCP/CLS/INP fautif. Ensuite, on a itéré par route : LCP (image hero, streaming, code-split), CLS (dimensions réservées, fonts stables), INP (moins de JS, handlers courts, useTransition). On suit nos p75 mobile/desktop et on alerte quand ça dérive.

Web Vitals (Core)

Les Core Web Vitals sont 3 métriques UX , à mesurer au 75ᵉ percentile (p75), séparément mobile/desktop : LCP/CLS/INP

Quels Core Web Vitals surveillez-vous ?

Je surveille principalement :

  • LCP: Largest Contentful Paint

Mesure le temps nécessaire pour afficher le contenu principal.

Objectif : \< 2.5 secondes

  • INP: Interaction To Next Paint

Mesure la réactivité de l'application.

Objectif : \< 200 ms

  • CLS Cumulative Layout Shift

Mesure les décalages visuels.

Objectif : \< 0.1

Comment je les mesure (terrain vs labo)

  • Terrain (RUM) : donnĂ©es rĂ©elles d'utilisateurs (ex. Search Console agrège les Core Web Vitals via CrUX). C'est votre vĂ©ritĂ© produit. [Assistance Google](https://support.google.com/webmasters/answer/9205520?hl=en&utm_source=chatgpt.com)
  • Labo : audits ponctuels (Lighthouse/PSI) pour diagnostiquer hors trafic rĂ©el. (ComplĂ©mentaire de la mesure terrain.) [Chrome for Developers](https://developer.chrome.com/docs/lighthouse/performance/lighthouse-largest-contentful-paint?utm_source=chatgpt.com)

Instrumentation Next.js 14 (App Router)

  • J'ajoute un composant client qui utilise useReportWebVitals et envoie LCP/CLS/INP vers notre backend d'analytics (beacon).
  • Je surveille les p75 par route (mobile & desktop), et j'active l'attribution quand dispo pour identifier l'Ă©lĂ©ment responsable (image LCP, nĹ“ud CLS, interaction INP).

qu'as-tu amélioré ?

J'ai travaillé sur plusieurs axes.

Premièrement :

  • RĂ©duction du JavaScript. Grâce aux Server Components.

Deuxièmement :

  • Streaming SSR.

j' affiche immédiatement : Header, Navigation, Skeleton.Pendant que les recommandations continuaient de charger. L'utilisateur avait immédiatement une interface.

Troisièmement :

  • Optimisation des images avec next/image.
  • Lazy loading.

Quatrièmement :

  • Code Splitting: Les composants lourds Ă©taient chargĂ©s uniquement lorsque nĂ©cessaire.

Tout cela a permis d'améliorer :

  • LCP
  • CLS
  • INP

Comment je les améliore concrètement

LCP (chargement principal)

  • Rendre cĂ´tĂ© serveur (RSC) + Streaming/Suspense pour montrer du contenu plus tĂ´t.
  • Optimiser l'image "hero" avec next/image (sizes, priority) et Ă©viter le JS inutile (code-split). [web.dev](https://web.dev/articles/optimize-lcp?utm_source=chatgpt.com)

CLS (stabilité visuelle)

  • RĂ©server l'espace des images/iframes (width/height ou aspect-ratio), utiliser des skeletons plutĂ´t que des insertions tardives, stabiliser les polices (Ă©viter les sauts). [web.dev](https://web.dev/articles/optimize-cls?utm_source=chatgpt.com)

INP (réactivité)

  • RĂ©duire les long tasks JS (split/idle), dĂ©placer les librairies lourdes hors du chemin critique, utiliser useTransition pour les MAJ non urgentes, virtualiser les grandes listes.

Nextjs Avantage et inconvénient

Next.js apporte un vrai gain en SEO, en performances initiales et en productivité grâce au SSR, SSG et au routage intégré. En contrepartie, il complexifie le build et le déploiement, et peut rallonger les temps de compilation. Une SPA React classique reste très adaptée pour des applications internes ou orientées PWA, car elle est plus simple, moins coûteuse à héberger et offre un contrôle total côté client, mais son SEO et son temps de premier rendu sont moins bons.

Avantages

  • Rendu serveur (SSR) & gĂ©nĂ©ration statique (SSG) → excellent SEO et temps de chargement initial plus rapide.
  • Routage basĂ© sur le système de fichiers → pas besoin de configurer React Router.
  • Optimisations intĂ©grĂ©es : code-splitting automatique, next/image, mise en cache, revalidations (ISR).
  • Support natif du streaming et des Server Components → meilleure UX et perfs.
  • DĂ©ploiement facile sur Vercel/Edge, support API Routes → backend lĂ©ger intĂ©grĂ©.

Inconvénients

  • Courbe d'apprentissage plus Ă©levĂ©e (SSR, SSG, ISR, RSC, distinction client/serveur).
  • Build plus longs sur gros projets (surtout avec SSG + beaucoup de pages).
  • HĂ©bergement un peu plus coĂ»teux qu'une SPA (besoin d'un runtime Node/Edge).
  • Moins flexible que du React pur (conventions Ă  respecter, structure imposĂ©e).
  • Certaines features optimisĂ©es pour Vercel, moins faciles sur d'autres plateformes.

gestion erreurs

En Next.js, la gestion d'erreur dépend surtout de ce que tu veux gérer :

  • erreurs prĂ©vues (validation, appel API qui Ă©choue, login invalide)
  • erreurs non prĂ©vues (exception, crash runtime)
  • 404 / ressource introuvable

Avec l'App Router, la façon recommandée aujourd'hui est :

  • retourner un Ă©tat pour les erreurs prĂ©vues dans les Server Functions / Server Actions, au lieu de throw dans tous les cas ;
  • utiliser error.tsx pour les erreurs inattendues dans un segment de route ;
  • utiliser notFound() + not-found.tsx pour les cas "introuvable".

Comment gères les erreurs

J'utilise plusieurs niveaux.

  • Pour une erreur globale, j'utilise global-error.tsx.
  • Pour une erreur spĂ©cifique Ă  une route ou une section, j'utilise error.tsx.
  • Pour un contenu absent, j'utilise not-found.tsx.

Par exemple, si une vidéo n'existe plus, je préfère afficher une page 404 propre avec suggestion de contenus similaires plutôt qu'une page blanche.

Et pour un bloc secondaire comme les recommandations, je peux isoler l'erreur pour ne pas casser toute la page.

L'objectif est que l'utilisateur puisse continuer à utiliser l'application même si une partie rencontre un problème.

Strategie de rendu

On a structuré l'app autour des React Server Components pour récupérer de données et le rendu côté serveur (perf, sécurité, SEO).

Les données proviennent d'un BFF qui agrège et sécurise les microservices, appelé uniquement depuis le serveur.

Les Server Actions gèrent les mutations via ce BFF puis déclenchent revalidatePath/tags pour rafraîchir les vues.

L'UX est optimisée au streaming et à des boundaries Suspense avec skeletons pour un rendu progressif.

Redux est réservé aux états d'interface partagés et éphémères (filtres, préférences, wizards, optimistic UI), sans dupliquer les données métier déjà fournies par le serveur.

Résultat : un front léger, prévisible et facile à tester.

Optimisation lenteur Page

Pour identifier les lenteurs ou une page est lente, Je commence toujours par mesurer. Je ne veux pas optimiser au hasard, parce qu'on peut perdre beaucoup de temps sur un faux problème.

D'abord, je regarde les données réelles sur le moniteur des logs (Datadog RUM). Ca me permet de savoir si le problème touche tous les utilisateurs ou seulement certains navigateurs, certains devices ou certaines connexions.

Ensuite, je regarde quelle métrique est dégradée : si c'est le LCP, je vais chercher l'élément principal qui ralentit l'affichage. Si c'est l'INP, je vais plutôt regarder les tâches JavaScript longues et les interactions lentes. Si c'est le CLS, je vais chercher les décalages visuels.

Ensuite, je complète avec Lighthouse et le bundle analyzer. Sur Next.js, les causes fréquentes sont des images mal optimisées, trop de JavaScript côté client, des imports trop lourds ou des composants passés en client alors qu'ils pourraient rester serveur.

Dans un cas concret, si le LCP vient d'une image héro, je vais utiliser le composant Image de Next.js, définir correctement les tailles, utiliser priority uniquement si cette image est vraiment critique, et éviter les dimensions instables. Si le problème vient du JavaScript, je vais regarder les dynamic imports, découper les composants lourds et limiter les dépendances inutiles.

Après correction, je compare les métriques avant/après dans Datadog. Pour moi, une optimisation n'est validée que si elle améliore réellement l'expérience utilisateur en production.

Hypothèse lenteur

Je n'ai volontairement aucune hypothèse technique au départ. Mon premier réflexe est d'aller chercher la donnée. Je vais regarder les métriques RUM dans Datadog pour savoir :

  • quelle page est lente
  • quelle mĂ©trique est dĂ©gradĂ©e
  • quels utilisateurs sont concernĂ©s
  • quels navigateurs sont impactĂ©s

Ensuite seulement je vais analyser.

Dans la pratique, les causes les plus fréquentes que j'ai rencontrées sur des projets Next.js sont :

  • trop de composants clients
  • hydratation excessive
  • mauvais dĂ©coupage des Server Components
  • requĂŞtes GraphQL coĂ»teuses
  • mauvaise stratĂ©gie de cache
  • bundles JavaScript trop volumineux

Mais je préfère toujours partir des mesures réelles plutôt que d'un avis personnel.

GraphQL dans Next.js

Dans un projet Next.js, je commence par mettre en place le typage automatique avec GraphQL Code Generator. Cela permet d'avoir des types TypeScript générés depuis le schéma GraphQL. On évite les erreurs entre le front et le back, et on améliore la productivité des développeurs.

Ensuite, j'utilise des fragments pour factoriser les champs communs. Par exemple, si plusieurs pages utilisent les mêmes informations utilisateur, je crée un fragment partagé. Cela évite que chaque développeur redéfinisse sa propre version de la donnée.

Je fais aussi attention à la performance des requêtes. Une requête GraphQL peut devenir très lourde si elle récupère trop de champs ou trop de relations. Donc je surveille les temps de réponse via APM, et je travaille avec le backend pour résoudre les problèmes de N+1, de pagination ou de cache.

Dans Next.js, selon le contexte, je peux récupérer les données côté serveur dans un Server Component, ou côté client si l'usage est très interactif. Mais par défaut, si la donnée sert au rendu initial de la page, je préfère la récupérer côté serveur.

Sécurité nextJS

Côté Next.js, le premier point important est l'authentification. Je privilégie les cookies HttpOnly pour stocker les tokens, plutôt que le localStorage, car cela réduit l'exposition aux attaques XSS.

Ensuite, je mets en place des contrôles côté serveur. Même si le front masque un bouton ou une page, ce n'est jamais suffisant. Les Server Actions, les API routes ou les appels backend doivent vérifier les droits de l'utilisateur.

Je fais aussi attention aux headers de sécurité, comme la Content Security Policy, X-Frame-Options, Strict-Transport-Security et la protection contre le clickjacking.

Enfin, je valide systématiquement les entrées utilisateur, par exemple avec Zod. La validation front améliore l'expérience utilisateur, mais la validation serveur reste obligatoire.

Nouvelle appl Next.js 16

Je partirais directement sur App Router. Je structurerais l'application autour des Server Components par défaut. Mon approche est simple : tout ce qui ne nécessite pas d'interaction utilisateur reste côté serveur. Les formulaires, filtres, modales ou composants interactifs deviennent des Client Components.

Cette séparation me permet de réduire considérablement la quantité de JavaScript envoyée au navigateur. Pour la récupération de données, je privilégie les appels côté serveur afin d'éviter les chaînes de chargement du type :

chargement de la page → chargement du JavaScript → appel API → affichage des données.

Je préfère :

chargement de la page → données déjà présentes dans le HTML.

Ensuite, je mets en place une stratégie de cache explicite basée sur les besoins métier.

Enfin, j'intègre dès le départ :TypeScript strict, tests automatisés, monitoring, et accessibilité.

TypeScript avancé

J'utilise TypeScript avant tout comme un outil de conception.

Par exemple, sur des API GraphQL, je génère automatiquement mes types afin de garantir la cohérence entre le frontend et le backend. J'utilise régulièrement les Generics pour construire des composants réutilisables. J'utilise également les Utility Types comme Pick, Omit, Partial ou Record pour éviter les duplications. Sur des projets complexes, cela permet de sécuriser énormément les refactorings. Quand un modèle métier évolue, TypeScript devient un véritable filet de sécurité.

REST et GraphQL

Je ne considère pas qu'il existe une réponse universelle.

GraphQL apporte beaucoup de valeur lorsque plusieurs écrans ont besoin de vues différentes d'une même donnée.

Par exemple, un détail client, une liste client et un tableau de bord peuvent récupérer exactement les champs dont ils ont besoin sans multiplier les endpoints.

Mais, GraphQL apporte aussi de la complexité.

Il faut gérer le schéma, la gouvernance, les performances et parfois les problèmes de N+1.

Pour des APIs simples ou fortement orientées ressources, REST reste souvent une excellente solution.

Dans plusieurs projets, nous avons même utilisé les deux approches selon les besoins. Le choix dépend davantage du contexte métier que d'une préférence technologique.

Pourquoi GraphQL plutĂ´t que REST ?

J'ai utilisé les deux.

Chez Nexity et Junior & Cie on a GraphQL.

L'avantage principal est que le client récupère uniquement les données dont il a besoin.

Par exemple :

une page mobile n'a peut-ĂŞtre besoin que : nom, prix

alors que la version desktop nécessite :

nom, prix, description, images, caractéristiques

GraphQL permet d'éviter l'overfetching.

Mais je reste pragmatique.

Si l'application est simple et qu'il existe peu de cas de consultation complexes, REST est souvent suffisant.

Je ne choisis pas GraphQL parce que c'est tendance mais parce qu'il répond à un besoin.

Grand risque avec Next

je pense que le plus grand risque est de ne pas comprendre réellement le framework.

Next.js simplifie énormément de choses mais masque aussi beaucoup de complexité.

J'ai déjà vu des équipes utiliser des Server Components comme des Client Components, désactiver complètement le cache parce qu'elles ne comprenaient pas son fonctionnement ou encore multiplier les appels de données sans mesurer leur impact.

Le danger est de penser que Next.js résout automatiquement tous les problèmes.

En réalité, il faut comprendre les mécanismes de rendu, de cache, d'hydratation et de streaming pour tirer pleinement parti du framework.

Accessibilité

J'ai travaillé sur plusieurs projets soumis à des exigences fortes d'accessibilité :

  • OUIGO
  • Junior & Cie
  • Nexity

Je commence toujours par utiliser les composants HTML natifs.

Ensuite je vérifie :

  • navigation clavier
  • focus visible
  • contrastes
  • ARIA lorsque nĂ©cessaire
  • compatibilitĂ© lecteurs d'Ă©cran

J' utilisons régulièrement :

  • Lighthouse
  • Axe
  • Browserstack

Un exemple concret :

sur OUIGO j'ai corrigé plusieurs composants de formulaire qui étaient utilisables à la souris mais problématiques au clavier.

L'objectif n'est pas uniquement de respecter WCAG mais de garantir que l'application est réellement utilisable pour tous.

Mise en place

Sur mes missions OUIGO, Junior & Cie et Nexity, je l'ai mise en place à plusieurs niveaux : dès l'intégration des maquettes, pendant le développement des composants, dans Storybook, puis dans les tests et les revues de code.

Par exemple, quand je développais un composant de formulaire ou un composant de sélection, je vérifiais systématiquement que l'utilisateur pouvait l'utiliser sans souris, uniquement au clavier. Je vérifiais aussi que le focus était visible, que le label était bien associé au champ, que les messages d'erreur étaient compréhensibles et que les lecteurs d'écran pouvaient annoncer correctement l'état du champ.

Un exemple concret chez OUIGO : sur un parcours de souscription, certains boutons radio fonctionnaient bien à la souris, mais pas correctement au clavier. Quand l'utilisateur naviguait avec Tab puis appuyait sur Entrée ou utilisait les flèches, le comportement n'était pas toujours cohérent. Le problème venait du fait que le composant était trop customisé visuellement et ne respectait pas complètement le comportement natif HTML.

Ma solution a été de revenir autant que possible au comportement natif des éléments HTML. Plutôt que de recréer entièrement un bouton radio avec des div, j'ai conservé un vrai input radio, associé à un label, puis j'ai appliqué le design par-dessus. Ensuite j'ai vérifié la navigation clavier : Tab pour arriver sur le groupe, flèches pour changer la valeur, focus visible, état checked correctement annoncé.

Un autre exemple concernait les messages d'erreur dans les formulaires. Visuellement, l'erreur était affichée sous le champ, mais elle n'était pas toujours liée au champ pour les lecteurs d'écran. J'ai corrigé cela avec une association explicite entre le champ et le message via aria-describedby, et en m'assurant que l'attribut aria-invalid était positionné quand la valeur était invalide.

La complexité principale, c'est souvent le compromis entre design custom et comportement accessible. Une maquette peut prévoir un composant très personnalisé, mais si on perd le comportement natif, on crée des problèmes pour les utilisateurs clavier ou lecteur d'écran. Donc ma démarche était de discuter avec UX/UI et PO pour conserver l'intention graphique tout en gardant une base HTML accessible.

J'utilisais aussi des outils comme Lighthouse, Axe, Storybook et BrowserStack pour contrôler les composants. Mais je ne me limitais pas aux outils automatiques, parce qu'ils ne détectent pas tout. Par exemple, un outil peut dire qu'il n'y a pas d'erreur critique, mais l'expérience clavier peut rester mauvaise. Donc je faisais aussi des tests manuels : navigation clavier, ordre de focus, comportement des modales, fermeture avec Échap, retour du focus après fermeture.

Sur une modale, par exemple, il faut éviter que le focus parte derrière la modale. Il faut piéger le focus dans la modale, permettre la fermeture avec Échap, mettre un titre accessible, puis restituer le focus sur le bouton qui a ouvert la modale après fermeture. C'est typiquement le genre de détail qui améliore vraiment l'usage.

Ce que je retiens, c'est que l'accessibilité n'est pas seulement une checklist RGAA/WCAG. C'est une manière de concevoir les composants pour qu'ils soient robustes, testables et utilisables par tous. Et pour moi, un composant accessible est souvent aussi un composant mieux structuré techniquement.

Optimiser le SEO

Je travaille sur plusieurs axes :

  • D'abord le rendu serveur.
  • Ensuite les mĂ©tadonnĂ©es :
  • Puis :sitemap.xml, robots.txt, donnĂ©es structurĂ©es [Schema.org](http://Schema.org), optimisation des images, Core Web Vitals

Sur Junior & Cie, le SEO était une préoccupation importante car le trafic provenait beaucoup des moteurs de recherche.

SEO dans l'App Router

Avec l'App Router, j'utilise l'API generateMetadata.

Cela permet de générer dynamiquement :

  • le titre ;
  • la description ;
  • les balises Open Graph ;
  • les balises canoniques ;
  • les robots ;
  • les informations spĂ©cifiques Ă  chaque contenu.

Par exemple, une fiche vidéo utilisera son propre titre, son résumé et sa miniature dans les métadonnées.

Cela évite d'avoir des balises génériques sur toutes les pages.

Page parfaitement indexée, mais qu'elle perde soudainement du trafic SEO

Je procède en plusieurs étapes.

D'abord, je vérifie si le contenu a changé ou si les métadonnées ont été modifiées.

Ensuite, j'analyse :

  • les balises title et description ;
  • les URLs canoniques ;
  • le fichier robots.txt et le sitemap ;
  • les Ă©ventuelles erreurs d'indexation dans Google Search Console ;
  • les Core Web Vitals ;
  • les performances rĂ©elles des utilisateurs.

Je regarde également si une modification technique récente, comme un changement de stratégie de rendu, une erreur de cache ou une mauvaise configuration des métadonnées, a pu impacter l'indexation.

Enfin, je compare les données avant et après le changement pour identifier précisément la cause plutôt que de supposer qu'il s'agit d'un problème SEO.

Quelle est votre expérience SEO concrète avec Next.js ?

Mon expérience la plus significative est sur le projet Junior & Cie, développé avec Next.js 14.

C'était une application de réservation pour les voyages d'enfants. Même si le SEO n'était pas aussi stratégique que sur un site média comme france.tv, nous avions tout de même des enjeux de performance et d'indexation sur certaines pages publiques.

Nous avons choisi Next.js notamment pour bénéficier du rendu côté serveur et des optimisations natives du framework.

Concrètement, j'ai travaillé sur :

  • l'utilisation de l'App Router ;
  • le rendu serveur des pages publiques ;
  • l'optimisation des images avec next/image ;
  • la gĂ©nĂ©ration des mĂ©tadonnĂ©es des pages ;
  • la rĂ©duction du JavaScript envoyĂ© au navigateur grâce aux Server Components lorsque cela Ă©tait pertinent.

L'objectif était d'avoir des pages rapides, bien référencées et une bonne expérience utilisateur.

Layout Vs template

Layout est persistant. Il n'est pas remonté à chaque navigation. Template est recréé à chaque changement de route.

J'utilise généralement : layout : header, footer, navigation template : analytics, animations, logique nécessitant un remount

Avantage layout?

L'intérêt principal des Layouts dans Next.js App Router est de rendre persistantes les parties communes de l'application. Cela améliore les performances, évite des re-renders inutiles, permet de conserver l'état local entre les navigations et de mutualiser certains chargements de données. Par exemple sur un parcours comme OUIGO, je pourrais placer la barre de progression, les informations utilisateur et la navigation dans un layout afin qu'ils restent présents pendant toute la souscription. Les Layouts apportent également une architecture plus modulaire en permettant à chaque domaine fonctionnel d'avoir sa propre structure tout en profitant des Server Components et du Streaming

Layout entre Pages Router et App Router

On ne peut pas partager layout entre page router et app router car ce sont deux mondes differents.

Chacun à son système Pour App router app/layout.tsx et pour page router pages/app.tsx ou pages/document.tsx

Redux et tansk query

Redux, je l'ai utilisé pour l'état applicatif global, surtout chez OUIGO sur les parcours web/mobile. Par exemple, dans un tunnel de vente ou d'après-vente, on a besoin de conserver des informations transverses entre plusieurs écrans : sélection du trajet, informations voyageur, options, état du panier, contexte utilisateur, étapes du parcours. Ces données ne sont pas seulement une réponse API brute, elles représentent l'état du parcours côté front.

Donc Redux servait plutôt à gérer le state métier côté client, avec des slices par domaine fonctionnel. L'objectif était d'éviter de passer les props partout et d'avoir un état prévisible, centralisé, facilement testable.

TanStack Query, je l'ai utilisé différemment, plutôt à La Poste avec Next.js/NestJS. Son rôle était de gérer l'état serveur : appels API, cache, loading, erreurs, refetch, invalidation après mutation.

Par exemple, pour récupérer une procuration, une liste de dossiers, un détail utilisateur ou des référentiels, TanStack Query évite de recréer à la main toute la logique :

Pourquoi nextjs/ react

Je choisirais [Next.js](http://Next.js), ça depends de l'application, le produit ici c'est 'une plateforme média a des enjeux forts de SEO, de performance et de temps d'affichage initial.

Avec une SPA React classique, le navigateur reçoit beaucoup de JavaScript avant de pouvoir afficher correctement la page. Avec Next.js, je peux rendre une grande partie côté serveur, utiliser les Server Components, le streaming, le cache et l'ISR.

Concrètement, pour une page vidéo ou une page catégorie, je peux afficher rapidement le contenu principal, améliorer le LCP((Largest Contentful Paint), réduire le JavaScript côté client et garder une bonne indexation SEO.

Plus javascript navigateur

Je vais chercher pourquoi autant de JavaScript est envoyé.

Je regarde plusieurs points.

  • D'abord combien de composants utilisent inutilement "use client".

Sur beaucoup de projets, on voit des layouts entiers ou des pages complètes en Client Component alors qu'ils pourraient être rendus côté serveur.

  • Ensuite j'analyse les librairies. Par exemple : une librairie de graphique, une librairie de calendrier, un player vidĂ©o

Ces composants peuvent être chargés dynamiquement uniquement lorsqu'ils sont nécessaires.

Je regarde également le découpage des bundles.

Si une seule page importe une librairie lourde, elle ne doit pas impacter toutes les autres pages.

  • Enfin je regarde si certains composants interactifs pourraient ĂŞtre transformĂ©s en Server Components.

L'objectif est toujours de réduire la quantité de JavaScript envoyée au navigateur.

Plateforme est lente

Nos utilisateurs disent que la plateforme est lente.

Pourtant Lighthouse nous donne 96.

Lighthouse mesure un scénario précis dans un environnement contrôlé.

Les utilisateurs, eux, utilisent :

  • diffĂ©rents tĂ©lĂ©phones ;
  • diffĂ©rents rĂ©seaux ;
  • diffĂ©rents navigateurs.

Je regarde donc les données réelles. Par exemple les Core Web Vitals collectés en production.

Il est possible que Lighthouse soit excellent sur un Mac connecté à la fibre. Mais qu'un téléphone Android milieu de gamme en 4G ait une expérience beaucoup moins bonne. Je fais toujours confiance au Real User Monitoring avant les mesures de laboratoire.

Types une réponse API

Je ne me contente pas de créer un type TypeScript.

Un type TypeScript ne protège qu'au moment du build. Mais une API peut renvoyer une donnée invalide à l'exécution.

Donc pour les flux critiques, je combine TypeScript avec une validation runtime.

J'ai Ă  la fois :

  • validation Ă  l'exĂ©cution ;
  • typage TypeScript ;
  • sĂ©curitĂ© sur les donnĂ©es externes.

Types les props

Je type explicitement les props avec Type, mais je reste simple. Je préfère éviter React.FC par défaut, parce qu'il ajoute implicitement certains comportements comme children, et ce n'est pas toujours souhaité

JuniorCie avec nextjs

Sur Junior & Cie, on a utilisé ou j'ai utilisé le framework avec Next.js 14, React et TypeScript.

L'objectif était de moderniser l'application, améliorer la maintenabilité et sécuriser les parcours de réservation.

J'ai organisé les pages autour du routing Next.js : pages publiques, parcours de réservation, layouts partagés, pages d'erreur et états de chargement.

Pour les pages publiques ou les contenus qui n'avaient pas besoin d'interactivité forte, j'ai privilégié le rendu serveur.

Ça permettait d'avoir un affichage plus rapide, moins de JavaScript côté client et une meilleure base SEO.

Je ne mettais pas "use client" partout.

Je l'utilisais surtout pour les formulaires, les interactions utilisateur, les champs de recherche ou les composants avec useState, useEffect.

JunioCie React Hook Form / Zod

Concrètement, je définissais un schéma Zod pour représenter les règles du formulaire. Ensuite, je le branchais à React Hook Form via zodResolver. Comme ça, la validation était centralisée, typée, réutilisable, et les erreurs remontaient automatiquement dans le formulaire.

Sur les parcours de réservation Junior & Cie, c'était important parce qu'on avait des formulaires avec plusieurs étapes et des règles métier. L'objectif était d'éviter d'avoir des validations dispersées dans les composants. Zod nous permettait d'avoir une source de vérité claire pour la validation.

Pourquoi pas juste useState ?

Pour un petit formulaire, useState peut suffire. Mais sur le formulaire métier avec plusieurs champs, des règles conditionnelles et validations, React Hook Form est plus adapté. Il réduit le boilerplate, et limite les re-render.

Zod Vs Yup

On a choisi Zod principalement parce qu'il s'intègre très bien avec TypeScript.

Le principal avantage est que le schéma de validation devient aussi la source de vérité pour les types.

Avec Zod, je définis une seule fois mon schéma et TypeScript peut automatiquement en déduire le type grâce à z.infer.

Cela évite de maintenir deux définitions différentes : une pour la validation et une autre pour les interfaces TypeScript.

Exemple concret

Prenons un formulaire de réservation. Avec Yup, je pouvais avoir : Interface Passager, et Puis un deuxième fichier const PassengerSchema \= yup.object({...})

Si j'ajoute un champ dans l'interface mais que j'oublie de modifier le schéma Yup, j'ai une incohérence.

Avec Zod, je fais : const PassengerSchema \= z.object({ firstName: z.string(),lastName: z.string()}) et type Passenger \= z.infer\<typeof PassengerSchema>

Le type est directement généré à partir du schéma. Il n'y a plus de duplication.

Avantage Zod

je vois plusieurs tels que

  • Une seule source de vĂ©ritĂ©: Le schĂ©ma sert : Ă  valider, Ă  typer. Je ne maintiens plus deux fichiers.
  • Une excellente intĂ©gration avec TypeScript: L'infĂ©rence de type est très performante. L'autocomplĂ©tion fonctionne immĂ©diatement. Le compilateur dĂ©tecte beaucoup plus facilement les erreurs.
  • RĂ©utilisation Front / Back: Comme nous utilisions aussi Node.js, certains schĂ©mas peuvent ĂŞtre partagĂ©s entre le frontend et le backend. Cela garantit que les mĂŞmes règles mĂ©tier sont appliquĂ©es partout.

Inconvénients de Zod

Je vois que zod:

  • a une syntaxe assez verbeuse lorsque les schĂ©mas sont très complexes.
  • lorsqu'une Ă©quipe possède dĂ©jĂ  beaucoup de schĂ©mas Yup, une migration reprĂ©sente un coĂ»t qu'il faut justifier.

Pourquoi changer Yup ?

Yup est une très bonne bibliothèque. Je ne dirais pas qu'elle est mauvaise. Simplement, elle a été conçue avant que TypeScript soit aussi largement adopté. Son intégration TypeScript est correcte, mais moins naturelle. Aujourd'hui, sur un projet moderne React + Next.js + TypeScript, je trouve que Zod apporte une meilleure cohérence.

Utilisation un CDN

J'utilise cdn dans le projet junior\&ci mais indirectement.

Sur Junior & Cie, l'application était déployée sur une infrastructure où un CDN était déjà en place pour distribuer les ressources statiques.

Je n'étais pas en charge de l'administration du CDN, mais j'ai développé l'application en tenant compte de son fonctionnement.

Par exemple, j' optimise les images avec next/image, les assets statiques sont servis depuis le dossier public, et je fais attention aux stratégies de cache pour que les ressources statiques puissent être correctement mises en cache.

J'ai donc travaillé avec un CDN, même si je n'ai pas configuré moi-même CloudFront en prod

Mis en cache dans Next.js

Principalement les ressources statiques :

  • les images ;
  • les fichiers JavaScript ;
  • les feuilles de style ;
  • les polices ;
  • les fichiers du dossier public.

Selon la stratégie de rendu, certaines pages générées statiquement ou via ISR peuvent également être distribuées par le CDN.

Mais, les données personnalisées ou très dynamiques ne sont généralement pas mises en cache de la même manière.

Comment next/image profite du CDN ?

Lorsque l'image est optimisée par Next.js, elle est redimensionnée et convertie dans un format adapté.

Une fois générée, cette version optimisée peut être mise en cache par le CDN.

Ainsi, les utilisateurs suivants récupèrent directement l'image depuis le CDN, sans solliciter à nouveau le serveur d'origine.

Cela améliore les temps de chargement et réduit la charge sur l'infrastructure.

Avez-vous fait concrètement pour que le CDN ?

Sur le projet Junior\&Cie, Je n'ai pas configuré le CDN lui-même, mais j'ai appliqué les bonnes pratiques côté application.

Par exemple :

  • utilisation de next/image pour optimiser les images ;
  • limitation des ressources inutiles ;
  • rĂ©duction du bundle JavaScript en privilĂ©giant les Server Components lorsque c'Ă©tait pertinent ;
  • gestion des assets statiques via le dossier public ;
  • choix d'une stratĂ©gie de rendu adaptĂ©e (SSR ou rendu statique selon les pages).

L'objectif était de fournir des ressources facilement cacheables et performantes.

Si demain on vous demande de configurer CloudFront, savez-vous le faire ?

Je connais le principe de fonctionnement d'un CDN et son intégration avec une application Next.js, mais je n'ai pas encore eu l'occasion de configurer moi-même CloudFront ou Akamai en production.

Mais, je suis à l'aise pour collaborer avec les équipes DevOps sur ces sujets. Je comprends les notions de cache, de TTL, d'invalidation, de distribution des assets et les impacts sur les performances de l'application.

Protocole Authentification HTTP Basic Authentication

Mécanisme: L'utilisateur fournit un nom d'utilisateur et un mot de passe qui sont encodés en base64 et envoyés avec chaque requête HTTP.

Avantages: Simplicité de mise en œuvre.

Inconvénients: Non sécurisé en l'absence de chiffrement (comme HTTPS). Les identifiants peuvent être facilement décodés. Pas adapté pour une authentification moderne.

HTTP Digest Authentication:

Mécanisme: Amélioration de la Basic Auth. Utilise un défi-réponse avec un hachage pour éviter d'envoyer le mot de passe en clair.

Avantages: Plus sécurisé que la Basic Auth.

Inconvénients: Encore moins courant et nécessite un échange supplémentaire pour le défi.

OAuth 2.0:

Mécanisme: Un protocole d'autorisation qui permet à des applications tierces d'accéder à des ressources d'utilisateur sans partager leurs identifiants.

Avantages: Flexible, supporte différents "grants" ou flux pour différents scénarios. Largement adopté pour les API modernes.

Inconvénients: Plus complexe. N'est pas en soi un protocole d'authentification (c'est là qu'OpenID Connect intervient).

OAuth 2.0 est un protocole d'autorisation qui permet à des applications tierces d'obtenir un accès limité à des ressources d'utilisateur sur un serveur, sans avoir besoin des identifiants de l'utilisateur. Il est largement utilisé pour accorder des jetons d'accès à des applications pour accéder aux comptes utilisateurs sur des services tels que Google, Facebook, et GitHub,

OpenID Connect (OIDC):

Mécanisme: Une couche d'authentification construite sur OAuth 2.0.

Avantages: Ajoute une authentification à OAuth 2.0, renvoie un ID token (JWT) contenant des informations sur l'utilisateur. Largement adopté et standardisé.

Inconvénients: Nécessite une compréhension d'OAuth 2.0. Peut être considéré comme complexe pour certains scénarios.

OpenID Connect (OIDC) est un protocole d'identité basé sur OAuth 2.0 qui facilite l'authentification des utilisateurs finale dans une application, en utilisant un fournisseur d'identité. OIDC ajoute une couche d'authentification à OAuth 2.0, qui est à l'origine un protocole d'autorisation.

Voici une explication simplifiée du flux:

  • Initialisation: L'application React dĂ©marre le processus d'authentification en redirigeant l'utilisateur vers le serveur d'authentification Keycloak.
  • Authentification: L'utilisateur s'authentifie auprès de Keycloak (via un formulaire de connexion ou tout autre mĂ©canisme d'authentification supportĂ©).
  • Redirection avec Jeton: Une fois l'authentification rĂ©ussie, Keycloak redirige l'utilisateur vers le point de terminaison de redirection (callback) de l'application React avec un code d'autorisation.
  • Échange de Code d'Autorisation: L'application React Ă©change le code d'autorisation avec Keycloak pour obtenir des jetons (un jeton d'accès et Ă©ventuellement un jeton d'identitĂ© et un jeton de rafraĂ®chissement).
  • Connexion au Backend: Avec le jeton d'accès obtenu, l'application React peut effectuer des appels sĂ©curisĂ©s au backend, qui vĂ©rifie la validitĂ© du jeton (gĂ©nĂ©ralement en le vĂ©rifiant avec Keycloak ou en vĂ©rifiant sa signature).

SAML (Security Assertion Markup Language):

Mécanisme: Un protocole XML pour l'échange d'informations d'authentification et d'autorisation. Utilisé pour le Single Sign-On (SSO) entre domaines.

Avantages: Éprouvé, largement utilisé dans les entreprises pour le SSO.

Inconvénients: Basé sur XML, donc considéré comme plus lourd que OIDC. Plus complexe à mettre en œuvre que OIDC.

SAML est un standard ouvert pour l'échange d'informations d'authentification et d'autorisation entre parties, principalement entre un fournisseur d'identité (Identity Provider, IdP) et un fournisseur de services (Service Provider, SP). SAML est utilisé pour le Single Sign-On (SSO) entre applications et services, permettant aux utilisateurs de se connecter une fois et d'avoir accès à plusieurs applications et services sans avoir à se reconnecter.

JWT (JSON Web Tokens):

Mécanisme: Un standard pour l'échange d'informations entre parties sous forme de tokens JSON. Souvent utilisé avec OAuth 2.0 et OIDC.

Avantages: Compact, peut être signé et crypté.

Inconvénients: JWT en soi n'est pas un protocole d'authentification, mais un format de token. La sécurité dépend de la bonne mise en œuvre et de la gestion appropriée des clés.

Authentification vs Autorisation

Authentification : Il s'agit de vérifier l'identité d'un utilisateur, généralement en demandant un nom d'utilisateur et un mot de passe. C'est le processus qui détermine si quelqu'un est bien qui il prétend être.

Autorisation : Une fois l'identité d'un utilisateur confirmée, l'autorisation détermine ce qu'il est autorisé à faire. Par exemple, un utilisateur peut être autorisé à visualiser une page, mais pas à la modifier.

Server First

Server First est une manière de concevoir une application. Lorsque je développe une page, je pars toujours du principe que le composant doit être un Server Component. Je ne le transforme en Client Component que lorsqu'il a réellement besoin du navigateur. Sur Junior & Cie, par exemple, les pages publiques ou les composants d'affichage pouvaient être rendus côté serveur. En revanche, les formulaires de réservation, les champs de saisie ou les composants nécessitant useState ou des événements utilisateur devenaient des Client Components. Cette approche permet de réduire le JavaScript envoyé au navigateur, de limiter l'hydratation et d'améliorer les performances.