mcpField
A
astro

astro

github.com/sickn33开发49.4k113 次安装3 天前更新
代码仓库

关于 astro

Astro 是用于构建博客、文档和作品集等内容型网站的 Web 框架技能。它涵盖文件路由、内容集合,以及仅为交互组件选择性注水,让大多数页面保持静态。

主要功能

  1. 01基于文件的页面路由
  2. 02类型化 Markdown 和 MDX 内容集合
  3. 03选择性注水组件
  4. 04支持多种 UI 框架
  5. 05静态输出及可选 SSR

适用场景

  1. 01构建文档或博客网站
  2. 02制作内容型营销页面
  3. 03为静态页面添加选择性交互

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/sickn33/agentic-awesome-skills --skill astro

安装后在 Claude Code 中输入/astro确认已加载。

详细介绍

Astro Web Framework

概述

Astro 是一个专为内容丰富的网站设计的 Web 框架,适用于博客、文档、作品集、营销网站和电子商务网站。它的核心创新是群岛架构:默认情况下,Astro 不会向浏览器发送任何 JavaScript。交互组件会作为相互隔离的“岛屿”按需进行水合。Astro 支持在同一项目中同时使用 React、Vue、Svelte、Solid 和其他 UI 框架,让你能为每个组件选择合适的工具。

何时使用此技能

  • 用于构建博客、文档网站、营销页面或作品集
  • 用于将性能和 Core Web Vitals 作为首要目标
  • 用于使用 Markdown 或 MDX 文件构建以内容为主的项目
  • 用于希望生成 SSG(静态)输出,并可为动态路由选择性启用 SSR
  • 用于用户询问 .astro 文件、Astro.props、内容集合或 client: 指令时

工作原理

步骤 1:项目设置
npm create astro@latest my-site
cd my-site
npm install
npm run dev

按需添加集成:

npx astro add tailwind        # Tailwind CSS
npx astro add react           # React component support
npx astro add mdx             # MDX support
npx astro add sitemap         # Auto sitemap.xml
npx astro add vercel          # Vercel SSR adapter

项目结构:

src/
  pages/          ← File-based routing (.astro, .md, .mdx)
  layouts/        ← Reusable page shells
  components/     ← UI components (.astro, .tsx, .vue, etc.)
  content/        ← Type-safe content collections (Markdown/MDX)
  styles/         ← Global CSS
public/           ← Static assets (copied as-is)
astro.config.mjs  ← Framework config
步骤 2:Astro 组件语法

.astro 文件顶部有一个代码围栏(仅在服务端运行),下方是模板:

---
// src/components/Card.astro
// This block runs on the server ONLY — never in the browser
interface Props {
  title: string;
  href: string;
  description: string;
}

const { title, href, description } = Astro.props;
---

<article class="card">
  <h2><a href={href}>{title}</a></h2>
  <p>{description}</p>
</article>

