EmDash per sviluppatori Astro

In questa pagina

EmDash aggiunge a un sito Astro un’applicazione di amministrazione, collezioni supportate da database, media, menu, tassonomie, impostazioni, revisioni e anteprime. Le pagine e i componenti restano normali file Astro.

Cosa aggiunge EmDash

FunzionalitàCosa offre
AmministrazioneGestione nel browser di collezioni, media, menu, tassonomie e impostazioni su /_emdash/admin
Collezioni su databaseContenuti gestiti dagli editor e interrogati al momento della richiesta
Libreria multimedialeImmagini e file archiviati, con valori di campi media per i template
Bozze, revisioni e anteprimeLavoro editoriale prima della pubblicazione
Menu e aree widgetRegioni del sito ordinate e modificabili, al di fuori dei campi delle voci
Impostazioni del sitoValori condivisi di identità e visualizzazione, come titolo, slogan, logo e dimensione della paginazione
PluginHook, route, archiviazione ed estensioni opzionali dell’amministrazione

Queste funzionalità convivono con Astro anziché sostituirlo. Astro continua a controllare il routing, i layout, il rendering, gli stili e l’adattatore di distribuzione.

EmDash e collezioni Astro

Le collezioni di contenuti di Astro e le collezioni di EmDash possono coesistere. Usa le collezioni Astro per i contenuti di proprietà del repository e EmDash per i contenuti gestiti tramite /_emdash/admin.

Collezione di contenuti AstroCollezione EmDash
ArchiviazioneFile nel progettoDatabase SQL
ModificaFlusso di lavoro del repositoryAmministrazione EmDash
QuerygetCollection()getEmDashCollection()
Rich textMarkdown o MDXPortable Text
DistribuzioneIn fase di build o con un loader liveLoader live a runtime

Usa entrambi i sistemi di collezioni quando la proprietà dei contenuti è diversa. Ad esempio, il sito di un prodotto può mantenere le note di rilascio scritte dagli sviluppatori in una collezione di contenuti Astro e gli articoli scritti dagli editor in EmDash:

---
import { getCollection } from "astro:content";
import { getEmDashCollection } from "emdash";

const [releaseNotes, { entries: articles }] = await Promise.all([
  getCollection("releases"),
  getEmDashCollection("articles", { limit: 3 }),
]);
---

I due risultati restano separati. EmDash non copia le voci basate su file nel proprio database.

Configurare un sito

I template Node attuali configurano Astro per l’output server, aggiungono l’integrazione EmDash e usano gli adattatori SQLite e di archiviazione locale.

La seguente configurazione ridotta contiene questi elementi necessari:

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 fornisce anche template Cloudflare configurati per D1 e R2. Parti dal template per la destinazione di distribuzione invece di convertire a mano gli adattatori Node.

Registrare la collezione live

I template espongono i contenuti di EmDash tramite un’unica collezione live di Astro chiamata _emdash:

import { defineLiveCollection } from "astro:content";
import { emdashLoader } from "emdash/runtime";

export const collections = {
  _emdash: defineLiveCollection({ loader: emdashLoader() }),
};

getEmDashCollection() e getEmDashEntry() selezionano il tipo di contenuto richiesto tramite questo loader.

Interrogare le collezioni

La seguente query legge gli articoli pubblicati più di recente. orderBy usa i nomi dei campi memorizzati e associa ogni nome a "asc" o "desc":

---
import { getEmDashCollection } from "emdash";

const { entries: posts, error, cacheHint } = await getEmDashCollection("posts", {
  orderBy: { published_at: "desc" },
  limit: 10,
});

if (error) return new Response("Could not load posts", { 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>
))}

Le query anonime restituiscono i contenuti pubblicati. Un filtro status esplicito è utile nel codice autenticato o compatibile con l’anteprima. where accetta campi di contenuto e nomi di tassonomie; consulta Interrogare i contenuti per le forme complete di filtri e paginazione.

Interrogare una voce

Passa uno slug o un ID del database a getEmDashEntry(). La seguente route usa lo slug del proprio URL:

---
import { decodeSlug, getEmDashEntry } from "emdash";
import { PortableText } from "emdash/ui";

const slug = decodeSlug(Astro.params.slug);
if (!slug) return Astro.rewrite("/404");

const { entry: post, error, cacheHint } = await getEmDashEntry("posts", slug);
if (error) return new Response("Could not load the post", { status: 500 });
if (!post) return Astro.rewrite("/404");
if (Astro.cache?.enabled) Astro.cache.set(cacheHint);
---

<article>
  <h1>{post.data.title}</h1>
  <PortableText value={post.data.content} />
</article>

L’entry.id restituito è l’identificatore di route di Astro e normalmente è lo slug. L’ID del contenuto nel database è entry.data.id. Usa data.id con gli helper che richiedono un ID di contenuto memorizzato.

Usare le funzionalità CMS dinamiche

EmDash esporta helper lato server per i dati che non appartengono a una singola voce di una collezione:

---
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>

Scegliere un formato di plugin

I plugin in sandbox e i plugin nativi hanno strutture di pacchetto diverse. I plugin in sandbox usano emdash-plugin.jsonc più un oggetto src/plugin.ts esportato come default. I plugin nativi esportano una factory di descrittore e un createPlugin() creato con definePlugin().

Leggi Scegliere un formato di plugin prima di aggiungere un plugin. Non copiare un esempio nativo di definePlugin() in un pacchetto in sandbox.

Prossimi passi