00:00:00(musique entraînante) - Bonjour à tous.
00:00:06Je m'appelle Aurora.
00:00:07Je suis développeuse web, originaire de Norvège.
00:00:09Je suis consultante chez Crane Consulting et je développe activement avec le routeur d'applications Next.js dans mon projet de conseil actuel.
00:00:16Aujourd'hui,
00:00:17je vais vous présenter des modèles de composition,
00:00:19de mise en cache et d'architecture dans Next.js moderne qui vous aideront à garantir l'évolutivité et la performance.
00:00:24Permettez-moi d'abord de rafraîchir le concept le plus fondamental de cette présentation : le rendu statique et dynamique.
00:00:30Nous les rencontrons tous deux dans le routeur d'applications Next.js.
00:00:33Le rendu statique nous permet de créer des sites web plus rapides,
00:00:36car le contenu pré-rendu peut être mis en cache et distribué mondialement,
00:00:39garantissant un accès plus rapide aux utilisateurs.
00:00:42Par exemple, le site web de la Next.js Conf.
00:00:46Le rendu statique réduit la charge du serveur,
00:00:48car le contenu n'a pas besoin d'être généré pour chaque requête utilisateur.
00:00:51Le contenu pré-rendu est également plus facile à indexer pour les robots des moteurs de recherche,
00:00:56car il est déjà disponible au chargement de la page.
00:00:58Le rendu dynamique,
00:00:59en revanche,
00:01:00permet à notre application d'afficher des données en temps réel ou fréquemment mises à jour.
00:01:05Il nous permet également de proposer du contenu personnalisé,
00:01:07comme des tableaux de bord et des profils utilisateur.
00:01:09Par exemple, le tableau de bord Vercel.
00:01:12Avec le rendu dynamique,
00:01:13nous pouvons accéder à des informations qui ne peuvent être connues qu'au moment de la requête.
00:01:16Dans ce cas,
00:01:17quel utilisateur accède à son tableau de bord,
00:01:19c'est-à-dire moi.
00:01:20Certaines API peuvent provoquer un rendu dynamique de la page.
00:01:25L'utilisation des props `params` et `search params` passées aux pages ou de leurs hooks équivalents entraînera un rendu dynamique.
00:01:32Cependant,
00:01:32avec `params`,
00:01:33nous pouvons prédéfinir un ensemble de pages pré-rendues à l'aide de `static params` génériques,
00:01:36et nous pouvons également mettre en cache les pages au fur et à mesure qu'elles sont générées par les utilisateurs.
00:01:40De plus,
00:01:41la lecture des cookies et en-têtes de requête entrants fera basculer la page en rendu dynamique.
00:01:46Contrairement aux `params`,
00:01:47cependant,
00:01:48tenter de mettre en cache ou de pré-rendre quoi que ce soit en utilisant des en-têtes ou des cookies provoquera des erreurs lors de la compilation,
00:01:52car ces informations ne peuvent pas être connues à l'avance.
00:01:56Enfin,
00:01:56l'utilisation de `fetch` avec une configuration de cache de données `no store` forcera également le rendu dynamique.
00:02:00Ce sont les principales.
00:02:01Il existe quelques autres API qui peuvent provoquer un rendu dynamique,
00:02:04mais ce sont celles que nous rencontrons le plus souvent..
00:02:06Dans les versions précédentes de Next,
00:02:08une page était rendue soit entièrement statique,
00:02:11soit entièrement dynamique.
00:02:13Une seule API dynamique sur une page fera basculer toute la page en rendu dynamique.
00:02:17Par exemple,
00:02:18une simple vérification d'authentification pour la valeur d'un cookie.
00:02:20En utilisant les composants serveur React avec `Suspense`,
00:02:23nous pouvons diffuser du contenu dynamique,
00:02:25comme une bannière de bienvenue personnalisée ou des recommandations,
00:02:28dès qu'ils sont prêts,
00:02:29et ne fournir que des `fallbacks` avec `Suspense` tout en affichant du contenu statique,
00:02:32comme une newsletter.
00:02:34Cependant,
00:02:34une fois que nous ajoutons plusieurs composants asynchrones sur une page dynamique,
00:02:38comme un produit vedette,
00:02:40ils s'exécuteraient également au moment de la requête,
00:02:42même s'ils ne dépendaient pas d'API dynamiques.
00:02:45Ainsi,
00:02:45pour éviter de bloquer le chargement initial de la page,
00:02:48nous suspendrions et diffuserions également ces composants,
00:02:50ce qui impliquerait un travail supplémentaire,
00:02:52la création de squelettes et des préoccupations concernant des éléments comme le décalage de mise en page.
00:02:56Cependant,
00:02:57les pages sont souvent un mélange de contenu statique et dynamique.
00:03:01Par exemple,
00:03:01une application e-commerce dépendante des informations utilisateur tout en contenant majoritairement des données statiques.
00:03:07Être forcé de choisir entre eux,
00:03:09entre statique ou dynamique,
00:03:10entraîne beaucoup de traitement redondant sur le serveur pour du contenu qui ne change jamais ou très rarement,
00:03:17et n'est pas optimal pour la performance.
00:03:19Pour résoudre ce problème,
00:03:21lors de la Next.js Conf de l'année dernière,
00:03:23la directive `use cache` a été annoncée.
00:03:26Et cette année,
00:03:26comme nous l'avons vu lors de la keynote,
00:03:28elle est disponible dans Next.js 16.
00:03:30Ainsi,
00:03:31avec `use cache`,
00:03:32les pages ne seront plus contraintes à un rendu statique ou dynamique.
00:03:36Elles peuvent être les deux.
00:03:37Et Next.js n'a plus à deviner la nature d'une page en fonction de son accès à des éléments comme les `params`.
00:03:43Tout est dynamique par défaut et `use cache` nous permet d'opter explicitement pour la mise en cache.
00:03:47`Use cache` permet une mise en cache composable.
00:03:51Nous pouvons marquer une page,
00:03:52un composant React ou une fonction comme pouvant être mis en cache.
00:03:55Ici,
00:03:56nous pouvons effectivement mettre en cache le composant des produits vedettes,
00:03:59car il n'a pas besoin de la requête et du traitement,
00:04:02et n'utilise pas d'API dynamiques.
00:04:03Et ces segments mis en cache peuvent être pré-rendus et inclus dans le shell statique avec le pré-rendu partiel,
00:04:08ce qui signifie que les produits vedettes sont désormais disponibles au chargement de la page et n'ont pas besoin d'être diffusés.
00:04:14Maintenant que nous avons ces connaissances de base importantes,
00:04:18passons à une démonstration.
00:04:19Une amélioration d'une base de code présentant des problèmes courants souvent rencontrés dans les applications Next.js.
00:04:24Ces problèmes incluent le `prop drilling` profond,
00:04:26rendant difficile la maintenance et la refactorisation des fonctionnalités,
00:04:28un JavaScript côté client redondant et des composants volumineux avec de multiples responsabilités,
00:04:32ainsi qu'un manque de rendu statique,
00:04:33entraînant des coûts de serveur supplémentaires et une performance dégradée.
00:04:36Alors oui, commençons.
00:04:37Et donnez-moi une seconde ici.
00:04:50Très bien, parfait.
00:04:54C'est une application très simple.
00:04:56Elle est inspirée d'une plateforme e-commerce.
00:04:59Et laissez-moi faire une première démonstration ici.
00:05:01Je peux donc charger cette page.
00:05:03J'ai du contenu comme ce produit vedette.
00:05:06J'ai des catégories vedettes,
00:05:07différentes données de produits.
00:05:09Il y a aussi cette page 'Parcourir tout' où je peux voir tous les produits de la plateforme et naviguer entre eux.
00:05:20Ensuite,
00:05:20nous avons cette page 'À propos' qui est juste statique.
00:05:24Je peux aussi me connecter en tant qu'utilisateur.
00:05:27Et cela me connectera à mon compte utilisateur.
00:05:30Et aussi obtenir ensuite du contenu personnalisé sur mon tableau de bord ici.
00:05:33Comme par exemple,
00:05:34des produits recommandés ou ces réductions personnalisées ici.
00:05:38Remarquez ici, il y a un assez bon mélange.
00:05:42Oh, et aussi une page que j'ai oublié de vous montrer.
00:05:45La page produit, la plus importante.
00:05:47Ici aussi,
00:05:48nous pouvons voir les informations sur le produit et les enregistrer si nous le souhaitons pour notre utilisateur.
00:05:52Remarquez donc qu'il y a un assez bon mélange de contenu statique et dynamique dans cette application en raison de toutes nos fonctionnalités dépendantes de l'utilisateur.
00:05:59Jetons également un coup d'œil au code, qui se trouve ici.
00:06:05J'utilise le routeur d'applications ici,
00:06:07bien sûr,
00:06:07dans Next.js 16.
00:06:08J'ai toutes mes différentes pages,
00:06:10comme la page 'À propos',
00:06:11la page 'Tout',
00:06:12notre page produit.
00:06:13J'ai aussi...
00:06:14j'utilise le découpage par fonctionnalité ici pour garder mon dossier d'application propre..
00:06:17J'ai différents composants et requêtes qui communiquent avec ma base de données via Prisma.
00:06:23Alors oui, et j'ai délibérément ralenti tout cela.
00:06:25C'est pourquoi nous avons cette très longue phase de chargement,
00:06:28juste pour que nous puissions plus facilement voir ce qui se passe.
00:06:31Les problèmes courants sur lesquels nous voulions travailler ici et que nous avons réellement dans cette application étaient le `prop drilling`,
00:06:37rendant difficile la maintenance et la refactorisation des fonctionnalités,
00:06:40l'accès au JavaScript côté client,
00:06:42et le manque de rendu statique entraînant des coûts de serveur supplémentaires et une performance intégrée.
00:06:47L'objectif de cette démonstration est donc d'améliorer cette application avec des modèles intelligents de composition,
00:06:53de mise en cache et d'architecture pour corriger ces problèmes courants et la rendre plus rapide,
00:06:58plus évolutive et plus facile à maintenir.
00:07:01Alors, commençons par cela.
00:07:02Le premier problème que nous voulons résoudre est en fait lié au `prop drilling`.
00:07:05Et ce serait ici dans la page.
00:07:10Remarquez ici, j'ai cette variable `logged in` en haut.
00:07:15Et vous pouvez voir que je la transmets à quelques composants.
00:07:17Elle a en fait été transmise à plusieurs niveaux jusqu'à cette bannière personnalisée.
00:07:20Cela va donc rendre difficile la réutilisation des éléments ici,
00:07:23car nous avons toujours cette dépendance `logged in` pour notre bannière de bienvenue.
00:07:28Avec les composants serveur,
00:07:29la meilleure pratique serait de pousser la récupération de données vers les composants qui l'utilisent et de résoudre les promesses plus profondément dans l'arbre.
00:07:37Et pour que cela soit authentifié,
00:07:39tant que cela utilise `fetch` ou quelque chose comme `React cache`,
00:07:42nous pouvons dupliquer plusieurs appels de ceci,
00:07:44et nous pouvons simplement le réutiliser partout où nous le souhaitons à l'intérieur de nos composants.
00:07:48Ce serait donc tout à fait réutilisable.
00:07:51Nous pouvons donc maintenant déplacer cela dans la section personnalisée ici.
00:07:54Et nous n'aurons plus besoin de cette prop.
00:07:57Et il suffit de le mettre directement – oups – ici.
00:08:01Et nous n'aurons plus besoin de le passer.
00:08:04Et puisque nous déplaçons maintenant cet appel asynchrone dans la section personnalisée,
00:08:07nous ne bloquons plus la page.
00:08:09Nous pouvons aller de l'avant et le suspendre avec un simple `Suspense` ici.
00:08:13Et nous n'aurons pas besoin de ce `fallback`.
00:08:16Quant à la bannière de bienvenue,
00:08:19je suppose que nous allons faire de même.
00:08:22Mais essayer d'utiliser la variable ou la valeur `logged in` ici,
00:08:26ça ne marche pas,
00:08:26n'est-ce pas ?
00:08:27Parce que c'est un composant client.
00:08:29Nous devons donc résoudre cela d'une manière différente.
00:08:30Et nous allons utiliser un modèle assez intelligent ici pour résoudre cela.
00:08:33Nous allons en fait aller dans le `layout` et tout envelopper ici avec un `auth provider`.
00:08:39Je vais donc mettre cela autour de toute mon application ici et obtenir cette variable `logged in` ici.
00:08:45Et je ne veux absolument pas bloquer tout mon `root layout`.
00:08:48Allons-y et supprimons l'`await` ici.
00:08:50Et passons simplement cela comme une promesse à ce `auth provider`.
00:08:55Et cela peut juste contenir cette promesse.
00:08:57Elle peut juste rester là à attendre que nous soyons prêts à la lire.
00:09:01Maintenant que c'est configuré.
00:09:03Cela signifie que nous pouvons en fait aller de l'avant et nous débarrasser de cette prop,
00:09:08tout d'abord.
00:09:09Et nous nous débarrasserons de celle-ci qui descend jusqu'à la bannière personnalisée.
00:09:12Et nous nous débarrasserons également du `prop drilling` ici ou de la signature.
00:09:16Et maintenant,
00:09:17nous pouvons utiliser ce `auth provider` pour récupérer cette valeur `logged in` localement à l'intérieur de la bannière personnalisée avec `use auth` avec ce fournisseur que nous venons de créer.
00:09:26Et la lire avec `use`.
00:09:28Cela fonctionnera donc en quelque sorte de manière à ce que nous devions le suspendre pendant qu'il se résout.
00:09:33J'ai donc maintenant co-localisé cette petite récupération de données à l'intérieur de la bannière personnalisée.
00:09:37Et je n'ai pas à passer ces props partout.
00:09:40Et pendant que cela se résout,
00:09:41allons-y et suspendons également celui-ci avec un `fallback`.
00:09:44Et faisons juste une bannière générale ici pour éviter tout décalage cumulatif étrange.
00:09:51Et enfin, débarrassons-nous également de celui-ci.
00:09:53Donc maintenant, cette bannière de bienvenue est composable.
00:09:58Elle est réutilisable.
00:09:59Nous n'avons pas de props ou de dépendances étranges sur la page d'accueil.
00:10:02Et puisque nous pouvons le réutiliser si facilement,
00:10:06allons-y et ajoutons-le également à cette page de navigation ici,
00:10:10qui sera là.
00:10:11Et je peux simplement l'utiliser ici sans aucune dépendance.
00:10:15Ainsi,
00:10:16grâce à ces modèles,
00:10:17nous sommes en mesure de maintenir une bonne architecture de composants en utilisant `React cache`,
00:10:25`React use`,
00:10:25et de rendre nos composants plus utilisables et composables.
00:10:30Très bien.
00:10:31Abordons le prochain défi courant,
00:10:33qui serait un JavaScript côté client excessif et des composants volumineux avec de multiples responsabilités.
00:10:40En fait, c'est aussi sur la page 'Tout' ici.
00:10:43Et encore une fois,
00:10:44nous devrons travailler sur cette bannière de bienvenue.
00:10:46C'est actuellement un composant client.
00:10:48Et la raison pour laquelle c'est un composant client est que j'ai cet état `dismissed` très simple ici.
00:10:53Je peux juste cliquer dessus.
00:10:54C'est une belle interaction UI.
00:10:56C'est bon.
00:10:57Ce qui n'est pas si bien,
00:10:58cependant,
00:10:59c'est qu'à cause de cela,
00:11:00je convertis tout ce composant en un composant côté client ou un composant client.
00:11:04Et j'utilise même `swr` pour la récupération côté client.
00:11:07J'ai maintenant cette couche API ici.
00:11:08Je n'ai plus de sécurité de type dans mes données.
00:11:11Oui, ce n'est pas nécessaire.
00:11:12Et nous brisons également la séparation des préoccupations ici parce que nous mélangeons la logique UI avec les données.
00:11:18Alors allons-y et utilisons un autre modèle intelligent pour résoudre cela.
00:11:21Il s'appelle le `donut pattern`.
00:11:23En gros,
00:11:23ce que je vais faire,
00:11:24c'est l'extraire dans un `wrapper` côté client.
00:11:27Alors créons un nouveau composant ici.
00:11:29Et appelons-le `banner container`.
00:11:32Et cela va contenir notre logique interactive avec la directive `use client`.
00:11:37Nous pouvons créer la signature.
00:11:38Nous pouvons coller tout ce que nous avions plus tôt.
00:11:42Et au lieu d'utiliser ces bannières,
00:11:44je vais juste insérer une prop ici,
00:11:46qui sera les `children`.
00:11:48C'est pourquoi on l'appelle le `donut pattern`.
00:11:50Nous créons simplement cette logique UI `wrapper` autour du contenu rendu par le serveur,
00:11:54ou cela pourrait être du contenu rendu par le serveur.
00:11:56Et puis,
00:11:57puisque nous n'avons plus cette dépendance côté client,
00:11:59nous pouvons aller de l'avant et supprimer le `use client`.
00:12:01Nous pouvons utiliser notre fonction asynchrone `isAuth` ici à la place.
00:12:06Nous pouvons en faire un composant serveur asynchrone.
00:12:09Nous pouvons même remplacer la récupération côté client par la récupération côté serveur.
00:12:11Alors,
00:12:12laissez-moi récupérer directement les données de réduction ici.
00:12:16Données de réduction.
00:12:18Et utilisons simplement notre modèle mental habituel comme avant avec la sécurité de type.
00:12:24Et cela signifie que je peux aussi supprimer cette couche API avec laquelle je ne veux pas travailler de toute façon.
00:12:29Enfin,
00:12:29pour `isLoading`,
00:12:30nous pouvons simplement exporter une nouvelle bannière de bienvenue ici avec notre conteneur de bannière `donut pattern` contenant du contenu rendu par le serveur.
00:12:38Et cela signifie que nous n'avons plus besoin de cet `isLoading`.
00:12:40Nous avons donc essentiellement refactorisé tout cela en un composant serveur et extrait un point de logique UI.
00:12:46Mais qu'est-ce que c'est ?
00:12:48Il semble que j'aie une autre erreur.
00:12:51C'est en fait à cause de `Motion`.
00:12:53Utilisez `Motion`.
00:12:54C'est une très bonne bibliothèque d'animation,
00:12:56mais elle nécessite la directive `useClient`.
00:12:59Et encore une fois,
00:13:00nous n'avons pas à rendre cela `useClient` juste pour l'animation.
00:13:03Nous pouvons créer,
00:13:04encore une fois,
00:13:05un `wrapper donut pattern` et simplement extraire des `wrappers` pour ces animations.
00:13:10Et cela signifie que nous n'avons pas à convertir quoi que ce soit ici en côté client.
00:13:14Et il me manque probablement quelque chose ici.
00:13:17Oui.
00:13:18Voilà.
00:13:21Donc maintenant, tout ici a été converti en serveur.
00:13:23Nous avons la même interaction.
00:13:24Nous avons toujours notre logique interactive ici,
00:13:26mais maintenant nous avons cette seule façon de récupérer des données.
00:13:29Et nous avons beaucoup moins de JS côté client.
00:13:31En fait,
00:13:32j'utilise moi-même ce `donut pattern` pour cet `UI boundary helper`,
00:13:40qui ressemble à ceci.
00:13:42Vous voyez ?
00:13:43Donc cela montre,
00:13:44encore une fois,
00:13:44ce que je veux dire,
00:13:45n'est-ce pas ?
00:13:45Avec le `donut pattern`,
00:13:46nous avons ce composant client autour d'un composant serveur.
00:13:49J'ai également marqué beaucoup de mes autres composants avec cet `UI helper` ici.
00:13:53Ici aussi, j'ai plus de composants serveur.
00:13:56Allons-y et améliorons ceux-là aussi,
00:13:58puisque nous devenons assez bons à cela maintenant.
00:14:01Ils sont dans le pied de page.
00:14:04Ces catégories...
00:14:04je veux dire,
00:14:05j'ai ce joli composant qui récupère ses propres données..
00:14:08Et je voulais juste ajouter ce truc `showMore`,
00:14:11juste au cas où ça deviendrait vraiment long.
00:14:14Et avec le `donut pattern`,
00:14:15je peux juste envelopper un composant `showMore` ici.
00:14:20Et cela contiendra ma logique UI.
00:14:23Et ça ressemble à ça, n'est-ce pas ?
00:14:27Plutôt cool.
00:14:28Et cela contient maintenant la logique client,
00:14:31nous permettant d'utiliser l'état.
00:14:33Nous utilisons le `children count` et `to array` pour découper cela.
00:14:36Et ce qui est si cool ici,
00:14:37c'est que ces deux-là sont maintenant des composants entièrement composables et réutilisables qui fonctionnent ensemble comme ceci.
00:14:42C'est vraiment la beauté de ces modèles que nous apprenons ici.
00:14:45Vous pouvez l'utiliser pour n'importe quoi.
00:14:50Je l'utilise aussi pour cette modale ici.
00:14:52Oui,
00:14:52rappelez-vous juste cela la prochaine fois que vous envisagerez d'ajouter une logique client à vos composants serveur.
00:14:59OK, nous connaissons le `donut pattern`.
00:15:01Nous savons comment l'utiliser pour créer ces composants composables et éviter le JS côté client,
00:15:07nous pouvons donc passer au dernier problème.
00:15:10Laissez-moi fermer cela à nouveau.
00:15:13Ce serait donc un manque de stratégies de rendu statique,
00:15:17n'est-ce pas ?
00:15:18En regardant ma sortie de compilation,
00:15:20j'ai en fait chaque page qui est une page dynamique ici.
00:15:24Cela signifie donc que chaque fois que je charge quelque chose ici,
00:15:27cela va s'exécuter pour chaque utilisateur.
00:15:29Désolé.
00:15:30Chaque utilisateur qui est ouvert à cela va obtenir cet état de chargement.
00:15:33Cela va gaspiller des coûts de serveur,
00:15:35rendant la performance pire.
00:15:37Et cela signifie aussi que quelque chose à l'intérieur de mes pages provoque un rendu dynamique ou force un rendu dynamique pour toutes mes pages.
00:15:45En fait, c'est à l'intérieur de mon `root layout`.
00:15:49Je ne sais pas si vous avez déjà rencontré cela.
00:15:51C'est ici.
00:15:53Dans mon en-tête, j'ai ce profil utilisateur.
00:15:57Et cela utilise,
00:15:57bien sûr,
00:15:58des cookies pour obtenir l'utilisateur actuel,
00:16:00et cela signifie que tout le reste est également rendu dynamiquement.
00:16:02Parce que encore une fois,
00:16:03les pages peuvent être soit dynamiques,
00:16:05soit statiques,
00:16:05n'est-ce pas ?
00:16:06C'est un problème assez courant et quelque chose qui a déjà été résolu dans les versions précédentes de Next,
00:16:11alors voyons ce que nous pourrions faire.
00:16:13Une chose que nous pourrions faire est de créer un groupe de routes et de diviser notre application en sections statiques et dynamiques,
00:16:20ce qui me permettrait d'extraire ma page 'À propos'.
00:16:23Je pourrais la rendre statiquement.
00:16:25C'est acceptable pour certaines applications,
00:16:27mais dans mon cas,
00:16:28la page importante est la page produit,
00:16:30et celle-ci est toujours dynamique,
00:16:32donc pas vraiment utile.
00:16:33Que diriez-vous de cette stratégie ?
00:16:35Donc ici,
00:16:35je crée ce paramètre de contexte de requête encodant un certain état dans mon URL,
00:16:40et ensuite je peux utiliser `generate static params` pour générer toutes les différentes variantes de mes pages.
00:16:46Cela me permettrait en fait,
00:16:48combiné à la récupération côté client des données utilisateur,
00:16:51de mettre cela en cache sur ma page produit.
00:16:54Certainement un modèle viable.
00:16:55C'est recommandé par le SDK Vercel Flags,
00:16:58appelé le `precompute pattern`,
00:17:00je crois.
00:17:00Mais c'est vraiment complexe,
00:17:01et j'ai plusieurs façons de récupérer des données.
00:17:04Et en fait,
00:17:04je ne veux pas réécrire toute mon application pour cela.
00:17:07Et si nous n'avions pas à faire toutes ces solutions de contournement ?
00:17:10Et s'il y avait un moyen plus simple ?
00:17:12Eh bien, il y en a un.
00:17:14Revenons à notre application.
00:17:17Nous pouvons donc en fait aller dans la configuration Next et simplement activer les composants de cache.
00:17:23Oh, super.
00:17:25OK,
00:17:25et ce que cela fait,
00:17:26comme vous le savez d'après la keynote,
00:17:29c'est que toutes nos appels asynchrones seront optés pour le temps de requête ou dynamique.
00:17:34Et cela nous donnera également des erreurs chaque fois que nous aurons un appel asynchrone non suspendu,
00:17:39et cela nous donnera cette directive `use cache` que nous pourrons utiliser pour mettre en cache de manière granulaire une page,
00:17:46une fonction ou un composant.
00:17:48Alors oui, allons-y et utilisons cela.
00:17:51Nous pouvons commencer par la page d'accueil ici.
00:17:55Jetons un coup d'œil.
00:17:56Donc encore une fois,
00:17:57j'ai ce mélange de contenu statique et dynamique.
00:17:59J'ai ma bannière de bienvenue pour moi,
00:18:01quelque chose pour vous aussi pour moi.
00:18:03Jetons un coup d'œil à cela avec cet `UI helper` à nouveau.
00:18:06Donc par exemple,
00:18:07la bannière est rendue dynamiquement avec ceci ici.
00:18:10Alors que j'ai marqué cela comme rendu hybride parce que le héros,
00:18:14il récupère cette chose asynchrone et ça va assez lentement.
00:18:18Mais cela ne dépend d'aucune sorte de données utilisateur ou d'API dynamiques.
00:18:21Cela signifie donc que tout ce qui est rendu en hybride ici peut en fait être réutilisé à travers les requêtes et à travers les utilisateurs.
00:18:27Et nous pouvons utiliser la directive `use cache` sur cela.
00:18:30Alors ajoutons la directive `use cache` ici et marquons-la comme mise en cache.
00:18:35Et cela me permettra de...
00:18:37chaque fois que je recharge cette page...
00:18:40je n'ai pas sauvegardé cela..
00:18:43Voilà.
00:18:44Cela ne rechargera pas cette partie car elle est mise en cache.
00:18:47C'est maintenant statique, n'est-ce pas ?
00:18:49Et il existe également d'autres API connexes comme le `cache tag` pour me permettre de typer cela ou de valider l'entrée de cache spécifique de manière granulaire ou de définir ma période de révélation.
00:19:01Mais pour cette démo,
00:19:02concentrons-nous simplement sur la directive simple.
00:19:05Maintenant que j'ai cette directive `use cache`,
00:19:07je peux en fait supprimer ma `suspense boundary` autour de ce héros.
00:19:10Et cela signifie...
00:19:12eh bien,
00:19:12ce que cela fera,
00:19:13c'est que le pré-rendu partiel pourra en fait inclure cela dans le shell pré-rendu statiquement afin que ce héros soit,
00:19:20dans ce cas,
00:19:21une partie de ma sortie de compilation..
00:19:23Faisons la même chose pour tout le reste sur cette page qui peut être partagé.
00:19:28Par exemple, j'ai ces catégories vedettes ici.
00:19:31Allons-y et faisons de même là-bas.
00:19:33Et ajoutons la directive `use cache` et marquons-la comme mise en cache.
00:19:37Comme ça.
00:19:39Et nous pouvons supprimer la `suspense boundary`.
00:19:40Nous n'en aurons plus besoin.
00:19:43Pareil pour les produits vedettes.
00:19:44Ajoutons `use cache` et marquons-le comme mis en cache.
00:19:48Oups.
00:19:50Et ensuite supprimons la `suspense boundary`.
00:19:52Remarquez donc la quantité de complexité que je suis capable de supprimer ici.
00:19:55Je n'ai pas à me soucier de mes squelettes,
00:19:57de mon décalage de mise en page cumulatif que je faisais avant.
00:20:00Et la page n'est plus...
00:20:01ou nous n'avons plus cette limitation statique versus dynamique au niveau de la page..
00:20:07Donc maintenant,
00:20:08quand je charge cette page,
00:20:10vous verrez que tout est mis en cache,
00:20:12sauf ce contenu véritablement spécifique à l'utilisateur.
00:20:16Exactement.
00:20:18C'est plutôt cool.
00:20:19Allons sur la page 'Parcourir' et faisons la même chose là-bas.
00:20:24Oui.
00:20:25J'ai déjà marqué toutes mes limites ici pour que vous puissiez facilement comprendre ce qui se passe.
00:20:29Et je veux au moins mettre en cache ces catégories.
00:20:33Il semble que j'aie une erreur, cependant.
00:20:37Peut-être reconnaissez-vous cela.
00:20:38Cela signifie donc que j'ai une route bloquante.
00:20:40Et je n'utilise pas de `suspense boundary` alors que je devrais le faire.
00:20:43En rafraîchissant cela, c'est vrai, hein ?
00:20:46C'est vraiment lent.
00:20:47Et cela cause des problèmes de performance et une mauvaise UX.
00:20:50C'est génial.
00:20:51`Use cache` ou les composants de cache m'aident à identifier mes routes bloquantes.
00:20:55Voyons en fait ce qui se passe à l'intérieur.
00:20:57C'est donc le problème, n'est-ce pas ?
00:20:59Je récupère ces catégories au niveau supérieur et je n'ai pas de `suspense boundary` au-dessus.
00:21:03En gros, nous devons faire un choix.
00:21:05Soit nous ajoutons une `suspense boundary` au-dessus,
00:21:07soit nous optons pour la mise en cache.
00:21:09Faisons d'abord la chose simple et ajoutons juste un `loading.tsx` ici.
00:21:12Et ajoutons une page de chargement ici,
00:21:17une belle UI de squelette.
00:21:21C'est plutôt bien.
00:21:21Cela a résolu l'erreur,
00:21:22mais je n'ai rien d'utile qui se passe sur cette page pendant que j'attends.
00:21:25Je ne peux même pas chercher.
00:21:27Donc avec les composants de cache, le dynamique est comme...
00:21:30ou statique versus dynamique est comme une échelle..
00:21:33Et c'est à nous de décider combien de statique nous voulons dans nos pages.
00:21:37Alors déplaçons cette page plus vers le statique et supprimons à nouveau ce `loading.tsx`.
00:21:43Et ensuite utilisons les modèles que nous apprenions plus tôt pour pousser cette récupération de données dans le composant et la co-localiser avec l'UI.
00:21:50Alors déplaçons cela dans mes filtres de catégories responsives ici.
00:21:54J'en ai deux à cause du design responsive.
00:21:57Je peux en fait aller de l'avant et juste l'ajouter ici.
00:22:01Oups.
00:22:03Et importons cela.
00:22:05Je n'ai plus besoin de cette prop.
00:22:06En fait, mon composant devient plus composable.
00:22:09Et au lieu de le suspendre,
00:22:11ajoutons simplement la directive `use cache`.
00:22:14Et cela devrait suffire.
00:22:16Remarquez donc comment je suis forcé de réfléchir davantage à l'endroit où je résous mes promesses et d'améliorer réellement mon architecture de composants grâce à cela.
00:22:24Je n'ai pas besoin de suspendre cela.
00:22:25Cela sera juste inclus dans le `static shell` ici.
00:22:28La liste des produits, laissez-moi juste la garder fraîche.
00:22:35Pour que je puisse la recharger à chaque fois.
00:22:37Alors que les catégories en bas,
00:22:39je veux aussi les mettre en cache.
00:22:41Alors allons-y et allons au pied de page.
00:22:44Et puisque j'utilise le `donut pattern` ici,
00:22:47cela peut en fait être mis en cache même si c'est à l'intérieur de cette partie de l'UI qui est interactive.
00:22:54C'est donc tout à fait bien.
00:22:55Ce modèle n'était donc pas seulement bon pour la composition,
00:22:57mais aussi pour la mise en cache.
00:22:58Je pense que j'ai une autre erreur là-bas.
00:23:03Voyons ce que c'est.
00:23:04J'ai toujours cette erreur.
00:23:08C'est en fait à cause de ces `search params`.
00:23:10Les `search params`,
00:23:10comme nous le savons,
00:23:11sont une API dynamique.
00:23:12Je ne peux pas mettre cela en cache.
00:23:13Mais je peux le résoudre plus profondément pour révéler plus de mon UI et la rendre statique.
00:23:18Alors allons-y et déplaçons cela,
00:23:20passons-le comme une promesse à la liste des produits.
00:23:24Nous allons le typer comme une promesse ici, comme ça.
00:23:30Résolvons-le à l'intérieur de la liste des produits,
00:23:33utilisons les `search parameters` résolus ici et ici.
00:23:36Et puisque cela est suspendu ici, l'erreur disparaîtra.
00:23:40Donc en rechargeant cela,
00:23:42la seule chose qui se recharge ici est juste la partie que j'ai spécifiquement choisie pour être dynamique.
00:23:48Tout le reste peut être mis en cache.
00:23:49Et cela signifie que je peux interagir avec ma bannière ou même chercher parce que cette partie a déjà été pré-rendue.
00:23:57Très bien,
00:23:58faisons la dernière page ici,
00:24:00qui est la page produit,
00:24:02qui est la plus difficile et la plus importante.
00:24:05C'est vraiment mauvais en ce moment.
00:24:08C'est super important pour une plateforme e-commerce,
00:24:10apparemment.
00:24:11Très bien, allons-y et réparons celui-là aussi.
00:24:15Donc ici, j'ai cette page produit.
00:24:18Commençons par mettre en cache juste le contenu réutilisable ici,
00:24:21par exemple,
00:24:22le produit lui-même.
00:24:23Et ajoutons juste `use cache` ici et marquons-le comme mis en cache.
00:24:27Cela devrait être bon.
00:24:28Cela signifie que nous pouvons supprimer la `suspense boundary` ici.
00:24:33Très bien,
00:24:33et cela ne se recharge plus à chaque requête ici,
00:24:37n'est-ce pas ?
00:24:38Pour les détails du produit, faisons la même chose.
00:24:40Ajoutons `use cache`.
00:24:41Marquons-le comme mis en cache et voyons si cela fonctionnera aussi.
00:24:47Non.
00:24:48En fait, c'est une erreur différente.
00:24:50Cela me dit que j'essaie d'utiliser des API dynamiques à l'intérieur de ce segment mis en cache.
00:24:54Et c'est vrai.
00:24:54J'utilise le bouton 'Enregistrer le produit', n'est-ce pas ?
00:24:56Cela m'a permis de cliquer et de basculer l'état enregistré.
00:25:00Alors, que pensez-vous que nous puissions faire avec cela ?
00:25:03Nous pouvons utiliser le `donut pattern` à nouveau.
00:25:06En fait,
00:25:06nous pouvons aussi insérer des segments dynamiques dans des segments de cache.
00:25:10Nous les intercalons donc comme avant, mais avec le cache.
00:25:12C'est plutôt cool.
00:25:14Allons-y et ajoutons les `children` ici comme ça.
00:25:19Et cela supprimera l'erreur.
00:25:21Et je peux simplement envelopper cela autour de ce seul segment dynamique de ma page ici,
00:25:26supprimer la `suspense boundary`,
00:25:28et ajouter juste une très petite UI de marque-page pour cette seule pièce dynamique de la page.
00:25:34Et voyons à quoi cela ressemble maintenant.
00:25:40Remarquez donc comment presque toute l'UI est disponible,
00:25:43mais j'ai ce petit morceau qui est dynamique,
00:25:46et c'est bien.
00:25:47Tout le reste est toujours là.
00:25:48Et laissons les avis dynamiques parce que nous pourrions les garder à jour.
00:25:53Il y a encore une erreur.
00:25:54Réglons cela rapidement.
00:25:56Encore une fois, ce sont les `params`.
00:25:58On m'aide à faire un choix : soit ajouter un `loading fallback`,
00:26:02soit mettre cela en cache.
00:26:04Utilisons simplement `generate static params` dans ce cas.
00:26:07Cela dépend un peu de votre cas d'utilisation et de votre ensemble de données.
00:26:10Mais pour ce cas,
00:26:10je vais juste ajouter quelques pages prédéfinies pré-rendues et ensuite simplement mettre en cache le reste au fur et à mesure qu'elles sont générées par les utilisateurs.
00:26:17Et cela supprimera mon erreur ici.
00:26:20Je pense donc que j'ai en fait terminé ma refactorisation.
00:26:22Allons-y et jetons un coup d'œil à la version déployée et voyons à quoi cela ressemble.
00:26:26Je viens de déployer cela sur Vercel.
00:26:27Et rappelez-vous,
00:26:29j'ai délibérément ralenti beaucoup de récupérations de données ici.
00:26:35Et pourtant,
00:26:36quand je charge cette page initialement,
00:26:39tout est déjà disponible.
00:26:40La seule chose ici,
00:26:41ce sont juste ces quelques segments dynamiques comme les réductions et le 'pour vous'.
00:26:46Pareil avec le 'parcourir tout'.
00:26:47Toute l'UI est déjà disponible.
00:26:50Et pour le produit lui-même, cela semble instantané.
00:26:54Et rappelez-vous,
00:26:55encore une fois,
00:26:56que tous ces segments de cache seront inclus avec le `static shell` avec le pré-rendu partiel.
00:27:00Et cela peut être pré-récupéré en utilisant le pré-chargement amélioré dans le nouveau routeur client de Next 16.
00:27:05Cela signifie donc que chaque navigation...
00:27:07cela semble si rapide, n'est-ce pas ?.
00:27:09Très bien,
00:27:10pour résumer,
00:27:11avec les composants de cache,
00:27:13il n'y a plus de statique versus dynamique.
00:27:17Et nous n'avons pas besoin d'éviter les API dynamiques ou de compromettre le contenu dynamique.
00:27:28Et nous pouvons ignorer ces hacks et solutions de contournement complexes utilisant plusieurs stratégies de récupération de données juste pour ce seul...
00:27:35ce `cache hit`, comme je vous l'ai montré..
00:27:37Donc dans Next.js moderne,
00:27:39dynamique versus statique est une échelle.
00:27:40Et nous décidons combien de statique nous voulons dans nos applications.
00:27:43Et tant que nous suivons certains modèles,
00:27:45nous pouvons avoir un modèle mental unique,
00:27:47qui est performant,
00:27:48composable et évolutif par défaut.
00:27:50Alors, revenons aux diapositives.
00:27:53Donc si vous n'êtes pas...
00:27:53nous ne sommes pas déjà impressionnés par la vitesse de cela,
00:27:55voici le score Lighthouse..
00:27:56J'ai donc collecté des données de terrain avec les Vercel Speed Insights.
00:28:00Nous avons donc un score de 100 sur toutes les pages les plus importantes,
00:28:03la page d'accueil,
00:28:04la page produit et la liste des produits,
00:28:06même si elles sont très dynamiques.
00:28:08Alors résumons enfin les modèles qui garantiront l'évolutivité et la performance dans les applications Next.js et nous permettront de tirer parti des dernières innovations et d'obtenir des scores comme celui-ci.
00:28:18Premièrement,
00:28:19nous pouvons affiner notre architecture en résolvant les promesses profondément dans l'arbre des composants et en récupérant les données localement à l'intérieur des composants en utilisant `React Cache` pour éviter le travail en double.
00:28:28Nous pouvons éviter le passage excessif de props aux composants client en utilisant des `context providers` combinés avec `React Use`.
00:28:35Deuxièmement,
00:28:35nous pouvons composer des composants serveur et client en utilisant le `donut pattern` pour réduire le JavaScript côté client,
00:28:40maintenir une séparation claire des préoccupations et permettre la réutilisation des composants.
00:28:43Et ce modèle nous permettra en outre de mettre en cache nos composants serveur composés plus tard.
00:28:50Et enfin,
00:28:50nous pouvons mettre en cache et pré-rendre avec `use cache`,
00:28:53soit par page,
00:28:53composant ou fonction,
00:28:54pour éliminer le traitement redondant,
00:28:56améliorer les performances et le SEO,
00:28:57et laisser le pré-rendu partiel rendre statiquement ces segments de l'application.
00:29:01Et si notre contenu est véritablement dynamique,
00:29:04nous pouvons le suspendre avec des `loading fallbacks` appropriés.
00:29:07Et rappelez-vous que tout cela est lié.
00:29:09Ainsi,
00:29:09meilleure est votre architecture,
00:29:10plus il est facile de composer,
00:29:11et plus il sera facile de mettre en cache et de pré-rendre avec les meilleurs résultats.
00:29:15Par exemple,
00:29:15la résolution d'API dynamiques profondément dans l'arbre vous permettra de créer un `static shell` partiellement rendu plus grand.
00:29:22Et avec cela,
00:29:22voici le dépôt de la version complétée de l'application.
00:29:25Il y a tellement de choses que je n'ai même pas montrées et que vous pouvez consulter.
00:29:29Et vous pouvez scanner le code QR pour trouver mes réseaux sociaux là-bas,
00:29:32ainsi que le dépôt,
00:29:33si vous ne voulez pas prendre une photo et le taper vous-même.
00:29:36Alors oui, c'est tout pour moi.
00:29:37Merci à la Next.js Conf de m'avoir accueillie ici.
00:29:39[MUSIQUE]