From 3a67ad0767da603a829c531b4eaff4cf1cdcb805 Mon Sep 17 00:00:00 2001 From: wehub-skill-sync Date: Mon, 13 Jul 2026 21:36:10 +0800 Subject: [PATCH] chore: import zh skill astro --- README.wehub.md | 9 ++ SKILL.md | 363 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 372 insertions(+) create mode 100644 README.wehub.md create mode 100644 SKILL.md diff --git a/README.wehub.md b/README.wehub.md new file mode 100644 index 0000000..1cc9800 --- /dev/null +++ b/README.wehub.md @@ -0,0 +1,9 @@ +# WeHub 来源说明 + +- Skill 名称:`astro` +- 中文类目:静态技术文档站搭建与部署 +- 上游仓库:`sickn33__antigravity-awesome-skills` +- 上游路径:`plugins/antigravity-awesome-skills-claude/skills/astro/SKILL.md` +- 上游链接:https://github.com/sickn33/antigravity-awesome-skills/blob/HEAD/plugins/antigravity-awesome-skills-claude/skills/astro/SKILL.md +- 本仓库为 WeHub 中文 Skill 汉化包,基于 skill 市场筛选 Top200 清单整理 +- 原作者、版权和许可证信息以上游仓库为准 diff --git a/SKILL.md b/SKILL.md new file mode 100644 index 0000000..de78d6e --- /dev/null +++ b/SKILL.md @@ -0,0 +1,363 @@ +--- +name: astro +description: "使用 Astro 构建以内容为中心的网站 —— 默认零 JavaScript、岛屿架构、多框架组件,支持 Markdown/MDX。" +category: frontend +risk: safe +source: community +date_added: "2026-03-18" +author: suhaibjanjua +tags: [astro, ssg, ssr, islands, content, markdown, mdx, performance] +tools: [claude, cursor, gemini] +--- + +# Astro Web 框架 + +## 概述 + +Astro 是一个专为内容密集型网站设计的 Web 框架 —— 博客、文档、作品集、营销站点和电子商务。其核心创新在于**岛屿架构**:默认情况下,Astro 不向浏览器发送任何 JavaScript。交互式组件会被选择性地水合为独立的"岛屿"。Astro 支持在同一项目中同时使用 React、Vue、Svelte、Solid 及其他 UI 框架,让你可以为每个组件选择最合适的工具。 + +## 何时使用本技能 + +- 当构建博客、文档站点、营销页面或作品集时使用 +- 当性能和 Core Web Vitals 是最高优先级时使用 +- 当项目包含大量 Markdown 或 MDX 文件时使用 +- 当用户询问 `.astro` 文件、`Astro.props`、内容集合或 `client:` 指令时使用 + +## 使用方法 + +### 第 1 步:项目设置 + +```bash +npm create astro@latest my-site +cd my-site +npm install +npm run dev +``` + +按需添加集成: + +```bash +npx astro add tailwind # Tailwind CSS +npx astro add react # React 组件支持 +npx astro add mdx # MDX 支持 +npx astro add sitemap # 自动生成 sitemap.xml +npx astro add vercel # Vercel SSR 适配器 +``` + +项目结构: + +``` +src/ + pages/ ← 基于文件的路由(.astro、.md、.mdx) + layouts/ ← 可复用的页面外壳 + components/ ← UI 组件(.astro、.tsx、.vue 等) + content/ ← 类型安全的内容集合(Markdown/MDX) + styles/ ← 全局 CSS +public/ ← 静态资源(原样复制) +astro.config.mjs ← 框架配置 +``` + +### 第 2 步:Astro 组件语法 + +`.astro` 文件顶部有一个代码围栏(仅服务端运行),下方是模板: + +```astro +--- +// src/components/Card.astro +// 此代码块仅在服务端运行 —— 绝不在浏览器中执行 +interface Props { + title: string; + href: string; + description: string; +} + +const { title, href, description } = Astro.props; +--- + +
+

{title}

+

{description}

