Pular para o conteúdo principal

Desenvolvimento com o Framework Astro no Cursor: Um Guia Completo

Astro development in Cursor

Astro é um framework web moderno projetado para sites baseados em conteúdo que não enviam JavaScript por padrão. Astro 4+ introduziu a API Content Layer aprimorada, desempenho mais rápido do dev server e suporte oficial a View Transitions. O Cursor, com sua base compatível com VS Code e assistente de IA integrado, é um excelente editor para trabalho com Astro -- ele entende arquivos .astro, fornece IntelliSense para frontmatter e props de componentes, e pode gerar componentes, coleções e integrações a partir de prompts em linguagem natural.

Este guia aborda o fluxo de trabalho completo de desenvolvimento com Astro no Cursor: configuração do projeto, coleções de conteúdo, View Transitions API, arquitetura de ilhas, integrações e geração de componentes com IA.

Configurando o Desenvolvimento Astro no Cursor​

Pré-requisitos​

Astro 4+ requer Node.js 18.14.1 ou mais recente (Node 20 LTS é recomendado). Verifique sua instalação:

node --version
npm --version

Se precisar de uma versão mais recente, use fnm ou nvm:

fnm install 20
fnm use 20
dica

O terminal integrado do Cursor (Ctrl+`) mantém seu diretório de trabalho atual sincronizado com o painel do Explorer, para que você possa criar um projeto e abrir imediatamente os arquivos gerados sem trocar de contexto.

Instalando as Ferramentas de Linguagem Astro​

O Cursor depende da extensão oficial Astro para suporte a linguagem. Instale-a a partir da view de Extensões (Ctrl+Shift+X):

  1. Pesquise por "Astro".
  2. Instale a extensão publicada pela equipe Astro.
  3. Recarregue o Cursor se solicitado.

A extensão fornece:

  • Realce de sintaxe para arquivos .astro.
  • Diagnósticos e verificação de tipos via @astrojs/language-server.
  • Formatação através do Prettier com o pacote prettier-plugin-astro.
  • IntelliSense para importações de componentes, props e expressões de frontmatter.
aviso

Se você instalou anteriormente uma extensão Astro da comunidade, desative-a antes de instalar a oficial. Extensões conflitantes causam diagnósticos duplicados e formatação não confiável.

Criando um Projeto Astro​

Use o CLI oficial create-astro para inicializar um novo projeto:

# Criar um novo projeto com o template minimal
npm create astro@latest my-astro-site -- --template minimal --no-install --no-git --typescript strict

cd my-astro-site
npm install

Abra a pasta do projeto no Cursor:

cursor .

A estrutura padrão do projeto se parece com isto:

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

Peça ao Cursor para criar um projeto completo: "Crie um projeto Astro 4 com TypeScript, Tailwind CSS e suporte a MDX." O Cursor gerará os arquivos de configuração e instalará as dependências em uma única passagem.

Trabalhando com Coleções de Conteúdo​

Coleções de Conteúdo são a maneira type-safe do Astro de gerenciar conteúdo local como posts de blog, documentação e listagens de produtos. A API Content Layer introduzida no Astro 4 fornece uma interface unificada para arquivos locais, APIs externas e integrações com CMS.

Definindo uma Coleção​

Crie um schema de coleção em 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 };
dica

Peça ao Cursor: "Gere um schema de coleção de conteúdo para um catálogo de produtos com nome, preço, descrição, array de imagens e enum de categoria." O Cursor entende Zod e produzirá um schema válido com validadores apropriados.

Escrevendo Entradas de Conteúdo​

Crie arquivos Markdown no diretório da coleção:

---
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.

Consultando Coleções em Páginas​

Use getCollection para buscar entradas com total segurança de tipos:

---
// 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>
aviso

Sempre use post.id (não post.slug) ao construir URLs com a API Content Layer. O comportamento do campo slug difere entre Astro 3 e Astro 4 -- id é o identificador estável e único no Astro 4+.

Páginas de Conteúdo Dinâmico​

Gere páginas individuais para cada entrada da coleção:

---
// 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>

View Transitions API​

O componente <ClientRouter /> do Astro (anteriormente <ViewTransitions />) habilita View Transitions nativas do navegador para navegação no lado do cliente sem um framework SPA completo.

Habilitando View Transitions​

Adicione o componente ao seu layout 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>

Animando Transições de Página​

Use CSS view-transition-name para definir alvos de transição nomeados:

/* 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; }
}

/* Transição nomeada para uma imagem hero */
.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;
}
dica

Peça ao Cursor: "Adicione View Transitions ao meu site Astro com um efeito de slide-in para navegação e cross-fade para conteúdo." O Cursor gerará os keyframes CSS e explicará como defini-los para elementos específicos usando view-transition-name.

Eventos de Ciclo de Vida​

Ouça eventos de transição em scripts do lado do cliente:

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

document.addEventListener('astro:before-swap', (event) => {
// Modificar o novo documento antes da troca
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>
aviso

Scripts do lado do cliente em arquivos .astro são processados pelo bundler do Astro. Se você precisa que um script seja executado em toda navegação com View Transitions, ouça o evento astro:page-load em vez de depender de código de nível superior, que só é executado no primeiro carregamento.

Arquitetura de Ilhas​

A arquitetura de ilhas do Astro permite incorporar componentes interativos (React, Vue, Svelte, Solid, etc.) dentro de HTML estático. Apenas os componentes ilha enviam JavaScript -- o restante da página permanece estático.

Adicionando uma Integração de Framework de UI​

Instale a integração React:

npx astro add react

Este comando modifica astro.config.mjs automaticamente:

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

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

Criando uma Ilha Interativa​

Crie um componente 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>
);
}

Use a diretiva client: em uma página Astro para hidratar a ilha:

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

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

<!-- Hidrata no carregamento da página -->
<Counter client:load initialCount={0} step={2} />

<!-- Hidrata quando visível no viewport -->
<Counter client:visible initialCount={10} />

<!-- Hidrata quando ocioso -->
<Counter client:idle initialCount={5} />

<!-- Hidrata quando media query corresponde -->
<Counter client:media="(max-width: 768px)" initialCount={0} />

<!-- Sem hidratação -- apenas renderizado no servidor -->
<Counter initialCount={100} />
</Layout>
dica

Peça ao Cursor: "Crie uma ilha React para um formulário de inscrição de newsletter com validação de email e renderize-a como client:visible no meu layout Astro." O Cursor gerará o componente, lidará com o estado do formulário, adicionará validação e o conectará ao seu arquivo de layout.

Escolhendo a Diretiva de Hidratação Correta​

DiretivaQuando Usar
client:loadInteratividade necessária imediatamente (nav, busca)
client:idleWidgets de baixa prioridade carregados durante tempo ocioso do navegador
client:visibleWidgets abaixo da dobra que hidratam quando rolados para a visualização
client:mediaComponentes que devem carregar apenas em tamanhos de tela específicos
client:onlyPular renderização no servidor inteiramente (útil para APIs somente do navegador)
aviso

Use client:only com cautela. Componentes renderizados com esta diretiva pulam a renderização no lado do servidor, o que significa que não aparecerão no HTML inicial. Isso prejudica o SEO e causa mudança de layout. Use apenas para componentes que dependem de APIs somente do navegador como window ou localStorage na primeira renderização.

Integrações e Ecossistema​

Integrações do Astro estendem o framework com capacidades adicionais. A IA do Cursor pode ajudá-lo a configurar e solucionar problemas de integrações rapidamente.

Integração Tailwind CSS​

npx astro add tailwind

Isso instala @tailwindcss/vite e configura o plugin Vite. Crie um arquivo CSS com o import do Tailwind:

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

Importe a folha de estilo no seu layout:

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

Peça ao Cursor: "Configure o Tailwind CSS v4 com meu projeto Astro e crie um componente de barra de navegação responsiva." O Cursor configurará o plugin Vite, gerará a entrada CSS e construirá a navegação responsiva com classes utilitárias.

Integração MDX​

npx astro add mdx

Use arquivos .mdx em suas coleções de conteúdo para incorporar componentes interativos dentro do 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.

Integrações de Sitemap e RSS​

npx astro add sitemap
npx astro add rss

Configure-as em 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()],
});

Gere um feed RSS em um endpoint standalone:

// 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>',
});
}

Geração de Componentes com IA no Cursor​

O assistente de IA do Cursor se destaca em gerar componentes Astro, layouts e schemas de coleção a partir de descrições em linguagem natural.

Gerando Componentes a partir de Prompts​

Abra o Cursor Chat (Ctrl+L) ou use a edição inline (Ctrl+I) e descreva o que você precisa:

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.

O Cursor produzirá um componente totalmente tipado e estilizado:

---
// 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>
dica

Ao gerar componentes, inclua a interface de props no seu prompt. Isso garante que o Cursor produza props tipadas que você pode reutilizar em páginas. Por exemplo: "Crie um componente Card que aceite uma prop title, description, href e opcional image."

Geração de Layout com IA​

Peça ao Cursor para gerar um layout reutilizável:

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.

Configuração de Integração com IA​

O Cursor pode ajudar a solucionar problemas de integração. Se suas classes Tailwind não estão sendo aplicadas, pergunte:

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?

O Cursor analisará a configuração, verificará problemas comuns (plugin Vite ausente, caminhos de importação incorretos, configuração de conteúdo) e sugerirá correções.

aviso

Ao usar a IA do Cursor para modificar astro.config.mjs, sempre revise o array integrations gerado. Integrações devem ser listadas na ordem correta -- por exemplo, mdx() deve vir antes de sitemap() se as páginas MDX devem ser incluídas no sitemap.

Build e Deploy​

Geração de Site Estático​

Astro usa saída estática por padrão. Construa o site:

npm run build

A saída vai para dist/. Visualize o build de produção localmente:

npm run preview

Server-Side Rendering (SSR)​

Para conteúdo dinâmico, ative o modo SSR:

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

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

Renderização Híbrida​

Astro 4 suporta renderização híbrida, permitindo misturar páginas estáticas e renderizadas no servidor:

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

Marque páginas individuais como renderizadas no servidor com export const prerender = false;.

Debugging e Desempenho​

Analisando o Tamanho do Bundle​

Instale o analisador de bundle:

npm install -D astro-bundle-analyzer

Adicione-o às suas integrações:

import bundleAnalyzer from 'astro-bundle-analyzer';

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

Peça ao Cursor: "Meu build do Astro está enviando muito JavaScript. Analise meus componentes e diga quais ilhas podem ser alteradas de client:load para client:visible ou client:idle." O Cursor revisará o uso dos seus componentes e recomendará otimizações de diretiva de hidratação.

Otimização de Imagens​

Use o componente <Image> integrado do Astro para otimização automática:

---
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}
/>
aviso

Imagens remotas requerem uma entrada config.image.service ou configuração img.config. Se você ver erros de build sobre domínios de imagem remota, adicione os domínios permitidos ao astro.config.mjs em image.domains ou image.remotePatterns.

Conclusão​

Astro 4+ combinado com o Cursor cria um poderoso ambiente de desenvolvimento para construir sites rápidos e baseados em conteúdo. A combinação de saída sem JavaScript por padrão, coleções de conteúdo type-safe, View Transitions e arquitetura de ilhas significa que você obtém excelente desempenho sem sacrificar a experiência do desenvolvedor. O assistente de IA do Cursor acelera cada passo -- do scaffolding e design de schema até geração de componentes e solução de problemas de integração. Comece com um template minimal, adicione coleções de conteúdo para seus dados estruturados, introduza ilhas interativas apenas onde necessário, e deixe o Cursor gerar o boilerplate para que você possa focar no conteúdo e design.