sibujs 4.13.1 → 4.14.1
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/README.md +1 -1
- package/dist/browser.cjs +15 -2
- package/dist/browser.js +9 -7
- package/dist/build.cjs +880 -281
- package/dist/build.d.cts +68 -3
- package/dist/build.d.ts +68 -3
- package/dist/build.js +88 -30
- package/dist/cdn.dev.global.js +12 -12
- package/dist/cdn.full.dev.global.js +13 -13
- package/dist/cdn.full.global.js +12 -12
- package/dist/cdn.global.js +12 -12
- package/dist/{chunk-J6FW5TV6.js → chunk-3HEX6QJQ.js} +5 -3
- package/dist/chunk-3HZOSMPX.js +90 -0
- package/dist/{chunk-K4LNUT5L.js → chunk-3T7TWMSD.js} +8 -6
- package/dist/{chunk-ADZHPN2B.js → chunk-4XCWNGRY.js} +3 -3
- package/dist/{chunk-2NC56RGY.js → chunk-55TAOW5M.js} +2 -2
- package/dist/{chunk-G3Z2FEBR.js → chunk-B2NLNZ3E.js} +119 -26
- package/dist/{chunk-EXXSN3BW.js → chunk-B3HOT4TK.js} +1 -1
- package/dist/{chunk-QKFVMIAV.js → chunk-FCWOMATN.js} +11 -3
- package/dist/{chunk-QC3NP47A.js → chunk-FFXZ6ELZ.js} +10 -6
- package/dist/{chunk-TUCPL2HB.js → chunk-GIJ33UJZ.js} +1 -1
- package/dist/chunk-KTJC7QPA.js +195 -0
- package/dist/chunk-L2IPKGUJ.js +2596 -0
- package/dist/{chunk-4UTGDVSA.js → chunk-LAHX7XFG.js} +7 -14
- package/dist/{chunk-PBJYCE2Z.js → chunk-LJ2LR5P4.js} +5 -5
- package/dist/{chunk-AM6DZLBM.js → chunk-LJMX4SQ7.js} +2 -2
- package/dist/{chunk-5RIBLY2N.js → chunk-LUZXFMKH.js} +6 -6
- package/dist/{chunk-VFPLWUT7.js → chunk-LZKKMDQF.js} +151 -86
- package/dist/{chunk-J4X7ICH4.js → chunk-NIHGSXOX.js} +8 -6
- package/dist/chunk-NT3ZYB5S.js +167 -0
- package/dist/{chunk-2O6JJCUR.js → chunk-OLMZF4RU.js} +49 -8
- package/dist/{chunk-22OPSWMF.js → chunk-OPRQW4LI.js} +2 -2
- package/dist/chunk-R5U7XKVJ.js +16 -0
- package/dist/{chunk-KC62VURU.js → chunk-RBRITLFL.js} +10 -8
- package/dist/{chunk-F2UWOZ6J.js → chunk-RVWJGWCL.js} +2 -2
- package/dist/{chunk-NYNYSPK7.js → chunk-S37PZD6I.js} +30 -45
- package/dist/chunk-TOV4PN3P.js +2015 -0
- package/dist/{chunk-C73VBPEF.js → chunk-TS6JDK7Y.js} +8 -8
- package/dist/{chunk-EU7T7EB3.js → chunk-TZNR6E6D.js} +4 -4
- package/dist/chunk-UYTYNCMZ.js +199 -0
- package/dist/{chunk-OIKD7YDY.js → chunk-VIAVYBNQ.js} +6 -5
- package/dist/{chunk-QZ47OZ25.js → chunk-WFMMSMA5.js} +8 -6
- package/dist/chunk-YIXMS546.js +1901 -0
- package/dist/{chunk-5XUGJM3J.js → chunk-YPLQQTWS.js} +1 -1
- package/dist/{chunk-CPQKWCJ2.js → chunk-ZKI4SDZ2.js} +16 -10
- package/dist/{chunk-YFTBCCVH.js → chunk-ZYK4NZZA.js} +5 -3
- package/dist/data.cjs +265 -35
- package/dist/data.d.cts +31 -1
- package/dist/data.d.ts +31 -1
- package/dist/data.js +16 -10
- package/dist/devtools.cjs +15 -2
- package/dist/devtools.js +9 -7
- package/dist/{dispose-GEIG2KOF.js → dispose-EIHHHDC7.js} +3 -1
- package/dist/ecosystem.cjs +62 -23
- package/dist/ecosystem.js +14 -12
- package/dist/extras.cjs +3562 -270
- package/dist/extras.d.cts +3 -3
- package/dist/extras.d.ts +3 -3
- package/dist/extras.js +39 -29
- package/dist/index.cjs +442 -253
- package/dist/index.d.cts +93 -283
- package/dist/index.d.ts +93 -283
- package/dist/index.js +26 -16
- package/dist/motion.cjs +12 -1
- package/dist/motion.js +6 -4
- package/dist/patterns.cjs +15 -2
- package/dist/patterns.js +10 -8
- package/dist/performance.cjs +36 -2
- package/dist/performance.d.cts +2 -2
- package/dist/performance.d.ts +2 -2
- package/dist/performance.js +14 -10
- package/dist/plugins.cjs +5267 -1807
- package/dist/plugins.d.cts +8 -834
- package/dist/plugins.d.ts +8 -834
- package/dist/plugins.js +64 -2329
- package/dist/prerenderServer-MXJEVWA3.js +350 -0
- package/dist/renderRoute-DP20XwMS.d.cts +86 -0
- package/dist/renderRoute-fxgsm2Ir.d.ts +86 -0
- package/dist/routeHead-CE9SV-cH.d.cts +995 -0
- package/dist/routeHead-DzVxPviY.d.ts +995 -0
- package/dist/{routeMiddleware-B1sp4P7a.d.ts → routeMiddleware-BySbueoE.d.ts} +0 -25
- package/dist/{routeMiddleware-CedQTsLK.d.cts → routeMiddleware-CijZD5eW.d.cts} +0 -25
- package/dist/{ssr-VBM6J5SJ.js → ssr-HHU3DAD2.js} +15 -6
- package/dist/ssr-JpGpHnpC.d.cts +841 -0
- package/dist/ssr-JpGpHnpC.d.ts +841 -0
- package/dist/ssr-dom.cjs +1904 -0
- package/dist/ssr-dom.d.cts +343 -0
- package/dist/ssr-dom.d.ts +343 -0
- package/dist/ssr-dom.js +19 -0
- package/dist/ssr.cjs +7677 -2069
- package/dist/ssr.d.cts +63 -5
- package/dist/ssr.d.ts +63 -5
- package/dist/ssr.js +136 -14
- package/dist/testing.cjs +6585 -87
- package/dist/testing.d.cts +80 -1
- package/dist/testing.d.ts +80 -1
- package/dist/testing.js +117 -4
- package/dist/ui.cjs +36 -2
- package/dist/ui.js +17 -14
- package/dist/widgets.cjs +14 -1
- package/dist/widgets.js +11 -9
- package/package.json +9 -2
- package/dist/chunk-2F4PSJ5Z.js +0 -765
- package/dist/chunk-7XHATCIH.js +0 -121
- package/dist/chunk-B36ADEIR.js +0 -21
- package/dist/ssr-Db0Sgdu3.d.cts +0 -245
- package/dist/ssr-Db0Sgdu3.d.ts +0 -245
package/dist/build.cjs
CHANGED
|
@@ -5,6 +5,9 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
|
5
5
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
6
|
var __getProtoOf = Object.getPrototypeOf;
|
|
7
7
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __esm = (fn, res) => function __init() {
|
|
9
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
10
|
+
};
|
|
8
11
|
var __export = (target, all) => {
|
|
9
12
|
for (var name in all)
|
|
10
13
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
@@ -27,6 +30,362 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
27
30
|
));
|
|
28
31
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
32
|
|
|
33
|
+
// src/build/prerenderServer.ts
|
|
34
|
+
var prerenderServer_exports = {};
|
|
35
|
+
__export(prerenderServer_exports, {
|
|
36
|
+
assertPrerendered: () => assertPrerendered,
|
|
37
|
+
buildSitemap: () => buildSitemap,
|
|
38
|
+
expandRoutes: () => expandRoutes,
|
|
39
|
+
injectIntoShell: () => injectIntoShell,
|
|
40
|
+
prerenderFromServerEntry: () => prerenderFromServerEntry
|
|
41
|
+
});
|
|
42
|
+
function joinPath(parent, child) {
|
|
43
|
+
if (child === "*" || child.startsWith("/*")) return child;
|
|
44
|
+
const p2 = parent.replace(/\/+$/, "");
|
|
45
|
+
const c = child.startsWith("/") ? child : `/${child}`;
|
|
46
|
+
return (p2 + c).replace(/\/{2,}/g, "/") || "/";
|
|
47
|
+
}
|
|
48
|
+
async function expandRoutes(routes) {
|
|
49
|
+
const out = [];
|
|
50
|
+
const visit = async (records, parent) => {
|
|
51
|
+
for (const record of records) {
|
|
52
|
+
if (!record || typeof record.path !== "string") continue;
|
|
53
|
+
const full = parent ? joinPath(parent, record.path) : record.path;
|
|
54
|
+
if (record.children?.length) await visit(record.children, full);
|
|
55
|
+
if (full.includes("*")) continue;
|
|
56
|
+
if ("redirect" in record && record.redirect !== void 0) {
|
|
57
|
+
if (!/:/.test(full)) out.push(full);
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
if (/:/.test(full)) {
|
|
61
|
+
if (typeof record.getStaticPaths !== "function") continue;
|
|
62
|
+
let entries;
|
|
63
|
+
try {
|
|
64
|
+
entries = await record.getStaticPaths();
|
|
65
|
+
} catch (err) {
|
|
66
|
+
throw new Error(
|
|
67
|
+
`[sibu prerender] getStaticPaths() of "${full}" failed: ${err instanceof Error ? err.message : String(err)}. If it reads an API, start it and point \`prerender.fetch\` at it.`,
|
|
68
|
+
{ cause: err }
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
for (const entry of entries) {
|
|
72
|
+
if (typeof entry === "string") {
|
|
73
|
+
out.push(entry);
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
let path2 = full;
|
|
77
|
+
for (const [key, value] of Object.entries(entry)) {
|
|
78
|
+
path2 = path2.replace(new RegExp(`:${key}(?=[/?#]|$)`, "g"), encodeURIComponent(String(value)));
|
|
79
|
+
}
|
|
80
|
+
if (/:[A-Za-z_]/.test(path2)) {
|
|
81
|
+
throw new Error(
|
|
82
|
+
`[sibu prerender] getStaticPaths() of "${full}" returned ${JSON.stringify(entry)}, which leaves a param unset`
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
out.push(path2);
|
|
86
|
+
}
|
|
87
|
+
continue;
|
|
88
|
+
}
|
|
89
|
+
if (record.children?.length) continue;
|
|
90
|
+
out.push(full);
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
await visit(routes, "");
|
|
94
|
+
return Array.from(new Set(out));
|
|
95
|
+
}
|
|
96
|
+
function escapeAttr(value) {
|
|
97
|
+
return value.replace(/&/g, "&").replace(/"/g, """).replace(/</g, "<").replace(/>/g, ">");
|
|
98
|
+
}
|
|
99
|
+
function escapeXml(value) {
|
|
100
|
+
return value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
101
|
+
}
|
|
102
|
+
function decodeTitleText(text2) {
|
|
103
|
+
const named = { amp: "&", lt: "<", gt: ">", quot: '"', apos: "'", nbsp: "\xA0" };
|
|
104
|
+
return text2.replace(/&(#x[0-9a-f]+|#[0-9]+|[a-z]+);/gi, (ref2, body2) => {
|
|
105
|
+
if (body2[0] !== "#") return named[body2.toLowerCase()] ?? ref2;
|
|
106
|
+
const code2 = body2[1] === "x" || body2[1] === "X" ? Number.parseInt(body2.slice(2), 16) : Number(body2.slice(1));
|
|
107
|
+
return code2 > 0 && code2 <= 1114111 ? String.fromCodePoint(code2) : ref2;
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
function injectIntoShell(shell, parts, container = "app") {
|
|
111
|
+
let html3 = shell;
|
|
112
|
+
const shellTitle = /<title>([\s\S]*?)<\/title>/i.exec(html3)?.[1] ?? "";
|
|
113
|
+
if (parts.head) {
|
|
114
|
+
let head2 = parts.head;
|
|
115
|
+
if (/<title>/i.test(head2)) {
|
|
116
|
+
html3 = html3.replace(/\s*<title>[\s\S]*?<\/title>/i, () => "");
|
|
117
|
+
const baseTitle = `<title data-sibu-base-title="${escapeAttr(decodeTitleText(shellTitle))}">`;
|
|
118
|
+
head2 = head2.replace(/<title>/i, () => baseTitle);
|
|
119
|
+
}
|
|
120
|
+
const headHtml = head2;
|
|
121
|
+
html3 = html3.replace(/<\/head>/i, () => ` ${headHtml}
|
|
122
|
+
</head>`);
|
|
123
|
+
}
|
|
124
|
+
if (parts.body) {
|
|
125
|
+
const id = container.replace(/[^A-Za-z0-9_-]/g, "");
|
|
126
|
+
const open = new RegExp(`(<([a-z][a-z0-9-]*)\\b[^>]*\\bid\\s*=\\s*["']${id}["'][^>]*>)([\\s\\S]*?)(</\\2>)`, "i");
|
|
127
|
+
if (!open.test(html3))
|
|
128
|
+
throw new Error(`[sibu prerender] the built index.html has no element with id="${id}" to render into`);
|
|
129
|
+
html3 = html3.replace(
|
|
130
|
+
open,
|
|
131
|
+
(_m, openTag, _tag, _inner, close) => `${openTag}${parts.body}${close}`
|
|
132
|
+
);
|
|
133
|
+
}
|
|
134
|
+
if (parts.state) html3 = html3.replace(/<\/body>/i, () => ` ${parts.state}
|
|
135
|
+
</body>`);
|
|
136
|
+
return html3;
|
|
137
|
+
}
|
|
138
|
+
function assertPrerendered(url, result, failures, timeout) {
|
|
139
|
+
if (failures.length > 0) {
|
|
140
|
+
throw new Error(
|
|
141
|
+
`[sibu prerender] ${url}: ${failures[0]}. The page needs data from an API that is not reachable at build time \u2014 start it and point \`prerender.fetch\` at it, or skip the request with isPrerendering().`
|
|
142
|
+
);
|
|
143
|
+
}
|
|
144
|
+
const pending = result.diagnostics.pending.join(", ");
|
|
145
|
+
if (result.failure === "timeout") {
|
|
146
|
+
throw new Error(
|
|
147
|
+
`[sibu prerender] ${url}: the route did not render within ${timeout} ms (pending: ${pending}). A lazy import, a guard or a route load did not finish in time; fix it or raise \`prerender.timeout\`.`
|
|
148
|
+
);
|
|
149
|
+
}
|
|
150
|
+
if (result.diagnostics.timedOut) {
|
|
151
|
+
throw new Error(`[sibu prerender] ${url}: did not settle within ${timeout} ms (pending: ${pending})`);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
function buildSitemap(origin, paths) {
|
|
155
|
+
const urls = paths.map((p2) => ` <url><loc>${escapeXml(origin + p2)}</loc></url>`).join("\n");
|
|
156
|
+
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
157
|
+
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
|
158
|
+
${urls}
|
|
159
|
+
</urlset>
|
|
160
|
+
`;
|
|
161
|
+
}
|
|
162
|
+
async function prerenderFromServerEntry(options, ctx, helpers) {
|
|
163
|
+
const fs = await import("fs/promises");
|
|
164
|
+
const path2 = await import("path");
|
|
165
|
+
const { pathToFileURL } = await import("url");
|
|
166
|
+
const { AsyncLocalStorage } = await import("async_hooks");
|
|
167
|
+
const outDir = options.outDir ? path2.resolve(ctx.root, options.outDir) : ctx.outDir;
|
|
168
|
+
const origin = (options.origin ?? "http://localhost").replace(/\/+$/, "");
|
|
169
|
+
const serverEntry = path2.resolve(ctx.root, String(options.server).replace(/^\//, ""));
|
|
170
|
+
const keptShell = path2.join(ctx.outDir, typeof options.shell === "string" ? options.shell : "200.html");
|
|
171
|
+
const shellPath = await fs.access(keptShell).then(() => keptShell).catch(() => path2.join(ctx.outDir, "index.html"));
|
|
172
|
+
const shell = await fs.readFile(shellPath, "utf8");
|
|
173
|
+
const tmpDir = path2.join(
|
|
174
|
+
outDir,
|
|
175
|
+
`.sibu-prerender-${Date.now().toString(36)}${Math.random().toString(36).slice(2, 8)}`
|
|
176
|
+
);
|
|
177
|
+
await fs.rm(tmpDir, { recursive: true, force: true });
|
|
178
|
+
const viteBuild = await helpers.loadViteBuild();
|
|
179
|
+
const driverSource = `import { renderRoute } from "sibujs/ssr";
|
|
180
|
+
import * as entry from ${JSON.stringify(serverEntry.split(path2.sep).join("/"))};
|
|
181
|
+
export { renderRoute, entry };
|
|
182
|
+
`;
|
|
183
|
+
const prev = process.env[helpers.childEnv];
|
|
184
|
+
process.env[helpers.childEnv] = "1";
|
|
185
|
+
try {
|
|
186
|
+
await viteBuild({
|
|
187
|
+
configFile: ctx.configFile,
|
|
188
|
+
root: ctx.root,
|
|
189
|
+
mode: ctx.mode,
|
|
190
|
+
logLevel: "warn",
|
|
191
|
+
plugins: [
|
|
192
|
+
{
|
|
193
|
+
name: "sibu-prerender-driver",
|
|
194
|
+
resolveId: (id) => id === DRIVER_ID ? DRIVER_RESOLVED : null,
|
|
195
|
+
load: (id) => id === DRIVER_RESOLVED ? driverSource : null
|
|
196
|
+
}
|
|
197
|
+
],
|
|
198
|
+
build: {
|
|
199
|
+
ssr: true,
|
|
200
|
+
outDir: tmpDir,
|
|
201
|
+
emptyOutDir: true,
|
|
202
|
+
copyPublicDir: false,
|
|
203
|
+
minify: false,
|
|
204
|
+
sourcemap: false,
|
|
205
|
+
rollupOptions: { input: DRIVER_ID, output: { format: "es", entryFileNames: "driver.mjs" } }
|
|
206
|
+
}
|
|
207
|
+
});
|
|
208
|
+
} finally {
|
|
209
|
+
if (prev === void 0) delete process.env[helpers.childEnv];
|
|
210
|
+
else process.env[helpers.childEnv] = prev;
|
|
211
|
+
}
|
|
212
|
+
await fs.writeFile(path2.join(tmpDir, "package.json"), '{ "type": "module" }\n', "utf8");
|
|
213
|
+
const currentRoute = new AsyncLocalStorage();
|
|
214
|
+
const realFetch = globalThis.fetch;
|
|
215
|
+
const custom = typeof options.fetch === "function" ? options.fetch : null;
|
|
216
|
+
const apiBase = typeof options.fetch === "string" ? options.fetch.replace(/\/+$/, "") : origin;
|
|
217
|
+
const buildFetch = (async (input2, init) => {
|
|
218
|
+
const raw = typeof input2 === "string" ? input2 : input2 instanceof URL ? input2.href : input2.url;
|
|
219
|
+
const url = /^[a-z][a-z0-9+.-]*:/i.test(raw) ? raw : apiBase + (raw.startsWith("/") ? raw : `/${raw}`);
|
|
220
|
+
try {
|
|
221
|
+
return await (custom ?? realFetch)(
|
|
222
|
+
typeof input2 === "object" && !(input2 instanceof URL) ? new Request(url, input2) : url,
|
|
223
|
+
init
|
|
224
|
+
);
|
|
225
|
+
} catch (err) {
|
|
226
|
+
const store2 = currentRoute.getStore();
|
|
227
|
+
const reason = err instanceof Error ? err.message : String(err);
|
|
228
|
+
store2?.failures.push(`GET ${url} failed (${reason})`);
|
|
229
|
+
throw err;
|
|
230
|
+
}
|
|
231
|
+
});
|
|
232
|
+
const driverUrl = pathToFileURL(path2.join(tmpDir, "driver.mjs")).href;
|
|
233
|
+
const results = [];
|
|
234
|
+
globalThis.fetch = buildFetch;
|
|
235
|
+
try {
|
|
236
|
+
const driver = await import(driverUrl);
|
|
237
|
+
const entry = driver.entry;
|
|
238
|
+
if (!Array.isArray(entry.routes)) {
|
|
239
|
+
throw new Error(
|
|
240
|
+
`[sibu prerender] the server entry ${options.server} must export \`routes\` (the app's route table)`
|
|
241
|
+
);
|
|
242
|
+
}
|
|
243
|
+
const explicit = Array.isArray(options.routes) ? options.routes : null;
|
|
244
|
+
const auto = explicit === null;
|
|
245
|
+
const listed = (explicit ? explicit.map((r) => typeof r === "string" ? { path: r } : r) : (await expandRoutes(entry.routes)).map((p2) => ({ path: p2 }))).filter((r) => r.path !== options.notFound);
|
|
246
|
+
const trailingSlash = options.trailingSlash === "never" ? "never" : "always";
|
|
247
|
+
const planned = listed.map((route) => ({ route, file: helpers.outputFileFor(route, trailingSlash) }));
|
|
248
|
+
const seen = /* @__PURE__ */ new Map();
|
|
249
|
+
for (const { route, file } of planned) {
|
|
250
|
+
helpers.resolveInsideOutDir(path2, outDir, file);
|
|
251
|
+
const other = seen.get(file);
|
|
252
|
+
if (other !== void 0) {
|
|
253
|
+
throw new Error(
|
|
254
|
+
`[sibu prerender] "${other}" and "${route.path}" would both be written to ${file}; a query variant needs its own \`output\` file.`
|
|
255
|
+
);
|
|
256
|
+
}
|
|
257
|
+
seen.set(file, route.path);
|
|
258
|
+
}
|
|
259
|
+
const renderOptions = {
|
|
260
|
+
router: { ...entry.routerOptions ?? {}, head: entry.head },
|
|
261
|
+
app: entry.app,
|
|
262
|
+
timeout: options.timeout ?? 15e3,
|
|
263
|
+
// A per-request page is written as the shell plus its route head: it is
|
|
264
|
+
// never rendered at build time, so its request-only fetches never run.
|
|
265
|
+
headOnly: ["ssr"],
|
|
266
|
+
hydration: options.hydration,
|
|
267
|
+
nonce: options.nonce,
|
|
268
|
+
maxStateBytes: options.maxStateBytes
|
|
269
|
+
};
|
|
270
|
+
const render = async (url) => {
|
|
271
|
+
const store2 = { route: url, failures: [] };
|
|
272
|
+
const result = await currentRoute.run(store2, () => driver.renderRoute(entry.routes, url, renderOptions));
|
|
273
|
+
assertPrerendered(url, result, store2.failures, renderOptions.timeout);
|
|
274
|
+
return result;
|
|
275
|
+
};
|
|
276
|
+
if (options.shell !== false) await fs.writeFile(path2.join(outDir, options.shell ?? "200.html"), shell, "utf8");
|
|
277
|
+
const redirects = [];
|
|
278
|
+
const indexable = [];
|
|
279
|
+
const queue = [...planned];
|
|
280
|
+
const concurrency = Math.max(1, options.concurrency ?? 4);
|
|
281
|
+
const write = async (file, html3) => {
|
|
282
|
+
const target = helpers.resolveInsideOutDir(path2, outDir, file);
|
|
283
|
+
await fs.mkdir(path2.dirname(target), { recursive: true });
|
|
284
|
+
await fs.writeFile(target, html3, "utf8");
|
|
285
|
+
};
|
|
286
|
+
await Promise.all(
|
|
287
|
+
Array.from({ length: Math.min(concurrency, queue.length) }, async () => {
|
|
288
|
+
for (let job = queue.shift(); job; job = queue.shift()) {
|
|
289
|
+
const { route, file } = job;
|
|
290
|
+
const started = Date.now();
|
|
291
|
+
const result = await render(route.path);
|
|
292
|
+
if (result.location !== null && result.redirectBy === "guard") {
|
|
293
|
+
results.push({
|
|
294
|
+
route: route.path,
|
|
295
|
+
file: "",
|
|
296
|
+
ms: Date.now() - started,
|
|
297
|
+
status: result.status,
|
|
298
|
+
kind: "skipped"
|
|
299
|
+
});
|
|
300
|
+
continue;
|
|
301
|
+
}
|
|
302
|
+
if (result.location !== null) {
|
|
303
|
+
redirects.push({ from: route.path, to: result.location, status: result.status });
|
|
304
|
+
results.push({
|
|
305
|
+
route: route.path,
|
|
306
|
+
file: "",
|
|
307
|
+
ms: Date.now() - started,
|
|
308
|
+
status: result.status,
|
|
309
|
+
kind: "redirect"
|
|
310
|
+
});
|
|
311
|
+
continue;
|
|
312
|
+
}
|
|
313
|
+
if (auto && result.failure === "guard") {
|
|
314
|
+
results.push({
|
|
315
|
+
route: route.path,
|
|
316
|
+
file: "",
|
|
317
|
+
ms: Date.now() - started,
|
|
318
|
+
status: result.status,
|
|
319
|
+
kind: "skipped"
|
|
320
|
+
});
|
|
321
|
+
continue;
|
|
322
|
+
}
|
|
323
|
+
if (result.status >= 400) {
|
|
324
|
+
throw new Error(
|
|
325
|
+
`[sibu prerender] ${route.path} answered ${result.status}${result.failure ? ` (${result.failure})` : ""}; list only pages that exist (the \`*\` route becomes 404.html through \`notFound\`).`
|
|
326
|
+
);
|
|
327
|
+
}
|
|
328
|
+
const body2 = result.render === "client" || result.render === "ssr" ? "" : result.html;
|
|
329
|
+
const state2 = body2 ? result.state : "";
|
|
330
|
+
await write(file, injectIntoShell(shell, { body: body2, head: result.head, state: state2 }, options.container));
|
|
331
|
+
if (!result.noindex && result.render !== "client") {
|
|
332
|
+
const pathname = route.path.split(/[?#]/)[0];
|
|
333
|
+
indexable.push(
|
|
334
|
+
trailingSlash === "always" && pathname !== "/" ? `${pathname.replace(/\/+$/, "")}/` : pathname
|
|
335
|
+
);
|
|
336
|
+
}
|
|
337
|
+
results.push({
|
|
338
|
+
route: route.path,
|
|
339
|
+
file,
|
|
340
|
+
ms: Date.now() - started,
|
|
341
|
+
status: result.status,
|
|
342
|
+
kind: body2 ? "page" : "shell"
|
|
343
|
+
});
|
|
344
|
+
}
|
|
345
|
+
})
|
|
346
|
+
);
|
|
347
|
+
const notFound = options.notFound ?? "/404";
|
|
348
|
+
if (notFound) {
|
|
349
|
+
const started = Date.now();
|
|
350
|
+
const result = await render(notFound);
|
|
351
|
+
if (result.status === 404) {
|
|
352
|
+
await write(
|
|
353
|
+
"404.html",
|
|
354
|
+
injectIntoShell(shell, { body: result.html, head: result.head, state: result.state }, options.container)
|
|
355
|
+
);
|
|
356
|
+
results.push({ route: notFound, file: "404.html", ms: Date.now() - started, status: 404, kind: "not-found" });
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
if (redirects.length > 0) await write("redirects.json", `${JSON.stringify(redirects, null, 2)}
|
|
360
|
+
`);
|
|
361
|
+
if (options.sitemap !== false && indexable.length > 0) {
|
|
362
|
+
indexable.sort();
|
|
363
|
+
await write("sitemap.xml", buildSitemap(origin, indexable));
|
|
364
|
+
}
|
|
365
|
+
if (options.robots) {
|
|
366
|
+
const extra = typeof options.robots === "string" ? `${options.robots.trim()}
|
|
367
|
+
` : "";
|
|
368
|
+
const sitemapLine = options.sitemap !== false && indexable.length > 0 ? `Sitemap: ${origin}/sitemap.xml
|
|
369
|
+
` : "";
|
|
370
|
+
await write("robots.txt", `User-agent: *
|
|
371
|
+
Allow: /
|
|
372
|
+
${extra}${sitemapLine}`);
|
|
373
|
+
}
|
|
374
|
+
} finally {
|
|
375
|
+
globalThis.fetch = realFetch;
|
|
376
|
+
await fs.rm(tmpDir, { recursive: true, force: true });
|
|
377
|
+
}
|
|
378
|
+
return results;
|
|
379
|
+
}
|
|
380
|
+
var DRIVER_ID, DRIVER_RESOLVED;
|
|
381
|
+
var init_prerenderServer = __esm({
|
|
382
|
+
"src/build/prerenderServer.ts"() {
|
|
383
|
+
"use strict";
|
|
384
|
+
DRIVER_ID = "virtual:sibu-prerender-driver";
|
|
385
|
+
DRIVER_RESOLVED = `\0${DRIVER_ID}`;
|
|
386
|
+
}
|
|
387
|
+
});
|
|
388
|
+
|
|
30
389
|
// build.ts
|
|
31
390
|
var build_exports = {};
|
|
32
391
|
__export(build_exports, {
|
|
@@ -237,6 +596,7 @@ function estimateImportSize(imports) {
|
|
|
237
596
|
// index.ts
|
|
238
597
|
var index_exports = {};
|
|
239
598
|
__export(index_exports, {
|
|
599
|
+
ClientOnly: () => ClientOnly,
|
|
240
600
|
DynamicComponent: () => DynamicComponent,
|
|
241
601
|
ErrorBoundary: () => ErrorBoundary,
|
|
242
602
|
ErrorDisplay: () => ErrorDisplay,
|
|
@@ -342,7 +702,9 @@ __export(index_exports, {
|
|
|
342
702
|
input: () => input,
|
|
343
703
|
ins: () => ins,
|
|
344
704
|
isBatching: () => isBatching,
|
|
705
|
+
isClient: () => isClient,
|
|
345
706
|
isSSR: () => isSSR,
|
|
707
|
+
isServer: () => isServer,
|
|
346
708
|
kbd: () => kbd,
|
|
347
709
|
label: () => label,
|
|
348
710
|
lazy: () => lazy,
|
|
@@ -416,7 +778,7 @@ __export(index_exports, {
|
|
|
416
778
|
setRuntimeErrorHandler: () => setRuntimeErrorHandler,
|
|
417
779
|
show: () => show,
|
|
418
780
|
signal: () => signal,
|
|
419
|
-
slot: () =>
|
|
781
|
+
slot: () => slot2,
|
|
420
782
|
small: () => small,
|
|
421
783
|
source: () => source,
|
|
422
784
|
span: () => span,
|
|
@@ -524,12 +886,12 @@ function claimedByBoundary(error, context2) {
|
|
|
524
886
|
}
|
|
525
887
|
function resolveEventTarget(node) {
|
|
526
888
|
const ELEMENT_NODE = 1;
|
|
527
|
-
let
|
|
528
|
-
while (
|
|
529
|
-
if (
|
|
530
|
-
return
|
|
889
|
+
let current2 = node;
|
|
890
|
+
while (current2) {
|
|
891
|
+
if (current2.nodeType === ELEMENT_NODE && typeof current2.dispatchEvent === "function") {
|
|
892
|
+
return current2;
|
|
531
893
|
}
|
|
532
|
-
|
|
894
|
+
current2 = current2.parentNode;
|
|
533
895
|
}
|
|
534
896
|
const self = node;
|
|
535
897
|
return typeof self.dispatchEvent === "function" ? self : null;
|
|
@@ -538,10 +900,21 @@ function defaultReport(error, context2) {
|
|
|
538
900
|
if (typeof console === "undefined") return;
|
|
539
901
|
console.error(`[SibuJS] Uncaught error during ${describe(context2)}: ${error.message}`, error);
|
|
540
902
|
}
|
|
903
|
+
function requestErrorSink() {
|
|
904
|
+
const shared = globalThis[/* @__PURE__ */ Symbol.for("sibujs.ssr.v1")];
|
|
905
|
+
if (!shared) return void 0;
|
|
906
|
+
const store2 = shared.als ? shared.als.getStore() : shared.fallbackDepth > 0 ? shared.fallbackStore : void 0;
|
|
907
|
+
return store2?.errors;
|
|
908
|
+
}
|
|
541
909
|
function reportError(error, context2) {
|
|
542
910
|
const err = normalizeError(error);
|
|
543
911
|
untrackedRun(() => {
|
|
544
912
|
if (claimedByBoundary(err, context2)) return;
|
|
913
|
+
const sink = requestErrorSink();
|
|
914
|
+
if (sink) {
|
|
915
|
+
sink.push({ error: err, context: context2 });
|
|
916
|
+
return;
|
|
917
|
+
}
|
|
545
918
|
const s2 = state();
|
|
546
919
|
const handler = s2.handler;
|
|
547
920
|
if (handler && s2.handlerDepth === 0) {
|
|
@@ -589,6 +962,78 @@ function devWarn(message) {
|
|
|
589
962
|
}
|
|
590
963
|
}
|
|
591
964
|
|
|
965
|
+
// src/core/rendering/adoptScope.ts
|
|
966
|
+
var current = null;
|
|
967
|
+
function inAdoptScope() {
|
|
968
|
+
return current?.s.on === true;
|
|
969
|
+
}
|
|
970
|
+
function currentSink() {
|
|
971
|
+
return current?.s.on ? current.s : null;
|
|
972
|
+
}
|
|
973
|
+
function createScopedElement(tag, ns) {
|
|
974
|
+
const c = current;
|
|
975
|
+
if (c?.s.on) {
|
|
976
|
+
const el = c.s.el(tag, ns, c.p + (c.n++).toString(36));
|
|
977
|
+
if (el) return el;
|
|
978
|
+
}
|
|
979
|
+
return ns ? document.createElementNS(ns, tag) : document.createElement(tag);
|
|
980
|
+
}
|
|
981
|
+
function captureScope() {
|
|
982
|
+
const c = current;
|
|
983
|
+
return c?.s.on ? { p: `${c.p}${(c.n++).toString(36)}.`, n: 0, s: c.s } : null;
|
|
984
|
+
}
|
|
985
|
+
function keyedScope(scope, key) {
|
|
986
|
+
if (!scope?.s.on) return null;
|
|
987
|
+
const type = typeof key;
|
|
988
|
+
if (type !== "string" && type !== "number") {
|
|
989
|
+
throw new TypeError(`[SibuJS] adopt: a key must be a string or a number, not ${type}`);
|
|
990
|
+
}
|
|
991
|
+
const text2 = String(key).replace(/[^\w-]/g, (c) => `~${c.charCodeAt(0).toString(16).padStart(4, "0")}`);
|
|
992
|
+
return { p: `${scope.p}${type === "string" ? "_" : "-"}${text2}.`, n: 0, s: scope.s };
|
|
993
|
+
}
|
|
994
|
+
function inScope(scope, fn) {
|
|
995
|
+
const prev = current;
|
|
996
|
+
if (!scope && !prev) return fn();
|
|
997
|
+
current = scope?.s.on ? { p: scope.p, n: 0, s: scope.s } : null;
|
|
998
|
+
try {
|
|
999
|
+
return fn();
|
|
1000
|
+
} finally {
|
|
1001
|
+
current = prev;
|
|
1002
|
+
}
|
|
1003
|
+
}
|
|
1004
|
+
|
|
1005
|
+
// src/core/rendering/hydrationHooks.ts
|
|
1006
|
+
var _a;
|
|
1007
|
+
var slot = globalThis[_a = /* @__PURE__ */ Symbol.for("sibujs.hydration.v2")] ?? (globalThis[_a] = { a: /* @__PURE__ */ new Set(), c: null });
|
|
1008
|
+
function isHydrating() {
|
|
1009
|
+
return slot.a.size > 0;
|
|
1010
|
+
}
|
|
1011
|
+
function ownSession() {
|
|
1012
|
+
return currentSink()?.h ?? slot.c;
|
|
1013
|
+
}
|
|
1014
|
+
function hydrationOwners() {
|
|
1015
|
+
const own = ownSession();
|
|
1016
|
+
return own ? own.open ? [own] : [] : Array.from(slot.a);
|
|
1017
|
+
}
|
|
1018
|
+
function afterHydration(fn) {
|
|
1019
|
+
const owners = hydrationOwners();
|
|
1020
|
+
let left = owners.length;
|
|
1021
|
+
const once = () => {
|
|
1022
|
+
if (--left < 1) fn();
|
|
1023
|
+
};
|
|
1024
|
+
if (left) for (const s2 of owners) s2.done.push(once);
|
|
1025
|
+
else fn();
|
|
1026
|
+
}
|
|
1027
|
+
function notify(session) {
|
|
1028
|
+
for (const wake of Array.from(session.wake)) wake();
|
|
1029
|
+
}
|
|
1030
|
+
function holdHydration(sessions, entry) {
|
|
1031
|
+
for (const s2 of sessions) s2.pending.add(entry);
|
|
1032
|
+
return () => {
|
|
1033
|
+
for (const s2 of sessions) if (s2.pending.delete(entry)) notify(s2);
|
|
1034
|
+
};
|
|
1035
|
+
}
|
|
1036
|
+
|
|
592
1037
|
// src/core/rendering/dispose.ts
|
|
593
1038
|
var elementDisposers = /* @__PURE__ */ new WeakMap();
|
|
594
1039
|
var MAX_DRAIN_TEARDOWNS = 1e4;
|
|
@@ -685,9 +1130,9 @@ function dispose(node) {
|
|
|
685
1130
|
const stack = [node];
|
|
686
1131
|
const order = [];
|
|
687
1132
|
while (stack.length > 0) {
|
|
688
|
-
const
|
|
689
|
-
order.push(
|
|
690
|
-
const children = Array.from(
|
|
1133
|
+
const current2 = stack.pop();
|
|
1134
|
+
order.push(current2);
|
|
1135
|
+
const children = Array.from(current2.childNodes);
|
|
691
1136
|
for (let i2 = 0; i2 < children.length; i2++) {
|
|
692
1137
|
stack.push(children[i2]);
|
|
693
1138
|
}
|
|
@@ -726,13 +1171,27 @@ function disposeNodeOwn(node) {
|
|
|
726
1171
|
}
|
|
727
1172
|
}
|
|
728
1173
|
function replaceChildrenSafely(parent, ...next) {
|
|
1174
|
+
if (isHydrating() && next.length > 0 && next[0] === parent.firstChild) {
|
|
1175
|
+
let ok = true;
|
|
1176
|
+
for (let i2 = 1; i2 < next.length && ok; i2++) ok = next[i2 - 1].nextSibling === next[i2];
|
|
1177
|
+
if (ok) {
|
|
1178
|
+
let rest = next[next.length - 1].nextSibling;
|
|
1179
|
+
while (rest) {
|
|
1180
|
+
const following = rest.nextSibling;
|
|
1181
|
+
dispose(rest);
|
|
1182
|
+
parent.removeChild(rest);
|
|
1183
|
+
rest = following;
|
|
1184
|
+
}
|
|
1185
|
+
return;
|
|
1186
|
+
}
|
|
1187
|
+
}
|
|
729
1188
|
for (let i2 = 0; i2 < next.length; i2++) {
|
|
730
1189
|
const node = next[i2];
|
|
731
1190
|
node.parentNode?.removeChild(node);
|
|
732
1191
|
}
|
|
733
|
-
const
|
|
734
|
-
for (let i2 = 0; i2 <
|
|
735
|
-
dispose(
|
|
1192
|
+
const current2 = Array.from(parent.childNodes);
|
|
1193
|
+
for (let i2 = 0; i2 < current2.length; i2++) {
|
|
1194
|
+
dispose(current2[i2]);
|
|
736
1195
|
}
|
|
737
1196
|
parent.replaceChildren(...next);
|
|
738
1197
|
}
|
|
@@ -804,19 +1263,19 @@ function sanitizeSrcset(value) {
|
|
|
804
1263
|
if (url.endsWith(",")) {
|
|
805
1264
|
url = url.replace(/,+$/, "");
|
|
806
1265
|
} else {
|
|
807
|
-
let
|
|
1266
|
+
let current2 = "";
|
|
808
1267
|
let inParens = false;
|
|
809
1268
|
while (i2 < n) {
|
|
810
1269
|
const ch = input2[i2];
|
|
811
1270
|
if (inParens) {
|
|
812
|
-
|
|
1271
|
+
current2 += ch;
|
|
813
1272
|
if (ch === ")") inParens = false;
|
|
814
1273
|
i2++;
|
|
815
1274
|
continue;
|
|
816
1275
|
}
|
|
817
1276
|
if (isSrcsetWhitespace(ch)) {
|
|
818
|
-
if (
|
|
819
|
-
|
|
1277
|
+
if (current2) descriptors.push(current2);
|
|
1278
|
+
current2 = "";
|
|
820
1279
|
i2++;
|
|
821
1280
|
continue;
|
|
822
1281
|
}
|
|
@@ -825,10 +1284,10 @@ function sanitizeSrcset(value) {
|
|
|
825
1284
|
break;
|
|
826
1285
|
}
|
|
827
1286
|
if (ch === "(") inParens = true;
|
|
828
|
-
|
|
1287
|
+
current2 += ch;
|
|
829
1288
|
i2++;
|
|
830
1289
|
}
|
|
831
|
-
if (
|
|
1290
|
+
if (current2) descriptors.push(current2);
|
|
832
1291
|
}
|
|
833
1292
|
if (url === "") continue;
|
|
834
1293
|
if (descriptors.length > 1) continue;
|
|
@@ -1401,8 +1860,8 @@ function commitSafeAttribute(el, name, value, options) {
|
|
|
1401
1860
|
else el.removeAttribute(name);
|
|
1402
1861
|
return true;
|
|
1403
1862
|
}
|
|
1404
|
-
const
|
|
1405
|
-
if (
|
|
1863
|
+
const current2 = ns ? el.getAttributeNS(ns, localName) : el.getAttribute(name);
|
|
1864
|
+
if (current2 === safe) return true;
|
|
1406
1865
|
if (ns) el.setAttributeNS(ns, name, safe);
|
|
1407
1866
|
else el.setAttribute(name, safe);
|
|
1408
1867
|
return true;
|
|
@@ -1990,7 +2449,7 @@ function forEachSubscriber(signal2, visit) {
|
|
|
1990
2449
|
}
|
|
1991
2450
|
|
|
1992
2451
|
// src/reactivity/track.ts
|
|
1993
|
-
var _runtimeVersion = true ? "4.
|
|
2452
|
+
var _runtimeVersion = true ? "4.14.1" : "dev";
|
|
1994
2453
|
var REGISTRY_KEY = /* @__PURE__ */ Symbol.for("sibujs.reactive.v1");
|
|
1995
2454
|
function resolveReactiveApi() {
|
|
1996
2455
|
const g2 = globalThis;
|
|
@@ -2211,10 +2670,11 @@ function restoreFocusWithin(snapshot, nodes, where, policy) {
|
|
|
2211
2670
|
// src/reactivity/bindChildNode.ts
|
|
2212
2671
|
function bindChildNode(placeholder, getter) {
|
|
2213
2672
|
let lastNodes = [];
|
|
2673
|
+
const scope = captureScope();
|
|
2214
2674
|
function commit() {
|
|
2215
2675
|
let result;
|
|
2216
2676
|
try {
|
|
2217
|
-
result = getter
|
|
2677
|
+
result = inScope(scope, getter);
|
|
2218
2678
|
} catch (err) {
|
|
2219
2679
|
reportError(err, { phase: "binding", name: "bindChildNode", node: placeholder });
|
|
2220
2680
|
return;
|
|
@@ -2473,7 +2933,7 @@ function tagFactory(tag, ns) {
|
|
|
2473
2933
|
throw new Error(`tagFactory: refusing to create <${tag}> \u2014 tag is blocked for security reasons.`);
|
|
2474
2934
|
}
|
|
2475
2935
|
if (typeof document === "undefined") noDocument();
|
|
2476
|
-
const el =
|
|
2936
|
+
const el = createScopedElement(tag, ns);
|
|
2477
2937
|
if (first === void 0) return el;
|
|
2478
2938
|
if (typeof first === "string") {
|
|
2479
2939
|
if (second !== void 0) {
|
|
@@ -2683,7 +3143,7 @@ var details = tagFactory("details");
|
|
|
2683
3143
|
var dialog = tagFactory("dialog");
|
|
2684
3144
|
var menu = tagFactory("menu");
|
|
2685
3145
|
var summary = tagFactory("summary");
|
|
2686
|
-
var
|
|
3146
|
+
var slot2 = tagFactory("slot");
|
|
2687
3147
|
var template = tagFactory("template");
|
|
2688
3148
|
var base = tagFactory("base");
|
|
2689
3149
|
var link = tagFactory("link");
|
|
@@ -2714,6 +3174,152 @@ var font = tagFactory("font");
|
|
|
2714
3174
|
var marquee = tagFactory("marquee");
|
|
2715
3175
|
var customElement = (tagName) => tagFactory(tagName);
|
|
2716
3176
|
|
|
3177
|
+
// src/core/rendering/streamBoundary.ts
|
|
3178
|
+
var _a2;
|
|
3179
|
+
var slot3 = globalThis[_a2 = /* @__PURE__ */ Symbol.for("sibujs.streamBoundary.v1")] ?? (globalThis[_a2] = { hook: null, current: null });
|
|
3180
|
+
function openBoundary(container) {
|
|
3181
|
+
return slot3.hook ? slot3.hook(container) : null;
|
|
3182
|
+
}
|
|
3183
|
+
function currentBoundary() {
|
|
3184
|
+
return slot3.current;
|
|
3185
|
+
}
|
|
3186
|
+
|
|
3187
|
+
// src/core/ssr-context.ts
|
|
3188
|
+
var SSR_KEY = /* @__PURE__ */ Symbol.for("sibujs.ssr.v1");
|
|
3189
|
+
function detectSSRShared() {
|
|
3190
|
+
let detected = null;
|
|
3191
|
+
try {
|
|
3192
|
+
if (typeof process !== "undefined" && process.versions && process.versions.node) {
|
|
3193
|
+
let mod = null;
|
|
3194
|
+
const getBuiltin = process.getBuiltinModule;
|
|
3195
|
+
if (typeof getBuiltin === "function") {
|
|
3196
|
+
mod = getBuiltin("node:async_hooks");
|
|
3197
|
+
} else if (typeof require === "function") {
|
|
3198
|
+
mod = require("async_hooks");
|
|
3199
|
+
}
|
|
3200
|
+
if (mod) detected = new mod.AsyncLocalStorage();
|
|
3201
|
+
}
|
|
3202
|
+
const globalAls = globalThis.AsyncLocalStorage;
|
|
3203
|
+
if (!detected && typeof globalAls === "function") detected = new globalAls();
|
|
3204
|
+
} catch {
|
|
3205
|
+
detected = null;
|
|
3206
|
+
}
|
|
3207
|
+
return {
|
|
3208
|
+
als: detected,
|
|
3209
|
+
fallbackStore: { ssr: false, suspenseIdCounter: 0, locale: void 0 },
|
|
3210
|
+
fallbackDepth: 0
|
|
3211
|
+
};
|
|
3212
|
+
}
|
|
3213
|
+
var _shared = globalThis[SSR_KEY] ?? (globalThis[SSR_KEY] = detectSSRShared());
|
|
3214
|
+
var als = _shared.als;
|
|
3215
|
+
var fallbackStore = _shared.fallbackStore;
|
|
3216
|
+
_shared.fallbackDepth ?? (_shared.fallbackDepth = 0);
|
|
3217
|
+
var _alsWarned = false;
|
|
3218
|
+
function warnMissingAsyncLocalStorage() {
|
|
3219
|
+
if (_alsWarned || als) return;
|
|
3220
|
+
const isNode = typeof process !== "undefined" && !!process.versions?.node;
|
|
3221
|
+
if (!isNode) return;
|
|
3222
|
+
_alsWarned = true;
|
|
3223
|
+
const version = process.versions.node;
|
|
3224
|
+
devWarn(
|
|
3225
|
+
`SSR request isolation is UNAVAILABLE on this runtime (Node ${version}). AsyncLocalStorage could not be loaded, so concurrent requests share one SSR store: request state and the query cache can bleed between them. Node >= 22.3 is required for isolated SSR under ESM; the CommonJS build works on older versions. A fully synchronous render is unaffected.`
|
|
3226
|
+
);
|
|
3227
|
+
}
|
|
3228
|
+
function getSSRStore() {
|
|
3229
|
+
if (als) {
|
|
3230
|
+
const s2 = als.getStore();
|
|
3231
|
+
if (s2) return s2;
|
|
3232
|
+
}
|
|
3233
|
+
return fallbackStore;
|
|
3234
|
+
}
|
|
3235
|
+
function getRequestStore() {
|
|
3236
|
+
if (als) return als.getStore() ?? null;
|
|
3237
|
+
return _shared.fallbackDepth > 0 ? fallbackStore : null;
|
|
3238
|
+
}
|
|
3239
|
+
function isSSR() {
|
|
3240
|
+
return getSSRStore().ssr;
|
|
3241
|
+
}
|
|
3242
|
+
function getRequestScopedCache(name) {
|
|
3243
|
+
if (!isSSR()) return null;
|
|
3244
|
+
const store2 = getSSRStore();
|
|
3245
|
+
const caches = store2.caches ?? (store2.caches = /* @__PURE__ */ new Map());
|
|
3246
|
+
let c = caches.get(name);
|
|
3247
|
+
if (!c) {
|
|
3248
|
+
c = /* @__PURE__ */ new Map();
|
|
3249
|
+
caches.set(name, c);
|
|
3250
|
+
}
|
|
3251
|
+
return c;
|
|
3252
|
+
}
|
|
3253
|
+
var PRERENDER_HOST = /* @__PURE__ */ Symbol.for("sibujs.prerender.v1");
|
|
3254
|
+
function isServer() {
|
|
3255
|
+
return getSSRStore().ssr || globalThis[PRERENDER_HOST] !== void 0;
|
|
3256
|
+
}
|
|
3257
|
+
function isClient() {
|
|
3258
|
+
return !isServer();
|
|
3259
|
+
}
|
|
3260
|
+
function enableSSR() {
|
|
3261
|
+
getSSRStore().ssr = true;
|
|
3262
|
+
}
|
|
3263
|
+
function disableSSR() {
|
|
3264
|
+
getSSRStore().ssr = false;
|
|
3265
|
+
}
|
|
3266
|
+
function runInSSRContext(fn) {
|
|
3267
|
+
const store2 = {
|
|
3268
|
+
ssr: true,
|
|
3269
|
+
suspenseIdCounter: 0,
|
|
3270
|
+
idCounter: 0,
|
|
3271
|
+
locale: void 0,
|
|
3272
|
+
pending: /* @__PURE__ */ new Set(),
|
|
3273
|
+
wake: null
|
|
3274
|
+
};
|
|
3275
|
+
if (als) {
|
|
3276
|
+
return als.run(store2, fn);
|
|
3277
|
+
}
|
|
3278
|
+
warnMissingAsyncLocalStorage();
|
|
3279
|
+
const prev = { ...fallbackStore };
|
|
3280
|
+
Object.assign(fallbackStore, store2);
|
|
3281
|
+
_shared.fallbackDepth++;
|
|
3282
|
+
try {
|
|
3283
|
+
return fn();
|
|
3284
|
+
} finally {
|
|
3285
|
+
_shared.fallbackDepth--;
|
|
3286
|
+
for (const key of Object.keys(fallbackStore)) {
|
|
3287
|
+
if (!(key in prev)) delete fallbackStore[key];
|
|
3288
|
+
}
|
|
3289
|
+
Object.assign(fallbackStore, prev);
|
|
3290
|
+
}
|
|
3291
|
+
}
|
|
3292
|
+
function trackPending(promise, label2, hydration = true) {
|
|
3293
|
+
const store2 = getRequestStore();
|
|
3294
|
+
const pending = store2?.pending;
|
|
3295
|
+
const sessions = pending || !hydration ? [] : hydrationOwners();
|
|
3296
|
+
if (!pending && sessions.length === 0) return promise;
|
|
3297
|
+
const entry = { label: label2, since: Date.now(), boundary: currentBoundary() ?? void 0 };
|
|
3298
|
+
pending?.add(entry);
|
|
3299
|
+
const release = holdHydration(sessions, entry);
|
|
3300
|
+
const done = () => {
|
|
3301
|
+
pending?.delete(entry);
|
|
3302
|
+
store2?.wake?.();
|
|
3303
|
+
release();
|
|
3304
|
+
};
|
|
3305
|
+
try {
|
|
3306
|
+
Promise.resolve(promise).then(done, done);
|
|
3307
|
+
} catch {
|
|
3308
|
+
done();
|
|
3309
|
+
}
|
|
3310
|
+
return promise;
|
|
3311
|
+
}
|
|
3312
|
+
function withSSR(fn) {
|
|
3313
|
+
const store2 = getSSRStore();
|
|
3314
|
+
const wasSSR = store2.ssr;
|
|
3315
|
+
store2.ssr = true;
|
|
3316
|
+
try {
|
|
3317
|
+
return fn();
|
|
3318
|
+
} finally {
|
|
3319
|
+
if (!wasSSR) store2.ssr = false;
|
|
3320
|
+
}
|
|
3321
|
+
}
|
|
3322
|
+
|
|
2717
3323
|
// src/core/rendering/lazy.ts
|
|
2718
3324
|
var PENDING_ERROR = "__sibuPendingError";
|
|
2719
3325
|
function dispatchPropagate(node, error) {
|
|
@@ -2740,18 +3346,28 @@ function takePendingError(node) {
|
|
|
2740
3346
|
function lazy(importFn) {
|
|
2741
3347
|
let cached = null;
|
|
2742
3348
|
return function LazyComponent() {
|
|
2743
|
-
if (cached) {
|
|
3349
|
+
if (cached && !inAdoptScope()) {
|
|
2744
3350
|
return cached();
|
|
2745
3351
|
}
|
|
2746
3352
|
const container = div({ class: "sibu-lazy" });
|
|
3353
|
+
const scope = captureScope();
|
|
3354
|
+
const boundary = currentBoundary();
|
|
2747
3355
|
let disposed = false;
|
|
2748
|
-
|
|
3356
|
+
const loading = inScope(null, () => span("sibu-lazy-loading", "Loading..."));
|
|
3357
|
+
if (cached) {
|
|
3358
|
+
const loaded = cached;
|
|
3359
|
+
replaceChildrenSafely(container, inScope(scope, () => loaded()));
|
|
3360
|
+
return container;
|
|
3361
|
+
}
|
|
3362
|
+
trackPending(importFn(), "lazy").then(
|
|
2749
3363
|
// The component renders after the import resolves, in the owner scope
|
|
2750
3364
|
// of whoever rendered the placeholder.
|
|
2751
3365
|
bindOwnerScope2((mod) => {
|
|
2752
3366
|
if (disposed) return;
|
|
2753
3367
|
cached = mod.default;
|
|
2754
|
-
const
|
|
3368
|
+
const component = cached;
|
|
3369
|
+
const build = () => inScope(scope, () => component());
|
|
3370
|
+
const rendered = boundary ? boundary.enter(build) : build();
|
|
2755
3371
|
replaceChildrenSafely(container, rendered);
|
|
2756
3372
|
})
|
|
2757
3373
|
).catch((err) => {
|
|
@@ -2763,7 +3379,7 @@ function lazy(importFn) {
|
|
|
2763
3379
|
);
|
|
2764
3380
|
dispatchPropagate(container, errorObj);
|
|
2765
3381
|
});
|
|
2766
|
-
container.appendChild(
|
|
3382
|
+
if (!(isHydrating() && container.firstChild)) container.appendChild(loading);
|
|
2767
3383
|
registerDisposer(container, () => {
|
|
2768
3384
|
disposed = true;
|
|
2769
3385
|
});
|
|
@@ -2772,8 +3388,15 @@ function lazy(importFn) {
|
|
|
2772
3388
|
}
|
|
2773
3389
|
function Suspense({ nodes, fallback }) {
|
|
2774
3390
|
const container = div({ class: "sibu-suspense" });
|
|
2775
|
-
const
|
|
2776
|
-
container
|
|
3391
|
+
const scope = captureScope();
|
|
3392
|
+
const boundary = openBoundary(container);
|
|
3393
|
+
const commit = (el) => {
|
|
3394
|
+
replaceChildrenSafely(container, el);
|
|
3395
|
+
boundary?.done();
|
|
3396
|
+
};
|
|
3397
|
+
const fallbackEl = inScope(null, fallback);
|
|
3398
|
+
if (isHydrating() && container.firstChild) dispose(fallbackEl);
|
|
3399
|
+
else container.appendChild(fallbackEl);
|
|
2777
3400
|
let suspenseDisposed = false;
|
|
2778
3401
|
let observer = null;
|
|
2779
3402
|
let childEl = null;
|
|
@@ -2788,11 +3411,11 @@ function Suspense({ nodes, fallback }) {
|
|
|
2788
3411
|
const renderContent = bindOwnerScope2(() => {
|
|
2789
3412
|
if (suspenseDisposed) return;
|
|
2790
3413
|
try {
|
|
2791
|
-
const el = nodes();
|
|
3414
|
+
const el = boundary ? boundary.enter(() => inScope(scope, nodes)) : inScope(scope, nodes);
|
|
2792
3415
|
childEl = el;
|
|
2793
3416
|
if (el.classList.contains("sibu-lazy")) {
|
|
2794
3417
|
if (!el.querySelector(".sibu-lazy-loading")) {
|
|
2795
|
-
|
|
3418
|
+
commit(el);
|
|
2796
3419
|
return;
|
|
2797
3420
|
}
|
|
2798
3421
|
observer = new MutationObserver(() => {
|
|
@@ -2801,12 +3424,12 @@ function Suspense({ nodes, fallback }) {
|
|
|
2801
3424
|
if (!loading) {
|
|
2802
3425
|
observer?.disconnect();
|
|
2803
3426
|
observer = null;
|
|
2804
|
-
|
|
3427
|
+
commit(el);
|
|
2805
3428
|
}
|
|
2806
3429
|
});
|
|
2807
3430
|
observer.observe(el, { childList: true, subtree: true });
|
|
2808
3431
|
} else {
|
|
2809
|
-
|
|
3432
|
+
commit(el);
|
|
2810
3433
|
}
|
|
2811
3434
|
} catch (err) {
|
|
2812
3435
|
const errorObj = err instanceof Error ? err : new Error(String(err));
|
|
@@ -2996,7 +3619,7 @@ function registerUnmountWatcher(element, cb) {
|
|
|
2996
3619
|
};
|
|
2997
3620
|
}
|
|
2998
3621
|
function onMount(callback, element) {
|
|
2999
|
-
if (typeof document === "undefined") return;
|
|
3622
|
+
if (typeof document === "undefined" || isSSR()) return;
|
|
3000
3623
|
const scope = getOwnerScope2();
|
|
3001
3624
|
callback = pinScope(scope, callback);
|
|
3002
3625
|
if (element) {
|
|
@@ -3031,7 +3654,7 @@ function onMount(callback, element) {
|
|
|
3031
3654
|
}
|
|
3032
3655
|
}
|
|
3033
3656
|
function onUnmount(callback, element) {
|
|
3034
|
-
if (typeof document === "undefined") return;
|
|
3657
|
+
if (typeof document === "undefined" || isSSR()) return;
|
|
3035
3658
|
watchUnmount(pinScope(getOwnerScope2(), callback), element);
|
|
3036
3659
|
}
|
|
3037
3660
|
function watchUnmount(callback, element) {
|
|
@@ -3068,112 +3691,6 @@ function emitDevtools(hook, event, payload) {
|
|
|
3068
3691
|
}
|
|
3069
3692
|
}
|
|
3070
3693
|
|
|
3071
|
-
// src/core/ssr-context.ts
|
|
3072
|
-
var SSR_KEY = /* @__PURE__ */ Symbol.for("sibujs.ssr.v1");
|
|
3073
|
-
function detectSSRShared() {
|
|
3074
|
-
let detected = null;
|
|
3075
|
-
try {
|
|
3076
|
-
if (typeof process !== "undefined" && process.versions && process.versions.node) {
|
|
3077
|
-
let mod = null;
|
|
3078
|
-
const getBuiltin = process.getBuiltinModule;
|
|
3079
|
-
if (typeof getBuiltin === "function") {
|
|
3080
|
-
mod = getBuiltin("node:async_hooks");
|
|
3081
|
-
} else if (typeof require === "function") {
|
|
3082
|
-
mod = require("async_hooks");
|
|
3083
|
-
}
|
|
3084
|
-
if (mod) detected = new mod.AsyncLocalStorage();
|
|
3085
|
-
}
|
|
3086
|
-
} catch {
|
|
3087
|
-
detected = null;
|
|
3088
|
-
}
|
|
3089
|
-
return {
|
|
3090
|
-
als: detected,
|
|
3091
|
-
fallbackStore: { ssr: false, suspenseIdCounter: 0, locale: void 0 },
|
|
3092
|
-
fallbackDepth: 0
|
|
3093
|
-
};
|
|
3094
|
-
}
|
|
3095
|
-
var _shared = globalThis[SSR_KEY] ?? (globalThis[SSR_KEY] = detectSSRShared());
|
|
3096
|
-
var als = _shared.als;
|
|
3097
|
-
var fallbackStore = _shared.fallbackStore;
|
|
3098
|
-
_shared.fallbackDepth ?? (_shared.fallbackDepth = 0);
|
|
3099
|
-
var _alsWarned = false;
|
|
3100
|
-
function warnMissingAsyncLocalStorage() {
|
|
3101
|
-
if (_alsWarned || als) return;
|
|
3102
|
-
const isNode = typeof process !== "undefined" && !!process.versions?.node;
|
|
3103
|
-
if (!isNode) return;
|
|
3104
|
-
_alsWarned = true;
|
|
3105
|
-
const version = process.versions.node;
|
|
3106
|
-
devWarn(
|
|
3107
|
-
`SSR request isolation is UNAVAILABLE on this runtime (Node ${version}). AsyncLocalStorage could not be loaded, so concurrent requests share one SSR store: request state and the query cache can bleed between them. Node >= 22.3 is required for isolated SSR under ESM; the CommonJS build works on older versions. A fully synchronous render is unaffected.`
|
|
3108
|
-
);
|
|
3109
|
-
}
|
|
3110
|
-
function getSSRStore() {
|
|
3111
|
-
if (als) {
|
|
3112
|
-
const s2 = als.getStore();
|
|
3113
|
-
if (s2) return s2;
|
|
3114
|
-
}
|
|
3115
|
-
return fallbackStore;
|
|
3116
|
-
}
|
|
3117
|
-
function getRequestStore() {
|
|
3118
|
-
if (als) return als.getStore() ?? null;
|
|
3119
|
-
return _shared.fallbackDepth > 0 ? fallbackStore : null;
|
|
3120
|
-
}
|
|
3121
|
-
function isSSR() {
|
|
3122
|
-
return getSSRStore().ssr;
|
|
3123
|
-
}
|
|
3124
|
-
function getRequestScopedCache(name) {
|
|
3125
|
-
if (!isSSR()) return null;
|
|
3126
|
-
const store2 = getSSRStore();
|
|
3127
|
-
const caches = store2.caches ?? (store2.caches = /* @__PURE__ */ new Map());
|
|
3128
|
-
let c = caches.get(name);
|
|
3129
|
-
if (!c) {
|
|
3130
|
-
c = /* @__PURE__ */ new Map();
|
|
3131
|
-
caches.set(name, c);
|
|
3132
|
-
}
|
|
3133
|
-
return c;
|
|
3134
|
-
}
|
|
3135
|
-
function enableSSR() {
|
|
3136
|
-
getSSRStore().ssr = true;
|
|
3137
|
-
}
|
|
3138
|
-
function disableSSR() {
|
|
3139
|
-
getSSRStore().ssr = false;
|
|
3140
|
-
}
|
|
3141
|
-
function runInSSRContext(fn) {
|
|
3142
|
-
const store2 = { ssr: true, suspenseIdCounter: 0, idCounter: 0, locale: void 0 };
|
|
3143
|
-
if (als) {
|
|
3144
|
-
return als.run(store2, fn);
|
|
3145
|
-
}
|
|
3146
|
-
warnMissingAsyncLocalStorage();
|
|
3147
|
-
const prevSSR = fallbackStore.ssr;
|
|
3148
|
-
const prevCounter = fallbackStore.suspenseIdCounter;
|
|
3149
|
-
const prevIdCounter = fallbackStore.idCounter;
|
|
3150
|
-
const prevLocale = fallbackStore.locale;
|
|
3151
|
-
fallbackStore.ssr = true;
|
|
3152
|
-
fallbackStore.suspenseIdCounter = 0;
|
|
3153
|
-
fallbackStore.idCounter = 0;
|
|
3154
|
-
fallbackStore.locale = void 0;
|
|
3155
|
-
_shared.fallbackDepth++;
|
|
3156
|
-
try {
|
|
3157
|
-
return fn();
|
|
3158
|
-
} finally {
|
|
3159
|
-
_shared.fallbackDepth--;
|
|
3160
|
-
fallbackStore.ssr = prevSSR;
|
|
3161
|
-
fallbackStore.suspenseIdCounter = prevCounter;
|
|
3162
|
-
fallbackStore.idCounter = prevIdCounter;
|
|
3163
|
-
fallbackStore.locale = prevLocale;
|
|
3164
|
-
}
|
|
3165
|
-
}
|
|
3166
|
-
function withSSR(fn) {
|
|
3167
|
-
const store2 = getSSRStore();
|
|
3168
|
-
const wasSSR = store2.ssr;
|
|
3169
|
-
store2.ssr = true;
|
|
3170
|
-
try {
|
|
3171
|
-
return fn();
|
|
3172
|
-
} finally {
|
|
3173
|
-
if (!wasSSR) store2.ssr = false;
|
|
3174
|
-
}
|
|
3175
|
-
}
|
|
3176
|
-
|
|
3177
3694
|
// src/core/signals/effect.ts
|
|
3178
3695
|
var _g = globalThis;
|
|
3179
3696
|
function on(deps, handler) {
|
|
@@ -3254,7 +3771,7 @@ function disposeEffect(ctx) {
|
|
|
3254
3771
|
}
|
|
3255
3772
|
function effect(effectFn, options) {
|
|
3256
3773
|
devAssert(typeof effectFn === "function", "effect: argument must be a function.");
|
|
3257
|
-
if (isSSR()) return () => {
|
|
3774
|
+
if (isSSR() && !options?.server) return () => {
|
|
3258
3775
|
};
|
|
3259
3776
|
const ctx = {
|
|
3260
3777
|
fn: effectFn,
|
|
@@ -4060,21 +4577,21 @@ function ErrorBoundary(optionsOrChildren, maybeChildren) {
|
|
|
4060
4577
|
stopResetKeysWatcher();
|
|
4061
4578
|
let baseline = null;
|
|
4062
4579
|
resetKeysTeardown = effect(() => {
|
|
4063
|
-
const
|
|
4580
|
+
const current2 = readResetKeyValues(keys);
|
|
4064
4581
|
if (baseline === null) {
|
|
4065
|
-
baseline =
|
|
4582
|
+
baseline = current2;
|
|
4066
4583
|
return;
|
|
4067
4584
|
}
|
|
4068
|
-
let changed =
|
|
4585
|
+
let changed = current2.length !== baseline.length;
|
|
4069
4586
|
if (!changed) {
|
|
4070
|
-
for (let i2 = 0; i2 <
|
|
4071
|
-
if (!Object.is(
|
|
4587
|
+
for (let i2 = 0; i2 < current2.length; i2++) {
|
|
4588
|
+
if (!Object.is(current2[i2], baseline[i2])) {
|
|
4072
4589
|
changed = true;
|
|
4073
4590
|
break;
|
|
4074
4591
|
}
|
|
4075
4592
|
}
|
|
4076
4593
|
}
|
|
4077
|
-
baseline =
|
|
4594
|
+
baseline = current2;
|
|
4078
4595
|
if (changed) retry();
|
|
4079
4596
|
});
|
|
4080
4597
|
};
|
|
@@ -4466,68 +4983,6 @@ function setGlobalErrorHandler(handler) {
|
|
|
4466
4983
|
globalErrorHandler = handler;
|
|
4467
4984
|
}
|
|
4468
4985
|
|
|
4469
|
-
// src/core/rendering/context.ts
|
|
4470
|
-
function context(defaultValue) {
|
|
4471
|
-
const [getValue, setValue] = signal(defaultValue);
|
|
4472
|
-
const warnIfSSR = (method) => {
|
|
4473
|
-
if (!DEV || !isSSR()) return;
|
|
4474
|
-
devWarn(
|
|
4475
|
-
`context.${method}() called during SSR. SibuJS context() is application-global \u2014 it is NOT isolated per request, so a concurrent request can observe this value. Do not use context() for request-specific SSR data; pass it explicitly or use request-scoped storage instead.`
|
|
4476
|
-
);
|
|
4477
|
-
};
|
|
4478
|
-
const ctx = {
|
|
4479
|
-
provide(value) {
|
|
4480
|
-
warnIfSSR("provide");
|
|
4481
|
-
const previous = getValue();
|
|
4482
|
-
setValue(value);
|
|
4483
|
-
return () => setValue(previous);
|
|
4484
|
-
},
|
|
4485
|
-
use() {
|
|
4486
|
-
return getValue;
|
|
4487
|
-
},
|
|
4488
|
-
get() {
|
|
4489
|
-
return getValue();
|
|
4490
|
-
},
|
|
4491
|
-
set(value) {
|
|
4492
|
-
warnIfSSR("set");
|
|
4493
|
-
setValue(value);
|
|
4494
|
-
},
|
|
4495
|
-
withContext(value, fn) {
|
|
4496
|
-
warnIfSSR("withContext");
|
|
4497
|
-
const previous = getValue();
|
|
4498
|
-
setValue(value);
|
|
4499
|
-
try {
|
|
4500
|
-
const result = fn();
|
|
4501
|
-
if (DEV && result !== null && typeof result?.then === "function") {
|
|
4502
|
-
devWarn(
|
|
4503
|
-
"context.withContext() received an async callback. Scoping is synchronous only \u2014 the previous value is restored as soon as the callback returns its promise, so anything after an `await` runs outside the scope."
|
|
4504
|
-
);
|
|
4505
|
-
}
|
|
4506
|
-
return result;
|
|
4507
|
-
} finally {
|
|
4508
|
-
setValue(previous);
|
|
4509
|
-
}
|
|
4510
|
-
}
|
|
4511
|
-
};
|
|
4512
|
-
return ctx;
|
|
4513
|
-
}
|
|
4514
|
-
|
|
4515
|
-
// src/core/rendering/createId.ts
|
|
4516
|
-
var COUNTER_KEY = /* @__PURE__ */ Symbol.for("sibujs.createId.v1");
|
|
4517
|
-
var _counter = globalThis[COUNTER_KEY] ?? (globalThis[COUNTER_KEY] = { n: 0 });
|
|
4518
|
-
function createId(prefix = "sibu") {
|
|
4519
|
-
const request = getRequestStore();
|
|
4520
|
-
if (request) {
|
|
4521
|
-
request.idCounter = (request.idCounter ?? 0) + 1;
|
|
4522
|
-
return `${prefix}-${request.idCounter}`;
|
|
4523
|
-
}
|
|
4524
|
-
_counter.n++;
|
|
4525
|
-
return `${prefix}-${_counter.n}`;
|
|
4526
|
-
}
|
|
4527
|
-
function __resetIdCounter() {
|
|
4528
|
-
_counter.n = 0;
|
|
4529
|
-
}
|
|
4530
|
-
|
|
4531
4986
|
// src/core/rendering/directives.ts
|
|
4532
4987
|
function show(condition, element) {
|
|
4533
4988
|
const resolved = typeof element === "function" ? element() : element;
|
|
@@ -4553,7 +5008,7 @@ function attachBranch(parent, anchor, branch, attachedOnce, where) {
|
|
|
4553
5008
|
() => `${where}: ${handedIn ? "a branch was given as an element rather than a function" : "a branch factory returned a node it had already returned"}, so the SAME node is being re-attached \u2014 any state it accumulated while detached (input value, scroll position, classes set imperatively) comes back with it. Its reactive bindings are left intact rather than disposed, because the node is not this directive's to tear down. Return a FRESH node per call (\`() => div(\u2026)\`) for rebuild semantics, or keep this form deliberately when the reuse is what you want.`
|
|
4554
5009
|
);
|
|
4555
5010
|
}
|
|
4556
|
-
parent.insertBefore(node, anchor.nextSibling);
|
|
5011
|
+
if (anchor.nextSibling !== node) parent.insertBefore(node, anchor.nextSibling);
|
|
4557
5012
|
return { node, owned };
|
|
4558
5013
|
}
|
|
4559
5014
|
function releaseBranchNode(node, owned) {
|
|
@@ -4569,6 +5024,7 @@ function when(condition, thenBranch, elseBranch, options) {
|
|
|
4569
5024
|
const elseNode = elseBranch;
|
|
4570
5025
|
const focusPolicy = options?.focus;
|
|
4571
5026
|
const anchor = document.createComment("when");
|
|
5027
|
+
const scope = captureScope();
|
|
4572
5028
|
let currentNode = null;
|
|
4573
5029
|
let lastCondition;
|
|
4574
5030
|
let initialized = false;
|
|
@@ -4588,7 +5044,7 @@ function when(condition, thenBranch, elseBranch, options) {
|
|
|
4588
5044
|
currentNode = null;
|
|
4589
5045
|
}
|
|
4590
5046
|
const branch = show2 ? thenBranch : elseNode !== void 0 ? elseNode : null;
|
|
4591
|
-
const attached = untracked2(() => attachBranch(parent, anchor, branch, attachedOnce, "when"));
|
|
5047
|
+
const attached = untracked2(() => inScope(scope, () => attachBranch(parent, anchor, branch, attachedOnce, "when")));
|
|
4592
5048
|
currentNode = attached.node;
|
|
4593
5049
|
currentNodeOwned = attached.owned;
|
|
4594
5050
|
restoreFocusWithin(focused, currentNode ? [currentNode] : [], "when", focusPolicy);
|
|
@@ -4619,6 +5075,7 @@ function match(value, cases, fallback, options) {
|
|
|
4619
5075
|
const fallbackNode = fallback;
|
|
4620
5076
|
const focusPolicy = options?.focus;
|
|
4621
5077
|
const anchor = document.createComment("match");
|
|
5078
|
+
const scope = captureScope();
|
|
4622
5079
|
let currentNode = null;
|
|
4623
5080
|
let lastKey;
|
|
4624
5081
|
let initialized = false;
|
|
@@ -4638,7 +5095,9 @@ function match(value, cases, fallback, options) {
|
|
|
4638
5095
|
currentNode = null;
|
|
4639
5096
|
}
|
|
4640
5097
|
const branch = Object.hasOwn(cases, key) ? cases[key] : fallbackNode;
|
|
4641
|
-
const attached = untracked2(
|
|
5098
|
+
const attached = untracked2(
|
|
5099
|
+
() => inScope(scope, () => attachBranch(parent, anchor, branch ?? null, attachedOnce, "match"))
|
|
5100
|
+
);
|
|
4642
5101
|
currentNode = attached.node;
|
|
4643
5102
|
currentNodeOwned = attached.owned;
|
|
4644
5103
|
restoreFocusWithin(focused, currentNode ? [currentNode] : [], "match", focusPolicy);
|
|
@@ -4661,6 +5120,76 @@ function match(value, cases, fallback, options) {
|
|
|
4661
5120
|
return anchor;
|
|
4662
5121
|
}
|
|
4663
5122
|
|
|
5123
|
+
// src/core/rendering/clientOnly.ts
|
|
5124
|
+
function ClientOnly(content, options = {}) {
|
|
5125
|
+
const server = isServer();
|
|
5126
|
+
const [ready, setReady] = signal(!server && !isHydrating());
|
|
5127
|
+
if (!server && !ready()) afterHydration(() => setReady(true));
|
|
5128
|
+
return when(ready, content, options.fallback);
|
|
5129
|
+
}
|
|
5130
|
+
|
|
5131
|
+
// src/core/rendering/context.ts
|
|
5132
|
+
function context(defaultValue) {
|
|
5133
|
+
const [getValue, setValue] = signal(defaultValue);
|
|
5134
|
+
const warnIfSSR = (method) => {
|
|
5135
|
+
if (!DEV || !isSSR()) return;
|
|
5136
|
+
devWarn(
|
|
5137
|
+
`context.${method}() called during SSR. SibuJS context() is application-global \u2014 it is NOT isolated per request, so a concurrent request can observe this value. Do not use context() for request-specific SSR data; pass it explicitly or use request-scoped storage instead.`
|
|
5138
|
+
);
|
|
5139
|
+
};
|
|
5140
|
+
const ctx = {
|
|
5141
|
+
provide(value) {
|
|
5142
|
+
warnIfSSR("provide");
|
|
5143
|
+
const previous = getValue();
|
|
5144
|
+
setValue(value);
|
|
5145
|
+
return () => setValue(previous);
|
|
5146
|
+
},
|
|
5147
|
+
use() {
|
|
5148
|
+
return getValue;
|
|
5149
|
+
},
|
|
5150
|
+
get() {
|
|
5151
|
+
return getValue();
|
|
5152
|
+
},
|
|
5153
|
+
set(value) {
|
|
5154
|
+
warnIfSSR("set");
|
|
5155
|
+
setValue(value);
|
|
5156
|
+
},
|
|
5157
|
+
withContext(value, fn) {
|
|
5158
|
+
warnIfSSR("withContext");
|
|
5159
|
+
const previous = getValue();
|
|
5160
|
+
setValue(value);
|
|
5161
|
+
try {
|
|
5162
|
+
const result = fn();
|
|
5163
|
+
if (DEV && result !== null && typeof result?.then === "function") {
|
|
5164
|
+
devWarn(
|
|
5165
|
+
"context.withContext() received an async callback. Scoping is synchronous only \u2014 the previous value is restored as soon as the callback returns its promise, so anything after an `await` runs outside the scope."
|
|
5166
|
+
);
|
|
5167
|
+
}
|
|
5168
|
+
return result;
|
|
5169
|
+
} finally {
|
|
5170
|
+
setValue(previous);
|
|
5171
|
+
}
|
|
5172
|
+
}
|
|
5173
|
+
};
|
|
5174
|
+
return ctx;
|
|
5175
|
+
}
|
|
5176
|
+
|
|
5177
|
+
// src/core/rendering/createId.ts
|
|
5178
|
+
var COUNTER_KEY = /* @__PURE__ */ Symbol.for("sibujs.createId.v1");
|
|
5179
|
+
var _counter = globalThis[COUNTER_KEY] ?? (globalThis[COUNTER_KEY] = { n: 0 });
|
|
5180
|
+
function createId(prefix = "sibu") {
|
|
5181
|
+
const request = getRequestStore();
|
|
5182
|
+
if (request) {
|
|
5183
|
+
request.idCounter = (request.idCounter ?? 0) + 1;
|
|
5184
|
+
return `${prefix}-${request.idCounter}`;
|
|
5185
|
+
}
|
|
5186
|
+
_counter.n++;
|
|
5187
|
+
return `${prefix}-${_counter.n}`;
|
|
5188
|
+
}
|
|
5189
|
+
function __resetIdCounter() {
|
|
5190
|
+
_counter.n = 0;
|
|
5191
|
+
}
|
|
5192
|
+
|
|
4664
5193
|
// src/utils/globalSingleton.ts
|
|
4665
5194
|
function globalSingleton(key, create) {
|
|
4666
5195
|
const g2 = globalThis;
|
|
@@ -4762,6 +5291,7 @@ function each(getArray, render, options) {
|
|
|
4762
5291
|
);
|
|
4763
5292
|
requireDocument();
|
|
4764
5293
|
const anchor = document.createComment("each:anchor");
|
|
5294
|
+
const scope = captureScope();
|
|
4765
5295
|
const end = document.createComment("each:end");
|
|
4766
5296
|
const oldKeysBufA = [];
|
|
4767
5297
|
const oldKeysBufB = [];
|
|
@@ -4791,7 +5321,9 @@ function each(getArray, render, options) {
|
|
|
4791
5321
|
const parent = anchor.parentNode;
|
|
4792
5322
|
if (!parent) return;
|
|
4793
5323
|
if (!sentinelInserted) {
|
|
4794
|
-
|
|
5324
|
+
const serverEnd = isHydrating() ? findServerEnd(anchor) : null;
|
|
5325
|
+
if (serverEnd) parent.replaceChild(end, serverEnd);
|
|
5326
|
+
else parent.insertBefore(end, anchor.nextSibling);
|
|
4795
5327
|
sentinelInserted = true;
|
|
4796
5328
|
}
|
|
4797
5329
|
if (newKeysBuf.length < newLen) {
|
|
@@ -4832,7 +5364,7 @@ function each(getArray, render, options) {
|
|
|
4832
5364
|
try {
|
|
4833
5365
|
suspendTracking2();
|
|
4834
5366
|
try {
|
|
4835
|
-
node = resolveNodeChild(render(itemGetter, indexGetter));
|
|
5367
|
+
node = resolveNodeChild(inScope(keyedScope(scope, key), () => render(itemGetter, indexGetter)));
|
|
4836
5368
|
} finally {
|
|
4837
5369
|
resumeTracking2();
|
|
4838
5370
|
}
|
|
@@ -4966,6 +5498,19 @@ function each(getArray, render, options) {
|
|
|
4966
5498
|
}
|
|
4967
5499
|
return anchor;
|
|
4968
5500
|
}
|
|
5501
|
+
function findServerEnd(anchor) {
|
|
5502
|
+
let depth = 0;
|
|
5503
|
+
for (let n = anchor.nextSibling; n; n = n.nextSibling) {
|
|
5504
|
+
if (n.nodeType !== 8) continue;
|
|
5505
|
+
const data2 = n.data;
|
|
5506
|
+
if (data2 === "each:anchor") depth++;
|
|
5507
|
+
else if (data2 === "each:end") {
|
|
5508
|
+
if (depth === 0) return n;
|
|
5509
|
+
depth--;
|
|
5510
|
+
}
|
|
5511
|
+
}
|
|
5512
|
+
return null;
|
|
5513
|
+
}
|
|
4969
5514
|
|
|
4970
5515
|
// src/core/rendering/fragment.ts
|
|
4971
5516
|
function Fragment(nodes) {
|
|
@@ -5089,19 +5634,19 @@ function parseTemplate(strings) {
|
|
|
5089
5634
|
pos++;
|
|
5090
5635
|
const statics = [];
|
|
5091
5636
|
const exprs = [];
|
|
5092
|
-
let
|
|
5637
|
+
let current2 = "";
|
|
5093
5638
|
while (pos < len && template2[pos] !== quote2) {
|
|
5094
5639
|
const innerIdx = tryExprIdx();
|
|
5095
5640
|
if (innerIdx >= 0) {
|
|
5096
|
-
statics.push(
|
|
5097
|
-
|
|
5641
|
+
statics.push(current2);
|
|
5642
|
+
current2 = "";
|
|
5098
5643
|
exprs.push(innerIdx);
|
|
5099
5644
|
} else {
|
|
5100
|
-
|
|
5645
|
+
current2 += template2[pos++];
|
|
5101
5646
|
}
|
|
5102
5647
|
}
|
|
5103
5648
|
if (pos < len) pos++;
|
|
5104
|
-
statics.push(
|
|
5649
|
+
statics.push(current2);
|
|
5105
5650
|
if (exprs.length === 0) {
|
|
5106
5651
|
return { kind: "static", value: statics[0] };
|
|
5107
5652
|
}
|
|
@@ -5110,20 +5655,20 @@ function parseTemplate(strings) {
|
|
|
5110
5655
|
{
|
|
5111
5656
|
const statics = [];
|
|
5112
5657
|
const exprs = [];
|
|
5113
|
-
let
|
|
5658
|
+
let current2 = "";
|
|
5114
5659
|
while (pos < len) {
|
|
5115
5660
|
const c = template2.charCodeAt(pos);
|
|
5116
5661
|
if (c === 32 || c === 9 || c === 10 || c === 13 || c === 62) break;
|
|
5117
5662
|
const innerIdx = tryExprIdx();
|
|
5118
5663
|
if (innerIdx >= 0) {
|
|
5119
|
-
statics.push(
|
|
5120
|
-
|
|
5664
|
+
statics.push(current2);
|
|
5665
|
+
current2 = "";
|
|
5121
5666
|
exprs.push(innerIdx);
|
|
5122
5667
|
} else {
|
|
5123
|
-
|
|
5668
|
+
current2 += template2[pos++];
|
|
5124
5669
|
}
|
|
5125
5670
|
}
|
|
5126
|
-
statics.push(
|
|
5671
|
+
statics.push(current2);
|
|
5127
5672
|
if (exprs.length === 0) {
|
|
5128
5673
|
return { kind: "static", value: statics[0] };
|
|
5129
5674
|
}
|
|
@@ -5247,7 +5792,7 @@ function parseTemplate(strings) {
|
|
|
5247
5792
|
return parseChildren();
|
|
5248
5793
|
}
|
|
5249
5794
|
function executeElement(tmpl, values) {
|
|
5250
|
-
const el = tmpl.svg ?
|
|
5795
|
+
const el = createScopedElement(tmpl.tag, tmpl.svg ? SVG_NS3 : void 0);
|
|
5251
5796
|
for (let i2 = 0; i2 < tmpl.attrs.length; i2++) {
|
|
5252
5797
|
const attr = tmpl.attrs[i2];
|
|
5253
5798
|
switch (attr.t) {
|
|
@@ -5340,7 +5885,7 @@ function renderTemplate(tmpl, values) {
|
|
|
5340
5885
|
if (tmpl.length === 1 && tmpl[0].t === 0) {
|
|
5341
5886
|
return executeElement(tmpl[0].el, values);
|
|
5342
5887
|
}
|
|
5343
|
-
const wrapper =
|
|
5888
|
+
const wrapper = createScopedElement("div");
|
|
5344
5889
|
for (let i2 = 0; i2 < tmpl.length; i2++) {
|
|
5345
5890
|
const child = tmpl[i2];
|
|
5346
5891
|
switch (child.t) {
|
|
@@ -5584,8 +6129,8 @@ function Portal(nodes, target) {
|
|
|
5584
6129
|
// src/core/rendering/slots.ts
|
|
5585
6130
|
function getSlot(slots, name = "default") {
|
|
5586
6131
|
if (slots == null || !Object.hasOwn(slots, name)) return void 0;
|
|
5587
|
-
const
|
|
5588
|
-
return typeof
|
|
6132
|
+
const slot4 = slots[name];
|
|
6133
|
+
return typeof slot4 === "function" ? slot4 : void 0;
|
|
5589
6134
|
}
|
|
5590
6135
|
|
|
5591
6136
|
// src/core/signals/array.ts
|
|
@@ -5669,7 +6214,7 @@ function reactiveArray(initial = []) {
|
|
|
5669
6214
|
let data2 = [...initial];
|
|
5670
6215
|
let snapshot = null;
|
|
5671
6216
|
const signal2 = { __v: 0 };
|
|
5672
|
-
function
|
|
6217
|
+
function notify2() {
|
|
5673
6218
|
snapshot = null;
|
|
5674
6219
|
signal2.__v++;
|
|
5675
6220
|
if (!enqueueBatchedSignal(signal2)) {
|
|
@@ -5688,52 +6233,52 @@ function reactiveArray(initial = []) {
|
|
|
5688
6233
|
push(...items) {
|
|
5689
6234
|
if (items.length === 0) return;
|
|
5690
6235
|
data2.push(...items);
|
|
5691
|
-
|
|
6236
|
+
notify2();
|
|
5692
6237
|
},
|
|
5693
6238
|
pop() {
|
|
5694
6239
|
if (data2.length === 0) return void 0;
|
|
5695
6240
|
const removed = data2.pop();
|
|
5696
|
-
|
|
6241
|
+
notify2();
|
|
5697
6242
|
return removed;
|
|
5698
6243
|
},
|
|
5699
6244
|
shift() {
|
|
5700
6245
|
if (data2.length === 0) return void 0;
|
|
5701
6246
|
const removed = data2.shift();
|
|
5702
|
-
|
|
6247
|
+
notify2();
|
|
5703
6248
|
return removed;
|
|
5704
6249
|
},
|
|
5705
6250
|
unshift(...items) {
|
|
5706
6251
|
if (items.length === 0) return;
|
|
5707
6252
|
data2.unshift(...items);
|
|
5708
|
-
|
|
6253
|
+
notify2();
|
|
5709
6254
|
},
|
|
5710
6255
|
splice(start, ...rest) {
|
|
5711
6256
|
const removed = nativeSplice(data2, start, rest);
|
|
5712
6257
|
if (removed.length > 0 || rest.length > 1) {
|
|
5713
|
-
|
|
6258
|
+
notify2();
|
|
5714
6259
|
}
|
|
5715
6260
|
return removed;
|
|
5716
6261
|
},
|
|
5717
6262
|
remove(index) {
|
|
5718
6263
|
if (index < 0 || index >= data2.length) return;
|
|
5719
6264
|
data2.splice(index, 1);
|
|
5720
|
-
|
|
6265
|
+
notify2();
|
|
5721
6266
|
},
|
|
5722
6267
|
removeWhere(predicate) {
|
|
5723
6268
|
const idx = data2.findIndex(predicate);
|
|
5724
6269
|
if (idx === -1) return;
|
|
5725
6270
|
data2.splice(idx, 1);
|
|
5726
|
-
|
|
6271
|
+
notify2();
|
|
5727
6272
|
},
|
|
5728
6273
|
set(items) {
|
|
5729
6274
|
data2 = [...items];
|
|
5730
|
-
|
|
6275
|
+
notify2();
|
|
5731
6276
|
},
|
|
5732
6277
|
update(index, value) {
|
|
5733
6278
|
if (index < 0 || index >= data2.length) return;
|
|
5734
6279
|
if (Object.is(data2[index], value)) return;
|
|
5735
6280
|
data2[index] = value;
|
|
5736
|
-
|
|
6281
|
+
notify2();
|
|
5737
6282
|
},
|
|
5738
6283
|
updateWhere(predicate, updater) {
|
|
5739
6284
|
let changed = false;
|
|
@@ -5746,23 +6291,23 @@ function reactiveArray(initial = []) {
|
|
|
5746
6291
|
}
|
|
5747
6292
|
}
|
|
5748
6293
|
}
|
|
5749
|
-
if (changed)
|
|
6294
|
+
if (changed) notify2();
|
|
5750
6295
|
},
|
|
5751
6296
|
sort(compareFn) {
|
|
5752
6297
|
if (data2.length <= 1) return;
|
|
5753
6298
|
data2.sort(compareFn);
|
|
5754
|
-
|
|
6299
|
+
notify2();
|
|
5755
6300
|
},
|
|
5756
6301
|
reverse() {
|
|
5757
6302
|
if (data2.length <= 1) return;
|
|
5758
6303
|
data2.reverse();
|
|
5759
|
-
|
|
6304
|
+
notify2();
|
|
5760
6305
|
},
|
|
5761
6306
|
filter(predicate) {
|
|
5762
6307
|
const filtered = data2.filter(predicate);
|
|
5763
6308
|
if (filtered.length === data2.length) return;
|
|
5764
6309
|
data2 = filtered;
|
|
5765
|
-
|
|
6310
|
+
notify2();
|
|
5766
6311
|
},
|
|
5767
6312
|
map(transform) {
|
|
5768
6313
|
let changed = false;
|
|
@@ -5773,12 +6318,12 @@ function reactiveArray(initial = []) {
|
|
|
5773
6318
|
changed = true;
|
|
5774
6319
|
}
|
|
5775
6320
|
}
|
|
5776
|
-
if (changed)
|
|
6321
|
+
if (changed) notify2();
|
|
5777
6322
|
},
|
|
5778
6323
|
clear() {
|
|
5779
6324
|
if (data2.length === 0) return;
|
|
5780
6325
|
data2 = [];
|
|
5781
|
-
|
|
6326
|
+
notify2();
|
|
5782
6327
|
}
|
|
5783
6328
|
};
|
|
5784
6329
|
return [get, actions];
|
|
@@ -6116,8 +6661,8 @@ function store(initialState) {
|
|
|
6116
6661
|
return snapshot;
|
|
6117
6662
|
};
|
|
6118
6663
|
const setState = (patch) => {
|
|
6119
|
-
const
|
|
6120
|
-
const nextState = typeof patch === "function" ? patch(
|
|
6664
|
+
const current2 = getSnapshot();
|
|
6665
|
+
const nextState = typeof patch === "function" ? patch(current2) : patch;
|
|
6121
6666
|
batch(() => {
|
|
6122
6667
|
Object.entries(nextState).forEach(([key, value]) => {
|
|
6123
6668
|
if (Object.hasOwn(signals, key)) {
|
|
@@ -6154,18 +6699,18 @@ function store(initialState) {
|
|
|
6154
6699
|
let prev;
|
|
6155
6700
|
let first = true;
|
|
6156
6701
|
return effect(() => {
|
|
6157
|
-
const
|
|
6702
|
+
const current2 = signals[key][0]();
|
|
6158
6703
|
if (first) {
|
|
6159
|
-
prev =
|
|
6704
|
+
prev = current2;
|
|
6160
6705
|
first = false;
|
|
6161
6706
|
return;
|
|
6162
6707
|
}
|
|
6163
|
-
if (!Object.is(
|
|
6708
|
+
if (!Object.is(current2, prev)) {
|
|
6164
6709
|
const oldPrev = prev;
|
|
6165
|
-
prev =
|
|
6710
|
+
prev = current2;
|
|
6166
6711
|
suspendTracking2();
|
|
6167
6712
|
try {
|
|
6168
|
-
callback(
|
|
6713
|
+
callback(current2, oldPrev);
|
|
6169
6714
|
} finally {
|
|
6170
6715
|
resumeTracking2();
|
|
6171
6716
|
}
|
|
@@ -6802,6 +7347,7 @@ var SUBPATH_ENTRIES = [
|
|
|
6802
7347
|
"ui",
|
|
6803
7348
|
"widgets",
|
|
6804
7349
|
"ssr",
|
|
7350
|
+
"ssr/dom",
|
|
6805
7351
|
"devtools",
|
|
6806
7352
|
"performance",
|
|
6807
7353
|
"ecosystem",
|
|
@@ -6876,7 +7422,7 @@ function generateImportMap(baseUrl) {
|
|
|
6876
7422
|
[PACKAGE_NAME]: `${base2}/dist/index.js`
|
|
6877
7423
|
};
|
|
6878
7424
|
for (const entry of SUBPATH_ENTRIES) {
|
|
6879
|
-
imports[`${PACKAGE_NAME}/${entry}`] = `${base2}/dist/${entry}.js`;
|
|
7425
|
+
imports[`${PACKAGE_NAME}/${entry}`] = `${base2}/dist/${entry.replace("/", "-")}.js`;
|
|
6880
7426
|
}
|
|
6881
7427
|
return {
|
|
6882
7428
|
imports,
|
|
@@ -7692,38 +8238,38 @@ function parseTemplate2(strings) {
|
|
|
7692
8238
|
pos++;
|
|
7693
8239
|
const statics2 = [];
|
|
7694
8240
|
const exprs2 = [];
|
|
7695
|
-
let
|
|
8241
|
+
let current3 = "";
|
|
7696
8242
|
while (pos < len && template2[pos] !== quote2) {
|
|
7697
8243
|
const innerIdx = tryExprIdx();
|
|
7698
8244
|
if (innerIdx >= 0) {
|
|
7699
|
-
statics2.push(
|
|
7700
|
-
|
|
8245
|
+
statics2.push(current3);
|
|
8246
|
+
current3 = "";
|
|
7701
8247
|
exprs2.push(innerIdx);
|
|
7702
8248
|
} else {
|
|
7703
|
-
|
|
8249
|
+
current3 += template2[pos++];
|
|
7704
8250
|
}
|
|
7705
8251
|
}
|
|
7706
8252
|
if (pos < len) pos++;
|
|
7707
|
-
statics2.push(
|
|
8253
|
+
statics2.push(current3);
|
|
7708
8254
|
if (exprs2.length === 0) return { kind: "static", value: statics2[0] };
|
|
7709
8255
|
return { kind: "mixed", statics: statics2, exprs: exprs2 };
|
|
7710
8256
|
}
|
|
7711
8257
|
const statics = [];
|
|
7712
8258
|
const exprs = [];
|
|
7713
|
-
let
|
|
8259
|
+
let current2 = "";
|
|
7714
8260
|
while (pos < len) {
|
|
7715
8261
|
const c = template2.charCodeAt(pos);
|
|
7716
8262
|
if (c === 32 || c === 9 || c === 10 || c === 13 || c === 62) break;
|
|
7717
8263
|
const innerIdx = tryExprIdx();
|
|
7718
8264
|
if (innerIdx >= 0) {
|
|
7719
|
-
statics.push(
|
|
7720
|
-
|
|
8265
|
+
statics.push(current2);
|
|
8266
|
+
current2 = "";
|
|
7721
8267
|
exprs.push(innerIdx);
|
|
7722
8268
|
} else {
|
|
7723
|
-
|
|
8269
|
+
current2 += template2[pos++];
|
|
7724
8270
|
}
|
|
7725
8271
|
}
|
|
7726
|
-
statics.push(
|
|
8272
|
+
statics.push(current2);
|
|
7727
8273
|
if (exprs.length === 0) return { kind: "static", value: statics[0] };
|
|
7728
8274
|
return { kind: "mixed", statics, exprs };
|
|
7729
8275
|
}
|
|
@@ -9129,7 +9675,7 @@ function findEntryInHtml(html3) {
|
|
|
9129
9675
|
const m = MODULE_SCRIPT.exec(html3) ?? MODULE_SCRIPT_SRC_FIRST.exec(html3);
|
|
9130
9676
|
return m ? m[1] : null;
|
|
9131
9677
|
}
|
|
9132
|
-
function outputFileFor(route) {
|
|
9678
|
+
function outputFileFor(route, trailingSlash = "always") {
|
|
9133
9679
|
if (route.output) {
|
|
9134
9680
|
const output2 = route.output;
|
|
9135
9681
|
if (/^[A-Za-z]:/.test(output2) || output2.includes("\0")) {
|
|
@@ -9159,6 +9705,10 @@ function outputFileFor(route) {
|
|
|
9159
9705
|
}
|
|
9160
9706
|
return decoded;
|
|
9161
9707
|
});
|
|
9708
|
+
if (trailingSlash === "never" && segments.length > 0) {
|
|
9709
|
+
const last = segments.pop();
|
|
9710
|
+
return [...segments, `${last}.html`].join("/");
|
|
9711
|
+
}
|
|
9162
9712
|
return [...segments, "index.html"].join("/");
|
|
9163
9713
|
}
|
|
9164
9714
|
function resolveInsideOutDir(path2, outDir, file) {
|
|
@@ -9174,17 +9724,36 @@ async function prerender(options, ctx) {
|
|
|
9174
9724
|
const path2 = await import("path");
|
|
9175
9725
|
const { pathToFileURL } = await import("url");
|
|
9176
9726
|
const { createRequire } = await import("module");
|
|
9727
|
+
const requireFromRoot = createRequire(path2.join(ctx.root, "package.json"));
|
|
9728
|
+
if (options.server) {
|
|
9729
|
+
const { prerenderFromServerEntry: prerenderFromServerEntry2 } = await Promise.resolve().then(() => (init_prerenderServer(), prerenderServer_exports));
|
|
9730
|
+
return prerenderFromServerEntry2(options, ctx, {
|
|
9731
|
+
outputFileFor,
|
|
9732
|
+
resolveInsideOutDir,
|
|
9733
|
+
loadViteBuild: () => loadViteBuild(requireFromRoot, fs, path2, pathToFileURL),
|
|
9734
|
+
childEnv: PRERENDER_CHILD_ENV
|
|
9735
|
+
});
|
|
9736
|
+
}
|
|
9737
|
+
if (options.routes === void 0 || options.routes === "auto") {
|
|
9738
|
+
throw new Error(
|
|
9739
|
+
'[sibu prerender] `routes: "auto"` needs a server entry (`prerender.server`); list the routes instead.'
|
|
9740
|
+
);
|
|
9741
|
+
}
|
|
9177
9742
|
const routes = options.routes.map((r) => typeof r === "string" ? { path: r } : r);
|
|
9743
|
+
if (options.notFound) routes.push({ path: options.notFound, output: "404.html" });
|
|
9178
9744
|
if (routes.length === 0) return [];
|
|
9745
|
+
const trailingSlash = options.trailingSlash === "never" ? "never" : "always";
|
|
9746
|
+
const outDir = options.outDir ? path2.resolve(ctx.root, options.outDir) : ctx.outDir;
|
|
9179
9747
|
const planned = routes.map((route) => {
|
|
9180
|
-
const file = outputFileFor(route);
|
|
9181
|
-
resolveInsideOutDir(path2,
|
|
9748
|
+
const file = outputFileFor(route, trailingSlash);
|
|
9749
|
+
resolveInsideOutDir(path2, outDir, file);
|
|
9182
9750
|
return { route, file };
|
|
9183
9751
|
});
|
|
9184
9752
|
const origin = (options.origin ?? "http://localhost").replace(/\/+$/, "");
|
|
9185
9753
|
const timeout = options.timeout ?? 15e3;
|
|
9186
9754
|
const settle = options.settle ?? 50;
|
|
9187
|
-
const
|
|
9755
|
+
const keptShell = path2.join(ctx.outDir, typeof options.shell === "string" ? options.shell : "200.html");
|
|
9756
|
+
const templatePath = await fs.access(keptShell).then(() => keptShell).catch(() => path2.join(ctx.outDir, "index.html"));
|
|
9188
9757
|
const template2 = await fs.readFile(templatePath, "utf8");
|
|
9189
9758
|
let entry = options.entry;
|
|
9190
9759
|
if (!entry) {
|
|
@@ -9202,7 +9771,7 @@ async function prerender(options, ctx) {
|
|
|
9202
9771
|
} catch {
|
|
9203
9772
|
throw new Error("[sibu prerender] needs jsdom to render routes. Install it: npm i -D jsdom");
|
|
9204
9773
|
}
|
|
9205
|
-
const tmpDir = path2.join(
|
|
9774
|
+
const tmpDir = path2.join(outDir, ".sibu-prerender");
|
|
9206
9775
|
await fs.rm(tmpDir, { recursive: true, force: true });
|
|
9207
9776
|
const viteBuild = await loadViteBuild(requireFromApp, fs, path2, pathToFileURL);
|
|
9208
9777
|
const prev = process.env[PRERENDER_CHILD_ENV];
|
|
@@ -9232,10 +9801,12 @@ async function prerender(options, ctx) {
|
|
|
9232
9801
|
await fs.writeFile(workerFile, WORKER_SOURCE, "utf8");
|
|
9233
9802
|
const entryUrl = pathToFileURL(path2.join(tmpDir, "entry.mjs")).href;
|
|
9234
9803
|
const jsdomUrl = pathToFileURL(jsdomPath).href;
|
|
9804
|
+
await fs.mkdir(outDir, { recursive: true });
|
|
9235
9805
|
if (options.shell !== false) {
|
|
9236
|
-
await fs.writeFile(path2.join(
|
|
9806
|
+
await fs.writeFile(path2.join(outDir, options.shell ?? "200.html"), template2, "utf8");
|
|
9237
9807
|
}
|
|
9238
9808
|
const results = [];
|
|
9809
|
+
const indexable = [];
|
|
9239
9810
|
const queue = [...planned];
|
|
9240
9811
|
const concurrency = Math.max(1, options.concurrency ?? 4);
|
|
9241
9812
|
try {
|
|
@@ -9253,16 +9824,35 @@ async function prerender(options, ctx) {
|
|
|
9253
9824
|
timeout,
|
|
9254
9825
|
settle
|
|
9255
9826
|
});
|
|
9256
|
-
const target = resolveInsideOutDir(path2,
|
|
9827
|
+
const target = resolveInsideOutDir(path2, outDir, file);
|
|
9257
9828
|
await fs.mkdir(path2.dirname(target), { recursive: true });
|
|
9258
9829
|
await fs.writeFile(target, html3, "utf8");
|
|
9259
9830
|
results.push({ route: route.path, file, ms: Date.now() - started });
|
|
9831
|
+
if (file !== "404.html" && !/<meta\b[^>]*name=["']robots["'][^>]*content=["'][^"']*noindex/i.test(html3)) {
|
|
9832
|
+
const pathname = route.path.split(/[?#]/)[0];
|
|
9833
|
+
indexable.push(
|
|
9834
|
+
trailingSlash === "always" && pathname !== "/" ? `${pathname.replace(/\/+$/, "")}/` : pathname
|
|
9835
|
+
);
|
|
9836
|
+
}
|
|
9260
9837
|
}
|
|
9261
9838
|
})
|
|
9262
9839
|
);
|
|
9263
9840
|
} finally {
|
|
9264
9841
|
await fs.rm(tmpDir, { recursive: true, force: true });
|
|
9265
9842
|
}
|
|
9843
|
+
if (options.sitemap && indexable.length > 0) {
|
|
9844
|
+
const { buildSitemap: buildSitemap2 } = await Promise.resolve().then(() => (init_prerenderServer(), prerenderServer_exports));
|
|
9845
|
+
await fs.writeFile(path2.join(outDir, "sitemap.xml"), buildSitemap2(origin, indexable.sort()), "utf8");
|
|
9846
|
+
}
|
|
9847
|
+
if (options.robots) {
|
|
9848
|
+
const extra = typeof options.robots === "string" ? `${options.robots.trim()}
|
|
9849
|
+
` : "";
|
|
9850
|
+
const sitemapLine = options.sitemap && indexable.length > 0 ? `Sitemap: ${origin}/sitemap.xml
|
|
9851
|
+
` : "";
|
|
9852
|
+
await fs.writeFile(path2.join(outDir, "robots.txt"), `User-agent: *
|
|
9853
|
+
Allow: /
|
|
9854
|
+
${extra}${sitemapLine}`, "utf8");
|
|
9855
|
+
}
|
|
9266
9856
|
return results;
|
|
9267
9857
|
}
|
|
9268
9858
|
function esmEntryOf(entry) {
|
|
@@ -9297,6 +9887,7 @@ async function loadViteBuild(requireFromApp, fs, path2, pathToFileURL) {
|
|
|
9297
9887
|
}
|
|
9298
9888
|
return build;
|
|
9299
9889
|
}
|
|
9890
|
+
var STARTUP_TIMEOUT = 6e4;
|
|
9300
9891
|
async function renderInWorker(workerFile, input2) {
|
|
9301
9892
|
const { Worker } = await import("worker_threads");
|
|
9302
9893
|
return new Promise((resolve, reject) => {
|
|
@@ -9308,12 +9899,14 @@ async function renderInWorker(workerFile, input2) {
|
|
|
9308
9899
|
fn();
|
|
9309
9900
|
void worker.terminate();
|
|
9310
9901
|
};
|
|
9311
|
-
const
|
|
9312
|
-
|
|
9313
|
-
|
|
9314
|
-
);
|
|
9315
|
-
worker.once("message", (msg) => {
|
|
9902
|
+
const backstop = (ms, what) => setTimeout(() => finish(() => reject(new Error(`[sibu prerender] ${input2.route}: ${what}`))), ms);
|
|
9903
|
+
let timer = backstop(Math.max(STARTUP_TIMEOUT, input2.timeout + 5e3), "worker did not load the app");
|
|
9904
|
+
worker.on("message", (msg) => {
|
|
9316
9905
|
clearTimeout(timer);
|
|
9906
|
+
if (msg.loaded) {
|
|
9907
|
+
timer = backstop(input2.timeout + 5e3, "worker did not respond");
|
|
9908
|
+
return;
|
|
9909
|
+
}
|
|
9317
9910
|
if (typeof msg.html === "string") finish(() => resolve(msg.html));
|
|
9318
9911
|
else finish(() => reject(new Error(`[sibu prerender] ${input2.route}: ${msg.error}`)));
|
|
9319
9912
|
});
|
|
@@ -9426,6 +10019,8 @@ try {
|
|
|
9426
10019
|
process.on("unhandledRejection", (reason) => errors.push(reason));
|
|
9427
10020
|
|
|
9428
10021
|
await import(entryUrl);
|
|
10022
|
+
// The route's timeout starts now; the parent's backstop restarts with it.
|
|
10023
|
+
parentPort.postMessage({ loaded: true });
|
|
9429
10024
|
|
|
9430
10025
|
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
9431
10026
|
const started = Date.now();
|
|
@@ -9640,7 +10235,7 @@ function parserSafeText(s2) {
|
|
|
9640
10235
|
function escapeHtml(str) {
|
|
9641
10236
|
return str.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
9642
10237
|
}
|
|
9643
|
-
function
|
|
10238
|
+
function escapeAttr2(str) {
|
|
9644
10239
|
return str.replace(/&/g, "&").replace(/"/g, """).replace(/</g, "<").replace(/>/g, ">");
|
|
9645
10240
|
}
|
|
9646
10241
|
function attributeHtml(name, lit) {
|
|
@@ -9656,7 +10251,7 @@ function attributeHtml(name, lit) {
|
|
|
9656
10251
|
return on2 ? `${lower}=""` : "";
|
|
9657
10252
|
}
|
|
9658
10253
|
if (!parserSafeText(lit.value)) return null;
|
|
9659
|
-
return `${lower}="${
|
|
10254
|
+
return `${lower}="${escapeAttr2(lit.value)}"`;
|
|
9660
10255
|
}
|
|
9661
10256
|
function parseCall(code2, list, i2) {
|
|
9662
10257
|
const at = (k2) => list[k2];
|
|
@@ -9731,8 +10326,8 @@ function parseCall(code2, list, i2) {
|
|
|
9731
10326
|
}
|
|
9732
10327
|
function toHtml(tag, call) {
|
|
9733
10328
|
const attrs = [];
|
|
9734
|
-
if (call.cls !== null) attrs.push(`class="${
|
|
9735
|
-
if (call.id !== null) attrs.push(`id="${
|
|
10329
|
+
if (call.cls !== null) attrs.push(`class="${escapeAttr2(call.cls)}"`);
|
|
10330
|
+
if (call.id !== null) attrs.push(`id="${escapeAttr2(call.id)}"`);
|
|
9736
10331
|
attrs.push(...call.attrs);
|
|
9737
10332
|
const attrStr = attrs.length > 0 ? ` ${attrs.join(" ")}` : "";
|
|
9738
10333
|
if (VOID_ELEMENTS3.has(tag)) {
|
|
@@ -9832,6 +10427,7 @@ function sibuVitePlugin(options = {}) {
|
|
|
9832
10427
|
return {
|
|
9833
10428
|
name: "sibu-vite-plugin",
|
|
9834
10429
|
enforce: "pre",
|
|
10430
|
+
api: { prerender: prerenderOptions },
|
|
9835
10431
|
config(_userConfig, env) {
|
|
9836
10432
|
isDevMode = resolveDevMode(devMode, env);
|
|
9837
10433
|
return {
|
|
@@ -9872,7 +10468,10 @@ function sibuVitePlugin(options = {}) {
|
|
|
9872
10468
|
const target = prerenderTarget;
|
|
9873
10469
|
prerenderTarget = null;
|
|
9874
10470
|
const results = await prerender(prerenderOptions, target);
|
|
9875
|
-
for (const r of results)
|
|
10471
|
+
for (const r of results) {
|
|
10472
|
+
const what = r.kind === "redirect" ? `redirect ${r.status} (redirects.json)` : r.kind === "skipped" ? `skipped (${r.status})` : r.file;
|
|
10473
|
+
console.log(`[sibu prerender] ${r.route} \u2192 ${what} (${r.ms} ms)`);
|
|
10474
|
+
}
|
|
9876
10475
|
},
|
|
9877
10476
|
transform(code2, id) {
|
|
9878
10477
|
if (!matchesPattern(id, include) || matchesPattern(id, exclude)) {
|