Zum Inhalt springen
Blume is now publicly available.
Blume
Deutsch
Esc
navigierenöffnen⌘Jvorschau
Auf dieser Seite

Islands

Lege eine interaktive Komponente in islands/ ab und nutze sie in jeder MDX-Seite — automatisch hydriert, ohne Import pro Seite.

Blume rendert deine Dokumentation standardmäßig als statisches HTML mit null JavaScript. Wenn du etwas Interaktives brauchst — eine Live-Demo, ein Diagramm, einen Playground — fügst du eine Island hinzu: eine Framework-Komponente, die JS nur für sich selbst ausliefert, und nur auf den Seiten, die sie verwenden.

Die islands/-Konvention

Lege eine Komponente in einen islands/-Ordner im Stammverzeichnis deines Projekts. Ihr Dateiname wird zu einer Komponente, die du in jeder .mdx-Seite verwenden kannst, ganz ohne Import:

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 />

Der Dateiname ist der Komponentenname, er muss also ein PascalCase-Bezeichner sein — nur Buchstaben, Ziffern und Unterstriche (Counter.tsx<Counter />). Kleingeschriebene Dateinamen, Namen mit Bindestrichen/Punkten/Leerzeichen (wie Time-Picker.tsx) und zwei Islands, die zum selben Namen aufgelöst werden, werden mit einer Build-Warnung übersprungen.

Islands in components.ts registrieren

Wenn du Islands lieber bei deinen übrigen Komponenten aufbewahren möchtest — oder ihnen einen anderen Namen als der Datei geben willst — registriere sie mit defineComponents. Die Gruppe islands verhält sich genau wie der islands/-Ordner: Jeder Eintrag steht in jeder MDX-Seite zur Verfügung und wird hydriert (standardmäßig mit client: "visible").

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

export default defineComponents({
  islands: {
    Counter, // <Counter /> in any MDX page, hydrated
  },
});

Referenziere die Komponente per Import oder über einen Pfad-String und lege mit der Deskriptor-Form einen Hydrierungsmodus pro Island fest:

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

Hydrierung

Standardmäßig nutzt eine Island client:visible: Sie hydriert, sobald die lesende Person sie in den sichtbaren Bereich scrollt, sodass auch eine Seite voller Islands sofort lädt. Entscheide dich mit einem export const client in der Island-Datei für eine andere Strategie:

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

export default function Chart() {
  /* ... */
}
client-Wert Hydriert Verwende es für
"visible" (Standard) Beim Scrollen in den sichtbaren Bereich Die meisten Islands
"load" Sofort beim Laden der Seite UI oberhalb der Falz, die sofort da sein muss
"idle" Wenn der Haupt-Thread untätig ist Nicht dringende Interaktivität
"only" Nur clientseitig, nie serverseitig gerendert Bibliotheken, die window/document brauchen (Diagramme, Editoren)

Frameworks

React funktioniert sofort — Blume aktiviert es automatisch, sobald dein Projekt eine .tsx/.jsx-Island enthält.

Der React Compiler ist standardmäßig aktiv, sobald React aktiviert ist, sodass deine Islands automatisch memoisiert werden — handgeschriebene useMemo/useCallback sind nicht nötig. Er wird mit Blume ausgeliefert; es gibt nichts zu installieren. Deaktivieren kannst du ihn in blume.config.ts:

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

Vue und Svelte werden ebenfalls unterstützt; installiere die passende Astro-Integration, und Blume verdrahtet den Renderer, sobald es eine .vue- oder .svelte-Island sieht:

# 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>

Props, die du in MDX übergibst (<Counter start={5} />), werden an die Komponente weitergereicht, und Kindelemente (<Counter>label</Counter>) kommen als Standard-Slot an.

Hooks

Islands hydrieren eigenständig, es gibt also keinen React-Context, durch den sich Projektdaten durchreichen ließen. Stattdessen liest blume/hooks einen kleinen Snapshot, den das Layout in die Seite serialisiert — kein Prop-Drilling nötig:

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 Gibt zurück
useBlume() { config, navigation } für die Website, oder null vor dem Mount
usePage() { route, title } für die aktuelle Seite, oder null vor dem Mount
useSearch() { search, results, loading } — den konfigurierten Suchanbieter abfragen
useAskAI() { ask, messages, loading, reset } — vom Ask-AI-Endpunkt streamen

useBlume() und usePage() geben null zurück, bis die Island mountet (damit Server und Client denselben ersten Frame rendern) — sichere das ab. Der Snapshot wird nur auf Seiten ausgegeben, die React ausliefern, eine vollständig statische Website zahlt also nichts dafür.

Auf benutzerdefinierten Seiten, die mit PageLayout gebaut sind, übergib clientData, damit Islands dort darauf zugreifen können:

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

War diese Seite hilfreich?