EmDash 為 Astro 網站新增管理應用程式、資料庫支援的集合、媒體、選單、分類法、設定、修訂和預覽功能。頁面和元件仍然是普通的 Astro 檔案。
EmDash 新增了什麼
| 功能 | 提供的內容 |
|---|---|
| 管理後台 | 在 /_emdash/admin 進行基於瀏覽器的集合、媒體、選單、分類法和設定管理 |
| 資料庫集合 | 在請求時查詢的編輯器管理內容 |
| 媒體庫 | 具有範本媒體欄位值的儲存圖片和檔案 |
| 草稿、修訂和預覽 | 發布前的編輯工作 |
| 選單和小工具區域 | 項目欄位之外的有序、可編輯網站區域 |
| 網站設定 | 共用的身分和顯示值,如標題、標語、標誌和分頁大小 |
| 外掛 | 掛鉤、路由、儲存和選用的管理擴充功能 |
這些功能與 Astro 共存,而非取代它。Astro 仍然控制路由、佈局、渲染、樣式和部署轉接器。
EmDash 和 Astro 集合
Astro 內容集合和 EmDash 集合可以共存。對儲存庫擁有的內容使用 Astro 集合,對透過 /_emdash/admin 管理的內容使用 EmDash。
| Astro 內容集合 | EmDash 集合 | |
|---|---|---|
| 儲存 | 專案中的檔案 | SQL 資料庫 |
| 編輯 | 儲存庫工作流程 | EmDash 管理後台 |
| 查詢 | getCollection() | getEmDashCollection() |
| 富文本 | Markdown 或 MDX | Portable Text |
| 交付 | 建置時或即時載入器 | 執行時即時載入器 |
當所有權不同時使用兩個集合系統。例如,產品網站可以將開發者撰寫的版本說明保存在 Astro 內容集合中,將編輯器撰寫的文章保存在 EmDash 中:
---
import { getCollection } from "astro:content";
import { getEmDashCollection } from "emdash";
const [releaseNotes, { entries: articles }] = await Promise.all([
getCollection("releases"),
getEmDashCollection("articles", { limit: 3 }),
]);
---
兩個結果保持分離。EmDash 不會將基於檔案的項目複製到其資料庫中。
設定網站
目前的 Node 範本將 Astro 設定為伺服器輸出,新增 EmDash 整合,並使用 SQLite 和本機儲存轉接器。
以下簡化設定包含這些必需部分:
import node from "@astrojs/node";
import react from "@astrojs/react";
import { defineConfig } from "astro/config";
import emdash, { local } from "emdash/astro";
import { sqlite } from "emdash/db";
export default defineConfig({
output: "server",
adapter: node({ mode: "standalone" }),
integrations: [
react(),
emdash({
database: sqlite({ url: "file:./data.db" }),
storage: local({
directory: "./uploads",
baseUrl: "/_emdash/api/media/file",
}),
}),
],
});
EmDash 還提供了為 D1 和 R2 設定的 Cloudflare 範本。請從部署目標的範本開始,而不是手動轉換 Node 轉接器。
註冊即時集合
範本透過一個名為 _emdash 的 Astro 即時集合公開 EmDash 內容:
import { defineLiveCollection } from "astro:content";
import { emdashLoader } from "emdash/runtime";
export const collections = {
_emdash: defineLiveCollection({ loader: emdashLoader() }),
};
getEmDashCollection() 和 getEmDashEntry() 透過此載入器選擇請求的內容類型。
查詢集合
以下查詢讀取最近發布的文章。orderBy 使用儲存的欄位名稱,並將每個名稱對應到 "asc" 或 "desc":
---
import { getEmDashCollection } from "emdash";
const { entries: posts, error, cacheHint } = await getEmDashCollection("posts", {
orderBy: { published_at: "desc" },
limit: 10,
});
if (error) return new Response("無法載入文章", { status: 500 });
if (Astro.cache?.enabled) Astro.cache.set(cacheHint);
---
{posts.map((post) => (
<article>
<h2><a href={`/posts/${post.id}`}>{post.data.title}</a></h2>
</article>
))}
匿名查詢返回已發布內容。明確的 status 篩選器在經過身分驗證或支援預覽的程式碼中很有用。where 接受內容欄位和分類法名稱;完整的篩選和分頁形式請參見查詢內容。
查詢單一項目
將 slug 或資料庫 ID 傳遞給 getEmDashEntry()。以下路由使用其 URL slug:
---
import { decodeSlug, getEmDashEntry } from "emdash";
import { PortableText } from "emdash/ui";
const slug = decodeSlug(Astro.params.slug);
if (!slug) return Astro.redirect("/404");
const { entry: post, error, cacheHint } = await getEmDashEntry("posts", slug);
if (error) return new Response("無法載入文章", { status: 500 });
if (!post) return Astro.redirect("/404");
if (Astro.cache?.enabled) Astro.cache.set(cacheHint);
---
<article>
<h1>{post.data.title}</h1>
<PortableText value={post.data.content} />
</article>
返回的 entry.id 是 Astro 的路由識別碼,通常是 slug。資料庫內容 ID 是 entry.data.id。在需要儲存內容 ID 的輔助函式中使用 data.id。
使用動態 CMS 功能
EmDash 匯出伺服器輔助函式,用於不屬於單一集合項目的資料:
---
import { getMenu, getSiteSettings } from "emdash";
import { WidgetArea } from "emdash/ui";
const [menu, settings] = await Promise.all([
getMenu("primary"),
getSiteSettings(),
]);
---
<header>
<a href="/">{settings.title}</a>
<nav>
{menu?.items.map((item) => <a href={item.url}>{item.label}</a>)}
</nav>
</header>
<main><slot /></main>
<aside><WidgetArea name="sidebar" /></aside>
選擇外掛格式
沙盒外掛和原生外掛有不同的套件結構。沙盒外掛使用 emdash-plugin.jsonc 加上預設匯出的 src/plugin.ts 物件。原生外掛匯出描述符工廠和使用 definePlugin() 建構的 createPlugin()。
新增外掛前請閱讀選擇外掛格式。不要將原生 definePlugin() 範例複製到沙盒套件中。