Saltar para o conteúdo
Blume
Esc
↑↓navegar↵abrir⌘Jpré-visualizar
Nesta página

Busca

Busca do lado do cliente que funciona imediatamente, sem chaves de API, além de adaptadores hospedados e semânticos para os quais você pode migrar conforme sua documentação cresce.

O Blume inclui busca local sem infraestrutura hospedada e sem chaves de API. Ela roda no navegador, funciona tanto em blume dev quanto em blume build e indexa apenas o seu conteúdo real — elementos de navegação e páginas excluídas são ignorados. Quando ela deixar de ser suficiente, você pode migrar para um backend hospedado ou semântico sem mudar a aparência ou o comportamento da busca — só muda o adaptador que você passa para search.

Cada backend é um adaptador importado de blume/search: Orama (o padrão), FlexSearch, Pagefind, Algolia, Orama Cloud, Typesense e Mixedbread. Cada adaptador cuida das próprias opções, da sua dependência de runtime e dos segredos de que precisa. Orama e Pagefind já vêm com o Blume; o SDK de cada um dos outros adaptadores é uma dependência peer opcional que você mesmo instala, então escolher um backend nunca traz os outros junto. Se ele estiver faltando, o blume build para antes de o Vite rodar, indicando o pacote e o comando que o instala, e o blume doctor também acusa a falta.

import { defineConfig } from "blume";
import { algolia } from "blume/search";

export default defineConfig({
  search: algolia({
    appId: "YOUR_APP_ID",
    apiKey: "YOUR_SEARCH_ONLY_KEY",
    indexName: "docs",
  }),
});

Um adaptador é uma descrição simples do backend — não um cliente ativo —, então o Blume consegue embuti-lo no site gerado e em um projeto ejetado. Passe o adaptador diretamente ou use a forma de objeto quando também quiser definir as opções de links populares, de indexação ou de analytics ao lado dele:

import { pagefind } from "blume/search";

search: {
  provider: pagefind(),
  popular: [{ href: "/guides/getting-started", icon: "rocket", label: "Getting started" }],
  indexing: { includeCodeBlocks: true },
},

Abra a busca pelo ícone de busca no cabeçalho, com ⌘K (ou Ctrl K) ou pressionando / quando não estiver digitando em um campo. Esc a fecha, e ⌘J (ou Ctrl J) alterna o painel de pré-visualização de resultados.

As consultas correspondem a títulos, descrições e texto do corpo das páginas, com as correspondências de título classificadas em primeiro lugar e as descrições acima do corpo.

Antes de o leitor digitar uma consulta, o diálogo de busca exibe uma lista Popular. Por padrão, são as seis primeiras páginas da barra lateral — o que, em sites com várias abas, muitas vezes destaca a seção errada. Em vez disso, fixe os links que você quiser:

search: {
  popular: [
    { href: "/guides/getting-started", icon: "rocket", label: "Getting started" },
    { href: "/guides/install", icon: "download", label: "Install" },
    { href: "/concepts/overview", label: "Overview" },
  ],
},

Cada entrada recebe um href (rota interna ou URL externa) e um label, além de um icon opcional — o nome de um ícone integrado, um caminho ou URL de imagem, ou um SVG inline (as mesmas entradas dos ícones de navegação), com um glifo de arquivo como padrão. Omita popular ou deixe a lista vazia para manter o comportamento padrão baseado na barra lateral. Deixar provider de fora da forma de objeto mantém o adaptador Orama padrão.

Escreva o href como se o site estivesse montado na raiz — um basePath é aplicado automaticamente, igual em navigation.featured. URLs externas passam sem alteração.

O que é indexado

Para Orama, FlexSearch, Algolia, Orama Cloud e Typesense — e para a ferramenta search_docs do servidor MCP —, o Blume indexa o título, a descrição e o corpo de cada página reduzido a texto simples: blocos de código, imagens e marcação são removidos, para que os resultados permaneçam relevantes. Esses índices são construídos a partir dos seus arquivos-fonte, então são idênticos em desenvolvimento e em produção. Já o Pagefind indexa o HTML compilado, e o Mixedbread sincroniza seu Markdown bruto, então ambos sempre buscam no código.

Se a sua documentação depende de exemplos de código para termos pesquisáveis como opções, métodos ou nomes de erros, ative os blocos de código cercados nos índices construídos a partir da fonte:

search: {
  indexing: {
    includeCodeBlocks: true,
  },
},