<style>
  /* Scoped to this component automatically */
  .card { border: 1px solid #eee; padding: 1rem; }
</style>
步骤 3:基于文件的页面和路由
src/pages/index.astro          → /
src/pages/about.astro          → /about
src/pages/blog/[slug].astro    → /blog/:slug (dynamic)
src/pages/blog/[...path].astro → /blog/* (catch-all)

使用 getStaticPaths 的动态路由:

---
// 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();
---

<h1>{post.data.title}</h1>
<Content />

步骤 3–4 和 RSS 中的内容集合示例使用的是 Astro 5 之前的旧版内容 API(src/content/config.ts、post.slug、post.render())。不要在新项目中未经修改就照搬这些示例:请根据已安装的主版本选择对应 API,按需迁移到内容加载器并使用 render(),同时在动态页面中导入 getCollection。Tailwind 集成的设置也取决于其主版本。请参阅 Astro 5 迁移指南。

步骤 4:内容集合

内容集合可让你以类型安全的方式访问 Markdown 和 MDX 文件:

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

<ul>
  {posts.map(post => (
    <li>
      <a href={`/blog/${post.slug}`}>{post.data.title}</a>
      <time>{post.data.date.toLocaleDateString()}</time>
    </li>
  ))}
</ul>
步骤 5:群岛——选择性水合

默认情况下,UI 框架组件会渲染为不含 JS 的静态 HTML。使用 client: 指令进行水合:

---
import Counter from '../components/Counter.tsx';  // React component
import VideoPlayer from '../components/VideoPlayer.svelte';
---


<Counter initialCount={0} />


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


<VideoPlayer src="/demo.mp4" client:visible />


<Analytics client:idle />


<MobileMenu client:media="(max-width: 768px)" />
步骤 6:布局
---
// src/layouts/BaseLayout.astro
interface Props {
  title: string;
  description?: string;
}
const { title, description = 'My Astro Site' } = Astro.props;
---

<html lang="en">
  <head>
    <meta charset="utf-8" />
    <title>{title}</title>
    <meta name="description" content={description} />
  </head>
  <body>
    <nav>...</nav>
    <main>
      <slot />  
    </main>
    <footer>...</footer>
  </body>
</html>
---
// src/pages/about.astro
import BaseLayout from '../layouts/BaseLayout.astro';
---

<BaseLayout title="About Us">
  <h1>About Us</h1>
  <p>Welcome to our company...</p>
</BaseLayout>
步骤 7:SSR 模式(按需渲染)

通过设置适配器启用动态页面的 SSR:

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

export default defineConfig({
  output: 'static',  // Astro 5+: prerender by default, opt routes out below
  adapter: vercel(),
});

使用 export const prerender = false 为单个页面启用 SSR。

示例

示例 1:带 RSS 订阅源的博客
// 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 Blog',
    description: 'Latest posts',
    site: context.site,
    items: posts.map(post => ({
      title: post.data.title,
      pubDate: post.data.date,
      link: `/blog/${post.slug}/`,
    })),
  });
}

订阅处理器只是一个不完整的应用示例:请定义 addToNewsletter,在静态模式下将此路由设为不预渲染,限制并验证 JSON 和电子邮件输入,处理下游错误,并在公开此功能前,添加适合部署环境的授权、滥用防护和 CSRF 防护。

示例 2:API 端点(SSR)
// 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: 'Email required' }), {
      status: 400,
      headers: { 'Content-Type': 'application/json' },
    });
  }

  await addToNewsletter(email);
  return new Response(JSON.stringify({ success: true }), { status: 200 });
};
示例 3:作为岛屿的 React 组件
// src/components/SearchBox.tsx
import { useState } from 'react';

export default function SearchBox() {
  const [query, setQuery] = useState('');
  const [results, setResults] = useState<Array<{ id: string; title: string }>>([]);

  async function search(e: React.FormEvent) {
    e.preventDefault();
    const data = await fetch(`/api/search?q=${encodeURIComponent(query)}`).then(r => {
      if (!r.ok) throw new Error(`Search failed: ${r.status}`);
      return r.json();
    });
    setResults(data);
  }

  return (
    <form onSubmit={search}>
      <input value={query} onChange={e => setQuery(e.target.value)} />
      <button type="submit">Search</button>
      <ul>{results.map(r => <li key={r.id}>{r.title}</li>)}</ul>
    </form>
  );
}
---
import SearchBox from '../components/SearchBox.tsx';
---

<SearchBox client:load />

最佳实践

  • ✅ 大多数组件都保持为静态 .astro 文件——只对必须交互的组件进行水合
  • ✅ 所有 Markdown/MDX 内容都使用内容集合——这样可以获得类型安全和自动验证
  • ✅ 对首屏以下的组件,优先使用 client:visible 而非 client:load,以减少初始 JS
  • ✅ 使用 import.meta.env 获取环境变量——为公开变量添加 PUBLIC_ 前缀
  • ✅ 添加来自 astro:transitions 的 <ClientRouter />,无需构建完整的 SPA 即可实现流畅的页面导航
  • ❌ 不要为每个组件都使用 client:load——这会削弱 Astro 的性能优势
  • ❌ 不要将机密放在 .astro frontmatter 中,尤其是这些内容会用于面向客户端的模板时
  • ❌ 静态模式下,动态路由不要省略 getStaticPaths——否则构建会失败

安全与注意事项

  • Frontmatter 会在构建时或服务器上执行,但插入 HTML、props 或脚本中的值会暴露给浏览器。不要将机密放入渲染输出中。
  • 仅将 import.meta.env.PUBLIC_* 用于非敏感值。私有环境变量不会自动暴露给客户端模块,但将其值插入渲染输出仍会泄露。
  • 使用 SSR 模式时,在执行数据库查询或 API 调用前,验证所有 Astro.request 输入。
  • 使用 set:html 渲染用户提供的内容前,请对其进行清理——它会绕过自动转义。

常见问题

  • 问题: React/Vue 组件中的 JavaScript 未在浏览器中运行 解决方案: 添加 client: 指令(client:load、client:visible 等)——否则组件只会渲染为静态 HTML。

  • 问题: 开发期间内容更新后,getStaticPaths 数据仍然过时 解决方案: Astro 的开发服务器会监视内容文件——如果对 content/config.ts 的更改未生效,请重启服务器。

  • 问题: Astro.props 的类型是 any——没有自动补全 解决方案: 在 frontmatter 中定义 Props 接口或类型,Astro 会自动推断类型。

  • 问题: .astro 组件中的 CSS 影响了其他组件 解决方案: .astro <style> 标签中的样式会自动限定作用域。仅在有意为子元素设置样式时使用 :global()。

相关技能

  • @sveltekit — 需要具有响应式 UI 的全栈框架时使用(相较于 Astro 对内容的侧重)
  • @nextjs-app-router-patterns — 需要以 React 为核心的全栈框架时使用
  • @tailwind-patterns — 使用 Tailwind CSS 为 Astro 网站设置样式
  • @progressive-web-app — 为 Astro 网站添加 PWA 功能

限制

  • 仅当任务明确符合上述范围时,才使用此技能。
  • 不要将输出视为环境特定验证、测试或专家审查的替代品。
  • 如果缺少必需的输入、权限、安全边界或成功标准,请暂停并要求澄清。

评论

支持 Markdown