Communitygithub.com

farulwananda/skills

在构建、审查或重构 Astro 组件、内容驱动型网站、静态页面或按需路由时使用。涵盖渲染边界、精简浏览器脚本、类型化属性、版本感知的内容集合、本地化路由、元数据和资源。

skills 是什么?

这是一个针对 Astro 框架的专业 AI 代理技能,专为组件开发、内容集合管理、路由配置和渲染策略优化而设计。它适用于各类 AI 代码助手(如 Claude Code 或 Cursor),帮助开发者遵循 Astro 最佳实践,避免常见错误。该技能强调根据项目配置(package.json、Astro 版本、适配器)做出决策,优先使用语义化 HTML 和原生 `<script>` 处理浏览器行为,而非引入不必要的框架。它提供完整的代码示例(如 `Card.astro`、`Counter.astro`、内容集合配置),并指导开发者在静态生成(SSG)与服务器端渲染(SSR)之间做出正确选择,同时确保国际化、规范 URL 和资产处理的正确性。该技能不支持自动安装集成或触发远程服务,所有操作均需显式授权。

兼容平台~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/farulwananda/skills/tree/HEAD/fw-writing-astro

在你喜欢的 AI 中提问

打开一个已预加载此 Agent Skill 的新对话。

文档

FW Writing Astro

范围与首要决策

此技能用于 Astro 特定的组件、路由、内容、渲染和集成。请勿用它来规定 React 内部机制、后端架构或部署提供商;仅在需要时才配对相关的框架/运行时技能。

在编辑之前,检查 package.json、锁文件、Astro 和适配器版本、astro.config.*、tsconfig、现有路由/布局/内容配置以及仓库脚本。遵循已安装版本的文档和现有约定。未经授权,不得安装集成、升级依赖、部署或调用付费服务。

  • 对于可以预先构建的内容,优先使用预渲染 HTML。Frontmatter 在构建时对预渲染路由执行,在按需路由上则在服务器端执行;它不是浏览器代码。
  • 对于实际请求时需要的功能(例如经过身份验证的内容或新鲜数据),使用 SSR。这需要一个兼容的适配器。在支持当前模型的版本中,默认静态输出可以通过 export const prerender = false 将个别路由选择为 SSR;output: 'server' 使 SSR 成为默认值,并允许 prerender = true 例外。旧版本有不同的混合配置:迁移前请检查。
  • 完全静态的网站通常不需要适配器。不要将 Astro 与 Cloudflare 等同起来,也不要把 SSR 强加给静态内容。
  • 保持可访问性、转义和信任边界。不要使用 set:html 插入不受信任的 HTML;在其实际的输入边界处对受信任格式的渲染进行清理。

原生组件和有效属性

使用 .astro 组件进行布局和静态内容。当组件接受属性时声明 Props;没有属性的页面不需要仪式性的接口。使用实际元素的属性,有意地转发属性,并避免使用具有不兼容属性集的多态标签。链接卡片可以使用文章内的链接,而不是将 href 发送给 article。不要将交互式控件嵌套在包装锚点内。

ASTRO-CARD — 完整的 src/components/Card.astro;不需要 CSS 库:

---
import type { HTMLAttributes } from 'astro/types';

interface Props extends Omit<HTMLAttributes<'article'>, 'title'> {
  title: string;
  description?: string;
  href?: string;
}

const { title, description, href, class: className, ...rest } = Astro.props;
---

<article {...rest} class:list={['card', className]}>
  <h2>{href ? <a href={href}>{title}</a> : title}</h2>
  {description && <p>{description}</p>}
  <slot />
</article>

使用具名插槽定义明确的内容区域,使用 class:list 实现条件类。分别验证不受信任的链接目标;字符串类型不是 URL 验证。

在框架岛屿之前使用小型浏览器行为

首先使用语义化 HTML(details、原生表单),然后在需要浏览器行为时使用一个小型处理的 <script>。不要仅仅为了切换菜单就添加 React/Vue/Svelte。Astro 脚本会被打包/去重;选择所有组件实例或使用作用域化的自定义元素。对于客户端导航,遵循已安装路由器的生命周期,并避免重复的监听器。Frontmatter 值不会自动在浏览器脚本中可用;仅通过显式的 DOM 属性或 props 传递非秘密数据。

ASTRO-BUTTON — 完整的 src/components/Counter.astro,用于普通的全页导航:

<button type="button" data-counter aria-label="增加计数">0</button>
<script>
  document.querySelectorAll<HTMLButtonElement>('button[data-counter]').forEach((button) => {
    let count = 0;
    button.addEventListener('click', () => {
      button.textContent = String(++count);
    });
  });
</script>

当现有的框架组件或大量的交互状态证明其合理性,并且已经安装了相应的集成时,才使用框架岛屿。对于立即需要的行为选择 client:load,对于非关键行为选择 client:idle,对于屏幕外内容选择 client:visible,对于实际的媒体相关需求选择 client:media。没有 client:* 指令的组件会渲染 HTML 而不进行框架水合。client:only 会跳过服务器渲染,并且需要有意的加载/回退体验,而不是作为万能的变通方法。

内容集合遵循已安装的版本