O corpo e o título de cada bloco cercado (blume.config.ts, acima) se tornam pesquisáveis; a linguagem e os marcadores do bloco, não. Em páginas .mdx, o índice lê os componentes como o texto que eles exibem — o título de um Card, o rótulo de uma Tab, as descrições de uma TypeTable — usando os mesmos serializadores das superfícies de agente, então uma entrada em agents.markdownComponents cobre também os seus próprios componentes. A opção não tem efeito no Pagefind nem no Mixedbread. Espere que o índice cresça junto com o conteúdo cercado — o índice do cliente é enviado a todos os leitores, os adaptadores hospedados armazenam mais (a sincronização do Algolia divide uma página longa em vários registros) e uma correspondência dentro de um bloco cercado exibe o código achatado no trecho do resultado.

Em um site com versionamento, os resultados ficam restritos por padrão à versão que está sendo visualizada, com um botão “Todas as versões” no rodapé do diálogo (memorizado por leitor). As correspondências de outras versões indicam sua versão na linha. Orama, FlexSearch, Algolia e Typesense respeitam esse escopo — os registros hospedados carregam uma faceta version, com a documentação atual enviada como "current". Pagefind, Orama Cloud e Mixedbread não restringem por versão: os resultados deles abrangem todas as versões, e o diálogo não exibe o botão.

Em um site com i18n, os resultados ficam restritos por padrão ao idioma da página que está sendo visualizada, com um botão “Todos os idiomas” ao lado (também memorizado por leitor). Orama e FlexSearch filtram o próprio índice no navegador, e Algolia, Orama Cloud e Typesense filtram pelo locale que cada registro carrega. O Pagefind mantém um índice por idioma: ele busca no índice do idioma da página e, com “Todos os idiomas”, incorpora os demais, nos quais passa a buscar com a redução de palavras ao radical (stemming) do idioma da página. O Mixedbread não restringe por idioma: os resultados dele abrangem todos os idiomas, e o diálogo não exibe o botão.

Tags

Adicione search.tags ao frontmatter de uma página para rotulá-la para um adaptador hospedado. A primeira tag da página é enviada como um campo tag no registro dela no Algolia, no Orama Cloud e no Typesense, onde você pode filtrar por ela no painel do provedor ou na sua própria interface de busca. O Typesense declara tag como faceta; no Algolia, adicione-a você mesmo aos attributesForFaceting do índice, e a sincronização a mantém lá.

search:
  tags: [api, reference]

O diálogo de busca não lê as tags. Os filtros dele agrupam os resultados pela seção da barra lateral em que cada página está e aparecem com o Orama e o FlexSearch, cujos índices carregam a seção de cada página.

Classificação

Dois campos do frontmatter definem como uma página é classificada. search.keywords lista termos extras pelos quais a página é encontrada, mesmo quando o texto dela não os usa. Isso é útil para uma página que os leitores procuram por um nome antigo, uma sigla ou um termo de um concorrente. search.boost multiplica a relevância da página: acima de 1, ela sobe; abaixo de 1, ela desce.

search:
  keywords: [install, setup, getting started]
  boost: 3

Reserve os boosts para as poucas páginas de que os leitores mais precisam, como um guia de início rápido ou uma visão geral, com valores de 2 a 5. Use um valor abaixo de 1, como 0.5, para uma página que deve ficar abaixo de outras com correspondência igualmente boa, como um guia legado. Mantenha os boosts abaixo de 10: acima disso, o boost abafa o quanto a página corresponde à busca, e ela passa a liderar buscas com as quais mal corresponde.

O quanto um boost move uma página depende do adaptador:

  • O Orama (o padrão) e o FlexSearch multiplicam cada correspondência pelo boost da página antes de ordenar, então um boost de 3 conta exatamente três vezes. A busca do servidor MCP e a do assistente classificam da mesma forma.
  • O Pagefind dá mais peso ao texto de uma página com boost. Ele atenua correspondências repetidas, então o ganho é menor que o multiplicador: um boost de 5 classifica a página mais acima, mas algo mais próximo do dobro. O Pagefind trata um boost acima de 10 como 10.
  • O Algolia ordena pelo boost entre resultados com correspondência mais ou menos equivalente, então um boost desempata casos próximos sem colocar uma correspondência mais fraca acima de uma forte. A sincronização adiciona desc(boost) ao ranking personalizado do índice, depois de qualquer ranking que você tenha definido.
  • O Typesense ordena pela relevância e, depois, pelo boost entre resultados com a mesma pontuação de relevância, então um boost resolve empates sem colocar uma correspondência mais fraca acima de uma forte.
  • O Orama Cloud busca um conjunto maior de resultados e os reordena pela relevância multiplicada pelo boost.
  • O Mixedbread busca no seu próprio store, para o qual o Blume não envia nada, então boosts e palavras-chave não chegam até ele.

