数据库选项

本页内容

EmDash 支持多种数据库后端。根据你的部署目标进行选择。

概览

数据库适用场景部署方式
D1Cloudflare Workers边缘,全球分布
HyperdriveCloudflare Workers 上的 PostgreSQL边缘,现有 Postgres
PostgreSQLNode.js 生产环境任何支持 Postgres 的平台
libSQL远程数据库边缘或 Node.js
SQLiteNode.js,本地开发单服务器

Cloudflare D1

D1 是 Cloudflare 的无服务器 SQLite 数据库。在部署到 Cloudflare Workers 时使用。

import { d1 } from "@emdash-cms/cloudflare";

export default defineConfig({
	integrations: [
		emdash({
			database: d1({ binding: "DB" }),
		}),
	],
});

配置

选项类型默认值描述
bindingstringwrangler.jsonc 中的 D1 绑定名称
sessionstring"disabled"读取副本模式(见下文)
bookmarkCookiestring"__em_d1_bookmark"会话书签的 Cookie 名称

设置

wrangler.jsonc

{
  "d1_databases": [
    {
      "binding": "DB",
      "database_name": "emdash-db"
    }
  ]
}

wrangler.toml

[[d1_databases]]
binding = "DB"
database_name = "emdash-db"

读取副本

D1 支持读取复制以降低全球分布站点的读取延迟。启用后,读取查询会路由到附近的副本,而不是始终查询主数据库。

EmDash 使用 D1 Sessions API 透明地管理此功能。使用 session 选项启用:

import { d1 } from "@emdash-cms/cloudflare";

export default defineConfig({
	integrations: [
		emdash({
			database: d1({
				binding: "DB",
				session: "auto",
			}),
		}),
	],
});

会话模式

模式行为
"disabled"无会话。所有查询都发送到主数据库。默认值。
"auto"匿名请求从最近的副本读取。认证用户通过书签 Cookie 获得 read-your-writes 一致性。
"primary-first""auto" 相同,但第一个查询始终发送到主数据库。适用于写入非常频繁的站点。

工作原理

  • 匿名访客获得 first-unconstrained — 读取从最近的副本获取以实现最低延迟。由于匿名用户从不写入,因此不需要一致性保证。
  • 认证用户(编辑者、作者)获得基于书签的会话。写入后,书签 Cookie 确保下一个请求至少看到该状态。
  • 写入请求POSTPUTDELETE)始终从主数据库开始。
  • 构建时查询(Astro 内容集合)完全绕过会话,直接使用主数据库。

libSQL

libSQL 是 SQLite 的一个分支,支持远程连接。当你需要远程数据库但不使用 Cloudflare D1 时使用。

import { libsql } from "emdash/db";

export default defineConfig({
	integrations: [
		emdash({
			database: libsql({
				url: process.env.LIBSQL_DATABASE_URL,
				authToken: process.env.LIBSQL_AUTH_TOKEN,
			}),
		}),
	],
});

配置

