@takazudo/zfb 0.1.0-next.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +45 -0
- package/LICENSE +21 -0
- package/README.md +207 -0
- package/bin/zfb.mjs +82 -0
- package/dist/config.d.ts +542 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +24 -0
- package/dist/config.js.map +1 -0
- package/dist/content.d.ts +240 -0
- package/dist/content.d.ts.map +1 -0
- package/dist/content.js +460 -0
- package/dist/content.js.map +1 -0
- package/dist/frontmatter.d.ts +23 -0
- package/dist/frontmatter.d.ts.map +1 -0
- package/dist/frontmatter.js +142 -0
- package/dist/frontmatter.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +21 -0
- package/dist/index.js.map +1 -0
- package/dist/island.d.ts +121 -0
- package/dist/island.d.ts.map +1 -0
- package/dist/island.js +273 -0
- package/dist/island.js.map +1 -0
- package/dist/jsx-types.d.ts +37 -0
- package/dist/jsx-types.d.ts.map +1 -0
- package/dist/jsx-types.js +12 -0
- package/dist/jsx-types.js.map +1 -0
- package/dist/paginate.d.ts +43 -0
- package/dist/paginate.d.ts.map +1 -0
- package/dist/paginate.js +44 -0
- package/dist/paginate.js.map +1 -0
- package/dist/plugins.d.ts +259 -0
- package/dist/plugins.d.ts.map +1 -0
- package/dist/plugins.js +42 -0
- package/dist/plugins.js.map +1 -0
- package/dist/runtime.d.ts +101 -0
- package/dist/runtime.d.ts.map +1 -0
- package/dist/runtime.js +454 -0
- package/dist/runtime.js.map +1 -0
- package/dist/types.d.ts +27 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +33 -0
- package/dist/types.js.map +1 -0
- package/package.json +98 -0
package/dist/runtime.js
ADDED
|
@@ -0,0 +1,454 @@
|
|
|
1
|
+
// Hydration scheduling helper consumed by the hydration runtime (Sub 3).
|
|
2
|
+
//
|
|
3
|
+
// Sub 3 owns the hydration runtime that walks the DOM, finds elements
|
|
4
|
+
// marked with `data-zfb-island`, and dispatches each one through this
|
|
5
|
+
// helper to decide *when* to fire the actual hydrate() call. The helper
|
|
6
|
+
// itself does not know how to hydrate — it only schedules the supplied
|
|
7
|
+
// `fire` callback.
|
|
8
|
+
//
|
|
9
|
+
// The branching matches the `When` union exactly:
|
|
10
|
+
// "visible" → IntersectionObserver, threshold 0.0, hydrate on first
|
|
11
|
+
// intersection, then disconnect.
|
|
12
|
+
// "idle" → requestIdleCallback if available, otherwise setTimeout(0).
|
|
13
|
+
// "load" → immediate, synchronous fire.
|
|
14
|
+
//
|
|
15
|
+
// Anything else is treated as "load" (with a console.warn in development).
|
|
16
|
+
// The helper is environment-tolerant: callers can run it in jsdom /
|
|
17
|
+
// happy-dom or bare Node, and the absence of `IntersectionObserver` /
|
|
18
|
+
// `requestIdleCallback` is handled gracefully.
|
|
19
|
+
import { resolveWhen } from "./types.js";
|
|
20
|
+
const g = globalThis;
|
|
21
|
+
/**
|
|
22
|
+
* Schedule a hydration `fire` callback for `target` according to `when`.
|
|
23
|
+
*
|
|
24
|
+
* Returns a `cancel` function that aborts the scheduling if it has not
|
|
25
|
+
* fired yet. After firing, calling `cancel` is a no-op. If the helper
|
|
26
|
+
* cannot find the relevant browser API (e.g. running in pure Node with no
|
|
27
|
+
* polyfill), it falls back to firing synchronously so server-side smoke
|
|
28
|
+
* tests still observe the call.
|
|
29
|
+
*/
|
|
30
|
+
export function scheduleHydrate(target, when, fire) {
|
|
31
|
+
const resolved = resolveWhen(when);
|
|
32
|
+
if (resolved === "load") {
|
|
33
|
+
fire();
|
|
34
|
+
return noop;
|
|
35
|
+
}
|
|
36
|
+
if (resolved === "idle") {
|
|
37
|
+
return scheduleIdle(fire);
|
|
38
|
+
}
|
|
39
|
+
// "visible"
|
|
40
|
+
return scheduleVisible(target, fire);
|
|
41
|
+
}
|
|
42
|
+
function noop() {
|
|
43
|
+
// intentionally empty
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Build a one-shot gate around `fn`. The returned `run` invokes `fn`
|
|
47
|
+
* exactly once provided `cancel` has not been called first; `cancel`
|
|
48
|
+
* marks the gate as cancelled (later `run` invocations become no-ops)
|
|
49
|
+
* and reports whether the gate had already fired.
|
|
50
|
+
*/
|
|
51
|
+
function oneShot(fn) {
|
|
52
|
+
let fired = false;
|
|
53
|
+
let cancelled = false;
|
|
54
|
+
return {
|
|
55
|
+
run() {
|
|
56
|
+
if (cancelled || fired)
|
|
57
|
+
return;
|
|
58
|
+
fired = true;
|
|
59
|
+
fn();
|
|
60
|
+
},
|
|
61
|
+
cancel() {
|
|
62
|
+
if (fired)
|
|
63
|
+
return true;
|
|
64
|
+
cancelled = true;
|
|
65
|
+
return false;
|
|
66
|
+
},
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
function scheduleIdle(fire) {
|
|
70
|
+
const gate = oneShot(fire);
|
|
71
|
+
if (typeof g.requestIdleCallback === "function") {
|
|
72
|
+
const handle = g.requestIdleCallback(gate.run);
|
|
73
|
+
return () => {
|
|
74
|
+
const alreadyFired = gate.cancel();
|
|
75
|
+
if (alreadyFired)
|
|
76
|
+
return;
|
|
77
|
+
if (typeof g.cancelIdleCallback === "function")
|
|
78
|
+
g.cancelIdleCallback(handle);
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
const handle = setTimeout(gate.run, 0);
|
|
82
|
+
return () => {
|
|
83
|
+
const alreadyFired = gate.cancel();
|
|
84
|
+
if (alreadyFired)
|
|
85
|
+
return;
|
|
86
|
+
clearTimeout(handle);
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
function scheduleVisible(target, fire) {
|
|
90
|
+
const Observer = g.IntersectionObserver;
|
|
91
|
+
// No IntersectionObserver (e.g. very old browsers, bare Node) — fail
|
|
92
|
+
// open and hydrate immediately so the island is at least functional.
|
|
93
|
+
if (typeof Observer !== "function") {
|
|
94
|
+
fire();
|
|
95
|
+
return noop;
|
|
96
|
+
}
|
|
97
|
+
const gate = oneShot(fire);
|
|
98
|
+
const observer = new Observer((entries, obs) => {
|
|
99
|
+
for (const entry of entries) {
|
|
100
|
+
if (entry.isIntersecting) {
|
|
101
|
+
obs.disconnect();
|
|
102
|
+
gate.run();
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}, { threshold: 0 });
|
|
107
|
+
observer.observe(target);
|
|
108
|
+
return () => {
|
|
109
|
+
const alreadyFired = gate.cancel();
|
|
110
|
+
if (alreadyFired)
|
|
111
|
+
return;
|
|
112
|
+
observer.disconnect();
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
// WeakMap<Element, unmount thunk> — replaces the old WeakSet.
|
|
116
|
+
// Value is a per-element function that calls the bundle's unmount(element)
|
|
117
|
+
// (or a noop if the bundle does not expose one). Used by unmountIslands()
|
|
118
|
+
// to fire framework lifecycle cleanups before a body swap.
|
|
119
|
+
const mounted = new WeakMap();
|
|
120
|
+
// Elements with an in-flight dynamic import that has not yet resolved.
|
|
121
|
+
// Two concurrent `mountIslands` invocations (or two `scheduleMount`
|
|
122
|
+
// calls hitting the same element through different code paths) could
|
|
123
|
+
// otherwise both pass the `mounted` guard and both spawn an
|
|
124
|
+
// `importIsland(url)` -> `fn()` chain, double-mounting the component.
|
|
125
|
+
// Adding the element to `pending` synchronously, before the import is
|
|
126
|
+
// fired, closes that window; the entry is removed in both the success
|
|
127
|
+
// (after `mounted.set`) and failure branches.
|
|
128
|
+
const pending = new WeakSet();
|
|
129
|
+
// Module-level captured manifest — set by the first `mountIslands` call and reused by
|
|
130
|
+
// `mountNewIslands()` so the client-router does not need to know the manifest directly.
|
|
131
|
+
// Named technical cause (W1B §12.1): the router lives in @takazudo/zfb-runtime; the
|
|
132
|
+
// islands manifest lives in @takazudo/zfb. Passing the manifest through the swap event
|
|
133
|
+
// would require widening the event API or threading manifest into router options. The
|
|
134
|
+
// captured-manifest pattern keeps the package boundary clean.
|
|
135
|
+
let capturedManifest = null;
|
|
136
|
+
// Map of element → cancel-function for deferred-hydration islands (data-when="idle"|"visible").
|
|
137
|
+
// Populated in scheduleMount; consulted on `zfb:before-swap` so deferred fires do not run
|
|
138
|
+
// against orphan elements after a body swap. (W1B §12.5)
|
|
139
|
+
const pendingCancels = new Map();
|
|
140
|
+
/**
|
|
141
|
+
* Walk the DOM and mount every `[data-zfb-island]` / `[data-zfb-island-skip-ssr]`
|
|
142
|
+
* element using `manifest`.
|
|
143
|
+
*
|
|
144
|
+
* No-op when `document` is undefined (SSR, edge runtime). Safe to call
|
|
145
|
+
* multiple times: each element is mounted at most once thanks to the
|
|
146
|
+
* `mounted` WeakSet guard.
|
|
147
|
+
*
|
|
148
|
+
* The manifest is captured at module level so `mountNewIslands()` can re-use
|
|
149
|
+
* it after an SPA body swap without needing the caller to re-supply it.
|
|
150
|
+
*/
|
|
151
|
+
export function mountIslands(manifest) {
|
|
152
|
+
if (typeof document === "undefined")
|
|
153
|
+
return;
|
|
154
|
+
// Capture the manifest for post-swap re-walks via mountNewIslands().
|
|
155
|
+
capturedManifest = manifest;
|
|
156
|
+
const ssrIslands = document.querySelectorAll("[data-zfb-island]");
|
|
157
|
+
for (const el of Array.from(ssrIslands)) {
|
|
158
|
+
// Skip the empty-skeleton case left behind when the server-side
|
|
159
|
+
// rewriter has not run yet (data-zfb-island="" with no component
|
|
160
|
+
// name). The hydration emit step is expected to fill this in
|
|
161
|
+
// before the page reaches the browser; if it didn't, we cannot
|
|
162
|
+
// dispatch.
|
|
163
|
+
const name = el.getAttribute("data-zfb-island");
|
|
164
|
+
if (!name)
|
|
165
|
+
continue;
|
|
166
|
+
scheduleMount(manifest, el, name, "hydrate");
|
|
167
|
+
}
|
|
168
|
+
const skipSsrIslands = document.querySelectorAll("[data-zfb-island-skip-ssr]");
|
|
169
|
+
for (const el of Array.from(skipSsrIslands)) {
|
|
170
|
+
const name = el.getAttribute("data-zfb-island-skip-ssr");
|
|
171
|
+
if (!name)
|
|
172
|
+
continue;
|
|
173
|
+
scheduleMount(manifest, el, name, "render");
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Re-walk the current document body and mount any new island markers introduced
|
|
178
|
+
* by an SPA body swap. Uses the manifest captured by the previous `mountIslands`
|
|
179
|
+
* call — no manifest arg required.
|
|
180
|
+
*
|
|
181
|
+
* The caller (client-router `router.ts`) invokes this after `swap()` + `runScripts()`
|
|
182
|
+
* and before dispatching `zfb:page-load`, per W1B §12.2 contract.
|
|
183
|
+
*
|
|
184
|
+
* No-op when called before `mountIslands` (capturedManifest is null) or when
|
|
185
|
+
* `document` is undefined.
|
|
186
|
+
*/
|
|
187
|
+
export function mountNewIslands() {
|
|
188
|
+
if (typeof document === "undefined")
|
|
189
|
+
return;
|
|
190
|
+
if (capturedManifest === null)
|
|
191
|
+
return;
|
|
192
|
+
const manifest = capturedManifest;
|
|
193
|
+
const ssrIslands = document.querySelectorAll("[data-zfb-island]");
|
|
194
|
+
for (const el of Array.from(ssrIslands)) {
|
|
195
|
+
const name = el.getAttribute("data-zfb-island");
|
|
196
|
+
if (!name)
|
|
197
|
+
continue;
|
|
198
|
+
scheduleMount(manifest, el, name, "hydrate");
|
|
199
|
+
}
|
|
200
|
+
const skipSsrIslands = document.querySelectorAll("[data-zfb-island-skip-ssr]");
|
|
201
|
+
for (const el of Array.from(skipSsrIslands)) {
|
|
202
|
+
const name = el.getAttribute("data-zfb-island-skip-ssr");
|
|
203
|
+
if (!name)
|
|
204
|
+
continue;
|
|
205
|
+
scheduleMount(manifest, el, name, "render");
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* Cancel deferred-hydration callbacks for all islands in the old body before a
|
|
210
|
+
* swap. Prevents idle / visibility callbacks from running against orphan elements
|
|
211
|
+
* after `swapBodyElement` removes them from the live document. (W1B §12.5)
|
|
212
|
+
*
|
|
213
|
+
* Call this on `zfb:before-swap` (or equivalently, in the router's swap sequence
|
|
214
|
+
* before `swap()` mutates the DOM). Fire-and-forget; safe to call if nothing is
|
|
215
|
+
* pending.
|
|
216
|
+
*/
|
|
217
|
+
export function cancelPendingIslands() {
|
|
218
|
+
for (const [el, cancel] of pendingCancels) {
|
|
219
|
+
cancel();
|
|
220
|
+
pendingCancels.delete(el);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
function scheduleMount(manifest, element, componentName, mode) {
|
|
224
|
+
// Skip elements already mounted OR currently importing — the latter
|
|
225
|
+
// prevents two concurrent `mountIslands` calls from each firing a
|
|
226
|
+
// separate dynamic import for the same element.
|
|
227
|
+
if (mounted.has(element) || pending.has(element))
|
|
228
|
+
return;
|
|
229
|
+
const entry = manifest[componentName];
|
|
230
|
+
if (entry == null) {
|
|
231
|
+
if (typeof process !== "undefined" && process.env && process.env["NODE_ENV"] !== "production") {
|
|
232
|
+
// eslint-disable-next-line no-console
|
|
233
|
+
console.warn(`[zfb] no island manifest entry for component "${componentName}" — ` +
|
|
234
|
+
`the runtime manifest is out of sync with the rendered HTML.`);
|
|
235
|
+
}
|
|
236
|
+
return;
|
|
237
|
+
}
|
|
238
|
+
const props = readProps(element);
|
|
239
|
+
const when = element.getAttribute("data-when") ?? undefined;
|
|
240
|
+
// Two manifest shapes:
|
|
241
|
+
//
|
|
242
|
+
// - `string` (per-island bundle URL): fetch via dynamic `import()`
|
|
243
|
+
// and call `mount` / `default` on the resolved module.
|
|
244
|
+
// - `IslandModule` (inline descriptor): the shared-bundle path has
|
|
245
|
+
// already imported every island's source into the same bundle and
|
|
246
|
+
// constructed a mount function for it. Skip the dynamic import
|
|
247
|
+
// and call the supplied function directly.
|
|
248
|
+
if (typeof entry !== "string") {
|
|
249
|
+
fireInlineMount(element, entry, props, mode);
|
|
250
|
+
return;
|
|
251
|
+
}
|
|
252
|
+
const url = entry;
|
|
253
|
+
const fire = () => {
|
|
254
|
+
// Re-check both guards in case `fire` is invoked from a deferred
|
|
255
|
+
// scheduler (rIC/rAF/visibility) after a sibling caller already
|
|
256
|
+
// mounted or started importing for this element.
|
|
257
|
+
if (mounted.has(element) || pending.has(element))
|
|
258
|
+
return;
|
|
259
|
+
// When the deferred fire actually runs, the cancel handle is no longer
|
|
260
|
+
// needed — remove it so pendingCancels doesn't hold stale entries.
|
|
261
|
+
pendingCancels.delete(element);
|
|
262
|
+
// Mark as pending BEFORE firing the import so any concurrent
|
|
263
|
+
// `mountIslands` invocation that arrives during the await window
|
|
264
|
+
// is short-circuited by `scheduleMount`'s guard.
|
|
265
|
+
pending.add(element);
|
|
266
|
+
// Dynamic-import is cached by the JS runtime, so repeat hits for
|
|
267
|
+
// the same URL share the resolved module — module-level
|
|
268
|
+
// singletons are fine.
|
|
269
|
+
//
|
|
270
|
+
// We move the element from `pending` to `mounted` only on the
|
|
271
|
+
// success path so a failed import (e.g. transient network blip
|
|
272
|
+
// in dev) doesn't permanently block a retry of the same element.
|
|
273
|
+
let started;
|
|
274
|
+
try {
|
|
275
|
+
started = importIsland(url);
|
|
276
|
+
}
|
|
277
|
+
catch (err) {
|
|
278
|
+
// Some implementations of dynamic-import wrappers can throw
|
|
279
|
+
// synchronously (e.g. URL parsing errors). Treat the same as
|
|
280
|
+
// an async rejection.
|
|
281
|
+
pending.delete(element);
|
|
282
|
+
// eslint-disable-next-line no-console
|
|
283
|
+
console.error(`[zfb] failed to start dynamic import for ${url}`, err);
|
|
284
|
+
return;
|
|
285
|
+
}
|
|
286
|
+
started.then((mod) => {
|
|
287
|
+
const fn = mod.mount ?? mod.default;
|
|
288
|
+
if (typeof fn !== "function") {
|
|
289
|
+
pending.delete(element);
|
|
290
|
+
if (typeof process !== "undefined" &&
|
|
291
|
+
process.env &&
|
|
292
|
+
process.env["NODE_ENV"] !== "production") {
|
|
293
|
+
// eslint-disable-next-line no-console
|
|
294
|
+
console.warn(`[zfb] island bundle at ${url} did not export mount() or default()`);
|
|
295
|
+
}
|
|
296
|
+
return;
|
|
297
|
+
}
|
|
298
|
+
// Stale-mount race guard: if the element was detached while the
|
|
299
|
+
// dynamic import was in-flight (e.g. a body swap happened), skip
|
|
300
|
+
// mounting — the element is no longer in the live document and
|
|
301
|
+
// its useEffect listeners would never receive a cleanup call.
|
|
302
|
+
if (!element.isConnected) {
|
|
303
|
+
pending.delete(element);
|
|
304
|
+
return;
|
|
305
|
+
}
|
|
306
|
+
const unmountThunk = mod.unmount
|
|
307
|
+
? () => mod.unmount(element)
|
|
308
|
+
: () => {
|
|
309
|
+
// noop — bundle does not expose unmount
|
|
310
|
+
};
|
|
311
|
+
mounted.set(element, unmountThunk);
|
|
312
|
+
pending.delete(element);
|
|
313
|
+
fn(props, element, mode);
|
|
314
|
+
}, (err) => {
|
|
315
|
+
// Surface the error in dev so the user notices, then clear
|
|
316
|
+
// both guards so a later retry (e.g. another scheduleHydrate
|
|
317
|
+
// fire) can attempt the import again.
|
|
318
|
+
pending.delete(element);
|
|
319
|
+
mounted.delete(element);
|
|
320
|
+
// eslint-disable-next-line no-console
|
|
321
|
+
console.error(`[zfb] failed to load island bundle ${url}`, err);
|
|
322
|
+
});
|
|
323
|
+
};
|
|
324
|
+
if (mode === "render") {
|
|
325
|
+
// SSR-skip islands ignore data-when: there is nothing to defer
|
|
326
|
+
// hydration of, just an empty container we paint into. Mount
|
|
327
|
+
// immediately so the user sees output.
|
|
328
|
+
fire();
|
|
329
|
+
return;
|
|
330
|
+
}
|
|
331
|
+
const cancel = scheduleHydrate(element, when, fire);
|
|
332
|
+
// Track deferred-hydration cancel handle so cancelPendingIslands() can abort
|
|
333
|
+
// idle / visibility callbacks before a body swap. (W1B §12.5)
|
|
334
|
+
if (when && when !== "load") {
|
|
335
|
+
pendingCancels.set(element, cancel);
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
/**
|
|
339
|
+
* Run the mount step for the inline-module manifest shape used by the
|
|
340
|
+
* shared-bundle path. The module is already in memory (it was imported
|
|
341
|
+
* into the bundle at build time), so there is no async window to
|
|
342
|
+
* coordinate around — we just call `mount` / `default` directly,
|
|
343
|
+
* gated by the same `data-when` semantics as the URL path.
|
|
344
|
+
*/
|
|
345
|
+
function fireInlineMount(element, mod, props, mode) {
|
|
346
|
+
const fn = mod.mount ?? mod.default;
|
|
347
|
+
if (typeof fn !== "function") {
|
|
348
|
+
if (typeof process !== "undefined" && process.env && process.env["NODE_ENV"] !== "production") {
|
|
349
|
+
// eslint-disable-next-line no-console
|
|
350
|
+
console.warn("[zfb] inline island manifest entry did not export mount() or default()");
|
|
351
|
+
}
|
|
352
|
+
return;
|
|
353
|
+
}
|
|
354
|
+
const fire = () => {
|
|
355
|
+
// Re-check the guard in case `fire` is invoked from a deferred
|
|
356
|
+
// scheduler (rIC/rAF/visibility) after a sibling caller already
|
|
357
|
+
// mounted this element.
|
|
358
|
+
if (mounted.has(element))
|
|
359
|
+
return;
|
|
360
|
+
// When the deferred fire actually runs, the cancel handle is no longer
|
|
361
|
+
// needed — remove it so pendingCancels doesn't hold stale entries.
|
|
362
|
+
pendingCancels.delete(element);
|
|
363
|
+
// Stale-mount race guard for deferred inline mounts: skip if the element
|
|
364
|
+
// was detached (e.g. body swap) while the idle/visible callback was queued.
|
|
365
|
+
if (!element.isConnected)
|
|
366
|
+
return;
|
|
367
|
+
const unmountThunk = mod.unmount
|
|
368
|
+
? () => mod.unmount(element)
|
|
369
|
+
: () => {
|
|
370
|
+
// noop — inline module does not expose unmount
|
|
371
|
+
};
|
|
372
|
+
mounted.set(element, unmountThunk);
|
|
373
|
+
fn(props, element, mode);
|
|
374
|
+
};
|
|
375
|
+
if (mode === "render") {
|
|
376
|
+
fire();
|
|
377
|
+
return;
|
|
378
|
+
}
|
|
379
|
+
const when = element.getAttribute("data-when") ?? undefined;
|
|
380
|
+
const cancel = scheduleHydrate(element, when, fire);
|
|
381
|
+
// Track deferred-hydration cancel handle so cancelPendingIslands() can abort
|
|
382
|
+
// idle / visibility callbacks before a body swap. (W1B §12.5)
|
|
383
|
+
if (when && when !== "load") {
|
|
384
|
+
pendingCancels.set(element, cancel);
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
/**
|
|
388
|
+
* Unmount all currently-mounted islands within `root` (default: `document.body`).
|
|
389
|
+
*
|
|
390
|
+
* Walks `root` for `[data-zfb-island]` and `[data-zfb-island-skip-ssr]` elements,
|
|
391
|
+
* looks up each element's unmount thunk in the `mounted` WeakMap, calls it (which
|
|
392
|
+
* triggers `render(null, element)` for Preact or `root.unmount()` for React), and
|
|
393
|
+
* removes the entry from the map so `mountNewIslands()` can re-mount later.
|
|
394
|
+
*
|
|
395
|
+
* Call this before `swapBodyElement(...)` so the OLD body's islands receive proper
|
|
396
|
+
* framework lifecycle cleanup (useEffect teardowns, etc.) before being discarded.
|
|
397
|
+
*
|
|
398
|
+
* No-op for elements not in the `mounted` map (e.g. never-mounted or already cleaned up).
|
|
399
|
+
*/
|
|
400
|
+
export function unmountIslands(root = document.body) {
|
|
401
|
+
const selector = "[data-zfb-island],[data-zfb-island-skip-ssr]";
|
|
402
|
+
const elements = root.querySelectorAll(selector);
|
|
403
|
+
for (const el of Array.from(elements)) {
|
|
404
|
+
const thunk = mounted.get(el);
|
|
405
|
+
if (thunk) {
|
|
406
|
+
thunk();
|
|
407
|
+
mounted.delete(el);
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
function readProps(element) {
|
|
412
|
+
const raw = element.getAttribute("data-props");
|
|
413
|
+
if (!raw)
|
|
414
|
+
return {};
|
|
415
|
+
try {
|
|
416
|
+
const parsed = JSON.parse(raw);
|
|
417
|
+
// Reject arrays explicitly: `typeof [] === "object"` is true but
|
|
418
|
+
// an array is not a valid props bag, and passing it through would
|
|
419
|
+
// mean the component receives index-keyed values where it
|
|
420
|
+
// expected a record. Fall through to the empty-object default
|
|
421
|
+
// instead of forwarding a malformed shape.
|
|
422
|
+
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
423
|
+
return parsed;
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
catch {
|
|
427
|
+
// fall through
|
|
428
|
+
}
|
|
429
|
+
return {};
|
|
430
|
+
}
|
|
431
|
+
/**
|
|
432
|
+
* Indirection so tests can stub the dynamic import without intercepting
|
|
433
|
+
* the global `import()`. In production this is a thin wrapper over
|
|
434
|
+
* native `import(url)`.
|
|
435
|
+
*/
|
|
436
|
+
let importImpl = (url) =>
|
|
437
|
+
// Modern bundlers (esbuild, Vite, Rollup, webpack) preserve a plain
|
|
438
|
+
// `import(<dynamic>)` call when the argument isn't a static literal,
|
|
439
|
+
// so we no longer need the `new Function(...)` indirection — which
|
|
440
|
+
// also failed under strict CSPs that disallow `unsafe-eval`.
|
|
441
|
+
import(/* @vite-ignore */ /* webpackIgnore: true */ url);
|
|
442
|
+
function importIsland(url) {
|
|
443
|
+
return importImpl(url);
|
|
444
|
+
}
|
|
445
|
+
/**
|
|
446
|
+
* Test-only seam. Replace the module dynamic-import with a fake.
|
|
447
|
+
* Returns the previous implementation so tests can restore it.
|
|
448
|
+
*/
|
|
449
|
+
export function __setIslandImporterForTests(impl) {
|
|
450
|
+
const prev = importImpl;
|
|
451
|
+
importImpl = impl;
|
|
452
|
+
return prev;
|
|
453
|
+
}
|
|
454
|
+
//# sourceMappingURL=runtime.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runtime.js","sourceRoot":"","sources":["../src/runtime.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hydration scheduling strategy.
|
|
3
|
+
*
|
|
4
|
+
* - `"visible"` — hydrate when the island first intersects the viewport
|
|
5
|
+
* (IntersectionObserver, threshold 0). Cheapest deferral for content the
|
|
6
|
+
* user has not scrolled to yet.
|
|
7
|
+
* - `"idle"` — hydrate during the next idle callback. Falls back to a
|
|
8
|
+
* `setTimeout(0)` on platforms without `requestIdleCallback`.
|
|
9
|
+
* - `"load"` — hydrate immediately and synchronously. Default when
|
|
10
|
+
* `when` is omitted.
|
|
11
|
+
*/
|
|
12
|
+
export type When = "visible" | "idle" | "load";
|
|
13
|
+
/** Public set of allowed `When` values, useful for runtime validation. */
|
|
14
|
+
export declare const WHEN_VALUES: readonly When[];
|
|
15
|
+
/** Default `when` strategy applied when `when` is omitted. */
|
|
16
|
+
export declare const DEFAULT_WHEN: When;
|
|
17
|
+
/** Type guard for `When`. */
|
|
18
|
+
export declare function isWhen(value: unknown): value is When;
|
|
19
|
+
/**
|
|
20
|
+
* Resolve the validated `when` value, warning in development for unknown
|
|
21
|
+
* inputs. Returns the input unchanged when valid, or [`DEFAULT_WHEN`]
|
|
22
|
+
* otherwise. Lives here (rather than in `island.ts`) so the runtime
|
|
23
|
+
* scheduler can import it without transitively pulling in the JSX
|
|
24
|
+
* wrapper.
|
|
25
|
+
*/
|
|
26
|
+
export declare function resolveWhen(when: unknown): When;
|
|
27
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAMA;;;;;;;;;;GAUG;AACH,MAAM,MAAM,IAAI,GAAG,SAAS,GAAG,MAAM,GAAG,MAAM,CAAC;AAE/C,0EAA0E;AAC1E,eAAO,MAAM,WAAW,EAAE,SAAS,IAAI,EAAgC,CAAC;AAExE,8DAA8D;AAC9D,eAAO,MAAM,YAAY,EAAE,IAAa,CAAC;AAEzC,6BAA6B;AAC7B,wBAAgB,MAAM,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,IAAI,CAEpD;AAED;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,CAW/C"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
// Public type surface for the zfb island system.
|
|
2
|
+
//
|
|
3
|
+
// `When` is the string-literal union of allowed `data-when` values. The
|
|
4
|
+
// hydration runtime (Sub 3) reads the same attribute and dispatches on the
|
|
5
|
+
// same set of strings. Keep these in sync; the unit tests pin the spelling.
|
|
6
|
+
/** Public set of allowed `When` values, useful for runtime validation. */
|
|
7
|
+
export const WHEN_VALUES = ["visible", "idle", "load"];
|
|
8
|
+
/** Default `when` strategy applied when `when` is omitted. */
|
|
9
|
+
export const DEFAULT_WHEN = "load";
|
|
10
|
+
/** Type guard for `When`. */
|
|
11
|
+
export function isWhen(value) {
|
|
12
|
+
return typeof value === "string" && WHEN_VALUES.includes(value);
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Resolve the validated `when` value, warning in development for unknown
|
|
16
|
+
* inputs. Returns the input unchanged when valid, or [`DEFAULT_WHEN`]
|
|
17
|
+
* otherwise. Lives here (rather than in `island.ts`) so the runtime
|
|
18
|
+
* scheduler can import it without transitively pulling in the JSX
|
|
19
|
+
* wrapper.
|
|
20
|
+
*/
|
|
21
|
+
export function resolveWhen(when) {
|
|
22
|
+
if (when === undefined)
|
|
23
|
+
return DEFAULT_WHEN;
|
|
24
|
+
if (isWhen(when))
|
|
25
|
+
return when;
|
|
26
|
+
if (typeof process !== "undefined" && process.env && process.env["NODE_ENV"] !== "production") {
|
|
27
|
+
// eslint-disable-next-line no-console
|
|
28
|
+
console.warn(`[zfb] <Island when="${String(when)}"> is not a valid value. ` +
|
|
29
|
+
`Expected "visible" | "idle" | "load". Falling back to "${DEFAULT_WHEN}".`);
|
|
30
|
+
}
|
|
31
|
+
return DEFAULT_WHEN;
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,iDAAiD;AACjD,EAAE;AACF,wEAAwE;AACxE,2EAA2E;AAC3E,4EAA4E;AAe5E,0EAA0E;AAC1E,MAAM,CAAC,MAAM,WAAW,GAAoB,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;AAExE,8DAA8D;AAC9D,MAAM,CAAC,MAAM,YAAY,GAAS,MAAM,CAAC;AAEzC,6BAA6B;AAC7B,MAAM,UAAU,MAAM,CAAC,KAAc;IACnC,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAK,WAAiC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;AACzF,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,WAAW,CAAC,IAAa;IACvC,IAAI,IAAI,KAAK,SAAS;QAAE,OAAO,YAAY,CAAC;IAC5C,IAAI,MAAM,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC;IAC9B,IAAI,OAAO,OAAO,KAAK,WAAW,IAAI,OAAO,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,KAAK,YAAY,EAAE,CAAC;QAC9F,sCAAsC;QACtC,OAAO,CAAC,IAAI,CACV,uBAAuB,MAAM,CAAC,IAAI,CAAC,2BAA2B;YAC5D,0DAA0D,YAAY,IAAI,CAC7E,CAAC;IACJ,CAAC;IACD,OAAO,YAAY,CAAC;AACtB,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@takazudo/zfb",
|
|
3
|
+
"version": "0.1.0-next.10",
|
|
4
|
+
"private": false,
|
|
5
|
+
"type": "module",
|
|
6
|
+
"description": "Rust-built static-site engine for Astro and Next.js users — millisecond rebuilds, single binary. SDK with islands, content collections, pagination, and config helpers.",
|
|
7
|
+
"keywords": [
|
|
8
|
+
"zfb",
|
|
9
|
+
"static-site-generator",
|
|
10
|
+
"ssg",
|
|
11
|
+
"islands",
|
|
12
|
+
"mdx",
|
|
13
|
+
"content-collections",
|
|
14
|
+
"preact",
|
|
15
|
+
"react",
|
|
16
|
+
"rust"
|
|
17
|
+
],
|
|
18
|
+
"license": "MIT",
|
|
19
|
+
"author": "Takeshi Takatsudo <takazudo@gmail.com> (https://github.com/Takazudo)",
|
|
20
|
+
"homepage": "https://takazudomodular.com/pj/zudo-front-builder/",
|
|
21
|
+
"repository": {
|
|
22
|
+
"type": "git",
|
|
23
|
+
"url": "git+https://github.com/Takazudo/zudo-front-builder.git",
|
|
24
|
+
"directory": "packages/zfb"
|
|
25
|
+
},
|
|
26
|
+
"bugs": {
|
|
27
|
+
"url": "https://github.com/Takazudo/zudo-front-builder/issues"
|
|
28
|
+
},
|
|
29
|
+
"main": "./dist/index.js",
|
|
30
|
+
"types": "./dist/index.d.ts",
|
|
31
|
+
"exports": {
|
|
32
|
+
".": {
|
|
33
|
+
"types": "./dist/index.d.ts",
|
|
34
|
+
"default": "./dist/index.js"
|
|
35
|
+
},
|
|
36
|
+
"./runtime": {
|
|
37
|
+
"types": "./dist/runtime.d.ts",
|
|
38
|
+
"default": "./dist/runtime.js"
|
|
39
|
+
},
|
|
40
|
+
"./content": {
|
|
41
|
+
"types": "./dist/content.d.ts",
|
|
42
|
+
"default": "./dist/content.js"
|
|
43
|
+
},
|
|
44
|
+
"./paginate": {
|
|
45
|
+
"types": "./dist/paginate.d.ts",
|
|
46
|
+
"default": "./dist/paginate.js"
|
|
47
|
+
},
|
|
48
|
+
"./config": {
|
|
49
|
+
"types": "./dist/config.d.ts",
|
|
50
|
+
"default": "./dist/config.js"
|
|
51
|
+
},
|
|
52
|
+
"./plugins": {
|
|
53
|
+
"types": "./dist/plugins.d.ts",
|
|
54
|
+
"default": "./dist/plugins.js"
|
|
55
|
+
},
|
|
56
|
+
"./frontmatter": {
|
|
57
|
+
"types": "./dist/frontmatter.d.ts",
|
|
58
|
+
"default": "./dist/frontmatter.js"
|
|
59
|
+
},
|
|
60
|
+
"./package.json": "./package.json"
|
|
61
|
+
},
|
|
62
|
+
"bin": {
|
|
63
|
+
"zfb": "./bin/zfb.mjs"
|
|
64
|
+
},
|
|
65
|
+
"files": [
|
|
66
|
+
"dist",
|
|
67
|
+
"bin",
|
|
68
|
+
"README.md",
|
|
69
|
+
"CHANGELOG.md",
|
|
70
|
+
"LICENSE"
|
|
71
|
+
],
|
|
72
|
+
"optionalDependencies": {
|
|
73
|
+
"@takazudo/zfb-darwin-arm64": "0.1.0-next.10",
|
|
74
|
+
"@takazudo/zfb-darwin-x64": "0.1.0-next.10",
|
|
75
|
+
"@takazudo/zfb-linux-arm64-gnu": "0.1.0-next.10",
|
|
76
|
+
"@takazudo/zfb-linux-x64-gnu": "0.1.0-next.10",
|
|
77
|
+
"@takazudo/zfb-win32-x64-msvc": "0.1.0-next.10"
|
|
78
|
+
},
|
|
79
|
+
"publishConfig": {
|
|
80
|
+
"access": "public"
|
|
81
|
+
},
|
|
82
|
+
"engines": {
|
|
83
|
+
"node": ">=22.0.0",
|
|
84
|
+
"pnpm": ">=10.0.0"
|
|
85
|
+
},
|
|
86
|
+
"devDependencies": {
|
|
87
|
+
"@types/node": "^22.0.0",
|
|
88
|
+
"happy-dom": "^15.7.4",
|
|
89
|
+
"typescript": "^5.9.0",
|
|
90
|
+
"vitest": "^2.1.9"
|
|
91
|
+
},
|
|
92
|
+
"scripts": {
|
|
93
|
+
"build": "tsc",
|
|
94
|
+
"test": "vitest run",
|
|
95
|
+
"test:watch": "vitest",
|
|
96
|
+
"typecheck": "tsc --noEmit"
|
|
97
|
+
}
|
|
98
|
+
}
|