EmDash 站点开发速查:解读 do-solo-demo 的 AGENTS.md(命令、关键文件与 CMS 开发规则)
EmDash 站点开发速查解读 do-solo-demo 的 AGENTS.md命令、关键文件与 CMS 开发规则【免费下载链接】emdashEmDash is a full-stack TypeScript CMS based on Astro; the spiritual successor to WordPress项目地址: https://gitcode.com/gh_mirrors/emdas/emdashEmDash 是基于 Astro 构建的全栈 TypeScript CMS自带完整的管理后台官方将其定位为 WordPress 的精神继承者。本指南以仓库内 infra/do-solo-demo/AGENTS.md 为核心骨架逐条展开其中的命令、关键文件与开发规则并结合do-solo-demo站点的真实源码astro.config.mjs、seed/seed.json、src/pages/等与emdash-cms/cloudflare的数据库实现进行深度印证。读完本文你将能够独立读懂任意 EmDash 站点工程的目录结构掌握内容查询、种子数据导入、类型生成与部署的完整流程并理解站点开发中必须遵守的五条核心规则及其底层原因。一、AGENTS.md 是什么站点自述文件infra/do-solo-demo/AGENTS.md是一份面向 Agent以及任何人类协作者的站点自述文件。它开篇即点明This is an EmDash site -- a CMS built on Astro with a full admin UI.这句话定义了整个工程的性质它不是普通 Astro 静态站而是运行在 Astro 之上、以数据库为内容源、带完整可视化后台的 CMS 站点。AGENTS.md 的价值在于把「开始干活需要知道的一切」压缩进一份文件包括常用命令、关键文件职责表、可加载的技能清单、以及必须遵守的开发规则。do-solo-demo是仓库中面向单主 Durable Objectsingle-primary DO基准测试的最小演示站点其工程布局也是所有 EmDash 站点的标准样板。二、命令速查从开发到部署AGENTS.md 给出了三条核心命令全部可以直接在infra/do-solo-demo目录下执行pnpm dev # Start the Astro dev server npx emdash types # Regenerate TypeScript types from a running site npx emdash seed seed/seed.json --validate # Validate seed filepnpm dev启动 Astro 开发服务器。项目使用 pnpm workspace见根目录 pnpm-workspace.yamlpackage.json中对应脚本为dev: astro dev。开发服务器启动时会自动重新生成类型文件emdash-env.d.ts。npx emdash types从「正在运行」的站点重新生成 TypeScript 类型。也就是说类型生成依赖本地 dev server 提供的 schema 信息内容集合有变更后执行此命令即可让编辑器获得最新的类型提示。npx emdash seed seed/seed.json --validate仅校验种子文件而不导入。校验通过后再去掉--validate执行完整导入。除了 AGENTS.md 列出的三条infra/do-solo-demo/package.json 中还定义了完整的生命周期脚本可作为日常开发的补充{ scripts: { dev: astro dev, build: astro build, preview: astro preview, deploy: astro build wrangler deploy, typecheck: astro check, bootstrap: emdash init emdash seed, seed: emdash seed } }bootstrap新环境初始化的一键命令先执行emdash init生成/补齐站点骨架再emdash seed导入种子内容。deploy先构建再通过 Wrangler 部署到 Cloudflare该站点使用astrojs/cloudflare适配器。typecheck基于astro check做全量类型检查。管理后台入口开发模式下管理后台位于http://localhost:4321/_emdash/admin所有 EmDash 站点的后台都挂载在/_emdash/admin路径下。登录后可以管理内容、媒体、菜单、组件等资源站点的src/layouts/Base.astro中还会在检测到登录态Astro.locals.user时自动显示 Admin 入口链接。三、关键文件职责一张表读懂整个工程AGENTS.md 用一张表格概括了工程中每个关键文件的作用原文如下FilePurposeastro.config.mjsAstro config withemdash()integration, database, and storagesrc/live.config.tsEmDash loader registration (boilerplate -- dont modify)seed/seed.jsonSchema definition demo content (collections, fields, taxonomies, menus, widgets)emdash-env.d.tsGenerated types for collections (auto-regenerated on dev server start)src/layouts/Base.astroBase layout with EmDash wiring (menus, search, page contributions)src/pages/Astro pages -- all server-rendered下面按「配置 → 内容模型 → 类型 → 布局 → 页面」的顺序逐一深入。3.1 astro.config.mjsemdash()集成与数据后端infra/do-solo-demo/astro.config.mjs 是站点的心脏。它把 Astro、Cloudflare 适配器与 EmDash 集成绑定在一起import cloudflare from astrojs/cloudflare; import react from astrojs/react; import { durableObjects, r2, sandbox } from emdash-cms/cloudflare; import { formsPlugin } from emdash-cms/plugin-forms; import webhookNotifier from emdash-cms/plugin-webhook-notifier; import { defineConfig, fontProviders } from astro/config; import emdash from emdash/astro; export default defineConfig({ output: server, adapter: cloudflare(), image: { layout: constrained, responsiveStyles: true, }, integrations: [ react(), emdash({ database: durableObjects({ binding: DB_DO, session: auto }), storage: r2({ binding: MEDIA }), plugins: [formsPlugin()], sandboxed: [webhookNotifier], sandboxRunner: sandbox(), experimental: { registry: https://registry.emdashcms.com, }, }), ], fonts: [ { provider: fontProviders.google(), name: Inter, cssVariable: --font-sans, weights: [400, 500, 600, 700], fallbacks: [sans-serif], }, { provider: fontProviders.google(), name: JetBrains Mono, cssVariable: --font-mono, weights: [400, 500], fallbacks: [monospace], }, ], devToolbar: { enabled: false }, });emdash()集成接收的关键配置项database: durableObjects({ binding: DB_DO, session: auto })内容数据库。do-solo-demo使用 Durable Object 承载 SQLitebinding 名DB_DODO class 为EmDashDBsession: auto表示会话自动管理。这是该演示站点命名为 do-solo 的原因——它刻意不配置读副本路由用于把「DO/RPC 架构本身的开销」与「读副本路由的开销」隔离开见 infra/do-solo-demo/wrangler.jsonc 中的注释。storage: r2({ binding: MEDIA })媒体存储绑定 R2 桶emdash-demo-mediabinding 名MEDIA。plugins: [formsPlugin()]启用官方表单插件emdash-cms/plugin-forms。sandboxed: [webhookNotifier]与sandboxRunner: sandbox()以沙箱方式运行 Webhook 通知插件插件代码在受控沙箱内执行。experimental.registry指向远程插件市场注册表。配置底部通过fonts声明了两套 Google 字体Inter 与 JetBrains Mono并输出为 CSS 变量--font-sans/--font-mono站点样式如 src/layouts/Base.astro 中的var(--font-sans)直接消费这些变量。3.2 src/live.config.tsLoader 注册样板勿改infra/do-solo-demo/src/live.config.ts 是 EmDash 的 Live Content Collections 注册点AGENTS.md 明确标注为 boilerplate -- dont modifyimport { defineLiveCollection } from astro:content; import { emdashLoader } from emdash/runtime; export const collections { _emdash: defineLiveCollection({ loader: emdashLoader() }), };它把数据库中的全部内容类型统一挂到_emdash这个集合下运行时通过getEmDashCollection()/getEmDashEntry()按具体类型查询。开发者日常不需要修改此文件。3.3 seed/seed.jsonSchema 定义 演示内容infra/do-solo-demo/seed/seed.json 是 EmDash 站点内容模型与演示数据的一站式定义文件AGENTS.md 将其职责概括为 Schema definition demo content (collections, fields, taxonomies, menus, widgets)。其顶层结构包含七个部分全部出现在实际文件中collections内容集合与字段collections定义内容类型。do-solo-demo定义了两个集合posts文章与pages页面每个集合包含slug、label、labelSingular、supports、fields等元数据{ slug: posts, label: Posts, labelSingular: Post, supports: [drafts, revisions, search, seo], commentsEnabled: true, fields: [ { slug: title, label: Title, type: string, required: true, searchable: true }, { slug: featured_image, label: Featured Image, type: image }, { slug: content, label: Content, type: portableText, searchable: true }, { slug: excerpt, label: Excerpt, type: text } ] }supports声明该集合启用的能力drafts草稿、revisions修订历史、search全文搜索、seoSEO 元数据。pages集合仅启用[drafts, revisions, search]。commentsEnabled: true使posts支持评论对应页面中渲染Comments/CommentForm组件。字段type支持string、image、portableText、text等required与searchable分别控制必填与搜索参与。taxonomies分类法注意 name 的精确匹配{ name: category, label: Categories, labelSingular: Category, hierarchical: true, collections: [posts], terms: [ { slug: development, label: Development }, { slug: design, label: Design }, { slug: notes, label: Notes } ] }category是层级分类法hierarchical: truetag是非层级标签hierarchical: false二者都只作用于posts集合。AGENTS.md 特别强调查询中使用的 taxonomy 名称必须与 seed 中name字段完全一致category而非categories这是第 5 条规则。bylines署名{ id: byline-editorial, slug: emdash-editorial, displayName: EmDash Editorial }定义站点作者/署名实体isGuest: true可标记客座作者。文章内容通过bylines数组引用如{ byline: byline-editorial }或带roleLabel: Guest essay。menus导航菜单{ name: primary, label: Primary Navigation, items: [ { type: custom, label: Home, url: / }, { type: custom, label: About, url: /pages/about }, { type: custom, label: Posts, url: /posts } ] }菜单在布局中通过getMenu(primary)读取并渲染到导航栏与页脚见 src/layouts/Base.astro。widgetAreas组件区域定义可嵌入页面特定位置的组件区。sidebar区聚合了core:search、core:categories、core:tags、core:recent-posts带count: 5、showDate: true设置、core:archivestype: monthly、limit: 6五个核心组件footer区则包含一个静态内容组件。页面通过WidgetArea namesidebar /渲染对应区域。sections可复用内容区块newsletter-signup、about-author等区块以 Portable Text 形式存储标题、描述、关键词与正文可用于在文章或页面中嵌入。content演示数据content包含一篇pages内容about与 8 条posts内容。其中 7 条状态为published每条带有title、excerpt、featured_image通过$media引用远程图片 URL、alt 与文件名、Portable Text 格式的content、bylines与taxonomies如category: [development]。第 8 条post-draft状态为draft——这正是supports: [drafts]的体现草稿不会出现在公开列表中。3.4 emdash-env.d.ts自动生成的集合类型infra/do-solo-demo/emdash-env.d.ts 由 EmDash 根据 seed/运行时 schema 自动生成为posts、pages等集合提供 TypeScript 类型。它会在 dev server 启动时自动重新生成也可通过npx emdash types手动刷新属于生成物、不应手工维护。3.5 src/layouts/Base.astro菜单、搜索与页面贡献infra/do-solo-demo/src/layouts/Base.astro 是所有页面的基座布局承担了 EmDash 的前端接线工作通过getMenu(primary)读取导航菜单并渲染到 header 与 footer通过LiveSearchemdash/ui/search在导航栏提供跨集合的实时搜索collections{[posts, pages]}通过createPublicPageContext(...)构建公共页面上下文交给EmDashHead、EmDashBodyStart、EmDashBodyEnd渲染 SEO 元信息与插件页面贡献通过WidgetArea namefooter /渲染页脚组件区通过Font cssVariable--font-sans preload /加载字体并在Astro.locals.user存在时展示 Admin 入口。3.6 src/pages/全服务端渲染的内容页面infra/do-solo-demo/src/pages/ 包含index.astro首页含 featured 6 宫格布局、posts/index.astro文章列表、posts/[slug].astro文章详情、pages/[slug].astro页面详情、category/[slug].astro、tag/[slug].astro分类/标签归档、search.astro、rss.xml.ts与404.astro。所有页面都是服务端渲染的动态路由不使用getStaticPaths()。四、Rules五条必须遵守的开发规则及源码印证AGENTS.md 用五条规则总结了 EmDash 站点开发中最容易踩坑的地方每条都可以在源码中找到直接证据。规则 1内容页面必须服务端渲染All content pages must be server-rendered (output: server). NogetStaticPaths()for CMS content.astro.config.mjs 中output: server是全局保证src/pages/posts/[slug].astro等动态路由直接读取Astro.params.slug并通过getEmDashEntry()查询数据库内容来自运行时而非构建期因此不能使用静态路径生成。CMS 内容天然是动态的静态化会丢失草稿过滤、实时更新等能力。规则 2图片字段是对象而非字符串Image fields are objects ({ src, alt }), not strings. UseImage image{...} /fromemdash/ui.在 seed/seed.json 中featured_image的类型是image其内容在content.posts中体现为{ $media: { url: ..., alt: ..., filename: ... } }对象。渲染时统一交给emdash/ui的Image image{post.data.featured_image} /见src/pages/index.astro与src/pages/posts/[slug].astro由 EmDash 负责尺寸约束image.layout: constrained与响应式样式。若把图片当字符串处理Image将无法正常工作。规则 3entry.id 是 slugentry.data.id 才是数据库 ULIDentry.idis the slug (for URLs).entry.data.idis the database ULID (for API calls likegetEntryTerms).这条规则在 src/pages/posts/[slug].astro 中体现得最清楚// Note: post.id is the slug, post.data.id is the database ULID. const [tags, { entries: recentPosts }] await Promise.all([ getEntryTerms(posts, post.data.id, tag), ... ]);URL 构造使用post.id如/posts/${post.id}而调用按条目查询的 API如getEntryTerms、getTermsForEntries必须传post.data.id。混淆二者会导致查询不到数据或 URL 错误。规则 4查询内容的页面必须设置缓存提示Always callAstro.cache.set(cacheHint)on pages that query content.getEmDashCollection()/getEmDashEntry()返回的cacheHint携带了该查询的缓存策略信息。src/pages/index.astro、posts/index.astro、posts/[slug].astro都在拿到结果后立即调用Astro.cache.set(cacheHint)使 Cloudflare 边缘缓存能够按内容版本正确失效。漏掉这步页面可能长期缓存过期内容或失去缓存收益。规则 5taxonomy 名称必须与 seed 的 name 完全一致Taxonomy names in queries must match the seedsnamefield exactly (e.g.,categorynotcategories).种子文件中 taxonomy 的name字段是category与tag单数查询时传入的字符串必须精确匹配。这也是数据模型即契约的体现——seed 中定义的名称是查询 API 的第一参数来源。五、源码级延伸内容查询 API 与数据后端5.1 内容查询 API 全景结合 AGENTS.md 与页面源码EmDash 站点的核心查询 API 可以归纳如下API用途出处getEmDashCollection(type, { orderBy, limit })查询某集合的条目列表支持数据库端排序与分页src/pages/index.astro、posts/index.astrogetEmDashEntry(type, slug)按 slug 查询单条内容src/pages/posts/[slug].astrogetEntryTerms(type, ulid, taxonomy)查询单条内容的分类法术语参数用data.idULIDsrc/pages/posts/[slug].astrogetTermsForEntries(type, ulids[], taxonomy)批量查询多条内容的术语避免 N1src/pages/index.astro、posts/index.astrogetMenu(name)读取菜单src/layouts/Base.astrogetSiteSettings()读取站点设置标题、副标题、Logosrc/layouts/Base.astrogetSeoMeta(entry, opts)生成 SEO 元数据title、og、canonical、robotssrc/pages/posts/[slug].astro页面源码还展示了两个值得借鉴的性能模式数据库端排序posts/index.astro注释Sort in the database rather than in JS与批量术语查询getTermsForEntries取代逐条getEntryTerms。首页甚至用limit: POSTS_PER_PAGE 1的多取一条技巧来探测是否还有更多内容避免先全量拉取再在 JS 里丢弃。5.2 数据后端EmDashDB Durable Object配置中database: durableObjects({ binding: DB_DO, session: auto })的底层实现在 packages/cloudflare/src/db 目录do-sql-class.ts中导出的EmDashDB是生产环境的 Durable Object 数据库类站点通过 RPC 调用其查询接口do-sql.ts创建以EmDashDBDO 为后端的 Kysely dialect并校验 Wrangler 配置中的EmDashDBbinding 与 migrationnew_sqlite_classes: [EmDashDB]是否齐全。对应地wrangler.jsonc 中声明了durable_objects.bindingsDB_DO→EmDashDBmigrationsv1新建EmDashDBSQLite 类r2_bucketsMEDIA→emdash-demo-mediaworker_loadersLOADER内容加载器绑定kv_namespacesSESSION会话存储配合session: autocompatibility_flagsnodejs_compat与experimentalroutes自定义域do-solo-demo.emdashcms.com。从配置注释可以推断do-solo-demo刻意不做replica_routing以单主 DO 形态作为性能基准与启用读副本路由的do-demo对照这也解释了它单 DO 演示的命名由来。六、Skills按任务加载对应技能AGENTS.md 提示站点技能位于.agents/skills/并推荐按任务加载三个技能。在本仓库中这三个技能位于顶层 skills/ 目录对应关系如下building-emdash-siteskills/building-emdash-site/SKILL.md内容查询、Portable Text 渲染、schema 设计、seed 文件、站点特性菜单、组件、搜索、SEO、评论、署名。AGENTS.md 建议从这里开始。creating-pluginsskills/creating-plugins/SKILL.md构建 EmDash 插件涵盖 hooks、存储、admin UI、API 路由与 Portable Text 块类型。对应do-solo-demo中formsPlugin、webhookNotifier等插件的使用场景。emdash-cliskills/emdash-cli/SKILL.mdCLI 命令覆盖内容管理、seed 导入、类型生成与可视化编辑流程。七、小结把 AGENTS.md 当作站点的操作手册do-solo-demo/AGENTS.md虽然只有几十行却完整勾勒了一个 EmDash 站点的全部上手路径三条核心命令对应开发、类型生成与种子校验六类关键文件对应配置、Loader、内容模型、生成类型、布局与页面五条规则则直接指向源码中可验证的约束服务端渲染、图片对象、id 语义、缓存提示、taxonomy 命名。结合本仓库的源码阅读你可以把这份速查表推广到任何 EmDash 站点工程——包括infra/blog-demo、demos/下的各演示站点以及 templates 目录中的官方模板——它们共享同一套工程结构与开发约定。【免费下载链接】emdashEmDash is a full-stack TypeScript CMS based on Astro; the spiritual successor to WordPress项目地址: https://gitcode.com/gh_mirrors/emdas/emdash创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考