EmDash 支援多種資料庫後端。根據你的部署目標選擇。
概覽
| 資料庫 | 最適用於 | 部署 |
|---|---|---|
| D1 | Cloudflare Workers | 邊緣,全球分散 |
| Hyperdrive | Cloudflare Workers 上的 PostgreSQL | 邊緣,現有 Postgres |
| PostgreSQL | 生產 Node.js | 有 Postgres 的任何平台 |
| libSQL | 遠端資料庫 | 邊緣或 Node.js |
| SQLite | Node.js,本地開發 | 單一伺服器 |
Cloudflare D1
D1 是 Cloudflare 的無伺服器 SQLite 資料庫。在部署到 Cloudflare Workers 時使用。
import { d1 } from "@emdash-cms/cloudflare";
export default defineConfig({
integrations: [
emdash({
database: d1({ binding: "DB" }),
}),
],
});
設定
| 選項 | 型別 | 預設值 | 描述 |
|---|---|---|---|
binding | string | — | wrangler.jsonc 中的 D1 繫結名稱 |
session | string | "disabled" | 唯讀複寫模式(見下方) |
bookmarkCookie | string | "__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 確保下一個請求至少看到該狀態。
- 寫入請求(
POST、PUT、DELETE)始終從主資料庫開始。 - 建置時查詢(Astro content collections)完全繞過工作階段並直接使用主資料庫。
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,
}),
}),
],
});
設定
| 選項 | 型別 | 描述 |
|---|---|---|
url | string | 資料庫 URL(libsql://... 或 file:...) |
authToken | string | 遠端資料庫的執行階段驗證權杖(本地可選) |
migrationAuthTokenEnv | string | 遷移權杖變數名(預設 TURSO_AUTH_TOKEN) |
本地開發
開發期間使用本地 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,
});
| 選項 | 型別 | 描述 |
|---|---|---|
connectionString | string | PostgreSQL 連線 URL |
host | string | 資料庫主機 |
port | number | 資料庫連接埠 |
database | string | 資料庫名稱 |
user | string | 資料庫使用者 |
password | string | 資料庫密碼 |
ssl | boolean | 啟用 SSL |
pool.min | number | 最小連線池數(預設 0) |
pool.max | number | 最大連線池數(預設 10) |
pool.connectionTimeoutMillis | number | 最大連線等待(pg 預設: 0,無逾時) |
pool.idleTimeoutMillis | number | 閒置用戶端生命期(pg 預設: 10,000 ms) |
migrationConnectionStringEnv | string | 遷移連線字串變數名(預設 DATABASE_URL) |
資料庫角色要求
EmDash 建立和更新自己的 PostgreSQL 表。核心遷移建立和修改系統及集合表,內容類型建立 ec_* 表,新增或移除欄位會修改其集合表。因此設定的 PostgreSQL 角色在網站的整個生命週期內都需要架構權限。
為 EmDash 使用一個標準角色。它需要:
- 資料庫的
CONNECT; - 活動架構的
USAGE和CREATE; - 每個 EmDash 表和函式的擁有權;以及
- 這些表的
SELECT、INSERT、UPDATE和DELETE。
大多數安裝可以使用資料庫的現有架構(通常是 public)。使用管理連線授予存取權限:
GRANT CONNECT ON DATABASE app TO emdash_app;
GRANT USAGE, CREATE ON SCHEMA public TO emdash_app;
EmDash 使用 PostgreSQL 的活動 current_schema()。它不建立架構或設定 search_path,因此請在部署前驗證連線:
SELECT
current_database(),
session_user,
current_user,
current_schema(),
current_setting('search_path');
可選:使用專用架構
當 EmDash 與另一個應用共享資料庫時,使用專用架構來隔離其物件:
GRANT CONNECT ON DATABASE app TO emdash_app;
CREATE SCHEMA emdash AUTHORIZATION emdash_app;
ALTER ROLE emdash_app IN DATABASE app SET search_path = emdash;
連線池
配接器內部使用 pg.Pool。根據部署調整池大小:
database: postgres({
connectionString: process.env.DATABASE_URL,
pool: { min: 2, max: 20 },
});
Hyperdrive
使用 hyperdrive() 配接器在 Cloudflare Workers 上執行 EmDash,後端使用現有的 PostgreSQL 資料庫。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.3(pnpm add pg) compatibility_flags: ["nodejs_compat"]compatibility_date >= "2024-09-23"
設定
首先準備 PostgreSQL 角色。然後使用該角色的連線字串建立 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>" 設定
| 選項 | 型別 | 預設值 | 描述 |
|---|---|---|---|
binding | string | "HYPERDRIVE" | 主(快取停用)Hyperdrive 繫結名稱 |
cachedBinding | string | — | 可選的快取啟用繫結用於匿名讀取 |
preferUncachedAfterWriteMs | number | 60000* | 內容發布後在匿名公開讀取中優先使用 binding 的毫秒數 |
migrationConnectionStringEnv | string | CLOUDFLARE_HYPERDRIVE_LOCAL_CONNECTION_STRING_<BINDING> | 包含直接 PostgreSQL origin URL 的環境變數 |
max | number | 5 | Worker 內到 Hyperdrive 的連線池最大大小 |
從快取提供匿名讀取
預設完全停用 Hyperdrive 快取。但使用 GET 或 HEAD 的匿名公開請求可以容忍短暫的過時視窗。如果可以接受,在同一資料庫上執行兩個 Hyperdrive 設定:一個快取關閉(主 binding),一個快取開啟(cachedBinding)。
這是 Cloudflare 記錄的雙設定模式。
修復 PostgreSQL 混合擁有權
如果網站使用了多個 PostgreSQL 使用者,首先選擇主 EmDash 連線將繼續使用的標準角色。備份並在修復擁有權期間停止架構變更。
檢查活動架構中的每個表:
SELECT
n.nspname AS schema_name,
c.relname AS table_name,
pg_get_userbyid(c.relowner) AS owner
FROM pg_class AS c
JOIN pg_namespace AS n ON n.oid = c.relnamespace
WHERE n.nspname = current_schema()
AND c.relkind IN ('r', 'p')
ORDER BY c.relname;
使用架構限定名稱轉移不匹配的物件:
ALTER TABLE emdash.content_taxonomies OWNER TO emdash_app;
ALTER TABLE emdash.ec_posts OWNER TO emdash_app;
ALTER FUNCTION emdash.emdash_media_usage_capture_work() OWNER TO emdash_app;
SQLite
SQLite 使用 Node.js 的內建資料庫驅動,是 Node.js 部署最簡單的選項。
import { sqlite } from "emdash/db";
export default defineConfig({
integrations: [
emdash({
database: sqlite({ url: "file:./data.db" }),
}),
],
});
設定
| 選項 | 型別 | 描述 |
|---|---|---|
url | string | 帶 file: 前綴的檔案路徑 |
檔案路徑
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 預設為所有支援的方言自動執行核心遷移。Astro build 和 sync 還會輸出經過驗證的無密鑰 .emdash/migrations.json,emdash migrate 可以在部署前套用。
參見管理核心資料庫遷移了解目標憑證、CI 序列化、auto/check/manual 執行階段策略和復原指引。
如果資料庫為空(無集合)且設定精靈未完成,EmDash 還會在首次啟動時套用種子檔案。種子從 .emdash/seed.json、package.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" });