EmDash per sviluppatori Astro

In questa pagina

EmDash aggiunge un’applicazione di amministrazione, collezioni salvate in database, media, menu, tassonomie, impostazioni, revisioni e anteprime a un sito Astro. Le pagine e i componenti rimangono file Astro ordinari.

Cosa aggiunge EmDash

FunzionalitàCosa fornisce
AdminGestione basata su browser di collezioni, media, menu, tassonomie e impostazioni su /_emdash/admin
Collezioni databaseContenuti gestiti dall’editor interrogati al momento della richiesta
Libreria mediaImmagini e file archiviati con valori dei 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, tagline, logo e dimensione della paginazione
PluginHook, route, archiviazione ed estensioni admin opzionali

Queste funzionalità vivono accanto ad Astro anziché sostituirlo. Astro controlla ancora il routing, i layout, il rendering, gli stili e l’adattatore di distribuzione.

EmDash e collezioni Astro

Le collezioni di contenuto Astro e le collezioni 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 contenuto AstroCollezione EmDash
ArchiviazioneFile nel progettoDatabase SQL
ModificaFlusso di lavoro del repositoryAdmin EmDash
QuerygetCollection()getEmDashCollection()
Testo riccoMarkdown o MDXPortable Text
ConsegnaBuild-time o live loaderLive loader a runtime

Usa entrambi i sistemi di collezioni quando la proprietà differisce. Ad esempio, un sito prodotto può mantenere le note di rilascio scritte dagli sviluppatori in una collezione di contenuto 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 rimangono separati. EmDash non copia le voci basate su file nel suo database.

Configurare un sito

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

La seguente configurazione ridotta contiene questi elementi richiesti:

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 il target di distribuzione anziché tradurre gli adattatori Node a mano.

Registrare la collezione live

I template espongono il contenuto EmDash attraverso una collezione live 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 archiviati e mappa 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("Impossibile caricare gli articoli", { 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 il contenuto pubblicato. Un filtro status esplicito è utile nel codice autenticato o con anteprima. where accetta campi di contenuto e nomi di tassonomia; vedi Interrogare i contenuti per le forme complete di filtro e paginazione.

Interrogare una voce

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

---
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("Impossibile caricare l'articolo", { 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>

L’entry.id restituito è l’identificatore di route di Astro ed è normalmente lo slug. L’ID del contenuto del database è entry.data.id. Usa data.id con le funzioni di supporto che richiedono un ID di contenuto archiviato.

Usare le funzionalità CMS dinamiche

EmDash esporta helper lato server per dati che non appartengono a una singola voce di 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 sandboxed e nativi hanno strutture di pacchetto diverse. I plugin sandboxed usano emdash-plugin.jsonc più un oggetto src/plugin.ts esportato di default. I plugin nativi esportano una factory di descrittori e createPlugin() costruito con definePlugin().

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

Prossimi passi