大模型应用
在 Astro 项目中使用 EmDash CMS…
当你需要基于 Astro 和 TypeScript 构建可扩展 CMS,或在 EmDash 中配置内容集合、插件、认证、WordPress 迁移和 MCP 集成时使用。
🧪 尚未被验证(还没有小呱复用过的记录,不代表不好)
GDI C 38/100
进化评分(GDI)
综合排序依据 —— 四个维度的加权结果,让你看出「为什么这条排在前面」
内在质量 55/100 ×0.35
使用度 0/100 ×0.30
口碑 50/100 ×0.20
新鲜度 60/100 ×0.15
适用场景
在 Astro 项目中使用 EmDash特定
解决思路
- 使用 `npm create emdash@latest` 脚手架新建 EmDash 项目,按提示选择模板(`blog`、`marketing`、`portfolio`、`starter`、`blank`)和平台(Cloudflare 或 Node.js/SQLite)。
- 直接部署到 Cloudflare:使用 README 的一键部署按钮,或运行 `npm create emdash@latest -- --template blog-cloudflare`,然后 `cd my-site`,再 `npm run deploy`。
- 向现有 Astro 项目添加 EmDash:运行 `npm install emdash`。
- 在 `astro.config.mjs` 中配置 Cloudflare D1:导入 `defineConfig`、`emdash from 'emdash/astro'`、`d1 from 'emdash/db'`,在 `integrations` 中调用 `emdash({ database: d1() })`。
- 使用 Node.js + SQLite(无需 Cloudflare 账号):在 `astro.config.mjs` 中导入 `sqlite from 'emdash/db'`,在 `integrations` 中调用 `emdash({ database: sqlite({ path: './content.db' }) })`。
- 常用 CLI:运行 `npm create emdash@latest` 脚手架新建 EmDash 项目。
- 常用 CLI:运行 `npx emdash types` 根据实时 schema 生成 TypeScript 类型。
- 常用 CLI:运行 `npx emdash seed` 用示例内容填充演示站点。
- 常用 CLI:运行 `npx emdash migrate` 执行数据库迁移。
- 常用 CLI:运行 `npx astro dev` 启动开发服务器。
- 常用 CLI:运行 `npx astro build` 构建生产版本。
- 常用 CLI:开发服务器启动后,打开 `http://localhost:4321/_emdash/admin` 进入管理面板。
- Monorepo/贡献者:运行 `pnpm install`。
- Monorepo/贡献者:运行 `pnpm build`。
- Monorepo/贡献者:运行 `pnpm test` 运行全部测试。
- Monorepo/贡献者:运行 `pnpm typecheck` 执行 TypeScript 检查。
- Monorepo/贡献者:运行 `pnpm lint:quick` 快速 lint(< 1s)。
- Monorepo/贡献者:运行 `pnpm format` 使用 oxfmt 格式化。
- Monorepo/贡献者:运行 `pnpm --filter emdash-demo seed` 运行演示(Node.js + SQLite,无需 Cloudflare)的 seed。
- Monorepo/贡献者:运行 `pnpm --filter emdash-demo dev` 启动演示开发服务器。
- 配置 Cloudflare:在 `wrangler.jsonc` 中设置 `name: 'my-emdash-site'`。
- 配置 Cloudflare:在 `wrangler.jsonc` 中设置 `compatibility_date: '2025-01-01'`。
- 配置 Cloudflare:在 `wrangler.jsonc` 中配置 `d1_databases`:`binding: 'DB'`、`database_name: 'emdash-content'`、`database_id: '$DATABASE_ID'`。
- 配置 Cloudflare:在 `wrangler.jsonc` 中配置 `r2_buckets`:`binding: 'MEDIA'`、`bucket_name: 'emdash-media'`。
- 配置 Cloudflare:在 `wrangler.jsonc` 中配置 `kv_namespaces`:`binding: 'SESSIONS'`、`id: '$KV_NAMESPACE_ID'`。
- 配置 Cloudflare:在 `wrangler.jsonc` 中配置 `worker_loaders`:`binding: 'PLUGIN_LOADER'`;免费账户可删除此块以禁用沙箱插件。
- 在 `astro.config.mjs` 中配置 Cloudflare 集成:导入 `emdash from 'emdash/astro'`、`d1 from 'emdash/db'`、`r2 from 'emdash/storage'`、`kv from 'emdash/sessions'`,调用 `emdash({ database: d1({ binding: 'DB' }), storage: r2({ binding: 'MEDIA' }), sessions: kv({ binding: 'SESSIONS' }) })`。
- 配置 Node.js + SQLite:在 `astro.config.mjs` 中导入 `sqlite from 'emdash/db'` 和 `localFiles from 'emdash/storage'`,调用 `emdash({ database: sqlite({ path: './content.db' }), storage: localFiles({ dir: './public/uploads' }) })`。
- 配置 PostgreSQL:导入 `postgres from 'emdash/db'`,设置 `database: postgres({ url: process.env.DATABASE_URL })`。
- 配置 Turso/libSQL:导入 `turso from 'emdash/db'`,设置 `database: turso({ url: process.env.TURSO_DATABASE_URL, authToken: process.env.TURSO_AUTH_TOKEN })`。
- 内容类型在管理 UI 中定义,无需代码;创建 collection 后运行 `npx emdash types` 生成类型定义到 `src/emdash.d.ts`。
- 在 Astro 页面获取 collection:在 `src/pages/blog/index.astro` 中导入 `getEmDashCollection from 'emdash'`,调用 `await getEmDashCollection('posts', { filter: { status: 'published' }, sort: { field: 'publishedAt', direction: 'desc' }, limit: 10 })`,并遍历 `entries`。
- 获取单条 entry:在 `src/pages/blog/[slug].astro` 中导入 `getEmDashEntry, renderPortableText from 'emdash'`,使用 `Astro.params.slug` 调用 `getEmDashEntry('posts', { slug })`,若无则 `Astro.redirect('/404')`,再调用 `renderPortableText(post.data.body)` 并用 `<Content />` 渲染。
- 分页:读取 `page = Number(Astro.params.page ?? 1)`,调用 `getEmDashCollection('posts', { filter: { status: 'published' }, sort: { field: 'publishedAt', direction: 'desc' }, limit: 10, offset: (page - 1) * 10 })`。
- 按 taxonomy 过滤:调用 `getEmDashCollection('posts', { filter: { status: 'published', tags: { contains: 'typescript' } } })`。
- Portable Text 渲染:EmDash 将富文本存为 Portable Text 结构化 JSON,而非 HTML;使用 `renderPortableText` 渲染。
- 自定义 block renderer:在 `src/portable-text.ts` 中导入 `definePortableTextComponents from 'emdash/blocks'`,定义 `types`(如 `callout`、`image`)和 `marks`(如 `highlight`)组件。
- 使用自定义 renderer:在 Astro 中导入 `components`,调用 `renderPortableText(post.data.body, { components })`。
- 插件开发:插件是主要扩展机制;Cloudflare 上插件运行在沙箱化 Worker isolate 中并有声明的 capability manifest;Node.js 上进程内运行(safe mode)。
- 最小插件:在 `plugins/my-plugin/index.ts` 中导入 `definePlugin from 'emdash/plugin'`,导出 `definePlugin({ id: 'my-plugin', name: 'My Plugin', version: '1.0.0', capabilities: [], hooks: {} })`。
- 带 content hooks 与 email 的插件:声明 `capabilities: ['read:content', 'email:send']`,实现 `content:afterSave` hook,当 `event.content.status === 'published'` 时调用 `ctx.email.send({ to: 'editors@example.com', subject: ..., text: ... })`。
- 带 KV 存储与 admin settings 的插件:声明 `capabilities: ['read:content', 'kv:read', 'kv:write']`,在 `settings.schema` 定义 `resetDaily` boolean;实现 `content:beforeRender` hook,用 `ctx.kv.get/set` 更新 `views:${event.content.id}`,并设置 `event.content.meta.views`;通过 `adminPages` 添加 `path: '/analytics'`、`title: 'View Analytics'`、`component: 'ViewAnalytics'`。
- 带自定义 block type 的插件:导入 `defineBlock from 'emdash/blocks'`,在 `blocks` 中定义 `name: 'callout'`、`title: 'Callout'`、字段 `type`(select options `info`/`warning`/`danger`,默认 `info`)和 `text`(text,label `Message`)。
- 带自定义 API route 的插件:声明 `capabilities: ['kv:write']`,在 `apiRoutes` 中添加 `method: 'POST'`、`path: '/subscribe'`、handler 从 `request.json()` 取 `email`,调用 `ctx.kv.set('subscriber:' + email, 'true')`,返回 JSON `{ ok: true }`。
- 可用 capability:`read:content` 读取已发布内容。
- 可用 capability:`write:content` 创建和更新内容。
- 可用 capability:`read:users` 读取用户资料。
- 可用 capability:`email:send` 通过配置的 email provider 发送邮件。
- 可用 capability:`kv:read` 读取插件自己的 KV namespace。
- 可用 capability:`kv:write` 写入插件自己的 KV namespace。
- 可用 capability:`http:fetch` 发起出站 HTTP 请求。
- 可用 capability:`storage:read` 读取媒体存储。
- 可用 capability:`storage:write` 写入媒体存储。
- 可用 hook:内容生命周期 `content:beforeSave`。
- 可用 hook:内容生命周期 `content:afterSave`。
- 可用 hook:内容生命周期 `content:beforeDelete`。
- 可用 hook:内容生命周期 `content:afterDelete`。
- 可用 hook:内容生命周期 `content:beforeRender`。
- 可用 hook:认证生命周期 `auth:afterLogin`。
- 可用 hook:认证生命周期 `auth:afterLogout`。
- 可用 hook:认证生命周期 `auth:afterRegister`。
- 可用 hook:媒体生命周期 `media:beforeUpload`。
- 可用 hook:媒体生命周期 `media:afterUpload`。
- 可用 hook:媒体生命周期 `media:beforeDelete`。
- 可用 hook:管理生命周期 `admin:init`。
- 认证:EmDash 使用 passkey-first(WebAuthn)认证,并以 OAuth 和 magic link 作为回退。
- 配置 OAuth providers:在 `astro.config.mjs` 中导入 `github, google from 'emdash/auth'`,在 `auth.providers` 中传入 `github({ clientId: process.env.GITHUB_CLIENT_ID, clientSecret: process.env.GITHUB_CLIENT_SECRET })` 和 `google({ clientId: process.env.GOOGLE_CLIENT_ID, clientSecret: process.env.GOOGLE_CLIENT_SECRET })`。
- 配置 magic link email:在 `auth.providers` 中传入 `magicLink({ from: 'noreply@yourdomain.com' })`,使用已配置的 email adapter。
- 保护页面:在 `src/pages/dashboard.astro` 中导入 `requireAuth from 'emdash/auth'`,调用 `await requireAuth(Astro)`;未认证会重定向到 `/login`。
- 获取当前用户(可选):导入 `getUser from 'emdash/auth'`,调用 `await getUser(Astro)`;未登录返回 `null`。
- 角色:导入 `requireRole from 'emdash/auth'`,调用 `await requireRole(Astro, 'editor')`;角色有 `administrator`、`editor`、`author`、`contributor`。
- WordPress 迁移:从 WXR 导出文件导入:`npx emdash import:wordpress ./export.xml`。
- WordPress 迁移:从 WordPress REST API 导入:`npx emdash import:wordpress --url https://yoursite.wordpress.com --api-key $WP_API_KEY`。
- WordPress 迁移:从 WordPress.com 导入:`npx emdash import:wordpress --wpcom --site yoursite.wordpress.com`。
- WordPress 导入器迁移 posts、pages、media attachments、categories、tags、authors、comments;Gutenberg blocks 通过 `gutenberg-to-portable-text` 包转换为 Portable Text。
- 内容 Schema:内容类型在管理面板 `/_emdash/admin` 创建,不在代码中创建;修改 collection 后运行 `npx emdash types` 重新生成 TypeScript 类型到 `src/emdash.d.ts`。
- Schema 字段类型:`text` 短字符串。
- Schema 字段类型:`richText` Portable Text(TipTap 编辑器)。
- Schema 字段类型:`number` 整数或浮点数。
- Schema 字段类型:`boolean` true/false 开关。
- Schema 字段类型:`date` / `datetime` 日期选择器。
- Schema 字段类型:`select` 单选下拉。
- Schema 字段类型:`multiSelect` 多选。
- Schema 字段类型:`image` 媒体库选择器。
- Schema 字段类型:`file` 文件附件。
- Schema 字段类型:`relation` 链接到另一个 collection entry。
- Schema 字段类型:`slug` URL 安全字符串,从源字段自动生成。
- Schema 字段类型:`json` 原始 JSON。
- MCP Server:EmDash 内置 MCP server,使 AI 工具如 Claude、ChatGPT 能直接管理站点内容。
- 配置 MCP:在 `astro.config.mjs` 中设置 `mcp: { enabled: true, allowedRoles: ['administrator', 'editor'] }`。
- MCP server 位于 `/_emdash/mcp`;连接 Claude Desktop 时在 `claude_desktop_config.json` 添加 `mcpServers.emdash`,设置 `url: 'https://yoursite.com/_emdash/mcp'` 和 `headers.Authorization: 'Bearer $EMDASH_MCP_TOKEN'`。
- 仓库结构:`packages/core/` 包含 Astro integration、APIs、admin UI、CLI。
- 仓库结构:`packages/auth/` 认证库。
- 仓库结构:`packages/blocks/` Portable Text block definitions。
- 仓库结构:`packages/cloudflare/` Cloudflare adapter(D1、R2、Worker Loader)。
- 仓库结构:`packages/plugins/` 一方插件(forms、embeds、SEO、audit-log 等)。
- 仓库结构:`packages/create-emdash/` npm create emdash 脚手架。
- 仓库结构:`packages/gutenberg-to-portable-text/` WordPress block converter。
- 仓库结构:`templates/` 包含 blog、marketing、portfolio、starter、blank。
- 仓库结构:`demos/` 开发示例站点。
- 仓库结构:`docs/` Starlight 文档站点。
- 一方插件:从 `emdash/plugins` 包安装,导入 `forms from 'emdash/plugins/forms'`、`seo from 'emdash/plugins/seo'`、`embeds from 'emdash/plugins/embeds'`、`auditLog from 'emdash/plugins/audit-log'`,在 `plugins: [forms(), seo(), embeds(), auditLog()]` 中注册。
- 故障排除:出现 “Dynamic Workers are not available on free accounts” 时,说明沙箱插件需要付费 Cloudflare 账户($5/mo+);从 `wrangler.jsonc` 移除 `worker_loaders` 块可禁用沙箱插件并改为进程内运行。
- 故障排除:管理面板返回 404 时,确保 Astro integration 已在 `astro.config.mjs` 注册,并在安装 EmDash 后重启 dev server。
- 故障排除:schema 变更后 TypeScript 报错时,运行 `npx emdash types` 重新生成类型。
- 故障排除:本地 D1 binding 报错时,使用 `wrangler dev` 而不是 `astro dev`,或改用 SQLite:`database: process.env.CF_PAGES ? d1() : sqlite({ path: './content.db' })`。
- 故障排除:迁移未应用时,运行 `npx emdash migrate`;Cloudflare D1 远程运行 `npx wrangler d1 migrations apply emdash-content --remote`。
- 故障排除:插件 hook 未触发时,确认插件已列入 `astro.config.mjs` 的 `plugins` 数组,且 hook 所需 capability 已在插件 `capabilities` 数组中声明;缺失 capability 会导致沙箱静默阻止调用。
适用边界 · 注意事项
- 项目不使用 Astro 或 TypeScript 时不适合;EmDash 构建在 Astro 和 TypeScript 上。
- 必须使用 Cloudflare 沙箱化 Worker 插件但只有免费 Cloudflare 账户时不适合;沙箱插件需要付费账户($5/mo+),除非移除 `worker_loaders` 并接受进程内运行。
- 希望富文本直接以 HTML 存储/输出且不愿使用 Portable Text 渲染流程时不适合。