@takazudo/zfb
Rust-built static-site engine for Astro and Next.js users — millisecond rebuilds, single binary.
The public SDK module for zfb: islands, content collections,
pagination, config, plugins, and frontmatter helpers. User pages reach this
package through the bare specifier "zfb" — the zfb-render runtime loader
registers the source under that name at build time so user TSX can write:
import { Island } from "zfb";Full documentation: https://takazudomodular.com/pj/zudo-front-builder/. Source: https://github.com/Takazudo/zudo-front-builder.
Install
npm install @takazudo/zfb
# or: pnpm add @takazudo/zfb
# or: yarn add @takazudo/zfbWhat lives here
This package is the canonical TypeScript source for the zfb SDK
surface. Today it covers:
<Island when="visible|idle|load">— JSX wrapper that marks a region for client-side hydration.scheduleHydrate(target, when, fire)— the runtime branching helper consumed by the hydration runtime.When,WHEN_VALUES,DEFAULT_WHEN,isWhen,resolveWhen— type and runtime utilities pinning the spelling of the three modes.getCollection(name),parseFrontmatter(raw)— content collection helpers exported fromzfb/content.parseFrontmatteris part of the public SDK surface so consumers can write custom content loaders that reuse the v0 frontmatter parser without re-implementing it.defaultComponents— eleven-entry per-element override map (h2,h3,h4,p,a,strong,blockquote,ul,ol,table,code) ported from zudo-doc'shtmlOverridesconvention.h1is deliberately omitted because page titles render<h1>from frontmatter. Each entry is a thin passthrough and is also exported as a named const (ContentParagraph,ContentLink, …) so consumers can tree-shake-import a single override. Spread into acomponentsprop to compose with custom overrides:import { defaultComponents } from "zfb"; <entry.Content components={{ ...defaultComponents, h2: MyFancyH2 }} />paginate(items, opts), plusPaginatedPage<T>/PaginateRoute<T>— exported fromzfb/paginate.defineConfig(config)— exported fromzfb/configfor thezfb.config.tsform (the recommended way to author a zfb project's configuration; the back-compatzfb.config.jsonform is still supported).
The package is JSX-runtime-agnostic: the Island component does not
import preact or react, so it works under either framework adapter
without bundling the wrong runtime.
Usage
import { Island } from "zfb";
import { Counter } from "../components/Counter.tsx"; // a "use client" component
export default function Page() {
return (
<>
<h1>Welcome</h1>
{/* Hydrate immediately on page load (default). */}
<Island>
<Counter />
</Island>
{/* Hydrate during the next idle callback. */}
<Island when="idle">
<Counter />
</Island>
{/* Hydrate only when the island first scrolls into view. */}
<Island when="visible">
<Counter />
</Island>
</>
);
}The three when= modes
when |
Trigger | Fallback |
|---|---|---|
"load" |
Synchronous, immediate fire after registration. Default. | n/a |
"idle" |
requestIdleCallback |
setTimeout(0) when not available |
"visible" |
IntersectionObserver, threshold 0, first intersection only |
Immediate fire when IntersectionObserver is missing |
Unknown values produce a console.warn in development builds and fall
back to "load".
Build-time output
The wrapper is intentionally type-erased at the JSX boundary. At the
call site, <Island when="visible">{children}</Island> renders as:
<div data-zfb-island data-when="visible"><!-- children --></div>The data-zfb-island attribute is empty here. The hydration emit step
in the zfb-render runtime walks rendered HTML and replaces it with
data-zfb-island="ComponentName" so the client-side hydration runtime
can look up the right module to call.
Runtime helper
The hydration runtime imports (or inlines) scheduleHydrate from this
package:
import { scheduleHydrate } from "@takazudo/zfb/runtime";
for (const el of document.querySelectorAll<HTMLElement>("[data-zfb-island]")) {
const when = el.getAttribute("data-when") ?? "load";
scheduleHydrate(el, when, () => hydrateOne(el));
}scheduleHydrate returns a cancel function that aborts the schedule
if hydration has not fired yet. After firing, calling cancel is a
no-op.
Markdown / GFM config
ZfbConfig.markdown.gfm controls which GitHub-Flavored-Markdown
constructs the MDX parser recognises. The field accepts three shapes:
Shorthand boolean — turn every GFM construct on or off in one step. Use this when you want the full GFM surface.
// zfb.config.ts import { defineConfig } from "zfb/config"; export default defineConfig({ markdown: { gfm: true, // strikethrough + table + autolink-literal + task-list-item + footnote-definition }, });Partial object — toggle individual constructs. Fields you omit fall back to the conservative default (
strikethrough: true,table: true, everything else off).// zfb.config.ts import { defineConfig } from "zfb/config"; export default defineConfig({ markdown: { gfm: { strikethrough: true, table: true, autolinkLiteral: false, // explicit opt-out taskListItem: false, footnoteDefinition: false, }, }, });Omitted entirely — the parser uses the conservative default.
~~text~~parses as<del>text</del>and pipe tables render as<table>; every other GFM construct stays off.export default defineConfig({ // no `markdown` field — strikethrough + table on, everything else off });
The five constructs you can toggle are: strikethrough, table,
autolinkLiteral, taskListItem, footnoteDefinition.
Projects that previously relied on raw ~~text~~ passing through as
literal characters should set markdown: { gfm: { strikethrough: false } }
or markdown: { gfm: false } to restore the old behaviour.
Tests
pnpm --filter @takazudo/zfb testThe tests run under vitest with happy-dom as the DOM implementation; no real browser is required.