@reckona/mreact-router 0.0.120 → 0.0.121

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/src/client.ts CHANGED
@@ -31,10 +31,7 @@ import {
31
31
  type RouterBundleAssetOutput,
32
32
  type RouterBundleChunkOutput,
33
33
  } from "./bundle-pipeline.js";
34
- import {
35
- resolveClientConsolePureFunctions,
36
- type AppRouterProductionOptions,
37
- } from "./config.js";
34
+ import { resolveClientConsolePureFunctions, type AppRouterProductionOptions } from "./config.js";
38
35
  import type { AppRoute } from "./routes.js";
39
36
  import { existingRouteShellCandidates } from "./route-shells.js";
40
37
  import {
@@ -116,6 +113,7 @@ interface ClientRouteSourceTransform {
116
113
  export interface ClientRouteInferenceResult {
117
114
  client: boolean;
118
115
  clientBoundaryImports: string[];
116
+ clientBoundaryFallbackImports: string[];
119
117
  diagnostics: ClientRouteInferenceDiagnostic[];
120
118
  }
121
119
 
@@ -265,6 +263,7 @@ export async function inferClientRouteModule(options: {
265
263
  client:
266
264
  mergedRouteInference.client || shellInferences.some((inference) => inference.client),
267
265
  clientBoundaryImports: mergedRouteInference.clientBoundaryImports,
266
+ clientBoundaryFallbackImports: mergedRouteInference.clientBoundaryFallbackImports,
268
267
  diagnostics: [
269
268
  ...mergedRouteInference.diagnostics,
270
269
  ...shellInferences.flatMap((inference) => inference.diagnostics),
@@ -325,6 +324,7 @@ function clientRouteInferenceFromBoundaryGraph(
325
324
  return {
326
325
  client: clientRoute || clientBoundaryImports.length > 0,
327
326
  clientBoundaryImports,
327
+ clientBoundaryFallbackImports: [],
328
328
  diagnostics: [],
329
329
  };
330
330
  }
@@ -338,6 +338,9 @@ function mergeClientRouteInference(
338
338
  clientBoundaryImports: Array.from(
339
339
  new Set([...left.clientBoundaryImports, ...right.clientBoundaryImports]),
340
340
  ),
341
+ clientBoundaryFallbackImports: Array.from(
342
+ new Set([...left.clientBoundaryFallbackImports, ...right.clientBoundaryFallbackImports]),
343
+ ),
341
344
  diagnostics: [...left.diagnostics, ...right.diagnostics],
342
345
  };
343
346
  }
@@ -466,6 +469,7 @@ export async function collectClientRouteReferences(options: {
466
469
  const output = transformCompilerModuleContext({
467
470
  code: source.code,
468
471
  clientBoundaryImports: source.inference.clientBoundaryImports,
472
+ clientBoundaryFallbackImports: source.inference.clientBoundaryFallbackImports,
469
473
  dev: false,
470
474
  filename: source.filename,
471
475
  moduleContext: source.moduleContext,
@@ -511,6 +515,7 @@ export async function collectClientRouteReferences(options: {
511
515
  routeInference.client ||
512
516
  sources.some((source) => source.filename !== options.filename && source.inference.client),
513
517
  clientBoundaryImports: routeInference.clientBoundaryImports,
518
+ clientBoundaryFallbackImports: routeInference.clientBoundaryFallbackImports,
514
519
  clientReferenceImports,
515
520
  clientReferenceManifest,
516
521
  diagnostics: sources
@@ -685,6 +690,7 @@ async function inferClientRouteModuleSource(options: {
685
690
 
686
691
  try {
687
692
  const clientBoundaryImports: string[] = [];
693
+ const clientBoundaryFallbackImports: string[] = [];
688
694
  const clientBoundaryExportNames = new Set<string>();
689
695
  const nestedClientExportNames = new Set<string>();
690
696
  const clientReferenceSourceFiles: string[] = [];
@@ -779,7 +785,10 @@ async function inferClientRouteModuleSource(options: {
779
785
  renderedComponentRoots,
780
786
  );
781
787
  if (
782
- matchesInferredExportNames(importedNavigationExportNames, imported.navigationLinkExportNames)
788
+ matchesInferredExportNames(
789
+ importedNavigationExportNames,
790
+ imported.navigationLinkExportNames,
791
+ )
783
792
  ) {
784
793
  usesNavigationLink = true;
785
794
  for (const exportName of renderedLocalExportNames(reference, exportInfo)) {
@@ -841,6 +850,9 @@ async function inferClientRouteModuleSource(options: {
841
850
  }
842
851
 
843
852
  clientBoundaryImports.push(reference.source);
853
+ if (!imported.clientBoundaryModule && isClientBoundaryFallbackEligibleSource(source)) {
854
+ clientBoundaryFallbackImports.push(reference.source);
855
+ }
844
856
  continue;
845
857
  }
846
858
 
@@ -933,6 +945,7 @@ async function inferClientRouteModuleSource(options: {
933
945
  clientProxy ||
934
946
  nestedClient,
935
947
  clientBoundaryImports,
948
+ clientBoundaryFallbackImports,
936
949
  clientBoundaryExportNames: Array.from(clientBoundaryExportNames),
937
950
  clientBoundaryModule: clientProxy || implicitModuleClient,
938
951
  nestedClientExportNames: Array.from(nestedClientExportNames),
@@ -956,6 +969,7 @@ function emptyClientRouteModuleInferenceResult(
956
969
  boundaryGraphFallbackRequired: false,
957
970
  client: false,
958
971
  clientBoundaryImports: [],
972
+ clientBoundaryFallbackImports: [],
959
973
  clientBoundaryExportNames: [],
960
974
  clientBoundaryModule: false,
961
975
  nestedClientExportNames: [],
@@ -992,7 +1006,12 @@ async function clientRouteModuleAnalysisForSource(options: {
992
1006
  })),
993
1007
  ),
994
1008
  );
995
- setLatestModuleCacheEntry(options.cache.moduleAnalysisByFile, options.filename, cacheKey, analysis);
1009
+ setLatestModuleCacheEntry(
1010
+ options.cache.moduleAnalysisByFile,
1011
+ options.filename,
1012
+ cacheKey,
1013
+ analysis,
1014
+ );
996
1015
  return analysis;
997
1016
  }
998
1017
 
@@ -1090,6 +1109,10 @@ function isStyleModuleSpecifier(source: string): boolean {
1090
1109
 
1091
1110
  const styleModuleExtensions = new Set([".css", ".less", ".sass", ".scss", ".styl", ".stylus"]);
1092
1111
 
1112
+ function isClientBoundaryFallbackEligibleSource(source: string): boolean {
1113
+ return !/\bon[A-Z][A-Za-z0-9_$]*\s*=/u.test(source) && !/\bglobalThis\b/u.test(source);
1114
+ }
1115
+
1093
1116
  function renderedImportedExportNames(
1094
1117
  reference: ClientRouteStaticImportReference,
1095
1118
  componentRoots: ReadonlySet<string>,
@@ -1227,14 +1250,14 @@ function startsUppercase(value: string): boolean {
1227
1250
  export function formatClientRouteInferenceDiagnostic(
1228
1251
  diagnostic: ClientRouteInferenceDiagnostic,
1229
1252
  ): string {
1230
- const route = diagnostic.routePath === undefined ? "" : ` on route ${JSON.stringify(diagnostic.routePath)}`;
1253
+ const route =
1254
+ diagnostic.routePath === undefined ? "" : ` on route ${JSON.stringify(diagnostic.routePath)}`;
1231
1255
  return `${diagnostic.code}: ${diagnostic.message}${route}`;
1232
1256
  }
1233
1257
 
1234
- function withClientRouteDiagnosticPath<T extends ClientRouteInferenceDiagnostic | ClientRouteInferenceResult>(
1235
- value: T,
1236
- routePath: string | undefined,
1237
- ): T {
1258
+ function withClientRouteDiagnosticPath<
1259
+ T extends ClientRouteInferenceDiagnostic | ClientRouteInferenceResult,
1260
+ >(value: T, routePath: string | undefined): T {
1238
1261
  if (routePath === undefined) {
1239
1262
  return value;
1240
1263
  }
@@ -411,7 +411,7 @@ async function transformServerSourceFile(
411
411
  console.warn(formatClientRouteInferenceDiagnostic(diagnostic));
412
412
  }
413
413
 
414
- const cacheKey = `${options.serverOutput}\0${options.dev ? "dev" : "prod"}\0${options.filename}\0${transformedSourceHash}\0${clientInference.clientBoundaryImports.join("\0")}\0${vitePluginsCacheKey(options.vitePlugins)}`;
414
+ const cacheKey = `${options.serverOutput}\0${options.dev ? "dev" : "prod"}\0${options.filename}\0${transformedSourceHash}\0${clientInference.clientBoundaryImports.join("\0")}\0${clientInference.clientBoundaryFallbackImports.join("\0")}\0${vitePluginsCacheKey(options.vitePlugins)}`;
415
415
  const cached = readRouterRuntimeCacheEntry(
416
416
  serverSourceTransformCache,
417
417
  cacheKey,
@@ -425,6 +425,7 @@ async function transformServerSourceFile(
425
425
  const output = transformCompilerModuleContext({
426
426
  code: source,
427
427
  clientBoundaryImports: clientInference.clientBoundaryImports,
428
+ clientBoundaryFallbackImports: clientInference.clientBoundaryFallbackImports,
428
429
  dev: options.dev,
429
430
  filename: options.filename,
430
431
  moduleContext,
@@ -488,12 +489,20 @@ function withNodeRequireShimForEsmBundle(options: {
488
489
  return code;
489
490
  }
490
491
 
491
- return `${rewritten.needsNativeImport ? 'const __mreactNativeImport = Function("specifier", "return import(specifier)");\n' : ""}${needsFilenameGlobalShim ? `const __filename = ${JSON.stringify(options.filename)};
492
+ return `${rewritten.needsNativeImport ? 'const __mreactNativeImport = Function("specifier", "return import(specifier)");\n' : ""}${
493
+ needsFilenameGlobalShim
494
+ ? `const __filename = ${JSON.stringify(options.filename)};
492
495
  const __dirname = ${JSON.stringify(dirname(options.filename))};
493
- ` : ""}${rewritten.needsRequire || needsRequireShim ? `import { createRequire as __mreactCreateRequire } from "node:module";
496
+ `
497
+ : ""
498
+ }${
499
+ rewritten.needsRequire || needsRequireShim
500
+ ? `import { createRequire as __mreactCreateRequire } from "node:module";
494
501
  const __mreactRequire = __mreactCreateRequire(${JSON.stringify(requireBaseUrl)});
495
502
  const require = __mreactRequire;
496
- ` : ""}${code}`;
503
+ `
504
+ : ""
505
+ }${code}`;
497
506
  }
498
507
 
499
508
  function needsCommonJsFilenameGlobalShim(code: string): boolean {
@@ -535,7 +544,11 @@ function rewriteNodeModulesExternalImports(code: string): {
535
544
  }
536
545
 
537
546
  needsNativeImport = true;
538
- const rewritten = esmImportClauseToNativeImportStatements(clause.trim(), specifier, importIndex++);
547
+ const rewritten = esmImportClauseToNativeImportStatements(
548
+ clause.trim(),
549
+ specifier,
550
+ importIndex++,
551
+ );
539
552
  for (const [name, replacement] of rewritten.bindings) {
540
553
  nativeImportBindings.set(name, replacement);
541
554
  }
@@ -601,7 +614,9 @@ function isNodeModulesPath(file: string): boolean {
601
614
  function isNodeImportableModuleFile(file: string): boolean {
602
615
  const extension = extname(file);
603
616
 
604
- return extension === ".cjs" || extension === ".mjs" || extension === ".js" || extension === ".node";
617
+ return (
618
+ extension === ".cjs" || extension === ".mjs" || extension === ".js" || extension === ".node"
619
+ );
605
620
  }
606
621
 
607
622
  function isNodeCommonJsModuleFile(file: string): boolean {
@@ -676,7 +691,10 @@ function commonJsImportClauseToRequireStatements(
676
691
  const defaultName = clause.slice(0, commaIndex).trim();
677
692
  const namedOrNamespace = clause.slice(commaIndex + 1).trim();
678
693
  const temporaryName = `__mreactExternalCommonJs${importIndex}`;
679
- const statements = [`const ${temporaryName} = ${requireExpression};`, `const ${defaultName} = ${temporaryName};`];
694
+ const statements = [
695
+ `const ${temporaryName} = ${requireExpression};`,
696
+ `const ${defaultName} = ${temporaryName};`,
697
+ ];
680
698
 
681
699
  if (namedOrNamespace.startsWith("* as ")) {
682
700
  statements.push(`const ${namedOrNamespace.slice(5).trim()} = ${temporaryName};`);
@@ -737,10 +755,7 @@ function collectNamedEsmImportBindings(
737
755
  }
738
756
  }
739
757
 
740
- function namedCommonJsImportsToRequireStatements(
741
- clause: string,
742
- sourceExpression: string,
743
- ): string {
758
+ function namedCommonJsImportsToRequireStatements(clause: string, sourceExpression: string): string {
744
759
  const objectBindings: string[] = [];
745
760
  const statements: string[] = [];
746
761
 
package/src/render.ts CHANGED
@@ -303,6 +303,7 @@ async function preloadBuiltPageRouteModules(options: {
303
303
  const stringOutput = transformServerModule({
304
304
  code: routeCode,
305
305
  clientBoundaryImports: options.analysis.clientInference.clientBoundaryImports,
306
+ clientBoundaryFallbackImports: options.analysis.clientInference.clientBoundaryFallbackImports,
306
307
  filename: options.file,
307
308
  serverModules: options.serverModules,
308
309
  serverOutput: "string",
@@ -321,6 +322,7 @@ async function preloadBuiltPageRouteModules(options: {
321
322
  const streamOutput = transformServerModule({
322
323
  code: routeCode,
323
324
  clientBoundaryImports: options.analysis.clientInference.clientBoundaryImports,
325
+ clientBoundaryFallbackImports: options.analysis.clientInference.clientBoundaryFallbackImports,
324
326
  filename: options.file,
325
327
  serverModules: options.serverModules,
326
328
  serverOutput: "stream",
@@ -1036,6 +1038,7 @@ async function renderAppRequestInternal(options: RenderAppRequestOptions): Promi
1036
1038
  const stringOutput = transformServerModule({
1037
1039
  code: routeCode,
1038
1040
  clientBoundaryImports: clientInference.clientBoundaryImports,
1041
+ clientBoundaryFallbackImports: clientInference.clientBoundaryFallbackImports,
1039
1042
  filename: matched.route.file,
1040
1043
  serverModules: options.serverModules,
1041
1044
  serverOutput: "string",
@@ -1179,6 +1182,7 @@ async function renderAppRequestInternal(options: RenderAppRequestOptions): Promi
1179
1182
  const output = transformServerModule({
1180
1183
  code: routeCode,
1181
1184
  clientBoundaryImports: clientInference.clientBoundaryImports,
1185
+ clientBoundaryFallbackImports: clientInference.clientBoundaryFallbackImports,
1182
1186
  filename: matched.route.file,
1183
1187
  serverModules: options.serverModules,
1184
1188
  serverOutput: "stream",
@@ -1285,6 +1289,7 @@ async function renderAppRequestInternal(options: RenderAppRequestOptions): Promi
1285
1289
  const output = transformServerModule({
1286
1290
  code: routeCode,
1287
1291
  clientBoundaryImports: clientInference.clientBoundaryImports,
1292
+ clientBoundaryFallbackImports: clientInference.clientBoundaryFallbackImports,
1288
1293
  filename: matched.route.file,
1289
1294
  serverModules: options.serverModules,
1290
1295
  serverOutput: "string",
@@ -2396,6 +2401,7 @@ async function loadBundledMiddlewareModule(options: {
2396
2401
  function transformServerModule(options: {
2397
2402
  code: string;
2398
2403
  clientBoundaryImports?: readonly string[];
2404
+ clientBoundaryFallbackImports?: readonly string[];
2399
2405
  filename: string;
2400
2406
  serverModules?: ReadonlyMap<string, BuiltServerModuleArtifact> | undefined;
2401
2407
  serverOutput: ServerOutputMode;
@@ -2428,7 +2434,9 @@ function transformServerModule(options: {
2428
2434
  }
2429
2435
 
2430
2436
  const awaitHydrationKey = options.serverAwaitHydration === true ? "1" : "0";
2431
- const key = `${options.filename}\0${options.serverOutput}\0${sourceHash}\0${awaitHydrationKey}`;
2437
+ const boundaryKey = options.clientBoundaryImports?.join("\0") ?? "";
2438
+ const fallbackKey = options.clientBoundaryFallbackImports?.join("\0") ?? "";
2439
+ const key = `${options.filename}\0${options.serverOutput}\0${sourceHash}\0${awaitHydrationKey}\0${boundaryKey}\0${fallbackKey}`;
2432
2440
  const cached = readRouterRuntimeCacheEntry(
2433
2441
  serverTransformCache,
2434
2442
  key,
@@ -2444,6 +2452,9 @@ function transformServerModule(options: {
2444
2452
  ...(options.clientBoundaryImports === undefined
2445
2453
  ? {}
2446
2454
  : { clientBoundaryImports: options.clientBoundaryImports }),
2455
+ ...(options.clientBoundaryFallbackImports === undefined
2456
+ ? {}
2457
+ : { clientBoundaryFallbackImports: options.clientBoundaryFallbackImports }),
2447
2458
  dev: true,
2448
2459
  filename: options.filename,
2449
2460
  serverEscape: nativeEscapeTransform,
@@ -2523,6 +2534,7 @@ function routeSourceAnalysisFromArtifact(
2523
2534
  clientInference: {
2524
2535
  client: artifact.clientRoute,
2525
2536
  clientBoundaryImports: [...artifact.clientBoundaryImports],
2537
+ clientBoundaryFallbackImports: [...(artifact.clientBoundaryFallbackImports ?? [])],
2526
2538
  diagnostics: [],
2527
2539
  },
2528
2540
  hasLoader: artifact.hasLoader,
@@ -3477,7 +3489,12 @@ async function renderShellPrefixSuffix(
3477
3489
  const artifact = serverModules?.get(shell.file)?.[serverOutput];
3478
3490
  const clientInference =
3479
3491
  artifact !== undefined && artifact.sourceHash === memoizedHashText(code)
3480
- ? { client: false, clientBoundaryImports: [], diagnostics: [] }
3492
+ ? {
3493
+ client: false,
3494
+ clientBoundaryImports: [],
3495
+ clientBoundaryFallbackImports: [],
3496
+ diagnostics: [],
3497
+ }
3481
3498
  : await inferClientRouteModule({
3482
3499
  cache: clientRouteInferenceCache,
3483
3500
  code: stripRouteClientOnlyExports(code, shell.file),
@@ -3490,6 +3507,7 @@ async function renderShellPrefixSuffix(
3490
3507
  const output = transformServerModule({
3491
3508
  code,
3492
3509
  clientBoundaryImports: clientInference.clientBoundaryImports,
3510
+ clientBoundaryFallbackImports: clientInference.clientBoundaryFallbackImports,
3493
3511
  filename: shell.file,
3494
3512
  serverModules,
3495
3513
  serverOutput,