@markless/router 0.8.0 → 0.10.0
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/dist/{create-server-entry-BsYTWdxi.js → create-server-entry-BnaEfDHl.js} +311 -66
- package/dist/index.js +2 -2
- package/dist/{request-locals-BDAhNpEa.js → navigation-timing-CzH6VaBR.js} +4 -2
- package/dist/vite/runtime/create-server-entry.d.ts +1 -0
- package/dist/vite/runtime/create-server-entry.js +1 -1
- package/dist/vite/runtime/mdx-route.d.ts +190 -7
- package/dist/vite/runtime/mdx-route.js +125 -13
- package/dist/vite.js +411 -62
- package/package.json +5 -5
- package/src/vite/entries/fragment-entry.ts +570 -238
- package/src/vite/entries/prerender-wake-entry.ts +3 -1
- package/src/vite/entries/resume-entry.ts +36 -23
- package/src/vite/entries/resume-modules.ts +7 -0
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import { a as
|
|
1
|
+
import { a as takeMiddlewareHeaders, c as SERVED_BODY_ATTRIBUTES_PROPERTY, d as servedHtmlAttributesScript, f as LINK_ATTRIBUTE, h as SCROLL_ATTRIBUTE, i as requestLocals, l as SERVED_HTML_ATTRIBUTES_PROPERTY, m as REPLACE_ATTRIBUTE, n as MARKLESS_NAV_SETTLE_DEADLINE_MS, o as HTML_ATTRIBUTES_SLOT, p as PREFETCH_ATTRIBUTE, s as ROUTE_SCRIPT_TYPE } from "./navigation-timing-CzH6VaBR.js";
|
|
2
2
|
import { i as matchRouteManifest, n as buildRouteManifestFromFileIds, o as normalizeRouteFileId } from "./route-manifest-DmoxXanW.js";
|
|
3
3
|
import { n as __marklessDebugBootstrapSource } from "./debug-channel-Di6SppZv.js";
|
|
4
|
-
import { CONTAINER_ATTRIBUTE, PROTOCOL_CONTAINER_END_COMMENT, PROTOCOL_CONTAINER_START_COMMENT, PROTOCOL_LOCATOR_PATHS_ATTRIBUTE } from "@markless/web/fns/container-region";
|
|
4
|
+
import { CONTAINER_ATTRIBUTE, PROTOCOL_CONTAINER_END_COMMENT, PROTOCOL_CONTAINER_START_COMMENT, PROTOCOL_LOCATOR_PATHS_ATTRIBUTE, PROTOCOL_STREAM_OPEN_PROPERTY } from "@markless/web/fns/container-region";
|
|
5
5
|
import { CONTAINER_RETIRE_PROPERTY, renderToString, splitSsrContainer } from "@markless/web/render-to-string";
|
|
6
6
|
import { STREAMED_ARM_SELECTOR, STREAM_ARM_EXECUTOR_GLOBAL, renderToStream } from "@markless/web/render-to-stream";
|
|
7
|
+
import { PROTOCOL_KEEP_ATTRIBUTE, PROTOCOL_OWN_ATTRIBUTE, installKeepParts } from "@markless/web/fns/keep-parts";
|
|
7
8
|
import { normalizeMarklessDevError, renderMarklessDevErrorDocument } from "@markless/bundler/dev-error";
|
|
8
9
|
//#region src/vite/link-intent.ts
|
|
9
10
|
function listenForLinkIntent(root, linkAttribute, preload, prefetchAttribute) {
|
|
@@ -55,13 +56,67 @@ function documentHandlersMessage(what) {
|
|
|
55
56
|
}
|
|
56
57
|
//#endregion
|
|
57
58
|
//#region src/vite/fragment-navigation.ts
|
|
58
|
-
function startFragmentNavigation(d, linkAttributeOf,
|
|
59
|
+
function startFragmentNavigation(d, linkAttributeOf, tableAttribute, importModule, loadRun, intentOf) {
|
|
59
60
|
const w = d.defaultView;
|
|
60
61
|
if (!w) return;
|
|
61
62
|
const host = d;
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
63
|
+
if (host.__marklessFragmentTables) return host.__marklessFragmentTables();
|
|
64
|
+
const read = /* @__PURE__ */ new WeakSet();
|
|
65
|
+
const table = {};
|
|
66
|
+
let unread = true;
|
|
67
|
+
host.__marklessFragmentTables = () => void (unread = true);
|
|
68
|
+
const fill = () => {
|
|
69
|
+
if (!unread) return table;
|
|
70
|
+
unread = false;
|
|
71
|
+
for (const script of d.querySelectorAll(`script[${tableAttribute}]`)) {
|
|
72
|
+
if (read.has(script)) continue;
|
|
73
|
+
read.add(script);
|
|
74
|
+
const [preloads, destinations] = JSON.parse(script.textContent);
|
|
75
|
+
for (const path in destinations) table[path] = destinations[path].map((at) => preloads[at]);
|
|
76
|
+
}
|
|
77
|
+
return table;
|
|
78
|
+
};
|
|
79
|
+
const routes = new Proxy(table, {
|
|
80
|
+
get: (_, key) => fill()[key],
|
|
81
|
+
has: (_, key) => key in fill(),
|
|
82
|
+
ownKeys: () => Reflect.ownKeys(fill()),
|
|
83
|
+
getOwnPropertyDescriptor: (_, key) => Reflect.getOwnPropertyDescriptor(fill(), key)
|
|
84
|
+
});
|
|
85
|
+
const landed = new Promise((done) => {
|
|
86
|
+
const start = () => {
|
|
87
|
+
const pending = [...d.head.querySelectorAll("link[rel=\"modulepreload\"]")].filter((link) => !w.performance.getEntriesByName(link.href, "resource").length);
|
|
88
|
+
let left = pending.length;
|
|
89
|
+
if (!left) return done();
|
|
90
|
+
const arrived = () => void (--left || done());
|
|
91
|
+
for (const link of pending) {
|
|
92
|
+
link.addEventListener("load", arrived, { once: true });
|
|
93
|
+
link.addEventListener("error", arrived, { once: true });
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
if (d.readyState === "complete") start();
|
|
97
|
+
else w.addEventListener("load", start, { once: true });
|
|
98
|
+
});
|
|
99
|
+
host.__marklessFragmentIdle = landed.then(() => {
|
|
100
|
+
const intent = intentOf();
|
|
101
|
+
if (!intent) return false;
|
|
102
|
+
const connection = w.navigator.connection;
|
|
103
|
+
let bytes = 0;
|
|
104
|
+
const spans = [];
|
|
105
|
+
for (const entry of [...w.performance.getEntriesByType("navigation"), ...w.performance.getEntriesByType("resource")]) {
|
|
106
|
+
if (!(entry.transferSize > 0)) continue;
|
|
107
|
+
bytes += entry.transferSize;
|
|
108
|
+
spans.push([entry.responseStart, entry.responseEnd]);
|
|
109
|
+
}
|
|
110
|
+
let busy = 0;
|
|
111
|
+
let reach = -Infinity;
|
|
112
|
+
for (const [from, to] of spans.sort((a, b) => a[0] - b[0])) {
|
|
113
|
+
busy += Math.max(0, to - Math.max(from, reach));
|
|
114
|
+
reach = Math.max(reach, to);
|
|
115
|
+
}
|
|
116
|
+
if (bytes && (busy === 0 || bytes / busy * 1e3 >= intent.idleBytesPerSecond)) return true;
|
|
117
|
+
if (bytes >= intent.idleMeasuredBytes) return false;
|
|
118
|
+
return connection?.effectiveType === "4g" && connection.saveData !== true;
|
|
119
|
+
});
|
|
65
120
|
const scrolled = /* @__PURE__ */ new Set();
|
|
66
121
|
const arriving = /* @__PURE__ */ new Map();
|
|
67
122
|
let running;
|
|
@@ -71,9 +126,14 @@ function startFragmentNavigation(d, linkAttributeOf, routes, importModule, loadR
|
|
|
71
126
|
const href = new URL(typeof item === "string" ? item : item.href, d.baseURI).href;
|
|
72
127
|
if (arriving.has(href)) return;
|
|
73
128
|
const link = d.createElement("link");
|
|
74
|
-
|
|
129
|
+
if (typeof item !== "string" && "as" in item) {
|
|
130
|
+
link.rel = "preload";
|
|
131
|
+
link.as = item.as;
|
|
132
|
+
} else {
|
|
133
|
+
link.rel = "modulepreload";
|
|
134
|
+
link.crossOrigin = "anonymous";
|
|
135
|
+
}
|
|
75
136
|
link.href = href;
|
|
76
|
-
link.crossOrigin = "anonymous";
|
|
77
137
|
arriving.set(href, new Promise((done) => link.onload = link.onerror = done));
|
|
78
138
|
d.head.appendChild(link);
|
|
79
139
|
};
|
|
@@ -114,7 +174,6 @@ function startFragmentNavigation(d, linkAttributeOf, routes, importModule, loadR
|
|
|
114
174
|
};
|
|
115
175
|
const wake = (event) => {
|
|
116
176
|
starting ??= loadRun().then((run) => {
|
|
117
|
-
delete host.__marklessFragmentWake;
|
|
118
177
|
return running = run(d, routes, importModule, scrolled, arriving, pressed);
|
|
119
178
|
});
|
|
120
179
|
starting.then((api) => api.replay(event), () => starting = void 0);
|
|
@@ -167,11 +226,7 @@ function startFragmentNavigation(d, linkAttributeOf, routes, importModule, loadR
|
|
|
167
226
|
event.preventDefault();
|
|
168
227
|
wake().then((api) => api.go(anchor) || w.location.assign(url.href), () => w.location.assign(url.href));
|
|
169
228
|
};
|
|
170
|
-
if (
|
|
171
|
-
const idle = () => w.requestIdleCallback ? w.requestIdleCallback(() => wake(), { timeout: 3e3 }) : w.setTimeout(() => wake(), 500);
|
|
172
|
-
if (d.readyState === "complete") idle();
|
|
173
|
-
else w.addEventListener("load", idle, { once: true });
|
|
174
|
-
}
|
|
229
|
+
if (d.querySelector(`script[${tableAttribute}]`)) landed.then(() => w.requestIdleCallback ? w.requestIdleCallback(() => wake(), { timeout: 3e3 }) : w.setTimeout(() => wake(), 500));
|
|
175
230
|
}
|
|
176
231
|
function runFragmentNavigation(d, config, routes, importModule, scrolled, arriving, early) {
|
|
177
232
|
const w = d.defaultView;
|
|
@@ -179,6 +234,7 @@ function runFragmentNavigation(d, config, routes, importModule, scrolled, arrivi
|
|
|
179
234
|
const location = w.location;
|
|
180
235
|
const connection = w.navigator.connection;
|
|
181
236
|
const pageKey = (url) => url.pathname + url.search;
|
|
237
|
+
const fetched = /* @__PURE__ */ new Set();
|
|
182
238
|
let module;
|
|
183
239
|
let loaded;
|
|
184
240
|
const load = () => {
|
|
@@ -189,23 +245,38 @@ function runFragmentNavigation(d, config, routes, importModule, scrolled, arrivi
|
|
|
189
245
|
return module;
|
|
190
246
|
};
|
|
191
247
|
const underEndpoints = (pathname) => config.endpointPrefixes.some((prefix) => (pathname + "/").startsWith(prefix + "/"));
|
|
192
|
-
const
|
|
248
|
+
const decoded = (part) => {
|
|
249
|
+
try {
|
|
250
|
+
return decodeURIComponent(part);
|
|
251
|
+
} catch {
|
|
252
|
+
return part;
|
|
253
|
+
}
|
|
254
|
+
};
|
|
255
|
+
const staticPages = /* @__PURE__ */ new Map();
|
|
256
|
+
const patterns = [];
|
|
257
|
+
for (const page of config.pages) {
|
|
258
|
+
const segments = page.split("/").filter(Boolean);
|
|
259
|
+
const under = underEndpoints(page);
|
|
260
|
+
if (segments.some((segment) => segment === "**" || segment === ":")) patterns.push([under, segments]);
|
|
261
|
+
else {
|
|
262
|
+
const key = JSON.stringify(segments);
|
|
263
|
+
staticPages.set(key, [...staticPages.get(key) ?? [], under]);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
const known = /* @__PURE__ */ new Map();
|
|
193
267
|
const isPage = (pathname) => {
|
|
268
|
+
const cached = known.get(pathname);
|
|
269
|
+
if (cached !== void 0) return cached;
|
|
194
270
|
const endpoint = underEndpoints(pathname);
|
|
195
|
-
const parts = pathname.split("/").filter(Boolean);
|
|
196
|
-
|
|
271
|
+
const parts = pathname.split("/").filter(Boolean).map(decoded);
|
|
272
|
+
const answer = !!staticPages.get(JSON.stringify(parts))?.some((under) => !endpoint || under) || patterns.some(([under, page]) => {
|
|
197
273
|
if (endpoint && !under) return false;
|
|
198
274
|
const rest = page.indexOf("**");
|
|
199
275
|
if (rest === -1 ? page.length !== parts.length : parts.length <= rest) return false;
|
|
200
|
-
return page.every((segment, index) =>
|
|
201
|
-
if (segment === "**" || segment === ":") return true;
|
|
202
|
-
try {
|
|
203
|
-
return segment === decodeURIComponent(parts[index]);
|
|
204
|
-
} catch {
|
|
205
|
-
return segment === parts[index];
|
|
206
|
-
}
|
|
207
|
-
});
|
|
276
|
+
return page.every((segment, index) => segment === "**" || segment === ":" || segment === parts[index]);
|
|
208
277
|
});
|
|
278
|
+
known.set(pathname, answer);
|
|
279
|
+
return answer;
|
|
209
280
|
};
|
|
210
281
|
const eligible = (anchor, forClick = false) => {
|
|
211
282
|
if (!anchor || anchor.localName !== "a") return;
|
|
@@ -241,9 +312,14 @@ function runFragmentNavigation(d, config, routes, importModule, scrolled, arrivi
|
|
|
241
312
|
if (present.has(href) || arriving.has(href)) continue;
|
|
242
313
|
present.add(href);
|
|
243
314
|
const link = d.createElement("link");
|
|
244
|
-
|
|
315
|
+
if ("as" in entry) {
|
|
316
|
+
link.rel = "preload";
|
|
317
|
+
link.as = entry.as;
|
|
318
|
+
} else {
|
|
319
|
+
link.rel = "modulepreload";
|
|
320
|
+
link.crossOrigin = entry.crossOrigin ?? "anonymous";
|
|
321
|
+
}
|
|
245
322
|
link.href = href;
|
|
246
|
-
link.crossOrigin = entry.crossOrigin ?? "anonymous";
|
|
247
323
|
if (low) link.fetchPriority = "low";
|
|
248
324
|
arriving.set(href, new Promise((done) => {
|
|
249
325
|
link.addEventListener("load", done, { once: true });
|
|
@@ -252,13 +328,45 @@ function runFragmentNavigation(d, config, routes, importModule, scrolled, arrivi
|
|
|
252
328
|
d.head.appendChild(link);
|
|
253
329
|
}
|
|
254
330
|
};
|
|
331
|
+
const parseAsLoaded = (html) => {
|
|
332
|
+
const raw = [];
|
|
333
|
+
const emptied = html.replace(/<!--[\s\S]*?-->|<(script|style|textarea|title)\b[^>]*>[\s\S]*?<\/\1\s*>|<noscript\b([^>]*)>([\s\S]*?)<\/noscript\s*>/gi, (match, _rawText, attributes, content) => {
|
|
334
|
+
if (content === void 0) return match;
|
|
335
|
+
raw.push(content);
|
|
336
|
+
return `<noscript${attributes ?? ""}></noscript>`;
|
|
337
|
+
});
|
|
338
|
+
if (!raw.length) return new DOMParser().parseFromString(html, "text/html");
|
|
339
|
+
const doc = new DOMParser().parseFromString(emptied, "text/html");
|
|
340
|
+
const tags = doc.getElementsByTagName("noscript");
|
|
341
|
+
if (tags.length !== raw.length) return new DOMParser().parseFromString(html, "text/html");
|
|
342
|
+
for (let index = 0; index < tags.length; index++) tags[index].textContent = raw[index];
|
|
343
|
+
return doc;
|
|
344
|
+
};
|
|
345
|
+
const preloadStyles = (doc) => {
|
|
346
|
+
for (const link of doc.head.querySelectorAll("link[rel=\"stylesheet\"][href]")) {
|
|
347
|
+
const href = new URL(link.getAttribute("href"), d.baseURI).href;
|
|
348
|
+
if ([...d.querySelectorAll("link[href]")].some((own) => own.href === href)) continue;
|
|
349
|
+
const preload = d.createElement("link");
|
|
350
|
+
preload.rel = "preload";
|
|
351
|
+
preload.as = "style";
|
|
352
|
+
preload.href = href;
|
|
353
|
+
for (const name of [
|
|
354
|
+
"media",
|
|
355
|
+
"crossorigin",
|
|
356
|
+
"integrity"
|
|
357
|
+
]) if (link.hasAttribute(name)) preload.setAttribute(name, link.getAttribute(name));
|
|
358
|
+
d.head.append(preload);
|
|
359
|
+
}
|
|
360
|
+
};
|
|
255
361
|
const parse = (url, text) => {
|
|
256
362
|
const at = text.indexOf(config.regionEndMarker);
|
|
257
363
|
const prefix = at === -1 ? text : text.slice(0, at);
|
|
364
|
+
const doc = parseAsLoaded(prefix);
|
|
365
|
+
preloadStyles(doc);
|
|
258
366
|
return {
|
|
259
367
|
url,
|
|
260
368
|
prefix,
|
|
261
|
-
doc
|
|
369
|
+
doc,
|
|
262
370
|
tail: at === -1 ? "" : text.slice(at + config.regionEndMarker.length)
|
|
263
371
|
};
|
|
264
372
|
};
|
|
@@ -291,7 +399,8 @@ function runFragmentNavigation(d, config, routes, importModule, scrolled, arrivi
|
|
|
291
399
|
cancel: () => reader.cancel()
|
|
292
400
|
};
|
|
293
401
|
};
|
|
294
|
-
const request = (url, speculative, started) => {
|
|
402
|
+
const request = (url, speculative, started, budget = Infinity) => {
|
|
403
|
+
fetched.add(pageKey(url));
|
|
295
404
|
const controller = started?.controller ?? new AbortController();
|
|
296
405
|
const read = async () => {
|
|
297
406
|
const prefix = config.requestPrefix;
|
|
@@ -301,9 +410,13 @@ function runFragmentNavigation(d, config, routes, importModule, scrolled, arrivi
|
|
|
301
410
|
const response = await (started?.response ?? w.fetch(target.href, {
|
|
302
411
|
credentials: "same-origin",
|
|
303
412
|
headers: speculative ? { purpose: "prefetch" } : {},
|
|
304
|
-
priority: speculative ? "auto" : "high",
|
|
413
|
+
priority: speculative === "idle" ? "low" : speculative ? "auto" : "high",
|
|
305
414
|
signal: controller.signal
|
|
306
415
|
}));
|
|
416
|
+
const cacheControl = response.headers.get("cache-control") ?? "";
|
|
417
|
+
const maxAge = Number(/(?:^|,)\s*max-age\s*=\s*"?(\d+)/i.exec(cacheControl)?.[1]);
|
|
418
|
+
if (/(?:^|,)\s*no-store\b/i.test(cacheControl)) entry.expires = w.performance.now();
|
|
419
|
+
else if (maxAge > 0) entry.expires = entry.at + maxAge * 1e3;
|
|
307
420
|
const type = response.headers.get("content-type") ?? "";
|
|
308
421
|
if (!response.ok || !type.includes("text/html") || !response.body) throw new Error(`MARKLESS_ROUTER_FRAGMENT_UNAVAILABLE: ${response.status}`);
|
|
309
422
|
const finalUrl = new URL(response.url || target.href);
|
|
@@ -311,9 +424,11 @@ function runFragmentNavigation(d, config, routes, importModule, scrolled, arrivi
|
|
|
311
424
|
if (!finalUrl.pathname.startsWith(`${prefix}/`)) throw new Error("MARKLESS_ROUTER_FRAGMENT_UNAVAILABLE: redirected");
|
|
312
425
|
finalUrl.pathname = finalUrl.pathname.slice(prefix.length);
|
|
313
426
|
finalUrl.hash = url.hash;
|
|
427
|
+
if (Number(response.headers.get("content-length") ?? 0) > budget) throw new Error("MARKLESS_ROUTER_FRAGMENT_OVER_IDLE_BUDGET");
|
|
314
428
|
const reader = response.body.getReader();
|
|
315
429
|
const decoder = new TextDecoder();
|
|
316
430
|
let text = "";
|
|
431
|
+
let bytes = 0;
|
|
317
432
|
for (;;) {
|
|
318
433
|
if (text.includes(config.regionEndMarker)) return {
|
|
319
434
|
...parse(finalUrl.href, text),
|
|
@@ -324,6 +439,11 @@ function runFragmentNavigation(d, config, routes, importModule, scrolled, arrivi
|
|
|
324
439
|
closed();
|
|
325
440
|
return parse(finalUrl.href, text + decoder.decode());
|
|
326
441
|
}
|
|
442
|
+
bytes += chunk.value.byteLength;
|
|
443
|
+
if (bytes > budget) {
|
|
444
|
+
reader.cancel();
|
|
445
|
+
throw new Error("MARKLESS_ROUTER_FRAGMENT_OVER_IDLE_BUDGET");
|
|
446
|
+
}
|
|
327
447
|
text += decoder.decode(chunk.value, { stream: true });
|
|
328
448
|
}
|
|
329
449
|
};
|
|
@@ -333,6 +453,7 @@ function runFragmentNavigation(d, config, routes, importModule, scrolled, arrivi
|
|
|
333
453
|
};
|
|
334
454
|
const entry = {
|
|
335
455
|
at: started?.at ?? w.performance.now(),
|
|
456
|
+
writes: state.writes,
|
|
336
457
|
result: read(),
|
|
337
458
|
open: true,
|
|
338
459
|
abort: () => {
|
|
@@ -343,25 +464,36 @@ function runFragmentNavigation(d, config, routes, importModule, scrolled, arrivi
|
|
|
343
464
|
entry.result.catch(closed);
|
|
344
465
|
return entry;
|
|
345
466
|
};
|
|
346
|
-
const prefetch = (url, code = true, started) => {
|
|
467
|
+
const prefetch = (url, code = true, started, budget = Infinity, idle = false) => {
|
|
347
468
|
const key = pageKey(url);
|
|
348
469
|
if (!config.prefetch || key === state.shown) return;
|
|
349
470
|
const existing = state.prefetches.get(key);
|
|
350
|
-
if (existing && w.performance.now()
|
|
471
|
+
if (existing && fresh(existing, w.performance.now())) return void (code && preloadCode(url, false));
|
|
351
472
|
existing?.abort();
|
|
352
473
|
const open = [...state.prefetches].filter(([, entry]) => entry.open);
|
|
353
474
|
for (const [stale, entry] of open.slice(0, Math.max(0, open.length + 1 - config.prefetchConnections))) {
|
|
354
475
|
state.prefetches.delete(stale);
|
|
355
476
|
entry.abort();
|
|
356
477
|
}
|
|
357
|
-
const entry = request(url, true, started);
|
|
478
|
+
const entry = request(url, idle ? "idle" : true, started, budget);
|
|
479
|
+
entry.result.catch(() => {
|
|
480
|
+
if (state.prefetches.get(key) === entry) state.prefetches.delete(key);
|
|
481
|
+
});
|
|
358
482
|
state.prefetches.set(key, entry);
|
|
483
|
+
expire(key, entry);
|
|
484
|
+
if (code) preloadCode(url, false);
|
|
485
|
+
};
|
|
486
|
+
const stamps = /* @__PURE__ */ new WeakMap();
|
|
487
|
+
let stamped = 0;
|
|
488
|
+
const expire = (key, entry) => {
|
|
489
|
+
const stamp = ++stamped;
|
|
490
|
+
stamps.set(entry, stamp);
|
|
359
491
|
w.setTimeout(() => {
|
|
360
|
-
|
|
492
|
+
const current = state.prefetches.get(key);
|
|
493
|
+
if (!current || stamps.get(current) !== stamp) return;
|
|
361
494
|
state.prefetches.delete(key);
|
|
362
|
-
|
|
495
|
+
current.abort();
|
|
363
496
|
}, config.prefetchTtlMs);
|
|
364
|
-
if (code) preloadCode(url, false);
|
|
365
497
|
};
|
|
366
498
|
let scanning = false;
|
|
367
499
|
let idleQueue = [];
|
|
@@ -371,8 +503,8 @@ function runFragmentNavigation(d, config, routes, importModule, scrolled, arrivi
|
|
|
371
503
|
for (const entry of state.prefetches.values()) if (entry.open) open += 1;
|
|
372
504
|
if (open >= config.prefetchConnections) return;
|
|
373
505
|
const url = idleQueue.shift();
|
|
374
|
-
if (state.prefetches.has(pageKey(url))) continue;
|
|
375
|
-
prefetch(url, false);
|
|
506
|
+
if (state.prefetches.has(pageKey(url)) || fetched.has(pageKey(url))) continue;
|
|
507
|
+
prefetch(url, false, void 0, config.idleFragmentBytes, true);
|
|
376
508
|
preloadCode(url, true);
|
|
377
509
|
}
|
|
378
510
|
};
|
|
@@ -393,18 +525,23 @@ function runFragmentNavigation(d, config, routes, importModule, scrolled, arrivi
|
|
|
393
525
|
visible.set(pageKey(url), url);
|
|
394
526
|
}
|
|
395
527
|
idleQueue = [];
|
|
396
|
-
for (const [key, url] of visible) if (idleQueue.length < config.idleFragments && !state.prefetches.has(key)) idleQueue.push(url);
|
|
528
|
+
for (const [key, url] of visible) if (idleQueue.length < config.idleFragments && !state.prefetches.has(key) && !fetched.has(key)) idleQueue.push(url);
|
|
397
529
|
pumpIdle();
|
|
398
530
|
};
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
531
|
+
(host.__marklessFragmentIdle ?? Promise.resolve(false)).then((fast) => {
|
|
532
|
+
if (!fast) return void (scanning = false);
|
|
533
|
+
if (w.requestIdleCallback) w.requestIdleCallback(run, { timeout: 3e3 });
|
|
534
|
+
else w.setTimeout(run, 500);
|
|
535
|
+
});
|
|
402
536
|
};
|
|
537
|
+
const fresh = (entry, now) => entry.writes === state.writes && now - entry.at < config.prefetchTtlMs && (entry.expires === void 0 || now < entry.expires);
|
|
403
538
|
const state = {
|
|
404
539
|
config,
|
|
405
540
|
routes,
|
|
406
541
|
prefetches: /* @__PURE__ */ new Map(),
|
|
407
542
|
visited: /* @__PURE__ */ new Map(),
|
|
543
|
+
writes: 0,
|
|
544
|
+
fresh,
|
|
408
545
|
shown: pageKey(new URL(location.href)),
|
|
409
546
|
eligible,
|
|
410
547
|
preloadCode,
|
|
@@ -418,8 +555,42 @@ function runFragmentNavigation(d, config, routes, importModule, scrolled, arrivi
|
|
|
418
555
|
};
|
|
419
556
|
host.__marklessFragmentNav = state;
|
|
420
557
|
if (early) prefetch(new URL(early.url), true, early);
|
|
558
|
+
const wrote = () => {
|
|
559
|
+
state.writes++;
|
|
560
|
+
for (const entry of state.prefetches.values()) entry.abort();
|
|
561
|
+
state.prefetches.clear();
|
|
562
|
+
state.visited.clear();
|
|
563
|
+
};
|
|
564
|
+
d.addEventListener("submit", wrote, true);
|
|
565
|
+
const read = /* @__PURE__ */ new Set([
|
|
566
|
+
"GET",
|
|
567
|
+
"HEAD",
|
|
568
|
+
"OPTIONS"
|
|
569
|
+
]);
|
|
570
|
+
const send = w.fetch;
|
|
571
|
+
w.fetch = function fetch(input, init) {
|
|
572
|
+
const response = send.call(w, input, init);
|
|
573
|
+
const request = input instanceof Request ? input : void 0;
|
|
574
|
+
const method = (init?.method ?? request?.method ?? "GET").toUpperCase();
|
|
575
|
+
if (!read.has(method)) {
|
|
576
|
+
let same = false;
|
|
577
|
+
try {
|
|
578
|
+
same = new URL(request?.url ?? String(input), location.href).origin === location.origin;
|
|
579
|
+
} catch {}
|
|
580
|
+
if (same) {
|
|
581
|
+
wrote();
|
|
582
|
+
response.then(wrote, wrote);
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
return response;
|
|
586
|
+
};
|
|
421
587
|
let restTimer = 0;
|
|
588
|
+
let resting = "";
|
|
422
589
|
let previous;
|
|
590
|
+
const stopRest = () => {
|
|
591
|
+
w.clearTimeout(restTimer);
|
|
592
|
+
resting = "";
|
|
593
|
+
};
|
|
423
594
|
const hover = (event) => {
|
|
424
595
|
const pointer = event;
|
|
425
596
|
if (pointer.pointerType !== "mouse") return;
|
|
@@ -428,20 +599,27 @@ function runFragmentNavigation(d, config, routes, importModule, scrolled, arrivi
|
|
|
428
599
|
y: pointer.clientY,
|
|
429
600
|
t: pointer.timeStamp
|
|
430
601
|
};
|
|
431
|
-
if (previous && point.x === previous.x && point.y === previous.y)
|
|
602
|
+
if (previous && point.x === previous.x && point.y === previous.y) {
|
|
603
|
+
if (eligible(anchorOf(event))?.href !== resting) stopRest();
|
|
604
|
+
return;
|
|
605
|
+
}
|
|
432
606
|
const gap = previous ? point.t - previous.t : 0;
|
|
433
607
|
const creeping = !!previous && gap > 0 && Math.hypot(point.x - previous.x, point.y - previous.y) / gap < .1;
|
|
434
608
|
previous = point;
|
|
435
|
-
|
|
609
|
+
stopRest();
|
|
436
610
|
const url = eligible(anchorOf(event));
|
|
437
611
|
if (!url) return;
|
|
438
|
-
if (creeping) prefetch(url);
|
|
439
|
-
|
|
612
|
+
if (creeping) return prefetch(url);
|
|
613
|
+
resting = url.href;
|
|
614
|
+
restTimer = w.setTimeout(() => {
|
|
615
|
+
resting = "";
|
|
616
|
+
prefetch(url);
|
|
617
|
+
}, Math.max(config.hoverDwellMs, gap * 1.5));
|
|
440
618
|
};
|
|
441
619
|
d.addEventListener("pointermove", hover, { passive: true });
|
|
442
|
-
d.addEventListener("pointerout",
|
|
620
|
+
d.addEventListener("pointerout", stopRest, { passive: true });
|
|
443
621
|
const press = (event) => {
|
|
444
|
-
|
|
622
|
+
stopRest();
|
|
445
623
|
const anchor = anchorOf(event);
|
|
446
624
|
const url = eligible(anchor);
|
|
447
625
|
if (url) prefetch(url);
|
|
@@ -456,7 +634,7 @@ function runFragmentNavigation(d, config, routes, importModule, scrolled, arrivi
|
|
|
456
634
|
const url = eligible(anchor, true);
|
|
457
635
|
if (!url) return false;
|
|
458
636
|
const current = new URL(location.href);
|
|
459
|
-
|
|
637
|
+
stopRest();
|
|
460
638
|
const replace = anchor.hasAttribute(config.replaceAttribute) || url.href === current.href;
|
|
461
639
|
const manual = anchor.getAttribute(config.scrollAttribute) === "manual";
|
|
462
640
|
const swap = (entry) => entry.navigate(d, url, replace ? "replace" : "push", manual ? "manual" : "reset");
|
|
@@ -495,6 +673,8 @@ function runFragmentNavigation(d, config, routes, importModule, scrolled, arrivi
|
|
|
495
673
|
};
|
|
496
674
|
}
|
|
497
675
|
const FRAGMENT_PATH_PREFIX = "/_markless/fragment";
|
|
676
|
+
/** Set on every fragment response, so a redirect it answers can be pointed back at a fragment. */
|
|
677
|
+
const FRAGMENT_RESPONSE_HEADER = "x-markless-fragment";
|
|
498
678
|
function fragmentPageUrl(url) {
|
|
499
679
|
if (!url.pathname.startsWith(`/_markless/fragment/`)) return void 0;
|
|
500
680
|
const page = new URL(url);
|
|
@@ -504,10 +684,15 @@ function fragmentPageUrl(url) {
|
|
|
504
684
|
const FRAGMENT_REGION_END = "<!--markless:region-end-->";
|
|
505
685
|
const FRAGMENT_APPEND_END = "<!--markless:append-end-->";
|
|
506
686
|
const FRAGMENT_PREFETCH_TTL_MS = 3e4;
|
|
687
|
+
const FRAGMENT_IDLE_FRAGMENT_BYTES = 262144;
|
|
688
|
+
const FRAGMENT_IDLE_BYTES_PER_SECOND = 25e4;
|
|
689
|
+
const FRAGMENT_IDLE_MEASURED_BYTES = 65536;
|
|
507
690
|
//#endregion
|
|
508
691
|
//#region src/vite/runtime/link-bridge-module.ts
|
|
509
692
|
/** Marks the page's link bridge script: inline in dev, a module stub importing the shared bridge in a build. */
|
|
510
693
|
const LINK_BRIDGE_SCRIPT_ATTRIBUTE = "data-markless-router-link-resumer";
|
|
694
|
+
/** Marks the page's route table: inert JSON `[preloads, destinations]`, each destination a list of indexes into preloads. */
|
|
695
|
+
const LINK_TABLE_SCRIPT_ATTRIBUTE = "data-markless-router-links";
|
|
511
696
|
/** The client output folder a build writes its link bridge files into, served as immutable static assets. */
|
|
512
697
|
const LINK_BRIDGE_DIR = "_markless/links";
|
|
513
698
|
function linkBridgeModulePath(base, hash) {
|
|
@@ -771,12 +956,35 @@ function routerLinkBridgeModules(options, manifest = buildRouteManifestFromFileI
|
|
|
771
956
|
return linkBridgeModules(options.base ?? "/", options.navigationEntryPath, fragmentBridge !== void 0 || options.prefetch !== false, options.documentNavigation === "document", fragmentBridge, options.debug);
|
|
772
957
|
}
|
|
773
958
|
function createServerEntry(options) {
|
|
959
|
+
installKeepParts();
|
|
774
960
|
const manifest = buildRouteManifestFromFileIds(options.routeFileIds);
|
|
775
961
|
assertCurrentRouteAssets(options);
|
|
776
962
|
const fragmentBridge = fragmentBridgeFor(options, manifest);
|
|
777
963
|
const fragmentNavigation = fragmentBridge !== void 0;
|
|
778
964
|
const linkBridgeModules = options.dev || options.linkBridgePaths ? void 0 : routerLinkBridgeModules(options, manifest);
|
|
779
965
|
const linkBridges = options.dev ? void 0 : options.linkBridgePaths ?? (linkBridgeModules && [linkBridgeModules[0].path, linkBridgeModules[1].path]);
|
|
966
|
+
const documentHeads = /* @__PURE__ */ new Map();
|
|
967
|
+
function pageStylesheetsAt(url, match, documentModule, request) {
|
|
968
|
+
const own = pageStylesheets(options, match.route.file) ?? [];
|
|
969
|
+
if (options.documentNavigation !== "document" || !documentModule) return Promise.resolve(own);
|
|
970
|
+
const key = url.pathname + url.search;
|
|
971
|
+
let head = documentHeads.get(key);
|
|
972
|
+
if (!head) {
|
|
973
|
+
if (documentHeads.size >= 1e3) documentHeads.delete(documentHeads.keys().next().value);
|
|
974
|
+
head = renderDocumentShell(documentModule, {
|
|
975
|
+
http: createPageHttp(request, url).context,
|
|
976
|
+
params: match.params,
|
|
977
|
+
url: {
|
|
978
|
+
href: url.href,
|
|
979
|
+
pathname: url.pathname,
|
|
980
|
+
search: url.search
|
|
981
|
+
},
|
|
982
|
+
status: 200
|
|
983
|
+
}, "").then(stylesheetHrefs, () => []);
|
|
984
|
+
documentHeads.set(key, head);
|
|
985
|
+
}
|
|
986
|
+
return head.then((hrefs) => [.../* @__PURE__ */ new Set([...own, ...hrefs])]);
|
|
987
|
+
}
|
|
780
988
|
async function fetch(request) {
|
|
781
989
|
const requestUrl = new URL(request.url);
|
|
782
990
|
const fragmentUrl = fragmentNavigation ? fragmentPageUrl(requestUrl) : void 0;
|
|
@@ -854,7 +1062,10 @@ function createServerEntry(options) {
|
|
|
854
1062
|
const documentLoads = options.documentNavigation === "document";
|
|
855
1063
|
const linkIntent = fragmentNavigation || options.prefetch !== false;
|
|
856
1064
|
const destinationPreloads = documentLoads || fragmentNavigation ? options.routeSsrModulePreloads : options.routeModulePreloads;
|
|
857
|
-
const pageArtifact = routedPageArtifact(renderSsr, baseArtifact, pageProps,
|
|
1065
|
+
const pageArtifact = routedPageArtifact(renderSsr, baseArtifact, pageProps, {
|
|
1066
|
+
file,
|
|
1067
|
+
...options.routeResumeModules?.[file] ? { resume: options.routeResumeModules[file] } : {}
|
|
1068
|
+
}, options.navigationEntryPath, pageStylesheets(options, file), documentModule?.default?.headInjections ?? [], linkIntent ? (html) => linkIntentPreloads(html, pageProps.url.href, manifest, destinationPreloads, fragmentNavigation, fragmentNavigation ? (destination, match) => pageStylesheetsAt(destination, match, documentModule, request) : void 0) : void 0, documentLoads, fragmentBridge, linkBridges);
|
|
858
1069
|
let rendersStorage = false;
|
|
859
1070
|
const routedArtifact = {
|
|
860
1071
|
...pageArtifact,
|
|
@@ -876,7 +1087,7 @@ function createServerEntry(options) {
|
|
|
876
1087
|
resumeModuleUrl: options.resumeEntryPath ?? baseArtifact?.resumeModuleUrl,
|
|
877
1088
|
modulePreloads: (html, resumes) => landingModulePreloads(resumes ? options.routeSsrModulePreloads?.[file] : void 0, linkBridges?.[html.includes("href=\"#/") ? 1 : 0])
|
|
878
1089
|
};
|
|
879
|
-
const headStart = (
|
|
1090
|
+
const headStart = (fragmentNavigation && !fragment ? servedHtmlAttributesScript() : "") + (fragment ? "" : options.importMap ?? "");
|
|
880
1091
|
if (options.render === "blocking") {
|
|
881
1092
|
const pageHtml = splitPageHtml(await renderToString(routedArtifact, renderOptions));
|
|
882
1093
|
privateToVisitor();
|
|
@@ -963,7 +1174,7 @@ function pageStylesheets(options, file) {
|
|
|
963
1174
|
if (documentHrefs.length === 0) return routeHrefs;
|
|
964
1175
|
return [.../* @__PURE__ */ new Set([...documentHrefs, ...routeHrefs ?? []])];
|
|
965
1176
|
}
|
|
966
|
-
function routedPageArtifact(renderSsr, baseArtifact, pageProps,
|
|
1177
|
+
function routedPageArtifact(renderSsr, baseArtifact, pageProps, route, navigationEntryPath, stylesheetHrefs, documentHeadInjections = [], intentPreloads, documentLoads = false, fragment, linkBridgePaths) {
|
|
967
1178
|
const headInjections = dedupeHeadLinks([
|
|
968
1179
|
...documentHeadInjections,
|
|
969
1180
|
...baseArtifact?.headInjections ?? [],
|
|
@@ -984,8 +1195,8 @@ function routedPageArtifact(renderSsr, baseArtifact, pageProps, file, navigation
|
|
|
984
1195
|
async renderSsr(renderProps, renderContext) {
|
|
985
1196
|
const output = await renderSsr(renderProps ?? pageProps, renderContext);
|
|
986
1197
|
if (!output) return { html: "" };
|
|
987
|
-
const routeScript = output.state || output.view ? renderRouteScript(
|
|
988
|
-
const linkBridge = navigationEntryPath ? renderLinkBridgeScript(navigationEntryPath, intentPreloads?.(output.html), documentLoads, fragment, output.html.includes("href=\"#/"), linkBridgePaths) : "";
|
|
1198
|
+
const routeScript = output.state || output.view ? renderRouteScript(route) : "";
|
|
1199
|
+
const linkBridge = navigationEntryPath ? renderLinkBridgeScript(navigationEntryPath, await intentPreloads?.(output.html), documentLoads, fragment, output.html.includes("href=\"#/"), linkBridgePaths) : "";
|
|
989
1200
|
const stateWithProps = withPagePropsCell(output.state, pageProps);
|
|
990
1201
|
return routeScript || linkBridge || stateWithProps !== output.state ? {
|
|
991
1202
|
...output,
|
|
@@ -1013,8 +1224,22 @@ function withPagePropsCell(state, props) {
|
|
|
1013
1224
|
function landingModulePreloads(routePreloads, linkBridgePath) {
|
|
1014
1225
|
const preloads = [];
|
|
1015
1226
|
addModulePreloads(preloads, /* @__PURE__ */ new Set(), routePreloads);
|
|
1016
|
-
|
|
1017
|
-
|
|
1227
|
+
const landing = preloads.map(highFetchPriority);
|
|
1228
|
+
if (linkBridgePath) landing.push({
|
|
1229
|
+
href: linkBridgePath,
|
|
1230
|
+
fetchPriority: "low"
|
|
1231
|
+
});
|
|
1232
|
+
return landing.length > 0 ? landing : void 0;
|
|
1233
|
+
}
|
|
1234
|
+
function highFetchPriority(preload) {
|
|
1235
|
+
if (typeof preload === "string") return {
|
|
1236
|
+
href: preload,
|
|
1237
|
+
fetchPriority: "high"
|
|
1238
|
+
};
|
|
1239
|
+
return preload.fetchPriority ? preload : {
|
|
1240
|
+
...preload,
|
|
1241
|
+
fetchPriority: "high"
|
|
1242
|
+
};
|
|
1018
1243
|
}
|
|
1019
1244
|
function routerLinkHrefs(html) {
|
|
1020
1245
|
return [...html.matchAll(/<a\b(?=[^>]*\bdata-markless-router-link(?:[\s=>]|$))(?=[^>]*\bhref="([^"]*)")[^>]*>/g)].map((match) => unescapeHtmlAttribute(match[1] ?? ""));
|
|
@@ -1022,16 +1247,28 @@ function routerLinkHrefs(html) {
|
|
|
1022
1247
|
function anchorHrefs(html) {
|
|
1023
1248
|
return [...html.matchAll(/<a\b(?=[^>]*\bhref="([^"]*)")[^>]*>/g)].map((match) => unescapeHtmlAttribute(match[1] ?? ""));
|
|
1024
1249
|
}
|
|
1025
|
-
function linkIntentPreloads(html, baseHref, manifest, routes, plainAnchors = false) {
|
|
1250
|
+
async function linkIntentPreloads(html, baseHref, manifest, routes, plainAnchors = false, stylesheetsOf) {
|
|
1026
1251
|
const destinations = Object.create(null);
|
|
1252
|
+
const here = new URL(baseHref);
|
|
1253
|
+
const herePage = stylesheetsOf && matchRouteManifest(here.pathname, manifest);
|
|
1254
|
+
const have = new Set(herePage ? await stylesheetsOf(here, herePage) : []);
|
|
1027
1255
|
for (const href of plainAnchors ? anchorHrefs(html) : routerLinkHrefs(html)) {
|
|
1028
1256
|
const url = parseSameOriginUrl(href, baseHref);
|
|
1029
1257
|
const match = url && matchRouteManifest(url.pathname, manifest);
|
|
1030
1258
|
const preloads = match && routes?.[match.route.file];
|
|
1031
|
-
if (url
|
|
1259
|
+
if (!url || !preloads || preloads.length === 0 && !plainAnchors || url.pathname in destinations) continue;
|
|
1260
|
+
const styles = stylesheetsOf ? (await stylesheetsOf(url, match)).filter((href) => !have.has(href)) : [];
|
|
1261
|
+
destinations[url.pathname] = styles.length ? [...preloads, ...styles.map((href) => ({
|
|
1262
|
+
href,
|
|
1263
|
+
as: "style"
|
|
1264
|
+
}))] : preloads;
|
|
1032
1265
|
}
|
|
1033
1266
|
return destinations;
|
|
1034
1267
|
}
|
|
1268
|
+
const STYLESHEET_LINK = /<link\b(?=[^>]*\brel="(?:[^"]*\s)?stylesheet(?:\s[^"]*)?")(?=[^>]*\bhref="([^"]*)")[^>]*>/g;
|
|
1269
|
+
function stylesheetHrefs(html) {
|
|
1270
|
+
return [...html.matchAll(STYLESHEET_LINK)].map((match) => unescapeHtmlAttribute(match[1]));
|
|
1271
|
+
}
|
|
1035
1272
|
function indexedPreloads(intentPreloads) {
|
|
1036
1273
|
const preloads = [];
|
|
1037
1274
|
const indexes = /* @__PURE__ */ new Map();
|
|
@@ -1142,18 +1379,20 @@ function insertHeadHtml(documentHtml, headHtml) {
|
|
|
1142
1379
|
if (headEnd === -1) return `${headHtml}${documentHtml}`;
|
|
1143
1380
|
return `${documentHtml.slice(0, headEnd)}${headHtml}${documentHtml.slice(headEnd)}`;
|
|
1144
1381
|
}
|
|
1145
|
-
function renderRouteScript(
|
|
1146
|
-
return `<script type="${ROUTE_SCRIPT_TYPE}">${escapeScriptJson(
|
|
1382
|
+
function renderRouteScript(route) {
|
|
1383
|
+
return `<script type="${ROUTE_SCRIPT_TYPE}">${escapeScriptJson(route)}<\/script>`;
|
|
1147
1384
|
}
|
|
1148
1385
|
function linkBridgeBody(resumeEntryPath, linkIntent, documentLoads, fragment, page, debug = debugDefined()) {
|
|
1149
1386
|
const inline = !("module" in page);
|
|
1150
1387
|
const fragmentNavigation = fragment !== void 0;
|
|
1151
1388
|
const fragmentSource = fragment ? `
|
|
1152
|
-
(${fragment.source})(d,()=>${JSON.stringify(LINK_ATTRIBUTE)},${
|
|
1389
|
+
(${fragment.source})(d,()=>${JSON.stringify(LINK_ATTRIBUTE)},${JSON.stringify(LINK_TABLE_SCRIPT_ATTRIBUTE)},(href)=>import(href),${"runPath" in page && page.runPath ? `()=>import(${JSON.stringify(page.runPath)}).then((m)=>m.default)` : `()=>Promise.resolve(${boundFragmentRun(fragment, documentLoads)})`},()=>(${fragment.prefetch ? escapeScriptJson({
|
|
1153
1390
|
code: [fragment.entry, ...fragment.entryImports],
|
|
1154
1391
|
hoverDwellMs: 20,
|
|
1155
1392
|
requestPrefix: FRAGMENT_PATH_PREFIX,
|
|
1156
|
-
prefetchAttribute: PREFETCH_ATTRIBUTE
|
|
1393
|
+
prefetchAttribute: PREFETCH_ATTRIBUTE,
|
|
1394
|
+
idleBytesPerSecond: FRAGMENT_IDLE_BYTES_PER_SECOND,
|
|
1395
|
+
idleMeasuredBytes: FRAGMENT_IDLE_MEASURED_BYTES
|
|
1157
1396
|
}) : "null"}));` : "";
|
|
1158
1397
|
const indexed = !fragmentNavigation && linkIntent ? inline ? page.intentPreloads && indexedPreloads(page.intentPreloads) : {
|
|
1159
1398
|
preloads: "preloads",
|
|
@@ -1260,21 +1499,22 @@ function renderLinkBridgeScript(resumeEntryPath, intentPreloads, documentLoads =
|
|
|
1260
1499
|
if (!r) return;
|
|
1261
1500
|
try { globalThis[Symbol.for('markless.debug.channel.v1.bootstrap')] = ${__marklessDebugBootstrapSource()}(r, 'ssr-inline', false); } catch {}
|
|
1262
1501
|
})();`)}<\/script>` : "";
|
|
1502
|
+
const table = fragment && intentPreloads && Object.keys(intentPreloads).length ? (({ preloads, destinations }) => `<script type="application/json" ${LINK_TABLE_SCRIPT_ATTRIBUTE}>${escapeScriptJson([preloads, destinations])}<\/script>`)(indexedPreloads(intentPreloads)) : "";
|
|
1263
1503
|
const modulePath = modulePaths?.[hashLinks ? 1 : 0];
|
|
1264
1504
|
if (modulePath) {
|
|
1265
1505
|
const indexed = !fragment && intentPreloads ? indexedPreloads(intentPreloads) : void 0;
|
|
1266
|
-
const args =
|
|
1506
|
+
const args = indexed ? [
|
|
1267
1507
|
"0",
|
|
1268
1508
|
escapeScriptJson(indexed.preloads),
|
|
1269
1509
|
escapeScriptJson(indexed.destinations)
|
|
1270
1510
|
] : [];
|
|
1271
|
-
return `${debugBootstrap}<script type="module" ${LINK_BRIDGE_SCRIPT_ATTRIBUTE}>${escapeInlineScript(`import b from${JSON.stringify(modulePath)};b(${args.join(",")})`)}<\/script>`;
|
|
1511
|
+
return `${debugBootstrap}${table}<script type="module" ${LINK_BRIDGE_SCRIPT_ATTRIBUTE}>${escapeInlineScript(`import b from${JSON.stringify(modulePath)};b(${args.join(",")})`)}<\/script>`;
|
|
1272
1512
|
}
|
|
1273
1513
|
const body = linkBridgeBody(resumeEntryPath, intentPreloads !== void 0, documentLoads, fragment, {
|
|
1274
1514
|
intentPreloads,
|
|
1275
1515
|
hashLinks
|
|
1276
1516
|
});
|
|
1277
|
-
return `${debugBootstrap}<script ${LINK_BRIDGE_SCRIPT_ATTRIBUTE}>${escapeInlineScript(`(()=>{const d=document,s=d.currentScript,r=s&&s.closest('[data-async-container]');if(!r)return;${body}
|
|
1517
|
+
return `${debugBootstrap}${table}<script ${LINK_BRIDGE_SCRIPT_ATTRIBUTE}>${escapeInlineScript(`(()=>{const d=document,s=d.currentScript,r=s&&s.closest('[data-async-container]');if(!r)return;${body}
|
|
1278
1518
|
})();`)}<\/script>`;
|
|
1279
1519
|
}
|
|
1280
1520
|
function boundFragmentRun(fragment, documentLoads) {
|
|
@@ -1290,21 +1530,26 @@ function fragmentConfig(fragment, documentLoads) {
|
|
|
1290
1530
|
scrollAttribute: SCROLL_ATTRIBUTE,
|
|
1291
1531
|
routeScriptType: ROUTE_SCRIPT_TYPE,
|
|
1292
1532
|
servedHtmlAttributesProperty: SERVED_HTML_ATTRIBUTES_PROPERTY,
|
|
1533
|
+
servedBodyAttributesProperty: SERVED_BODY_ATTRIBUTES_PROPERTY,
|
|
1293
1534
|
retireProperty: CONTAINER_RETIRE_PROPERTY,
|
|
1294
1535
|
streamExecutorGlobal: STREAM_ARM_EXECUTOR_GLOBAL,
|
|
1295
1536
|
streamedArmSelector: STREAMED_ARM_SELECTOR,
|
|
1537
|
+
streamOpenProperty: PROTOCOL_STREAM_OPEN_PROPERTY,
|
|
1538
|
+
pendingDeadlineMs: MARKLESS_NAV_SETTLE_DEADLINE_MS,
|
|
1296
1539
|
requestPrefix: FRAGMENT_PATH_PREFIX,
|
|
1297
1540
|
regionEndMarker: FRAGMENT_REGION_END,
|
|
1298
1541
|
appendMarker: FRAGMENT_APPEND_END,
|
|
1299
1542
|
pageEndComment: PROTOCOL_CONTAINER_END_COMMENT,
|
|
1300
1543
|
pageStartComment: PROTOCOL_CONTAINER_START_COMMENT,
|
|
1301
1544
|
containerAttributes: [CONTAINER_ATTRIBUTE, PROTOCOL_LOCATOR_PATHS_ATTRIBUTE],
|
|
1545
|
+
keepAttributes: [PROTOCOL_KEEP_ATTRIBUTE, PROTOCOL_OWN_ATTRIBUTE],
|
|
1302
1546
|
documentLoads,
|
|
1303
1547
|
hoverDwellMs: 20,
|
|
1304
1548
|
prefetchTtlMs: FRAGMENT_PREFETCH_TTL_MS,
|
|
1305
1549
|
prefetchConnections: 2,
|
|
1306
1550
|
endpointPrefixes: [API_PATHNAME_PREFIX],
|
|
1307
1551
|
idleFragments: 6,
|
|
1552
|
+
idleFragmentBytes: FRAGMENT_IDLE_FRAGMENT_BYTES,
|
|
1308
1553
|
idleWithoutConnectionInfo: true,
|
|
1309
1554
|
prefetch: fragment.prefetch,
|
|
1310
1555
|
pages: fragment.pages
|
|
@@ -1349,4 +1594,4 @@ function insertImportMap(html, importMap) {
|
|
|
1349
1594
|
return `${html.slice(0, at)}${importMap}${html.slice(at)}`;
|
|
1350
1595
|
}
|
|
1351
1596
|
//#endregion
|
|
1352
|
-
export {
|
|
1597
|
+
export { FRAGMENT_RESPONSE_HEADER as a, documentHandlersMessage as c, FRAGMENT_PATH_PREFIX as i, listenForLinkIntent as l, routerLinkBridgeModules as n, runFragmentNavigation as o, LINK_BRIDGE_DIR as r, startFragmentNavigation as s, createServerEntry as t };
|