- CMS
- 后端
- 前端
- 插件系统
【免费下载链接】emdash
EmDash is a full-stack TypeScript CMS based on Astro; the spiritual successor to WordPress
导读
templates/starter-cloudflare是 EmDash 官方提供的通用起步模板,它把一个带完整管理后台的 Astro CMS 站点直接部署到 Cloudflare Workers 之上:使用 D1 作为数据库、R2 作为媒体存储,站点默认包含 posts / pages 两个内容集合以及 category / tag 两个分类法。读完本文,你将掌握该模板的文件结构、核心命令、schema 定义方式、服务端渲染(SSR)规范,并能在其基础上快速搭建属于你自己的内容站点或将其替换为 blog / portfolio / marketing 等带完整视觉系统的模板。
模板定位:最小化、不预设视觉风格
该模板的定位是一个「通用起点」:包含 posts、pages、categories、tags,但没有预置theme.css、没有自定义字体配置、也没有超越浏览器默认样式的排版。主页、文章列表、文章详情、页面、分类页、标签页全部以极简样式渲染(templates/starter-cloudflare/CLAUDE.md)。
这带来的结果是:该模板的定制工作是「做加法」而不是「做减法」——自带内容、schema、路由与后台,只缺设计层。如果你想要开箱即用的设计模板,应改用blog、portfolio或marketing(它们都带可通过theme.css换肤的完整视觉系统)。
常用命令与后台入口
模板在 package.json 中预置了五组脚本:
pnpm dev # 启动 Astro 开发服务器(等价于 astro dev) pnpm build # 构建生产版本(astro build) pnpm preview # 本地预览构建产物(astro preview) pnpm deploy # 构建后通过 wrangler deploy 发布到 Cloudflare Workers pnpm typecheck # 用 astro check 做类型检查针对 EmDash 特有的两个高频命令:
pnpm dev # 启动 Astro 开发服务器 npx emdash types # 基于运行中的站点重新生成 TypeScript 类型管理后台地址固定为http://localhost:4321/_emdash/admin(templates/starter-cloudflare/CLAUDE.md)。emdash-env.d.ts中的集合类型会在开发服务器启动时自动重新生成,npx emdash types用于手动触发同一过程。
关键文件速览
| 文件 | 用途 |
|---|---|
astro.config.mjs | Astro 配置,注册emdash()集成、数据库与存储绑定 |
src/live.config.ts | EmDash loader 注册(样板代码,不要修改) |
seed/seed.json | Schema 定义 + 演示内容(集合、字段、分类法、菜单、widgets) |
emdash-env.d.ts | 集合的生成类型(开发服务器启动时自动重新生成) |
src/layouts/Base.astro | 基础布局,包含 EmDash 接线(菜单、搜索、页面贡献) |
src/pages/ | Astro 页面,全部服务端渲染 |
配置层:D1 数据库 + R2 媒体存储
astro.config.mjs 是理解模板运行环境的关键。它做了四件事:
- 声明
output: "server"——这是 EmDash 内容站点必须的 SSR 模式; - 挂载
@astrojs/cloudflare适配器; - 通过
@emdash-cms/cloudflare包提供d1()与r2()两个适配函数,分别绑定 D1 数据库(binding 为DB)与 R2 媒体桶(binding 为MEDIA),session: "auto"表示 D1 会话由集成自动管理; - 注册
emdash()集成,并关闭devToolbar。
对应的 wrangler.jsonc 声明了 Worker 运行时环境:compatibility_date与nodejs_compat兼容标志、名为my-emdash-site的 D1 数据库、名为my-emdash-media的 R2 桶,以及一个每分钟触发的crons维护定时器("* * * * *")。文件里还注释说明了:沙箱化插件需要 Worker Loader(Workers 付费计划),如需启用可取消worker_loaders绑定的注释。
Worker 入口 src/worker.ts 从@emdash-cms/cloudflare/worker引入默认 handler、createScheduledHandler与PluginBridge,并导出scheduled定时处理——这是模板能运行维护型定时任务的底层接线。
数据层:live.config.ts 与 loader 注册
src/live.config.ts 全文只有 6 行:通过astro:content的defineLiveCollection配合emdash/runtime的emdashLoader()注册一个名为_emdash的 live collection。它把 EmDash 的内容查询能力接入 Astro Content Layer,是页面中getEmDashCollection/getEmDashEntry等 API 能够工作的前提,因此模板明确标注「boilerplate — don't modify」。
Schema 详解:seed.json
模板的数据模型全部定义在 seed/seed.json 中,它同时承担 schema 定义与演示内容两种职责,package.json里的"emdash": { "seed": "seed/seed.json" }字段将其与 CLI 工具关联。
集合与字段
- posts:
title(string,必填、可搜索)、featured_image(image)、content(portableText,可搜索)、excerpt(text),支持 drafts / revisions / search / seo; - pages:
title(string,必填、可搜索)、content(portableText,可搜索),带urlPattern: "/{slug}",支持 drafts / revisions / search。
分类法与菜单
- 分类法
category(层级化hierarchical: true,预置general、updates两个 term)与tag(非层级化,预置starter、example)都只挂载在posts集合上; - 单一
primary菜单,包含 Home、Posts、About 三个自定义链接; widgetAreas定义了一个名为sidebar的 widget 区域,预置了三个组件 widget:core:search搜索、core:categories分类列表、core:recent-posts最近文章(count: 5)。
演示内容
seed 内还包含一页(/about)与一篇文章(/posts/welcome)。文章的content以 Portable Text 块结构书写(_type: "block"+_type: "span"的 children),并演示了taxonomies字段如何关联category与tag的 term slug。
站点设置(settings)只有title(My Site)与tagline(Built with EmDash)两个字段,与src/utils/site-identity.ts中的resolveStarterSiteIdentity工具函数对应——该函数把设置解析为siteTitle/siteTagline/siteLogo,并在无设置时回退到"My Site"/"Built with EmDash"默认值。
页面路由与服务端渲染
模板的src/pages/下所有页面均为 SSR(output: "server"),不适用getStaticPaths()。路由清单(templates/starter-cloudflare/CLAUDE.md):
| 页面 | 路径 | 展示内容 |
|---|---|---|
| Home | / | 站点标题 + tagline,链接到 Posts / About |
| All posts | /posts | 文章列表 |
| Post detail | /posts/[slug] | 文章内容 |
| Page | /[slug] | 静态页面内容(如/about) |
| Category | /category/[slug] | 按分类过滤的文章 |
| Tag | /tag/[slug] | 按标签过滤的文章 |
主页与列表页的查询模式
src/pages/index.astro 演示了最基础的查询:getEmDashCollection("posts", { orderBy: { published_at: "desc" } })按发布时间倒序取文章,并通过Astro.cache.set(cacheHint)写入缓存提示(Cloudflare 适配器会把它转换为页面缓存)。首页还会在无文章时输出一个指向/emdash/admin/content/posts/new的「创建文章」链接。
文章列表页 templates/starter-cloudflare/src/pages/posts/index.astro 则演示了批量查询 taxonomy 的优化做法:先用getEmDashCollection取全部文章,再用getTermsForEntries("posts", posts.map(p => p.data.id), "tag")一次性批量获取所有文章的标签映射,避免对每篇文章单独调用getEntryTerms造成 N 次往返。
详情页、分类页与标签页
文章详情页 templates/starter-cloudflare/src/pages/posts/[slug].astro 是内容型页面的完整示例:
- 用
decodeSlug(Astro.params.slug)解码 slug,非法或未命中时Astro.redirect("/404"); getEmDashEntry("posts", slug)取单条 entry,并通过getSeoMeta基于内容字段生成 SEO meta(title / description / canonical / ogImage),传入Base布局;post.data.terms?.tag ?? []与post.data.terms?.category ?? []读取由getEmDashEntry预先水合(hydrate)好的分类法 term;- 用
emdash/ui的PortableText渲染 Portable Text 正文,用Image渲染图片字段; - 关键细节:编辑高亮依赖
{...post.edit.featured_image}与{...post.edit.title}属性展开,这是 EmDash 可视化编辑能力的接线点。
通用页面 templates/starter-cloudflare/src/pages/[slug].astro 结构相同,仅渲染title与PortableText正文。分类页与标签页(category/[slug].astro、tag/[slug].astro)模式一致:先getTerm("category" | "tag", slug)取 term,再用getEmDashCollection("posts", { where: { category: term.slug } })或{ where: { tag: term.slug } }过滤文章。
基础布局 Base.astro
src/layouts/Base.astro 承担所有页面的外壳:
- 通过
getMenu("primary")取菜单、getSiteSettings()取站点身份并渲染导航栏,导航内嵌emdash/ui/search的LiveSearch(搜索集合限定为posts与pages); - 通过
createPublicPageContext创建公共页面上下文(区分 content / custom 两种页面类型),并渲染EmDashHead、EmDashBodyStart、EmDashBodyEnd三兄弟组件完成 SEO、脚本与插件页面贡献(page contributions)的注入; <footer>里通过<WidgetArea name="sidebar" />渲染 sidebar widget 区域。
必须遵守的编码规则
CLAUDE.md 明确列出了在模板中开发时必须遵守的五条硬性规则(templates/starter-cloudflare/CLAUDE.md),它们直接决定代码能否在 Cloudflare 环境下正确工作:
- 所有内容页面必须服务端渲染(
output: "server"),禁止对 CMS 内容使用getStaticPaths(); - 图片字段是对象
{ src, alt }而非字符串,必须用emdash/ui导出的<Image image={...} />渲染——这在所有页面示例中均有体现; entry.id是 slug(用于 URL),而entry.data.id是数据库 ULID(用于getEntryTerms等 API 调用)——例如列表页批量取标签时传的是post.data.id,而拼链接时用的是post.id;- 查询内容的页面必须调用
Astro.cache.set(cacheHint); - 查询中的 taxonomy 名称必须与 seed 的
"name"字段完全一致(如"category"而非"categories")。
视觉定制:从零开始建立设计系统
模板刻意不施加任何视觉风格(「None imposed. Define your own.」),它默认不包含(templates/starter-cloudflare/CLAUDE.md):
src/styles/theme.css——需要 CSS 变量主题时创建它并从Base.astro引入;astro.config.mjs中的字体——fonts: []为空数组,需要 web 字体时按cssVariable绑定方式添加 Google Fonts 条目;- 带样式的
components/目录(卡片、标签列表等)——按需自行构建。
合理的首轮定制步骤(templates/starter-cloudflare/CLAUDE.md):
- 选择一套展示字体 + 一套正文字体,写入
astro.config.mjs并绑定到--font-display与--font-bodyCSS 变量; - 创建
src/styles/theme.css,定义配色、字号阶梯与间距 token; - 在
Base.astro中引入——布局已经自带一个小型 reset,把主题样式放在页面样式之上; - 在各个 Astro 页面的
<style>块中引用这些 CSS 变量构建页面级样式。
同时有三条「不要做」的边界(templates/starter-cloudflare/CLAUDE.md):
- 不要把它当作成品设计——无样式输出是有意为之,直接上线会显得未完成;
- 不要不加考虑地引入组件库(Tailwind UI、shadcn 等)——模板「小」是刻意设计;
- 不要在这里复刻 blog 模板的三栏阅读视图——想要那种效果应直接从
blog模板开始。
Agent 技能与文档支持
模板面向 AI 编码助手做了完整铺垫(templates/starter-cloudflare/CLAUDE.md)。仓库根目录下对应三份技能文档:
- building-emdash-site(skills/building-emdash-site/SKILL.md)——内容查询、Portable Text 渲染、schema 设计、seed 文件、站点特性(菜单、widgets、搜索、SEO、评论、byline),建议从这里开始;
- creating-plugins(skills/creating-plugins/SKILL.md)——用 hooks、storage、管理后台 UI、API 路由与 Portable Text 块类型构建 EmDash 插件;
- emdash-cli(skills/emdash-cli/SKILL.md)——内容管理、seeding、类型生成与可视化编辑流程相关的 CLI 命令。
EmDash 官方文档还以 MCP 服务器形式提供(https://docs.emdashcms.com/mcp),当需要核对某个 API、hook、配置项、字段类型或模式时,应通过search_docs查询实时文档而不是依赖训练数据的记忆。模板随附.mcp.json、.cursor/mcp.json与.vscode/mcp.json,Claude Code、Cursor、VS Code 会自动发现文档服务器;其他工具(OpenCode、Windsurf 等)需要一次性手动配置。
总结:从模板到站点的路径
starter-cloudflare的价值在于它把「能跑起来的 EmDash 站点」压缩到最小:SSR 渲染、D1 + R2 存储、完整的 posts/pages/category/tag 内容模型、后台管理界面与搜索都已就绪,剩下的工作全部集中在视觉层。你可以沿用它的查询与渲染模式,参考 templates/starter-cloudflare/src/pages 下每个页面的写法,配合 templates/starter-cloudflare/seed/seed.json 扩展自己的集合与字段;也可以直接改用带完整视觉系统的blog、portfolio或marketing模板,再通过theme.css换肤。
- CMS
- 后端
- 前端
- 插件系统
【免费下载链接】emdash
EmDash is a full-stack TypeScript CMS based on Astro; the spiritual successor to WordPress
相关推荐
深入解析 EmDash blog-cloudflare 模板:在 Astro 上构建部署于 Cloudflare Workers 的 CMS 博客
深入解析 EmDash blog cloudflare 模板:在 Astro 上构建部署于 Cloudflare Workers 的 CMS 博客 导读 tem
CMS后端前端插件系统EmDash Cloudflare Demo 实战指南:在 Workers + D1 上运行 Astro 驱动的全栈 CMS
EmDash Cloudflare Demo 实战指南:在 Workers + D1 上运行 Astro 驱动的全栈 CMS 本指南以仓库中的 demos/cl
CMS后端前端插件系统EmDash 博客模板(Cloudflare 版)实战指南:基于 Astro + D1 + R2 的编辑器优先 CMS 站点搭建
EmDash 博客模板(Cloudflare 版)实战指南:基于 Astro + D1 + R2 的编辑器优先 CMS 站点搭建 本指南围绕 EmDash 官方
CMS后端前端插件系统
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考