Next 13

Une introduction sur les Server Components, next/image, @next/font et autres nouveautés annoncées par Next.js pour la version 13.

App directory

Les pages ne sont plus un fichier dans l'aborescence, mais un répertoire.

  • On peut mettre des composants directement dans le répertoire d'une page, quand ils ne sont utilisés que pour cette page.

    Ça s'appelle "colocating", c'est à dire mettre les élements qui sont utilisés ensemble au même endroit. C'est plus facile à lire et à comprendre.

    Les composants qui sont utilisés dans toute l'application peuvent être placés dans un répertoire /components à la racine du projet. Les composants utilisés uniquement dans une page donnée peuvent être placés dans le répertoire de la page, par exemple /app/MY_PAGE/components .

  • On peut définir un fichier layout.tsx par page (donc un par répertoire) qui définira une layout (une mise en page) spécifique à cette page et à tous ses enfants.

@next/font

@next/font permet d'inclure des fonts de manière beaucoup plus simple qu'avant. Cela fonctionne avec les Google Fonts ou les Fonts customs qu'on sert directement depuis notre application - Local Fonts.

Le vrai avantage de @next/font c'est qu'ils sont précompilés par Next au moment du build et servi avec le premier HTML du DOM qui est téléchargé. On n'a donc aucun Content Layout Shift.

Autres avantages:

  • pas de requêtes externes, par example à Google Font, lors d'une visite sur la page par un utilisateur, et donc conforme RGPD. Les requêtes à Google Fonts se font uniquement au build

next/image

Avec next/image les images sont gérées plus facilement, avec encore plus de focus sur la performance:

  • la taille de l'image a générer (pour béneficier des images responsives en fonction du viewport):

    • est calculée automatiquement si l'image est dans le projet

    • doit être fournie avec une width ou une height dans les props obligatoire

next/image fournit automatiquement les attributs srcset qui permet d'afficher l'image de la bonne taille en fonction de l'écran.

  • le paramètre alt est devenu obligatoire pour forcer à rendre les images accessibles

  • props quality pour optimiser automatiquement les images. Par défault quality=75

  • lazy loading automatique

  • présence d'un placeholder blur pour que l'image apparaisse plus vite

    %[loom.com/share/e42d98735abd47c4b5ec4f9d75df..

On peut aussi utiliser next/image pour afficher des SVGs sans avoir recours à des plugins supplémentaires comme svgr

Ajout d'un SVG avec svgr

Ajout d'un SVG avec next/image

Server components

Les composants dans le dossier app/ de Next.js sont par défaut des Server components. Cela veut dire qu'ils sont "rendered" sur le serveur (lambda Node.js hébergée par Vercel par exemple), et non sur le client (le browser).

Cela veut dire que le HTML de chaque composant est généré sur le serveur et renvoyé directement par le serveur. Si le composant est un Server component, il n'y a pas de JS envoyé par le serveur pour ce composant. Ce qui fait un bundle size plus petit téléchargé par le browser.

Avec le directory pages (ancien fonctionnement)

En observant le type de données téléchargées sur une app avec /pages directory:

  • 96.8kB de JS

  • 10.5kB de HTML

Avec le directory app (nouveau)

En observant le type de données téléchargées sur une app avec /app directory:

  • 85kB de JS

  • 15.8kB de HTML

Analyse

Sur la version avec le directory pages/ (ancienne version) on a plus de JavaScript qui est téléchargé et executé. Cela a pour conséquence l'évaluation de plus de code par le browser et donc plus de Total Blocking Time (TBT) et de Time To Interactive (TTI).

Sur la version avec le directory app/ (nouvelle version) la taille du HTML téléchargée est plus grande, on a aussi moins de JavaScript. Le TBT est drastiquement inférieur - 50ms vs 200ms en moyenne - et le TTI est aussi très inférieur - 1.8s vs 2.4s en moyenne. Le browser a moins de code à évaluer et monopolise donc moins de temps avant d'afficher le DOM.

Le First Contentful Paint est sensiblement identique, même s'il est un peu plus rapide sur l'ancienne version (pages/) - 950ms vs 1s en moyenne - pour une raison que j'ignore.

💡 La différence de rapidité est vraiment minime sur une page statique très simple comme celle-ci. Cela nous sert plus à comprendre les différences dans le rendu du HTML / JS et le comportement de l'app.