选项类型描述
urlstring数据库 URL(libsql://...file:...
authTokenstring远程数据库的认证令牌(本地可选)

本地开发

开发时使用本地 libSQL 文件:

database: libsql({ url: "file:./data.db" });

PostgreSQL

PostgreSQL 支持需要完整关系数据库的 Node.js 部署。

import { postgres } from "emdash/db";

export default defineConfig({
	integrations: [
		emdash({
			database: postgres({
				connectionString: process.env.DATABASE_URL,
			}),
		}),
	],
});

配置

你可以使用连接字符串或单独的参数进行连接:

// 连接字符串
database: postgres({
	connectionString: "postgres://user:password@localhost:5432/emdash",
});

// 单独参数
database: postgres({
	host: "localhost",
	port: 5432,
	database: "emdash",
	user: "emdash",
	password: process.env.DB_PASSWORD,
	ssl: true,
});
选项类型描述
connectionStringstringPostgreSQL 连接 URL
hoststring数据库主机
portnumber数据库端口
databasestring数据库名称
userstring数据库用户
passwordstring数据库密码
sslboolean启用 SSL
pool.minnumber连接池最小连接数(默认 0)
pool.maxnumber连接池最大连接数(默认 10)

连接池

适配器内部使用 pg.Pool。根据你的部署调整池大小:

database: postgres({
	connectionString: process.env.DATABASE_URL,
	pool: { min: 2, max: 20 },
});

Hyperdrive

使用 hyperdrive() 适配器在 Cloudflare Workers 上运行 EmDash,连接现有的 PostgreSQL — 或 Postgres 兼容(如 PlanetScale Postgres)— 数据库。Hyperdrive 通过 Cloudflare 网络池化和加速连接;EmDash 的 PostgreSQL 方言执行查询。

import { hyperdrive, r2 } from "@emdash-cms/cloudflare";

export default defineConfig({
	integrations: [
		emdash({
			database: hyperdrive({ binding: "HYPERDRIVE" }),
			storage: r2({ binding: "MEDIA" }),
		}),
	],
});

要求

  • 站点中安装 pg >= 8.16.3pnpm add pg
  • compatibility_flags: ["nodejs_compat"]
  • compatibility_date >= "2024-09-23"

设置

创建 Hyperdrive 配置并将绑定添加到你的 Wrangler 配置:

wrangler hyperdrive create emdash-db \
  --connection-string "postgres://user:password@host/db?sslmode=verify-full" \
  --caching-disabled

wrangler.jsonc

{
  "hyperdrive": [
    {
      "binding": "HYPERDRIVE",
      "id": "<your-hyperdrive-id>"
    }
  ]
}

wrangler.toml

[[hyperdrive]]
binding = "HYPERDRIVE"
id = "<your-hyperdrive-id>"

配置

选项类型默认值描述
bindingstring"HYPERDRIVE"主(缓存禁用)Hyperdrive 绑定
cachedBindingstring用于匿名读取的可选缓存启用绑定
maxnumber5Worker 内到 Hyperdrive 的连接池最大大小

从缓存提供匿名读取

默认情况下,你完全禁用 Hyperdrive 缓存,因为管理后台和写入需要 read-after-write 一致性。但匿名公共读取 — 无会话、无写入 — 可以容忍短暂的过时数据窗口。如果这个权衡可以接受,运行同一数据库上的两个 Hyperdrive 配置:一个禁用缓存(主 binding),一个启用缓存(cachedBinding)。EmDash 将匿名读取请求通过缓存启用的绑定路由,而所有认证请求和写入保持在无缓存的主绑定上,保持 read-after-write 一致性。

# 主 — 缓存禁用(管理、认证请求、写入、迁移)
wrangler hyperdrive create emdash-db \
  --connection-string "postgres://user:password@host/db?sslmode=verify-full" \
  --caching-disabled

# 缓存启用 — 相同连接字符串,缓存启用(仅匿名读取)
wrangler hyperdrive create emdash-db-cached \
  --connection-string "postgres://user:password@host/db?sslmode=verify-full"
{
	"hyperdrive": [
		{ "binding": "HYPERDRIVE", "id": "<caching-disabled-id>" },
		{ "binding": "HYPERDRIVE_CACHED", "id": "<caching-enabled-id>" }
	]
}
database: hyperdrive({ binding: "HYPERDRIVE", cachedBinding: "HYPERDRIVE_CACHED" });

这是 Cloudflare 为缓存文档化的双配置模式。EmDash 按请求决定使用哪个绑定:

  • 公共站点路径的匿名读取GET/HEAD、无会话、不在 /_emdash 下)→ 缓存启用的 cachedBinding
  • 认证请求(编辑者、作者)→ 无缓存 binding
  • 写入POSTPUTDELETE,包括匿名)→ 无缓存 binding
  • /_emdash 下的任何请求(管理、设置、认证、内部 API),即使是匿名 GET → 无缓存 binding
  • 迁移和冷启动 → 始终主 binding

SQLite

使用 better-sqlite3 的 SQLite 是 Node.js 部署最简单的选项。

import { sqlite } from "emdash/db";

export default defineConfig({
	integrations: [
		emdash({
			database: sqlite({ url: "file:./data.db" }),
		}),
	],
});

配置

选项类型描述
urlstringfile: 前缀的文件路径

文件路径

url 必须以 file: 开头:

// 相对路径
database: sqlite({ url: "file:./data/emdash.db" });

// 绝对路径
database: sqlite({ url: "file:/var/data/emdash.db" });

// 从环境变量
database: sqlite({ url: `file:${process.env.DATABASE_PATH}` });

迁移

EmDash 在每个支持的方言(D1、SQLite、libSQL、PostgreSQL)的第一次请求时自动运行迁移。迁移打包在 emdash 包中并嵌入到你的构建中。

如果数据库为空(没有集合)且设置向导未完成,EmDash 还会在首次启动时应用种子文件。种子从 .emdash/seed.jsonpackage.json#emdash.seed 中的路径或 seed/seed.json 读取 — 取最先找到的 — 并在编译时嵌入构建。如果都不存在,则使用内置的默认种子。后续针对现有数据库的启动不会更改其内容。

基于环境的配置

按环境使用不同的数据库:

import { sqlite, libsql, postgres } from "emdash/db";
import { d1 } from "@emdash-cms/cloudflare";

const database = import.meta.env.PROD ? d1({ binding: "DB" }) : sqlite({ url: "file:./data.db" });

export default defineConfig({
	integrations: [emdash({ database })],
});

选择也可以基于环境变量而非构建模式:

const database = process.env.DATABASE_URL
	? postgres({ connectionString: process.env.DATABASE_URL })
	: sqlite({ url: "file:./data.db" });