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 运行时兼容性或生产重定向的正确性。报告实际运行的命令、版本假设、缺失的集成/内容夹具以及未验证的托管行为。不要将安装、部署或触发远程服务作为隐式验证步骤。
来源与出处
这是作者的整合,并非第三方技能的大规模复制。仅阅读与任务和已安装版本相关的文档:
- 官方 Astro:组件与属性、浏览器脚本、按需渲染。
- 官方 Astro:内容集合、Astro 5 迁移、国际化路由、Cloudflare 适配器。
- astrolicious/agent-skills 是一个社区参考,并非官方 Astro 文档或兼容性保证。有选择地参考它;官方的版本匹配 API 文档优先。