astro-developer
npx skills add https://github.com/mokbhai/claude --skill astro-developer
Agent 安装分布
Skill 文档
Astro Developer Skill
Overview
Enables comprehensive Astro web development including component creation, project setup, configuration optimization, islands architecture implementation, content collections management, and deployment strategies. This skill emphasizes Tailwind CSS-first development for consistent, maintainable styling.
Quick Start
Identify the task type and follow the corresponding workflow:
- New Project Setup â Use “Project Initialization” workflow
- Component Development â Use “Component Creation” guidelines with Tailwind CSS
- Testing Setup â See Testing Guide for Vitest/Playwright
- Performance Optimization â Use “Islands Architecture” patterns, see Performance Guide
- State Management â See State Management Guide for React islands
- Troubleshooting Issues â See Common Pitfalls Guide
- Content Management â Use “Content Collections” workflow
- Configuration & Deployment â Use “Configuration” and “Deployment” sections
Core Capabilities
1. Project Initialization & Setup
Create new Astro projects with optimal configurations:
# Basic Astro project
npm create astro@latest my-project
# With specific integrations
npm create astro@latest -- --add react --add tailwind --add mdx
# From template
npm create astro@latest -- --template blog
Essential project structure to create:
src/
âââ components/ # Reusable Astro/UI framework components
âââ layouts/ # Page layout templates
âââ pages/ # File-based routing (REQUIRED)
âââ styles/ # CSS/Sass files
âââ content/ # Content collections (Markdown/MDX)
âââ env.d.ts # TypeScript environment types
public/ # Static assets (robots.txt, favicon, etc)
astro.config.mjs # Astro configuration
tsconfig.json # TypeScript configuration
package.json # Project dependencies and scripts
2. Component Creation
Astro Components (.astro)
Create server-rendered components with zero client-side JavaScript and Tailwind CSS styling:
---
// Component frontmatter - runs on server only
import { SITE_TITLE } from '@/config';
export interface Props {
title?: string;
published?: Date;
variant?: 'default' | 'primary' | 'secondary';
}
const { title, published, variant = 'default' } = Astro.props;
const variantClasses = {
default: 'bg-white dark:bg-gray-800',
primary: 'bg-blue-500 dark:bg-blue-600 text-white',
secondary: 'bg-gray-100 dark:bg-gray-700'
};
---
<!-- Component template - HTML with special syntax -->
<html lang="en" class="h-full">
<head>
<title>{title || SITE_TITLE}</title>
</head>
<body class="h-full m-0 font-sans leading-relaxed text-gray-900 dark:text-gray-100 bg-white dark:bg-gray-900">
<main class={`${variantClasses[variant]} p-6 rounded-lg shadow-sm`}>
{title && <h1 class="text-2xl font-bold mb-4">{title}</h1>}
{published && (
<time class="text-sm text-gray-600 dark:text-gray-400">
{published.toLocaleDateString()}
</time>
)}
<slot /> <!-- Children content -->
</main>
</body>
</html>
UI Framework Components (React, Vue, Svelte)
Add interactivity with client directives:
---
import ReactCounter from '@/components/ReactCounter.jsx';
import VueComponent from '@/components/VueComponent.vue';
import SvelteButton from '@/components/SvelteButton.svelte';
---
<!-- Load immediately -->
<ReactCounter client:load />
<!-- Load when visible in viewport -->
<SvelteButton client:visible />
<!-- Load when browser is idle -->
<VueComponent client:idle />
<!-- Load only on mobile -->
<ReactCounter client:load media="(max-width: 768px)" />
3. Islands Architecture
Implement optimal performance with selective hydration:
Client Islands Strategy
- Identify interactive components – Carousels, forms, modals
- Choose appropriate client directive:
client:load– Immediately (headers, critical features)client:idle– When browser free (secondary features)client:visible– When scrolled to (below-fold content)client:media– Based on media query
---
import InteractiveHeader from '@/components/InteractiveHeader.astro';
import ImageCarousel from '@/components/ImageCarousel.jsx';
import NewsletterForm from '@/components/NewsletterForm.jsx';
import SocialShare from '@/components/SocialShare.jsx';
---
<!-- Above fold, critical interactivity -->
<InteractiveHeader client:load />
<!-- Content heavy, load when visible -->
<ImageCarousel client:visible />
<!-- Secondary feature, load when idle -->
<NewsletterForm client:idle />
<!-- Mobile-only interactivity -->
<SocialShare client:load media="(max-width: 768px)" />
Server Islands for Dynamic Content
Use server:defer for personalized/dynamic content:
---
import UserProfile from '@/components/UserProfile.astro';
import RecommendedPosts from '@/components/RecommendedPosts.astro';
---
<!-- Static content loads immediately -->
<main>
<h1>Welcome to our blog</h1>
<p>Explore our latest articles...</p>
</main>
<!-- Dynamic content loads in parallel -->
<aside>
<!-- User's profile with personalized data -->
<UserProfile server:defer />
<!-- Recommended posts based on history -->
<RecommendedPosts server:defer />
</aside>
4. Routing & Pages
File-Based Routing
Create pages using Astro’s file-based routing:
src/pages/
âââ index.astro # â /
âââ about.astro # â /about
âââ blog/
â âââ index.astro # â /blog
â âââ [slug].astro # â /blog/post-title
â âââ [...page].astro # â /blog/2, /blog/3
âââ api/
âââ posts.json.js # â /api/posts (API endpoint)
Dynamic Routes
Handle dynamic segments with params:
---
// src/pages/blog/[slug].astro
import { getCollection } from 'astro:content';
export async function getStaticPaths() {
const posts = await getCollection('blog');
return posts.map((post) => ({
params: { slug: post.slug },
props: post,
}));
}
const { Content, frontmatter } = Astro.props;
---
<h1>{frontmatter.title}</h1>
<p>Published: {frontmatter.pubDate.toLocaleDateString()}</p>
<Content />
API Routes
Create server endpoints:
// src/pages/api/posts.json.js
export async function GET() {
return Response.json({
posts: [
{ id: 1, title: "First post" },
{ id: 2, title: "Second post" },
],
});
}
export async function POST({ request }) {
const data = await request.json();
// Process form submission
return Response.json({ success: true });
}
5. Content Collections
Organize and validate content with type safety:
Configure Collections
// src/content/config.ts
import { defineCollection, z } from "astro:content";
const blog = defineCollection({
schema: z.object({
title: z.string(),
pubDate: z.date(),
updatedDate: z.date().optional(),
description: z.string(),
heroImage: z.string().optional(),
tags: z.array(z.string()).default([]),
draft: z.boolean().default(false),
}),
});
const projects = defineCollection({
schema: z.object({
title: z.string(),
description: z.string(),
startDate: z.date(),
endDate: z.date().optional(),
technologies: z.array(z.string()),
demoUrl: z.string().url().optional(),
repoUrl: z.string().url().optional(),
}),
});
export const collections = { blog, projects };
Use Content in Pages
---
// src/pages/blog/index.astro
import { getCollection } from 'astro:content';
import BlogLayout from '@/layouts/BlogLayout.astro';
import BlogPost from '@/components/BlogPost.astro';
const posts = await getCollection('blog', ({ data }) => !data.draft);
const sortedPosts = posts.sort((a, b) =>
b.data.pubDate.valueOf() - a.data.pubDate.valueOf()
);
---
<BlogLayout title="Blog">
{sortedPosts.map((post) => (
<BlogPost post={post} />
))}
</BlogLayout>
6. Styling & Integrations
Tailwind CSS Integration (Primary Styling Approach)
This skill emphasizes Tailwind CSS as the primary styling solution for all Astro projects.
// astro.config.mjs
import tailwind from "@astrojs/tailwind";
export default defineConfig({
integrations: [tailwind()],
});
Configure Tailwind for optimal performance:
// tailwind.config.js
export default {
content: ["./src/**/*.{astro,html,js,jsx,md,mdx,svelte,ts,tsx,vue}"],
darkMode: "class", // Enables dark mode with .dark class
theme: {
extend: {
fontFamily: {
sans: ["Inter", "system-ui", "sans-serif"],
},
colors: {
// Define brand colors
primary: {
50: "#eff6ff",
500: "#3b82f6",
600: "#2563eb",
900: "#1e3a8a",
},
},
},
},
plugins: [],
};
Global styles setup:
/* src/styles/global.css */
@tailwind base;
@tailwind components;
@tailwind utilities;
@layer base {
/* Custom base styles */
}
@layer components {
/* Custom component classes */
}
Tailwind CSS Best Practices
-
Use Custom Brand Colors: Always use the predefined brand colors from
global.css<!-- â Use brand colors --> <div class="bg-mitra-blue text-warm-cream"> <div class="border-lush-green bg-warm-orange/10"> <!-- â Avoid generic colors --> <div class="bg-blue-500 text-yellow-100"> <div class="border-green-500 bg-orange-100">Available brand colors:
- Primary:
mitra-blue,mitra-yellow,lush-green,warm-orange - Text:
charcoal-grey,warm-cream - Gradients:
bg-magic-gradient(custom utility),bg-linear-to-brwith brand colors
- Primary:
-
Variant-based styling: Use JavaScript objects with brand colors
const buttonVariants = { primary: "bg-mitra-blue hover:bg-mitra-blue-dark text-white", secondary: "bg-warm-cream hover:bg-grey-100 text-charcoal-grey", accent: "bg-warm-orange hover:bg-warm-orange-dark text-white", }; -
Responsive design: Use Tailwind’s responsive prefixes
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4"> -
Dark mode: Implement with
dark:prefix<div class="bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100"> -
Composition: Combine utility classes with brand colors
<!-- â Using brand colors --> <div class="flex flex-col items-center justify-center p-8 bg-linear-to-br from-mitra-blue/10 to-lush-green/10 rounded-2xl shadow-xl"> <div class="p-6 border border-warm-orange/20 bg-magic-gradient"> -
Custom properties: Use CSS variables for dynamic values
<div style="--delay: 100ms" class="animate-pulse [--delay:200ms]">
6. Tailwind CSS v4 Canonical Class Names
IMPORTANT: Tailwind CSS v4 uses different canonical class names. Always use these updated forms:
bg-gradient-to-*âbg-linear-to-*(e.g.,bg-gradient-to-râbg-linear-to-r)flex-shrink-0âshrink-0aspect-[3/2]âaspect-3/2(remove brackets for simple ratios)grayscale-[30%]âgrayscale-30(remove brackets for percentage values)
Examples:
<!-- Correct (Tailwind v4) -->
<div class="bg-linear-to-r from-blue-500 to-purple-600 shrink-0 aspect-3/2 grayscale-30">
<!-- Incorrect (deprecated) -->
<!-- These will trigger linter warnings: -->
<!-- bg-gradient-to-r â should be bg-linear-to-r -->
<!-- flex-shrink-0 â should be shrink-0 -->
<!-- aspect-[3/2] â should be aspect-3/2 -->
<!-- grayscale-[30%] â should be grayscale-30 -->
React Integration
// astro.config.mjs
import react from "@astrojs/react";
export default defineConfig({
integrations: [react()],
});
MDX Integration
// astro.config.mjs
import mdx from "@astrojs/mdx";
export default defineConfig({
integrations: [mdx()],
});
7. Performance Optimization
Image Optimization
---
import { Image } from 'astro:assets';
import heroImage from '@/images/hero.jpg';
---
<!-- Optimized, responsive images -->
<Image
src={heroImage}
alt="Hero section background"
widths={[400, 800, 1200]}
formats={['avif', 'webp', 'jpg']}
loading="eager"
/>
View Transitions
Enable smooth page transitions:
---
// src/layouts/MainLayout.astro
import { ViewTransitions } from 'astro:transitions';
---
<html>
<head>
<ViewTransitions />
</head>
<body>
<header>
<nav>
<a href="/" transition:name="home">Home</a>
<a href="/about" transition:name="about">About</a>
</nav>
</header>
<main transition:name="main-content">
<slot />
</main>
</body>
</html>
8. Configuration Best Practices
Optimize astro.config.mjs
import { defineConfig } from "astro/config";
import react from "@astrojs/react";
import sitemap from "@astrojs/sitemap";
import tailwind from "@astrojs/tailwind";
export default defineConfig({
// Site metadata for SEO
site: "https://yoursite.com",
base: "/subpath", // If deploying to subdirectory
// Integrations
integrations: [react(), tailwind(), sitemap()],
// Build optimizations
build: {
format: "directory", // Clean URLs
assets: "_assets", // Custom assets path
},
// Vite configurations
vite: {
optimizeDeps: {
exclude: ["some-large-package"],
},
},
// Server options for SSR
output: "hybrid", // or 'server' or 'static'
// Security headers
security: {
allowedHosts: ["yoursite.com"],
},
});
TypeScript Configuration
// tsconfig.json
{
"extends": "astro/tsconfigs/strict",
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": ["./src/*"],
"@/components/*": ["./src/components/*"],
"@/layouts/*": ["./src/layouts/*"]
},
"types": ["@astrojs/image/client"]
},
"include": ["src/**/*.ts", "src/**/*.d.ts"]
}
9. Deployment Strategies
Static Site Generation (Default)
npm run build # Creates static files in dist/
Deploy to:
- Vercel, Netlify, Cloudflare Pages
- GitHub Pages, GitLab Pages
- Any static hosting
Hybrid Rendering
// astro.config.mjs
export default defineConfig({
output: 'hybrid',
});
// Individual pages can opt-in to SSR
---
export const prerender = false;
---
Server-Side Rendering
// astro.config.mjs
export default defineConfig({
output: "server",
adapter: node({
mode: "standalone",
}),
});
Deploy to:
- Node.js servers
- Docker containers
- Serverless platforms (Vercel, Netlify Functions)
10. Testing Strategies
See Testing Guide for comprehensive testing documentation.
Vitest for Unit Testing
npm install -D vitest @vitest/ui jsdom
// vitest.config.ts
import { getViteConfig } from 'astro/config';
export default getViteConfig({
test: {
environment: 'jsdom',
include: ['src/**/*.{test,spec}.{js,ts,jsx,tsx}'],
},
});
Playwright for E2E Testing
npm init playwright@latest
// playwright.config.ts
import { defineConfig } from '@playwright/test';
export default defineConfig({
webServer: {
command: 'npm run preview',
url: 'http://localhost:4321/',
},
});
Container API for Astro Components
import { experimental_AstroContainer as AstroContainer } from 'astro/container';
import { expect, test } from 'vitest';
import Card from '../src/components/Card.astro';
test('Card renders with props', async () => {
const container = await AstroContainer.create();
const result = await container.renderToString(Card, {
props: { title: 'Test' },
});
expect(result).toContain('Test');
});
11. TypeScript Best Practices
See Common Pitfalls Guide for TypeScript-specific issues.
Strict Mode Configuration
// tsconfig.json
{
"extends": "astro/tsconfigs/strict",
"compilerOptions": {
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noImplicitReturns": true,
"baseUrl": ".",
"paths": {
"@/*": ["./src/*"],
"@/components/*": ["./src/components/*"],
"@/layouts/*": ["./src/layouts/*"]
}
}
}
Type-Safe Props
---
export interface Props {
title: string;
count: number;
isActive?: boolean;
tags: string[];
}
const { title, count, isActive = false, tags } = Astro.props;
---
12. State Management for React Islands
See State Management Guide for comprehensive patterns.
Zustand (Recommended)
// src/store/useStore.ts
import { create } from 'zustand';
export const useStore = create((set) => ({
count: 0,
increment: () => set((state) => ({ count: state.count + 1 })),
}));
Usage Across Islands
// Component 1
import { useStore } from '@/store/useStore';
function Counter() {
const { increment } = useStore();
return <button onClick={increment}>+</button>;
}
// Component 2
import { useStore } from '@/store/useStore';
function Display() {
const count = useStore((state) => state.count);
return <div>{count}</div>;
}
Common Patterns & Solutions
Environment Variables
// Create .env file
PUBLIC_API_URL=https://api.example.com
SECRET_KEY=your-secret-key
// Use in components
const apiUrl = import.meta.env.PUBLIC_API_URL;
SEO Best Practices
---
// src/layouts/BaseLayout.astro
interface Props {
title: string;
description: string;
image?: string;
url?: string;
}
const { title, description, image, url } = Astro.props;
const siteUrl = Astro.site;
const canonicalUrl = url ? new URL(url, siteUrl) : siteUrl;
---
<html>
<head>
<title>{title}</title>
<meta name="description" content={description} />
<link rel="canonical" href={canonicalUrl} />
{image && (
<meta property="og:image" content={new URL(image, siteUrl)} />
)}
<meta property="og:title" content={title} />
<meta property="og:description" content={description} />
<meta property="og:url" content={canonicalUrl} />
<meta name="twitter:card" content="summary_large_image" />
</head>
</html>
Error Handling
---
// src/pages/404.astro
import Layout from '@/layouts/Layout.astro';
---
<Layout title="Not Found">
<h1>404 - Page not found</h1>
<p>Sorry, we couldn't find that page.</p>
</Layout>
// src/pages/error/[...code].astro
export function getStaticPaths() {
return [{ params: { code: "403" } }, { params: { code: "500" } }];
}
const { code } = Astro.params;
const errorMessages = {
403: "Forbidden",
500: "Internal Server Error",
};
Common Issues & Solutions
Component Not Interactive
Problem: React/Vue components render but don’t respond to user interaction.
Solution: Add client:* directive. By default, Astro strips all client-side JavaScript.
---
import ReactComponent from '@/components/ReactComponent.jsx';
---
<!-- â Wrong: No client directive -->
<ReactComponent />
<!-- â
Correct: Add appropriate client directive -->
<ReactComponent client:load />
Context API Not Working Across Islands
Problem: React Context providers don’t share state between different component islands.
Solution: Each Astro island hydrates in isolation. Use external state management (Zustand, Redux, MobX) for cross-island state sharing.
See State Management Guide for detailed patterns.
document or window is Not Defined
Problem: Error accessing browser APIs during server-side rendering.
Solution: Move browser-only code to <script> tags or use lifecycle methods in framework components.
---
// â Wrong: Browser API in frontmatter
const width = window.innerWidth;
---
<!-- â
Correct: Move to script tag -->
<script>
const width = window.innerWidth;
</script>
TypeScript Ref Callback Errors
When using React refs with arrays in TypeScript, avoid this common error:
// â Incorrect - TypeScript error
<div ref={(el) => (cardsRef.current[index] = el)}>
// â
Correct - Wrap the assignment
<div ref={(el) => {
cardsRef.current[index] = el;
}}>
Tailwind CSS v4 Migration
Common issues when migrating from Tailwind CSS v3 to v4:
- Gradient classes: Always use
bg-linear-to-*instead ofbg-gradient-to-* - Aspect ratios: Use
aspect-3/2instead ofaspect-[3/2]for simple ratios - Flexbox: Use
shrink-0instead offlex-shrink-0 - Filters: Use
grayscale-30instead ofgrayscale-[30%]for percentage values
File Path Resolution
If you encounter errors about missing files that should exist:
- Check if the file exists at the expected path
- The error might be from an outdated diagnostic cache
- Files may have been renamed or moved
Resources
scripts/
The scripts/ directory contains automation utilities:
create-component.js– Generates component boilerplateoptimize-images.js– Batch image optimizationgenerate-sitemap.js– Custom sitemap generation
Execute scripts without loading into context:
node scripts/create-component.js --name MyComponent --type astro
references/
Reference materials for detailed information:
component-patterns.md– Common Astro component patternsintegration-guide.md– Detailed integration setup guides (React, Vue, Tailwind, MDX, etc.)testing-guide.md– NEW: Comprehensive testing strategies with Vitest, Playwright, and Container APIcommon-pitfalls.md– NEW: Common mistakes and solutions for islands architecture, client directives, SSR vs static renderingperformance-optimization.md– NEW: Build optimization, image optimization, code splitting, deployment strategiesstate-management.md– NEW: State management patterns for React islands (Zustand, Redux Toolkit, Jotai, TanStack Query)
Load reference materials when specific detailed information is needed:
Read references/testing-guide.md when setting up testing infrastructure
Read references/common-pitfalls.md when troubleshooting hydration or directive issues
Read references/performance-optimization.md when optimizing build size or load times
Read references/state-management.md when implementing cross-island state sharing
assets/
Templates and boilerplate code:
component-templates/– Starting templates for different component typeslayout-templates/– Common layout patternspage-templates/– Page boilerplate for different use cases
Use assets as starting points:
- Copy component templates for new components
- Reference layout templates for consistent structure
- Adapt page templates for common page types
This skill provides comprehensive Astro development guidance from project setup through deployment optimization.