@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/src/client.ts
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 {
|
|
6
6
|
analyzeBoundaryGraph,
|
|
7
7
|
collectClientRouteModuleAnalysis,
|
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
type BoundaryGraphResult,
|
|
11
11
|
type ClientRouteModuleAnalysis,
|
|
12
12
|
type ClientRouteStaticImportReference,
|
|
13
|
+
type StaticExportReference,
|
|
13
14
|
type StaticImportReference,
|
|
14
15
|
type TopLevelExportRenderInfo,
|
|
15
16
|
} from "@reckona/mreact-compiler";
|
|
@@ -68,6 +69,7 @@ export interface ClientRouteManifestEntry {
|
|
|
68
69
|
export interface BuildClientRouteOutputOptions {
|
|
69
70
|
cacheDir?: string | undefined;
|
|
70
71
|
code: string;
|
|
72
|
+
debugLabels?: boolean | undefined;
|
|
71
73
|
clientBoundaryImports?: readonly string[] | undefined;
|
|
72
74
|
clientReferenceImports?: readonly ClientReferenceImport[] | undefined;
|
|
73
75
|
clientReferenceManifest?: readonly ClientReferenceMetadata[] | undefined;
|
|
@@ -117,10 +119,37 @@ export interface ClientRouteInferenceResult {
|
|
|
117
119
|
client: boolean;
|
|
118
120
|
clientBoundaryImports: string[];
|
|
119
121
|
clientBoundaryFallbackImports: string[];
|
|
122
|
+
components?: ClientRouteComponent[] | undefined;
|
|
120
123
|
diagnostics: ClientRouteInferenceDiagnostic[];
|
|
121
124
|
}
|
|
122
125
|
|
|
126
|
+
export type ClientRouteComponentClassification =
|
|
127
|
+
| "client-boundary"
|
|
128
|
+
| "client-route"
|
|
129
|
+
| "server-only"
|
|
130
|
+
| "server-render"
|
|
131
|
+
| "shared"
|
|
132
|
+
| "unknown";
|
|
133
|
+
|
|
134
|
+
export type ClientRouteComponentOrigin =
|
|
135
|
+
| "client-filename"
|
|
136
|
+
| "compat-filename"
|
|
137
|
+
| "inferred-client-runtime"
|
|
138
|
+
| "server-only-import"
|
|
139
|
+
| "server-render"
|
|
140
|
+
| "unresolved-reference"
|
|
141
|
+
| "use-client-directive"
|
|
142
|
+
| "use-server-directive";
|
|
143
|
+
|
|
144
|
+
export interface ClientRouteComponent {
|
|
145
|
+
classification: ClientRouteComponentClassification;
|
|
146
|
+
exportName: string;
|
|
147
|
+
file: string;
|
|
148
|
+
origin: ClientRouteComponentOrigin;
|
|
149
|
+
}
|
|
150
|
+
|
|
123
151
|
interface ClientRouteModuleInferenceResult extends ClientRouteInferenceResult {
|
|
152
|
+
availableExportNames: string[];
|
|
124
153
|
boundaryGraphFallbackCandidate: boolean;
|
|
125
154
|
boundaryGraphFallbackRequired: boolean;
|
|
126
155
|
clientBoundaryExportNames: string[];
|
|
@@ -133,6 +162,28 @@ interface ClientRouteModuleInferenceResult extends ClientRouteInferenceResult {
|
|
|
133
162
|
usesNavigationLink: boolean;
|
|
134
163
|
}
|
|
135
164
|
|
|
165
|
+
interface ClientRouteComponentCollector {
|
|
166
|
+
clientReachable: Set<string>;
|
|
167
|
+
components: Map<string, ClientRouteComponent>;
|
|
168
|
+
localExportNamesByFile: Map<string, Set<string>>;
|
|
169
|
+
pendingExportValidations: ClientRoutePendingExportValidation[];
|
|
170
|
+
reachable: Set<string>;
|
|
171
|
+
staticExportEdges: ClientRouteStaticExportEdge[];
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
interface ClientRoutePendingExportValidation {
|
|
175
|
+
exportNames: string[];
|
|
176
|
+
file: string;
|
|
177
|
+
importer: string;
|
|
178
|
+
source: string;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
interface ClientRouteStaticExportEdge {
|
|
182
|
+
file: string;
|
|
183
|
+
reference: StaticExportReference;
|
|
184
|
+
resolved: string;
|
|
185
|
+
}
|
|
186
|
+
|
|
136
187
|
export interface ClientReferenceImport {
|
|
137
188
|
exportName: string;
|
|
138
189
|
importSource: string;
|
|
@@ -147,10 +198,11 @@ export interface ClientRouteReferenceResult extends ClientRouteInferenceResult {
|
|
|
147
198
|
|
|
148
199
|
export interface ClientRouteInferenceDiagnostic {
|
|
149
200
|
code:
|
|
150
|
-
|
|
|
151
|
-
|
|
|
152
|
-
|
|
|
153
|
-
|
|
|
201
|
+
| "MR_CLIENT_BOUNDARY_INFERENCE_SERVER_ONLY_REFERENCE"
|
|
202
|
+
| "MR_CLIENT_BOUNDARY_INFERENCE_FUNCTION_CALL_INTERACTIVE"
|
|
203
|
+
| "MR_CLIENT_BOUNDARY_INFERENCE_UNRESOLVED_REFERENCE"
|
|
204
|
+
| "MR_CLIENT_BOUNDARY_INFERENCE_UNSUPPORTED_REFERENCE"
|
|
205
|
+
| "MR_NAVIGATION_RUNTIME_LINK_DISABLED";
|
|
154
206
|
filename: string;
|
|
155
207
|
level: "warn";
|
|
156
208
|
localNames: string[];
|
|
@@ -217,6 +269,7 @@ export async function inferClientRouteModule(options: {
|
|
|
217
269
|
appDir?: string | undefined;
|
|
218
270
|
cache?: ClientRouteInferenceCache | undefined;
|
|
219
271
|
code: string;
|
|
272
|
+
collectComponents?: boolean | undefined;
|
|
220
273
|
filename: string;
|
|
221
274
|
moduleContext?: CompilerModuleContext | undefined;
|
|
222
275
|
routePath?: string | undefined;
|
|
@@ -224,6 +277,16 @@ export async function inferClientRouteModule(options: {
|
|
|
224
277
|
}): Promise<ClientRouteInferenceResult> {
|
|
225
278
|
const cache = options.cache ?? createClientRouteInferenceCache();
|
|
226
279
|
const sourceTransform = clientRouteSourceTransformForVitePlugins(options.vitePlugins);
|
|
280
|
+
const componentCollector: ClientRouteComponentCollector | undefined = options.collectComponents
|
|
281
|
+
? {
|
|
282
|
+
clientReachable: new Set(),
|
|
283
|
+
components: new Map(),
|
|
284
|
+
localExportNamesByFile: new Map(),
|
|
285
|
+
pendingExportValidations: [],
|
|
286
|
+
reachable: new Set(),
|
|
287
|
+
staticExportEdges: [],
|
|
288
|
+
}
|
|
289
|
+
: undefined;
|
|
227
290
|
const code = await transformClientRouteSource({
|
|
228
291
|
code: options.code,
|
|
229
292
|
filename: options.filename,
|
|
@@ -234,9 +297,11 @@ export async function inferClientRouteModule(options: {
|
|
|
234
297
|
const routeInference = await inferClientRouteModuleSource({
|
|
235
298
|
cache,
|
|
236
299
|
code,
|
|
300
|
+
componentCollector,
|
|
237
301
|
filename: options.filename,
|
|
238
302
|
...(sourceTransform === undefined ? { moduleContext: options.moduleContext } : {}),
|
|
239
303
|
root: true,
|
|
304
|
+
routeEntry: true,
|
|
240
305
|
seen: new Set(),
|
|
241
306
|
sourceTransform,
|
|
242
307
|
});
|
|
@@ -253,15 +318,29 @@ export async function inferClientRouteModule(options: {
|
|
|
253
318
|
: routeInference;
|
|
254
319
|
|
|
255
320
|
if (options.appDir === undefined) {
|
|
256
|
-
|
|
321
|
+
const exportDiagnostics = finalizeClientRouteComponentExportValidations(componentCollector);
|
|
322
|
+
return withClientRouteDiagnosticPath(
|
|
323
|
+
{
|
|
324
|
+
...mergedRouteInference,
|
|
325
|
+
...(componentCollector === undefined
|
|
326
|
+
? {}
|
|
327
|
+
: {
|
|
328
|
+
components: normalizedClientRouteComponents(componentCollector, options.filename),
|
|
329
|
+
}),
|
|
330
|
+
diagnostics: [...mergedRouteInference.diagnostics, ...exportDiagnostics],
|
|
331
|
+
},
|
|
332
|
+
options.routePath,
|
|
333
|
+
);
|
|
257
334
|
}
|
|
258
335
|
|
|
259
336
|
const shellInferences = await inferClientRouteShellModules({
|
|
260
337
|
appDir: options.appDir,
|
|
261
338
|
cache,
|
|
339
|
+
componentCollector,
|
|
262
340
|
filename: options.filename,
|
|
263
341
|
sourceTransform,
|
|
264
342
|
});
|
|
343
|
+
const exportDiagnostics = finalizeClientRouteComponentExportValidations(componentCollector);
|
|
265
344
|
|
|
266
345
|
return withClientRouteDiagnosticPath(
|
|
267
346
|
{
|
|
@@ -269,9 +348,15 @@ export async function inferClientRouteModule(options: {
|
|
|
269
348
|
mergedRouteInference.client || shellInferences.some((inference) => inference.client),
|
|
270
349
|
clientBoundaryImports: mergedRouteInference.clientBoundaryImports,
|
|
271
350
|
clientBoundaryFallbackImports: mergedRouteInference.clientBoundaryFallbackImports,
|
|
351
|
+
...(componentCollector === undefined
|
|
352
|
+
? {}
|
|
353
|
+
: {
|
|
354
|
+
components: normalizedClientRouteComponents(componentCollector, options.filename),
|
|
355
|
+
}),
|
|
272
356
|
diagnostics: [
|
|
273
357
|
...mergedRouteInference.diagnostics,
|
|
274
358
|
...shellInferences.flatMap((inference) => inference.diagnostics),
|
|
359
|
+
...exportDiagnostics,
|
|
275
360
|
],
|
|
276
361
|
},
|
|
277
362
|
options.routePath,
|
|
@@ -376,6 +461,7 @@ export async function collectClientRouteReferences(options: {
|
|
|
376
461
|
filename: options.filename,
|
|
377
462
|
moduleContext: routeModuleContext,
|
|
378
463
|
root: true,
|
|
464
|
+
routeEntry: true,
|
|
379
465
|
seen: new Set(),
|
|
380
466
|
sourceTransform,
|
|
381
467
|
});
|
|
@@ -412,6 +498,7 @@ export async function collectClientRouteReferences(options: {
|
|
|
412
498
|
filename: sourceOptions.filename,
|
|
413
499
|
moduleContext,
|
|
414
500
|
root: true,
|
|
501
|
+
routeEntry: false,
|
|
415
502
|
seen: new Set(),
|
|
416
503
|
sourceTransform,
|
|
417
504
|
}));
|
|
@@ -458,6 +545,7 @@ export async function collectClientRouteReferences(options: {
|
|
|
458
545
|
filename: shell,
|
|
459
546
|
moduleContext,
|
|
460
547
|
root: true,
|
|
548
|
+
routeEntry: false,
|
|
461
549
|
seen: new Set(),
|
|
462
550
|
sourceTransform,
|
|
463
551
|
}),
|
|
@@ -603,6 +691,7 @@ export function navigationRuntimeLinkDisabledDiagnostic(options: {
|
|
|
603
691
|
async function inferClientRouteShellModules(options: {
|
|
604
692
|
appDir: string;
|
|
605
693
|
cache: ClientRouteInferenceCache;
|
|
694
|
+
componentCollector?: ClientRouteComponentCollector | undefined;
|
|
606
695
|
filename: string;
|
|
607
696
|
sourceTransform?: ClientRouteSourceTransform | undefined;
|
|
608
697
|
}): Promise<ClientRouteInferenceResult[]> {
|
|
@@ -619,8 +708,10 @@ async function inferClientRouteShellModules(options: {
|
|
|
619
708
|
return await inferClientRouteModuleSource({
|
|
620
709
|
cache: options.cache,
|
|
621
710
|
code,
|
|
711
|
+
componentCollector: options.componentCollector,
|
|
622
712
|
filename: shell,
|
|
623
713
|
root: true,
|
|
714
|
+
routeEntry: false,
|
|
624
715
|
seen: new Set(),
|
|
625
716
|
sourceTransform: options.sourceTransform,
|
|
626
717
|
});
|
|
@@ -661,6 +752,380 @@ export function isClientRouteSource(code: string): boolean {
|
|
|
661
752
|
);
|
|
662
753
|
}
|
|
663
754
|
|
|
755
|
+
function collectClientRouteComponentsForModule(
|
|
756
|
+
collector: ClientRouteComponentCollector | undefined,
|
|
757
|
+
options: {
|
|
758
|
+
analysis: ClientRouteModuleAnalysis;
|
|
759
|
+
filename: string;
|
|
760
|
+
root: boolean;
|
|
761
|
+
routeEntry: boolean;
|
|
762
|
+
},
|
|
763
|
+
): void {
|
|
764
|
+
if (collector === undefined) {
|
|
765
|
+
return;
|
|
766
|
+
}
|
|
767
|
+
|
|
768
|
+
if (options.root) {
|
|
769
|
+
markClientRouteComponentReachable(collector, options.filename, ["default"]);
|
|
770
|
+
}
|
|
771
|
+
|
|
772
|
+
const localExportNames =
|
|
773
|
+
collector.localExportNamesByFile.get(options.filename) ?? new Set<string>();
|
|
774
|
+
for (const info of options.analysis.topLevelExportRenderInfo) {
|
|
775
|
+
localExportNames.add(info.name);
|
|
776
|
+
}
|
|
777
|
+
collector.localExportNamesByFile.set(options.filename, localExportNames);
|
|
778
|
+
|
|
779
|
+
const serverOnly =
|
|
780
|
+
options.analysis.hasUseServerDirective || hasServerOnlyImports(options.analysis);
|
|
781
|
+
const explicitClient = isExplicitClientRouteSource(options.analysis, options.filename);
|
|
782
|
+
|
|
783
|
+
for (const info of options.analysis.topLevelExportRenderInfo) {
|
|
784
|
+
const component = {
|
|
785
|
+
classification: serverOnly
|
|
786
|
+
? "server-only"
|
|
787
|
+
: explicitClient || info.clientRuntime
|
|
788
|
+
? options.routeEntry && info.name === "default"
|
|
789
|
+
? "client-route"
|
|
790
|
+
: "client-boundary"
|
|
791
|
+
: "server-render",
|
|
792
|
+
exportName: info.name,
|
|
793
|
+
file: options.filename,
|
|
794
|
+
origin: clientRouteComponentOrigin({
|
|
795
|
+
analysis: options.analysis,
|
|
796
|
+
filename: options.filename,
|
|
797
|
+
info,
|
|
798
|
+
serverOnly,
|
|
799
|
+
}),
|
|
800
|
+
} satisfies ClientRouteComponent;
|
|
801
|
+
collector.components.set(
|
|
802
|
+
clientRouteComponentKey(component.file, component.exportName),
|
|
803
|
+
component,
|
|
804
|
+
);
|
|
805
|
+
}
|
|
806
|
+
|
|
807
|
+
for (const info of options.analysis.topLevelExportRenderInfo) {
|
|
808
|
+
if (!isClientRouteComponentReachable(collector, options.filename, info.name)) {
|
|
809
|
+
continue;
|
|
810
|
+
}
|
|
811
|
+
|
|
812
|
+
const renderedNames = new Set([
|
|
813
|
+
...(options.analysis.reachableExportRenderedComponentNames[info.name] ?? []),
|
|
814
|
+
...(options.analysis.reachableExportRenderedComponentRoots[info.name] ?? []),
|
|
815
|
+
]);
|
|
816
|
+
|
|
817
|
+
for (const rendered of options.analysis.topLevelExportRenderInfo) {
|
|
818
|
+
if (
|
|
819
|
+
rendered.name !== "default" &&
|
|
820
|
+
(renderedNames.has(rendered.name) || renderedNames.has(rendered.localName ?? rendered.name))
|
|
821
|
+
) {
|
|
822
|
+
markClientRouteComponentReachable(collector, options.filename, [rendered.name], {
|
|
823
|
+
clientExecution: clientRouteComponentRunsOnClient(collector, options.filename, info.name),
|
|
824
|
+
});
|
|
825
|
+
}
|
|
826
|
+
}
|
|
827
|
+
}
|
|
828
|
+
}
|
|
829
|
+
|
|
830
|
+
function clientRouteComponentOrigin(options: {
|
|
831
|
+
analysis: ClientRouteModuleAnalysis;
|
|
832
|
+
filename: string;
|
|
833
|
+
info: TopLevelExportRenderInfo;
|
|
834
|
+
serverOnly: boolean;
|
|
835
|
+
}): ClientRouteComponentOrigin {
|
|
836
|
+
if (options.analysis.hasUseServerDirective) {
|
|
837
|
+
return "use-server-directive";
|
|
838
|
+
}
|
|
839
|
+
|
|
840
|
+
if (options.serverOnly) {
|
|
841
|
+
return "server-only-import";
|
|
842
|
+
}
|
|
843
|
+
|
|
844
|
+
if (options.analysis.hasUseClientDirective) {
|
|
845
|
+
return "use-client-directive";
|
|
846
|
+
}
|
|
847
|
+
|
|
848
|
+
if (/\.compat(?:\.mreact)?\.[cm]?[jt]sx?$/.test(options.filename)) {
|
|
849
|
+
return "compat-filename";
|
|
850
|
+
}
|
|
851
|
+
|
|
852
|
+
if (/\.client(?:\.mreact)?\.[cm]?[jt]sx?$/.test(options.filename)) {
|
|
853
|
+
return "client-filename";
|
|
854
|
+
}
|
|
855
|
+
|
|
856
|
+
return options.info.clientRuntime ? "inferred-client-runtime" : "server-render";
|
|
857
|
+
}
|
|
858
|
+
|
|
859
|
+
function normalizedClientRouteComponents(
|
|
860
|
+
collector: ClientRouteComponentCollector,
|
|
861
|
+
routeFile: string,
|
|
862
|
+
): ClientRouteComponent[] {
|
|
863
|
+
return Array.from(collector.components.values())
|
|
864
|
+
.filter(
|
|
865
|
+
(component) =>
|
|
866
|
+
collector.reachable.has(clientRouteComponentKey(component.file, component.exportName)) ||
|
|
867
|
+
collector.reachable.has(clientRouteComponentKey(component.file, "*")),
|
|
868
|
+
)
|
|
869
|
+
.map((component) =>
|
|
870
|
+
component.classification === "server-render" &&
|
|
871
|
+
(collector.clientReachable.has(
|
|
872
|
+
clientRouteComponentKey(component.file, component.exportName),
|
|
873
|
+
) ||
|
|
874
|
+
collector.clientReachable.has(clientRouteComponentKey(component.file, "*")))
|
|
875
|
+
? { ...component, classification: "shared" as const }
|
|
876
|
+
: component,
|
|
877
|
+
)
|
|
878
|
+
.sort((left, right) => {
|
|
879
|
+
const leftRoute = left.file === routeFile && left.exportName === "default";
|
|
880
|
+
const rightRoute = right.file === routeFile && right.exportName === "default";
|
|
881
|
+
|
|
882
|
+
if (leftRoute !== rightRoute) {
|
|
883
|
+
return leftRoute ? -1 : 1;
|
|
884
|
+
}
|
|
885
|
+
|
|
886
|
+
return left.file === right.file
|
|
887
|
+
? left.exportName === right.exportName
|
|
888
|
+
? left.classification.localeCompare(right.classification)
|
|
889
|
+
: left.exportName.localeCompare(right.exportName)
|
|
890
|
+
: left.file.localeCompare(right.file);
|
|
891
|
+
});
|
|
892
|
+
}
|
|
893
|
+
|
|
894
|
+
function clientRouteComponentKey(file: string, exportName: string): string {
|
|
895
|
+
return `${file}\0${exportName}`;
|
|
896
|
+
}
|
|
897
|
+
|
|
898
|
+
function markClientRouteComponentReachable(
|
|
899
|
+
collector: ClientRouteComponentCollector | undefined,
|
|
900
|
+
file: string,
|
|
901
|
+
exportNames: readonly string[] | undefined,
|
|
902
|
+
options: { clientExecution?: boolean | undefined } = {},
|
|
903
|
+
): void {
|
|
904
|
+
if (collector === undefined) {
|
|
905
|
+
return;
|
|
906
|
+
}
|
|
907
|
+
|
|
908
|
+
if (exportNames === undefined) {
|
|
909
|
+
collector.reachable.add(clientRouteComponentKey(file, "*"));
|
|
910
|
+
if (options.clientExecution === true) {
|
|
911
|
+
collector.clientReachable.add(clientRouteComponentKey(file, "*"));
|
|
912
|
+
}
|
|
913
|
+
return;
|
|
914
|
+
}
|
|
915
|
+
|
|
916
|
+
for (const exportName of exportNames) {
|
|
917
|
+
const key = clientRouteComponentKey(file, exportName);
|
|
918
|
+
collector.reachable.add(key);
|
|
919
|
+
if (options.clientExecution === true) {
|
|
920
|
+
collector.clientReachable.add(key);
|
|
921
|
+
}
|
|
922
|
+
}
|
|
923
|
+
}
|
|
924
|
+
|
|
925
|
+
function clientRouteComponentRunsOnClient(
|
|
926
|
+
collector: ClientRouteComponentCollector | undefined,
|
|
927
|
+
file: string,
|
|
928
|
+
exportName: string,
|
|
929
|
+
): boolean {
|
|
930
|
+
if (collector === undefined) {
|
|
931
|
+
return false;
|
|
932
|
+
}
|
|
933
|
+
|
|
934
|
+
const key = clientRouteComponentKey(file, exportName);
|
|
935
|
+
const component = collector.components.get(key);
|
|
936
|
+
return (
|
|
937
|
+
component?.classification === "client-boundary" ||
|
|
938
|
+
component?.classification === "client-route" ||
|
|
939
|
+
component?.classification === "shared" ||
|
|
940
|
+
collector.clientReachable.has(key) ||
|
|
941
|
+
collector.clientReachable.has(clientRouteComponentKey(file, "*"))
|
|
942
|
+
);
|
|
943
|
+
}
|
|
944
|
+
|
|
945
|
+
function isClientRouteComponentReachable(
|
|
946
|
+
collector: ClientRouteComponentCollector | undefined,
|
|
947
|
+
file: string,
|
|
948
|
+
exportName: string,
|
|
949
|
+
): boolean {
|
|
950
|
+
return (
|
|
951
|
+
collector === undefined ||
|
|
952
|
+
collector.reachable.has(clientRouteComponentKey(file, exportName)) ||
|
|
953
|
+
collector.reachable.has(clientRouteComponentKey(file, "*"))
|
|
954
|
+
);
|
|
955
|
+
}
|
|
956
|
+
|
|
957
|
+
function propagateClientRouteComponentStaticExport(
|
|
958
|
+
collector: ClientRouteComponentCollector | undefined,
|
|
959
|
+
file: string,
|
|
960
|
+
resolved: string,
|
|
961
|
+
reference: StaticExportReference,
|
|
962
|
+
): void {
|
|
963
|
+
if (collector === undefined) {
|
|
964
|
+
return;
|
|
965
|
+
}
|
|
966
|
+
|
|
967
|
+
const wildcardReachable = collector.reachable.has(clientRouteComponentKey(file, "*"));
|
|
968
|
+
const wildcardClientExecution = clientRouteComponentRunsOnClient(collector, file, "*");
|
|
969
|
+
|
|
970
|
+
if (reference.exportAll) {
|
|
971
|
+
if (wildcardReachable) {
|
|
972
|
+
markClientRouteComponentReachable(collector, resolved, undefined, {
|
|
973
|
+
clientExecution: wildcardClientExecution,
|
|
974
|
+
});
|
|
975
|
+
}
|
|
976
|
+
|
|
977
|
+
for (const key of collector.reachable) {
|
|
978
|
+
const [reachableFile, exportName] = key.split("\0");
|
|
979
|
+
|
|
980
|
+
if (reachableFile === file && exportName !== undefined && exportName !== "*") {
|
|
981
|
+
markClientRouteComponentReachable(collector, resolved, [exportName], {
|
|
982
|
+
clientExecution: clientRouteComponentRunsOnClient(collector, file, exportName),
|
|
983
|
+
});
|
|
984
|
+
}
|
|
985
|
+
}
|
|
986
|
+
return;
|
|
987
|
+
}
|
|
988
|
+
|
|
989
|
+
for (const specifier of reference.specifiers) {
|
|
990
|
+
if (
|
|
991
|
+
wildcardReachable ||
|
|
992
|
+
collector.reachable.has(clientRouteComponentKey(file, specifier.exportedName))
|
|
993
|
+
) {
|
|
994
|
+
markClientRouteComponentReachable(collector, resolved, [specifier.localName], {
|
|
995
|
+
clientExecution:
|
|
996
|
+
wildcardClientExecution ||
|
|
997
|
+
clientRouteComponentRunsOnClient(collector, file, specifier.exportedName),
|
|
998
|
+
});
|
|
999
|
+
}
|
|
1000
|
+
}
|
|
1001
|
+
|
|
1002
|
+
if (reference.specifiers.length === 0) {
|
|
1003
|
+
for (const exportName of reference.exportedNames) {
|
|
1004
|
+
if (wildcardReachable || collector.reachable.has(clientRouteComponentKey(file, exportName))) {
|
|
1005
|
+
markClientRouteComponentReachable(collector, resolved, [exportName], {
|
|
1006
|
+
clientExecution:
|
|
1007
|
+
wildcardClientExecution ||
|
|
1008
|
+
clientRouteComponentRunsOnClient(collector, file, exportName),
|
|
1009
|
+
});
|
|
1010
|
+
}
|
|
1011
|
+
}
|
|
1012
|
+
}
|
|
1013
|
+
}
|
|
1014
|
+
|
|
1015
|
+
function collectUnknownClientRouteComponents(
|
|
1016
|
+
collector: ClientRouteComponentCollector | undefined,
|
|
1017
|
+
options: {
|
|
1018
|
+
exportNames: readonly string[] | undefined;
|
|
1019
|
+
file: string;
|
|
1020
|
+
},
|
|
1021
|
+
): void {
|
|
1022
|
+
if (collector === undefined) {
|
|
1023
|
+
return;
|
|
1024
|
+
}
|
|
1025
|
+
|
|
1026
|
+
for (const exportName of options.exportNames ?? ["*"]) {
|
|
1027
|
+
const component = {
|
|
1028
|
+
classification: "unknown",
|
|
1029
|
+
exportName,
|
|
1030
|
+
file: options.file,
|
|
1031
|
+
origin: "unresolved-reference",
|
|
1032
|
+
} satisfies ClientRouteComponent;
|
|
1033
|
+
collector.components.set(
|
|
1034
|
+
clientRouteComponentKey(component.file, component.exportName),
|
|
1035
|
+
component,
|
|
1036
|
+
);
|
|
1037
|
+
markClientRouteComponentReachable(collector, component.file, [component.exportName]);
|
|
1038
|
+
}
|
|
1039
|
+
}
|
|
1040
|
+
|
|
1041
|
+
function collectClientRoutePendingExportValidation(
|
|
1042
|
+
collector: ClientRouteComponentCollector | undefined,
|
|
1043
|
+
options: ClientRoutePendingExportValidation,
|
|
1044
|
+
): void {
|
|
1045
|
+
if (collector === undefined || options.exportNames.length === 0) {
|
|
1046
|
+
return;
|
|
1047
|
+
}
|
|
1048
|
+
|
|
1049
|
+
collector.pendingExportValidations.push(options);
|
|
1050
|
+
}
|
|
1051
|
+
|
|
1052
|
+
function collectClientRouteStaticExportEdge(
|
|
1053
|
+
collector: ClientRouteComponentCollector | undefined,
|
|
1054
|
+
options: ClientRouteStaticExportEdge,
|
|
1055
|
+
): void {
|
|
1056
|
+
collector?.staticExportEdges.push(options);
|
|
1057
|
+
}
|
|
1058
|
+
|
|
1059
|
+
function finalizeClientRouteComponentExportValidations(
|
|
1060
|
+
collector: ClientRouteComponentCollector | undefined,
|
|
1061
|
+
): ClientRouteInferenceDiagnostic[] {
|
|
1062
|
+
if (collector === undefined) {
|
|
1063
|
+
return [];
|
|
1064
|
+
}
|
|
1065
|
+
|
|
1066
|
+
const exportNamesByFile = new Map<string, Set<string>>();
|
|
1067
|
+
for (const [file, names] of collector.localExportNamesByFile) {
|
|
1068
|
+
exportNamesByFile.set(file, new Set(names));
|
|
1069
|
+
}
|
|
1070
|
+
|
|
1071
|
+
let changed = true;
|
|
1072
|
+
while (changed) {
|
|
1073
|
+
changed = false;
|
|
1074
|
+
|
|
1075
|
+
for (const edge of collector.staticExportEdges) {
|
|
1076
|
+
const exportedNames = exportNamesByFile.get(edge.file) ?? new Set<string>();
|
|
1077
|
+
const sourceNames = exportNamesByFile.get(edge.resolved) ?? new Set<string>();
|
|
1078
|
+
const namesToAdd = edge.reference.exportAll
|
|
1079
|
+
? new Set([...sourceNames].filter((exportName) => exportName !== "default"))
|
|
1080
|
+
: new Set(
|
|
1081
|
+
edge.reference.specifiers
|
|
1082
|
+
.filter((specifier) => sourceNames.has(specifier.localName))
|
|
1083
|
+
.map((specifier) => specifier.exportedName),
|
|
1084
|
+
);
|
|
1085
|
+
|
|
1086
|
+
for (const exportName of namesToAdd) {
|
|
1087
|
+
if (!exportedNames.has(exportName)) {
|
|
1088
|
+
exportedNames.add(exportName);
|
|
1089
|
+
changed = true;
|
|
1090
|
+
}
|
|
1091
|
+
}
|
|
1092
|
+
|
|
1093
|
+
exportNamesByFile.set(edge.file, exportedNames);
|
|
1094
|
+
}
|
|
1095
|
+
}
|
|
1096
|
+
|
|
1097
|
+
const diagnostics: ClientRouteInferenceDiagnostic[] = [];
|
|
1098
|
+
const seen = new Set<string>();
|
|
1099
|
+
for (const pending of collector.pendingExportValidations) {
|
|
1100
|
+
const availableExportNames = exportNamesByFile.get(pending.file) ?? new Set<string>();
|
|
1101
|
+
const missingExportNames = pending.exportNames.filter(
|
|
1102
|
+
(exportName) => !availableExportNames.has(exportName),
|
|
1103
|
+
);
|
|
1104
|
+
if (missingExportNames.length === 0) {
|
|
1105
|
+
continue;
|
|
1106
|
+
}
|
|
1107
|
+
|
|
1108
|
+
const key = `${pending.importer}\0${pending.source}\0${missingExportNames.join("\0")}`;
|
|
1109
|
+
if (seen.has(key)) {
|
|
1110
|
+
continue;
|
|
1111
|
+
}
|
|
1112
|
+
seen.add(key);
|
|
1113
|
+
collectUnknownClientRouteComponents(collector, {
|
|
1114
|
+
exportNames: missingExportNames,
|
|
1115
|
+
file: pending.file,
|
|
1116
|
+
});
|
|
1117
|
+
diagnostics.push(
|
|
1118
|
+
unresolvedClientRouteReferenceDiagnostic({
|
|
1119
|
+
exportNames: missingExportNames,
|
|
1120
|
+
filename: pending.importer,
|
|
1121
|
+
source: pending.source,
|
|
1122
|
+
}),
|
|
1123
|
+
);
|
|
1124
|
+
}
|
|
1125
|
+
|
|
1126
|
+
return diagnostics;
|
|
1127
|
+
}
|
|
1128
|
+
|
|
664
1129
|
function isExplicitClientRouteSource(
|
|
665
1130
|
analysis: ClientRouteModuleAnalysis,
|
|
666
1131
|
filename: string,
|
|
@@ -687,33 +1152,49 @@ function hasServerOnlyImports(analysis: ClientRouteModuleAnalysis): boolean {
|
|
|
687
1152
|
async function inferClientRouteModuleSource(options: {
|
|
688
1153
|
cache: ClientRouteInferenceCache;
|
|
689
1154
|
code: string;
|
|
1155
|
+
componentCollector?: ClientRouteComponentCollector | undefined;
|
|
690
1156
|
filename: string;
|
|
691
1157
|
moduleContext?: CompilerModuleContext | undefined;
|
|
692
1158
|
root: boolean;
|
|
1159
|
+
routeEntry: boolean;
|
|
693
1160
|
seen: Set<string>;
|
|
694
1161
|
sourceTransform?: ClientRouteSourceTransform | undefined;
|
|
695
1162
|
}): Promise<ClientRouteModuleInferenceResult> {
|
|
696
1163
|
const analysis = await clientRouteModuleAnalysisForSource(options);
|
|
697
1164
|
const usesNavigationLinkLocal = detectLinkComponentUsage(analysis);
|
|
1165
|
+
collectClientRouteComponentsForModule(options.componentCollector, {
|
|
1166
|
+
analysis,
|
|
1167
|
+
filename: options.filename,
|
|
1168
|
+
root: options.root,
|
|
1169
|
+
routeEntry: options.routeEntry,
|
|
1170
|
+
});
|
|
1171
|
+
const forcedInference = isServerOnlyClientRouteSource(analysis)
|
|
1172
|
+
? emptyClientRouteModuleInferenceResult({
|
|
1173
|
+
availableExportNames: analysis.topLevelExportRenderInfo.map((info) => info.name),
|
|
1174
|
+
navigationLinkExportNames: detectLinkComponentExportNames(analysis),
|
|
1175
|
+
serverOnly: true,
|
|
1176
|
+
serverOnlyClientRuntime: analysis.clientRuntime,
|
|
1177
|
+
usesNavigationLink: usesNavigationLinkLocal,
|
|
1178
|
+
})
|
|
1179
|
+
: isExplicitClientRouteSource(analysis, options.filename)
|
|
1180
|
+
? emptyClientRouteModuleInferenceResult({
|
|
1181
|
+
availableExportNames: analysis.topLevelExportRenderInfo.map((info) => info.name),
|
|
1182
|
+
client: true,
|
|
1183
|
+
clientBoundaryModule: true,
|
|
1184
|
+
})
|
|
1185
|
+
: undefined;
|
|
698
1186
|
|
|
699
|
-
if (
|
|
700
|
-
return
|
|
701
|
-
navigationLinkExportNames: detectLinkComponentExportNames(analysis),
|
|
702
|
-
serverOnly: true,
|
|
703
|
-
serverOnlyClientRuntime: analysis.clientRuntime,
|
|
704
|
-
usesNavigationLink: usesNavigationLinkLocal,
|
|
705
|
-
});
|
|
706
|
-
}
|
|
707
|
-
|
|
708
|
-
if (isExplicitClientRouteSource(analysis, options.filename)) {
|
|
709
|
-
return emptyClientRouteModuleInferenceResult({
|
|
710
|
-
client: true,
|
|
711
|
-
clientBoundaryModule: true,
|
|
712
|
-
});
|
|
1187
|
+
if (forcedInference !== undefined && options.componentCollector === undefined) {
|
|
1188
|
+
return forcedInference;
|
|
713
1189
|
}
|
|
714
1190
|
|
|
715
1191
|
if (options.seen.has(options.filename)) {
|
|
716
|
-
return
|
|
1192
|
+
return (
|
|
1193
|
+
forcedInference ??
|
|
1194
|
+
emptyClientRouteModuleInferenceResult({
|
|
1195
|
+
availableExportNames: analysis.topLevelExportRenderInfo.map((info) => info.name),
|
|
1196
|
+
})
|
|
1197
|
+
);
|
|
717
1198
|
}
|
|
718
1199
|
|
|
719
1200
|
options.seen.add(options.filename);
|
|
@@ -725,11 +1206,14 @@ async function inferClientRouteModuleSource(options: {
|
|
|
725
1206
|
const nestedClientExportNames = new Set<string>();
|
|
726
1207
|
const clientReferenceSourceFiles: string[] = [];
|
|
727
1208
|
const diagnostics: ClientRouteInferenceDiagnostic[] = [];
|
|
1209
|
+
const availableExportNames = new Set(
|
|
1210
|
+
analysis.topLevelExportRenderInfo.map((info) => info.name),
|
|
1211
|
+
);
|
|
728
1212
|
let boundaryGraphFallbackRequired = false;
|
|
729
1213
|
let clientProxy = false;
|
|
730
1214
|
let nestedClient = false;
|
|
731
1215
|
let usesNavigationLink = usesNavigationLinkLocal;
|
|
732
|
-
const navigationLinkExportNames = new Set
|
|
1216
|
+
const navigationLinkExportNames = new Set(detectLinkComponentExportNames(analysis));
|
|
733
1217
|
const exportInfo = analysis.topLevelExportRenderInfo;
|
|
734
1218
|
const implicitModuleClient = exportInfo.length === 0 && analysis.clientRuntime;
|
|
735
1219
|
for (const info of exportInfo) {
|
|
@@ -739,9 +1223,12 @@ async function inferClientRouteModuleSource(options: {
|
|
|
739
1223
|
}
|
|
740
1224
|
if (
|
|
741
1225
|
hasServerOnlyImports(analysis) &&
|
|
742
|
-
(implicitModuleClient || clientBoundaryExportNames.size > 0)
|
|
1226
|
+
(implicitModuleClient || clientBoundaryExportNames.size > 0) &&
|
|
1227
|
+
options.componentCollector === undefined
|
|
743
1228
|
) {
|
|
744
1229
|
return emptyClientRouteModuleInferenceResult({
|
|
1230
|
+
availableExportNames: Array.from(availableExportNames),
|
|
1231
|
+
navigationLinkExportNames: detectLinkComponentExportNames(analysis),
|
|
745
1232
|
serverOnly: true,
|
|
746
1233
|
serverOnlyClientRuntime: true,
|
|
747
1234
|
});
|
|
@@ -774,17 +1261,67 @@ async function inferClientRouteModuleSource(options: {
|
|
|
774
1261
|
continue;
|
|
775
1262
|
}
|
|
776
1263
|
|
|
1264
|
+
const renderingExportNames = rendered ? renderedLocalExportNames(reference, exportInfo) : [];
|
|
1265
|
+
const renderedImportedNames = rendered
|
|
1266
|
+
? renderedImportedExportNames(reference, renderedComponentRoots)
|
|
1267
|
+
: [];
|
|
1268
|
+
const renderedFromReachableExport =
|
|
1269
|
+
rendered &&
|
|
1270
|
+
renderingExportNames.some((exportName) =>
|
|
1271
|
+
isClientRouteComponentReachable(options.componentCollector, options.filename, exportName),
|
|
1272
|
+
);
|
|
777
1273
|
const resolved = await resolveAppLocalModule({
|
|
778
1274
|
allowExplicitNonSource: options.sourceTransform !== undefined,
|
|
779
1275
|
cache: options.cache,
|
|
780
1276
|
importer: options.filename,
|
|
781
1277
|
specifier: reference.source,
|
|
1278
|
+
tolerateUnresolved: options.componentCollector !== undefined,
|
|
782
1279
|
});
|
|
783
1280
|
|
|
784
1281
|
if (resolved === undefined) {
|
|
1282
|
+
if (
|
|
1283
|
+
options.componentCollector !== undefined &&
|
|
1284
|
+
renderedFromReachableExport &&
|
|
1285
|
+
reference.source.startsWith(".")
|
|
1286
|
+
) {
|
|
1287
|
+
collectUnknownClientRouteComponents(options.componentCollector, {
|
|
1288
|
+
exportNames: renderedImportedNames,
|
|
1289
|
+
file: resolve(dirname(options.filename), reference.source),
|
|
1290
|
+
});
|
|
1291
|
+
diagnostics.push(
|
|
1292
|
+
unresolvedClientRouteReferenceDiagnostic({
|
|
1293
|
+
filename: options.filename,
|
|
1294
|
+
source: reference.source,
|
|
1295
|
+
}),
|
|
1296
|
+
);
|
|
1297
|
+
}
|
|
785
1298
|
continue;
|
|
786
1299
|
}
|
|
787
1300
|
|
|
1301
|
+
if (renderedFromReachableExport) {
|
|
1302
|
+
const clientExecution = renderingExportNames.some((exportName) =>
|
|
1303
|
+
clientRouteComponentRunsOnClient(
|
|
1304
|
+
options.componentCollector,
|
|
1305
|
+
options.filename,
|
|
1306
|
+
exportName,
|
|
1307
|
+
),
|
|
1308
|
+
);
|
|
1309
|
+
markClientRouteComponentReachable(
|
|
1310
|
+
options.componentCollector,
|
|
1311
|
+
resolved,
|
|
1312
|
+
renderedImportedNames,
|
|
1313
|
+
{ clientExecution },
|
|
1314
|
+
);
|
|
1315
|
+
if (renderedImportedNames !== undefined) {
|
|
1316
|
+
collectClientRoutePendingExportValidation(options.componentCollector, {
|
|
1317
|
+
exportNames: renderedImportedNames,
|
|
1318
|
+
file: resolved,
|
|
1319
|
+
importer: options.filename,
|
|
1320
|
+
source: reference.source,
|
|
1321
|
+
});
|
|
1322
|
+
}
|
|
1323
|
+
}
|
|
1324
|
+
|
|
788
1325
|
const source = await readClientRouteSource({
|
|
789
1326
|
cache: options.cache,
|
|
790
1327
|
filename: resolved,
|
|
@@ -793,6 +1330,7 @@ async function inferClientRouteModuleSource(options: {
|
|
|
793
1330
|
const imported = await inferClientRouteModuleSource({
|
|
794
1331
|
cache: options.cache,
|
|
795
1332
|
code: source,
|
|
1333
|
+
componentCollector: options.componentCollector,
|
|
796
1334
|
filename: resolved,
|
|
797
1335
|
moduleContext: await compilerModuleContextForSource({
|
|
798
1336
|
cache: options.cache,
|
|
@@ -800,6 +1338,7 @@ async function inferClientRouteModuleSource(options: {
|
|
|
800
1338
|
filename: resolved,
|
|
801
1339
|
}),
|
|
802
1340
|
root: false,
|
|
1341
|
+
routeEntry: false,
|
|
803
1342
|
seen: options.seen,
|
|
804
1343
|
sourceTransform: options.sourceTransform,
|
|
805
1344
|
});
|
|
@@ -843,8 +1382,8 @@ async function inferClientRouteModuleSource(options: {
|
|
|
843
1382
|
}
|
|
844
1383
|
|
|
845
1384
|
if (rendered) {
|
|
846
|
-
const importedExportNames =
|
|
847
|
-
const renderedExportNames =
|
|
1385
|
+
const importedExportNames = renderedImportedNames;
|
|
1386
|
+
const renderedExportNames = renderingExportNames;
|
|
848
1387
|
const importedBoundary =
|
|
849
1388
|
imported.clientBoundaryModule ||
|
|
850
1389
|
matchesInferredExportNames(importedExportNames, imported.clientBoundaryExportNames);
|
|
@@ -907,12 +1446,33 @@ async function inferClientRouteModuleSource(options: {
|
|
|
907
1446
|
cache: options.cache,
|
|
908
1447
|
importer: options.filename,
|
|
909
1448
|
specifier: reference.source,
|
|
1449
|
+
tolerateUnresolved: options.componentCollector !== undefined,
|
|
910
1450
|
});
|
|
911
1451
|
|
|
912
1452
|
if (resolved === undefined) {
|
|
1453
|
+
if (options.componentCollector !== undefined) {
|
|
1454
|
+
diagnostics.push(
|
|
1455
|
+
unresolvedClientRouteReferenceDiagnostic({
|
|
1456
|
+
filename: options.filename,
|
|
1457
|
+
source: reference.source,
|
|
1458
|
+
}),
|
|
1459
|
+
);
|
|
1460
|
+
}
|
|
913
1461
|
continue;
|
|
914
1462
|
}
|
|
915
1463
|
|
|
1464
|
+
propagateClientRouteComponentStaticExport(
|
|
1465
|
+
options.componentCollector,
|
|
1466
|
+
options.filename,
|
|
1467
|
+
resolved,
|
|
1468
|
+
reference,
|
|
1469
|
+
);
|
|
1470
|
+
collectClientRouteStaticExportEdge(options.componentCollector, {
|
|
1471
|
+
file: options.filename,
|
|
1472
|
+
reference,
|
|
1473
|
+
resolved,
|
|
1474
|
+
});
|
|
1475
|
+
|
|
916
1476
|
const source = await readClientRouteSource({
|
|
917
1477
|
cache: options.cache,
|
|
918
1478
|
filename: resolved,
|
|
@@ -921,6 +1481,7 @@ async function inferClientRouteModuleSource(options: {
|
|
|
921
1481
|
const exported = await inferClientRouteModuleSource({
|
|
922
1482
|
cache: options.cache,
|
|
923
1483
|
code: source,
|
|
1484
|
+
componentCollector: options.componentCollector,
|
|
924
1485
|
filename: resolved,
|
|
925
1486
|
moduleContext: await compilerModuleContextForSource({
|
|
926
1487
|
cache: options.cache,
|
|
@@ -928,10 +1489,23 @@ async function inferClientRouteModuleSource(options: {
|
|
|
928
1489
|
filename: resolved,
|
|
929
1490
|
}),
|
|
930
1491
|
root: false,
|
|
1492
|
+
routeEntry: false,
|
|
931
1493
|
seen: options.seen,
|
|
932
1494
|
sourceTransform: options.sourceTransform,
|
|
933
1495
|
});
|
|
934
1496
|
diagnostics.push(...exported.diagnostics);
|
|
1497
|
+
if (reference.exportAll) {
|
|
1498
|
+
for (const exportName of exported.availableExportNames) {
|
|
1499
|
+
availableExportNames.add(exportName);
|
|
1500
|
+
}
|
|
1501
|
+
} else {
|
|
1502
|
+
for (const specifier of reference.specifiers) {
|
|
1503
|
+
availableExportNames.add(specifier.exportedName);
|
|
1504
|
+
}
|
|
1505
|
+
for (const exportName of reference.exportedNames) {
|
|
1506
|
+
availableExportNames.add(exportName);
|
|
1507
|
+
}
|
|
1508
|
+
}
|
|
935
1509
|
// A re-export renders nothing itself, so it does not set the module's
|
|
936
1510
|
// own `usesNavigationLink`; it only forwards per-export `Link` usage so
|
|
937
1511
|
// an importer that renders this name can decide precisely. Map the
|
|
@@ -973,7 +1547,8 @@ async function inferClientRouteModuleSource(options: {
|
|
|
973
1547
|
}
|
|
974
1548
|
}
|
|
975
1549
|
|
|
976
|
-
|
|
1550
|
+
const inferred = {
|
|
1551
|
+
availableExportNames: Array.from(availableExportNames),
|
|
977
1552
|
boundaryGraphFallbackCandidate:
|
|
978
1553
|
analysis.staticExports.length > 0 || boundaryGraphFallbackRequired,
|
|
979
1554
|
boundaryGraphFallbackRequired,
|
|
@@ -995,6 +1570,15 @@ async function inferClientRouteModuleSource(options: {
|
|
|
995
1570
|
serverOnlyClientRuntime: false,
|
|
996
1571
|
usesNavigationLink,
|
|
997
1572
|
};
|
|
1573
|
+
return forcedInference === undefined
|
|
1574
|
+
? inferred
|
|
1575
|
+
: {
|
|
1576
|
+
...forcedInference,
|
|
1577
|
+
availableExportNames: inferred.availableExportNames,
|
|
1578
|
+
diagnostics,
|
|
1579
|
+
navigationLinkExportNames: inferred.navigationLinkExportNames,
|
|
1580
|
+
usesNavigationLink: inferred.usesNavigationLink,
|
|
1581
|
+
};
|
|
998
1582
|
} finally {
|
|
999
1583
|
options.seen.delete(options.filename);
|
|
1000
1584
|
}
|
|
@@ -1004,6 +1588,7 @@ function emptyClientRouteModuleInferenceResult(
|
|
|
1004
1588
|
overrides: Partial<ClientRouteModuleInferenceResult> = {},
|
|
1005
1589
|
): ClientRouteModuleInferenceResult {
|
|
1006
1590
|
return {
|
|
1591
|
+
availableExportNames: [],
|
|
1007
1592
|
boundaryGraphFallbackCandidate: false,
|
|
1008
1593
|
boundaryGraphFallbackRequired: false,
|
|
1009
1594
|
client: false,
|
|
@@ -1425,7 +2010,7 @@ function removeSafeCallbackHandlerAttributes(
|
|
|
1425
2010
|
|
|
1426
2011
|
function matchingBraceEnd(source: string, openBraceIndex: number): number | undefined {
|
|
1427
2012
|
let depth = 0;
|
|
1428
|
-
let quote: "
|
|
2013
|
+
let quote: '"' | "'" | "`" | undefined;
|
|
1429
2014
|
let escaped = false;
|
|
1430
2015
|
|
|
1431
2016
|
for (let index = openBraceIndex; index < source.length; index += 1) {
|
|
@@ -1442,7 +2027,7 @@ function matchingBraceEnd(source: string, openBraceIndex: number): number | unde
|
|
|
1442
2027
|
continue;
|
|
1443
2028
|
}
|
|
1444
2029
|
|
|
1445
|
-
if (char === "
|
|
2030
|
+
if (char === '"' || char === "'" || char === "`") {
|
|
1446
2031
|
quote = char;
|
|
1447
2032
|
continue;
|
|
1448
2033
|
}
|
|
@@ -1491,9 +2076,7 @@ function destructuredPropsCallbackNames(source: string): Set<string> {
|
|
|
1491
2076
|
addDestructuredCallbackNames(names, match[1] ?? "");
|
|
1492
2077
|
}
|
|
1493
2078
|
|
|
1494
|
-
for (const match of source.matchAll(
|
|
1495
|
-
/\{[^{}]*:\s*\{([^{}]+)\}\s*(?:=\s*\{\})?[^{}]*\}/gu,
|
|
1496
|
-
)) {
|
|
2079
|
+
for (const match of source.matchAll(/\{[^{}]*:\s*\{([^{}]+)\}\s*(?:=\s*\{\})?[^{}]*\}/gu)) {
|
|
1497
2080
|
addDestructuredCallbackNames(names, match[1] ?? "");
|
|
1498
2081
|
}
|
|
1499
2082
|
|
|
@@ -1531,10 +2114,7 @@ function addDestructuredCallbackNames(names: Set<string>, destructured: string):
|
|
|
1531
2114
|
const alias = destructuredBindingName(rawAlias);
|
|
1532
2115
|
const name = alias ?? property;
|
|
1533
2116
|
|
|
1534
|
-
if (
|
|
1535
|
-
name !== undefined &&
|
|
1536
|
-
(isCallbackPropName(property) || isCallbackPropName(name))
|
|
1537
|
-
) {
|
|
2117
|
+
if (name !== undefined && (isCallbackPropName(property) || isCallbackPropName(name))) {
|
|
1538
2118
|
names.add(name);
|
|
1539
2119
|
}
|
|
1540
2120
|
}
|
|
@@ -1623,6 +2203,28 @@ function serverOnlyClientImportReferenceDiagnostic(options: {
|
|
|
1623
2203
|
};
|
|
1624
2204
|
}
|
|
1625
2205
|
|
|
2206
|
+
function unresolvedClientRouteReferenceDiagnostic(options: {
|
|
2207
|
+
exportNames?: readonly string[] | undefined;
|
|
2208
|
+
filename: string;
|
|
2209
|
+
source: string;
|
|
2210
|
+
}): ClientRouteInferenceDiagnostic {
|
|
2211
|
+
const exportSuffix =
|
|
2212
|
+
options.exportNames === undefined || options.exportNames.length === 0
|
|
2213
|
+
? ""
|
|
2214
|
+
: ` (${options.exportNames.map((name) => JSON.stringify(name)).join(", ")})`;
|
|
2215
|
+
|
|
2216
|
+
return {
|
|
2217
|
+
code: "MR_CLIENT_BOUNDARY_INFERENCE_UNRESOLVED_REFERENCE",
|
|
2218
|
+
filename: options.filename,
|
|
2219
|
+
level: "warn",
|
|
2220
|
+
localNames: [...(options.exportNames ?? [])],
|
|
2221
|
+
message:
|
|
2222
|
+
`${options.filename}: rendered component reference ${JSON.stringify(options.source)}${exportSuffix} ` +
|
|
2223
|
+
"could not be resolved to an exported component.",
|
|
2224
|
+
source: options.source,
|
|
2225
|
+
};
|
|
2226
|
+
}
|
|
2227
|
+
|
|
1626
2228
|
function functionCallInteractiveImportDiagnostic(options: {
|
|
1627
2229
|
filename: string;
|
|
1628
2230
|
reference: StaticImportReference;
|
|
@@ -1718,6 +2320,7 @@ async function resolveAppLocalModule(options: {
|
|
|
1718
2320
|
cache: ClientRouteInferenceCache;
|
|
1719
2321
|
importer: string;
|
|
1720
2322
|
specifier: string;
|
|
2323
|
+
tolerateUnresolved?: boolean | undefined;
|
|
1721
2324
|
}): Promise<string | undefined> {
|
|
1722
2325
|
if (!options.specifier.startsWith(".")) {
|
|
1723
2326
|
return undefined;
|
|
@@ -1725,7 +2328,7 @@ async function resolveAppLocalModule(options: {
|
|
|
1725
2328
|
|
|
1726
2329
|
const cacheKey = `${options.importer}\0${options.specifier}\0${
|
|
1727
2330
|
options.allowExplicitNonSource === true ? "explicit" : "source"
|
|
1728
|
-
}`;
|
|
2331
|
+
}\0${options.tolerateUnresolved === true ? "tolerant" : "strict"}`;
|
|
1729
2332
|
const cached = options.cache.resolvedByImport.get(cacheKey);
|
|
1730
2333
|
|
|
1731
2334
|
if (cached !== undefined) {
|
|
@@ -1736,6 +2339,7 @@ async function resolveAppLocalModule(options: {
|
|
|
1736
2339
|
allowExplicitNonSource: options.allowExplicitNonSource === true,
|
|
1737
2340
|
importer: options.importer,
|
|
1738
2341
|
specifier: options.specifier,
|
|
2342
|
+
tolerateUnresolved: options.tolerateUnresolved === true,
|
|
1739
2343
|
});
|
|
1740
2344
|
options.cache.resolvedByImport.set(cacheKey, resolved);
|
|
1741
2345
|
return resolved;
|
|
@@ -1745,6 +2349,7 @@ async function resolveAppLocalModuleUncached(options: {
|
|
|
1745
2349
|
allowExplicitNonSource: boolean;
|
|
1746
2350
|
importer: string;
|
|
1747
2351
|
specifier: string;
|
|
2352
|
+
tolerateUnresolved: boolean;
|
|
1748
2353
|
}): Promise<string | undefined> {
|
|
1749
2354
|
const { importer, specifier } = options;
|
|
1750
2355
|
const base = join(dirname(importer), specifier);
|
|
@@ -1764,6 +2369,10 @@ async function resolveAppLocalModuleUncached(options: {
|
|
|
1764
2369
|
}
|
|
1765
2370
|
}
|
|
1766
2371
|
|
|
2372
|
+
if (options.tolerateUnresolved) {
|
|
2373
|
+
return undefined;
|
|
2374
|
+
}
|
|
2375
|
+
|
|
1767
2376
|
throw new Error(`${importer}: could not resolve app-local import ${JSON.stringify(specifier)}.`);
|
|
1768
2377
|
}
|
|
1769
2378
|
|
|
@@ -2104,6 +2713,13 @@ export async function buildClientRouteOutput(
|
|
|
2104
2713
|
const entry = await buildClientRouteEntrySource(options);
|
|
2105
2714
|
const dropConsoleFunctions =
|
|
2106
2715
|
options.dropConsoleFunctions ?? resolveClientConsolePureFunctions(options.dropClientConsole);
|
|
2716
|
+
const sourceRegionModulePaths =
|
|
2717
|
+
options.debugLabels === true ? undefined : new Set([options.filename]);
|
|
2718
|
+
const runtimePlugin = workspaceRuntimePlugin({
|
|
2719
|
+
debugLabels: options.debugLabels === true,
|
|
2720
|
+
routeFiles: [options.filename],
|
|
2721
|
+
sourceRegionModulePaths,
|
|
2722
|
+
});
|
|
2107
2723
|
const bundled = await bundleRouterModule({
|
|
2108
2724
|
code: entry.code,
|
|
2109
2725
|
cacheDir: options.cacheDir,
|
|
@@ -2115,7 +2731,8 @@ export async function buildClientRouteOutput(
|
|
|
2115
2731
|
minify: options.minify === true,
|
|
2116
2732
|
platform: "browser",
|
|
2117
2733
|
preserveExports: true,
|
|
2118
|
-
|
|
2734
|
+
sourceRegionModulePaths,
|
|
2735
|
+
plugins: [runtimePlugin],
|
|
2119
2736
|
sourceMap: options.sourceMap,
|
|
2120
2737
|
vitePlugins: options.vitePlugins,
|
|
2121
2738
|
});
|
|
@@ -2149,6 +2766,15 @@ export async function buildClientRouteBatchOutput(options: {
|
|
|
2149
2766
|
}),
|
|
2150
2767
|
})),
|
|
2151
2768
|
);
|
|
2769
|
+
const debugLabels = options.routes.some((route) => route.debugLabels === true);
|
|
2770
|
+
const sourceRegionModulePaths = debugLabels
|
|
2771
|
+
? undefined
|
|
2772
|
+
: new Set(entries.map((entry) => entry.filename));
|
|
2773
|
+
const runtimePlugin = workspaceRuntimePlugin({
|
|
2774
|
+
debugLabels,
|
|
2775
|
+
routeFiles: entries.map((entry) => entry.filename),
|
|
2776
|
+
sourceRegionModulePaths,
|
|
2777
|
+
});
|
|
2152
2778
|
const bundled = await bundleRouterModules({
|
|
2153
2779
|
base: options.assetBaseUrl ?? "/_mreact/client/",
|
|
2154
2780
|
cacheDir: options.cacheDir,
|
|
@@ -2162,7 +2788,8 @@ export async function buildClientRouteBatchOutput(options: {
|
|
|
2162
2788
|
})),
|
|
2163
2789
|
minify: options.minify === true,
|
|
2164
2790
|
platform: "browser",
|
|
2165
|
-
|
|
2791
|
+
sourceRegionModulePaths,
|
|
2792
|
+
plugins: [runtimePlugin],
|
|
2166
2793
|
root: options.projectRoot,
|
|
2167
2794
|
sourceMap: options.sourceMap,
|
|
2168
2795
|
dropConsoleFunctions: options.dropConsoleFunctions,
|
|
@@ -2199,13 +2826,22 @@ export async function buildClientRouteEntrySource(
|
|
|
2199
2826
|
filename: options.filename,
|
|
2200
2827
|
});
|
|
2201
2828
|
const routeSourceAnalysis = collectClientRouteModuleAnalysisFromContext(moduleContext);
|
|
2829
|
+
const compilerFilename =
|
|
2830
|
+
options.debugLabels === true ? basename(options.filename) : options.filename;
|
|
2831
|
+
const compilerModuleContext =
|
|
2832
|
+
compilerFilename === options.filename
|
|
2833
|
+
? moduleContext
|
|
2834
|
+
: createCompilerModuleContext({
|
|
2835
|
+
code: options.code,
|
|
2836
|
+
filename: compilerFilename,
|
|
2837
|
+
});
|
|
2202
2838
|
const compiled = transformCompilerModuleContext({
|
|
2203
2839
|
code: options.code,
|
|
2204
2840
|
clientBoundaryImports: options.clientBoundaryImports ?? [],
|
|
2205
|
-
filename:
|
|
2206
|
-
moduleContext,
|
|
2841
|
+
filename: compilerFilename,
|
|
2842
|
+
moduleContext: compilerModuleContext,
|
|
2207
2843
|
target: "client",
|
|
2208
|
-
dev: options.
|
|
2844
|
+
dev: options.debugLabels === true,
|
|
2209
2845
|
});
|
|
2210
2846
|
|
|
2211
2847
|
if (compiled.diagnostics.length > 0) {
|
|
@@ -2238,7 +2874,11 @@ export async function buildClientRouteEntrySource(
|
|
|
2238
2874
|
const routeId = routeIdForPath(options.routePath);
|
|
2239
2875
|
const routeUsesCells = detectRouteCellStateHint(compiled.code);
|
|
2240
2876
|
const routeUsesReactiveEffect = detectRouteReactiveEffectHint(compiled.code);
|
|
2241
|
-
const
|
|
2877
|
+
const routeUsesDomRefs = compiled.metadata.imports.some(
|
|
2878
|
+
(entry) =>
|
|
2879
|
+
entry.source === "@reckona/mreact-reactive-dom" && entry.specifiers.includes("bindDomRef"),
|
|
2880
|
+
);
|
|
2881
|
+
const routeUsesCleanupScope = routeUsesCells || routeUsesReactiveEffect || routeUsesDomRefs;
|
|
2242
2882
|
const routeExplicitlyRequiresHydration = isExplicitClientRouteSource(
|
|
2243
2883
|
routeSourceAnalysis,
|
|
2244
2884
|
options.filename,
|
|
@@ -2254,6 +2894,7 @@ export async function buildClientRouteEntrySource(
|
|
|
2254
2894
|
routeExplicitlyRequiresHydration ||
|
|
2255
2895
|
routeUsesCells ||
|
|
2256
2896
|
routeUsesReactiveEffect ||
|
|
2897
|
+
routeUsesDomRefs ||
|
|
2257
2898
|
routeHasEventBindings;
|
|
2258
2899
|
const routeUsesOnlyClientReferenceBoundaries =
|
|
2259
2900
|
!routeRequiresFullHydration &&
|
|
@@ -2276,7 +2917,7 @@ export async function buildClientRouteEntrySource(
|
|
|
2276
2917
|
? `import { bindCapturedEvent as __mreactBindCapturedEvent } from "@reckona/mreact-reactive-dom/internal";\n`
|
|
2277
2918
|
: "";
|
|
2278
2919
|
const routeReactiveDomMetadataImport = !routeUsesOnlyClientReferenceBoundaries
|
|
2279
|
-
? `${routeCapturedEventImport}import { withEventBindingMetadata as __mreactWithEventBindingMetadata, withPropBindingMetadata as __mreactWithPropBindingMetadata } from "@reckona/mreact-reactive-dom";\n`
|
|
2920
|
+
? `${routeCapturedEventImport}import { ${routeUsesDomRefs ? "getDomRefBindings as __mreactGetDomRefBindings, " : ""}withEventBindingMetadata as __mreactWithEventBindingMetadata, withPropBindingMetadata as __mreactWithPropBindingMetadata } from "@reckona/mreact-reactive-dom";\n`
|
|
2280
2921
|
: "";
|
|
2281
2922
|
const navigationStateDeclaration = inlineClientNavigation
|
|
2282
2923
|
? `const __mreactNavigationState = __mreactGlobal.__mreactNavigationState ??= {
|
|
@@ -2552,9 +3193,10 @@ __mreactGlobal.__mreactRouteCell = (nativeCell, initial) => {
|
|
|
2552
3193
|
__mreactActiveCellIndex = 0;
|
|
2553
3194
|
}
|
|
2554
3195
|
return () => {
|
|
2555
|
-
|
|
2556
|
-
|
|
2557
|
-
|
|
3196
|
+
__mreactRunLifecycleTasks(
|
|
3197
|
+
Array.from(__mreactRouteEffectDisposers),
|
|
3198
|
+
(__mreactDispose) => __mreactDispose(),
|
|
3199
|
+
);
|
|
2558
3200
|
__mreactRouteEffectDisposers.clear();
|
|
2559
3201
|
};
|
|
2560
3202
|
});
|
|
@@ -2566,13 +3208,33 @@ __mreactGlobal.__mreactRouteCell = (nativeCell, initial) => {
|
|
|
2566
3208
|
? ` __mreactDisposeRoute(__mreactRouteId);
|
|
2567
3209
|
const __mreactRouteEffectDisposers = new Set();
|
|
2568
3210
|
__mreactRouteDisposers.set(__mreactRouteId, () => {
|
|
2569
|
-
|
|
2570
|
-
|
|
2571
|
-
|
|
3211
|
+
__mreactRunLifecycleTasks(
|
|
3212
|
+
Array.from(__mreactRouteEffectDisposers),
|
|
3213
|
+
(__mreactDispose) => __mreactDispose(),
|
|
3214
|
+
);
|
|
2572
3215
|
__mreactRouteEffectDisposers.clear();
|
|
2573
3216
|
});
|
|
2574
3217
|
`
|
|
2575
3218
|
: "";
|
|
3219
|
+
const routeLifecycleFunctions = `
|
|
3220
|
+
function __mreactRunLifecycleTasks(values, run) {
|
|
3221
|
+
let firstError;
|
|
3222
|
+
|
|
3223
|
+
for (const value of values) {
|
|
3224
|
+
try {
|
|
3225
|
+
run(value);
|
|
3226
|
+
} catch (error) {
|
|
3227
|
+
firstError ??= error;
|
|
3228
|
+
}
|
|
3229
|
+
}
|
|
3230
|
+
|
|
3231
|
+
if (firstError !== undefined) {
|
|
3232
|
+
queueMicrotask(() => {
|
|
3233
|
+
throw firstError;
|
|
3234
|
+
});
|
|
3235
|
+
}
|
|
3236
|
+
}
|
|
3237
|
+
`;
|
|
2576
3238
|
const routeCellDropFunction = routeUsesCells
|
|
2577
3239
|
? `
|
|
2578
3240
|
function __mreactDropMismatchedRouteState(previousState, nextState) {
|
|
@@ -2598,12 +3260,18 @@ function __mreactDisposeRoute(routeId) {
|
|
|
2598
3260
|
}
|
|
2599
3261
|
`
|
|
2600
3262
|
: "";
|
|
2601
|
-
const routeCleanupNavigationDispose =
|
|
2602
|
-
|
|
2603
|
-
|
|
3263
|
+
const routeCleanupNavigationDispose = ` if (currentRouteId !== nextRouteId) {
|
|
3264
|
+
const __mreactRegisteredRouteDisposers = __mreactGlobal.__mreactRouteDisposers;
|
|
3265
|
+
const __mreactRegisteredRouteDispose = __mreactRegisteredRouteDisposers?.get(currentRouteId);
|
|
3266
|
+
if (__mreactRegisteredRouteDispose !== undefined) {
|
|
3267
|
+
__mreactRegisteredRouteDisposers.delete(currentRouteId);
|
|
3268
|
+
__mreactRunLifecycleTasks(
|
|
3269
|
+
[__mreactRegisteredRouteDispose],
|
|
3270
|
+
(__mreactDispose) => __mreactDispose(),
|
|
3271
|
+
);
|
|
3272
|
+
}
|
|
2604
3273
|
}
|
|
2605
|
-
|
|
2606
|
-
: "";
|
|
3274
|
+
`;
|
|
2607
3275
|
const routeNodeResolver = routeUsesCells
|
|
2608
3276
|
? `
|
|
2609
3277
|
function __mreactResolveRouteNode(value) {
|
|
@@ -2642,9 +3310,7 @@ function __mreactResolveRouteNode(value) {
|
|
|
2642
3310
|
const previousDisposers = current.__mreactEventDisposers;
|
|
2643
3311
|
|
|
2644
3312
|
if (Array.isArray(previousDisposers)) {
|
|
2645
|
-
|
|
2646
|
-
dispose();
|
|
2647
|
-
}
|
|
3313
|
+
__mreactRunLifecycleTasks(previousDisposers, (dispose) => dispose());
|
|
2648
3314
|
}
|
|
2649
3315
|
|
|
2650
3316
|
const rawBindings = next.__mreactEventBindings;
|
|
@@ -2673,14 +3339,26 @@ function __mreactResolveRouteNode(value) {
|
|
|
2673
3339
|
const previousDisposers = current.__mreactEventDisposers;
|
|
2674
3340
|
|
|
2675
3341
|
if (Array.isArray(previousDisposers)) {
|
|
2676
|
-
|
|
2677
|
-
dispose();
|
|
2678
|
-
}
|
|
3342
|
+
__mreactRunLifecycleTasks(previousDisposers, (dispose) => dispose());
|
|
2679
3343
|
}
|
|
2680
3344
|
|
|
2681
3345
|
current.__mreactEventDisposers = [];
|
|
2682
3346
|
current.__mreactHasEvents = false;
|
|
2683
3347
|
}
|
|
3348
|
+
`;
|
|
3349
|
+
const routeDomRefBindingSyncFunction = routeUsesDomRefs
|
|
3350
|
+
? `function __mreactSyncDomRefBindings(current, next) {
|
|
3351
|
+
__mreactRunLifecycleTasks(
|
|
3352
|
+
Array.from(__mreactGetDomRefBindings(current)),
|
|
3353
|
+
(binding) => binding.dispose(),
|
|
3354
|
+
);
|
|
3355
|
+
__mreactRunLifecycleTasks(
|
|
3356
|
+
Array.from(__mreactGetDomRefBindings(next)),
|
|
3357
|
+
(binding) => binding.retarget(current),
|
|
3358
|
+
);
|
|
3359
|
+
}
|
|
3360
|
+
`
|
|
3361
|
+
: `function __mreactSyncDomRefBindings() {}
|
|
2684
3362
|
`;
|
|
2685
3363
|
const boundaryOnlyHydrationBlock = routeRequiresFullHydration
|
|
2686
3364
|
? ""
|
|
@@ -2740,6 +3418,7 @@ ${routeCellHydrationIndent}__mreactMarker.setAttribute(__mreactRouteHydratedAttr
|
|
|
2740
3418
|
${routeCellHydrationIndent}__mreactMarkRouteHydrated();
|
|
2741
3419
|
${routeCellHydrationEnd}}
|
|
2742
3420
|
${routeCellDropFunction}
|
|
3421
|
+
${routeLifecycleFunctions}
|
|
2743
3422
|
${routeCleanupFunction}
|
|
2744
3423
|
|
|
2745
3424
|
function __mreactMarkRouteHydrated() {
|
|
@@ -3327,13 +4006,14 @@ function __mreactApplyNavigationHtml(html, url) {
|
|
|
3327
4006
|
const currentRouteId = currentMarker.getAttribute("${routeHydrationContract.routeMarkerAttribute}");
|
|
3328
4007
|
const nextRouteId = nextMarker.getAttribute("${routeHydrationContract.routeMarkerAttribute}");
|
|
3329
4008
|
|
|
4009
|
+
${routeCleanupNavigationDispose}
|
|
3330
4010
|
__mreactMarkRouteHydrating();
|
|
3331
4011
|
__mreactSyncHeadMetadata(template.content, html);
|
|
3332
4012
|
if (!__mreactApplyNavigationShellHtml(currentMarker, nextMarker)) {
|
|
3333
4013
|
__mreactUnmountCompatBoundaries(currentMarker);
|
|
3334
4014
|
__mreactResumeNode(currentMarker, nextMarker);
|
|
3335
4015
|
}
|
|
3336
|
-
|
|
4016
|
+
__mreactSyncRouteDataScripts(template.content, currentRouteId, nextRouteId);
|
|
3337
4017
|
|
|
3338
4018
|
const script = template.content.querySelector('script[type="module"][src]')?.getAttribute("src");
|
|
3339
4019
|
if (script !== null && script !== undefined) {
|
|
@@ -4491,6 +5171,7 @@ function __mreactResumeNode(current, next) {
|
|
|
4491
5171
|
}
|
|
4492
5172
|
|
|
4493
5173
|
__mreactSyncEventBindings(current, next);
|
|
5174
|
+
__mreactSyncDomRefBindings(current, next);
|
|
4494
5175
|
__mreactSyncAttributes(current, next);
|
|
4495
5176
|
__mreactSyncPropBindings(current, next);
|
|
4496
5177
|
__mreactResumeChildren(current, next);
|
|
@@ -4513,6 +5194,7 @@ function __mreactShouldReplaceNode(current, next) {
|
|
|
4513
5194
|
}
|
|
4514
5195
|
|
|
4515
5196
|
${routeEventBindingSyncFunction}
|
|
5197
|
+
${routeDomRefBindingSyncFunction}
|
|
4516
5198
|
|
|
4517
5199
|
function __mreactSyncAttributes(current, next) {
|
|
4518
5200
|
for (const attribute of Array.from(current.attributes)) {
|
|
@@ -4532,9 +5214,7 @@ function __mreactSyncPropBindings(current, next) {
|
|
|
4532
5214
|
const previousBindings = current.__mreactPropBindings;
|
|
4533
5215
|
|
|
4534
5216
|
if (Array.isArray(previousBindings)) {
|
|
4535
|
-
|
|
4536
|
-
binding.dispose?.();
|
|
4537
|
-
}
|
|
5217
|
+
__mreactRunLifecycleTasks(previousBindings, (binding) => binding.dispose?.());
|
|
4538
5218
|
}
|
|
4539
5219
|
|
|
4540
5220
|
const bindings = next.__mreactPropBindings;
|
|
@@ -4550,9 +5230,7 @@ function __mreactSyncPropBindings(current, next) {
|
|
|
4550
5230
|
next.__mreactPropBindings = [];
|
|
4551
5231
|
next.__mreactHasReactiveProps = false;
|
|
4552
5232
|
|
|
4553
|
-
|
|
4554
|
-
binding.retarget?.(current);
|
|
4555
|
-
}
|
|
5233
|
+
__mreactRunLifecycleTasks(bindings, (binding) => binding.retarget?.(current));
|
|
4556
5234
|
}
|
|
4557
5235
|
|
|
4558
5236
|
function __mreactResumeChildren(current, next) {
|
|
@@ -4605,7 +5283,11 @@ function __mreactResumeChildren(current, next) {
|
|
|
4605
5283
|
};
|
|
4606
5284
|
}
|
|
4607
5285
|
|
|
4608
|
-
function workspaceRuntimePlugin(options: {
|
|
5286
|
+
function workspaceRuntimePlugin(options: {
|
|
5287
|
+
debugLabels: boolean;
|
|
5288
|
+
routeFiles: readonly string[];
|
|
5289
|
+
sourceRegionModulePaths?: Set<string> | undefined;
|
|
5290
|
+
}) {
|
|
4609
5291
|
const routeFiles = new Set(options.routeFiles);
|
|
4610
5292
|
const packageFile = (monorepoDir: string, packageName: string, entry: string): string =>
|
|
4611
5293
|
workspacePackageFile({
|
|
@@ -4733,15 +5415,31 @@ export function invalidateReactiveDevtoolsCache() {}
|
|
|
4733
5415
|
export function prepareReactiveEffectRunDevtoolsEvent() { return undefined; }`,
|
|
4734
5416
|
loader: "ts",
|
|
4735
5417
|
}));
|
|
5418
|
+
if (options.sourceRegionModulePaths !== undefined) {
|
|
5419
|
+
buildApi.onLoad({ filter: /.*/ }, (args) => {
|
|
5420
|
+
if (
|
|
5421
|
+
isAbsolute(args.path) &&
|
|
5422
|
+
isRouteClientDependencySourcePath(args.path, routeFiles) &&
|
|
5423
|
+
!runtimePackageDirs.some((runtimePackageDir) =>
|
|
5424
|
+
args.path.startsWith(`${runtimePackageDir}${sep}`),
|
|
5425
|
+
)
|
|
5426
|
+
) {
|
|
5427
|
+
options.sourceRegionModulePaths?.add(args.path);
|
|
5428
|
+
}
|
|
5429
|
+
|
|
5430
|
+
return undefined;
|
|
5431
|
+
});
|
|
5432
|
+
}
|
|
4736
5433
|
buildApi.onLoad({ filter: /\.(?:mreact\.)?[cm]?[jt]sx$/ }, async (args) => {
|
|
4737
5434
|
if (!isRouteClientDependencySourcePath(args.path, routeFiles)) {
|
|
4738
5435
|
return undefined;
|
|
4739
5436
|
}
|
|
4740
5437
|
|
|
4741
5438
|
const source = await readFile(args.path, "utf8");
|
|
5439
|
+
const compilerFilename = options.debugLabels ? basename(args.path) : args.path;
|
|
4742
5440
|
const moduleContext = createCompilerModuleContext({
|
|
4743
5441
|
code: source,
|
|
4744
|
-
filename:
|
|
5442
|
+
filename: compilerFilename,
|
|
4745
5443
|
});
|
|
4746
5444
|
|
|
4747
5445
|
if (!hasJsxSyntax(moduleContext.program)) {
|
|
@@ -4750,8 +5448,8 @@ export function prepareReactiveEffectRunDevtoolsEvent() { return undefined; }`,
|
|
|
4750
5448
|
|
|
4751
5449
|
const output = transformCompilerModuleContext({
|
|
4752
5450
|
code: source,
|
|
4753
|
-
dev:
|
|
4754
|
-
filename:
|
|
5451
|
+
dev: options.debugLabels,
|
|
5452
|
+
filename: compilerFilename,
|
|
4755
5453
|
mode: isCompatSourcePath(args.path) ? "compat" : "reactive",
|
|
4756
5454
|
moduleContext,
|
|
4757
5455
|
target: "client",
|