As palavras-chave são pesquisadas em todos os adaptadores, exceto no Mixedbread.

Análise de buscas

Com um adaptador de analytics configurado, a busca informa o que os leitores procuram. Uma consulta é registrada quando se estabiliza, após um segundo sem digitação ou quando o leitor escolhe um resultado ou fecha o diálogo, como um evento search com a query, o número de results e o path de onde a busca foi feita. Uma consulta sem resultados aparece com results: 0, então filtrar por esse valor lista o que a sua documentação ainda não cobre. Escolher um resultado envia um evento search_select com a query, a position do resultado (começando em 1), a url dele e o path de onde ele foi escolhido, para medir a taxa de cliques.

As consultas são enviadas exatamente como foram digitadas, com até 100 caracteres. A sua ferramenta de analytics as recebe da mesma forma que recebe os termos de busca de qualquer página, então trate-as como entrada do leitor: um leitor pode colar um endereço de e-mail ou uma chave na caixa, e o Google Analytics e o Plausible proíbem o envio de dados pessoais. Para manter o texto das consultas longe dos seus provedores, desative-o:

search: {
  analytics: { queries: false },
},

Os eventos search e search_select passam então a carregar queryChars, o tamanho da consulta, no lugar de query. O texto trafega apenas no evento DOM blume:track, como query em detail.props, para que um listener escrito por você possa encaminhá-lo para onde você decidir, da mesma forma que o assistente lida com as perguntas. Com o consentimento de cookies ativado, apenas os leitores que permitiram analytics são contabilizados.

Adaptadores

Os adaptadores do lado do cliente dispensam chaves e não precisam de opções — seus clientes são configurados a partir de i18n (ou, no caso do Pagefind, a partir do HTML compilado), então uma chave desconhecida é rejeitada pela validação da configuração em vez de ser ignorada. Os hospedados recebem credenciais públicas (seguras para enviar ao navegador) e leem sua chave de administração secreta de uma variável de ambiente no momento do build — o segredo nunca chega à configuração nem ao bundle do cliente. Toda opção que você passa para um adaptador hospedado é mantida exatamente como está e repassada ao cliente de busca dele no navegador (ou, no caso do Mixedbread, ao endpoint de busca), então uma opção que o Blume não nomeia ainda chega ao SDK — o liteClient do Algolia, o Client do Typesense ou o OramaClient. Essas opções precisam ser valores JSON — o descritor é embutido no projeto gerado como um literal, então uma função, undefined ou um bigint faz a validação da configuração falhar apontando o caminho da opção, em vez de se perder no trajeto.

Algolia, Orama Cloud e Typesense enviam suas páginas para o índice deles ao final de cada blume build. Quando a chave de administração não está definida, o build emite um aviso e pula o envio, então um build sem segredos, como um local, continua funcionando. Quando a chave está definida e o envio falha (uma chave errada, um host inacessível, um registro rejeitado), o build falha com BLUME_SEARCH_SYNC_FAILED em vez de publicar com um índice que ele não atualizou.

Orama (padrão)

O mecanismo padrão do Blume. Ele constrói um índice JSON servido em /blume-search.json e o consulta no navegador — instantâneo, do lado do cliente e ativo em blume dev enquanto você edita. Sem chaves, sem serviço. Omitir search por completo já o seleciona; escreva-o só quando quiser deixar isso explícito:

import { orama } from "blume/search";

search: orama(),

Escritas não latinas

O tokenizador padrão mantém apenas letras latinas e dígitos, então, sem isso, textos em qualquer outra escrita — japonês, chinês, coreano e tailandês, mas igualmente russo, grego, hebraico e híndi — não produziriam nenhuma correspondência. O Blume cuida disso para você: páginas em um idioma que corresponde a uma escrita não latina são indexadas com um tokenizador que segmenta palavras (baseado no Intl.Segmenter, nativo do navegador e do Node). Basta declarar os idiomas do seu site:

i18n: {
  defaultLocale: "ja",
  locales: [{ code: "ja", label: "日本語" }],
}

