Zum Inhalt springen
Blume
Esc
↑↓navigieren↵öffnen⌘Jvorschau
Auf dieser Seite

Auf Blume 2 upgraden

Hebe eine Blume-1-Site mit einem Befehl auf Blume 2 und nutze dann diesen Leitfaden für jede Konfigurationsänderung – oder überlass das gesamte Upgrade Codex oder Claude Code.

Blume 2 ändert die Konfiguration, nicht die Inhalte: Deine Markdown- und MDX-Seiten brauchen keine Anpassungen (unter Frontmatter findest du ein Feld, das jetzt etwas bewirkt). Einstellungen, die früher ein benannter String oder ein Block mit Schlüssel waren – der Suchanbieter, das Deployment-Ziel, Content-Quellen, API-Referenzen, Analytics und das Modell-Backend des Assistenten –, sind jetzt Adapter, die du aus einem blume/*-Subpath importierst und aufrufst. Ask AI heißt jetzt Assistent, daher wird ai.ask zu ai.assistant. Die maschinenlesbaren Einstellungen wandern von ai in einen neuen Schlüssel agents, und Überschreibungen in components.ts werden vor dem Build geprüft. Eine Site ohne Konfiguration oder eine, die nichts davon setzt, braucht nur das Versions-Update.

Mit einem Befehl upgraden

Führe das Upgrade in deinem Projekt aus, also im Ordner mit blume.config.ts:

npx blume@latest upgrade
pnpm dlx blume@latest upgrade
yarn dlx blume@latest upgrade
bunx blume@latest upgrade
nubx blume@latest upgrade
aube dlx blume@latest upgrade

Der Befehl hebt blume in deiner package.json auf 2 an, installiert es mit dem Paketmanager, den dein Projekt nutzt, und prüft dann deine Konfiguration und components.ts gegen Blume 2. Jede noch nötige Änderung wird mit Datei, Zeile und Ersatz aufgelistet – einschließlich package.json-Scripts, die noch die entfernten blume build-Flags übergeben –, und der Befehl endet mit einem Exit-Code ungleich null, bis keine mehr übrig ist. Führst du ihn in einem Ordner ohne Konfiguration und ohne blume-Abhängigkeit aus, bricht er stattdessen mit einem Fehler ab. Starte ihn über npx blume@latest statt über blume: Der Befehl kommt mit Blume 2, ein Projekt auf Version 1 hat ihn also noch nicht. Unter pnpm 12 ergänzt du --allow-build=esbuild nach pnpm dlx, da pnpm 12 das Installationsskript von esbuild nicht ohne Freigabe ausführt.

Wenn du die Änderungen stattdessen einem Coding-Agent überlassen willst, ergänze --codex oder --claude:

npx blume@latest upgrade --codex
pnpm dlx blume@latest upgrade --codex
yarn dlx blume@latest upgrade --codex
bunx blume@latest upgrade --codex
nubx blume@latest upgrade --codex
aube dlx blume@latest upgrade --codex

Der Agent startet interaktiv mit den Befunden und diesem Leitfaden, setzt jede Änderung um und führt blume doctor und blume build aus, bis beide durchlaufen – so prüfst du jede Bearbeitung über seinen eigenen Freigabeablauf. Übergib --no-install, um package.json anzuheben, ohne zu installieren.

Die folgenden Abschnitte behandeln jede Änderung – zum Upgraden von Hand oder um zu prüfen, was der Agent gemacht hat.

search nimmt einen Adapter aus blume/search statt eines provider-Strings mit Zugangsdaten-Block. Die standardmäßige lokale Suche braucht keine Änderung.

export default defineConfig({
  search: {
    provider: "algolia",
    algolia: { appId: "APP_ID", indexName: "docs", searchApiKey: "SEARCH_KEY" },
  },
});
import { defineConfig } from "blume";
import { algolia } from "blume/search";

export default defineConfig({
  search: algolia({ appId: "APP_ID", indexName: "docs", apiKey: "SEARCH_KEY" }),
});
  • Orama Cloud, Typesense und Mixedbread werden genauso auf oramaCloud(), typesense() und mixedbread() abgebildet. Der reine Such-Key heißt in jedem Adapter, der einen erwartet, apiKey; mixedbread() nimmt statt eines Keys eine storeId, da seine Abfragen auf dem Docs-Server laufen. Alle weiteren Optionen, die du ihm übergibst, werden an den Store-Suchaufruf weitergereicht, bei dem top_k standardmäßig 8 ist. Admin-Keys bleiben in ihren Umgebungsvariablen (ALGOLIA_ADMIN_API_KEY, ORAMA_PRIVATE_API_KEY, TYPESENSE_ADMIN_API_KEY, MIXEDBREAD_API_KEY).
  • provider: "pagefind" wird zu pagefind(), und provider: "none" wird zu search: false.
  • Um popular-Links oder indexing-Optionen zu behalten, umschließt du den Adapter: search: { provider: algolia({ … }), popular: […] }.

Deployment

deployment nimmt einen Host-Adapter aus blume/deploy statt der Felder adapter und output. site und base wandern in die Optionen des Adapters.

export default defineConfig({
  deployment: {
    adapter: "vercel",
    output: "server",
    site: "https://docs.example.com",
  },
});
import { defineConfig } from "blume";
import { vercel } from "blume/deploy";

export default defineConfig({
  deployment: vercel({ site: "https://docs.example.com" }),
});
  • netlify(), cloudflare() und node() funktionieren genauso. Sobald du einen Host-Adapter angibst, wird auf Server-Output umgeschaltet; übergib output: "static", um einen statischen Build mit den Plattformdateien dieses Hosts zu behalten.
  • Eine Konfiguration, die nur site oder base setzt, bleibt, wie sie ist: deployment: { site, base } ist weiterhin die statische Form.
  • redirects lesen :name-Segmente und ein abschließendes * als Muster, die auf jedem Host gleich ausgewertet werden (siehe Redirects mit Mustern). Blume 1 hat Muster nie unterstützt und sie unverändert an den jeweiligen Host weitergegeben – prüf also jedes from oder to, das eines enthält.
  • Die Flags --adapter, --output und --base von blume build gibt es nicht mehr; übergibst du eines davon, bricht der Build mit einem Fehler ab, der die deployment-Einstellung nennt, die es ersetzt. Setze den Adapter in blume.config.ts und gib ihn explizit an: Server-Output wird nicht mehr aus der Umgebung der Plattform abgeleitet. Ein CI-Schritt, der pro Deployment ein anderes --base übergeben hat, kann es stattdessen in der Konfiguration aus einer Umgebungsvariable lesen.

Die Optionen der einzelnen Adapter findest du unter Deployment.

Content-Quellen

Jeder Eintrag in content.sources ist ein Adapter aus blume/sources statt eines { type }-Objekts.

export default defineConfig({
  content: {
    sources: [
      { type: "filesystem", root: "content" },
      {
        type: "github-releases",
        owner: "acme",
        repo: "sdk",
        prefix: "changelog",
      },
    ],
  },
});
import { defineConfig } from "blume";
import { filesystem, githubReleases } from "blume/sources";

export default defineConfig({
  content: {
    sources: [
      filesystem({ root: "content" }),
      githubReleases({ owner: "acme", repo: "sdk", prefix: "changelog" }),
    ],
  },
});
  • mdx-remote, sanity, notion und obsidian werden zu mdxRemote(), sanity(), notion() und obsidian(), wobei alle anderen Felder unverändert in den Aufruf wandern. { type: "custom", source } wird zu custom(source).
  • content.root, content.include und content.exclude sind weiterhin die Kurzform für einen einzelnen Ordner, können aber nicht mehr neben sources stehen. Verschiebe sie in den filesystem()-Eintrag.
  • Release-Seiten aus githubReleases() werden jetzt in nur einer Sprache veröffentlicht, eine mehrsprachige Site kopiert sie also nicht mehr unter die URL jeder anderen Locale (/de/changelog/…). Wenn andere Sites auf diese Kopien verlinken, füge Redirects auf die Seiten der Standard-Locale hinzu.
  • Text, den du in Notion eingibst, wird jetzt so dargestellt, wie er geschrieben ist: Eine Komponente, ein { oder ein Markdown-Zeichen auf einer notion()-Seite erscheint wie eingegeben, statt als MDX gelesen zu werden. Enthalten deine Notion-Seiten Komponenten oder Markdown, die als Text eingegeben sind, setz mdx: true für die Quelle.

API-Referenzen

Die Top-Level-Blöcke openapi, asyncapi und graphql werden zu einer einzigen reference-Liste mit Adaptern aus blume/reference. Lass enabled weg.

export default defineConfig({
  openapi: { enabled: true, spec: "./openapi.yaml" },
  graphql: {
    enabled: true,
    spec: "./schema.graphql",
    endpoint: "https://api.example.com/graphql",
  },
});
import { defineConfig } from "blume";
import { graphql, openapi } from "blume/reference";

export default defineConfig({
  reference: [
    openapi({ spec: "./openapi.yaml" }),
    graphql({
      spec: "./schema.graphql",
      endpoint: "https://api.example.com/graphql",
    }),
  ],
});
  • asyncapi: { … } wird zu asyncapi({ … }) mit denselben Optionen.
  • Eine AsyncAPI-Spec in Version 1.x oder 2.x wird weiterhin automatisch nach 3.0 konvertiert, der Konverter ist jetzt aber eine optionale Peer-Dependency: Installiere @asyncapi/converter in deinem Projekt, sonst schlägt der Build fehl und nennt dir den Installationsbefehl. Eine 3.x-Spec braucht nichts.
  • renderer: "scalar" wird zu einem eigenen scalar({ spec, theme, … })-Eintrag in der Liste, der route und sources des Blocks übernimmt.
  • Ein Block mit enabled: false wird einfach aus der Liste weggelassen.

Analytics

Das analytics-Objekt wird zu einer Liste von Adaptern aus blume/analytics.

export default defineConfig({
  analytics: {
    posthog: { key: "phc_…" },
    vercel: true,
  },
});
import { defineConfig } from "blume";
import { posthog, vercel } from "blume/analytics";

export default defineConfig({
  analytics: [posthog({ key: "phc_…" }), vercel()],
});

cloudflare: { token } wird zu cloudflare({ token }), und jeder scripts[]-Eintrag wird zu script({ … }).

Assistent

Ask AI heißt jetzt Assistent, und die Konfiguration zieht mit dem Namen um: ai.ask wird zu ai.assistant. Der provider des Assistenten nimmt einen Adapter aus blume/ai, der das Modell und die zugehörigen Felder verwaltet.

export default defineConfig({
  ai: {
    ask: {
      enabled: true,
      provider: "openrouter",
      model: "anthropic/claude-sonnet-4-5",
      reasoning: "none",
    },
  },
});
import { defineConfig } from "blume";
import { openrouter } from "blume/ai";

export default defineConfig({
  ai: {
    assistant: {
      enabled: true,
      provider: openrouter({
        model: "anthropic/claude-sonnet-4-5",
        reasoning: "none",
      }),
    },
  },
});

Ein provider-Name aus 1.x wird auf gateway(), openrouter(), llmgateway() oder inkeep() abgebildet und openai-compatible auf openai({ baseUrl, name, model, apiKeyEnv }); alle weiteren findest du in der Adapter-Liste. model, apiKeyEnv, baseUrl, headers und reasoning wandern in den Adapter; enabled, instructions, retrieval, suggestions, cors und endpoint wandern unverändert nach ai.assistant. Lässt du provider weg, wird weiterhin das AI Gateway verwendet.

Die Umbenennung betrifft jeden Namen, in dem Ask AI vorkam:

  • i18n.ui-Überschreibungen: Die Gruppe ask wird zu assistant, und search.askAi und search.askAiHint werden zu search.assistant und search.assistantHint.
  • useAskAI aus blume/hooks wird zu useAssistant, samt den Typen UseAssistant und UseAssistantOptions.
  • Die Prop askEnabled an PageLayout, RootLayout, Header und einer Search-Überschreibung wird zu assistantEnabled.
  • Im Modul blume:data wird config.ask zu config.assistant und ui.ask zu ui.assistant, und der Typ UIStrings aus blume zieht entsprechend nach.
  • Die Adapter-Typen aus blume/ai tauschen ihr Präfix Ask gegen Assistant (AskAdapter wird zu AssistantAdapter, AskGatewayOptions wird zu AssistantGatewayOptions), und askReasoningLevels und AskReasoning aus blume/schema werden zu assistantReasoningLevels und AssistantReasoning.
  • Das Window-Event blume:open-ask-ai wird zu blume:open-assistant, und das Attribut data-blume-ask an <body> wird zu data-blume-assistant.

Die generierte Route /api/ask und die Analytics-Events ask, ask_answer und ask_error behalten ihre Namen, Aufrufer und Dashboards brauchen also keine Änderung. blume upgrade und blume doctor nennen jeden alten Konfigurationsschlüssel, den sie finden – ai.ask ebenso wie die i18n.ui-Schlüssel –, samt seinem Ersatz.

Hast du schon auf Blume 2.0.0 upgegradet? Diese Version hat noch ai.ask gelesen – aktualisiere blume also wie gewohnt und nimm dieselbe Umbenennung vor.

Agents und weitere Verschiebungen in der Konfiguration

Die maschinenlesbaren Einstellungen wandern von ai in einen neuen Schlüssel agents, und drei kleinere Felder ändern ihre Form.

export default defineConfig({
  ai: { mcp: { enabled: true }, skills: "./skills" },
  lastModified: true,
  markdown: {
    codeBlocks: { theme: { light: "github-light", dark: "github-dark" } },
  },
  theme: { layout: "sidebar" },
});
export default defineConfig({
  agents: { mcp: { enabled: true }, skills: "./skills" },
  lastModified: "git",
  markdown: {
    code: { theme: { light: "github-light", dark: "github-dark" } },
  },
});
  • ai.api, ai.catalog, ai.llmsTxt, ai.markdownComponents, ai.mcp, ai.skills, ai.webBotAuth und ai.webmcp werden zu agents.*, ebenso seo.agentReadability und seo.contentSignals. In ai bleiben nur assistant (früher ask) und openInChat.
  • lastModified ist ein einfacher Wert: true wird zu "git", und { type: "git" } oder { type: "frontmatter" } wird zum bloßen String.
  • markdown.codeBlocks geht in markdown.code auf.
  • theme.layout entfällt. Es wurde nirgends gelesen, also lösch es.

Frontmatter

Seiten behalten ihr Frontmatter. Ein Feld ändert, was es bewirkt: search.boost. Blume 1 hat es akzeptiert, die Suche hat es aber nie ausgewertet – eine Seite wurde ohne das Feld also genauso gerankt. Jetzt multipliziert es die Suchrelevanz der Seite (siehe Ranking). Prüf jede Seite, die es setzt: Ein Boost, den du irgendwann hinzugefügt und dann vergessen hast, schiebt die Seite jetzt nach oben.

Komponenten-Überschreibungen

Blume 2 prüft jeden Eintrag in components.ts vor dem Build, statt zur Laufzeit auf einen Fallback zurückzugreifen. Jeder mdx- und layout-Eintrag muss eine importierte Komponente, ein Pfad-String oder ein { component, client, media }-Objekt sein, und die Gruppe islands entfällt: Ein mdx-Eintrag mit einem client-Modus ist eine Island.

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

export default defineComponents({
  islands: { Counter },
});
import { defineComponents } from "blume";
import Counter from "./islands/Counter.tsx";

export default defineComponents({
  mdx: { Counter: { component: Counter, client: "visible" } },
});

Eine Inline-Funktion, eine direkt in components.ts deklarierte Komponente, ein Spread oder ein berechneter Schlüssel schlägt jetzt mit BLUME_COMPONENTS_INVALID fehl, wobei der betroffene Eintrag genannt wird. Verschiebe die Komponente in eine eigene Datei und importiere sie. Die Ordnerkonvention islands/ funktioniert wie bisher. Die akzeptierten Formen findest du unter Anpassung.

Apps nach einem Eject

Eine App, die du unter Blume 1 ejectet hast, läuft nicht mehr über die Blume-CLI, hängt aber weiterhin vom Paket blume ab. Ihre Seiten importieren Blumes Komponenten, src/generated/ enthält einen Snapshot deiner Site, den der Generator von Blume 1 geschrieben hat, und astro build lädt blume.config.ts erneut, um den Suchindex, llms.txt und die Sitemap zu schreiben. Hebst du blume darunter auf 2 an, trifft dieser Blume-1-Snapshot auf Blume-2-Komponenten, die die neuen Formen erwarten – ejecte also stattdessen erneut:

Copy the project out

Kopiere alles außer astro.config.mjs, src/, .blume/, dist/ und node_modules/ in einen leeren Ordner: deine Inhalte, blume.config.ts, components.ts, islands/, public/, alle Spec-Dateien, die deine Referenzen einlesen, und package.json. Lass die ejectete App, wie sie ist.

Upgrade the copy

Führe in der Kopie npx blume@latest upgrade aus und setz um, was der Befehl auflistet, damit blume.config.ts und components.ts gültiges Blume 2 sind. Führe dann npx blume build aus, um sicherzustellen, dass die Site baut, bevor du sie ejectest.

Eject a fresh copy

Führe npx blume eject --yes in der Kopie aus, installiere die Pakete, die der Befehl hinzufügt, und baue sie mit npm run build.

Carry your edits across

Vergleiche die frische astro.config.mjs und src/ per Diff mit deiner ejecteten App und übertrage deine eigenen Änderungen auf die neuen Dateien.

Bis die frische Kopie fertig ist, belässt du die ejectete App auf Blume 1 ("blume": "^1") und führst darin nicht blume upgrade aus: Solange du die Version nicht anhebst, ändert sich nichts.

Kommandozeilen-Flags

Jeder blume-Befehl lehnt jetzt Flags ab, die er nicht kennt – Blume 1 hat sie ignoriert. Ein Script oder CI-Schritt, der ein überflüssiges oder falsch geschriebenes Flag übergibt, schlägt fehl und nennt das nicht erkannte Flag sowie die Flags, die der Befehl akzeptiert. blume upgrade meldet nur die drei entfernten blume build-Flags (--adapter, --output, --base), prüf also auch deine anderen blume-Scripts.

Ergebnis prüfen

Sobald blume upgrade nichts mehr zu ändern meldet, führe die Prüfungen der Site selbst aus:

npx blume doctor
npx blume build

Die vollständige Liste der Änderungen samt Begründung findest du im Changelog.

Zuletzt aktualisiert am

War diese Seite hilfreich?