O template de blog do EmDash fornece um site Astro funcional com posts, páginas, autores, categorias, tags, busca, comentários, widgets e um feed RSS. Este tutorial cria a versão para Cloudflare, publica um post e acompanha esse post pelo código do template.
Pré-requisitos
Instale o Node.js 22.12 ou posterior e o pnpm antes de começar.
Você só precisa de uma conta Cloudflare quando for fazer o deploy do site. Durante o desenvolvimento local, o template executa no seu computador versões locais do banco de dados e do armazenamento de arquivos.
Criar o scaffold do blog
O comando a seguir cria my-blog a partir do template de blog para Cloudflare e instala as dependências com o pnpm:
npm create emdash@latest my-blog -- --template cloudflare:blog --pm pnpm --yes
O scaffolder também cria um arquivo .env local com uma EMDASH_ENCRYPTION_KEY. O .gitignore gerado exclui o .env do controle de versão. Se o comando informar que a instalação das dependências falhou, entre no diretório do projeto e execute pnpm install antes de continuar.
Inicie o servidor de desenvolvimento local:
cd my-blog
pnpm dev
Abra a URL local exibida no terminal e depois abra /_emdash/admin. Conclua a tela de configuração se esta for a primeira execução. Os dados seed do template criam o modelo de conteúdo e o conteúdo de exemplo durante a configuração.
Entender o modelo de conteúdo
O template define duas coleções em seed/seed.json:
postshabilita rascunhos, revisões, busca e SEO por meio desupports, e habilita comentários separadamente comcommentsEnabled: true;pagesoferece suporte a rascunhos, revisões e busca.
Cada post tem estes campos personalizados:
| Campo | Finalidade |
|---|---|
title | Título obrigatório do post |
featured_image | Imagem opcional exibida com o post |
content | Corpo em Portable Text |
excerpt | Texto curto usado nas listas de posts e como alternativa para os metadados |
O EmDash adiciona campos de sistema, como o ID de conteúdo estável, o slug, o status, os horários de criação e atualização e o horário de publicação. O template também define as taxonomias category e tag para os posts, além de bylines que podem creditar um ou mais autores.
O servidor de desenvolvimento gera emdash-env.d.ts a partir desse esquema. Como resultado, getEmDashCollection("posts") retorna entradas cuja propriedade data é tipada como Post.
Publicar o primeiro post
-
Na barra lateral do administrador, selecione Posts e depois Add New.
-
Informe um título. O EmDash sugere um slug a partir do título; edite-o se a URL pública precisar de outro valor.
-
Adicione um resumo e escreva o corpo no editor Content.
-
Selecione uma imagem destacada da biblioteca de mídia ou envie uma. Adicione um texto alternativo que descreva a função da imagem no post.
-
Atribua um byline, uma categoria e as tags relevantes no painel de configurações.
-
Selecione Save. A entrada se torna um rascunho e o editor abre a URL permanente dela.
-
Selecione Preview e confira a página do post. Volte ao editor e selecione Publish quando o rascunho estiver pronto.
Abra /posts/your-post-slug no site local. O post também aparece na página inicial e no arquivo de posts. Se ele não aparecer, confirme que o editor mostra Published, e não Draft nem Scheduled.
Depois da publicação, as edições são salvas automaticamente em um novo rascunho enquanto o post atual permanece no ar. Selecione Publish changes quando o rascunho revisado deve substituí-lo. O guia de criação de conteúdo explica pré-visualizações, agendamento, revisões e bloqueios de edição.
Seguir a consulta de coleção
A página inicial e o arquivo de posts chamam getEmDashCollection() durante a renderização no servidor. O template ordena os posts no banco de dados pelo campo armazenado published_at:
---
import { getEmDashCollection, getTermsForEntries } from "emdash";
const { entries: posts, cacheHint } = await getEmDashCollection("posts", {
orderBy: { published_at: "desc" },
});
if (Astro.cache?.enabled) Astro.cache.set(cacheHint);
const tagsByEntry = await getTermsForEntries(
"posts",
posts.map((post) => post.data.id),
"tag",
);
---
A consulta de coleção retorna as entradas publicadas por padrão. Ela usa published_at, o nome do campo no banco de dados, para ordenar. A propriedade publishedAt retornada é um Date do JavaScript para renderização.
O helper de taxonomias recebe post.data.id porque as atribuições de taxonomia pertencem ao ID de conteúdo estável. Os links usam post.id, pois esse é o slug voltado para a URL produzido pelo carregador de conteúdo:
<a href={`/posts/${post.id}`}>
<h2>{post.data.title}</h2>
{post.data.excerpt && <p>{post.data.excerpt}</p>}
</a>
O template atual agrupa as buscas de tags com getTermsForEntries() em vez de consultar uma vez para cada post. Os bylines já estão incluídos em post.data.bylines pela consulta de coleção.
Seguir a consulta de post
A rota dinâmica do post lê o slug da URL e chama getEmDashEntry(). O trecho a seguir mostra o caminho essencial de consulta e renderização, enquanto o template completo também trata SEO, bylines, comentários, posts relacionados e widgets:
---
import { decodeSlug, getEmDashEntry } from "emdash";
import { Image, 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("Unable to load post", { status: 500 });
if (!post) return Astro.rewrite("/404");
if (Astro.cache?.enabled) Astro.cache.set(cacheHint);
---
<article>
{post.data.featured_image && <Image image={post.data.featured_image} priority />}
<h1>{post.data.title}</h1>
<PortableText value={post.data.content} />
</article>
O Image lê o valor de mídia selecionado pelo editor e gera uma saída responsiva. O PortableText transforma os dados de blocos armazenados em títulos, parágrafos, links, imagens, blocos de código e nos demais tipos de bloco compatíveis.
Os dois templates de blog definem output: "server" em astro.config.mjs. Essas consultas são executadas quando uma requisição é renderizada, portanto o conteúdo publicado não depende de uma lista estática de rotas criada durante o build.
Usar categorias e tags
O template inclui rotas de arquivo para cada categoria e tag. A rota de uma categoria primeiro resolve o slug do termo e depois filtra os posts por essa taxonomia:
---
import { decodeSlug, getEmDashCollection, getTerm } from "emdash";
const slug = decodeSlug(Astro.params.slug);
const category = slug
? await getTerm("category", slug, { includeCounts: false })
: null;
if (!category) return Astro.rewrite("/404");
const { entries: posts, error } = await getEmDashCollection("posts", {
where: { category: category.slug },
orderBy: { published_at: "desc" },
});
if (error) return new Response("Unable to load posts", { status: 500 });
---
A rota tag usa o mesmo padrão com getTerm("tag", slug) e where: { tag: term.slug }. Os editores gerenciam termos e atribuições no administrador; o guia de taxonomias cobre categorias hierárquicas, tags planas e taxonomias personalizadas.
getEmDashEntry() inclui os termos atribuídos ao post, de modo que a rota de detalhe pode renderizá-los sem outra consulta:
---
const categories = post.data.terms?.category ?? [];
const tags = post.data.terms?.tag ?? [];
---
{categories.map((category) => (
<a href={`/category/${category.slug}`}>{category.label}</a>
))}
{tags.map((tag) => (
<a href={`/tag/${tag.slug}`}>{tag.label}</a>
))}
Adicionar paginação ao arquivo
O arquivo de posts do template renderiza todos os posts publicados. Quando o arquivo crescer, adicione um limit e use paginação por offset para rotas numeradas como /posts/page/2, ou paginação por cursor para um link Older posts. Mantenha orderBy: { published_at: "desc" } inalterado entre as páginas para que a ordem das entradas não mude inesperadamente.
Os exemplos de paginação mostram as duas abordagens e explicam quando escolher cada uma.
Verificar o feed RSS
O template já serve /rss.xml. O endpoint dele lê os 20 posts mais recentes com getEmDashCollection(), formata cada data de publicação e faz o escape do título e do resumo antes de inseri-los no XML. Ele também lê o título e o slogan do site nas configurações do EmDash.
Depois de publicar o post de teste, abra /rss.xml e procure pelo título dele. Se o site for usar uma URL absoluta de produção nos feeds, defina a opção site do Astro antes do deploy; durante o desenvolvimento local, o endpoint recorre à origem da requisição atual.
Neste ponto, o blog tem um fluxo de criação, páginas de post em tempo de execução, arquivos de taxonomias, renderização de mídia e um feed. Continue com Consultar conteúdo para filtros e paginação, ou com Biblioteca de mídia para a edição de recursos e o rastreamento de uso. Para redigir ou editar posts com um assistente de IA, siga Ferramentas de IA.