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

Ilhas

Coloque um componente interativo em islands/ e use-o em qualquer página MDX — hidratado automaticamente, sem importação por página.

O Blume renderiza sua documentação como HTML estático com zero JavaScript por padrão. Quando você precisa de algo interativo — uma demonstração ao vivo, um gráfico, um playground — você adiciona uma ilha: um componente de framework que envia JS apenas para si mesmo, apenas nas páginas que o utilizam.

A convenção islands/

Coloque um componente em uma pasta islands/ na raiz do seu projeto. O nome do arquivo se torna um componente que você pode usar em qualquer página .mdx, sem importação:

import { useState } from "react";

export default function Counter() {
  const [count, setCount] = useState(0);
  return <button onClick={() => setCount(count + 1)}>Clicked {count}</button>;
}
Here's a live counter: <Counter />

O nome do arquivo é o nome do componente, então ele deve ser um identificador em PascalCase — apenas letras, dígitos e sublinhados (Counter.tsx → <Counter />). Nomes de arquivo em minúsculas e nomes com traços/pontos/espaços (como Time-Picker.tsx) são ignorados com um aviso de compilação. Quando duas ilhas resolvem para o mesmo nome — Counter.tsx e Counter.vue, ou dois arquivos Counter.tsx em subpastas diferentes — o Blume mantém a primeira pela ordem dos caminhos de arquivo e ignora a outra, com um aviso de compilação.

Uma ilha é a única forma de executar código no navegador a partir de uma página. Um manipulador de eventos JavaScript em um elemento HTML simples no MDX, como <button onClick={() => open()}>, nunca é executado: a página é HTML estático, então a função é escrita no atributo como texto. O Blume emite um aviso BLUME_MDX_EVENT_HANDLER na linha em que ele aparece. Mova essa marcação para uma ilha e use a ilha na página.

Registrando ilhas em components.ts

Se você preferir manter as ilhas junto ao restante dos seus componentes — ou dar a elas um nome diferente do arquivo — registre-as com defineComponents como uma entrada mdx com um modo client. Isso é tudo o que uma ilha é: um componente MDX que é hidratado. Cada entrada está disponível em todas as páginas MDX, e uma entrada com o mesmo nome de um arquivo em islands/ o substitui.

import { defineComponents } from "blume";
import Counter from "./widgets/Counter.tsx";

export default defineComponents({
  mdx: {
    Counter: { component: Counter, client: "visible" }, // <Counter /> in any MDX page, hydrated
  },
});

Referencie o componente por importação ou por uma string de caminho, e escolha o modo de hidratação por ilha ("media" recebe uma consulta media ao lado):

export default defineComponents({
  mdx: {
    Chart: { component: "./widgets/Chart.tsx", client: "only" },
  },
});

Diferente da pasta, não há padrão: uma entrada mdx sem client é renderizada como HTML estático, e o Blume emite um aviso quando essa entrada é um componente React, Vue ou Svelte. O Blume lê o components.ts estaticamente, então uma entrada deve ser um componente importado, uma string de caminho ou um literal de objeto { component, client, media } — veja Personalização para as formas aceitas e o erro que você recebe caso contrário.

Hidratação

Por padrão, uma ilha usa client:visible: ela é hidratada quando o leitor a rola até o campo de visão, então uma página cheia de ilhas ainda carrega instantaneamente. Opte por uma estratégia diferente com um export const client no arquivo da ilha:

// Skip server rendering entirely — for components that touch the DOM/window.
export const client = "only";

export default function Chart() {
  /* ... */
}
Valor de client Hidrata Use para
"visible" (padrão) Quando rolado até o campo de visão A maioria das ilhas
"load" Imediatamente ao carregar a página UI acima da dobra, que deve ser instantânea
"idle" Quando a thread principal está ociosa Interatividade não urgente
"only" Apenas no cliente, nunca renderizado no servidor Bibliotecas que precisam de window/document (gráficos, editores)
"media" (apenas components.ts) Quando uma media query CSS corresponde UI que só roda em alguns tamanhos, como um menu apenas para mobile

"media" precisa da consulta ao lado, então está disponível apenas para uma entrada em components.ts — { component: Menu, client: "media", media: "(max-width: 50em)" }. Um arquivo em islands/ que o declara volta para "visible" com um aviso.

Frameworks

O React funciona de imediato — o Blume o ativa automaticamente assim que seu projeto contém uma ilha .tsx/.jsx.

O React Compiler está ativado por padrão sempre que o React está habilitado, então suas ilhas são memoizadas automaticamente — sem necessidade de useMemo/useCallback escritos à mão. Ele vem com o Blume; não há nada para instalar. Desative em blume.config.ts:

export default defineConfig({
  react: { compiler: false },
});

Vue e Svelte também são suportados; instale a integração Astro correspondente e o Blume configura o renderizador quando encontra uma ilha .vue ou .svelte:

# Vue
npm install @astrojs/vue vue

# Svelte
npm install @astrojs/svelte svelte
<script setup>
import { ref } from "vue";
const on = ref(false);
</script>

<template>
  <button @click="on = !on">{{ on ? "On" : "Off" }}</button>
</template>

As props que você passa no MDX (<Counter start={5} />) são encaminhadas ao componente, e os filhos (<Counter>label</Counter>) chegam como o slot padrão.

Hooks

As ilhas são hidratadas por conta própria, então não há contexto do React para conduzir os dados do projeto. Em vez disso, blume/hooks lê um pequeno snapshot que o layout serializa na página — sem props para repassar:

import { useBlume, usePage } from "blume/hooks";

export default function PageInfo() {
  const blume = useBlume();
  const page = usePage();
  if (!(blume && page)) {
    return null;
  }
  return (
    <p>
      You're reading <strong>{page.title}</strong> on {blume.config.title}.
    </p>
  );
}
Hook Retorna
useBlume() { config, navigation } do site, ou null antes da montagem
usePage() { route, title } da página atual, ou null antes da montagem
useSearch() { search, results, loading } — consulta o provedor de busca configurado
useAssistant() { ask, messages, loading, reset } — transmite a partir do endpoint do assistente

useBlume() e usePage() retornam null até que a ilha seja montada (para que servidor e cliente renderizem o mesmo primeiro quadro) — proteja-se contra isso. O snapshot é emitido apenas em páginas que enviam React, então um site totalmente estático não paga nada.

Em páginas personalizadas construídas com PageLayout, passe clientData para que as ilhas ali possam lê-lo:

<PageLayout
  clientData={{ config: data.config, navigation: data.navigation, page: { route: "/", title: "Home" } }}
  {/* …other props… */}
/>

Última atualização a

Esta página foi útil?