Saltar para o conteúdo
Blume
Português
Esc
navegarabrir⌘Jpré-visualizar
Nesta página

FAQ

Perguntas comuns sobre o Blume — como ele se compara a outras ferramentas de documentação e por que um formatador de Markdown pode colapsar as suas diretivas de callout.

Respostas para perguntas que aparecem com frequência. Falta alguma? Abra uma issue ou pergunte ao assistente na própria página.

Em que o Blume é diferente do Mintlify, do Fumadocs e de outros?

A maioria das ferramentas de documentação fica em um de dois extremos. Plataformas gerenciadas como o Mintlify entregam um resultado polido rápido, mas o build e a hospedagem são o serviço deles — você escreve dentro do sistema deles e publica na infraestrutura deles. Bibliotecas de componentes e starters como o Fumadocs, o Nextra ou o Docusaurus são open-source e flexíveis, mas entregam para você um aplicativo (um projeto Next.js ou React) que você precisa montar, conectar e manter antes e depois de escrever uma única palavra.

O Blume segue um terceiro caminho: o framework é o template. Você aponta ele para uma pasta de Markdown e ele gera e conduz o site inteiro — navegação, busca, temas, imagens Open Graph, SEO e endpoints de IA — sem nenhum app para cuidar. É totalmente open-source e você mesmo pode hospedar, então não existe serviço gerenciado nem dependência de fornecedor, mas também não existe boilerplate para manter.

Blume Mintlify Fumadocs / Nextra / Docusaurus
Modelo Framework de configuração zero; só conteúdo Plataforma hospedada Biblioteca + app que você monta
Código-fonte Open-source (MIT) Núcleo fechado Open-source
Hospedagem Em qualquer lugar — estático ou uma função de servidor A infraestrutura gerenciada deles Em qualquer lugar; você faz o build e publica
Você mantém O seu Markdown O seu Markdown + configuração da plataforma O seu Markdown + o app em volta dele
Renderização Astro; o tema principal não envia nenhum JS de cliente O runtime deles Runtime React/Next.js
Recursos de IA llms.txt, Markdown bruto, Ask AI, MCP — integrados, sem serviço hospedado Integrados (hospedados) Traga os seus

Vale destacar algumas consequências:

  • O resultado é seu. O blume build gera um site simples que você hospeda na Vercel, Netlify, Cloudflare, S3 ou na sua própria máquina. Nada manda dados para casa.
  • Sem dependência de fornecedor, com duas saídas. O seu conteúdo é Markdown portátil, e o blume eject transforma o projeto em um app Astro autônomo que continua usando o pacote blume quando você quiser controle total.
  • Rápido por padrão. O tema principal não usa React e renderiza HTML estático, então as páginas vão bem nos Core Web Vitals sem ajuste nenhum. Você adota os recursos de servidor (Ask AI, MCP) só quando precisa deles.
  • Configuração com segurança de tipos. O blume.config.ts e cada meta.ts são TypeScript real validado por um schema — e não YAML de tipagem frouxa.

Veja Por que o Blume existe para a versão mais longa.

O Blume é gratuito e open-source?

Sim — o Blume tem licença MIT e é gratuito. Você instala o pacote blume, mantém o seu conteúdo no seu próprio repositório e hospeda o build onde quiser. Não tem plano pago, nem preço por usuário, nem conta para criar. O código-fonte está no GitHub.

Preciso saber Astro, React ou Tailwind?

Não. Uma pasta de Markdown é um site completo — navegação, busca e temas são inferidos ou definidos com um punhado de tokens. Você só recorre à stack por baixo quando quiser personalizar: ilhas interativas (React), substituições de componentes ou tokens de tema (Tailwind). E, mesmo assim, o blume.config.ts é tipado, então o seu editor te guia.

Posso usar componentes React e MDX?

Sim. Qualquer página pode ser .md ou .mdx, e o MDX permite inserir os componentes integrados sem imports. Você também pode adicionar as suas próprias ilhas .tsx/.jsx — o Blume ativa o React automaticamente só nas páginas que as usam, então o tema principal continua livre de JavaScript em todo o resto.

Onde posso publicar?

Em qualquer lugar. O blume build gera HTML estático por padrão, que você pode servir de qualquer hospedagem estática ou CDN — Vercel, Netlify, Cloudflare Pages, GitHub Pages, S3 ou o seu próprio servidor. Os recursos exclusivos de servidor (Ask AI, o servidor MCP, renderização sob demanda) mudam o build para uma função de servidor por meio de um adaptador para Vercel, Node, Netlify ou Cloudflare. Veja Publicação.

A busca precisa de um serviço hospedado?

Não. O Orama monta um índice local que funciona tanto em desenvolvimento quanto em produção, sem nada para hospedar ou pagar. Para sites muito grandes, o Pagefind está a uma flag de distância. De qualquer forma, o índice vai junto como parte do seu site.

Como personalizo a aparência?

Comece pelos tokens de tema — cor de destaque, fontes, raio e um theme.css para tudo o mais que o Tailwind conseguir expressar. Vá além substituindo componentes integrados ou adicionando páginas personalizadas. Quando você quiser o projeto Astro em si, o blume eject entrega um app autônomo que continua usando o pacote blume.

Por que o oxfmt / Ultracite está colapsando as minhas diretivas?

Se você formata o seu Markdown com o Ultracite (que roda oxlint + oxfmt) — como o próprio Blume faz — talvez note que as diretivas de contêiner ficam achatadas em uma única linha depois de uma passagem de formatação:

:::note
Regenerate the project with blume dev.
:::

vira

:::note Regenerate the project with blume dev. :::

