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
| Recurso | O que fornece |
|---|---|
| Admin | Gerenciamento baseado em navegador de coleções, mídia, menus, taxonomias e configurações em /_emdash/admin |
| Coleções de banco de dados | Conteúdo gerenciado por editores consultado no momento da requisição |
| Biblioteca de mídia | Imagens e arquivos armazenados com valores de campo de mídia para templates |
| Rascunhos, revisões e pré-visualizações | Trabalho editorial antes da publicação |
| Menus e áreas de widgets | Regiões do site ordenadas e editáveis fora dos campos de entrada |
| Configurações do site | Valores compartilhados de identidade e exibição como título, tagline, logo e tamanho da paginação |
| Plugins | Hooks, 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 Astro | Coleção EmDash | |
|---|---|---|
| Armazenamento | Arquivos no projeto | Banco de dados SQL |
| Edição | Fluxo de trabalho do repositório | Admin do EmDash |
| Consulta | getCollection() | getEmDashCollection() |
| Texto rico | Markdown ou MDX | Portable Text |
| Entrega | Build-time ou carregador ao vivo | Carregador 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.