Next.js
Next.js est devenu le leader incontesté 🎖 des webapp React type SSR ! Next.js 12 Canary est la version courante développée et maintenue par des équipes de Vercel (ex Zeit), la société qui a levé 102$ million en 2021 pour accélérer les développements.
D'un point de vue de développeur, ce qui rend l'usage de Next.js intuitif, réside dans le fait le routage est une correspondance entre un fichier JavaScript et une URL, le fichier /pages/toto.js générera automatiquement l'URL http://monsite/toto, et ce modèle supporte le routage dynamique (avec des variables dans l'URL).
Next.js est donc LE standard en 2022, mais un sérieux concurrent commence a émerger : Remix 💿, créé par les concepteurs de React Router (Michael Jackson & Ryan Florence et rejoints depuis peu Kent C. Dodds). Ecouter une discussion des créateurs de Remix (podcast 🔉).
Intérêts de Next.js
Les intérêts de Next.js par rapport à une solution classique à base d'API Back + React en front sont :
- supporte différentes méthodes de rendu de pages (SSR, SSG et CSR) permettant d'optimiser le SEO. Le SSR est ce qui a fait le succès 🥂 de Next.js.
- utilise un routage (routing) très intuitif et dynamique
- support de > ES6 ainsi que typescript
- guides d'upgrade assez clean pour migrer de version de Next.js et un codemod est également disponible pour automatiser en partie les migrations
- learning curve plutot raide pour les développeurs React avec une prise en main rapide grâce à leurs super tutos 🚀
Routing
Pages
Une URL est crée automatiquement dès qu'on dépose un fichier JS ou JSX dans le dossier /pages/
(par convention).
De plus Next.js supporte:
- les nested routes : l'URL
pages/toto/titi/tutu
sera routée vers le fichiertutu.jsx
pages/toto/titi/tutu.jsx
- les Index routes : l'URL
pages/toto/titi/tutu
sera routée vers le fichierindex
suivant :pages/toto/titi/tutu/index.jsx
- les routes dynamiques (depuis v9) : utilisation d'une variable d'URL
/:toto
pour etre routé vers/[toto].js
(valable pour les dossiers aussi), et de catch all routes/[...toto].js
API
Il est possible depuis Next.js 10 de créer des API dans Next.js, pages/api
sera mappé à /api/*
.
⚠ Attention, cette solution est plutot limités comparée à des solutions robustes et pleines de fonctionnalités comme NestJS. D'après la doc le use case typique d'une API Next.js est de jouer un role de Proxy soit pour masquer des URL internes, soit pour utiliser des variables d'environements. J'ajouterai que c'est un très bon moyen de POCer 🏎 !
Public
Pour les éléments statiques (images, css, robots.txt
, favicon.ico
, et autres) il existe le dossier /public/
(anciennement /static/
) réservé a cet effet.
Cycle de vie du Router
Le Router de Next.js propose un ensemble d'évènements qu'il est possible d'écouter :
- routeChangeStart(url)
- routeChangeComplete(url)
- routeChangeError(err, url)
- beforeHistoryChange(url)
- hashChangeStart(url)
- hashChangeComplete(url)
Navigation
La navigation est simplifiée par l'usage de :
-
composants Next.js Link du package
next/link
-
un routage imperatif grâce au hook
useRouter
du packagenext/router
qui nous retourne un objetrouter
auxquels on peut associer l'objet URL et par exemple pour la fonctionrouter.push
on a les arguments :- la prop href permet au framework de faire le lien entre l'URL et les fichiers JS contenu dans le dossier pages
- la prop as permet de créer et d'afficher dans le HTML résultant un href alias (ici le lien pointera vers /p/xxx), qu'il faudra traité coté back (méthode render de l'API next).
-
le shallow routing qui consiste à ne pas avoir a charger une nouvelle fois la page et byepasser toutes les méthodes de data fetching (
getServerSideProps
,getStaticProps
, etgetInitialProps
) si on navigue sur la meme page.
Data fetching
La Next.js 9.3 a introduit 3 nouvelles fonctions async exporté de pages Next.js qui vont progressivement remplacer l'ancien getInitialProps
:
getStaticProps
etgetServerSideProps
pour distinguer si on utiliser SSR ou SSG pour chaque pagegetStaticPaths
pour générer des pages statiques sur des routes dynamiques
getServerSideProps
getServerSideProps permet de générer la page en mode SSR coté serveur.
Le point intéressant à noter est que lors de l'utilisation de next/link
or next/router
pour la navigation, seul un appel d'API est émis pour récupérer la data sous forme de JSON. Cela permet de ne pas casser le flow de la SPA.
getStaticProps
getStaticProps implique la génération d'une page en mode SSG (comme avec Gatsby).On utilise le SSG lorsque les données sont disponible lors du build et ne sont pas spécifique à un utilisateur (peuvent etre mis en cache).
getStaticPaths
getStaticPaths est utilisé dans le cas de pages utilisant getStaticProps
(ci-dessus) et exploitant la fonctionnalité de Dynamic Routes pour générer toutes les pages avec toutes les combinaisons de routes lors de la build.
getInitialProps (à ne plus utiliser)
Depuis Next.js 9.3 il est recommandé de ne plus utiliser getInitialProps
mais plutot getStaticProps
ou getServerSideProps
.
Styling
styled-jsx le CSS-in-JS de Next.js
Next.js a fait le choix d'embarquer styled-jsx qui est une des solution CSS-in-JS mais il existe de nombreuses solutions qu'il est possible d'utiliser avec Next.js (Styled Components ou Emotion), voir des exemples d'utilisations dans cette section exemple.
Le CSS-in-JS permet d'avoir des styles scopés au niveau du composant, des styles dynamiques fonction du code, et surtout d'appliquer les styles lors du rendu coté serveur.
L'utilisation est encore une fois très intuitive, car il suffit d'écrire ses styles directement dans des balises <style jsx>
à l’intérieur de ses composants en utilisant la syntaxe template strings:
<style global jsx>{`
h1, a {
font-family: "Arial";
}
`}</style>
CSS classique
Il est cependant possible depuis Next.js 9.2 d'utiliser les CSS Modules 🎉 en important directement des .css
(styles global) ou des .module.css
pour des styles scopés au composant.
Squelettes de projets Next.JS
Un outil sympathique, qui fourni un squelette de projet Next.js/React/Redux est create-next-app, parfait pour voir rapidement les branchements entre ces outils :)
Concernant Material UI, il y a un exemple de projet Nexjs/MaterialUI ainsi qu'une doc SSR Material UI.Divers et DX
Appels Ajax
Support de fetch par polyfill coté navigateur (depuis Next.js 9.1.7), et coté Nodejs(depuis Nexjs 9.4). Nous pouvons donc simplement utiliser fetch() partout dans notre code.
Variable d'environnements
Next 9.4 a simplifié et clarifié l'usage des variable d'environnements avec :
- le support des fichiers .env
- par défaut les vars d'env sont disponible uniquement coté serveur, mais s'ils sont prefixés par
NEXT_PUBLIC_
il sont également disponibles dans le navigateur (plus besoin d'utiliser lenext.config.js
pour y définir les vars)
Chemins absolu pour les imports and aliases
Toujours depuis la 9.4 Next.js supporte désormais la personnalisation des chemins d'imports de modules dans le jsconfig.json
(JS projects) ou le tsconfig.json
(TS projects) :
- les chemins absolu en ajoutant la clé
"baseUrl": "."
. - les alias de modules en ajoutant la clé
"paths": {"@/design-system/*": ["components/design-system/*"]}
// tsconfig.json ou jsconfig.json
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/design-system/*": ["components/design-system/*"]
}
}
}
Debugging
La doc Next.js nous fourni (et c'est plutot rare pour le souligner) le .vscode/launch.json
qui est la config de VSCode pour debugger un projet Next.js 😍🥳 🎉.
Elle est un peu particulière parcequ'il faut pouvoir debugger coté client et serveur :
{
"version": "0.2.0",
"configurations": [
{
"name": "Next.js: debug server-side",
"type": "node-terminal",
"request": "launch",
"command": "npm run dev"
},
{
"name": "Next.js: debug client-side",
"type": "pwa-chrome",
"request": "launch",
"url": "http://localhost:3000"
},
{
"name": "Next.js: debug full stack",
"type": "node-terminal",
"request": "launch",
"command": "npm run dev",
"console": "integratedTerminal",
"serverReadyAction": {
"pattern": "started server on .+, url: (https?://.+)",
"uriFormat": "%s",
"action": "debugWithChrome"
}
}
]
}