用途
EmDash 是一个基于 Astro 和 Cloudflare 的全栈 TypeScript CMS,定位为 WordPress 的精神继任者:可扩展、对开发者友好。它通过插件系统扩展功能,插件运行在沙箱化的 Worker 隔离环境中,而不是拥有完整的文件系统或数据库访问权限。EmDash 将富文本存储为 Portable Text(结构化 JSON)而非 HTML,支持以通行密钥(passkey)优先的认证,并可运行在 Cloudflare(D1 + R2 + Workers)或任何带 SQLite 的 Node.js 服务器上。
本条目是一个面向 AI 编程智能体的技能(Skill),用于帮助开发者使用 EmDash 构建站点。
主要能力
- 内容建模:内容类型在管理后台 UI 中定义,无需编写代码;创建集合后可生成 TypeScript 类型。
- 内容查询:提供 getEmDashCollection、getEmDashEntry 等 API,支持过滤、排序、分页、按分类法过滤。
- Portable Text 渲染:富文本以结构化 JSON 存储,通过 renderPortableText 渲染,并支持自定义块渲染器。
- 插件系统:插件是主要扩展机制。在 Cloudflare 上运行于沙箱化 Worker 隔离环境,需声明能力清单;在 Node.js 上以进程内(安全模式)运行。
- 认证:以通行密钥(WebAuthn)优先,支持 OAuth 与魔法链接回退,并提供角色控制。
- WordPress 迁移:支持从 WXR 导出文件、WordPress REST API、WordPress.com 导入,迁移文章、页面、媒体、分类、标签、作者与评论,Gutenberg 块通过 gutenberg-to-portable-text 包转换。
- MCP 服务器:内置 MCP 服务器,使 Claude、ChatGPT 等 AI 工具可直接管理站点内容。
- 一方插件:提供 forms、seo、embeds、audit-log 等插件。
使用方式
安装与脚手架:
npm create emdash@latest
按提示选择模板(blog、marketing、portfolio、starter、blank)与平台(Cloudflare 或 Node.js/SQLite)。
一键部署到 Cloudflare:
npm create emdash@latest -- --template blog-cloudflare
cd my-site
npm run deploy
添加到现有 Astro 项目:
npm install emdash
// astro.config.mjs
import { defineConfig } from "astro/config";
import emdash from "emdash/astro";
import { d1 } from "emdash/db";
export default defineConfig({
integrations: [
emdash({
database: d1(), // Cloudflare D1
}),
],
});
Node.js + SQLite(无需 Cloudflare 账户):
// astro.config.mjs
import { defineConfig } from "astro/config";
import emdash from "emdash/astro";
import { sqlite } from "emdash/db";
export default defineConfig({
integrations: [
emdash({
database: sqlite({ path: "./content.db" }),
}),
],
});
常用 CLI 命令:
npm create emdash@latest # 脚手架新项目
npx emdash types # 从实时 schema 生成 TypeScript 类型
npx emdash seed # 用示例内容填充演示站点
npx emdash migrate # 运行数据库迁移
npx astro dev # 启动开发服务器
npx astro build # 生产构建
open http://localhost:4321/_emdash/admin # 打开管理面板
Monorepo / 贡献者命令:
pnpm install
pnpm build
pnpm test # 运行所有测试
pnpm typecheck # TypeScript 检查
pnpm lint:quick # 快速 lint(< 1s)
pnpm format # 使用 oxfmt 格式化
pnpm --filter emdash-demo seed
pnpm --filter emdash-demo dev
配置方面,Cloudflare 使用 wrangler.jsonc 配置 D1、R2、KV 与 Worker Loaders;Node.js + SQLite 使用 sqlite 与 localFiles;还支持 PostgreSQL 与 Turso/libSQL。
内容查询示例:
---
// src/pages/blog/index.astro
import { getEmDashCollection } from "emdash";
const { entries: posts } = await getEmDashCollection("posts", {
filter: { status: "published" },
sort: { field: "publishedAt", direction: "desc" },
limit: 10,
});
---
单条内容查询与 Portable Text 渲染:
---
import { getEmDashEntry, renderPortableText } from "emdash";
const { slug } = Astro.params;
const post = await getEmDashEntry("posts", { slug });
if (!post) return Astro.redirect("/404");
const { Content } = await renderPortableText(post.data.body);
---
<article>
<h1>{post.data.title}</h1>
<Content />
</article>
插件开发使用 definePlugin,可声明 capabilities、hooks、settings、adminPages、blocks、apiRoutes。可用能力包括 read:content、write:content、read:users、email:send、kv:read、kv:write、http:fetch、storage:read、storage:write。可用钩子覆盖内容生命周期(content:beforeSave、content:afterSave、content:beforeDelete、content:afterDelete、content:beforeRender)、认证生命周期(auth:afterLogin、auth:afterLogout、auth:afterRegister)、媒体生命周期(media:beforeUpload、media:afterUpload、media:beforeDelete)与 admin:init。
认证配置支持 GitHub、Google OAuth 与魔法链接,并提供 requireAuth、getUser、requireRole 等辅助函数,角色包括 administrator、editor、author、contributor。
WordPress 迁移命令:
npx emdash import:wordpress ./export.xml
npx emdash import:wordpress --url https://yoursite.wordpress.com --api-key $WP_API_KEY
npx emdash import:wordpress --wpcom --site yoursite.wordpress.com
MCP 服务器在 astro.config.mjs 中启用,可通过 allowedRoles 限制角色,端点位于 /_emdash/mcp,可接入 Claude Desktop。
适用场景
- 需要可扩展、对开发者友好的内容管理系统的 Astro 项目。
- 希望从 WordPress 迁移到现代 TypeScript 技术栈的站点。
- 需要沙箱化插件安全模型的 Cloudflare 部署场景。
- 希望让 AI 工具(如 Claude、ChatGPT)直接管理站点内容的场景。
限制
- 沙箱化插件需要付费 Cloudflare 账户($5/月及以上);免费账户需从 wrangler.jsonc 移除 worker_loaders 块以禁用沙箱化插件,改为进程内运行。
- 管理面板返回 404 时需确认 Astro 集成已注册并重启开发服务器。
- schema 变更后需重新生成 TypeScript 类型。
- 本地使用 D1 绑定时应使用 wrangler dev 而非 astro dev,或改用 SQLite。
- 插件钩子未触发时需确认插件已在 plugins 数组中列出,且钩子所需能力已在 capabilities 中声明,缺失能力会导致沙箱静默阻止调用。
- 关于收费、价格、平台支持范围等更多细节,资料中未提供完整信息。