zudo-doc 6 への移行
5.x の利用側を zudo-react・Wind のメジャーリリースへ更新します。
リリース状況
このガイドは、5.x から zudo-doc 6.0.0 への移行を説明します。6.0.0 は @takazudo/zudo-doc、@takazudo/zudo-doc-history-server、create-zudo-doc を揃えて公開するメジャーリリースです(6.0.0 のリリースノートを参照)。三つのパッケージはすべて npm で 6.0.0(latest)として公開済みです。公開時のワークフローと、公開パッケージを使った利用側の検証結果は 6.0.0 の公開記録にまとめています。エンジン対象は、同じバージョンに揃えた公開済みの zfb 4.3.3 ファミリーで、パッケージの peer 下限は ^4.3.3 です。過去の 3.0/3.1 を移行先としてインストールしないでください。
#4097 の修正は 4.3.0 で初めて公開され、issue は解決済みです。サポート対象の 4.3.1 ファミリーで、公開パッケージを使う厳密なブラウザー・ナビゲーション検証は 3/3 PASS(失敗・skip・retry なし) でした。ソースに紐付いた検証記録を参照してください。これは Linux Chromium の証拠であり、ネイティブ macOS WebKit や Apple IME の検証ではありません。移行状況の記録には、プラットフォーム上の限界と、残っていた手動 IME 確認をオーナーが取り消したことが記録されています。
3.x の利用側は、zudo-doc 3 からの移行から始め、著作した内容を維持しながら、それ以前の scaffold/API の変更を棚卸し・照合してください。
依存関係と TypeScript
既存のプロジェクトを更新するには、プロジェクト自身の package.json を編集し、パッケージマネージャーで再インストールします。@takazudo/zudo-doc を ^6.0.0 にし、@takazudo/zudo-doc-history-server を宣言している場合はそれも ^6.0.0 にします(doc history または asset viewer を有効にしている場合にだけ必要です)。インストールするすべてのエンジンパッケージ(@takazudo/zfb、@takazudo/zfb-runtime、@takazudo/zfb-md-wasm、使用する場合は Cloudflare adapter)を 4.3.3 に揃えてください。コアの描画には Preact は不要です。
create-zudo-doc はプロジェクトを生成する initializer で、アプリケーションの依存パッケージではありません。既存のプロジェクトに追加したり、既存のプロジェクトに対して再実行したりしないでください。6.0.0 の生成結果と比較したい場合は、別のディレクトリで pnpm dlx create-zudo-doc@6.0.0 を実行して新規または参照用の scaffold を作り、必要な部分だけを取り込みます。
次のようにパッケージのベース設定を継承します。ベースが jsx: "react-jsx" と jsxImportSource: を所有します。react、react-dom、react/jsx-runtime から Preact への互換パスを削除し、React/Preact の型 import も変更します。必要なプロジェクト固有のエイリアスだけを残し、. のように明示的な相対パスで指定してください。各 paths エントリは、それを宣言した tsconfig を基準に解決されます。ベースは baseUrl を設定しません(TypeScript 7 ではこのオプションが TS5102 で拒否されます)。そのため、同じプロジェクト設定が TypeScript 5.9 と 7.0 の両方で型チェックを通ります。TypeScript 5 を使い続ける既存プロジェクトは、独自の baseUrl を残してもかまいません。config と仮想モジュールの宣言を読み込むベースのトップレベル files を上書きしないでください。
{
"extends": "@takazudo/zudo-doc/tsconfig.base.json",
"include": ["src", "pages", "zfb.config.ts"],
"compilerOptions": {
"paths": { "@/*": ["./src/*"] }
}
}CSS と Wind
CSS のエントリから Tailwind の import と @theme、@source、@tailwind、@apply、@utility、@plugin の各ディレクティブを削除します。トークンの宣言は変数名を維持して通常の :root に移します。--color-*: initial によるパレットのリセットも削除します。theme-no-reset.css は theme.css に変更し、safelist.css の import は削除してください。以前の二つのサブパス export は廃止されます。
次の公開 CSS import を使います。パネルを有効にする場合だけ @takazudo/ を追加してください。物理的な dist/*.css パスは import しません。compiled.css は zfb の CSS ビルドを使わない埋め込み用に、ブラウザーで使える公開 export として残ります。この構成で追加する必須 import ではありません。
@layer zw-reset, zd-flow;
@import "@takazudo/zudo-doc/theme.css";
@import "@takazudo/zudo-doc/content.css";
@import "@takazudo/zudo-doc/page-loading.css";
@import "@takazudo/zudo-doc/features.css";
:root {
--spacing-hsp-md: 1rem;
--z-index-toolbar: 25;
}zudoDoc() が新しい公開 manifest @takazudo/ を自動で登録します。パッケージの dist/ をスキャンせずに、必要なユーティリティ候補を供給するため、通常は自分で manifest を import・登録する必要はありません。Wind のトークンは既存の CSS 変数を参照し、テーマやパネルによる動的な更新を維持します。
変数の値は :root、ユーティリティの対応付けはトップレベルの wind オプションで変更します。zfb がパッケージの既定値にこの変更を deep-merge します。wind は Settings のフィールドではありません。リセットは wind.reset で選びます(パッケージの既定値は "owned-v1")。wind: false は Wind 全体を無効にします。
import { defineConfig } from "@takazudo/zfb/config";
import { zudoDoc } from "@takazudo/zudo-doc/config";
export default defineConfig(zudoDoc({
wind: {
tokens: { colors: { accent: "var(--brand-accent)" } },
reset: "owned-v1",
},
}));Wind は独自に定義されたユーティリティ言語で、Tailwind の互換実装ではありません。パッケージ設定は名前付きの spacing を使い、暗黙の数値 spacing スケールはありません。ブレークポイントは sm/lg/xl(640/1024/1280px)で、dark ユーティリティモードも使いません。既存の data-theme による変数切り替えは継続します。未対応のユーティリティは zd- クラスの明示的な CSS と、その出力を確認する検証が必要です。生成されたユーティリティは layer に属さず、 authored CSS の後に置かれるため、移行時はセレクターの詳細度を確認してください。
pnpm exec zfb wind audit --project-root . --fail-on error を実行します。エラー時の終了フラグは必須です。audit の成功だけでは manifest の網羅性や CSS の出力・計算結果を証明できません。manifest、 authored class、出力されたルール、ブラウザーの検証を維持してください。
公開型・props の変更一覧
| 5.x の契約 | 6.0 の移行先 |
|---|---|
Preact VNode / React ReactNode | 要素 description には zudo-react Description、描画できる値・戻り値には Child |
| Preact の component callback 型 | zudo-react Component<P>。FrontmatterCellRenderer、ThemePackDialogComponent などのドメイン名は維持 |
| Preact の intrinsic attributes | @takazudo/ の JSX.IntrinsicElements["button"](または対象のタグ) |
intrinsic と互換の content component・共有 icon の className | class。EnlargeDialogProps.class も同じ規則 |
ThemePackDialogProps.open: boolean | 一つの client component tree 内の ReadonlySignal<boolean>。Island props にこの signal をシリアライズしない |
useModalDialog(...) | 既存の . サブパスにある modalDialog(scope, options) と ModalDialogOptions / ModalDialogResult |
.、. | 廃止。. を追加し、ほかの公開 CSS export は維持 |
| コアの必須 Preact peer | 廃止。zdtp 0.8.6 が Preact 依存を所有するため、パネル利用側は zdtp のみインストール |
ThemeToggle の defaultMode、respectPrefersColorScheme、labels、pendingUntilHydrated は維持します。ほかのドメイン props 名も維持してください。class への変更は intrinsic と互換の API が対象で、独自の className props を一律に変更するものではありません(たとえば SidebarTree は独自の className を維持します)。
ENLARGE_DIALOG_STYLE は . から引き続き export されます。実際の 4.3.3 対象では固定の style object { position: "fixed", inset: 0, margin: "auto" } で、EnlargeDialogProps.style は typeof ENLARGE_DIALOG_STYLE です。以前の 3.x 計画にあった文字列化は、ネイティブの style 対応によって不要になりました。対応する CSS property 名を使い、ゼロ以外の長さには単位を明示してください。完全な CSS 宣言の文字列も使用できます。
eject した component と host component
対話的な component は、setup 時の signals、computed、Show、For、scope の activation/cleanup を使って書き換えます。JSX は scope ごとに一度だけ実行されるので、単に count.value を読んだ snapshot ではテキストはリアクティブになりません。intrinsic event は on:click、on:input、on:change を使います。ネイティブの change は確定時に発生するため、入力中の更新には input または対応する modelValue を使います。React の onChange を機械的にすべてネイティブの change に変更しないでください。
modalDialog は dialog を所有する scope の setup 中に呼び出します。dialog が条件付きなら Show の中に子 component を置き、その子で helper を呼び出します。options は isOpen、onClose、navigateEvent、backdropClickClose、manageFocus、restoreFocusOnly、returnFocusRef です。結果は dialogRef と handleBackdropClick を含みます。通常のモジュールの helper であり、"use client" の island export ではありません。
"use client";
import { computed, getScope, signal } from "@takazudo/zfb/zudo-react";
import { modalDialog } from "@takazudo/zudo-doc/use-modal-dialog";
export function ExampleDialog() {
const scope = getScope();
const open = signal(false);
const { dialogRef, handleBackdropClick } = modalDialog(scope, {
isOpen: open,
onClose: () => { open.value = false; },
backdropClickClose: true,
manageFocus: true,
});
return <>
<button type="button" on:click={() => { open.value = true; }}>Open</button>
<dialog ref={dialogRef} on:click={handleBackdropClick}>
<p>{computed(() => open.value ? "Open" : "Closed")}</p>
<button type="button" on:click={() => { open.value = false; }}>Close</button>
</dialog>
</>;
}固定 target の server boundary
defineChromeBindings と六つの主要置換キー(Header、Footer、Sidebar、Toc、Breadcrumb、DocPager)を維持します。省略した slot は既定の実装を使います。runtime の値はトピックごとのサブパスから import してください。パッケージ root は型専用です。config 評価(.、.)と browser import は異なる graph です。browser-safe な既定値は内部の settings-defaults.ts にあり、. が再 export します。. は型専用、. は engine-free のままです。client entry から host の仮想 route module を import しないでください。
host override の DocHistory と DesignTokenPanelBootstrap は、パッケージが Island で包む動的な client component ではなく、server boundary を受け取るようになります。boundary は自身の名前付き client target を静的に import し、Island の mount を所有し、Fragment を返します。任意の BodyEndIslandsDeps.ThemePackSwitcher も同じ boundary 規則です。パッケージの settings gate と override の優先順位を維持してください。独自のパネル設定は通常、island の置換ではなく designTokenPanelConfigModule を使います。
標準の history には、維持される公開 export DocHistoryBoundary を使います。client props を構築する前に ssrFallback を取り除き、fallback markup は server に残し、slug/locale/base/date のデータだけを JSON で渡します。
import { defineChromeBindings } from "@takazudo/zudo-doc/chrome-bindings";
import { DocHistoryBoundary } from "@takazudo/zudo-doc/doc-history-area";
export const chromeBindings = defineChromeBindings({
DocHistory: DocHistoryBoundary,
});独自のパネル boundary も同じ静的な形を使います。client target は、一意の名前を持つ自作の "use client" component です。
import { Island } from "@takazudo/zfb";
import { defineChromeBindings } from "@takazudo/zudo-doc/chrome-bindings";
import { MyPanelClient } from "./my-panel-client";
function MyPanelBoundary() {
return <><Island when="load"><MyPanelClient /></Island></>;
}
export const chromeBindings = defineChromeBindings({
DesignTokenPanelBootstrap: MyPanelBoundary,
});Island boundary を越えられるのは有限の JSON scalar、dense array、plain record だけです。client description を作る前に、値のない任意の object key を明示的に省略し、SSR とシリアライズで同じ正規化済みデータを使います。function、signal、description、date/class、循環参照、getter、symbol、undefined の array 要素は無効です。client child の props に ssrFallback を含めたり、JSON の往復で props を消毒したりしないでください。DocHistory client と、ImageEnlargeSsrFallback、MermaidEnlargeSsrFallback など既存の公開 fallback component は、それぞれの公開サブパスで引き続き使用できます。
zdtp と runtime の制約
インストール済みの zdtp 0.8.6 manifest は Preact ^10.29.1 を自身の依存として含み、自身の CSS を .(. も)から export します。パネルを使う場合は zdtp をインストールしてください。Preact を別途インストールする必要はなくなりました(0.8.5 までは peer でした)。zdtp が opaque な Preact subtree と内部の Tailwind browser 依存を所有します。host の描画エンジンを Preact/Tailwind に戻すものではありません。lazy load、mode ごとのパネル永続状態、root の CSS 変数更新を維持します。
現在のエンジンにあるネイティブの順序付きリスト、先頭改行の処理、変更のない root の永続化を使います。island の identity/props が同じなら live scope の状態を維持し、変更されたら再生成します。パッケージの zfb:before-swap adapter は切り離された incoming document だけを更新し、live 側の data-zd-props-preserve を尊重し、安全でない構造変更には incoming の persistence を取り除きます。一律 remount は復活させないでください。
parser の規則も owned JSX の契約です。table/select は正しい構造を維持し、tbody を明示し、table の構造レベルに Show/For/component region を直接置きません。rawHtml は信頼できる文字列を受け取り、children と同時に使えません。サニタイズは行いません。raw HTML に island wrapper や runtime protocol marker を入れないでください。script/style の payload は closing-tag guard を付けた静的な raw text が必要です。ネイティブ対応は 3.x の調査時点から変化しているので、古い iframe/head/style shim をコピーせず、公開済み 4.3.3 の型宣言と契約を確認してください。
サポートされる固定 target の composition #4004 の契約と、Wind coverage #3371 の限界を確認してください。過去の issue は背景情報であり、現在の公開ゲートが通過した証拠ではありません。
任意の導入と検証
静的な agent export と MCP は個別に選択する任意の機能で、このコア移行の必須条件ではありません。zudoDoc() を直接設定する場合、パッケージの agentExport、mcp、llmsTxt の既定値はすべて false です。create-zudo-doc の initializer は llmsTxt を既定で選択し、agent export と MCP は任意の選択です。明示的に導入しない限り、既存の選択を維持してください。完全な導入手順は llms.txt、Agent-readable export、MCP サーバーを参照してください。
更新した本番サイトをデプロイする前に、公開済みの 6.0.0 パッケージで検証します。strict な型検査(廃止 export・無効 props が拒否されることも)、公開 CSS/manifest の解決、実ビルド、hydration、繰り返すナビゲーションが対象です。base path、locale fallback、history fallback のシリアライズ、開いた dialog、sidebar の永続状態、パネルによる変数更新も確認します。二言語の内容を揃え、format と link 検査を実行してください。