@reckona/mreact-router 0.0.195 → 0.0.197
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 +3 -1
- package/dist/boundaries.d.ts +66 -0
- package/dist/boundaries.d.ts.map +1 -0
- package/dist/boundaries.js +168 -0
- package/dist/boundaries.js.map +1 -0
- package/dist/build.d.ts +3 -0
- package/dist/build.d.ts.map +1 -1
- package/dist/build.js +18 -1
- package/dist/build.js.map +1 -1
- package/dist/bundle-pipeline.d.ts +2 -0
- package/dist/bundle-pipeline.d.ts.map +1 -1
- package/dist/bundle-pipeline.js +25 -3
- package/dist/bundle-pipeline.js.map +1 -1
- package/dist/cli-options.d.ts +1 -0
- package/dist/cli-options.d.ts.map +1 -1
- package/dist/cli-options.js +30 -0
- package/dist/cli-options.js.map +1 -1
- package/dist/cli.js +16 -0
- package/dist/cli.js.map +1 -1
- package/dist/client-route-inference.d.ts +1 -1
- package/dist/client-route-inference.d.ts.map +1 -1
- package/dist/client-route-inference.js.map +1 -1
- package/dist/client.d.ts +12 -6
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +518 -54
- package/dist/client.js.map +1 -1
- package/dist/index.d.ts +4 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/vite.js +1 -0
- package/dist/vite.js.map +1 -1
- package/package.json +11 -11
- package/src/boundaries.ts +285 -0
- package/src/build.ts +25 -1
- package/src/bundle-pipeline.ts +50 -3
- package/src/cli-options.ts +36 -1
- package/src/cli.ts +23 -0
- package/src/client-route-inference.ts +3 -0
- package/src/client.ts +769 -71
- package/src/index.ts +24 -5
- package/src/vite.ts +1 -0
package/dist/client.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
2
|
import { readFile, stat } from "node:fs/promises";
|
|
3
3
|
import { builtinModules } from "node:module";
|
|
4
|
-
import { dirname, extname, join, relative, sep } from "node:path";
|
|
4
|
+
import { basename, dirname, extname, isAbsolute, join, relative, resolve, sep } from "node:path";
|
|
5
5
|
import { analyzeBoundaryGraph, collectClientRouteModuleAnalysis, formatDiagnostic, } from "@reckona/mreact-compiler";
|
|
6
6
|
import { collectClientRouteModuleAnalysisFromContext, createCompilerModuleContext, hasUnguardedBrowserGlobalReference, readTopLevelBooleanExport, readTopLevelBooleanExportFromContext, stripTypeScriptWithOxc, transformCompilerModuleContext, } from "@reckona/mreact-compiler/internal";
|
|
7
7
|
import { assetPath } from "./assets.js";
|
|
@@ -54,6 +54,16 @@ export async function isClientRouteModule(options) {
|
|
|
54
54
|
export async function inferClientRouteModule(options) {
|
|
55
55
|
const cache = options.cache ?? createClientRouteInferenceCache();
|
|
56
56
|
const sourceTransform = clientRouteSourceTransformForVitePlugins(options.vitePlugins);
|
|
57
|
+
const componentCollector = options.collectComponents
|
|
58
|
+
? {
|
|
59
|
+
clientReachable: new Set(),
|
|
60
|
+
components: new Map(),
|
|
61
|
+
localExportNamesByFile: new Map(),
|
|
62
|
+
pendingExportValidations: [],
|
|
63
|
+
reachable: new Set(),
|
|
64
|
+
staticExportEdges: [],
|
|
65
|
+
}
|
|
66
|
+
: undefined;
|
|
57
67
|
const code = await transformClientRouteSource({
|
|
58
68
|
code: options.code,
|
|
59
69
|
filename: options.filename,
|
|
@@ -63,9 +73,11 @@ export async function inferClientRouteModule(options) {
|
|
|
63
73
|
const routeInference = await inferClientRouteModuleSource({
|
|
64
74
|
cache,
|
|
65
75
|
code,
|
|
76
|
+
componentCollector,
|
|
66
77
|
filename: options.filename,
|
|
67
78
|
...(sourceTransform === undefined ? { moduleContext: options.moduleContext } : {}),
|
|
68
79
|
root: true,
|
|
80
|
+
routeEntry: true,
|
|
69
81
|
seen: new Set(),
|
|
70
82
|
sourceTransform,
|
|
71
83
|
});
|
|
@@ -78,21 +90,38 @@ export async function inferClientRouteModule(options) {
|
|
|
78
90
|
}))
|
|
79
91
|
: routeInference;
|
|
80
92
|
if (options.appDir === undefined) {
|
|
81
|
-
|
|
93
|
+
const exportDiagnostics = finalizeClientRouteComponentExportValidations(componentCollector);
|
|
94
|
+
return withClientRouteDiagnosticPath({
|
|
95
|
+
...mergedRouteInference,
|
|
96
|
+
...(componentCollector === undefined
|
|
97
|
+
? {}
|
|
98
|
+
: {
|
|
99
|
+
components: normalizedClientRouteComponents(componentCollector, options.filename),
|
|
100
|
+
}),
|
|
101
|
+
diagnostics: [...mergedRouteInference.diagnostics, ...exportDiagnostics],
|
|
102
|
+
}, options.routePath);
|
|
82
103
|
}
|
|
83
104
|
const shellInferences = await inferClientRouteShellModules({
|
|
84
105
|
appDir: options.appDir,
|
|
85
106
|
cache,
|
|
107
|
+
componentCollector,
|
|
86
108
|
filename: options.filename,
|
|
87
109
|
sourceTransform,
|
|
88
110
|
});
|
|
111
|
+
const exportDiagnostics = finalizeClientRouteComponentExportValidations(componentCollector);
|
|
89
112
|
return withClientRouteDiagnosticPath({
|
|
90
113
|
client: mergedRouteInference.client || shellInferences.some((inference) => inference.client),
|
|
91
114
|
clientBoundaryImports: mergedRouteInference.clientBoundaryImports,
|
|
92
115
|
clientBoundaryFallbackImports: mergedRouteInference.clientBoundaryFallbackImports,
|
|
116
|
+
...(componentCollector === undefined
|
|
117
|
+
? {}
|
|
118
|
+
: {
|
|
119
|
+
components: normalizedClientRouteComponents(componentCollector, options.filename),
|
|
120
|
+
}),
|
|
93
121
|
diagnostics: [
|
|
94
122
|
...mergedRouteInference.diagnostics,
|
|
95
123
|
...shellInferences.flatMap((inference) => inference.diagnostics),
|
|
124
|
+
...exportDiagnostics,
|
|
96
125
|
],
|
|
97
126
|
}, options.routePath);
|
|
98
127
|
}
|
|
@@ -161,6 +190,7 @@ export async function collectClientRouteReferences(options) {
|
|
|
161
190
|
filename: options.filename,
|
|
162
191
|
moduleContext: routeModuleContext,
|
|
163
192
|
root: true,
|
|
193
|
+
routeEntry: true,
|
|
164
194
|
seen: new Set(),
|
|
165
195
|
sourceTransform,
|
|
166
196
|
});
|
|
@@ -184,6 +214,7 @@ export async function collectClientRouteReferences(options) {
|
|
|
184
214
|
filename: sourceOptions.filename,
|
|
185
215
|
moduleContext,
|
|
186
216
|
root: true,
|
|
217
|
+
routeEntry: false,
|
|
187
218
|
seen: new Set(),
|
|
188
219
|
sourceTransform,
|
|
189
220
|
}));
|
|
@@ -227,6 +258,7 @@ export async function collectClientRouteReferences(options) {
|
|
|
227
258
|
filename: shell,
|
|
228
259
|
moduleContext,
|
|
229
260
|
root: true,
|
|
261
|
+
routeEntry: false,
|
|
230
262
|
seen: new Set(),
|
|
231
263
|
sourceTransform,
|
|
232
264
|
}),
|
|
@@ -343,8 +375,10 @@ async function inferClientRouteShellModules(options) {
|
|
|
343
375
|
return await inferClientRouteModuleSource({
|
|
344
376
|
cache: options.cache,
|
|
345
377
|
code,
|
|
378
|
+
componentCollector: options.componentCollector,
|
|
346
379
|
filename: shell,
|
|
347
380
|
root: true,
|
|
381
|
+
routeEntry: false,
|
|
348
382
|
seen: new Set(),
|
|
349
383
|
sourceTransform: options.sourceTransform,
|
|
350
384
|
});
|
|
@@ -366,6 +400,256 @@ export function isClientRouteSource(code) {
|
|
|
366
400
|
const analysis = collectClientRouteModuleAnalysis({ code });
|
|
367
401
|
return (analysis.hasUseClientDirective || (!analysis.hasUseServerDirective && analysis.clientRuntime));
|
|
368
402
|
}
|
|
403
|
+
function collectClientRouteComponentsForModule(collector, options) {
|
|
404
|
+
if (collector === undefined) {
|
|
405
|
+
return;
|
|
406
|
+
}
|
|
407
|
+
if (options.root) {
|
|
408
|
+
markClientRouteComponentReachable(collector, options.filename, ["default"]);
|
|
409
|
+
}
|
|
410
|
+
const localExportNames = collector.localExportNamesByFile.get(options.filename) ?? new Set();
|
|
411
|
+
for (const info of options.analysis.topLevelExportRenderInfo) {
|
|
412
|
+
localExportNames.add(info.name);
|
|
413
|
+
}
|
|
414
|
+
collector.localExportNamesByFile.set(options.filename, localExportNames);
|
|
415
|
+
const serverOnly = options.analysis.hasUseServerDirective || hasServerOnlyImports(options.analysis);
|
|
416
|
+
const explicitClient = isExplicitClientRouteSource(options.analysis, options.filename);
|
|
417
|
+
for (const info of options.analysis.topLevelExportRenderInfo) {
|
|
418
|
+
const component = {
|
|
419
|
+
classification: serverOnly
|
|
420
|
+
? "server-only"
|
|
421
|
+
: explicitClient || info.clientRuntime
|
|
422
|
+
? options.routeEntry && info.name === "default"
|
|
423
|
+
? "client-route"
|
|
424
|
+
: "client-boundary"
|
|
425
|
+
: "server-render",
|
|
426
|
+
exportName: info.name,
|
|
427
|
+
file: options.filename,
|
|
428
|
+
origin: clientRouteComponentOrigin({
|
|
429
|
+
analysis: options.analysis,
|
|
430
|
+
filename: options.filename,
|
|
431
|
+
info,
|
|
432
|
+
serverOnly,
|
|
433
|
+
}),
|
|
434
|
+
};
|
|
435
|
+
collector.components.set(clientRouteComponentKey(component.file, component.exportName), component);
|
|
436
|
+
}
|
|
437
|
+
for (const info of options.analysis.topLevelExportRenderInfo) {
|
|
438
|
+
if (!isClientRouteComponentReachable(collector, options.filename, info.name)) {
|
|
439
|
+
continue;
|
|
440
|
+
}
|
|
441
|
+
const renderedNames = new Set([
|
|
442
|
+
...(options.analysis.reachableExportRenderedComponentNames[info.name] ?? []),
|
|
443
|
+
...(options.analysis.reachableExportRenderedComponentRoots[info.name] ?? []),
|
|
444
|
+
]);
|
|
445
|
+
for (const rendered of options.analysis.topLevelExportRenderInfo) {
|
|
446
|
+
if (rendered.name !== "default" &&
|
|
447
|
+
(renderedNames.has(rendered.name) || renderedNames.has(rendered.localName ?? rendered.name))) {
|
|
448
|
+
markClientRouteComponentReachable(collector, options.filename, [rendered.name], {
|
|
449
|
+
clientExecution: clientRouteComponentRunsOnClient(collector, options.filename, info.name),
|
|
450
|
+
});
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
function clientRouteComponentOrigin(options) {
|
|
456
|
+
if (options.analysis.hasUseServerDirective) {
|
|
457
|
+
return "use-server-directive";
|
|
458
|
+
}
|
|
459
|
+
if (options.serverOnly) {
|
|
460
|
+
return "server-only-import";
|
|
461
|
+
}
|
|
462
|
+
if (options.analysis.hasUseClientDirective) {
|
|
463
|
+
return "use-client-directive";
|
|
464
|
+
}
|
|
465
|
+
if (/\.compat(?:\.mreact)?\.[cm]?[jt]sx?$/.test(options.filename)) {
|
|
466
|
+
return "compat-filename";
|
|
467
|
+
}
|
|
468
|
+
if (/\.client(?:\.mreact)?\.[cm]?[jt]sx?$/.test(options.filename)) {
|
|
469
|
+
return "client-filename";
|
|
470
|
+
}
|
|
471
|
+
return options.info.clientRuntime ? "inferred-client-runtime" : "server-render";
|
|
472
|
+
}
|
|
473
|
+
function normalizedClientRouteComponents(collector, routeFile) {
|
|
474
|
+
return Array.from(collector.components.values())
|
|
475
|
+
.filter((component) => collector.reachable.has(clientRouteComponentKey(component.file, component.exportName)) ||
|
|
476
|
+
collector.reachable.has(clientRouteComponentKey(component.file, "*")))
|
|
477
|
+
.map((component) => component.classification === "server-render" &&
|
|
478
|
+
(collector.clientReachable.has(clientRouteComponentKey(component.file, component.exportName)) ||
|
|
479
|
+
collector.clientReachable.has(clientRouteComponentKey(component.file, "*")))
|
|
480
|
+
? { ...component, classification: "shared" }
|
|
481
|
+
: component)
|
|
482
|
+
.sort((left, right) => {
|
|
483
|
+
const leftRoute = left.file === routeFile && left.exportName === "default";
|
|
484
|
+
const rightRoute = right.file === routeFile && right.exportName === "default";
|
|
485
|
+
if (leftRoute !== rightRoute) {
|
|
486
|
+
return leftRoute ? -1 : 1;
|
|
487
|
+
}
|
|
488
|
+
return left.file === right.file
|
|
489
|
+
? left.exportName === right.exportName
|
|
490
|
+
? left.classification.localeCompare(right.classification)
|
|
491
|
+
: left.exportName.localeCompare(right.exportName)
|
|
492
|
+
: left.file.localeCompare(right.file);
|
|
493
|
+
});
|
|
494
|
+
}
|
|
495
|
+
function clientRouteComponentKey(file, exportName) {
|
|
496
|
+
return `${file}\0${exportName}`;
|
|
497
|
+
}
|
|
498
|
+
function markClientRouteComponentReachable(collector, file, exportNames, options = {}) {
|
|
499
|
+
if (collector === undefined) {
|
|
500
|
+
return;
|
|
501
|
+
}
|
|
502
|
+
if (exportNames === undefined) {
|
|
503
|
+
collector.reachable.add(clientRouteComponentKey(file, "*"));
|
|
504
|
+
if (options.clientExecution === true) {
|
|
505
|
+
collector.clientReachable.add(clientRouteComponentKey(file, "*"));
|
|
506
|
+
}
|
|
507
|
+
return;
|
|
508
|
+
}
|
|
509
|
+
for (const exportName of exportNames) {
|
|
510
|
+
const key = clientRouteComponentKey(file, exportName);
|
|
511
|
+
collector.reachable.add(key);
|
|
512
|
+
if (options.clientExecution === true) {
|
|
513
|
+
collector.clientReachable.add(key);
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
function clientRouteComponentRunsOnClient(collector, file, exportName) {
|
|
518
|
+
if (collector === undefined) {
|
|
519
|
+
return false;
|
|
520
|
+
}
|
|
521
|
+
const key = clientRouteComponentKey(file, exportName);
|
|
522
|
+
const component = collector.components.get(key);
|
|
523
|
+
return (component?.classification === "client-boundary" ||
|
|
524
|
+
component?.classification === "client-route" ||
|
|
525
|
+
component?.classification === "shared" ||
|
|
526
|
+
collector.clientReachable.has(key) ||
|
|
527
|
+
collector.clientReachable.has(clientRouteComponentKey(file, "*")));
|
|
528
|
+
}
|
|
529
|
+
function isClientRouteComponentReachable(collector, file, exportName) {
|
|
530
|
+
return (collector === undefined ||
|
|
531
|
+
collector.reachable.has(clientRouteComponentKey(file, exportName)) ||
|
|
532
|
+
collector.reachable.has(clientRouteComponentKey(file, "*")));
|
|
533
|
+
}
|
|
534
|
+
function propagateClientRouteComponentStaticExport(collector, file, resolved, reference) {
|
|
535
|
+
if (collector === undefined) {
|
|
536
|
+
return;
|
|
537
|
+
}
|
|
538
|
+
const wildcardReachable = collector.reachable.has(clientRouteComponentKey(file, "*"));
|
|
539
|
+
const wildcardClientExecution = clientRouteComponentRunsOnClient(collector, file, "*");
|
|
540
|
+
if (reference.exportAll) {
|
|
541
|
+
if (wildcardReachable) {
|
|
542
|
+
markClientRouteComponentReachable(collector, resolved, undefined, {
|
|
543
|
+
clientExecution: wildcardClientExecution,
|
|
544
|
+
});
|
|
545
|
+
}
|
|
546
|
+
for (const key of collector.reachable) {
|
|
547
|
+
const [reachableFile, exportName] = key.split("\0");
|
|
548
|
+
if (reachableFile === file && exportName !== undefined && exportName !== "*") {
|
|
549
|
+
markClientRouteComponentReachable(collector, resolved, [exportName], {
|
|
550
|
+
clientExecution: clientRouteComponentRunsOnClient(collector, file, exportName),
|
|
551
|
+
});
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
return;
|
|
555
|
+
}
|
|
556
|
+
for (const specifier of reference.specifiers) {
|
|
557
|
+
if (wildcardReachable ||
|
|
558
|
+
collector.reachable.has(clientRouteComponentKey(file, specifier.exportedName))) {
|
|
559
|
+
markClientRouteComponentReachable(collector, resolved, [specifier.localName], {
|
|
560
|
+
clientExecution: wildcardClientExecution ||
|
|
561
|
+
clientRouteComponentRunsOnClient(collector, file, specifier.exportedName),
|
|
562
|
+
});
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
if (reference.specifiers.length === 0) {
|
|
566
|
+
for (const exportName of reference.exportedNames) {
|
|
567
|
+
if (wildcardReachable || collector.reachable.has(clientRouteComponentKey(file, exportName))) {
|
|
568
|
+
markClientRouteComponentReachable(collector, resolved, [exportName], {
|
|
569
|
+
clientExecution: wildcardClientExecution ||
|
|
570
|
+
clientRouteComponentRunsOnClient(collector, file, exportName),
|
|
571
|
+
});
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
function collectUnknownClientRouteComponents(collector, options) {
|
|
577
|
+
if (collector === undefined) {
|
|
578
|
+
return;
|
|
579
|
+
}
|
|
580
|
+
for (const exportName of options.exportNames ?? ["*"]) {
|
|
581
|
+
const component = {
|
|
582
|
+
classification: "unknown",
|
|
583
|
+
exportName,
|
|
584
|
+
file: options.file,
|
|
585
|
+
origin: "unresolved-reference",
|
|
586
|
+
};
|
|
587
|
+
collector.components.set(clientRouteComponentKey(component.file, component.exportName), component);
|
|
588
|
+
markClientRouteComponentReachable(collector, component.file, [component.exportName]);
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
function collectClientRoutePendingExportValidation(collector, options) {
|
|
592
|
+
if (collector === undefined || options.exportNames.length === 0) {
|
|
593
|
+
return;
|
|
594
|
+
}
|
|
595
|
+
collector.pendingExportValidations.push(options);
|
|
596
|
+
}
|
|
597
|
+
function collectClientRouteStaticExportEdge(collector, options) {
|
|
598
|
+
collector?.staticExportEdges.push(options);
|
|
599
|
+
}
|
|
600
|
+
function finalizeClientRouteComponentExportValidations(collector) {
|
|
601
|
+
if (collector === undefined) {
|
|
602
|
+
return [];
|
|
603
|
+
}
|
|
604
|
+
const exportNamesByFile = new Map();
|
|
605
|
+
for (const [file, names] of collector.localExportNamesByFile) {
|
|
606
|
+
exportNamesByFile.set(file, new Set(names));
|
|
607
|
+
}
|
|
608
|
+
let changed = true;
|
|
609
|
+
while (changed) {
|
|
610
|
+
changed = false;
|
|
611
|
+
for (const edge of collector.staticExportEdges) {
|
|
612
|
+
const exportedNames = exportNamesByFile.get(edge.file) ?? new Set();
|
|
613
|
+
const sourceNames = exportNamesByFile.get(edge.resolved) ?? new Set();
|
|
614
|
+
const namesToAdd = edge.reference.exportAll
|
|
615
|
+
? new Set([...sourceNames].filter((exportName) => exportName !== "default"))
|
|
616
|
+
: new Set(edge.reference.specifiers
|
|
617
|
+
.filter((specifier) => sourceNames.has(specifier.localName))
|
|
618
|
+
.map((specifier) => specifier.exportedName));
|
|
619
|
+
for (const exportName of namesToAdd) {
|
|
620
|
+
if (!exportedNames.has(exportName)) {
|
|
621
|
+
exportedNames.add(exportName);
|
|
622
|
+
changed = true;
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
exportNamesByFile.set(edge.file, exportedNames);
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
const diagnostics = [];
|
|
629
|
+
const seen = new Set();
|
|
630
|
+
for (const pending of collector.pendingExportValidations) {
|
|
631
|
+
const availableExportNames = exportNamesByFile.get(pending.file) ?? new Set();
|
|
632
|
+
const missingExportNames = pending.exportNames.filter((exportName) => !availableExportNames.has(exportName));
|
|
633
|
+
if (missingExportNames.length === 0) {
|
|
634
|
+
continue;
|
|
635
|
+
}
|
|
636
|
+
const key = `${pending.importer}\0${pending.source}\0${missingExportNames.join("\0")}`;
|
|
637
|
+
if (seen.has(key)) {
|
|
638
|
+
continue;
|
|
639
|
+
}
|
|
640
|
+
seen.add(key);
|
|
641
|
+
collectUnknownClientRouteComponents(collector, {
|
|
642
|
+
exportNames: missingExportNames,
|
|
643
|
+
file: pending.file,
|
|
644
|
+
});
|
|
645
|
+
diagnostics.push(unresolvedClientRouteReferenceDiagnostic({
|
|
646
|
+
exportNames: missingExportNames,
|
|
647
|
+
filename: pending.importer,
|
|
648
|
+
source: pending.source,
|
|
649
|
+
}));
|
|
650
|
+
}
|
|
651
|
+
return diagnostics;
|
|
652
|
+
}
|
|
369
653
|
function isExplicitClientRouteSource(analysis, filename) {
|
|
370
654
|
return analysis.hasUseClientDirective || isClientBoundaryFilename(filename);
|
|
371
655
|
}
|
|
@@ -384,22 +668,35 @@ function hasServerOnlyImports(analysis) {
|
|
|
384
668
|
async function inferClientRouteModuleSource(options) {
|
|
385
669
|
const analysis = await clientRouteModuleAnalysisForSource(options);
|
|
386
670
|
const usesNavigationLinkLocal = detectLinkComponentUsage(analysis);
|
|
387
|
-
|
|
388
|
-
|
|
671
|
+
collectClientRouteComponentsForModule(options.componentCollector, {
|
|
672
|
+
analysis,
|
|
673
|
+
filename: options.filename,
|
|
674
|
+
root: options.root,
|
|
675
|
+
routeEntry: options.routeEntry,
|
|
676
|
+
});
|
|
677
|
+
const forcedInference = isServerOnlyClientRouteSource(analysis)
|
|
678
|
+
? emptyClientRouteModuleInferenceResult({
|
|
679
|
+
availableExportNames: analysis.topLevelExportRenderInfo.map((info) => info.name),
|
|
389
680
|
navigationLinkExportNames: detectLinkComponentExportNames(analysis),
|
|
390
681
|
serverOnly: true,
|
|
391
682
|
serverOnlyClientRuntime: analysis.clientRuntime,
|
|
392
683
|
usesNavigationLink: usesNavigationLinkLocal,
|
|
393
|
-
})
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
684
|
+
})
|
|
685
|
+
: isExplicitClientRouteSource(analysis, options.filename)
|
|
686
|
+
? emptyClientRouteModuleInferenceResult({
|
|
687
|
+
availableExportNames: analysis.topLevelExportRenderInfo.map((info) => info.name),
|
|
688
|
+
client: true,
|
|
689
|
+
clientBoundaryModule: true,
|
|
690
|
+
})
|
|
691
|
+
: undefined;
|
|
692
|
+
if (forcedInference !== undefined && options.componentCollector === undefined) {
|
|
693
|
+
return forcedInference;
|
|
400
694
|
}
|
|
401
695
|
if (options.seen.has(options.filename)) {
|
|
402
|
-
return
|
|
696
|
+
return (forcedInference ??
|
|
697
|
+
emptyClientRouteModuleInferenceResult({
|
|
698
|
+
availableExportNames: analysis.topLevelExportRenderInfo.map((info) => info.name),
|
|
699
|
+
}));
|
|
403
700
|
}
|
|
404
701
|
options.seen.add(options.filename);
|
|
405
702
|
try {
|
|
@@ -409,6 +706,7 @@ async function inferClientRouteModuleSource(options) {
|
|
|
409
706
|
const nestedClientExportNames = new Set();
|
|
410
707
|
const clientReferenceSourceFiles = [];
|
|
411
708
|
const diagnostics = [];
|
|
709
|
+
const availableExportNames = new Set(analysis.topLevelExportRenderInfo.map((info) => info.name));
|
|
412
710
|
let boundaryGraphFallbackRequired = false;
|
|
413
711
|
let clientProxy = false;
|
|
414
712
|
let nestedClient = false;
|
|
@@ -422,8 +720,11 @@ async function inferClientRouteModuleSource(options) {
|
|
|
422
720
|
}
|
|
423
721
|
}
|
|
424
722
|
if (hasServerOnlyImports(analysis) &&
|
|
425
|
-
(implicitModuleClient || clientBoundaryExportNames.size > 0)
|
|
723
|
+
(implicitModuleClient || clientBoundaryExportNames.size > 0) &&
|
|
724
|
+
options.componentCollector === undefined) {
|
|
426
725
|
return emptyClientRouteModuleInferenceResult({
|
|
726
|
+
availableExportNames: Array.from(availableExportNames),
|
|
727
|
+
navigationLinkExportNames: detectLinkComponentExportNames(analysis),
|
|
427
728
|
serverOnly: true,
|
|
428
729
|
serverOnlyClientRuntime: true,
|
|
429
730
|
});
|
|
@@ -450,15 +751,46 @@ async function inferClientRouteModuleSource(options) {
|
|
|
450
751
|
if (reference.sideEffect && isStyleModuleSpecifier(reference.source)) {
|
|
451
752
|
continue;
|
|
452
753
|
}
|
|
754
|
+
const renderingExportNames = rendered ? renderedLocalExportNames(reference, exportInfo) : [];
|
|
755
|
+
const renderedImportedNames = rendered
|
|
756
|
+
? renderedImportedExportNames(reference, renderedComponentRoots)
|
|
757
|
+
: [];
|
|
758
|
+
const renderedFromReachableExport = rendered &&
|
|
759
|
+
renderingExportNames.some((exportName) => isClientRouteComponentReachable(options.componentCollector, options.filename, exportName));
|
|
453
760
|
const resolved = await resolveAppLocalModule({
|
|
454
761
|
allowExplicitNonSource: options.sourceTransform !== undefined,
|
|
455
762
|
cache: options.cache,
|
|
456
763
|
importer: options.filename,
|
|
457
764
|
specifier: reference.source,
|
|
765
|
+
tolerateUnresolved: options.componentCollector !== undefined,
|
|
458
766
|
});
|
|
459
767
|
if (resolved === undefined) {
|
|
768
|
+
if (options.componentCollector !== undefined &&
|
|
769
|
+
renderedFromReachableExport &&
|
|
770
|
+
reference.source.startsWith(".")) {
|
|
771
|
+
collectUnknownClientRouteComponents(options.componentCollector, {
|
|
772
|
+
exportNames: renderedImportedNames,
|
|
773
|
+
file: resolve(dirname(options.filename), reference.source),
|
|
774
|
+
});
|
|
775
|
+
diagnostics.push(unresolvedClientRouteReferenceDiagnostic({
|
|
776
|
+
filename: options.filename,
|
|
777
|
+
source: reference.source,
|
|
778
|
+
}));
|
|
779
|
+
}
|
|
460
780
|
continue;
|
|
461
781
|
}
|
|
782
|
+
if (renderedFromReachableExport) {
|
|
783
|
+
const clientExecution = renderingExportNames.some((exportName) => clientRouteComponentRunsOnClient(options.componentCollector, options.filename, exportName));
|
|
784
|
+
markClientRouteComponentReachable(options.componentCollector, resolved, renderedImportedNames, { clientExecution });
|
|
785
|
+
if (renderedImportedNames !== undefined) {
|
|
786
|
+
collectClientRoutePendingExportValidation(options.componentCollector, {
|
|
787
|
+
exportNames: renderedImportedNames,
|
|
788
|
+
file: resolved,
|
|
789
|
+
importer: options.filename,
|
|
790
|
+
source: reference.source,
|
|
791
|
+
});
|
|
792
|
+
}
|
|
793
|
+
}
|
|
462
794
|
const source = await readClientRouteSource({
|
|
463
795
|
cache: options.cache,
|
|
464
796
|
filename: resolved,
|
|
@@ -467,6 +799,7 @@ async function inferClientRouteModuleSource(options) {
|
|
|
467
799
|
const imported = await inferClientRouteModuleSource({
|
|
468
800
|
cache: options.cache,
|
|
469
801
|
code: source,
|
|
802
|
+
componentCollector: options.componentCollector,
|
|
470
803
|
filename: resolved,
|
|
471
804
|
moduleContext: await compilerModuleContextForSource({
|
|
472
805
|
cache: options.cache,
|
|
@@ -474,6 +807,7 @@ async function inferClientRouteModuleSource(options) {
|
|
|
474
807
|
filename: resolved,
|
|
475
808
|
}),
|
|
476
809
|
root: false,
|
|
810
|
+
routeEntry: false,
|
|
477
811
|
seen: options.seen,
|
|
478
812
|
sourceTransform: options.sourceTransform,
|
|
479
813
|
});
|
|
@@ -505,8 +839,8 @@ async function inferClientRouteModuleSource(options) {
|
|
|
505
839
|
continue;
|
|
506
840
|
}
|
|
507
841
|
if (rendered) {
|
|
508
|
-
const importedExportNames =
|
|
509
|
-
const renderedExportNames =
|
|
842
|
+
const importedExportNames = renderedImportedNames;
|
|
843
|
+
const renderedExportNames = renderingExportNames;
|
|
510
844
|
const importedBoundary = imported.clientBoundaryModule ||
|
|
511
845
|
matchesInferredExportNames(importedExportNames, imported.clientBoundaryExportNames);
|
|
512
846
|
const importedNested = matchesInferredExportNames(importedExportNames, imported.nestedClientExportNames);
|
|
@@ -553,10 +887,23 @@ async function inferClientRouteModuleSource(options) {
|
|
|
553
887
|
cache: options.cache,
|
|
554
888
|
importer: options.filename,
|
|
555
889
|
specifier: reference.source,
|
|
890
|
+
tolerateUnresolved: options.componentCollector !== undefined,
|
|
556
891
|
});
|
|
557
892
|
if (resolved === undefined) {
|
|
893
|
+
if (options.componentCollector !== undefined) {
|
|
894
|
+
diagnostics.push(unresolvedClientRouteReferenceDiagnostic({
|
|
895
|
+
filename: options.filename,
|
|
896
|
+
source: reference.source,
|
|
897
|
+
}));
|
|
898
|
+
}
|
|
558
899
|
continue;
|
|
559
900
|
}
|
|
901
|
+
propagateClientRouteComponentStaticExport(options.componentCollector, options.filename, resolved, reference);
|
|
902
|
+
collectClientRouteStaticExportEdge(options.componentCollector, {
|
|
903
|
+
file: options.filename,
|
|
904
|
+
reference,
|
|
905
|
+
resolved,
|
|
906
|
+
});
|
|
560
907
|
const source = await readClientRouteSource({
|
|
561
908
|
cache: options.cache,
|
|
562
909
|
filename: resolved,
|
|
@@ -565,6 +912,7 @@ async function inferClientRouteModuleSource(options) {
|
|
|
565
912
|
const exported = await inferClientRouteModuleSource({
|
|
566
913
|
cache: options.cache,
|
|
567
914
|
code: source,
|
|
915
|
+
componentCollector: options.componentCollector,
|
|
568
916
|
filename: resolved,
|
|
569
917
|
moduleContext: await compilerModuleContextForSource({
|
|
570
918
|
cache: options.cache,
|
|
@@ -572,10 +920,24 @@ async function inferClientRouteModuleSource(options) {
|
|
|
572
920
|
filename: resolved,
|
|
573
921
|
}),
|
|
574
922
|
root: false,
|
|
923
|
+
routeEntry: false,
|
|
575
924
|
seen: options.seen,
|
|
576
925
|
sourceTransform: options.sourceTransform,
|
|
577
926
|
});
|
|
578
927
|
diagnostics.push(...exported.diagnostics);
|
|
928
|
+
if (reference.exportAll) {
|
|
929
|
+
for (const exportName of exported.availableExportNames) {
|
|
930
|
+
availableExportNames.add(exportName);
|
|
931
|
+
}
|
|
932
|
+
}
|
|
933
|
+
else {
|
|
934
|
+
for (const specifier of reference.specifiers) {
|
|
935
|
+
availableExportNames.add(specifier.exportedName);
|
|
936
|
+
}
|
|
937
|
+
for (const exportName of reference.exportedNames) {
|
|
938
|
+
availableExportNames.add(exportName);
|
|
939
|
+
}
|
|
940
|
+
}
|
|
579
941
|
// A re-export renders nothing itself, so it does not set the module's
|
|
580
942
|
// own `usesNavigationLink`; it only forwards per-export `Link` usage so
|
|
581
943
|
// an importer that renders this name can decide precisely. Map the
|
|
@@ -620,7 +982,8 @@ async function inferClientRouteModuleSource(options) {
|
|
|
620
982
|
}
|
|
621
983
|
}
|
|
622
984
|
}
|
|
623
|
-
|
|
985
|
+
const inferred = {
|
|
986
|
+
availableExportNames: Array.from(availableExportNames),
|
|
624
987
|
boundaryGraphFallbackCandidate: analysis.staticExports.length > 0 || boundaryGraphFallbackRequired,
|
|
625
988
|
boundaryGraphFallbackRequired,
|
|
626
989
|
client: clientBoundaryImports.length > 0 ||
|
|
@@ -640,6 +1003,15 @@ async function inferClientRouteModuleSource(options) {
|
|
|
640
1003
|
serverOnlyClientRuntime: false,
|
|
641
1004
|
usesNavigationLink,
|
|
642
1005
|
};
|
|
1006
|
+
return forcedInference === undefined
|
|
1007
|
+
? inferred
|
|
1008
|
+
: {
|
|
1009
|
+
...forcedInference,
|
|
1010
|
+
availableExportNames: inferred.availableExportNames,
|
|
1011
|
+
diagnostics,
|
|
1012
|
+
navigationLinkExportNames: inferred.navigationLinkExportNames,
|
|
1013
|
+
usesNavigationLink: inferred.usesNavigationLink,
|
|
1014
|
+
};
|
|
643
1015
|
}
|
|
644
1016
|
finally {
|
|
645
1017
|
options.seen.delete(options.filename);
|
|
@@ -647,6 +1019,7 @@ async function inferClientRouteModuleSource(options) {
|
|
|
647
1019
|
}
|
|
648
1020
|
function emptyClientRouteModuleInferenceResult(overrides = {}) {
|
|
649
1021
|
return {
|
|
1022
|
+
availableExportNames: [],
|
|
650
1023
|
boundaryGraphFallbackCandidate: false,
|
|
651
1024
|
boundaryGraphFallbackRequired: false,
|
|
652
1025
|
client: false,
|
|
@@ -883,7 +1256,7 @@ function matchingBraceEnd(source, openBraceIndex) {
|
|
|
883
1256
|
}
|
|
884
1257
|
continue;
|
|
885
1258
|
}
|
|
886
|
-
if (char === "
|
|
1259
|
+
if (char === '"' || char === "'" || char === "`") {
|
|
887
1260
|
quote = char;
|
|
888
1261
|
continue;
|
|
889
1262
|
}
|
|
@@ -940,8 +1313,7 @@ function addDestructuredCallbackNames(names, destructured) {
|
|
|
940
1313
|
const property = destructuredBindingName(rawProperty);
|
|
941
1314
|
const alias = destructuredBindingName(rawAlias);
|
|
942
1315
|
const name = alias ?? property;
|
|
943
|
-
if (name !== undefined &&
|
|
944
|
-
(isCallbackPropName(property) || isCallbackPropName(name))) {
|
|
1316
|
+
if (name !== undefined && (isCallbackPropName(property) || isCallbackPropName(name))) {
|
|
945
1317
|
names.add(name);
|
|
946
1318
|
}
|
|
947
1319
|
}
|
|
@@ -1001,6 +1373,20 @@ function serverOnlyClientImportReferenceDiagnostic(options) {
|
|
|
1001
1373
|
source: options.reference.source,
|
|
1002
1374
|
};
|
|
1003
1375
|
}
|
|
1376
|
+
function unresolvedClientRouteReferenceDiagnostic(options) {
|
|
1377
|
+
const exportSuffix = options.exportNames === undefined || options.exportNames.length === 0
|
|
1378
|
+
? ""
|
|
1379
|
+
: ` (${options.exportNames.map((name) => JSON.stringify(name)).join(", ")})`;
|
|
1380
|
+
return {
|
|
1381
|
+
code: "MR_CLIENT_BOUNDARY_INFERENCE_UNRESOLVED_REFERENCE",
|
|
1382
|
+
filename: options.filename,
|
|
1383
|
+
level: "warn",
|
|
1384
|
+
localNames: [...(options.exportNames ?? [])],
|
|
1385
|
+
message: `${options.filename}: rendered component reference ${JSON.stringify(options.source)}${exportSuffix} ` +
|
|
1386
|
+
"could not be resolved to an exported component.",
|
|
1387
|
+
source: options.source,
|
|
1388
|
+
};
|
|
1389
|
+
}
|
|
1004
1390
|
function functionCallInteractiveImportDiagnostic(options) {
|
|
1005
1391
|
const localNames = options.reference.localNames.filter(startsUppercase);
|
|
1006
1392
|
const component = localNames[0] ?? options.reference.localNames[0] ?? options.reference.source;
|
|
@@ -1066,7 +1452,7 @@ async function resolveAppLocalModule(options) {
|
|
|
1066
1452
|
if (!options.specifier.startsWith(".")) {
|
|
1067
1453
|
return undefined;
|
|
1068
1454
|
}
|
|
1069
|
-
const cacheKey = `${options.importer}\0${options.specifier}\0${options.allowExplicitNonSource === true ? "explicit" : "source"}`;
|
|
1455
|
+
const cacheKey = `${options.importer}\0${options.specifier}\0${options.allowExplicitNonSource === true ? "explicit" : "source"}\0${options.tolerateUnresolved === true ? "tolerant" : "strict"}`;
|
|
1070
1456
|
const cached = options.cache.resolvedByImport.get(cacheKey);
|
|
1071
1457
|
if (cached !== undefined) {
|
|
1072
1458
|
return cached;
|
|
@@ -1075,6 +1461,7 @@ async function resolveAppLocalModule(options) {
|
|
|
1075
1461
|
allowExplicitNonSource: options.allowExplicitNonSource === true,
|
|
1076
1462
|
importer: options.importer,
|
|
1077
1463
|
specifier: options.specifier,
|
|
1464
|
+
tolerateUnresolved: options.tolerateUnresolved === true,
|
|
1078
1465
|
});
|
|
1079
1466
|
options.cache.resolvedByImport.set(cacheKey, resolved);
|
|
1080
1467
|
return resolved;
|
|
@@ -1094,6 +1481,9 @@ async function resolveAppLocalModuleUncached(options) {
|
|
|
1094
1481
|
return candidate;
|
|
1095
1482
|
}
|
|
1096
1483
|
}
|
|
1484
|
+
if (options.tolerateUnresolved) {
|
|
1485
|
+
return undefined;
|
|
1486
|
+
}
|
|
1097
1487
|
throw new Error(`${importer}: could not resolve app-local import ${JSON.stringify(specifier)}.`);
|
|
1098
1488
|
}
|
|
1099
1489
|
async function isFile(path) {
|
|
@@ -1318,6 +1708,12 @@ export async function buildNavigationRuntimeBundle(options = {}) {
|
|
|
1318
1708
|
export async function buildClientRouteOutput(options) {
|
|
1319
1709
|
const entry = await buildClientRouteEntrySource(options);
|
|
1320
1710
|
const dropConsoleFunctions = options.dropConsoleFunctions ?? resolveClientConsolePureFunctions(options.dropClientConsole);
|
|
1711
|
+
const sourceRegionModulePaths = options.debugLabels === true ? undefined : new Set([options.filename]);
|
|
1712
|
+
const runtimePlugin = workspaceRuntimePlugin({
|
|
1713
|
+
debugLabels: options.debugLabels === true,
|
|
1714
|
+
routeFiles: [options.filename],
|
|
1715
|
+
sourceRegionModulePaths,
|
|
1716
|
+
});
|
|
1321
1717
|
const bundled = await bundleRouterModule({
|
|
1322
1718
|
code: entry.code,
|
|
1323
1719
|
cacheDir: options.cacheDir,
|
|
@@ -1329,7 +1725,8 @@ export async function buildClientRouteOutput(options) {
|
|
|
1329
1725
|
minify: options.minify === true,
|
|
1330
1726
|
platform: "browser",
|
|
1331
1727
|
preserveExports: true,
|
|
1332
|
-
|
|
1728
|
+
sourceRegionModulePaths,
|
|
1729
|
+
plugins: [runtimePlugin],
|
|
1333
1730
|
sourceMap: options.sourceMap,
|
|
1334
1731
|
vitePlugins: options.vitePlugins,
|
|
1335
1732
|
});
|
|
@@ -1350,6 +1747,15 @@ export async function buildClientRouteBatchOutput(options) {
|
|
|
1350
1747
|
vitePlugins: options.vitePlugins ?? route.vitePlugins,
|
|
1351
1748
|
}),
|
|
1352
1749
|
})));
|
|
1750
|
+
const debugLabels = options.routes.some((route) => route.debugLabels === true);
|
|
1751
|
+
const sourceRegionModulePaths = debugLabels
|
|
1752
|
+
? undefined
|
|
1753
|
+
: new Set(entries.map((entry) => entry.filename));
|
|
1754
|
+
const runtimePlugin = workspaceRuntimePlugin({
|
|
1755
|
+
debugLabels,
|
|
1756
|
+
routeFiles: entries.map((entry) => entry.filename),
|
|
1757
|
+
sourceRegionModulePaths,
|
|
1758
|
+
});
|
|
1353
1759
|
const bundled = await bundleRouterModules({
|
|
1354
1760
|
base: options.assetBaseUrl ?? "/_mreact/client/",
|
|
1355
1761
|
cacheDir: options.cacheDir,
|
|
@@ -1363,7 +1769,8 @@ export async function buildClientRouteBatchOutput(options) {
|
|
|
1363
1769
|
})),
|
|
1364
1770
|
minify: options.minify === true,
|
|
1365
1771
|
platform: "browser",
|
|
1366
|
-
|
|
1772
|
+
sourceRegionModulePaths,
|
|
1773
|
+
plugins: [runtimePlugin],
|
|
1367
1774
|
root: options.projectRoot,
|
|
1368
1775
|
sourceMap: options.sourceMap,
|
|
1369
1776
|
dropConsoleFunctions: options.dropConsoleFunctions,
|
|
@@ -1392,13 +1799,20 @@ export async function buildClientRouteEntrySource(options) {
|
|
|
1392
1799
|
filename: options.filename,
|
|
1393
1800
|
});
|
|
1394
1801
|
const routeSourceAnalysis = collectClientRouteModuleAnalysisFromContext(moduleContext);
|
|
1802
|
+
const compilerFilename = options.debugLabels === true ? basename(options.filename) : options.filename;
|
|
1803
|
+
const compilerModuleContext = compilerFilename === options.filename
|
|
1804
|
+
? moduleContext
|
|
1805
|
+
: createCompilerModuleContext({
|
|
1806
|
+
code: options.code,
|
|
1807
|
+
filename: compilerFilename,
|
|
1808
|
+
});
|
|
1395
1809
|
const compiled = transformCompilerModuleContext({
|
|
1396
1810
|
code: options.code,
|
|
1397
1811
|
clientBoundaryImports: options.clientBoundaryImports ?? [],
|
|
1398
|
-
filename:
|
|
1399
|
-
moduleContext,
|
|
1812
|
+
filename: compilerFilename,
|
|
1813
|
+
moduleContext: compilerModuleContext,
|
|
1400
1814
|
target: "client",
|
|
1401
|
-
dev: options.
|
|
1815
|
+
dev: options.debugLabels === true,
|
|
1402
1816
|
});
|
|
1403
1817
|
if (compiled.diagnostics.length > 0) {
|
|
1404
1818
|
throw new Error(compiled.diagnostics
|
|
@@ -1416,7 +1830,8 @@ export async function buildClientRouteEntrySource(options) {
|
|
|
1416
1830
|
const routeId = routeIdForPath(options.routePath);
|
|
1417
1831
|
const routeUsesCells = detectRouteCellStateHint(compiled.code);
|
|
1418
1832
|
const routeUsesReactiveEffect = detectRouteReactiveEffectHint(compiled.code);
|
|
1419
|
-
const
|
|
1833
|
+
const routeUsesDomRefs = compiled.metadata.imports.some((entry) => entry.source === "@reckona/mreact-reactive-dom" && entry.specifiers.includes("bindDomRef"));
|
|
1834
|
+
const routeUsesCleanupScope = routeUsesCells || routeUsesReactiveEffect || routeUsesDomRefs;
|
|
1420
1835
|
const routeExplicitlyRequiresHydration = isExplicitClientRouteSource(routeSourceAnalysis, options.filename);
|
|
1421
1836
|
const routeHasEventBindings = (compiled.metadata.eventHydrationManifest?.events.length ?? 0) > 0;
|
|
1422
1837
|
const routeCapturesEventBindings = compiled.code.includes("__mreactEventBindings");
|
|
@@ -1427,6 +1842,7 @@ export async function buildClientRouteEntrySource(options) {
|
|
|
1427
1842
|
const routeRequiresFullHydration = routeExplicitlyRequiresHydration ||
|
|
1428
1843
|
routeUsesCells ||
|
|
1429
1844
|
routeUsesReactiveEffect ||
|
|
1845
|
+
routeUsesDomRefs ||
|
|
1430
1846
|
routeHasEventBindings;
|
|
1431
1847
|
const routeUsesOnlyClientReferenceBoundaries = !routeRequiresFullHydration &&
|
|
1432
1848
|
clientReferenceManifest.length > 0 &&
|
|
@@ -1447,7 +1863,7 @@ export async function buildClientRouteEntrySource(options) {
|
|
|
1447
1863
|
? `import { bindCapturedEvent as __mreactBindCapturedEvent } from "@reckona/mreact-reactive-dom/internal";\n`
|
|
1448
1864
|
: "";
|
|
1449
1865
|
const routeReactiveDomMetadataImport = !routeUsesOnlyClientReferenceBoundaries
|
|
1450
|
-
? `${routeCapturedEventImport}import { withEventBindingMetadata as __mreactWithEventBindingMetadata, withPropBindingMetadata as __mreactWithPropBindingMetadata } from "@reckona/mreact-reactive-dom";\n`
|
|
1866
|
+
? `${routeCapturedEventImport}import { ${routeUsesDomRefs ? "getDomRefBindings as __mreactGetDomRefBindings, " : ""}withEventBindingMetadata as __mreactWithEventBindingMetadata, withPropBindingMetadata as __mreactWithPropBindingMetadata } from "@reckona/mreact-reactive-dom";\n`
|
|
1451
1867
|
: "";
|
|
1452
1868
|
const navigationStateDeclaration = inlineClientNavigation
|
|
1453
1869
|
? `const __mreactNavigationState = __mreactGlobal.__mreactNavigationState ??= {
|
|
@@ -1723,9 +2139,10 @@ __mreactGlobal.__mreactRouteCell = (nativeCell, initial) => {
|
|
|
1723
2139
|
__mreactActiveCellIndex = 0;
|
|
1724
2140
|
}
|
|
1725
2141
|
return () => {
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
2142
|
+
__mreactRunLifecycleTasks(
|
|
2143
|
+
Array.from(__mreactRouteEffectDisposers),
|
|
2144
|
+
(__mreactDispose) => __mreactDispose(),
|
|
2145
|
+
);
|
|
1729
2146
|
__mreactRouteEffectDisposers.clear();
|
|
1730
2147
|
};
|
|
1731
2148
|
});
|
|
@@ -1736,13 +2153,33 @@ __mreactGlobal.__mreactRouteCell = (nativeCell, initial) => {
|
|
|
1736
2153
|
? ` __mreactDisposeRoute(__mreactRouteId);
|
|
1737
2154
|
const __mreactRouteEffectDisposers = new Set();
|
|
1738
2155
|
__mreactRouteDisposers.set(__mreactRouteId, () => {
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
2156
|
+
__mreactRunLifecycleTasks(
|
|
2157
|
+
Array.from(__mreactRouteEffectDisposers),
|
|
2158
|
+
(__mreactDispose) => __mreactDispose(),
|
|
2159
|
+
);
|
|
1742
2160
|
__mreactRouteEffectDisposers.clear();
|
|
1743
2161
|
});
|
|
1744
2162
|
`
|
|
1745
2163
|
: "";
|
|
2164
|
+
const routeLifecycleFunctions = `
|
|
2165
|
+
function __mreactRunLifecycleTasks(values, run) {
|
|
2166
|
+
let firstError;
|
|
2167
|
+
|
|
2168
|
+
for (const value of values) {
|
|
2169
|
+
try {
|
|
2170
|
+
run(value);
|
|
2171
|
+
} catch (error) {
|
|
2172
|
+
firstError ??= error;
|
|
2173
|
+
}
|
|
2174
|
+
}
|
|
2175
|
+
|
|
2176
|
+
if (firstError !== undefined) {
|
|
2177
|
+
queueMicrotask(() => {
|
|
2178
|
+
throw firstError;
|
|
2179
|
+
});
|
|
2180
|
+
}
|
|
2181
|
+
}
|
|
2182
|
+
`;
|
|
1746
2183
|
const routeCellDropFunction = routeUsesCells
|
|
1747
2184
|
? `
|
|
1748
2185
|
function __mreactDropMismatchedRouteState(previousState, nextState) {
|
|
@@ -1768,12 +2205,18 @@ function __mreactDisposeRoute(routeId) {
|
|
|
1768
2205
|
}
|
|
1769
2206
|
`
|
|
1770
2207
|
: "";
|
|
1771
|
-
const routeCleanupNavigationDispose =
|
|
1772
|
-
|
|
1773
|
-
|
|
2208
|
+
const routeCleanupNavigationDispose = ` if (currentRouteId !== nextRouteId) {
|
|
2209
|
+
const __mreactRegisteredRouteDisposers = __mreactGlobal.__mreactRouteDisposers;
|
|
2210
|
+
const __mreactRegisteredRouteDispose = __mreactRegisteredRouteDisposers?.get(currentRouteId);
|
|
2211
|
+
if (__mreactRegisteredRouteDispose !== undefined) {
|
|
2212
|
+
__mreactRegisteredRouteDisposers.delete(currentRouteId);
|
|
2213
|
+
__mreactRunLifecycleTasks(
|
|
2214
|
+
[__mreactRegisteredRouteDispose],
|
|
2215
|
+
(__mreactDispose) => __mreactDispose(),
|
|
2216
|
+
);
|
|
2217
|
+
}
|
|
1774
2218
|
}
|
|
1775
|
-
|
|
1776
|
-
: "";
|
|
2219
|
+
`;
|
|
1777
2220
|
const routeNodeResolver = routeUsesCells
|
|
1778
2221
|
? `
|
|
1779
2222
|
function __mreactResolveRouteNode(value) {
|
|
@@ -1812,9 +2255,7 @@ function __mreactResolveRouteNode(value) {
|
|
|
1812
2255
|
const previousDisposers = current.__mreactEventDisposers;
|
|
1813
2256
|
|
|
1814
2257
|
if (Array.isArray(previousDisposers)) {
|
|
1815
|
-
|
|
1816
|
-
dispose();
|
|
1817
|
-
}
|
|
2258
|
+
__mreactRunLifecycleTasks(previousDisposers, (dispose) => dispose());
|
|
1818
2259
|
}
|
|
1819
2260
|
|
|
1820
2261
|
const rawBindings = next.__mreactEventBindings;
|
|
@@ -1843,14 +2284,26 @@ function __mreactResolveRouteNode(value) {
|
|
|
1843
2284
|
const previousDisposers = current.__mreactEventDisposers;
|
|
1844
2285
|
|
|
1845
2286
|
if (Array.isArray(previousDisposers)) {
|
|
1846
|
-
|
|
1847
|
-
dispose();
|
|
1848
|
-
}
|
|
2287
|
+
__mreactRunLifecycleTasks(previousDisposers, (dispose) => dispose());
|
|
1849
2288
|
}
|
|
1850
2289
|
|
|
1851
2290
|
current.__mreactEventDisposers = [];
|
|
1852
2291
|
current.__mreactHasEvents = false;
|
|
1853
2292
|
}
|
|
2293
|
+
`;
|
|
2294
|
+
const routeDomRefBindingSyncFunction = routeUsesDomRefs
|
|
2295
|
+
? `function __mreactSyncDomRefBindings(current, next) {
|
|
2296
|
+
__mreactRunLifecycleTasks(
|
|
2297
|
+
Array.from(__mreactGetDomRefBindings(current)),
|
|
2298
|
+
(binding) => binding.dispose(),
|
|
2299
|
+
);
|
|
2300
|
+
__mreactRunLifecycleTasks(
|
|
2301
|
+
Array.from(__mreactGetDomRefBindings(next)),
|
|
2302
|
+
(binding) => binding.retarget(current),
|
|
2303
|
+
);
|
|
2304
|
+
}
|
|
2305
|
+
`
|
|
2306
|
+
: `function __mreactSyncDomRefBindings() {}
|
|
1854
2307
|
`;
|
|
1855
2308
|
const boundaryOnlyHydrationBlock = routeRequiresFullHydration
|
|
1856
2309
|
? ""
|
|
@@ -1909,6 +2362,7 @@ ${routeCellHydrationIndent}__mreactMarker.setAttribute(__mreactRouteHydratedAttr
|
|
|
1909
2362
|
${routeCellHydrationIndent}__mreactMarkRouteHydrated();
|
|
1910
2363
|
${routeCellHydrationEnd}}
|
|
1911
2364
|
${routeCellDropFunction}
|
|
2365
|
+
${routeLifecycleFunctions}
|
|
1912
2366
|
${routeCleanupFunction}
|
|
1913
2367
|
|
|
1914
2368
|
function __mreactMarkRouteHydrated() {
|
|
@@ -2495,13 +2949,14 @@ function __mreactApplyNavigationHtml(html, url) {
|
|
|
2495
2949
|
const currentRouteId = currentMarker.getAttribute("${routeHydrationContract.routeMarkerAttribute}");
|
|
2496
2950
|
const nextRouteId = nextMarker.getAttribute("${routeHydrationContract.routeMarkerAttribute}");
|
|
2497
2951
|
|
|
2952
|
+
${routeCleanupNavigationDispose}
|
|
2498
2953
|
__mreactMarkRouteHydrating();
|
|
2499
2954
|
__mreactSyncHeadMetadata(template.content, html);
|
|
2500
2955
|
if (!__mreactApplyNavigationShellHtml(currentMarker, nextMarker)) {
|
|
2501
2956
|
__mreactUnmountCompatBoundaries(currentMarker);
|
|
2502
2957
|
__mreactResumeNode(currentMarker, nextMarker);
|
|
2503
2958
|
}
|
|
2504
|
-
|
|
2959
|
+
__mreactSyncRouteDataScripts(template.content, currentRouteId, nextRouteId);
|
|
2505
2960
|
|
|
2506
2961
|
const script = template.content.querySelector('script[type="module"][src]')?.getAttribute("src");
|
|
2507
2962
|
if (script !== null && script !== undefined) {
|
|
@@ -3658,6 +4113,7 @@ function __mreactResumeNode(current, next) {
|
|
|
3658
4113
|
}
|
|
3659
4114
|
|
|
3660
4115
|
__mreactSyncEventBindings(current, next);
|
|
4116
|
+
__mreactSyncDomRefBindings(current, next);
|
|
3661
4117
|
__mreactSyncAttributes(current, next);
|
|
3662
4118
|
__mreactSyncPropBindings(current, next);
|
|
3663
4119
|
__mreactResumeChildren(current, next);
|
|
@@ -3680,6 +4136,7 @@ function __mreactShouldReplaceNode(current, next) {
|
|
|
3680
4136
|
}
|
|
3681
4137
|
|
|
3682
4138
|
${routeEventBindingSyncFunction}
|
|
4139
|
+
${routeDomRefBindingSyncFunction}
|
|
3683
4140
|
|
|
3684
4141
|
function __mreactSyncAttributes(current, next) {
|
|
3685
4142
|
for (const attribute of Array.from(current.attributes)) {
|
|
@@ -3699,9 +4156,7 @@ function __mreactSyncPropBindings(current, next) {
|
|
|
3699
4156
|
const previousBindings = current.__mreactPropBindings;
|
|
3700
4157
|
|
|
3701
4158
|
if (Array.isArray(previousBindings)) {
|
|
3702
|
-
|
|
3703
|
-
binding.dispose?.();
|
|
3704
|
-
}
|
|
4159
|
+
__mreactRunLifecycleTasks(previousBindings, (binding) => binding.dispose?.());
|
|
3705
4160
|
}
|
|
3706
4161
|
|
|
3707
4162
|
const bindings = next.__mreactPropBindings;
|
|
@@ -3717,9 +4172,7 @@ function __mreactSyncPropBindings(current, next) {
|
|
|
3717
4172
|
next.__mreactPropBindings = [];
|
|
3718
4173
|
next.__mreactHasReactiveProps = false;
|
|
3719
4174
|
|
|
3720
|
-
|
|
3721
|
-
binding.retarget?.(current);
|
|
3722
|
-
}
|
|
4175
|
+
__mreactRunLifecycleTasks(bindings, (binding) => binding.retarget?.(current));
|
|
3723
4176
|
}
|
|
3724
4177
|
|
|
3725
4178
|
function __mreactResumeChildren(current, next) {
|
|
@@ -3885,22 +4338,33 @@ export function invalidateReactiveDevtoolsCache() {}
|
|
|
3885
4338
|
export function prepareReactiveEffectRunDevtoolsEvent() { return undefined; }`,
|
|
3886
4339
|
loader: "ts",
|
|
3887
4340
|
}));
|
|
4341
|
+
if (options.sourceRegionModulePaths !== undefined) {
|
|
4342
|
+
buildApi.onLoad({ filter: /.*/ }, (args) => {
|
|
4343
|
+
if (isAbsolute(args.path) &&
|
|
4344
|
+
isRouteClientDependencySourcePath(args.path, routeFiles) &&
|
|
4345
|
+
!runtimePackageDirs.some((runtimePackageDir) => args.path.startsWith(`${runtimePackageDir}${sep}`))) {
|
|
4346
|
+
options.sourceRegionModulePaths?.add(args.path);
|
|
4347
|
+
}
|
|
4348
|
+
return undefined;
|
|
4349
|
+
});
|
|
4350
|
+
}
|
|
3888
4351
|
buildApi.onLoad({ filter: /\.(?:mreact\.)?[cm]?[jt]sx$/ }, async (args) => {
|
|
3889
4352
|
if (!isRouteClientDependencySourcePath(args.path, routeFiles)) {
|
|
3890
4353
|
return undefined;
|
|
3891
4354
|
}
|
|
3892
4355
|
const source = await readFile(args.path, "utf8");
|
|
4356
|
+
const compilerFilename = options.debugLabels ? basename(args.path) : args.path;
|
|
3893
4357
|
const moduleContext = createCompilerModuleContext({
|
|
3894
4358
|
code: source,
|
|
3895
|
-
filename:
|
|
4359
|
+
filename: compilerFilename,
|
|
3896
4360
|
});
|
|
3897
4361
|
if (!hasJsxSyntax(moduleContext.program)) {
|
|
3898
4362
|
return undefined;
|
|
3899
4363
|
}
|
|
3900
4364
|
const output = transformCompilerModuleContext({
|
|
3901
4365
|
code: source,
|
|
3902
|
-
dev:
|
|
3903
|
-
filename:
|
|
4366
|
+
dev: options.debugLabels,
|
|
4367
|
+
filename: compilerFilename,
|
|
3904
4368
|
mode: isCompatSourcePath(args.path) ? "compat" : "reactive",
|
|
3905
4369
|
moduleContext,
|
|
3906
4370
|
target: "client",
|