SQLite
Desenvolvimento local com sqlite({ url: "file:./data.db" })
O EmDash integra-se profundamente com o Astro para oferecer uma experiência completa de CMS. Esta página explica as principais decisões arquiteturais e como as peças se encaixam.
┌──────────────────────────────────────────────────────────────────┐│ Seu site Astro ││ ││ ┌────────────────────────────────────────────────────────────┐ ││ │ Integração do EmDash │ ││ │ │ ││ │ ┌──────────────┐ ┌──────────────┐ ┌───────────────┐ │ ││ │ │ APIs │ │ Painel │ │ Plugins │ │ ││ │ │ de conteúdo │ │ admin │ │ │ │ ││ │ └──────────────┘ └──────────────┘ └───────────────┘ │ ││ │ │ ││ │ ┌──────────────────────────────────────────────────────┐ │ ││ │ │ Camada de dados │ │ ││ │ │ Banco de dados (D1/SQLite) + Armazenamento (R2/S3) │ │ ││ │ └──────────────────────────────────────────────────────┘ │ ││ └────────────────────────────────────────────────────────────┘ ││ ││ ┌────────────────────────────────────────────────────────────┐ ││ │ Framework Astro │ ││ │ Live Collections · Middleware · Sessions │ ││ └────────────────────────────────────────────────────────────┘ │└──────────────────────────────────────────────────────────────────┘O EmDash funciona como uma integração do Astro. Ele injeta rotas para o painel administrativo e APIs REST, fornece um carregador de conteúdo para Coleções ao Vivo e gerencia migrações de banco de dados e conexões de armazenamento.
Diferente dos CMS tradicionais que definem esquema em código, o EmDash armazena definições de esquema no próprio banco de dados. Duas tabelas do sistema rastreiam a estrutura do seu conteúdo:
_emdash_collections — Metadados da coleção (slug, rótulo, recursos)_emdash_fields — Definições de campo para cada coleçãoQuando você cria uma coleção “produtos” com campos de título e preço via a interface administrativa, o EmDash:
_emdash_collections e _emdash_fieldsALTER TABLE para criar ec_products com as colunas apropriadasEste design permite:
Cada coleção obtém sua própria tabela SQLite com o prefixo ec_:
-- Criada quando a coleção "posts" é adicionadaCREATE TABLE ec_posts ( -- Colunas do sistema (sempre presentes) id TEXT PRIMARY KEY, slug TEXT UNIQUE, status TEXT DEFAULT 'draft', -- draft, published, scheduled author_id TEXT, created_at TEXT DEFAULT (datetime('now')), updated_at TEXT DEFAULT (datetime('now')), published_at TEXT, deleted_at TEXT, -- Exclusão lógica version INTEGER DEFAULT 1, -- Bloqueio otimista
-- Colunas de conteúdo (das suas definições de campo) title TEXT NOT NULL, content JSON, -- Portable Text excerpt TEXT);Por que tabelas por coleção em vez de uma única tabela de conteúdo com JSON?
O EmDash usa as Coleções ao Vivo do Astro 6 para servir conteúdo em tempo de execução. As alterações de conteúdo ficam disponíveis imediatamente sem reconstruções estáticas.
O emdashLoader() implementa a interface LiveLoader do Astro:
import { defineLiveCollection } from "astro:content";import { emdashLoader } from "emdash/runtime";
export const collections = { _emdash: defineLiveCollection({ loader: emdashLoader() }),};Consulte o conteúdo usando as funções wrapper fornecidas:
import { getEmDashCollection, getEmDashEntry } from "emdash";
// Obter todos os posts publicadosconst { entries: posts } = await getEmDashCollection("posts");
// Obter rascunhosconst { entries: drafts } = await getEmDashCollection("posts", { status: "draft",});
// Obter uma única entrada por slugconst { entry: post } = await getEmDashEntry("posts", "my-post-slug");A integração do EmDash usa a API injectRoute do Astro para adicionar rotas administrativas e de API:
| Padrão de Caminho | Propósito |
|---|---|
/_emdash/admin/[...path] | SPA do painel administrativo |
/_emdash/api/manifest | Manifesto administrativo (coleções, plugins) |
/_emdash/api/content/[collection] | CRUD para entradas de conteúdo |
/_emdash/api/media/* | Operações da biblioteca de mídia |
/_emdash/api/schema/* | Gerenciamento de esquema |
/_emdash/api/settings | Configurações do site |
/_emdash/api/menus/* | Menus de navegação |
/_emdash/api/taxonomies/* | Categorias, tags, taxonomias personalizadas |
As rotas são injetadas a partir do pacote emdash — nada é copiado para o seu projeto.
O EmDash usa Kysely para consultas SQL com segurança de tipos em todos os bancos de dados suportados:
SQLite
Desenvolvimento local com sqlite({ url: "file:./data.db" })
D1
SQL serverless da Cloudflare com d1({ binding: "DB" })
libSQL
SQLite remoto com libsql({ url: "...", authToken: "..." })
A configuração do banco de dados é passada para a integração em astro.config.mjs:
import { defineConfig } from "astro/config";import emdash from "emdash/astro";import { sqlite } from "emdash/db";import { local } from "emdash/storage";
export default defineConfig({ integrations: [ emdash({ database: sqlite({ url: "file:./data.db" }), storage: local({ directory: "./uploads", baseUrl: "/_emdash/api/media/file", }), }), ],});Os arquivos de mídia são armazenados separadamente do banco de dados. O EmDash suporta:
Os uploads usam URLs assinadas para uploads diretos do cliente para o armazenamento, contornando os limites de tamanho do corpo dos Workers.
Os plugins estendem o EmDash através de um sistema de hooks inspirado no WordPress:
content:beforeSave, content:afterSave, content:beforeDelete, content:afterDeletemedia:beforeUpload, media:afterUploadOs plugins podem ser executados em dois modos:
import { seoPlugin } from "@emdash-cms/plugin-seo";
emdash({ plugins: [seoPlugin({ maxTitleLength: 60 })],});Uma solicitação típica de conteúdo segue este caminho:
Astro recebe a solicitação
Seu componente de página é executado.
O conteúdo é consultado
getEmDashCollection() chama getLiveCollection() do Astro.
O carregador é executado
emdashLoader consulta a tabela ec_* apropriada via Kysely.
Os dados são retornados
As entradas são mapeadas para o formato do Astro com id, slug e data.
A página é renderizada
Seu componente recebe o conteúdo e renderiza o HTML.
Para solicitações administrativas:
O middleware autentica
Ele valida o token de sessão.
A rota da API processa a solicitação
As operações CRUD passam pelos repositórios.
Os hooks são acionados
beforeCreate, afterUpdate e os demais hooks são executados.
O banco de dados é atualizado
O Kysely executa o SQL necessário.
A resposta é retornada
O SPA administrativo recebe uma resposta JSON.
O EmDash gera módulos virtuais no momento da compilação para configurar o runtime:
| Módulo | Propósito |
|---|---|
virtual:emdash/config | Configuração de banco de dados e armazenamento |
virtual:emdash/dialect | Fábrica de dialeto de banco de dados |
virtual:emdash/plugin-admins | Importações estáticas para interfaces administrativas de plugins |
Essa abordagem garante que os bundlers possam resolver e realizar tree-shake adequadamente no código dos plugins.
Coleções
Aprenda sobre coleções de conteúdo e tipos de campo.
Modelo de Conteúdo
Painel Administrativo
Explore a arquitetura do painel administrativo.