Aller au contenu principal

Développement du Framework Astro dans Cursor : Un Guide Complet

Astro development in Cursor

Astro est un framework web moderne conçu pour les sites web axés sur le contenu qui livrent zéro JavaScript par défaut. Astro 4+ a introduit l'API Content Layer améliorée, des performances de serveur de développement plus rapides et le support officiel des View Transitions. Cursor, avec sa base compatible VS Code et son assistant IA intégré, est un excellent éditeur pour le travail Astro -- il comprend les fichiers .astro, fournit l'IntelliSense pour le frontmatter et les props des composants, et peut générer des composants, des collections et des intégrations à partir de prompts en langage naturel.

Ce guide couvre le flux de travail complet de développement Astro dans Cursor : configuration du projet, collections de contenu, API View Transitions, architecture islands, intégrations et génération de composants assistée par IA.

Configuration du Développement Astro dans Cursor​

Prérequis​

Astro 4+ nécessite Node.js 18.14.1 ou plus récent (Node 20 LTS est recommandé). Vérifiez votre installation :

node --version
npm --version

Si vous avez besoin d'une version plus récente, utilisez fnm ou nvm :

fnm install 20
fnm use 20
astuce

Le terminal intégré de Cursor (Ctrl+`) garde votre répertoire de travail actuel synchronisé avec le panneau Explorer, vous pouvez donc scaffolder un projet et ouvrir immédiatement les fichiers générés sans changer de contexte.

Installation des Outils Linguistiques Astro​

Cursor s'appuie sur l'extension officielle Astro pour le support linguistique. Installez-la depuis la vue Extensions (Ctrl+Shift+X) :

  1. Recherchez "Astro".
  2. Installez l'extension publiée par l'équipe Astro.
  3. Rechargez Cursor si nécessaire.

L'extension fournit :

  • La coloration syntaxique pour les fichiers .astro.
  • Les diagnostics et la vérification des types via @astrojs/language-server.
  • Le formatage via Prettier avec le package prettier-plugin-astro.
  • L'IntelliSense pour les imports de composants, les props et les expressions frontmatter.
attention

Si vous avez précédemment installé une extension Astro communautaire, désactivez-la avant d'installer l'officielle. Les extensions en conflit causent des diagnostics en double et un formatage peu fiable.

Scaffolding d'un Projet Astro​

Utilisez le CLI officiel create-astro pour démarrer un nouveau projet :

# Create a new project with the minimal template
npm create astro@latest my-astro-site -- --template minimal --no-install --no-git --typescript strict

cd my-astro-site
npm install

Ouvrez le dossier du projet dans Cursor :

cursor .

La structure de projet par défaut ressemble à ceci :

my-astro-site/
├── src/
│ ├── components/
│ ├── layouts/
│ │ └── Layout.astro
│ ├── pages/
│ │ └── index.astro
│ └── styles/
│ └── global.css
├── public/
├── astro.config.mjs
├── tsconfig.json
└── package.json
astuce

Demandez à Cursor de scaffolder un projet complet pour vous : "Créez un projet Astro 4 avec TypeScript, Tailwind CSS et le support MDX." Cursor générera les fichiers de configuration et installera les dépendances en une seule fois.

Utilisation des Collections de Contenu​

Les collections de contenu sont la méthode type-safe d'Astro pour gérer le contenu local comme les articles de blog, la documentation et les listes de produits. L'API Content Layer introduite dans Astro 4 fournit une interface unifiée pour les fichiers locaux, les API externes et les intégrations CMS.

Définition d'une Collection​

Créez un schéma de collection dans src/content/config.ts :

import { defineCollection, z } from 'astro:content';
import { glob } from 'astro/loaders';

const blog = defineCollection({
loader: glob({ pattern: '**/*.md', base: './src/content/blog' }),
schema: ({ image }) =>
z.object({
title: z.string(),
description: z.string(),
pubDate: z.coerce.date(),
updatedDate: z.coerce.date().optional(),
author: z.string().default('Anonymous'),
tags: z.array(z.string()).default([]),
cover: image().optional(),
draft: z.boolean().default(false),
}),
});

const docs = defineCollection({
loader: glob({ pattern: '**/*.md', base: './src/content/docs' }),
schema: z.object({
title: z.string(),
order: z.number(),
section: z.string(),
}),
});

export const collections = { blog, docs };
astuce

Demandez à Cursor : "Générez un schéma de collection de contenu pour un catalogue de produits avec nom, prix, description, tableau d'images et énumération de catégorie." Cursor comprend Zod et produira un schéma valide avec les validateurs appropriés.

Écriture d'Entrées de Contenu​

Créez des fichiers Markdown dans le répertoire de la collection :

---
title: "Getting Started with Astro 4"
description: "Learn the new Content Layer API and View Transitions in Astro 4."
pubDate: 2024-06-15
author: "Jane Doe"
tags: ["astro", "tutorial"]
cover: "../../assets/blog/astro-cover.jpg"
---

Astro 4 brings a faster dev server, improved Content Layer API,
and native View Transitions support.

Interrogation des Collections dans les Pages​

Utilisez getCollection pour récupérer des entrées avec une sécurité de type complète :

---
// src/pages/blog/index.astro
import { getCollection } from 'astro:content';
import Layout from '../../layouts/Layout.astro';

const posts = (await getCollection('blog'))
.filter((post) => !post.data.draft)
.sort((a, b) => b.data.pubDate.valueOf() - a.data.pubDate.valueOf());
---

<Layout title="Blog">
<main>
<h1>Blog</h1>
<ul>
{posts.map((post) => (
<li>
<a href={`/blog/${post.id}/`}>
<time datetime={post.data.pubDate.toISOString()}>
{post.data.pubDate.toLocaleDateString('en-US')}
</time>
{post.data.title}
</a>
</li>
))}
</ul>
</main>
</Layout>
attention

Utilisez toujours post.id (et non post.slug) lors de la construction d'URL avec l'API Content Layer. Le comportement du champ slug diffère entre Astro 3 et Astro 4 -- id est l'identifiant unique et stable dans Astro 4+.

Pages de Contenu Dynamiques​

Générez des pages individuelles pour chaque entrée de collection :

---
// src/pages/blog/[...id].astro
import { getCollection, render } from 'astro:content';
import Layout from '../../layouts/Layout.astro';

export async function getStaticPaths() {
const posts = await getCollection('blog');
return posts.map((post) => ({
params: { id: post.id },
props: { post },
}));
}

const { post } = Astro.props;
const { Content } = await render(post);
---

<Layout title={post.data.title}>
<article>
<header>
<h1>{post.data.title}</h1>
<p>By {post.data.author}</p>
</header>
<Content />
</article>
</Layout>

API View Transitions​

Le composant <ClientRouter /> d'Astro (anciennement <ViewTransitions />) active les View Transitions natives du navigateur pour la navigation côté client sans un framework SPA complet.

Activation des View Transitions​

Ajoutez le composant à votre layout de base :

---
// src/layouts/Layout.astro
import { ClientRouter } from 'astro:transitions';

interface Props {
title: string;
}

const { title } = Astro.props;
---

<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>{title}</title>
<ClientRouter />
</head>
<body>
<slot />
</body>
</html>

Animation des Transitions de Page​

Utilisez CSS view-transition-name pour définir des cibles de transition nommées :

/* src/styles/global.css */
::view-transition-old(root) {
animation: fade-out 0.3s ease;
}

::view-transition-new(root) {
animation: fade-in 0.3s ease;
}

@keyframes fade-out {
to { opacity: 0; }
}

@keyframes fade-in {
from { opacity: 0; }
}

/* Named transition for a hero image */
.hero-image {
view-transition-name: hero-image;
}

::view-transition-old(hero-image) {
animation: scale-down 0.4s ease;
}

::view-transition-new(hero-image) {
animation: scale-up 0.4s ease;
}
astuce

Demandez à Cursor : "Ajoutez des View Transitions à mon site Astro avec un effet de glissement pour la navigation et un fondu enchaîné pour le contenu." Cursor générera les keyframes CSS et expliquera comment les cibler sur des éléments spécifiques à l'aide de view-transition-name.

Événements de Cycle de Vie​

Écoutez les événements de transition dans les scripts côté client :

<script>
document.addEventListener('astro:page-load', () => {
console.log('New page loaded after transition');
initAnalytics();
});

document.addEventListener('astro:before-swap', (event) => {
// Modify the new document before it swaps in
const newDoc = event.newDocument;
const theme = localStorage.getItem('theme') ?? 'light';
newDoc.documentElement.dataset.theme = theme;
});

document.addEventListener('astro:after-swap', () => {
console.log('DOM swapped, scripts re-executed');
});
</script>
attention

Les scripts côté client dans les fichiers .astro sont traités par le bundler d'Astro. Si vous avez besoin qu'un script s'exécute à chaque navigation avec View Transitions, écoutez l'événement astro:page-load plutôt que de vous fier au code de niveau supérieur, qui ne s'exécute qu'au premier chargement.

Architecture Islands​

L'architecture islands d'Astro vous permet d'intégrer des composants interactifs (React, Vue, Svelte, Solid, etc.) dans du HTML statique. Seuls les composants island livrent du JavaScript -- le reste de la page reste statique.

Ajout d'une Intégration de Framework UI​

Installez l'intégration React :

npx astro add react

Cette commande modifie astro.config.mjs automatiquement :

import { defineConfig } from 'astro/config';
import react from '@astrojs/react';

export default defineConfig({
integrations: [react()],
});

Création d'une Island Interactive​

Créez un composant React :

// src/components/Counter.tsx
import { useState } from 'react';

interface CounterProps {
initialCount?: number;
step?: number;
}

export default function Counter({ initialCount = 0, step = 1 }: CounterProps) {
const [count, setCount] = useState(initialCount);

return (
<div className="counter">
<button onClick={() => setCount((c) => c - step)}>-</button>
<span>{count}</span>
<button onClick={() => setCount((c) => c + step)}>+</button>
</div>
);
}

Utilisez la directive client: dans une page Astro pour hydrater l'island :

---
// src/pages/index.astro
import Layout from '../layouts/Layout.astro';
import Counter from '../components/Counter.tsx';
---

<Layout title="Home">
<h1>Welcome</h1>

<!-- Hydrates on page load -->
<Counter client:load initialCount={0} step={2} />

<!-- Hydrates when visible in viewport -->
<Counter client:visible initialCount={10} />

<!-- Hydrates on idle -->
<Counter client:idle initialCount={5} />

<!-- Hydrates on media query match -->
<Counter client:media="(max-width: 768px)" initialCount={0} />

<!-- No hydration -- server-rendered only -->
<Counter initialCount={100} />
</Layout>
astuce

Demandez à Cursor : "Créez une island React pour un formulaire d'inscription à la newsletter avec validation d'email, et affichez-la en client:visible dans mon layout Astro." Cursor générera le composant, gérera l'état du formulaire, ajoutera la validation et le connectera à votre fichier de layout.

Choix de la Bonne Directive d'Hydratation​

DirectiveQuand l'utiliser
client:loadInteractivité immédiatement nécessaire (nav, recherche)
client:idleWidgets de priorité inférieure chargés pendant le temps d'inactivité du navigateur
client:visibleWidgets sous la ligne de flottaison qui s'hydratent au défilement
client:mediaComposants qui ne doivent se charger que sur des tailles d'écran spécifiques
client:onlyIgnorer complètement le rendu côté serveur (utile pour les API navigateur uniquement)
attention

Utilisez client:only avec prudence. Les composants rendus avec cette directive ignorent le rendu côté serveur, ce qui signifie qu'ils n'apparaîtront pas dans le HTML initial. Cela nuit au référencement et provoque un décalage de mise en page. Utilisez-le uniquement pour les composants qui dépendent d'API navigateur uniquement comme window ou localStorage au premier rendu.

Intégrations et Écosystème​

Les intégrations Astro étendent le framework avec des capacités supplémentaires. L'IA de Cursor peut vous aider à configurer et dépanner les intégrations rapidement.

Intégration Tailwind CSS​

npx astro add tailwind

Cela installe @tailwindcss/vite et configure le plugin Vite. Créez un fichier CSS avec l'import Tailwind :

/* src/styles/global.css */
@import "tailwindcss";

Importez la feuille de style dans votre layout :

---
// src/layouts/Layout.astro
import '../styles/global.css';
---
astuce

Demandez à Cursor : "Configurez Tailwind CSS v4 avec mon projet Astro et créez un composant de barre de navigation responsive." Cursor configurera le plugin Vite, générera l'entrée CSS et construira la navigation responsive avec des classes utilitaires.

Intégration MDX​

npx astro add mdx

Utilisez des fichiers .mdx dans vos collections de contenu pour intégrer des composants interactifs dans le Markdown :

---
title: "Interactive Blog Post"
description: "A post with embedded React components."
pubDate: 2024-06-20
---

import Counter from '../components/Counter.tsx';

This is a paragraph in MDX.

<Counter client:visible initialCount={0} />

More content after the island.

Intégrations Sitemap et RSS​

npx astro add sitemap
npx astro add rss

Configurez-les dans astro.config.mjs :

import { defineConfig } from 'astro/config';
import sitemap from '@astrojs/sitemap';
import mdx from '@astrojs/mdx';

export default defineConfig({
site: 'https://example.com',
integrations: [mdx(), sitemap()],
});

Générez un flux RSS dans un endpoint autonome :

// src/pages/rss.xml.ts
import rss from '@astrojs/rss';
import { getCollection } from 'astro:content';

export async function GET(context) {
const posts = await getCollection('blog');
return rss({
title: 'My Astro Blog',
description: 'Latest posts',
site: context.site,
items: posts
.filter((post) => !post.data.draft)
.sort((a, b) => b.data.pubDate.valueOf() - a.data.pubDate.valueOf())
.map((post) => ({
title: post.data.title,
description: post.data.description,
pubDate: post.data.pubDate,
link: `/blog/${post.id}/`,
})),
customData: '<language>en-us</language>',
});
}

Génération de Composants Assistée par IA dans Cursor​

L'assistant IA de Cursor excelle dans la génération de composants Astro, de layouts et de schémas de collection à partir de descriptions en langage naturel.

Génération de Composants à partir de Prompts​

Ouvrez Cursor Chat (Ctrl+L) ou utilisez l'édition en ligne (Ctrl+I) et décrivez ce dont vous avez besoin :

Generate an Astro component for a responsive pricing table with three tiers:
Starter ($9), Pro ($29), and Enterprise ($99). Include a "Popular" badge on
the Pro tier, feature lists with checkmarks, and CTA buttons. Use Tailwind
classes and accept props for the tier data.

Cursor produira un composant entièrement typé et stylé :

---
// src/components/PricingTable.astro
interface PricingTier {
name: string;
price: number;
description: string;
features: string[];
popular?: boolean;
ctaText: string;
ctaLink: string;
}

interface Props {
tiers: PricingTier[];
}

const { tiers } = Astro.props;
---

<section class="py-12">
<div class="grid grid-cols-1 md:grid-cols-3 gap-8 max-w-5xl mx-auto">
{tiers.map((tier) => (
<div
class:list={[
'relative rounded-2xl border p-8',
tier.popular
? 'border-blue-500 shadow-xl scale-105'
: 'border-gray-200',
]}
>
{tier.popular && (
<span class="absolute -top-3 left-1/2 -translate-x-1/2 rounded-full bg-blue-500 px-4 py-1 text-sm text-white font-semibold">
Popular
</span>
)}
<h3 class="text-xl font-bold">{tier.name}</h3>
<p class="text-gray-500 text-sm mt-1">{tier.description}</p>
<p class="text-4xl font-bold mt-4">
${tier.price}<span class="text-base font-normal text-gray-500">/mo</span>
</p>
<ul class="mt-6 space-y-3">
{tier.features.map((feature) => (
<li class="flex items-center gap-2">
<svg class="w-5 h-5 text-green-500" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
<path stroke-linecap="round" stroke-linejoin="round" d="M5 13l4 4L19 7" />
</svg>
{feature}
</li>
))}
</ul>
<a
href={tier.ctaLink}
class:list={[
'mt-8 block rounded-lg py-3 text-center font-semibold transition-colors',
tier.popular
? 'bg-blue-500 text-white hover:bg-blue-600'
: 'bg-gray-100 text-gray-900 hover:bg-gray-200',
]}
>
{tier.ctaText}
</a>
</div>
))}
</div>
</section>
astuce

Lors de la génération de composants, incluez l'interface des props dans votre prompt. Cela garantit que Cursor produit des props typées que vous pouvez réutiliser entre les pages. Par exemple : "Créez un composant Card qui accepte une prop title, description, href et image optionnelle."

Génération de Layout Assistée par IA​

Demandez à Cursor de générer un layout réutilisable :

Create a base Astro layout with a sticky header containing a logo, navigation
links (Home, Blog, About, Contact), and a theme toggle button. Include a footer
with social links and copyright. Add View Transitions and a dark mode toggle
using a script that reads from localStorage.

Configuration d'Intégration Assistée par IA​

Cursor peut aider à dépanner les problèmes d'intégration. Si vos classes Tailwind ne s'appliquent pas, demandez :

My Tailwind CSS v4 classes are not being applied in my Astro project.
Here is my astro.config.mjs and global.css. What is wrong?

Cursor analysera la configuration, vérifiera les pièges courants (plugin Vite manquant, chemins d'import incorrects, configuration de contenu) et suggérera des corrections.

attention

Lors de l'utilisation de l'IA de Cursor pour modifier astro.config.mjs, vérifiez toujours le tableau integrations généré. Les intégrations doivent être listées dans le bon ordre -- par exemple, mdx() doit venir avant sitemap() si les pages MDX doivent être incluses dans le sitemap.

Build et Déploiement​

Génération de Site Statique​

Astro produit une sortie statique par défaut. Construisez le site :

npm run build

La sortie se trouve dans dist/. Prévisualisez le build de production localement :

npm run preview

Rendu Côté Serveur (SSR)​

Pour le contenu dynamique, activez le mode SSR :

// astro.config.mjs
import { defineConfig } from 'astro/config';
import node from '@astrojs/node';

export default defineConfig({
output: 'server',
adapter: node({ mode: 'standalone' }),
});

Rendu Hybride​

Astro 4 prend en charge le rendu hybride, vous permettant de mélanger des pages statiques et rendues côté serveur :

// astro.config.mjs
export default defineConfig({
output: 'hybrid',
});

Marquez des pages individuelles comme rendues côté serveur avec export const prerender = false;.

Débogage et Performance​

Analyse de la Taille du Bundle​

Installez l'analyseur de bundle :

npm install -D astro-bundle-analyzer

Ajoutez-le à vos intégrations :

import bundleAnalyzer from 'astro-bundle-analyzer';

export default defineConfig({
integrations: [bundleAnalyzer()],
});
astuce

Demandez à Cursor : "Mon build Astro livre trop de JavaScript. Analyse mes composants et dis-moi quelles islands peuvent passer de client:load à client:visible ou client:idle." Cursor examinera votre utilisation des composants et recommandera des optimisations de directive d'hydratation.

Optimisation des Images​

Utilisez le composant intégré <Image> d'Astro pour l'optimisation automatique :

---
import { Image } from 'astro:assets';
import heroImage from '../assets/hero.jpg';
---

<Image
src={heroImage}
alt="Hero image"
width={1200}
height={600}
loading="eager"
formats={['avif', 'webp']}
quality={80}
/>
attention

Les images distantes nécessitent une entrée config.image.service ou une configuration img.config. Si vous voyez des erreurs de build concernant les domaines d'images distantes, ajoutez les domaines autorisés à astro.config.mjs sous image.domains ou image.remotePatterns.

Conclusion​

Astro 4+ associé à Cursor crée un environnement de développement puissant pour construire des sites web rapides et axés sur le contenu. La combinaison d'une sortie zéro-JS par défaut, de collections de contenu type-safe, des View Transitions et de l'architecture islands signifie que vous obtenez d'excellentes performances sans sacrifier l'expérience développeur. L'assistant IA de Cursor accélère chaque étape -- du scaffolding et de la conception de schéma à la génération de composants et au dépannage d'intégration. Commencez avec un modèle minimal, ajoutez des collections de contenu pour vos données structurées, introduisez des islands interactives uniquement là où c'est nécessaire, et laissez Cursor générer le code passe-partout afin que vous puissiez vous concentrer sur le contenu et le design.