+
+ + +``` + +### 第 3 步:基于文件的页面与路由 + +``` +src/pages/index.astro → / +src/pages/about.astro → /about +src/pages/blog/[slug].astro → /blog/:slug(动态路由) +src/pages/blog/[...path].astro → /blog/*(通配路由) +``` + +带 `getStaticPaths` 的动态路由: + +```astro +--- +// src/pages/blog/[slug].astro +export async function getStaticPaths() { + const posts = await getCollection('blog'); + return posts.map(post => ({ + params: { slug: post.slug }, + props: { post }, + })); +} + +const { post } = Astro.props; +const { Content } = await post.render(); +--- + +

{post.data.title}

+ +``` + +### 第 4 步:内容集合 + +内容集合让你可以对 Markdown 和 MDX 文件进行类型安全访问: + +```typescript +// src/content/config.ts +import { z, defineCollection } from 'astro:content'; + +const blog = defineCollection({ + type: 'content', + schema: z.object({ + title: z.string(), + date: z.coerce.date(), + tags: z.array(z.string()).default([]), + draft: z.boolean().default(false), + }), +}); + +export const collections = { blog }; +``` + +```astro +--- +// src/pages/blog/index.astro +import { getCollection } from 'astro:content'; + +const posts = (await getCollection('blog')) + .filter(p => !p.data.draft) + .sort((a, b) => b.data.date.valueOf() - a.data.date.valueOf()); +--- + + +``` + +### 第 5 步:岛屿 —— 选择性水合 + +默认情况下,UI 框架组件会渲染为不含 JavaScript 的静态 HTML。使用 `client:` 指令进行水合: + +```astro +--- +import Counter from '../components/Counter.tsx'; // React 组件 +import VideoPlayer from '../components/VideoPlayer.svelte'; +--- + + + + + + + + + + + + + + + +``` + +### 第 6 步:布局 + +```astro +--- +// src/layouts/BaseLayout.astro +interface Props { + title: string; + description?: string; +} +const { title, description = '我的 Astro 站点' } = Astro.props; +--- + + + + + {title} + + + + +
+ +
+
...
+ + +``` + +```astro +--- +// src/pages/about.astro +import BaseLayout from '../layouts/BaseLayout.astro'; +--- + + +

关于我们

+

欢迎来到我们的公司...

+
+``` + +### 第 7 步:SSR 模式(按需渲染) + +通过设置适配器启用 SSR,以支持动态页面: + +```javascript +// astro.config.mjs +import { defineConfig } from 'astro/config'; +import vercel from '@astrojs/vercel/serverless'; + +export default defineConfig({ + output: 'hybrid', // 'static' | 'server' | 'hybrid' + adapter: vercel(), +}); +``` + +使用 `export const prerender = false` 将单个页面切换为 SSR 模式。 + +## 示例 + +### 示例 1:带 RSS 订阅的博客 + +```typescript +// 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: '我的博客', + description: '最新文章', + site: context.site, + items: posts.map(post => ({ + title: post.data.title, + pubDate: post.data.date, + link: `/blog/${post.slug}/`, + })), + }); +} +``` + +### 示例 2:API 端点(SSR) + +```typescript +// src/pages/api/subscribe.ts +import type { APIRoute } from 'astro'; + +export const POST: APIRoute = async ({ request }) => { + const { email } = await request.json(); + + if (!email) { + return new Response(JSON.stringify({ error: '需要提供邮箱' }), { + status: 400, + headers: { 'Content-Type': 'application/json' }, + }); + } + + await addToNewsletter(email); + return new Response(JSON.stringify({ success: true }), { status: 200 }); +}; +``` + +### 示例 3:React 组件作为岛屿 + +```tsx +// src/components/SearchBox.tsx +import { useState } from 'react'; + +export default function SearchBox() { + const [query, setQuery] = useState(''); + const [results, setResults] = useState([]); + + async function search(e: React.FormEvent) { + e.preventDefault(); + const data = await fetch(`/api/search?q=${query}`).then(r => r.json()); + setResults(data); + } + + return ( +
+ setQuery(e.target.value)} /> + +
    {results.map(r =>
  • {r.title}
  • )}
+
+ ); +} +``` + +```astro +--- +import SearchBox from '../components/SearchBox.tsx'; +--- + + +``` + +## 最佳实践 + +- ✅ 尽可能将大多数组件保留为静态 `.astro` 文件 —— 仅对必须交互的部分进行水合 +- ✅ 对所有 Markdown/MDX 内容使用内容集合 —— 可获得类型安全和自动校验 +- ✅ 对首屏以下的组件优先使用 `client:visible` 而非 `client:load`,以减少初始 JavaScript 体积 +- ✅ 使用 `import.meta.env` 管理环境变量 —— 公开变量以 `PUBLIC_` 为前缀 +- ✅ 使用 `astro:transitions` 中的 `` 实现流畅的页面导航,无需完整的 SPA +- ❌ 不要在每个组件上都使用 `client:load` —— 这会抵消 Astro 的性能优势 +- ❌ 不要在面向客户端的模板中使用的 `.astro` 文件围栏中放入密钥 +- ❌ 在静态模式下不要跳过动态路由的 `getStaticPaths` —— 否则构建将失败 + +## 安全注意事项 + +- `.astro` 文件中的围栏代码仅在服务端运行,绝不会暴露给浏览器。 +- 仅对非敏感值使用 `import.meta.env.PUBLIC_*`。私有环境变量(无 `PUBLIC_` 前缀)绝不会发送给客户端。 +- 使用 SSR 模式时,在数据库查询或 API 调用之前验证所有 `Astro.request` 输入。 +- 使用 `set:html` 渲染用户提供的内容前必须先进行转义处理 —— 它会绕过自动转义。 + +## 常见陷阱 + +- **问题:** React/Vue 组件的 JavaScript 在浏览器中不运行 + **解决方法:** 添加 `client:` 指令(`client:load`、`client:visible` 等)—— 不加指令时,组件仅渲染为静态 HTML。 + +- **问题:** 开发过程中内容更新后 `getStaticPaths` 的数据未更新 + **解决方法:** Astro 的开发服务器会监听内容文件 —— 如果对 `content/config.ts` 的修改未生效,请重启服务器。 + +- **问题:** `Astro.props` 的类型为 `any` —— 无自动补全 + **解决方法:** 在围栏中定义 `Props` 接口或类型,Astro 会自动推断类型。 + +- **问题:** `.astro` 组件中的 CSS 泄漏到其他组件中 + **解决方法:** `.astro` 的 `