【免费下载链接】forge
forge是 Cloudflare 开源的 schema-first OpenAPI 工具框架,其中的astro-fern负责把 OpenAPI 规范转换成可直接部署的 API 文档站。本指南面向新手和普通用户,带你完整走一遍:如何用Astro + astro-fern从零搭建一个OpenAPI 驱动的 API 文档站,涵盖目录结构、核心配置、路由策略、AI Agent 友好输出(llms.txt),以及部署注意事项。
📌 先搞清楚:三个角色各管什么
理解分工是入门第一步:数据归astro-fern,展示归你的 Astro 应用。
| 角色 | 负责内容 |
|---|---|
astro-fern | OpenAPI 加载、快照、代码示例(snippets)、目录(catalog)、路由规划、Agent 文档 |
fern-forge | 通过扩展 API 校验 Forge 元数据、提供 SDK 投影 |
| 你的 Astro 应用 | HTML、导航、主题、代码渲染器、可见性策略、自定义 URL |
💡 一句话记忆:
astro-fern提供归一化的内容和懒加载服务端 API,你的应用只负责把它"画"出来。
🚀 快速上手:最小可用的 5 个核心文件
一个能跑起来的 astro-fern 文档站只需要 5 个文件:
| 文件 | 作用 |
|---|---|
astro.config.mjs | 注册集成、适配器、路由策略、Agent 选项 |
src/content.config.ts | 注册apiReference目录,提供内容策略 |
src/live.config.ts | 注册apiOperations实时集合 |
src/env.d.ts | 为Astro.locals补充类型 |
src/pages/api/[...slug].astro | 在配置的 Fern base 下渲染人类操作页面 |
⚠️ 集合名
apiReference与apiOperations是固定的,因为服务端 API 靠它们定位目录和操作工件。
1️⃣ 配置 Astro
在astro.config.mjs中引入astroFern集成(示例使用 Node 适配器):
// astro.config.mjs import node from '@astrojs/node'; import astroFern from 'astro-fern'; import { defineConfig } from 'astro/config'; export default defineConfig({ output: 'server', adapter: node({ mode: 'standalone' }), integrations: [ astroFern({ routing: { base: '/api', target: 'path' }, }), ], });生产环境请把SITE_URL设为公开部署源;本地开发时,集成会通过Astro.locals自动提供一个 artifact fetcher。
2️⃣ 注册内容(content.config)
在src/content.config.ts里声明产品(products)、目标(targets)和 OpenAPI 源:
// src/content.config.ts import { defineFernManifest, type FernContentOptions } from 'astro-fern'; import { defineFernCollections } from 'astro-fern/collections'; const manifest = defineFernManifest({ targets: [{ id: 'curl', kind: 'http', label: 'curl', language: 'bash' }], products: [ { id: 'dns', pathPrefixes: ['/zones'], sections: [{ id: 'records', tag: 'DNS Records', title: 'DNS records' }], }, ], }); export const collections = { ...defineFernCollections({ source: new URL('./openapi.json', import.meta.url), manifest, } satisfies FernContentOptions), };把带DNS Records标签的接口放进src/openapi.json,/zones下的操作就自动归到dns产品。
3️⃣ 注册操作加载器(live.config)
// src/live.config.ts import { defineLiveCollection } from 'astro:content'; import { fernOperationLiveLoader } from 'astro-fern/live'; export const collections = { apiOperations: defineLiveCollection({ loader: fernOperationLiveLoader(), }), };4️⃣ 补充本地类型
// src/env.d.ts /// <reference types="astro/client" /> /// <reference types="astro-fern/locals" />5️⃣ 渲染一个操作页
--- // src/pages/api/[...slug].astro import { getFernPageForPath } from 'astro-fern/server'; export const prerender = false; const fetcher = Astro.locals.fernArtifactFetcher; const resolved = await getFernPageForPath(Astro.url.pathname, { ...(fetcher ? { request: Astro.request, fetcher } : {}), }); if (!resolved) return new Response('Not found', { status: 404 }); const { page, target } = resolved; --- <main> <h1>{page.operation.title}</h1> <p>{page.operation.httpMethod} {page.operation.path}</p> <div set:html={page.operation.description.html} /> </main>🧩 关键坑:astro.config 与 content.config 的分工
新手最容易踩的坑是——这两个文件运行在不同的模块图里,职责不能混:
- 运行时路由选项(
routing、agents)→ 写在astro.config - OpenAPI 源和内容策略(
source、manifest、snippets)→ 写在content.config
真实的 Cloudflare 文档站就是把两者彻底分开维护的,可直接对照 packages/docs-site/astro.config.mjs 与 packages/docs-site/src/content.config.ts。
🗂️ 定义产品与区段(Manifest)
Manifest 为导航和路由提供稳定身份,核心是targets+products:
const manifest = defineFernManifest({ targets: [curlTarget], products: [ { id: 'dns', title: 'DNS', description: 'Manage DNS records and settings.', sdkGroup: 'dns', pathPrefixes: ['/zones'], sections: [ { id: 'records', tag: 'DNS Records', title: 'Records' }, { id: 'settings', tag: 'DNS Settings', title: 'Settings' }, ], }, ], });产品归属规则(按优先级):
- 带
sdkGroup的产品,接收第一段 SDK 组相等的操作(优先于pathPrefixes)。 - 不带
sdkGroup但有pathPrefixes的产品,用路径前缀匹配。 - 两者都没有的产品,可接收属于其任一 section 的操作。
- 当任意 OpenAPI tag精确匹配section 的
tag时,该 section 接收这个操作。 - 一个操作可属于多个产品,当且仅当所有匹配产品都声明了
sdkGroup。
📎 不想手写产品?
discoverProducts()能从 SDK 组首段推导产品 ID、从每个操作的首个 tag 推导 section,一步到位。
🎯 路由策略:hash 还是 path?
| 模式 | 路径示例 | 适用场景 |
|---|---|---|
| Hash(默认) | /api/dns/records/methods/list/#curl | target 是"交互式状态",一份文档服务所有 target |
| Path | /api/dns/curl/records/methods/list/ | 每个 target 都需要独立可索引的文档(利于 SEO) |
非默认快照会在产品后插入 slug,例如:
/api/dns/records/methods/list/ /api/dns/v1/records/methods/list/📌 选择建议:每个 target 都要被搜索引擎独立收录 → 用path;target 只是页内切换 → 用hash。
🤖 面向 AI Agent:Markdown 与 llms.txt
astro-fern 默认会注入纯 Markdown 操作文档和嵌套的llms.txt索引,让 LLM / AI 助手能高效读取你的 API 文档:
| 选项 | 默认 | 作用 |
|---|---|---|
agents.injectRoutes | true | 挂载配置的 agent 路由 |
agents.markdown | true | 为每个操作规划聚合 + 每 target 的 Markdown |
agents.llms | 全部作用域 | 规划 site / product / snapshot / target 索引 |
agents.directive | 默认指令 | 前置说明文字,设为false可省略 |
llms.txt各级作用域路径:
| 作用域 | 路径 | 内容 |
|---|---|---|
site | /llms.txt | 所有产品 |
product | /api/{product}/llms.txt | 默认快照中的产品 |
snapshot | /api/{product}/{slug}/llms.txt | 一个产品快照 |
target | /api/{product}/targets/{target}/llms.txt | 一个 target 的操作 |
💡 想在应用里自己控制挂载路径?把
agents.injectRoutes设为false,用getAgentRoutes()拿到所需路径即可。
📚 版本快照(Snapshots)
一个 snapshot 代表一个"被文档化的 API 状态"。单一 source 会创建一个隐式快照(id/slug=current,default: true)。需要多版本时,显式声明:
source: { kind: 'snapshots', snapshots: [ { id: 'v1', label: 'Version 1', slug: 'v1', source: new URL('./openapi.v1.json', import.meta.url) }, { id: 'v2', label: 'Version 2', slug: 'v2', default: true, source: new URL('./openapi.v2.json', import.meta.url) }, ], },每个快照有自己的 source、身份、label、slug、default标志和可选 target 覆盖。跨版本切换时,直接用内置的无样式组件:
--- import SnapshotSwitcher from 'astro-fern/components/SnapshotSwitcher.astro'; --- <SnapshotSwitcher label="API version" />它会在至少有一个可用快照时渲染锚点链接,没有适用快照时不渲染任何标记。
📦 部署要点(别漏了)
- 内容加载会把目录写入
public/_astro-fern/operations/与catalogs/,保留该路径并纳入部署静态资源。 - 用
.gitignore忽略public/_astro-fern/。 - 以 digest 命名的文件给一个长且不可变的缓存(如
Cache-Control: public, max-age=31536000, immutable)。 - 把
site设为可信公开源,或向页面加载辅助函数传origin。 - ⚠️不要把密钥放进 OpenAPI 字段、扩展数据或 snippet 渲染器输出——操作工件是公开可访问的。
🛠️ 本地运行参考
# 克隆仓库并安装依赖 git clone https://gitcode.com/gh_mirrors/forge55/forge cd forge pnpm install # 类型检查 / Lint / 单元测试 pnpm typecheck && pnpm check && pnpm test # 开发 / 构建文档站 pnpm --filter docs-site dev pnpm --filter docs-site build🔗 延伸阅读与关键源码
- 完整官方文档:packages/astro-fern/README.md
- 集成入口:packages/astro-fern/integration.ts
- Manifest 定义:packages/astro-fern/manifest.ts
- 内容集合:packages/astro-fern/collections.ts
- 实时加载器:packages/astro-fern/operation-live-loader.ts
- 服务端 API:packages/astro-fern/server.ts
- 真实文档站配置:packages/docs-site/astro.config.mjs
- 内容注册:packages/docs-site/src/content.config.ts
- 实时集合:packages/docs-site/src/live.config.ts
- 操作渲染页:packages/docs-site/src/pages/[product]/[...slug].astro
- Forge 扩展:packages/fern-forge/README.md
- 文档站说明:packages/docs-site/README.md
【免费下载链接】forge
相关推荐
在 Astro 站点中集成 Scalar API Reference:基于 OpenAPI/Swagger 的完整配置指南
在 Astro 站点中集成 Scalar API Reference:基于 OpenAPI/Swagger 的完整配置指南 本篇技术指南讲解如何在 Astro
开发工具API 工具前端Starlight:基于Astro构建现代化文档网站框架
Starlight:基于Astro构建现代化文档网站框架 Starlight是一个基于Astro框架构建的全功能文档网站框架,专为现代化技术文档需求而设计。它结
文档前端开发工具Docker Curriculum 的 Starlight 文档站:基于 Astro 的 Docker 教程站点构建与定制指南
Docker Curriculum 的 Starlight 文档站:基于 Astro 的 Docker 教程站点构建与定制指南 导读 本文围绕开源仓库 dock
云原生DevOps
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考