@markless/router 0.5.0 → 0.7.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-yboa-2m6.js +1333 -0
- package/dist/index-BjxpxRL7.d.ts +248 -0
- package/dist/index.d.ts +2 -233
- package/dist/index.js +64 -15
- package/dist/request-locals-BDAhNpEa.js +94 -0
- package/dist/route-manifest-DMizh42B.js +456 -0
- package/dist/typescript-plugin.cjs +1 -1
- package/dist/typescript-plugin.js +1 -1
- package/dist/vite/runtime/create-route-discovery.js +1 -1
- package/dist/vite/runtime/create-server-entry.d.ts +16 -0
- package/dist/vite/runtime/create-server-entry.js +2 -658
- package/dist/vite/runtime/mdx-route.d.ts +21 -2
- package/dist/vite/runtime/mdx-route.js +65 -3
- package/dist/vite.js +239 -39
- package/package.json +4 -4
- package/src/vite/entries/fragment-entry.ts +290 -32
- package/dist/fragment-navigation-CIiNnFFc.js +0 -323
- package/dist/link-attributes-nY1Qkmx2.js +0 -7
- package/dist/request-files-Ca8E0FOo.js +0 -233
- package/dist/request-locals-BFPF6Vdm.js +0 -28
- package/dist/route-manifest-Bw_nFohL.js +0 -189
|
@@ -368,9 +368,23 @@ type ProtocolViewPayload = {
|
|
|
368
368
|
* Element children of the parent that stand before the rows. Rows occupy
|
|
369
369
|
* `[rowStartOffset, rowStartOffset + items.length)` among the parent's child
|
|
370
370
|
* elements; a repeat whose rows begin at 0 omits the field. A repeat whose
|
|
371
|
-
* prefix has no compile-time element count
|
|
371
|
+
* prefix has no compile-time element count says `rowEndOffset` instead, or
|
|
372
|
+
* ships no record at all when its suffix has none either.
|
|
372
373
|
*/
|
|
373
374
|
readonly rowStartOffset?: number;
|
|
375
|
+
/**
|
|
376
|
+
* Element children of the parent that stand after the rows, set only when
|
|
377
|
+
* the prefix has no compile-time element count. Rows then occupy the
|
|
378
|
+
* `items.length` element children ending `rowEndOffset` before the last.
|
|
379
|
+
*/
|
|
380
|
+
readonly rowEndOffset?: number;
|
|
381
|
+
/**
|
|
382
|
+
* The browser can never change these rows: the collection and every value a
|
|
383
|
+
* row shows are fixed once the page is served, so the record carries no row
|
|
384
|
+
* markup and resume neither follows the collection nor loads row-building
|
|
385
|
+
* code. Pay-per-use: a repeat whose rows can change omits the field.
|
|
386
|
+
*/
|
|
387
|
+
readonly fixed?: true;
|
|
374
388
|
/**
|
|
375
389
|
* The `@empty` arm's finished markup, for the mint that raises it when the
|
|
376
390
|
* collection empties after resume and takes it back out when a row returns.
|
|
@@ -756,11 +770,13 @@ type RuntimeGraphDelete = {
|
|
|
756
770
|
readonly graphNodeId: string;
|
|
757
771
|
readonly path: ReadonlyArray<string>;
|
|
758
772
|
};
|
|
773
|
+
/** DOM work a subscription holds back until its whole pass has run, so it lands in one task with that pass's journal. */
|
|
774
|
+
type RuntimeGraphCommit = () => void | Promise<void>;
|
|
759
775
|
type RuntimeGraphSubscription = {
|
|
760
776
|
readonly id: string;
|
|
761
777
|
readonly graphNodeId: string;
|
|
762
778
|
readonly path?: ReadonlyArray<string>;
|
|
763
|
-
readonly run: (value: unknown) => DomJournalResult | void | Promise<DomJournalResult | void>;
|
|
779
|
+
readonly run: (value: unknown) => DomJournalResult | RuntimeGraphCommit | void | Promise<DomJournalResult | RuntimeGraphCommit | void>;
|
|
764
780
|
};
|
|
765
781
|
/**
|
|
766
782
|
* Told about a write the moment it lands, before the flush that write schedules.
|
|
@@ -820,6 +836,8 @@ type RuntimeGraph = {
|
|
|
820
836
|
readonly settleWriteObservers?: () => Promise<void> | undefined;
|
|
821
837
|
/** Whether a write is waiting on a flush that has not yet reached the journal. */
|
|
822
838
|
readonly hasPendingFlush?: () => boolean;
|
|
839
|
+
/** Keeps the scheduled flush back until each returned release has run once; `flush()` itself still runs. */
|
|
840
|
+
readonly holdFlush?: () => () => void;
|
|
823
841
|
readonly subscribeJournal: (listener: DomJournalListener) => () => void;
|
|
824
842
|
readonly flush: () => Promise<void>;
|
|
825
843
|
readonly takeJournal: () => DomJournalEntry[];
|
|
@@ -897,6 +915,7 @@ type ResumeDomEvent = {
|
|
|
897
915
|
readonly bubbles?: boolean;
|
|
898
916
|
readonly preventDefault?: () => void;
|
|
899
917
|
readonly stopPropagation?: () => void;
|
|
918
|
+
readonly composedPath?: () => ReadonlyArray<ResumeDomElement>;
|
|
900
919
|
__marklessPressHost?: ResumeDomElement;
|
|
901
920
|
};
|
|
902
921
|
type ResumeSharedPatchEvent = {
|
|
@@ -1,4 +1,64 @@
|
|
|
1
1
|
import { i as protocolStateVersion, n as protocolInstanceQualifies, t as protocolInstancePath } from "../../protocol-constants-B4WxrZAS.js";
|
|
2
|
+
//#endregion
|
|
3
|
+
//#region ../serializer/src/protocol-record-keys.ts
|
|
4
|
+
/** The field names each templated record list may spell, in the order its templates index them. */
|
|
5
|
+
const PROTOCOL_RECORD_KEYS = {
|
|
6
|
+
"markless/state": {
|
|
7
|
+
computed: "graphNodeId name async deriveSymbolId value version root $type $ref source flags records id type fields items entries values bytes arrayType buffer byteOffset length byteLength directValue dependencies path snapshot status key error",
|
|
8
|
+
sharedSeeds: "graphNodeId deriveSymbolId dependencies path reads",
|
|
9
|
+
sharedDefinitions: "id name exportedName scope version graphNodeIds projectionIds dependencies definitionId definitionName returnProperties kind graphNodeId path"
|
|
10
|
+
},
|
|
11
|
+
"markless/view": {
|
|
12
|
+
domUpdates: "hostNodeId source graphNodeId path target kind prefix suffix trueValue falseValue textNode name constantClass leadingClass symbolId",
|
|
13
|
+
behaviors: "hostNodeId source functionSource inputSources inputValues inputGraphReads inputIndex graphNodeId path symbolId usesGraph",
|
|
14
|
+
elementHandles: "hostNodeId handleId name plural"
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
//#endregion
|
|
18
|
+
//#region ../serializer/src/protocol-templated-lists.ts
|
|
19
|
+
/**
|
|
20
|
+
* The record lists a payload script may serve as record templates instead of a plain array. The
|
|
21
|
+
* inline resumer reads the others at page load, before any decoder has loaded, so they stay plain.
|
|
22
|
+
*/
|
|
23
|
+
const PROTOCOL_TEMPLATED_LISTS = {
|
|
24
|
+
"markless/state": [
|
|
25
|
+
"computed",
|
|
26
|
+
"sharedSeeds",
|
|
27
|
+
"sharedDefinitions"
|
|
28
|
+
],
|
|
29
|
+
"markless/view": [
|
|
30
|
+
"domUpdates",
|
|
31
|
+
"behaviors",
|
|
32
|
+
"elementHandles"
|
|
33
|
+
]
|
|
34
|
+
};
|
|
35
|
+
//#endregion
|
|
36
|
+
//#region ../serializer/src/protocol-record-templates.ts
|
|
37
|
+
function expandRecordTemplates(list, keys = "") {
|
|
38
|
+
if (Array.isArray(list)) return list;
|
|
39
|
+
const { t, r } = list;
|
|
40
|
+
const names = keys.split(" ");
|
|
41
|
+
const parts = t.map((text) => text.replace(/~(\d+):/g, (_, at) => `"${names[+at]}":`).split(/\^(\d+)/));
|
|
42
|
+
return r.map((ref) => {
|
|
43
|
+
if (typeof ref === "number") return JSON.parse(parts[ref][0]);
|
|
44
|
+
if (!Array.isArray(ref)) return ref;
|
|
45
|
+
const part = parts[ref[0]];
|
|
46
|
+
let text = part[0];
|
|
47
|
+
for (let at = 1; at < part.length; at += 2) text += ref[+part[at] + 1] + part[at + 1];
|
|
48
|
+
return JSON.parse(text);
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
/** Expands, in place, every templated list of a freshly parsed payload script. */
|
|
52
|
+
function decodeProtocolPayloadLists(type, payload) {
|
|
53
|
+
const record = payload;
|
|
54
|
+
const keys = PROTOCOL_RECORD_KEYS[type];
|
|
55
|
+
if (record) for (const key of PROTOCOL_TEMPLATED_LISTS[type]) {
|
|
56
|
+
const list = record[key];
|
|
57
|
+
if (list && !Array.isArray(list)) record[key] = expandRecordTemplates(list, keys[key]);
|
|
58
|
+
}
|
|
59
|
+
return payload;
|
|
60
|
+
}
|
|
61
|
+
//#endregion
|
|
2
62
|
//#region ../serializer/src/storage-cookie.ts
|
|
3
63
|
const STORAGE_RENDER_CONTEXT_READER = "storageValue";
|
|
4
64
|
//#endregion
|
|
@@ -582,9 +642,11 @@ const marklessDecodeScalarCell = (c, g, s) => {
|
|
|
582
642
|
const marklessFindElementAtDomOrderIndex = (r, i) => {
|
|
583
643
|
let c = r.__marklessCensus;
|
|
584
644
|
if (!c) {
|
|
585
|
-
const w = document.createTreeWalker(r,
|
|
645
|
+
const w = document.createTreeWalker(r, 129);
|
|
586
646
|
c = r.__marklessCensus = r.nodeType === 1 ? [r] : [];
|
|
587
|
-
for (let n; n = w.nextNode();) c.push(n);
|
|
647
|
+
for (let n; n = w.nextNode();) if (n.nodeType !== 8) c.push(n);
|
|
648
|
+
else if (n.data === "markless:page-start") c.length = 1;
|
|
649
|
+
else if (n.data === "markless:page-end") break;
|
|
588
650
|
}
|
|
589
651
|
return c[i];
|
|
590
652
|
};
|
|
@@ -744,7 +806,7 @@ function locate(root, view, host) {
|
|
|
744
806
|
}
|
|
745
807
|
function readScript(root, type) {
|
|
746
808
|
const text = root.querySelector(`script[type="${type}"]`)?.textContent;
|
|
747
|
-
return text ? JSON.parse(text) : void 0;
|
|
809
|
+
return text ? decodeProtocolPayloadLists(type, JSON.parse(text)) : void 0;
|
|
748
810
|
}
|
|
749
811
|
function references(value, id) {
|
|
750
812
|
return value === id || !!value && typeof value === "object" && Object.values(value).some((child) => references(child, id));
|
package/dist/vite.js
CHANGED
|
@@ -1,17 +1,16 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { r as transformRequestFileSource } from "./request-files-Ca8E0FOo.js";
|
|
1
|
+
import { d as REPLACE_ATTRIBUTE, f as SCROLL_ATTRIBUTE, l as LINK_ATTRIBUTE, u as PREFETCH_ATTRIBUTE } from "./request-locals-BDAhNpEa.js";
|
|
2
|
+
import { i as matchRouteManifest, l as transformRequestFileSource, n as buildRouteManifestFromFileIds, o as normalizeRouteFileId, r as isPageModuleFile, t as assertNoEndpointConflicts } from "./route-manifest-DMizh42B.js";
|
|
4
3
|
import { t as __marklessRouteHref } from "./route-href-CGooO_g6.js";
|
|
5
4
|
import { r as protocolIslandSegment } from "./protocol-constants-B4WxrZAS.js";
|
|
6
|
-
import { a as startFragmentNavigation, s as listenForLinkIntent } from "./
|
|
5
|
+
import { a as runFragmentNavigation, i as FRAGMENT_PATH_PREFIX, n as routerLinkBridgeModules, o as startFragmentNavigation, s as listenForLinkIntent } from "./create-server-entry-yboa-2m6.js";
|
|
7
6
|
import { dirname, extname, isAbsolute, join, normalize, relative, resolve } from "pathe";
|
|
8
|
-
import { decodePath, joinURL, parsePath, parseQuery, parseURL, stringifyQuery, withLeadingSlash, withQuery, withoutLeadingSlash } from "ufo";
|
|
9
|
-
import { existsSync } from "node:fs";
|
|
7
|
+
import { decodePath, joinURL, parsePath, parseQuery, parseURL, stringifyQuery, withLeadingSlash, withQuery, withoutBase, withoutLeadingSlash } from "ufo";
|
|
8
|
+
import { existsSync, readdirSync } from "node:fs";
|
|
10
9
|
import { mkdir, readFile, rename, rm, stat, writeFile } from "node:fs/promises";
|
|
11
10
|
import { nitro } from "nitro/vite";
|
|
12
11
|
import { minifySync, sortUserPlugins } from "vite";
|
|
13
|
-
import { isClientPrimarySourceRequest, isExecutionLogChunk, isMarklessNavigationPack, isRenderDataSourceRequest, isResumeSourceRequest, isRouteNavigationSourceRequest, isSymbolOnlySourceRequest, lazyStartupPackName, marklessDeferredChunkFileNames, optimizedDepsToInclude, plannedLandingFiles, startupPackOfLazy, symbolVirtualModuleSourceFile } from "@markless/bundler/preload";
|
|
14
|
-
import {
|
|
12
|
+
import { isClientPrimarySourceRequest, isExecutionLogChunk, isMarklessNavigationPack, isRenderDataSourceRequest, isResumeSourceRequest, isRouteNavigationSourceRequest, isSymbolOnlySourceRequest, lazyStartupPackName, marklessDeferredChunkFileNames, optimizedDepsToInclude, plannedLandingFiles, resolverVirtualModuleSourceFile, startupPackOfLazy, symbolVirtualModuleSourceFile, warmEvaluatedImports } from "@markless/bundler/preload";
|
|
13
|
+
import { MARKLESS_BUILD_PREFIX, MARKLESS_CHUNK_SPECIFIER_PREFIX, MARKLESS_IMPORT_MAP_ASSET, MARKLESS_PUBLIC_BUILD_METADATA_FILES, importMapScript, marklessBuildManifestDir } from "@markless/bundler/rolldown";
|
|
15
14
|
import { parseModule } from "@tsrx/yuku";
|
|
16
15
|
import { toHtml } from "hast-util-to-html";
|
|
17
16
|
import { HastReader, createMdxHastHandle, defineHastPlugin, dropHandle, materializeHastTree, resolveHastSubscriptions, serializeHandle, visitHastHandle } from "satteri";
|
|
@@ -119,6 +118,7 @@ function createLinkTypes() {
|
|
|
119
118
|
//#endregion
|
|
120
119
|
//#region src/vite/route-typegen.ts
|
|
121
120
|
const PAGE_EXTENSIONS = /* @__PURE__ */ new Set([".tsrx", ".mdx"]);
|
|
121
|
+
const ENDPOINT_EXTENSIONS = /* @__PURE__ */ new Set([".ts"]);
|
|
122
122
|
function routeTypegenPlugin() {
|
|
123
123
|
let root = "";
|
|
124
124
|
return {
|
|
@@ -137,26 +137,25 @@ function routeTypegenPlugin() {
|
|
|
137
137
|
async function writeRouteTypes(fs, root) {
|
|
138
138
|
const pageFiles = await discoverPageFiles(fs, root);
|
|
139
139
|
const manifest = buildRouteManifestFromFileIds(pageFiles);
|
|
140
|
+
assertNoEndpointConflicts(manifest, await discoverFiles(fs, root, "api", ENDPOINT_EXTENSIONS));
|
|
140
141
|
await writeIfChanged(fs, join(root, routeTypesEnvPath), routeTypesEnvDeclaration);
|
|
141
142
|
await writeIfChanged(fs, join(root, routeTypesOutputPath), createRouteTypesDeclaration(manifest));
|
|
142
143
|
}
|
|
143
|
-
|
|
144
|
-
|
|
144
|
+
function discoverPageFiles(fs, root) {
|
|
145
|
+
return discoverFiles(fs, root, "pages", PAGE_EXTENSIONS);
|
|
146
|
+
}
|
|
147
|
+
async function discoverFiles(fs, root, dir, extensions) {
|
|
145
148
|
const files = [];
|
|
146
|
-
await
|
|
149
|
+
await collectFiles(fs, root, join(root, dir), extensions, files);
|
|
147
150
|
return files.toSorted((left, right) => left.localeCompare(right));
|
|
148
151
|
}
|
|
149
|
-
async function
|
|
152
|
+
async function collectFiles(fs, root, dir, extensions, files) {
|
|
150
153
|
const entries = await readdirIfExists(fs, dir);
|
|
151
|
-
await Promise.all(entries.map((entry) =>
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
await collectPageFiles(fs, root, path, files);
|
|
157
|
-
return;
|
|
158
|
-
}
|
|
159
|
-
if (entry.isFile() && PAGE_EXTENSIONS.has(extname(path))) files.push(withLeadingSlash(relative(root, path)));
|
|
154
|
+
await Promise.all(entries.map(async (entry) => {
|
|
155
|
+
const path = join(dir, entry.name);
|
|
156
|
+
if (entry.isDirectory()) await collectFiles(fs, root, path, extensions, files);
|
|
157
|
+
else if (entry.isFile() && extensions.has(extname(path))) files.push(withLeadingSlash(relative(root, path)));
|
|
158
|
+
}));
|
|
160
159
|
}
|
|
161
160
|
async function readdirIfExists(fs, dir) {
|
|
162
161
|
try {
|
|
@@ -513,7 +512,8 @@ function createClientAssetsManifest(input) {
|
|
|
513
512
|
resume: input.resumeEntry,
|
|
514
513
|
...input.prerenderWakeEntry ? { prerenderWake: input.prerenderWakeEntry } : {},
|
|
515
514
|
navigation: input.navigationEntry,
|
|
516
|
-
...input.fragmentEntry ? { fragment: input.fragmentEntry } : {}
|
|
515
|
+
...input.fragmentEntry ? { fragment: input.fragmentEntry } : {},
|
|
516
|
+
...input.fragmentImports?.length ? { fragmentImports: input.fragmentImports } : {}
|
|
517
517
|
},
|
|
518
518
|
routes: {
|
|
519
519
|
navigation: sortRouteMap(input.routes.navigation),
|
|
@@ -602,7 +602,8 @@ async function validateClientAssetsManifest(input, base, clientOutDir) {
|
|
|
602
602
|
resume: requiredString(input.entries.resume, "entries.resume"),
|
|
603
603
|
...input.entries.prerenderWake !== void 0 ? { prerenderWake: requiredString(input.entries.prerenderWake, "entries.prerenderWake") } : {},
|
|
604
604
|
navigation: requiredString(input.entries.navigation, "entries.navigation"),
|
|
605
|
-
...input.entries.fragment !== void 0 ? { fragment: requiredString(input.entries.fragment, "entries.fragment") } : {}
|
|
605
|
+
...input.entries.fragment !== void 0 ? { fragment: requiredString(input.entries.fragment, "entries.fragment") } : {},
|
|
606
|
+
...input.entries.fragmentImports !== void 0 ? { fragmentImports: requiredStrings(input.entries.fragmentImports, "entries.fragmentImports") } : {}
|
|
606
607
|
};
|
|
607
608
|
const routes = {
|
|
608
609
|
navigation: routeMap(input.routes.navigation, "routes.navigation"),
|
|
@@ -616,6 +617,7 @@ async function validateClientAssetsManifest(input, base, clientOutDir) {
|
|
|
616
617
|
...entries.prerenderWake !== void 0 ? [entries.prerenderWake] : [],
|
|
617
618
|
entries.navigation,
|
|
618
619
|
...entries.fragment !== void 0 ? [entries.fragment] : [],
|
|
620
|
+
...entries.fragmentImports ?? [],
|
|
619
621
|
...Object.values(routes.navigation).flat(),
|
|
620
622
|
...Object.values(routes.ssr).flat(),
|
|
621
623
|
...Object.values(routes.styles).flat(),
|
|
@@ -640,6 +642,10 @@ async function validateClientAssetsManifest(input, base, clientOutDir) {
|
|
|
640
642
|
...importMap ? { importMap } : {}
|
|
641
643
|
};
|
|
642
644
|
}
|
|
645
|
+
function requiredStrings(input, label) {
|
|
646
|
+
if (!Array.isArray(input)) throw clientAssetsManifestError(`has invalid ${label}`);
|
|
647
|
+
return input.map((item, index) => requiredString(item, `${label}[${index}]`));
|
|
648
|
+
}
|
|
643
649
|
function routeMap(input, label) {
|
|
644
650
|
if (!isRecord$1(input)) throw clientAssetsManifestError(`has invalid ${label}`);
|
|
645
651
|
const routes = {};
|
|
@@ -840,7 +846,7 @@ function emitQueuedResumeContainerEvent(source, { censusRepair = true } = {}) {
|
|
|
840
846
|
" const root = input.root;",
|
|
841
847
|
censusRepair ? " if (root.__marklessShifted) return import('@markless/web/fns/served-census-repair').then((census) => (census.marklessRepairCensus(root), resumeContainerEvent(input)));" : "",
|
|
842
848
|
" if (!root.__marklessDispatch) {",
|
|
843
|
-
" let handler = marklessResumeContainerEvent, tail = Promise.resolve(), done = tail, lastEvent = null, lastEventTime = undefined;",
|
|
849
|
+
" let handler = marklessResumeContainerEvent, tail = Promise.resolve(), done = tail, lastEvent = null, lastEventTime = undefined, seen = new WeakMap();",
|
|
844
850
|
" root.__marklessRegisterDispatch = next => {",
|
|
845
851
|
" const fallback = handler;",
|
|
846
852
|
" handler = input => next(input, fallback);",
|
|
@@ -848,7 +854,8 @@ function emitQueuedResumeContainerEvent(source, { censusRepair = true } = {}) {
|
|
|
848
854
|
" root.__marklessDispatch = next => {",
|
|
849
855
|
" const event = next.event, eventTime = event?.timeStamp;",
|
|
850
856
|
" if (event && next.eventRecord && next.element) event.__marklessPressHost ??= next.element;",
|
|
851
|
-
" if (event === lastEvent && eventTime === lastEventTime) return done;",
|
|
857
|
+
" if ((event === lastEvent && eventTime === lastEventTime) || (seen.has(event) && seen.get(event) === eventTime)) return done;",
|
|
858
|
+
" if (Object(event) === event) seen.set(event, eventTime);",
|
|
852
859
|
" lastEvent = event;",
|
|
853
860
|
" lastEventTime = eventTime;",
|
|
854
861
|
" let release;",
|
|
@@ -1444,6 +1451,63 @@ function nodes(value) {
|
|
|
1444
1451
|
return Array.isArray(value) ? value.filter((item) => node(item)) : [];
|
|
1445
1452
|
}
|
|
1446
1453
|
//#endregion
|
|
1454
|
+
//#region src/vite/nitro-fragment-requests.ts
|
|
1455
|
+
function fragmentRequestModule() {
|
|
1456
|
+
return {
|
|
1457
|
+
name: "markless-router:fragment-requests",
|
|
1458
|
+
async setup(nitro) {
|
|
1459
|
+
const dir = join(nitro.options.buildDir, "markless-router");
|
|
1460
|
+
const plugin = join(dir, "fragment-requests.mjs");
|
|
1461
|
+
await mkdir(dir, { recursive: true });
|
|
1462
|
+
await writeFile(plugin, [
|
|
1463
|
+
`const prefix = ${JSON.stringify(`${FRAGMENT_PATH_PREFIX}/`)};`,
|
|
1464
|
+
"export default function fragmentRequests(nitroApp) {",
|
|
1465
|
+
" nitroApp.hooks?.hook('request', (event) => {",
|
|
1466
|
+
" const { pathname } = event.url;",
|
|
1467
|
+
" if (!pathname.startsWith(prefix)) return;",
|
|
1468
|
+
" const page = new URL(event.url.href);",
|
|
1469
|
+
" page.pathname = pathname.slice(prefix.length - 1);",
|
|
1470
|
+
" event.url = page;",
|
|
1471
|
+
" });",
|
|
1472
|
+
"}",
|
|
1473
|
+
""
|
|
1474
|
+
].join("\n"));
|
|
1475
|
+
nitro.options.plugins.push(plugin);
|
|
1476
|
+
}
|
|
1477
|
+
};
|
|
1478
|
+
}
|
|
1479
|
+
//#endregion
|
|
1480
|
+
//#region src/vite/nitro-prerender.ts
|
|
1481
|
+
function serverBuildState() {
|
|
1482
|
+
return { entry: void 0 };
|
|
1483
|
+
}
|
|
1484
|
+
function recordServerEntry(state, outDir, bundle, isServerEntry) {
|
|
1485
|
+
if (!outDir) return;
|
|
1486
|
+
const entries = Object.values(bundle).filter((item) => item.type === "chunk" && item.isEntry);
|
|
1487
|
+
const entry = entries.find((chunk) => chunk.facadeModuleId && isServerEntry(chunk.facadeModuleId)) ?? (entries.length === 1 ? entries[0] : void 0);
|
|
1488
|
+
if (entry) state.entry = resolve(outDir, entry.fileName);
|
|
1489
|
+
}
|
|
1490
|
+
function prerenderRendererModule(state) {
|
|
1491
|
+
return {
|
|
1492
|
+
name: "markless-router:prerender-renderer",
|
|
1493
|
+
setup(nitro) {
|
|
1494
|
+
nitro.hooks.hook("prerender:config", async (config) => {
|
|
1495
|
+
if (!state.entry) return;
|
|
1496
|
+
const dir = join(nitro.options.buildDir, "markless-router");
|
|
1497
|
+
const handler = join(dir, "prerender-renderer.mjs");
|
|
1498
|
+
await mkdir(dir, { recursive: true });
|
|
1499
|
+
await writeFile(handler, [
|
|
1500
|
+
`import * as service from ${JSON.stringify(state.entry)};`,
|
|
1501
|
+
"const server = service.default ?? service;",
|
|
1502
|
+
"export default ({ req }) => server.fetch(req);",
|
|
1503
|
+
""
|
|
1504
|
+
].join("\n"));
|
|
1505
|
+
config.renderer = { handler };
|
|
1506
|
+
});
|
|
1507
|
+
}
|
|
1508
|
+
};
|
|
1509
|
+
}
|
|
1510
|
+
//#endregion
|
|
1447
1511
|
//#region src/vite/index.ts
|
|
1448
1512
|
const PAGE_SERVER_ONLY_PROPS = [{
|
|
1449
1513
|
exportName: "default",
|
|
@@ -1467,6 +1531,7 @@ const FRAGMENT_ENTRY_PATH_ID = "virtual:markless-router/fragment-entry-path";
|
|
|
1467
1531
|
const ROUTE_PRELOADS_ID = "virtual:markless-router/route-preloads";
|
|
1468
1532
|
const ROUTE_PRELOADS_PLACEHOLDER = "__MARKLESS_ROUTER_ROUTE_PRELOADS__";
|
|
1469
1533
|
const DOCUMENT_STYLESHEETS_PLACEHOLDER = "__MARKLESS_ROUTER_DOCUMENT_STYLESHEETS__";
|
|
1534
|
+
const LINK_BRIDGE_PATHS_PLACEHOLDER = "__MARKLESS_ROUTER_LINK_BRIDGE_PATHS__";
|
|
1470
1535
|
const SERVER_ENTRY_ID = "virtual:markless-router/server-entry";
|
|
1471
1536
|
const ROUTE_HREF_ID = "virtual:markless-router/route-href";
|
|
1472
1537
|
const ROUTER_OPTIONS_ID = "virtual:markless-router/options";
|
|
@@ -1507,8 +1572,9 @@ function router(options = {}) {
|
|
|
1507
1572
|
const fragmentEntry = resumeEntryState();
|
|
1508
1573
|
const routePreloads = routePreloadState();
|
|
1509
1574
|
return [
|
|
1510
|
-
routerConfigPlugin(nitroPlugins, resumeEntry, prerenderWakeEntry, navigationEntry, routePreloads, fragmentEntry),
|
|
1575
|
+
routerConfigPlugin(nitroPlugins, resumeEntry, prerenderWakeEntry, navigationEntry, routePreloads, fragmentEntry, serverBuildState()),
|
|
1511
1576
|
devSourceModuleRequestPlugin(),
|
|
1577
|
+
devPageForUrlPlugin(options),
|
|
1512
1578
|
pageServerOnlyPropsPlugin(),
|
|
1513
1579
|
mdxTransformPlugin(),
|
|
1514
1580
|
requestFileTransformPlugin(),
|
|
@@ -1516,6 +1582,7 @@ function router(options = {}) {
|
|
|
1516
1582
|
anchorTransformPlugin(),
|
|
1517
1583
|
htmlTransformPlugin(),
|
|
1518
1584
|
virtualModulesPlugin(resumeEntry, prerenderWakeEntry, navigationEntry, routePreloads, options, fragmentEntry),
|
|
1585
|
+
linkBridgeFilesPlugin(navigationEntry, fragmentEntry, options),
|
|
1519
1586
|
nitroPlugins
|
|
1520
1587
|
];
|
|
1521
1588
|
}
|
|
@@ -1523,10 +1590,43 @@ function pageServerOnlyPropsPlugin() {
|
|
|
1523
1590
|
return {
|
|
1524
1591
|
name: "markless-router:page-server-only-props",
|
|
1525
1592
|
configResolved(config) {
|
|
1526
|
-
config.plugins.find((plugin) => typeof plugin.api?.declareServerOnlyProps === "function")
|
|
1593
|
+
const markless = config.plugins.find((plugin) => typeof plugin.api?.declareServerOnlyProps === "function");
|
|
1594
|
+
markless?.api.declareServerOnlyProps((moduleId) => isPageModuleFile(normalizeRouteFileId(moduleId)) ? PAGE_SERVER_ONLY_PROPS : void 0);
|
|
1595
|
+
markless?.api.declareRouteModules?.((moduleId) => isPageModuleFile(normalizeRouteFileId(moduleId)));
|
|
1596
|
+
}
|
|
1597
|
+
};
|
|
1598
|
+
}
|
|
1599
|
+
function devPageForUrlPlugin(options) {
|
|
1600
|
+
return {
|
|
1601
|
+
name: "markless-router:dev-page-for-url",
|
|
1602
|
+
apply: "serve",
|
|
1603
|
+
configResolved(config) {
|
|
1604
|
+
config.plugins.find((plugin) => typeof plugin.api?.declarePageForUrl === "function")?.api.declarePageForUrl((href) => devPageForUrl(config.root, config.base, options.mode, href));
|
|
1527
1605
|
}
|
|
1528
1606
|
};
|
|
1529
1607
|
}
|
|
1608
|
+
function devPageForUrl(root, base, mode, href) {
|
|
1609
|
+
let url;
|
|
1610
|
+
try {
|
|
1611
|
+
url = new URL(href);
|
|
1612
|
+
} catch {
|
|
1613
|
+
return;
|
|
1614
|
+
}
|
|
1615
|
+
const pagesDir = join(root, "pages");
|
|
1616
|
+
if (!existsSync(pagesDir)) return void 0;
|
|
1617
|
+
const fileIds = readdirSync(pagesDir, {
|
|
1618
|
+
recursive: true,
|
|
1619
|
+
encoding: "utf8"
|
|
1620
|
+
}).map((file) => join("pages", file));
|
|
1621
|
+
let manifest;
|
|
1622
|
+
try {
|
|
1623
|
+
manifest = buildRouteManifestFromFileIds(fileIds);
|
|
1624
|
+
} catch {
|
|
1625
|
+
return;
|
|
1626
|
+
}
|
|
1627
|
+
const pathname = mode === "hash" && url.hash.startsWith("#/") ? url.hash.slice(1) : withoutBase(url.pathname, base);
|
|
1628
|
+
return matchRouteManifest(pathname, manifest)?.route.file ?? manifest.statusPages.notFound;
|
|
1629
|
+
}
|
|
1530
1630
|
function devSourceModuleRequestPlugin() {
|
|
1531
1631
|
let root = "";
|
|
1532
1632
|
return {
|
|
@@ -1547,7 +1647,7 @@ function devSourceModuleRequestPlugin() {
|
|
|
1547
1647
|
}
|
|
1548
1648
|
};
|
|
1549
1649
|
}
|
|
1550
|
-
function routerConfigPlugin(nitroPluginsFromRouter, resumeEntry, prerenderWakeEntry, navigationEntry, routePreloads, fragmentEntry = resumeEntryState()) {
|
|
1650
|
+
function routerConfigPlugin(nitroPluginsFromRouter, resumeEntry, prerenderWakeEntry, navigationEntry, routePreloads, fragmentEntry = resumeEntryState(), serverBuild = serverBuildState()) {
|
|
1551
1651
|
let clientOutDir = "";
|
|
1552
1652
|
let clientEnvironmentName = "";
|
|
1553
1653
|
let clientEnvironmentConfig;
|
|
@@ -1581,7 +1681,7 @@ function routerConfigPlugin(nitroPluginsFromRouter, resumeEntry, prerenderWakeEn
|
|
|
1581
1681
|
ssrEnvironment.build.rolldownOptions.input ??= scopedVirtualEntryId(SERVER_ENTRY_ID, config.root);
|
|
1582
1682
|
const serverWatch = withWatchIgnores(config.server?.watch);
|
|
1583
1683
|
return {
|
|
1584
|
-
nitro: createNitroConfig(config.nitro, config.root, serverWatch.ignored, env?.command === "build"),
|
|
1684
|
+
nitro: createNitroConfig(config.nitro, config.root, serverWatch.ignored, env?.command === "build", serverBuild),
|
|
1585
1685
|
server: {
|
|
1586
1686
|
...config.server,
|
|
1587
1687
|
watch: serverWatch
|
|
@@ -1642,6 +1742,7 @@ function routerConfigPlugin(nitroPluginsFromRouter, resumeEntry, prerenderWakeEn
|
|
|
1642
1742
|
prerenderWakeEntry.fileName = manifest.entries.prerenderWake ? clientAssetFileName(manifest.entries.prerenderWake, manifest.base) : void 0;
|
|
1643
1743
|
navigationEntry.fileName = clientAssetFileName(manifest.entries.navigation, manifest.base);
|
|
1644
1744
|
fragmentEntry.fileName = manifest.entries.fragment ? clientAssetFileName(manifest.entries.fragment, manifest.base) : void 0;
|
|
1745
|
+
fragmentEntry.imports = manifest.entries.fragmentImports;
|
|
1645
1746
|
routePreloads.routes = manifest.routes;
|
|
1646
1747
|
routePreloads.persisted = true;
|
|
1647
1748
|
routePreloads.importMap = manifest.importMap;
|
|
@@ -1660,7 +1761,17 @@ function routerConfigPlugin(nitroPluginsFromRouter, resumeEntry, prerenderWakeEn
|
|
|
1660
1761
|
const navigationChunk = Object.values(bundle).find((item) => item.type === "chunk" && isVirtualEntryChunk(item, NAVIGATION_ENTRY_ORIGIN));
|
|
1661
1762
|
if (navigationChunk) navigationEntry.fileName = navigationChunk.fileName;
|
|
1662
1763
|
const fragmentChunk = Object.values(bundle).find((item) => item.type === "chunk" && isVirtualEntryChunk(item, FRAGMENT_ENTRY_ORIGIN));
|
|
1663
|
-
if (fragmentChunk)
|
|
1764
|
+
if (fragmentChunk) {
|
|
1765
|
+
fragmentEntry.fileName = fragmentChunk.fileName;
|
|
1766
|
+
const everyChunk = new Map(outputChunks(bundle).map((chunk) => [chunk.fileName, chunk]));
|
|
1767
|
+
const closure = /* @__PURE__ */ new Set();
|
|
1768
|
+
includeChunk(closure, {
|
|
1769
|
+
chunks: everyChunk,
|
|
1770
|
+
everyChunk
|
|
1771
|
+
}, fragmentChunk.fileName);
|
|
1772
|
+
closure.delete(fragmentChunk.fileName);
|
|
1773
|
+
fragmentEntry.imports = [...closure].map((fileName) => joinURL(routePreloads.base, fileName));
|
|
1774
|
+
}
|
|
1664
1775
|
routePreloads.routes = routeModulePreloadsFromBundle({
|
|
1665
1776
|
base: routePreloads.base,
|
|
1666
1777
|
bundle,
|
|
@@ -1680,15 +1791,19 @@ function routerConfigPlugin(nitroPluginsFromRouter, resumeEntry, prerenderWakeEn
|
|
|
1680
1791
|
resumeEntry: joinURL(routePreloads.base, resumeEntry.fileName),
|
|
1681
1792
|
...prerenderWakeEntry.fileName ? { prerenderWakeEntry: joinURL(routePreloads.base, prerenderWakeEntry.fileName) } : {},
|
|
1682
1793
|
navigationEntry: joinURL(routePreloads.base, navigationEntry.fileName),
|
|
1683
|
-
...fragmentEntry.fileName ? {
|
|
1794
|
+
...fragmentEntry.fileName ? {
|
|
1795
|
+
fragmentEntry: joinURL(routePreloads.base, fragmentEntry.fileName),
|
|
1796
|
+
fragmentImports: fragmentEntry.imports
|
|
1797
|
+
} : {},
|
|
1684
1798
|
routes: routePreloads.routes
|
|
1685
1799
|
});
|
|
1686
1800
|
}
|
|
1687
1801
|
}
|
|
1688
1802
|
},
|
|
1689
|
-
async writeBundle(
|
|
1803
|
+
async writeBundle(options, bundle) {
|
|
1690
1804
|
const environment = this.environment;
|
|
1691
1805
|
const isClientEnvironment = environment?.name ? environment.name === clientEnvironmentName : environment?.config === clientEnvironmentConfig;
|
|
1806
|
+
if (productionBuild && environment?.name === "ssr") recordServerEntry(serverBuild, options.dir, bundle, (id) => id.startsWith(`\0${SERVER_ENTRY_ID}`));
|
|
1692
1807
|
if (!productionBuild || !isClientEnvironment) return;
|
|
1693
1808
|
if (!pendingClientAssets) throw new Error("Markless Router client build finished without a client-assets manifest.");
|
|
1694
1809
|
const renames = bundle ? chunkRenamesSince(capturedChunkNames, bundle) : /* @__PURE__ */ new Map();
|
|
@@ -1701,6 +1816,7 @@ function routerConfigPlugin(nitroPluginsFromRouter, resumeEntry, prerenderWakeEn
|
|
|
1701
1816
|
navigationEntry,
|
|
1702
1817
|
fragmentEntry
|
|
1703
1818
|
]) if (entry.fileName) entry.fileName = renames.get(entry.fileName) ?? entry.fileName;
|
|
1819
|
+
fragmentEntry.imports = pendingClientAssets.entries.fragmentImports;
|
|
1704
1820
|
}
|
|
1705
1821
|
const importMap = bundle?.[MARKLESS_IMPORT_MAP_ASSET];
|
|
1706
1822
|
if (importMap?.type === "asset") pendingClientAssets = {
|
|
@@ -1744,6 +1860,7 @@ function requestFileIdForTransform(root, id) {
|
|
|
1744
1860
|
if (!isAbsolute(pathname)) return;
|
|
1745
1861
|
const relativeFileId = root ? withoutLeadingSlash(normalize(relative(root, pathname))) : withoutLeadingSlash(normalize(pathname));
|
|
1746
1862
|
if (relativeFileId.startsWith("api/") || relativeFileId.startsWith("middleware/")) return relativeFileId;
|
|
1863
|
+
if (relativeFileId.startsWith("pages/")) return void 0;
|
|
1747
1864
|
return relativeFileId.match(/(?:^|\/)((?:api|middleware)\/.+\.ts)$/)?.[1];
|
|
1748
1865
|
}
|
|
1749
1866
|
function requestFileBuildTransformPlugin(root) {
|
|
@@ -1760,7 +1877,7 @@ function requestFileBuildTransformPlugin(root) {
|
|
|
1760
1877
|
}
|
|
1761
1878
|
};
|
|
1762
1879
|
}
|
|
1763
|
-
function createNitroConfig(nitroConfig, root = ".", serverWatchIgnored = [], isBuild = false) {
|
|
1880
|
+
function createNitroConfig(nitroConfig, root = ".", serverWatchIgnored = [], isBuild = false, serverBuild = serverBuildState()) {
|
|
1764
1881
|
const scanDirs = Array.isArray(nitroConfig?.scanDirs) ? nitroConfig.scanDirs.filter((dir) => typeof dir === "string") : [];
|
|
1765
1882
|
const watchOptions = withWatchIgnores(nitroConfig?.watchOptions, serverWatchIgnored);
|
|
1766
1883
|
const publicAssets = Array.isArray(nitroConfig?.publicAssets) ? nitroConfig.publicAssets : [];
|
|
@@ -1780,9 +1897,15 @@ function createNitroConfig(nitroConfig, root = ".", serverWatchIgnored = [], isB
|
|
|
1780
1897
|
...publicAssets
|
|
1781
1898
|
],
|
|
1782
1899
|
routesDir: nitroConfig?.routesDir ?? ".output/markless/router/nitro-routes",
|
|
1900
|
+
modules: [
|
|
1901
|
+
...nitroConfig?.modules ?? [],
|
|
1902
|
+
fragmentRequestModule(),
|
|
1903
|
+
...isBuild ? [prerenderRendererModule(serverBuild)] : []
|
|
1904
|
+
],
|
|
1783
1905
|
...isBuild && { routeRules: {
|
|
1784
1906
|
[`/${MARKLESS_BUILD_PREFIX}**`]: { headers: { "cache-control": "public, max-age=31536000, immutable" } },
|
|
1785
|
-
|
|
1907
|
+
[`/_markless/links/**`]: { headers: { "cache-control": "public, max-age=31536000, immutable" } },
|
|
1908
|
+
...Object.fromEntries(MARKLESS_PUBLIC_BUILD_METADATA_FILES.map((file) => [`/${file}`, { headers: { "cache-control": "public, max-age=0, must-revalidate" } }])),
|
|
1786
1909
|
...nitroConfig?.routeRules
|
|
1787
1910
|
} },
|
|
1788
1911
|
rolldownConfig: withRequestFileBuildPlugin(nitroConfig?.rolldownConfig, root),
|
|
@@ -1935,8 +2058,75 @@ function linkIntentEnabled(options) {
|
|
|
1935
2058
|
return options.prefetch !== false;
|
|
1936
2059
|
}
|
|
1937
2060
|
function entryPathSource(exportName, entry, entryId, root) {
|
|
1938
|
-
const
|
|
1939
|
-
|
|
2061
|
+
return `export const ${exportName} = ${JSON.stringify(entryPath(entry, entryId, root))};`;
|
|
2062
|
+
}
|
|
2063
|
+
function entryPath(entry, entryId, root) {
|
|
2064
|
+
return entry.fileName ? joinURL(entry.base, entry.fileName) : joinURL(entry.base, "@id", scopedVirtualEntryId(entryId, root));
|
|
2065
|
+
}
|
|
2066
|
+
function linkBridgeFilesPlugin(navigationEntry, fragmentEntry, options) {
|
|
2067
|
+
let root = "";
|
|
2068
|
+
let base = "/";
|
|
2069
|
+
let clientOutDir = "";
|
|
2070
|
+
let debug = false;
|
|
2071
|
+
let modules = [];
|
|
2072
|
+
return {
|
|
2073
|
+
name: "markless-router:link-bridge-files",
|
|
2074
|
+
apply: "build",
|
|
2075
|
+
sharedDuringBuild: true,
|
|
2076
|
+
configResolved(config) {
|
|
2077
|
+
root = config.root;
|
|
2078
|
+
base = config.base;
|
|
2079
|
+
debug = config.define?.__MARKLESS_DEBUG_ENABLED__ === "true";
|
|
2080
|
+
const client = Object.values(config.environments).find((environment) => environment.consumer === "client");
|
|
2081
|
+
if (client) clientOutDir = resolve(config.root, client.build.outDir);
|
|
2082
|
+
},
|
|
2083
|
+
generateBundle: {
|
|
2084
|
+
order: "post",
|
|
2085
|
+
async handler(_options, bundle) {
|
|
2086
|
+
if (this.environment?.name !== "ssr") return;
|
|
2087
|
+
const chunks = outputChunks(bundle);
|
|
2088
|
+
const target = chunks.find((chunk) => chunk.code?.includes(LINK_BRIDGE_PATHS_PLACEHOLDER));
|
|
2089
|
+
if (!target) return;
|
|
2090
|
+
if (!navigationEntry.fileName) throw new Error("Markless Router built its server entry before its navigation entry.");
|
|
2091
|
+
const documentFile = join(root, "document.tsrx");
|
|
2092
|
+
const documentSource = await readFile(documentFile, "utf8").catch(() => void 0);
|
|
2093
|
+
const built = routerLinkBridgeModules({
|
|
2094
|
+
base,
|
|
2095
|
+
navigationEntryPath: entryPath(navigationEntry, NAVIGATION_ENTRY_ID, root),
|
|
2096
|
+
fragmentEntryPath: entryPath(fragmentEntry, FRAGMENT_ENTRY_ID, root),
|
|
2097
|
+
fragmentEntryImports: fragmentEntry.imports,
|
|
2098
|
+
fragmentNavigationSource: minifiedFragmentNavigationSource(),
|
|
2099
|
+
fragmentNavigationRunSource: minifiedFragmentNavigationSource(runFragmentNavigation),
|
|
2100
|
+
prefetch: options.prefetch,
|
|
2101
|
+
documentNavigation: documentNavigationFor(documentSource, documentFile),
|
|
2102
|
+
routeFileIds: bundledPageFileIds(chunks, root),
|
|
2103
|
+
debug
|
|
2104
|
+
});
|
|
2105
|
+
modules = built;
|
|
2106
|
+
target.code = target.code.replace(LINK_BRIDGE_PATHS_PLACEHOLDER, jsStringLiteralContent(JSON.stringify(built.slice(0, 2).map((module) => module.path))));
|
|
2107
|
+
}
|
|
2108
|
+
},
|
|
2109
|
+
async writeBundle() {
|
|
2110
|
+
if (this.environment?.name !== "ssr" || modules.length === 0) return;
|
|
2111
|
+
const prefix = base.replace(/\/?$/, "/");
|
|
2112
|
+
for (const module of modules) {
|
|
2113
|
+
const file = join(clientOutDir, module.path.slice(prefix.length));
|
|
2114
|
+
await mkdir(dirname(file), { recursive: true });
|
|
2115
|
+
await writeFile(file, module.source, "utf8");
|
|
2116
|
+
}
|
|
2117
|
+
}
|
|
2118
|
+
};
|
|
2119
|
+
}
|
|
2120
|
+
function bundledPageFileIds(chunks, root) {
|
|
2121
|
+
const files = /* @__PURE__ */ new Set();
|
|
2122
|
+
for (const chunk of chunks) for (const id of chunk.moduleIds ?? []) {
|
|
2123
|
+
if (id.startsWith("\0")) continue;
|
|
2124
|
+
const pathname = decodePath(parseURL(id).pathname);
|
|
2125
|
+
if (!isAbsolute(pathname)) continue;
|
|
2126
|
+
const file = normalizeRouteFileId(relative(root, pathname));
|
|
2127
|
+
if (isPageModuleFile(file)) files.add(file);
|
|
2128
|
+
}
|
|
2129
|
+
return [...files];
|
|
1940
2130
|
}
|
|
1941
2131
|
function serverEntrySource(root, options) {
|
|
1942
2132
|
const query = rootScopeQuery(root);
|
|
@@ -1950,14 +2140,17 @@ function serverEntrySource(root, options) {
|
|
|
1950
2140
|
`import { pageModuleLoaders, routeFileIds } from '${ROUTE_DISCOVERY_ID}${query}';`,
|
|
1951
2141
|
`import { documentNavigation } from '${ROUTER_OPTIONS_ID}${query}';`,
|
|
1952
2142
|
`const documentModuleLoaders = import.meta.glob(['/document.tsrx']);`,
|
|
2143
|
+
`const linkBridgePathsJson = globalThis.__marklessRouterLinkBridgePathsJson ?? ${JSON.stringify(LINK_BRIDGE_PATHS_PLACEHOLDER)};`,
|
|
1953
2144
|
`const entry = createServerEntry({`,
|
|
1954
2145
|
` dev: import.meta.env.DEV,`,
|
|
2146
|
+
` linkBridgePaths: linkBridgePathsJson === ${JSON.stringify(LINK_BRIDGE_PATHS_PLACEHOLDER)} ? undefined : JSON.parse(linkBridgePathsJson),`,
|
|
1955
2147
|
` base: import.meta.env.BASE_URL,`,
|
|
1956
2148
|
` resumeEntryPath,`,
|
|
1957
2149
|
` prerenderWakeEntryPath,`,
|
|
1958
2150
|
` navigationEntryPath,`,
|
|
1959
2151
|
` fragmentEntryPath,`,
|
|
1960
2152
|
` fragmentNavigationSource: ${JSON.stringify(minifiedFragmentNavigationSource())},`,
|
|
2153
|
+
` fragmentNavigationRunSource: ${JSON.stringify(minifiedFragmentNavigationSource(runFragmentNavigation))},`,
|
|
1961
2154
|
...options.prefetch === false ? [" prefetch: false,"] : [],
|
|
1962
2155
|
` routeModulePreloads,`,
|
|
1963
2156
|
` routeSsrModulePreloads,`,
|
|
@@ -1973,8 +2166,8 @@ function serverEntrySource(root, options) {
|
|
|
1973
2166
|
`export default entry;`
|
|
1974
2167
|
].join("\n");
|
|
1975
2168
|
}
|
|
1976
|
-
function minifiedFragmentNavigationSource() {
|
|
1977
|
-
const result = minifySync("markless-fragment-navigation.js", `export default (${
|
|
2169
|
+
function minifiedFragmentNavigationSource(source = startFragmentNavigation) {
|
|
2170
|
+
const result = minifySync("markless-fragment-navigation.js", `export default (${source.toString()});`, {
|
|
1978
2171
|
compress: true,
|
|
1979
2172
|
mangle: true,
|
|
1980
2173
|
module: true
|
|
@@ -2086,6 +2279,10 @@ function routeModulePreloadsFromBundle(input) {
|
|
|
2086
2279
|
routeChunkFileNames.add(chunk.fileName);
|
|
2087
2280
|
}
|
|
2088
2281
|
const symbolChunks = symbolChunksBySourceFile(chunks);
|
|
2282
|
+
const resolverSourceFiles = new Set(allChunks.flatMap((chunk) => (chunk.moduleIds ?? []).flatMap((moduleId) => {
|
|
2283
|
+
const sourceFile = resolverVirtualModuleSourceFile(moduleId.startsWith("\0") ? moduleId.slice(1) : moduleId);
|
|
2284
|
+
return sourceFile ? [sourceModulePathname(sourceFile)] : [];
|
|
2285
|
+
})));
|
|
2089
2286
|
const polyfillFileNames = new Set(chunks.filter((chunk) => chunk.facadeModuleId && input.navigationPolyfillIds?.has(chunk.facadeModuleId)).map((chunk) => chunk.fileName));
|
|
2090
2287
|
const navigation = {};
|
|
2091
2288
|
const ssr = {};
|
|
@@ -2135,8 +2332,10 @@ function routeModulePreloadsFromBundle(input) {
|
|
|
2135
2332
|
}
|
|
2136
2333
|
includeChunk(ssrFileNames, landingScope, landingChunk.fileName, true);
|
|
2137
2334
|
const routeSourceFiles = sourceFilesForChunks(/* @__PURE__ */ new Set([...navigationFileNames, ...ssrFileNames]), chunksByFileName);
|
|
2335
|
+
let routeHasSymbols = false;
|
|
2138
2336
|
for (const [sourceFile, symbolFileNames] of symbolChunks) {
|
|
2139
2337
|
if (!routeSourceFiles.has(sourceFile)) continue;
|
|
2338
|
+
routeHasSymbols = true;
|
|
2140
2339
|
for (const fileName of symbolFileNames) {
|
|
2141
2340
|
includeChunk(navigationFileNames, scope, fileName, true);
|
|
2142
2341
|
includeChunk(ssrFileNames, landingScope, fileName, true);
|
|
@@ -2145,6 +2344,7 @@ function routeModulePreloadsFromBundle(input) {
|
|
|
2145
2344
|
const styleFileNames = /* @__PURE__ */ new Set([...navigationFileNames, ...ssrFileNames]);
|
|
2146
2345
|
const planned = plannedLanding?.get(routeFile);
|
|
2147
2346
|
if (planned) narrowToPlanned(ssrFileNames, planned, landingScope, [input.resumeChunk, input.prerenderWakeChunk]);
|
|
2347
|
+
for (const fileName of ssrFileNames) for (const specifier of warmEvaluatedImports(everyChunk.get(fileName)?.code ?? "")) includeChunk(ssrFileNames, landingScope, normalize(join(dirname(fileName), specifier)));
|
|
2148
2348
|
navigation[routeFile] = [...navigationFileNames].map((fileName) => joinURL(input.base, fileName));
|
|
2149
2349
|
const firstEventPath = /* @__PURE__ */ new Set();
|
|
2150
2350
|
const lazySiblings = [...ssrFileNames].filter((fileName) => {
|
|
@@ -2157,7 +2357,7 @@ function routeModulePreloadsFromBundle(input) {
|
|
|
2157
2357
|
for (const fileName of routeScopedDynamicImports(entry, routeFile)) includeChunk(firstEventPath, landingScope, fileName);
|
|
2158
2358
|
}
|
|
2159
2359
|
for (const fileName of lazySiblings) includeChunk(firstEventPath, landingScope, fileName);
|
|
2160
|
-
ssr[routeFile] = [...[...firstEventPath].filter((fileName) => ssrFileNames.has(fileName)), ...[...ssrFileNames].filter((fileName) => !firstEventPath.has(fileName))].map((fileName) => joinURL(input.base, fileName));
|
|
2360
|
+
ssr[routeFile] = !routeHasSymbols && [...routeSourceFiles].some((file) => resolverSourceFiles.has(file)) ? [] : [...[...firstEventPath].filter((fileName) => ssrFileNames.has(fileName)), ...[...ssrFileNames].filter((fileName) => !firstEventPath.has(fileName))].map((fileName) => joinURL(input.base, fileName));
|
|
2161
2361
|
styles[routeFile] = routeStylesheetsForChunks(routeFileChunks, styleFileNames, chunksByFileName, input.base);
|
|
2162
2362
|
}
|
|
2163
2363
|
return {
|