面向 Astro 開發者的 EmDash

本頁內容

EmDash 為 Astro 網站新增管理應用程式、資料庫支援的集合、媒體、選單、分類法、設定、修訂和預覽功能。頁面和元件仍然是普通的 Astro 檔案。

EmDash 新增了什麼

功能提供的內容
管理後台/_emdash/admin 進行基於瀏覽器的集合、媒體、選單、分類法和設定管理
資料庫集合在請求時查詢的編輯器管理內容
媒體庫具有範本媒體欄位值的儲存圖片和檔案
草稿、修訂和預覽發布前的編輯工作
選單和小工具區域項目欄位之外的有序、可編輯網站區域
網站設定共用的身分和顯示值,如標題、標語、標誌和分頁大小
外掛掛鉤、路由、儲存和選用的管理擴充功能

這些功能與 Astro 共存,而非取代它。Astro 仍然控制路由、佈局、渲染、樣式和部署轉接器。

EmDash 和 Astro 集合

Astro 內容集合和 EmDash 集合可以共存。對儲存庫擁有的內容使用 Astro 集合,對透過 /_emdash/admin 管理的內容使用 EmDash。

Astro 內容集合EmDash 集合
儲存專案中的檔案SQL 資料庫
編輯儲存庫工作流程EmDash 管理後台
查詢getCollection()getEmDashCollection()
富文本Markdown 或 MDXPortable 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() 範例複製到沙盒套件中。

下一步