Os mesmos tokenizadores atendem o diálogo de busca, a ferramenta search_docs do servidor MCP e o embasamento do assistente. Quem decide é a escrita, não o nome do idioma — az-Cyrl é segmentado, enquanto sr-Latn não é. Com um padrão não latino, todas as páginas compartilham o tokenizador do idioma padrão: as palavras latinas sobrevivem intactas à segmentação, então páginas em inglês permanecem pesquisáveis ao lado do idioma padrão. Com um padrão latino, as páginas em escrita latina mantêm o tokenizador padrão e cada tradução em uma escrita não latina recebe o tokenizador do próprio idioma, então as páginas em japonês e em híndi de um site em inglês são pesquisáveis a partir do próprio idioma e em uma busca em todos os idiomas. O tokenizador padrão remove os acentos e reescreve as letras que não têm um acento a remover (ø como o, ł como l, ß como ss), então cafe encontra café e lodz encontra Łódź, e o diálogo de busca e os trechos do assistente também encontram a palavra acentuada na página. Onde os acentos diferenciam palavras (ändra e andra em sueco, os tons do vietnamita), uma consulta também corresponde a palavras que diferem dela apenas nesses acentos.

Japonês e chinês vão um passo além. A segmentação sozinha indexa um termo composto como suas partes — 資金決済法 como 資金, 決済 e 法 — o que permite que uma página que mencione cada parte em algum lugar seja melhor classificada do que a página que realmente trata do termo. Por isso, Han, Hiragana e Katakana são indexados como pares de caracteres sobrepostos, e as consultas sobre esses índices preferem páginas que contenham os pares de um termo juntos, afrouxando para a correspondência de qualquer par quando nenhuma página os contém todos, de modo que digitar uma frase inteira ainda retorna as páginas mais próximas. Coreano e tailandês mantêm suas palavras segmentadas.

FlexSearch

Uma segunda opção do lado do cliente e sem chaves (instale flexsearch). Ela reutiliza o mesmo índice /blume-search.json que o Orama gera e constrói um índice de documentos do FlexSearch no navegador. Funciona em blume dev e blume build.

O FlexSearch não tem um mecanismo equivalente de segmentação, então, para sites em escritas não latinas, prefira o Orama (o padrão) ou o Pagefind, cujo binário pagefind_extended indexa um conjunto amplo de idiomas e segmenta chinês, japonês e coreano nativamente.

import { flexsearch } from "blume/search";

search: flexsearch(),

Pagefind

Para documentações muito grandes, opte pelo Pagefind. Ele indexa o HTML compilado e carrega o índice em fragmentos sob demanda, mantendo a carga inicial mínima por maior que o site fique.

import { pagefind } from "blume/search";

search: pagefind(),

O Pagefind só é executado durante o blume build, então a busca não fica disponível em blume dev com esse adaptador. Ele indexa o artigo de cada página da documentação — não o cabeçalho, a barra lateral ou o rodapé ao redor —, então páginas personalizadas construídas sobre PageLayout, a página 404 e o índice de changelog gerado não aparecem nos resultados dele.

Algolia

Instale algoliasearch. O navegador consulta o Algolia diretamente com sua chave somente de busca. Cada blume build substitui o índice usando a chave de administração de ALGOLIA_ADMIN_API_KEY (o build emite um aviso e pula o envio se ela não estiver definida). Todo o índice é substituído a cada sincronização, então páginas que você excluir ou renomear não permanecem como resultados desatualizados. Se ainda não existir um índice com o nome definido em indexName, a sincronização o cria, então um nome digitado errado cria um segundo índice em vez de fazer o build falhar. A sincronização espera até cerca de sete minutos por cada tarefa de indexação que o Algolia coloca na fila, e uma tarefa que não tiver terminado até lá faz o build falhar com BLUME_SEARCH_SYNC_FAILED. A sincronização também adiciona filterOnly(locale) e filterOnly(version) aos attributesForFaceting do índice, mantendo as facetas que você mesmo declarou, porque o diálogo restringe os resultados por idioma e por versão da documentação, e, no Algolia, um filtro sobre um atributo que não foi declarado para facetas não corresponde a nada.

O Algolia limita cada registro a 10 KB nos planos Build e Grow, então a sincronização divide uma página mais longa em vários registros, cada um com o título, a descrição e a URL da página e um trecho do texto dela. Em seguida, ela define o attributeForDistinct do índice como url, a menos que você tenha definido o seu, para que uma página dividida apareça uma única vez nos resultados, no registro com a melhor correspondência.