Uma vez que a linha de abertura :::note é unida à prosa, ela deixa de ser uma diretiva, então é renderizada como texto literal em vez de um callout.

Por que isso acontece

Isso é um bug no formatador de Markdown do oxfmt (herdado do printer de Markdown do Prettier — veja prettier/prettier#19040). Quando ele quebra a prosa, trata as linhas de fence ::: como texto comum e junta com a linha vizinha, quebrando a diretiva. Isso afeta todos os tipos de diretiva de contêiner — :::note, :::tip, :::info, :::warning, :::danger, :::success.

Reportamos o problema upstream em oxc-project/oxc#24096; até ser corrigido lá, o patch abaixo é a solução alternativa.

A correção

Aplique um patch no oxfmt para que ele preserve a quebra de linha que fica encostada em um fence :::. O Blume inclui a mesma correção no próprio repositório, e você pode aplicá-la em qualquer projeto.

  1. Salve o patch como patches/oxfmt@0.66.0.patch:

    diff --git a/dist/markdown-BgZGxhM2.js b/dist/markdown-BgZGxhM2.js
    index 859231f9387a50df16419bc22b5268c4e446ddbc..dcc0ffda6f71adb27a03e3918a3db6fc7a58ffe9 100644
    --- a/dist/markdown-BgZGxhM2.js
    +++ b/dist/markdown-BgZGxhM2.js
    @@ -4872,7 +4872,43 @@ function lu(e, t, r) {
     		case "sentence": return Oh(e, r);
     		case "word": return t.parser !== "mdx" ? zh(e, t) : Uh(e);
     		case "whitespace": {
    -			let { next: a } = e, u = a && /^>|^(?:[*+-]|#{1,6}|\d+[).])$/.test(a.value) && !NE(e) && !(t.proseWrap === "preserve" && RE(e)) ? "never" : t.proseWrap;
    +			let { next: a, previous: oxfmtFencePrev } = e;
    +			// Preserve line breaks that sit directly against a `:::` container
    +			// directive fence, so `proseWrap: "never"` keeps the opening/closing
    +			// fence on their own lines instead of joining them into the prose (which
    +			// breaks the directive). Ordinary prose still wraps per proseWrap.
    +			// See prettier/prettier#19040.
    +			let oxfmtIsFence = (w) => w != null && typeof w.value === "string" && w.value.startsWith(":::");
    +			// A titled directive (`:::warning[Heads up]`) parses its `[title]` as a
    +			// linkReference between two sentence nodes at the paragraph level: the
    +			// fence word ends the sentence before the reference, and the body's
    +			// leading newline opens the sentence after it. So when this whitespace
    +			// starts its sentence, climb to the paragraph and check whether the two
    +			// preceding siblings are a (link) reference and a sentence ending in a
    +			// `:::` fence word.
    +			let oxfmtPrevIsTitledFence = !1;
    +			if (oxfmtFencePrev == null && e.index === 0 && e.grandparent != null && Array.isArray(e.grandparent.children)) {
    +				let oxfmtSibs = e.grandparent.children, oxfmtSentIdx = oxfmtSibs.indexOf(e.parent);
    +				if (oxfmtSentIdx >= 2) {
    +					let oxfmtLink = oxfmtSibs[oxfmtSentIdx - 1], oxfmtBefore = oxfmtSibs[oxfmtSentIdx - 2];
    +					let oxfmtLastWord = oxfmtBefore && oxfmtBefore.type === "sentence" && Array.isArray(oxfmtBefore.children) ? oxfmtBefore.children[oxfmtBefore.children.length - 1] : null;
    +					oxfmtPrevIsTitledFence = oxfmtLink != null && (oxfmtLink.type === "linkReference" || oxfmtLink.type === "link") && oxfmtIsFence(oxfmtLastWord);
    +				}
    +			}
    +			// The plain-markdown parser keeps a titled fence's `[title]` as literal
    +			// words, so the whole directive is one sentence. For a newline
    +			// whitespace, walk back to the start of its visual line within the
    +			// sentence; a line led by a `:::` word is a fence whose break must stay.
    +			if (!oxfmtPrevIsTitledFence && e.node.value.includes("\n") && e.parent != null && Array.isArray(e.parent.children)) {
    +				let oxfmtLineFirst = null;
    +				for (let oxfmtJ = e.index - 1; oxfmtJ >= 0; oxfmtJ--) {
    +					let oxfmtSib = e.parent.children[oxfmtJ];
    +					if (oxfmtSib.type === "whitespace" && typeof oxfmtSib.value === "string" && oxfmtSib.value.includes("\n")) break;
    +					oxfmtLineFirst = oxfmtSib;
    +				}
    +				oxfmtPrevIsTitledFence = oxfmtIsFence(oxfmtLineFirst);
    +			}
    +			let u = oxfmtIsFence(oxfmtFencePrev) || oxfmtPrevIsTitledFence || oxfmtIsFence(a) ? "preserve" : a && /^>|^(?:[*+-]|#{1,6}|\d+[).])$/.test(a.value) && !NE(e) && !(t.proseWrap === "preserve" && RE(e)) ? "never" : t.proseWrap;
     			return ou(e, n.value, u, !1, t);
     		}
     		case "emphasis": {
  2. Registre ele no patchedDependencies do seu gerenciador de pacotes. Com o Bun ou o pnpm, adicione ao package.json:

    {
      "patchedDependencies": {
        "oxfmt@0.66.0": "patches/oxfmt@0.66.0.patch"
      }
    }
  3. Reinstale para que o patch seja aplicado:

    npm install
    pnpm install
    yarn install
    bun install

Esta página foi útil?