# Prompt-to-PR : Créer un site statique SEO avec Astro

> SOP complète pour générer un site statique SEO piloté par le contenu avec Astro, Tailwind, collections de contenu MDX, sitemap et balises canoniques à partir de zéro.

**Type:** Playbook  
**Tools:** Cursor, Claude Code, Codex, Windsurf  
**Stack:** Astro, TypeScript, Tailwind  
**Difficulty:** medium  
**Updated:** 2026-06-08

---

Créez un site Astro 5 entièrement statique prêt pour la production, optimisé pour la recherche organique : collections de contenu, typographie Tailwind, `@astrojs/sitemap` et métadonnées `<head>` correctes intégrées dès le départ.

## 1. Exigence

Créez un site statique de marketing/contenu qui obtient un score de 100 sur Lighthouse SEO et Accessibilité. Le contenu est rédigé dans des fichiers MDX gérés par les collections de contenu Astro. Aucun framework JavaScript nécessaire — la sortie est du HTML+CSS pur avec des îlots optionnels.

## 2. Premier prompt

```txt title="First Prompt"
Scaffold a new Astro 5 static SEO site from scratch in the current directory.

Requirements:
1. Init with: `bunx create astro@latest . --template minimal --typescript strict --no-git`
2. Add integrations:
   - `@astrojs/tailwind` with `@tailwindcss/typography`
   - `@astrojs/sitemap`
   - `@astrojs/mdx`
3. Create a content collection `blog` in `src/content/blog/` with this Zod schema:
   title, description, pubDate (Date), updatedDate (Date, optional),
   author (string, default "Admin"), tags (string[], default []), draft (bool, default false).
4. Create a BaseLayout.astro with:
   - A `<head>` block: charset, viewport, canonical (`Astro.url.href`),
     og:title, og:description, og:url, og:type, twitter:card.
   - Accept `title`, `description`, `image` props.
5. Create pages:
   - `/` — hero + last 6 non-draft posts
   - `/blog` — paginated list (10 per page) using `paginate()`
   - `/blog/[slug]` — single post rendered with `<Content />`
   - `/tags/[tag]` — posts filtered by tag
6. Create `src/content/blog/hello-world.mdx` as a real sample post.
7. Configure `astro.config.ts`:
   - `site: process.env.SITE_URL ?? "http://localhost:4321"`
   - `integrations: [tailwind(), sitemap(), mdx()]`
   - `output: "static"`
8. Add a `.env.example` with `SITE_URL=https://example.com`.
```

## 3. Modifications de fichiers attendues

```txt
astro.config.ts
tailwind.config.ts
src/content.config.ts                    (blog collection schema)
src/layouts/BaseLayout.astro             (head + canonical + OG tags)
src/pages/index.astro
src/pages/blog/index.astro               (paginated)
src/pages/blog/[slug].astro
src/pages/tags/[tag].astro
src/content/blog/hello-world.mdx
.env.example
package.json                             (updated with all integrations)
```

## 4. Liste de vérification

- `astro.config.ts` définit `site` — nécessaire pour que `@astrojs/sitemap` émette des URLs absolues.
- `BaseLayout.astro` produit une balise `<link rel="canonical">` en utilisant `Astro.url.href`.
- La page de liste du blog utilise `Astro.props.page.data` de `paginate()` — pas un appel brut à `getCollection()`.
- Les brouillons (`draft: true`) sont exclus en production via la garde `import.meta.env.PROD`.
- `<html lang="en">` est défini sur l'élément racine.
- `tailwind.config.ts` inclut le plugin `typography` et cible `src/**/*.{astro,mdx}`.
- L'intégration `sitemap()` est présente — vérifiez que `dist/sitemap-index.xml` existe après `bun run build`.

## 5. Commandes de test

```bash
bun install
bun run dev
# visit http://localhost:4321 and confirm hero + posts render

bun run build
# expect zero errors

bun run preview
# check /sitemap-index.xml and /sitemap-0.xml exist
# check /blog and /blog/hello-world render with correct <title> and canonical

# Lighthouse CLI smoke test (optional)
bunx lighthouse http://localhost:4321 --output json --quiet | jq '.categories.seo.score'
# expect 1 (100%)
```

## 6. Échecs courants

- **Le sitemap génère des URLs relatives** — `site` manquant dans `astro.config.ts`. Ajoutez-le.
- **`getCollection` retourne les brouillons en production** — filtrez : `posts.filter(p => !p.data.draft || !import.meta.env.PROD)`.
- **Pagination 404 sur `/blog`** — la première page doit être `/blog/` (index), pas `/blog/1`. Astro's `paginate()` produit `/blog/`, `/blog/2/`, etc. par défaut.
- **Contenu MDX non stylisé** — la classe `prose` de `@tailwindcss/typography` manque sur le wrapper d'article dans `[slug].astro`.
- **Les balises OG utilisent un chemin d'image relatif** — doit être une URL absolue. Préfixez avec `Astro.site`.

## 7. Prompt de correction

```txt title="Fix Prompt"
The sitemap at /sitemap-0.xml contains relative paths like "/blog/hello-world"
instead of absolute URLs like "https://example.com/blog/hello-world".

Fix: add `site: "https://example.com"` (or `process.env.SITE_URL`) to the
top-level astro.config.ts object. The sitemap integration reads this value
to prefix all URLs.
```

## 8. Description de la PR

```md title="PR description"
## Init: Static Astro 5 SEO site

- Astro 5 + TypeScript strict + Tailwind (with `@tailwindcss/typography`)
- `@astrojs/sitemap` and `@astrojs/mdx` integrations
- Content collection `blog` with Zod schema (title, description, pubDate, tags, draft)
- BaseLayout with canonical, OG, and Twitter Card meta tags
- Pages: home, paginated blog list, single post, tag archive
- Sample `hello-world.mdx` post
- `bun run build` emits `sitemap-index.xml` and all static pages
```