import { algolia } from "blume/search";

search: algolia({
  appId: "YOUR_APP_ID",
  apiKey: "YOUR_SEARCH_ONLY_KEY", // public
  indexName: "docs",
}),

Orama Cloud

Orama hospedado (instale @oramacloud/client). O navegador consulta o endpoint do seu índice com a chave de API pública; o blume build envia registros para o índice usando ORAMA_PRIVATE_API_KEY. Defina indexId para habilitar a sincronização; sem ele, o build emite um aviso e pula a sincronização mesmo com a chave definida.

import { oramaCloud } from "blume/search";

search: oramaCloud({
  endpoint: "https://cloud.orama.run/v1/indexes/your-index",
  apiKey: "YOUR_PUBLIC_API_KEY",
  indexId: "your-index-id", // for the build-time sync
}),

Typesense

Typesense auto-hospedado ou na nuvem. Instale typesense. O navegador consulta a coleção com a chave somente de busca. Cada blume build importa suas páginas para uma nova coleção usando TYPESENSE_ADMIN_API_KEY, depois aponta para ela um alias com o nome definido em collection e descarta a coleção que foi substituída. As buscas continuam lendo a coleção anterior até que a nova esteja completa, e páginas excluídas ou renomeadas não permanecem como resultados desatualizados. Se a sincronização falhar, o build falha e o alias continua servindo a última sincronização completa. A chave de administração precisa ter permissão para gerenciar coleções e aliases. Na primeira sincronização, uma coleção que já tenha o nome de collection (de uma versão anterior do Blume) é substituída pelo alias, e as chaves de busca restritas a esse nome continuam funcionando. Configurações que você ajustar manualmente em uma coleção não são levadas para a próxima, então reaplique-as após um build.

import { typesense } from "blume/search";

search: typesense({
  host: "xyz.a1.typesense.net",
  collection: "docs",
  apiKey: "YOUR_SEARCH_ONLY_KEY", // public
  // port + protocol default to 443 / https
}),

O tokenizador padrão do Typesense divide o texto nos espaços, então, em chinês, japonês ou tailandês, uma consulta só corresponde a partir do início de um trecho contínuo de texto. Defina locale como o idioma das suas páginas em um código de duas letras (locale: "ja", "zh", "th"), e a sincronização tokeniza os campos pesquisados para esse idioma; palavras em escrita latina nesses campos continuam correspondendo. Uma única coleção abriga todos os idiomas, então a configuração se aplica a todos eles.

Mixedbread

Busca semântica via Mixedbread (instale @mixedbread/sdk). As consultas passam por um endpoint /api/search gerado que guarda sua chave, então esse adaptador exige saída de servidor: um adaptador de hospedagem como deployment: vercel() de blume/deploy (veja Renderização no servidor). O endpoint lê MIXEDBREAD_API_KEY. O Blume não envia nada para o store: sincronize sua pasta de conteúdo usando a CLI do Mixedbread no seu build, por exemplo, mxbai store sync <STORE_ID> ./docs --yes (a CLI lê a chave dela de MXBAI_API_KEY).

Cada resultado aponta para a página que o arquivo dele renderiza, identificada pelo caminho que a CLI registra para o arquivo, então execute a sincronização a partir da raiz do seu projeto ou de uma pasta acima dela, como a raiz de um monorepo. Uma página aparece uma única vez, no trecho com a melhor correspondência, e trechos de arquivos que não são páginas, ou de páginas excluídas da busca, ficam de fora.

import { mixedbread } from "blume/search";

search: mixedbread({
  storeId: "YOUR_STORE_ID",
}),

O diálogo de busca espera o leitor fazer uma pausa na digitação antes de enviar uma consulta e descarta as consultas que o leitor já deixou para trás ao continuar digitando. Cada consulta enviada conta para o limite de taxa do endpoint.

search: false,

Em vez disso, defina provider: false na forma de objeto quando ainda quiser que indexing se aplique ao índice do servidor MCP.

Excluindo páginas

Apenas as páginas indexáveis são pesquisadas. Uma página fica de fora do índice quando define search.exclude no frontmatter:

search:
  exclude: true

Páginas ocultas também são excluídas por padrão. Para indexá-las mesmo assim, ative explicitamente:

search: {
  indexing: { includeHiddenPages: true },
}

Última atualização a

Esta página foi útil?