Skip to content

Commit 0ee8e89

Browse files
Slashgearclaude
andcommitted
docs: add Astro migration study
Comprehensive analysis of migrating from Next.js to Astro, covering feature mapping, interactive components (React islands), ISR strategy, OG image generation, and a phased migration plan. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent 0e8bfe8 commit 0ee8e89

1 file changed

Lines changed: 229 additions & 0 deletions

File tree

docs/migration-astro.md

Lines changed: 229 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,229 @@
1+
# Etude de migration Next.js vers Astro
2+
3+
## Contexte
4+
5+
Le site LyonJS tourne sur Next.js 16 (App Router, React 19, standalone output) deploye sur Scaleway Serverless Containers. Ce document evalue la faisabilite et l'interet d'une migration vers Astro.
6+
7+
## Pourquoi migrer ?
8+
9+
### Avantages attendus
10+
11+
- **Performance** : Astro genere du HTML statique par defaut, zero JS cote client sauf pour les composants interactifs. Le site LyonJS est principalement du contenu statique, donc la majorite des pages n'aurait aucun JS client.
12+
- **Simplicite** : Pas de distinction server component / client component. Tous les composants Astro sont serveur par defaut, le JS client est opt-in via les directives `client:*`.
13+
- **Bundle size** : React n'est charge que pour les "islands" interactives (7 composants sur ~40), pas pour tout le site.
14+
- **MDX natif** : Astro supporte MDX nativement, sans config supplementaire.
15+
- **Build statique** : Astro est concu pour le SSG. Le mode SSR/ISR est possible mais le SSG est le mode par defaut, ce qui colle bien avec le profil du site.
16+
- **Independance framework** : Plus de dependance forte a React pour le rendu des pages. React n'est utilise que la ou il apporte de la valeur (interactivite).
17+
- **Taille de l'image Docker** : Sans le runtime Next.js/Node en mode standalone, l'image serait plus legere.
18+
19+
### Inconvenients / risques
20+
21+
- **Perte de l'ISR** : Next.js revalide les pages toutes les heures (`revalidate = 3600`). En SSG pur avec Astro, il faut rebuilder pour mettre a jour. Solutions : SSR mode, ou rebuild periodique via cron CI.
22+
- **Ecosysteme React reduit** : Les librairies React (`motion`, `yet-another-react-lightbox`, `react-markdown`) fonctionnent via les islands, mais c'est un pattern moins ergonomique que le tout-React.
23+
- **OG images dynamiques** : Next.js genere des images OG via `next/og` (edge runtime + JSX). Astro n'a pas d'equivalent natif, il faut utiliser `@vercel/og`, `satori`, ou generer les images au build.
24+
- **Courbe d'apprentissage** : Syntaxe `.astro` differente de JSX (frontmatter + template). Les contributeurs devront s'adapter.
25+
- **Middleware** : Pas d'equivalent direct au middleware Next.js. Les headers CSP devront etre configures au niveau du serveur (Scaleway / Docker) ou via Astro SSR middleware.
26+
27+
## Inventaire des fonctionnalites a migrer
28+
29+
### Pages et routes
30+
31+
| Next.js (App Router) | Astro | Effort |
32+
|---|---|---|
33+
| `app/page.tsx` | `src/pages/index.astro` | Faible |
34+
| `app/a-propos/page.tsx` | `src/pages/a-propos.astro` | Faible |
35+
| `app/code-de-conduite/page.tsx` | `src/pages/code-de-conduite.astro` | Faible |
36+
| `app/devenir-sponsor/page.tsx` | `src/pages/devenir-sponsor.astro` | Faible |
37+
| `app/budget-et-financement/page.tsx` | `src/pages/budget-et-financement.astro` | Faible |
38+
| `app/evenements-precedents/page.tsx` | `src/pages/evenements-precedents/index.astro` | Faible |
39+
| `app/evenements-precedents/[year]/page.tsx` | `src/pages/evenements-precedents/[year].astro` avec `getStaticPaths()` | Moyen |
40+
| `app/evenement/[slug]/page.tsx` | `src/pages/evenement/[slug].astro` avec `getStaticPaths()` | Moyen |
41+
| `app/lyonjs-100/page.tsx` | `src/pages/lyonjs-100.astro` | Faible |
42+
| `app/not-found.tsx` | `src/pages/404.astro` | Faible |
43+
| `app/layout.tsx` | `src/layouts/Layout.astro` | Moyen |
44+
| `app/robots.ts` | `src/pages/robots.txt.ts` | Faible |
45+
| `app/sitemap.ts` | `@astrojs/sitemap` integration | Faible |
46+
47+
### Data fetching
48+
49+
| Pattern Next.js | Equivalent Astro | Notes |
50+
|---|---|---|
51+
| `generateStaticParams()` | `getStaticPaths()` | Meme concept, syntaxe differente |
52+
| `revalidate = 3600` (ISR) | Rebuild CI ou SSR mode | Pas d'ISR en SSG, voir section dediee |
53+
| `React cache()` | Appel direct dans le frontmatter | Pas de deduplication automatique, mais les appels sont dans le frontmatter donc executes une seule fois |
54+
| Server components async | Composants Astro (async par defaut) | Transition naturelle |
55+
56+
### Composants interactifs (React islands)
57+
58+
Ces 7 composants necessitent du JS client et deviendraient des islands React dans Astro :
59+
60+
| Composant | Utilise | Directive Astro |
61+
|---|---|---|
62+
| `HomeHero.tsx` | motion (animations) | `client:load` |
63+
| `Number.tsx` | motion, next/font | `client:visible` |
64+
| `Collapsible.tsx` | useState | `client:visible` |
65+
| `NavLink.tsx` | next/navigation (usePathname) | `client:load` |
66+
| `MobileNavigation.tsx` | useState, usePathname, useEffect | `client:load` |
67+
| `PhotoAlbum.tsx` | useState, dynamic import lightbox | `client:visible` |
68+
| `EventCard.tsx` | dynamic import react-markdown | `client:visible` |
69+
70+
**Note** : `NavLink` et `MobileNavigation` utilisent `usePathname()` de `next/navigation`. A remplacer par `window.location.pathname` ou `Astro.url.pathname` (partie serveur) + event listeners cote client.
71+
72+
### Images
73+
74+
| Next.js | Astro |
75+
|---|---|
76+
| `next/image` (8 fichiers) | `astro:assets` `<Image>` component |
77+
| `remotePatterns` dans next.config | `image.domains` dans astro.config |
78+
| Optimisation automatique (sharp) | Optimisation automatique (sharp) |
79+
80+
Le composant `<Image>` d'Astro offre les memes fonctionnalites (lazy loading, format moderne, responsive). Migration directe.
81+
82+
### MDX
83+
84+
| Next.js | Astro |
85+
|---|---|
86+
| `@next/mdx` + `mdx-components.tsx` | `@astrojs/mdx` integration |
87+
| 5 fichiers `.mdx` | Meme fichiers, syntaxe compatible |
88+
| Custom components mapping | Components passees via props dans le layout |
89+
90+
Astro a un excellent support MDX natif. Les composants React embarques dans le MDX (`<Orgas />`, `<Socials />`) peuvent rester en React via les islands ou etre convertis en composants Astro.
91+
92+
### Metadata / SEO
93+
94+
| Next.js | Astro |
95+
|---|---|
96+
| `export const metadata: Metadata` | `<head>` dans le layout + props |
97+
| `generateMetadata()` | Props dynamiques dans le layout |
98+
| `opengraph-image.tsx` (6 fichiers) | `satori` + `sharp` au build (voir ci-dessous) |
99+
| `robots.ts` | `src/pages/robots.txt.ts` |
100+
| `sitemap.ts` | `@astrojs/sitemap` |
101+
| JSON-LD structured data | `<script type="application/ld+json">` dans le layout |
102+
103+
### OG Images dynamiques
104+
105+
C'est le point le plus complexe. Actuellement 6 routes generent des images OG via `next/og` (basee sur `satori`).
106+
107+
**Options avec Astro** :
108+
1. **`astro-og-canvas`** : Librairie communautaire pour generer des OG images au build
109+
2. **`satori` + `sharp` directement** : Meme moteur que `next/og`, utilisable dans `getStaticPaths()` pour generer les images au build
110+
3. **Service externe** : Generer via un endpoint API separe
111+
112+
Recommandation : option 2, generer les images au build avec `satori` directement.
113+
114+
### Middleware / Headers de securite
115+
116+
Le `middleware.ts` actuel gere :
117+
- Nonce CSP pour les scripts inline
118+
- Headers de securite (X-Frame-Options, etc.)
119+
120+
**Avec Astro** :
121+
- Les headers statiques (X-Frame-Options, etc.) → configures dans le Dockerfile / reverse proxy / `astro.config.mjs` en mode SSR
122+
- Le nonce CSP → plus necessaire si pas de scripts inline. Sinon, middleware Astro en mode SSR.
123+
- Alternative : configurer les headers directement dans Scaleway Serverless Containers
124+
125+
### Redirections
126+
127+
Une seule redirection (`/lyonjs-100/programme``/lyonjs-100`) → `redirects` dans `astro.config.mjs`.
128+
129+
### Styles
130+
131+
| Next.js | Astro |
132+
|---|---|
133+
| CSS Modules (20+ fichiers) | CSS Modules supportes nativement |
134+
| `globals.css` | Import global dans le layout |
135+
| `normalize.css` | Import dans le layout |
136+
| `classnames` | Continue a fonctionner |
137+
138+
Migration transparente, rien a changer.
139+
140+
## Strategie ISR vs rebuild
141+
142+
Le site utilise `revalidate = 3600` sur plusieurs pages pour actualiser les donnees Meetup toutes les heures.
143+
144+
**Options avec Astro** :
145+
146+
| Option | Description | Impact |
147+
|---|---|---|
148+
| **SSG + rebuild cron** | Workflow CI schedule qui rebuild et redeploy toutes les heures | Simple, pas de serveur Node, image Docker minimale (nginx) |
149+
| **SSR mode** | Astro en mode `output: 'server'` avec cache headers | Garde le comportement ISR, mais necessite Node.js runtime |
150+
| **Hybride** | `output: 'hybrid'` — pages statiques par defaut, quelques routes SSR | Meilleur compromis |
151+
152+
**Recommandation** : SSG + rebuild cron. Le contenu change rarement (quelques meetups par mois). Un rebuild horaire ou quotidien suffit largement. Cela permet de deployer une image Docker statique (nginx) au lieu d'un runtime Node.js.
153+
154+
## Plan de migration
155+
156+
### Phase 1 : Setup et infrastructure
157+
158+
- [ ] Initialiser le projet Astro avec `@astrojs/react`, `@astrojs/mdx`, `@astrojs/sitemap`
159+
- [ ] Configurer `astro.config.mjs` (images, redirections, site URL)
160+
- [ ] Creer le layout principal (`Layout.astro`) avec les meta, les styles globaux, le JSON-LD
161+
- [ ] Configurer les headers de securite dans le Dockerfile ou la config Astro
162+
- [ ] Adapter le Dockerfile (build statique → nginx ou SSR → Node)
163+
164+
### Phase 2 : Pages statiques
165+
166+
- [ ] Migrer les 5 pages MDX (a-propos, code-de-conduite, devenir-sponsor, budget, lyonjs-100)
167+
- [ ] Migrer les composants de layout (Header, Footer, Navigation)
168+
- [ ] Migrer le systeme de navigation (NavLink, MobileNavigation → islands React ou composants Astro natifs)
169+
- [ ] Migrer la page 404
170+
171+
### Phase 3 : Pages dynamiques
172+
173+
- [ ] Migrer le module Meetup API (graphql-request, queries) — reutilisable tel quel
174+
- [ ] Migrer `data-override.ts` et `overrideEvent.ts` — reutilisable tel quel
175+
- [ ] Migrer la homepage (NextEvent, LastReplays, Numbers, HomeHero)
176+
- [ ] Migrer `/evenements-precedents` et `/evenements-precedents/[year]` avec `getStaticPaths()`
177+
- [ ] Migrer `/evenement/[slug]` avec `getStaticPaths()`
178+
179+
### Phase 4 : Composants interactifs
180+
181+
- [ ] Convertir HomeHero et Number en islands React (`client:visible`)
182+
- [ ] Convertir Collapsible en island ou composant Astro natif (`<details>`)
183+
- [ ] Convertir PhotoAlbum + lightbox en island React
184+
- [ ] Convertir MobileNavigation (remplacer `usePathname` par du JS vanilla ou island)
185+
186+
### Phase 5 : SEO et finitions
187+
188+
- [ ] Generer les OG images au build avec `satori`
189+
- [ ] Configurer `@astrojs/sitemap`
190+
- [ ] Migrer `robots.txt`
191+
- [ ] Verifier les meta tags et le JSON-LD sur toutes les pages
192+
- [ ] Mettre a jour les tests Playwright (les selectors devraient rester les memes)
193+
194+
### Phase 6 : CI/CD
195+
196+
- [ ] Adapter le Dockerfile pour Astro
197+
- [ ] Si SSG pur : optionnel — remplacer le runtime Node.js par nginx pour une image plus legere
198+
- [ ] Ajouter un workflow cron pour rebuild periodique (si SSG)
199+
- [ ] Verifier que les deploys Scaleway fonctionnent
200+
201+
## Estimation de la complexite
202+
203+
| Element | Fichiers | Complexite |
204+
|---|---|---|
205+
| Pages statiques (MDX) | 5 | Faible |
206+
| Layout + Header + Footer | 3 | Faible |
207+
| Navigation (mobile, links) | 3 | Moyenne |
208+
| Homepage (hero, numbers, replays) | 5 | Moyenne |
209+
| Pages dynamiques (events, years) | 4 | Moyenne |
210+
| Module Meetup API | 5 | Faible (reutilisable) |
211+
| Data files | 9 | Aucune (reutilisable) |
212+
| OG images | 6 | Elevee |
213+
| Middleware → headers | 1 | Faible |
214+
| Tests Playwright | 3 | Faible (memes URLs) |
215+
| CI/CD + Docker | 3 | Faible |
216+
217+
**Code reutilisable sans modification** : tout le dossier `data/`, le module `meetup/` (queries, API), les utilitaires (`dateUtils`, `slugify`, `overrideEvent`), les types, `classnames`, CSS Modules.
218+
219+
**Code a reecrire** : les pages (syntaxe `.astro`), les composants de layout, les OG images.
220+
221+
**Code a adapter** : les 7 composants React interactifs (ajouter `client:*` directives).
222+
223+
## Conclusion
224+
225+
La migration est faisable et presente un interet reel pour ce type de site (contenu statique, peu d'interactivite). Les principaux benefices sont la reduction du JS client, la simplification de l'architecture, et potentiellement une image Docker plus legere.
226+
227+
Les points de friction sont les OG images dynamiques (necessite du travail custom avec satori) et la perte de l'ISR (compensable par un rebuild cron).
228+
229+
Le code metier (API Meetup, data, types, utilitaires, CSS) est largement reutilisable. Le gros du travail est la reecriture des pages en syntaxe Astro et l'adaptation des composants interactifs en islands.

0 commit comments

Comments
 (0)