astro-developer
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseAstro Developer Skill
Astro开发者技能
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.
支持全面的Astro Web开发,包括组件创建、项目搭建、配置优化、Islands架构实现、内容集合管理以及部署策略。本技能强调以Tailwind CSS优先的开发方式,以实现一致、可维护的样式设计。
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
识别任务类型并遵循相应工作流程:
- 新项目搭建 → 使用「项目初始化」工作流程
- 组件开发 → 遵循结合Tailwind CSS的「组件创建」指南
- 测试设置 → 查看测试指南了解Vitest/Playwright的使用
- 性能优化 → 使用「Islands架构」模式,查看性能指南
- 状态管理 → 查看状态管理指南了解React islands的实现
- 问题排查 → 查看常见问题指南
- 内容管理 → 使用「内容集合」工作流程
- 配置与部署 → 参考「配置」和「部署」章节
Core Capabilities
核心能力
1. Project Initialization & Setup
1. 项目初始化与搭建
Create new Astro projects with optimal configurations:
bash
undefined创建配置优化的Astro新项目:
bash
undefinedBasic Astro project
基础Astro项目
npm create astro@latest my-project
npm create astro@latest my-project
With specific integrations
带特定集成
npm create astro@latest -- --add react --add tailwind --add mdx
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
undefinednpm create astro@latest -- --template blog
需创建的核心项目结构:
src/
├── components/ # 可复用的Astro/UI框架组件
├── layouts/ # 页面布局模板
├── pages/ # 文件式路由(必填)
├── styles/ # CSS/Sass文件
├── content/ # 内容集合(Markdown/MDX)
└── env.d.ts # TypeScript环境类型
public/ # 静态资源(robots.txt、favicon等)
astro.config.mjs # Astro配置文件
tsconfig.json # TypeScript配置文件
package.json # 项目依赖与脚本
undefined2. Component Creation
2. 组件创建
Astro Components (.astro)
Astro组件(.astro)
Create server-rendered components with zero client-side JavaScript and Tailwind CSS styling:
astro
---
// 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>创建零客户端JavaScript的服务端渲染组件,并结合Tailwind CSS样式:
astro
---
// 组件前置代码 - 仅在服务端运行
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'
};
---
<!-- 组件模板 - 带特殊语法的HTML -->
<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 /> <!-- 子内容插槽 -->
</main>
</body>
</html>UI Framework Components (React, Vue, Svelte)
UI框架组件(React、Vue、Svelte)
Add interactivity with client directives:
astro
---
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)" />通过客户端指令添加交互性:
astro
---
import ReactCounter from '@/components/ReactCounter.jsx';
import VueComponent from '@/components/VueComponent.vue';
import SvelteButton from '@/components/SvelteButton.svelte';
---
<!-- 立即加载 -->
<ReactCounter client:load />
<!-- 进入视口时加载 -->
<SvelteButton client:visible />
<!-- 浏览器空闲时加载 -->
<VueComponent client:idle />
<!-- 仅在移动端加载 -->
<ReactCounter client:load media="(max-width: 768px)" />3. Islands Architecture
3. Islands架构
Implement optimal performance with selective hydration:
通过选择性水合实现最优性能:
Client Islands Strategy
客户端Islands策略
- Identify interactive components - Carousels, forms, modals
- Choose appropriate client directive:
- - Immediately (headers, critical features)
client:load - - When browser free (secondary features)
client:idle - - When scrolled to (below-fold content)
client:visible - - Based on media query
client:media
astro
---
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)" />- 识别交互式组件 - 轮播图、表单、模态框
- 选择合适的客户端指令:
- - 立即加载(页头、核心功能)
client:load - - 浏览器空闲时加载(次要功能)
client:idle - - 滚动到视图时加载(折叠下方内容)
client:visible - - 基于媒体查询加载
client:media
astro
---
import InteractiveHeader from '@/components/InteractiveHeader.astro';
import ImageCarousel from '@/components/ImageCarousel.jsx';
import NewsletterForm from '@/components/NewsletterForm.jsx';
import SocialShare from '@/components/SocialShare.jsx';
---
<!-- 首屏区域,核心交互 -->
<InteractiveHeader client:load />
<!-- 内容密集,进入视口时加载 -->
<ImageCarousel client:visible />
<!-- 次要功能,浏览器空闲时加载 -->
<NewsletterForm client:idle />
<!-- 仅移动端交互 -->
<SocialShare client:load media="(max-width: 768px)" />Server Islands for Dynamic Content
服务端Islands用于动态内容
Use for personalized/dynamic content:
server:deferastro
---
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>使用加载个性化/动态内容:
server:deferastro
---
import UserProfile from '@/components/UserProfile.astro';
import RecommendedPosts from '@/components/RecommendedPosts.astro';
---
<!-- 静态内容立即加载 -->
<main>
<h1>欢迎访问我们的博客</h1>
<p>探索我们的最新文章...</p>
</main>
<!-- 动态内容并行加载 -->
<aside>
<!-- 带个性化数据的用户资料 -->
<UserProfile server:defer />
<!-- 基于浏览历史的推荐文章 -->
<RecommendedPosts server:defer />
</aside>4. Routing & Pages
4. 路由与页面
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)使用Astro的文件式路由创建页面:
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端点)Dynamic Routes
动态路由
Handle dynamic segments with params:
astro
---
// 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 />通过参数处理动态路由片段:
astro
---
// 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>发布时间:{frontmatter.pubDate.toLocaleDateString()}</p>
<Content />API Routes
API路由
Create server endpoints:
javascript
// 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 });
}创建服务端端点:
javascript
// src/pages/api/posts.json.js
export async function GET() {
return Response.json({
posts: [
{ id: 1, title: "第一篇文章" },
{ id: 2, title: "第二篇文章" },
],
});
}
export async function POST({ request }) {
const data = await request.json();
// 处理表单提交
return Response.json({ success: true });
}5. Content Collections
5. 内容集合
Organize and validate content with type safety:
通过类型安全的方式组织和验证内容:
Configure Collections
配置内容集合
typescript
// 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 };typescript
// 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
在页面中使用内容
astro
---
// 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>astro
---
// 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="博客">
{sortedPosts.map((post) => (
<BlogPost post={post} />
))}
</BlogLayout>6. Styling & Integrations
6. 样式与集成
Tailwind CSS Integration (Primary Styling Approach)
Tailwind CSS集成(主要样式方案)
This skill emphasizes Tailwind CSS as the primary styling solution for all Astro projects.
javascript
// astro.config.mjs
import tailwind from "@astrojs/tailwind";
export default defineConfig({
integrations: [tailwind()],
});Configure Tailwind for optimal performance:
javascript
// 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:
css
/* src/styles/global.css */
@tailwind base;
@tailwind components;
@tailwind utilities;
@layer base {
/* Custom base styles */
}
@layer components {
/* Custom component classes */
}本技能强调将Tailwind CSS作为所有Astro项目的主要样式解决方案。
javascript
// astro.config.mjs
import tailwind from "@astrojs/tailwind";
export default defineConfig({
integrations: [tailwind()],
});配置Tailwind以实现最优性能:
javascript
// tailwind.config.js
export default {
content: ["./src/**/*.{astro,html,js,jsx,md,mdx,svelte,ts,tsx,vue}"],
darkMode: "class", // 通过.dark类启用暗色模式
theme: {
extend: {
fontFamily: {
sans: ["Inter", "system-ui", "sans-serif"],
},
colors: {
// 定义品牌颜色
primary: {
50: "#eff6ff",
500: "#3b82f6",
600: "#2563eb",
900: "#1e3a8a",
},
},
},
},
plugins: [],
};全局样式设置:
css
/* src/styles/global.css */
@tailwind base;
@tailwind components;
@tailwind utilities;
@layer base {
/* 自定义基础样式 */
}
@layer components {
/* 自定义组件类 */
}Tailwind CSS Best Practices
Tailwind CSS最佳实践
-
Use Custom Brand Colors: Always use the predefined brand colors from
global.cssastro<!-- ✅ 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-greenwarm-orange - Text: ,
charcoal-greywarm-cream - Gradients: (custom utility),
bg-magic-gradientwith brand colorsbg-linear-to-br
- Primary:
-
Variant-based styling: Use JavaScript objects with brand colorsjavascript
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 prefixesastro
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4"> -
Dark mode: Implement withprefix
dark:astro<div class="bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100"> -
Composition: Combine utility classes with brand colorsastro
<!-- ✅ 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 valuesastro
<div style="--delay: 100ms" class="animate-pulse [--delay:200ms]">
-
使用自定义品牌颜色:始终使用中预定义的品牌颜色
global.cssastro<!-- ✅ 推荐:使用品牌颜色 --> <div class="bg-mitra-blue text-warm-cream"> <div class="border-lush-green bg-warm-orange/10"> <!-- ❌ 不推荐:使用通用颜色 --> <div class="bg-blue-500 text-yellow-100"> <div class="border-green-500 bg-orange-100">可用品牌颜色:- 主色调:、
mitra-blue、mitra-yellow、lush-greenwarm-orange - 文字色:、
charcoal-greywarm-cream - 渐变:(自定义工具类)、结合品牌颜色的
bg-magic-gradientbg-linear-to-br
- 主色调:
-
基于变体的样式:使用JavaScript对象结合品牌颜色javascript
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", }; -
响应式设计:使用Tailwind的响应式前缀astro
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4"> -
暗色模式:通过前缀实现
dark:astro<div class="bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100"> -
样式组合:结合工具类与品牌颜色astro
<!-- ✅ 使用品牌颜色 --> <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"> -
自定义属性:使用CSS变量实现动态值astro
<div style="--delay: 100ms" class="animate-pulse [--delay:200ms]">
6. Tailwind CSS v4 Canonical Class Names
6. Tailwind CSS v4标准类名
IMPORTANT: Tailwind CSS v4 uses different canonical class names. Always use these updated forms:
- →
bg-gradient-to-*(e.g.,bg-linear-to-*→bg-gradient-to-r)bg-linear-to-r - →
flex-shrink-0shrink-0 - →
aspect-[3/2](remove brackets for simple ratios)aspect-3/2 - →
grayscale-[30%](remove brackets for percentage values)grayscale-30
Examples:
astro
<!-- 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 -->重要提示:Tailwind CSS v4使用不同的标准类名,请始终使用以下更新后的形式:
- →
bg-gradient-to-*(例如:bg-linear-to-*→bg-gradient-to-r)bg-linear-to-r - →
flex-shrink-0shrink-0 - →
aspect-[3/2](简单比例移除方括号)aspect-3/2 - →
grayscale-[30%](百分比值移除方括号)grayscale-30
示例:
astro
<!-- 正确(Tailwind v4) -->
<div class="bg-linear-to-r from-blue-500 to-purple-600 shrink-0 aspect-3/2 grayscale-30">
<!-- 错误(已废弃) -->
<!-- 这些会触发代码检查警告: -->
<!-- bg-gradient-to-r → 应改为bg-linear-to-r -->
<!-- flex-shrink-0 → 应改为shrink-0 -->
<!-- aspect-[3/2] → 应改为aspect-3/2 -->
<!-- grayscale-[30%] → 应改为grayscale-30 -->React Integration
React集成
javascript
// astro.config.mjs
import react from "@astrojs/react";
export default defineConfig({
integrations: [react()],
});javascript
// astro.config.mjs
import react from "@astrojs/react";
export default defineConfig({
integrations: [react()],
});MDX Integration
MDX集成
javascript
// astro.config.mjs
import mdx from "@astrojs/mdx";
export default defineConfig({
integrations: [mdx()],
});javascript
// astro.config.mjs
import mdx from "@astrojs/mdx";
export default defineConfig({
integrations: [mdx()],
});7. Performance Optimization
7. 性能优化
Image Optimization
图片优化
astro
---
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"
/>astro
---
import { Image } from 'astro:assets';
import heroImage from '@/images/hero.jpg';
---
<!-- 经过优化的响应式图片 -->
<Image
src={heroImage}
alt="首页横幅背景"
widths={[400, 800, 1200]}
formats={['avif', 'webp', 'jpg']}
loading="eager"
/>View Transitions
视图过渡
Enable smooth page transitions:
astro
---
// 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>启用流畅的页面过渡效果:
astro
---
// src/layouts/MainLayout.astro
import { ViewTransitions } from 'astro:transitions';
---
<html>
<head>
<ViewTransitions />
</head>
<body>
<header>
<nav>
<a href="/" transition:name="home">首页</a>
<a href="/about" transition:name="about">关于我们</a>
</nav>
</header>
<main transition:name="main-content">
<slot />
</main>
</body>
</html>8. Configuration Best Practices
8. 配置最佳实践
Optimize astro.config.mjs
优化astro.config.mjs
javascript
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"],
},
});javascript
import { defineConfig } from "astro/config";
import react from "@astrojs/react";
import sitemap from "@astrojs/sitemap";
import tailwind from "@astrojs/tailwind";
export default defineConfig({
// SEO用站点元数据
site: "https://yoursite.com",
base: "/subpath", // 若部署到子目录
// 集成插件
integrations: [react(), tailwind(), sitemap()],
// 构建优化
build: {
format: "directory", // 干净URL
assets: "_assets", // 自定义资源路径
},
// Vite配置
vite: {
optimizeDeps: {
exclude: ["some-large-package"],
},
},
// SSR用服务器选项
output: "hybrid", // 或'server'、'static'
// 安全头
security: {
allowedHosts: ["yoursite.com"],
},
});TypeScript Configuration
TypeScript配置
json
// 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"]
}json
// 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
9. 部署策略
Static Site Generation (Default)
静态站点生成(默认)
bash
npm run build # Creates static files in dist/Deploy to:
- Vercel, Netlify, Cloudflare Pages
- GitHub Pages, GitLab Pages
- Any static hosting
bash
npm run build # 在dist/目录生成静态文件可部署至:
- Vercel、Netlify、Cloudflare Pages
- GitHub Pages、GitLab Pages
- 任何静态托管平台
Hybrid Rendering
混合渲染
javascript
// astro.config.mjs
export default defineConfig({
output: 'hybrid',
});
// Individual pages can opt-in to SSR
---
export const prerender = false;
---javascript
// astro.config.mjs
export default defineConfig({
output: 'hybrid',
});
// 单个页面可选择启用SSR
---
export const prerender = false;
---Server-Side Rendering
服务端渲染
javascript
// astro.config.mjs
export default defineConfig({
output: "server",
adapter: node({
mode: "standalone",
}),
});Deploy to:
- Node.js servers
- Docker containers
- Serverless platforms (Vercel, Netlify Functions)
javascript
// astro.config.mjs
export default defineConfig({
output: "server",
adapter: node({
mode: "standalone",
}),
});可部署至:
- Node.js服务器
- Docker容器
- 无服务器平台(Vercel、Netlify Functions)
10. Testing Strategies
10. 测试策略
See Testing Guide for comprehensive testing documentation.
查看测试指南获取全面的测试文档。
Vitest for Unit Testing
Vitest单元测试
bash
npm install -D vitest @vitest/ui jsdomtypescript
// vitest.config.ts
import { getViteConfig } from 'astro/config';
export default getViteConfig({
test: {
environment: 'jsdom',
include: ['src/**/*.{test,spec}.{js,ts,jsx,tsx}'],
},
});bash
npm install -D vitest @vitest/ui jsdomtypescript
// 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
Playwright端到端测试
bash
npm init playwright@latesttypescript
// playwright.config.ts
import { defineConfig } from '@playwright/test';
export default defineConfig({
webServer: {
command: 'npm run preview',
url: 'http://localhost:4321/',
},
});bash
npm init playwright@latesttypescript
// 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
Astro组件的容器API
javascript
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');
});javascript
import { experimental_AstroContainer as AstroContainer } from 'astro/container';
import { expect, test } from 'vitest';
import Card from '../src/components/Card.astro';
test('Card组件可根据props渲染', async () => {
const container = await AstroContainer.create();
const result = await container.renderToString(Card, {
props: { title: '测试' },
});
expect(result).toContain('测试');
});11. TypeScript Best Practices
11. TypeScript最佳实践
See Common Pitfalls Guide for TypeScript-specific issues.
查看常见问题指南获取TypeScript相关问题的解决方案。
Strict Mode Configuration
严格模式配置
json
// tsconfig.json
{
"extends": "astro/tsconfigs/strict",
"compilerOptions": {
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noImplicitReturns": true,
"baseUrl": ".",
"paths": {
"@/*": ["./src/*"],
"@/components/*": ["./src/components/*"],
"@/layouts/*": ["./src/layouts/*"]
}
}
}json
// 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
类型安全的Props
astro
---
export interface Props {
title: string;
count: number;
isActive?: boolean;
tags: string[];
}
const { title, count, isActive = false, tags } = Astro.props;
---astro
---
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
12. React Islands的状态管理
See State Management Guide for comprehensive patterns.
查看状态管理指南获取全面的实现模式。
Zustand (Recommended)
Zustand(推荐)
typescript
// src/store/useStore.ts
import { create } from 'zustand';
export const useStore = create((set) => ({
count: 0,
increment: () => set((state) => ({ count: state.count + 1 })),
}));typescript
// 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
跨Islands使用
jsx
// 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>;
}jsx
// 组件1
import { useStore } from '@/store/useStore';
function Counter() {
const { increment } = useStore();
return <button onClick={increment}>+</button>;
}
// 组件2
import { useStore } from '@/store/useStore';
function Display() {
const count = useStore((state) => state.count);
return <div>{count}</div>;
}Common Patterns & Solutions
常见模式与解决方案
Environment Variables
环境变量
typescript
// 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;typescript
// 创建.env文件
PUBLIC_API_URL=https://api.example.com
SECRET_KEY=your-secret-key
// 在组件中使用
const apiUrl = import.meta.env.PUBLIC_API_URL;SEO Best Practices
SEO最佳实践
astro
---
// 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>astro
---
// 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
错误处理
astro
---
// 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>javascript
// 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",
};astro
---
// src/pages/404.astro
import Layout from '@/layouts/Layout.astro';
---
<Layout title="页面未找到">
<h1>404 - 页面未找到</h1>
<p>抱歉,我们无法找到您访问的页面。</p>
</Layout>javascript
// src/pages/error/[...code].astro
export function getStaticPaths() {
return [{ params: { code: "403" } }, { params: { code: "500" } }];
}
const { code } = Astro.params;
const errorMessages = {
403: "禁止访问",
500: "服务器内部错误",
};Common Issues & Solutions
常见问题与解决方案
Component Not Interactive
组件无交互性
Problem: React/Vue components render but don't respond to user interaction.
Solution: Add directive. By default, Astro strips all client-side JavaScript.
client:*astro
---
import ReactComponent from '@/components/ReactComponent.jsx';
---
<!-- ❌ Wrong: No client directive -->
<ReactComponent />
<!-- ✅ Correct: Add appropriate client directive -->
<ReactComponent client:load />问题:React/Vue组件可渲染,但无法响应用户交互。
解决方案:添加指令。默认情况下,Astro会移除所有客户端JavaScript。
client:*astro
---
import ReactComponent from '@/components/ReactComponent.jsx';
---
<!-- ❌ 错误:无客户端指令 -->
<ReactComponent />
<!-- ✅ 正确:添加合适的客户端指令 -->
<ReactComponent client:load />Context API Not Working Across Islands
Context API在跨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.
问题:React Context提供者无法在不同组件Islands间共享状态。
解决方案:每个Astro Island都是独立水合的。使用外部状态管理工具(Zustand、Redux、MobX)实现跨Islands状态共享。
查看状态管理指南获取详细实现模式。
document
or window
is Not Defined
documentwindowdocument
或window
未定义
documentwindowProblem: Error accessing browser APIs during server-side rendering.
Solution: Move browser-only code to tags or use lifecycle methods in framework components.
<script>astro
---
// ❌ Wrong: Browser API in frontmatter
const width = window.innerWidth;
---
<!-- ✅ Correct: Move to script tag -->
<script>
const width = window.innerWidth;
</script>问题:服务端渲染期间访问浏览器API时出现错误。
解决方案:将仅浏览器端代码移至标签中,或在框架组件中使用生命周期方法。
<script>astro
---
// ❌ 错误:在前置代码中使用浏览器API
const width = window.innerWidth;
---
<!-- ✅ 正确:移至script标签 -->
<script>
const width = window.innerWidth;
</script>TypeScript Ref Callback Errors
TypeScript Ref回调错误
When using React refs with arrays in TypeScript, avoid this common error:
tsx
// ❌ Incorrect - TypeScript error
<div ref={(el) => (cardsRef.current[index] = el)}>
// ✅ Correct - Wrap the assignment
<div ref={(el) => {
cardsRef.current[index] = el;
}}>在TypeScript中使用React refs数组时,避免以下常见错误:
tsx
// ❌ 错误 - TypeScript报错
<div ref={(el) => (cardsRef.current[index] = el)}>
// ✅ 正确 - 包裹赋值操作
<div ref={(el) => {
cardsRef.current[index] = el;
}}>Tailwind CSS v4 Migration
Tailwind CSS v4迁移
Common issues when migrating from Tailwind CSS v3 to v4:
- Gradient classes: Always use instead of
bg-linear-to-*bg-gradient-to-* - Aspect ratios: Use instead of
aspect-3/2for simple ratiosaspect-[3/2] - Flexbox: Use instead of
shrink-0flex-shrink-0 - Filters: Use instead of
grayscale-30for percentage valuesgrayscale-[30%]
从Tailwind CSS v3迁移至v4时的常见问题:
- 渐变类:始终使用而非
bg-linear-to-*bg-gradient-to-* - 宽高比:简单比例使用而非
aspect-3/2aspect-[3/2] - Flexbox:使用而非
shrink-0flex-shrink-0 - 滤镜:百分比值使用而非
grayscale-30grayscale-[30%]
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/
scripts/
The scripts/ directory contains automation utilities:
- - Generates component boilerplate
create-component.js - - Batch image optimization
optimize-images.js - - Custom sitemap generation
generate-sitemap.js
Execute scripts without loading into context:
bash
node scripts/create-component.js --name MyComponent --type astroscripts/目录包含自动化工具:
- - 生成组件模板代码
create-component.js - - 批量图片优化
optimize-images.js - - 自定义站点地图生成
generate-sitemap.js
无需加载上下文即可执行脚本:
bash
node scripts/create-component.js --name MyComponent --type astroreferences/
references/
Reference materials for detailed information:
- - Common Astro component patterns
component-patterns.md - - Detailed integration setup guides (React, Vue, Tailwind, MDX, etc.)
integration-guide.md - - NEW: Comprehensive testing strategies with Vitest, Playwright, and Container API
testing-guide.md - - NEW: Common mistakes and solutions for islands architecture, client directives, SSR vs static rendering
common-pitfalls.md - - NEW: Build optimization, image optimization, code splitting, deployment strategies
performance-optimization.md - - NEW: State management patterns for React islands (Zustand, Redux Toolkit, Jotai, TanStack Query)
state-management.md
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参考资料提供详细信息:
- - 常见Astro组件模式
component-patterns.md - - 详细的集成设置指南(React、Vue、Tailwind、MDX等)
integration-guide.md - - 新增:结合Vitest、Playwright和容器API的全面测试策略
testing-guide.md - - 新增:Islands架构、客户端指令、SSR与静态渲染的常见错误及解决方案
common-pitfalls.md - - 新增:构建优化、图片优化、代码分割、部署策略
performance-optimization.md - - 新增:React Islands的状态管理模式(Zustand、Redux Toolkit、Jotai、TanStack Query)
state-management.md
需要特定详细信息时加载参考资料:
设置测试基础设施时,阅读references/testing-guide.md
排查水合或指令问题时,阅读references/common-pitfalls.md
优化构建体积或加载速度时,阅读references/performance-optimization.md
实现跨Islands状态共享时,阅读references/state-management.mdassets/
assets/
Templates and boilerplate code:
- - Starting templates for different component types
component-templates/ - - Common layout patterns
layout-templates/ - - Page boilerplate for different use cases
page-templates/
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.
模板与样板代码:
- - 不同组件类型的起始模板
component-templates/ - - 常见布局模式
layout-templates/ - - 不同使用场景的页面样板
page-templates/
将资源作为起始点使用:
- 复制组件模板创建新组件
- 参考布局模板保持结构一致
- 调整页面模板适配常见页面类型
本技能提供从项目搭建到部署优化的全面Astro开发指导。