对重复的结构化内容使用集合,而不是对每个孤立的页面都使用。在编辑前检查现有配置和条目标识符:

  • Astro 5 引入了 Content Layer 加载器模型,通常位于 src/content.config.ts。旧项目可能使用 src/content/config.ts 和 type: 'content' 而不是加载器。这些文件位置/API 不可互换。
  • 检查已安装的 Zod 导出。以下示例针对 Astro 5 从 astro:content 导出的 z;当前文档使用 astro/zod。不要机械地替换一个缺乏该模块的版本中的导入。
  • 加载器条目使用 id;不要假定使用旧的 slug 或 entry.render() API。对于 Content Layer 渲染,使用支持的 render(entry) 辅助函数。如果包含 MDX 文件,则需要 MDX 集成。

ASTRO-COLLECTION-V5 — 完整的 src/content.config.ts,用于 Astro 5 与本地 Markdown 条目:

import { defineCollection, z } from 'astro:content';
import { glob } from 'astro/loaders';

const blog = defineCollection({
  loader: glob({ pattern: '**/*.md', base: './src/content/blog' }),
  schema: z.object({
    title: z.string(),
    description: z.string(),
    pubDate: z.coerce.date(),
    updatedDate: z.coerce.date().optional(),
    tags: z.array(z.string()).default([]),
    draft: z.boolean().default(false),
  }),
});

export const collections = { blog };

ASTRO-COLLECTION-LIST — 完整的页面 src/pages/blog/index.astro,与上述集合配对,并且至少有一个符合 schema 的 Markdown 条目:

---
import { getCollection } from 'astro:content';
const posts = await getCollection('blog', ({ data }) => !import.meta.env.PROD || !data.draft);
posts.sort((a, b) => b.data.pubDate.valueOf() - a.data.pubDate.valueOf());
---
<h1>博客</h1>
<ul>{posts.map((post) => <li>{post.data.title}</li>)}</ul>

此列表故意不虚构详情页 URL。如果添加链接,请实现匹配的动态路由和用于预渲染页面的 getStaticPaths()。在详情路由和列表页都检查草稿状态;只过滤索引不是访问控制。请求时的私有内容不得通过构建输出或公共缓存泄露。

语言、规范 URL 与 404 一致性

在更改路由之前确定 URL 策略:配置的生产环境 site、部署 base、尾部斜杠/构建格式、语言前缀、根行为以及回退行为必须与实际文件和主机重定向保持一致。

  • 使用基于文件夹的路由。当 prefixDefaultLocale: false 时,默认语言的页面位于根目录;其他语言则拥有文件夹。当为 true 时,所有语言都有语言文件夹,根索引仍需有意的处理。
  • 在有用时使用版本支持的 astro:i18n 辅助函数。配置不会翻译内容或创建缺失的页面。仅链接现有的翻译;切换语言时保留有意义的等效路径。
  • 规范 URL 应使用生产环境源和选定的规范路径名,而不是来自 Astro.url.href 的任意请求主机/查询参数。为部署设置 site;考虑 base 和尾部斜杠规范化。为文档设置 lang,并仅为具有互惠链接的真实等效页面发出 hreflang 替代项。不要将所有语言的规范 URL 都设为英文。
  • 当需要自定义错误页面时,实现 src/pages/404.astro。在 SSR 路径上返回真正的 404 状态,而不是成功的错误体。在静态托管上,验证生成的 404 文件以状态 404 提供。不要对多页面网站使用 SPA 回退,也不要将每个缺失的语言路径都重定向到首页。避免索引错误页面,并且不要为每个缺失的 URL 提供自引用规范 URL。

ASTRO-CANONICAL-FRAGMENT — 部分布局示例,不是独立页面。假设已配置 site,并且当前路径名已符合仓库的 base/locale/slash 策略:

---
if (!Astro.site) throw new Error('配置生产环境站点 URL');
const canonical = new URL(Astro.url.pathname, Astro.site);
---
<link rel="canonical" href={canonical} />

资产与部署边界

对于需要处理的图像,优先使用 src/assets/ 和来自 astro:assets 的 Image。将需要不变 URL、robots.txt 和图标等资源保留在 public/ 中;对于有意直通/远程的情况,普通的 <img> 也是有效的。提供有意义的 alt(装饰性图像则为空)以及固有的尺寸或等效的布局约束。将响应式图像 API 与已安装版本匹配,避免急切加载每个图像;仅优先加载真正在首屏之上的关键图像。在启用 SSR 图像服务之前,检查其运行时/成本要求。

仅在需要时使用现有主机的标头/重定向机制。_headers 和 _redirects 是特定于提供商的,不是通用的 Astro 要求。对于适配器 SSR,遵循该适配器版本的生成输出和运行时绑定约定,而不是手写的通用静态/SPA 配置。

验证与报告

在授权后,使用仓库现有的 check/build/test 脚本。检查属性类型、发出的路由、集合验证、草稿详情页暴露、语言切换链接、规范 URL 源/查询移除、base/slash 行为、未知路由状态、键盘行为以及浏览器控制台错误。成功的静态构建不能证明 SSR 运行时兼容性或生产重定向的正确性。报告实际运行的命令、版本假设、缺失的集成/内容夹具以及未验证的托管行为。不要将安装、部署或触发远程服务作为隐式验证步骤。

来源与出处

这是作者的整合,并非第三方技能的大规模复制。仅阅读与任务和已安装版本相关的文档:

相关技能