EmDash para desenvolvedores Astro

Nesta página

O EmDash adiciona uma aplicação de administração, coleções armazenadas em banco de dados, mídia, menus, taxonomias, configurações, revisões e pré-visualizações a um site Astro. As páginas e componentes permanecem como arquivos Astro comuns.

O que o EmDash adiciona

RecursoO que fornece
AdminGerenciamento baseado em navegador de coleções, mídia, menus, taxonomias e configurações em /_emdash/admin
Coleções de banco de dadosConteúdo gerenciado por editores consultado no momento da requisição
Biblioteca de mídiaImagens e arquivos armazenados com valores de campo de mídia para templates
Rascunhos, revisões e pré-visualizaçõesTrabalho editorial antes da publicação
Menus e áreas de widgetsRegiões do site ordenadas e editáveis fora dos campos de entrada
Configurações do siteValores compartilhados de identidade e exibição como título, tagline, logo e tamanho da paginação
PluginsHooks, rotas, armazenamento e extensões de administração opcionais

Esses recursos coexistem com o Astro em vez de substituí-lo. O Astro ainda controla o roteamento, layouts, renderização, estilos e o adaptador de implantação.

EmDash e coleções Astro

As coleções de conteúdo do Astro e as coleções do EmDash podem coexistir. Use coleções do Astro para conteúdo de propriedade do repositório e EmDash para conteúdo gerenciado através de /_emdash/admin.

Coleção de conteúdo AstroColeção EmDash
ArmazenamentoArquivos no projetoBanco de dados SQL
EdiçãoFluxo de trabalho do repositórioAdmin do EmDash
ConsultagetCollection()getEmDashCollection()
Texto ricoMarkdown ou MDXPortable Text
EntregaBuild-time ou carregador ao vivoCarregador ao vivo em tempo de execução

Use ambos os sistemas de coleções quando a propriedade difere. Por exemplo, um site de produto pode manter notas de lançamento escritas por desenvolvedores em uma coleção de conteúdo Astro e artigos escritos por editores no EmDash:

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

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

Os dois resultados permanecem separados. O EmDash não copia entradas baseadas em arquivo para seu banco de dados.

Configurar um site

Os templates Node atuais configuram o Astro para saída de servidor, adicionam a integração EmDash e usam os adaptadores SQLite e armazenamento local.

A seguinte configuração reduzida contém essas peças necessárias:

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",
      }),
    }),
  ],
});

O EmDash também fornece templates Cloudflare configurados para D1 e R2. Comece pelo template do alvo de implantação em vez de traduzir os adaptadores Node manualmente.

Registrar a coleção ao vivo

Os templates expõem o conteúdo do EmDash através de uma coleção ao vivo do Astro chamada _emdash:

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

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

getEmDashCollection() e getEmDashEntry() selecionam o tipo de conteúdo solicitado através deste carregador.

Consultar coleções

A seguinte consulta lê as publicações mais recentemente publicadas. orderBy usa nomes de campos armazenados e mapeia cada nome para "asc" ou "desc":

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

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

if (error) return new Response("Não foi possível carregar as publicações", { 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>
))}

Consultas anônimas retornam conteúdo publicado. Um filtro status explícito é útil em código autenticado ou com suporte a pré-visualização. where aceita campos de conteúdo e nomes de taxonomia; veja Consultar conteúdo para as formas completas de filtro e paginação.

Consultar uma entrada

Passe um slug ou ID do banco de dados para getEmDashEntry(). A seguinte rota usa seu slug de 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("Não foi possível carregar a publicação", { 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>

O entry.id retornado é o identificador de rota do Astro e normalmente é o slug. O ID do conteúdo no banco de dados é entry.data.id. Use data.id com helpers que requerem um ID de conteúdo armazenado.

Usar recursos dinâmicos do CMS

O EmDash exporta helpers do servidor para dados que não pertencem a uma única entrada de coleção:

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

Escolher um formato de plugin

Plugins sandboxed e nativos têm estruturas de pacote diferentes. Plugins sandboxed usam emdash-plugin.jsonc mais um objeto src/plugin.ts exportado por padrão. Plugins nativos exportam uma fábrica de descritores e createPlugin() construído com definePlugin().

Leia Escolher um formato de plugin antes de adicionar um plugin. Não copie um exemplo nativo de definePlugin() em um pacote sandboxed.

Próximos passos