@reckona/mreact-router 0.0.96 → 0.0.98

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.
Files changed (100) hide show
  1. package/README.md +4 -0
  2. package/dist/actions.d.ts +7 -0
  3. package/dist/actions.d.ts.map +1 -1
  4. package/dist/actions.js +26 -2
  5. package/dist/actions.js.map +1 -1
  6. package/dist/adapters/aws-lambda.d.ts.map +1 -1
  7. package/dist/adapters/aws-lambda.js +10 -7
  8. package/dist/adapters/aws-lambda.js.map +1 -1
  9. package/dist/adapters/static.d.ts.map +1 -1
  10. package/dist/adapters/static.js +13 -0
  11. package/dist/adapters/static.js.map +1 -1
  12. package/dist/build.d.ts +38 -1
  13. package/dist/build.d.ts.map +1 -1
  14. package/dist/build.js +1093 -307
  15. package/dist/build.js.map +1 -1
  16. package/dist/bundle-pipeline.d.ts +7 -0
  17. package/dist/bundle-pipeline.d.ts.map +1 -1
  18. package/dist/bundle-pipeline.js +121 -69
  19. package/dist/bundle-pipeline.js.map +1 -1
  20. package/dist/cache.d.ts.map +1 -1
  21. package/dist/cache.js +10 -8
  22. package/dist/cache.js.map +1 -1
  23. package/dist/cli-options.d.ts +1 -0
  24. package/dist/cli-options.d.ts.map +1 -1
  25. package/dist/cli-options.js +16 -0
  26. package/dist/cli-options.js.map +1 -1
  27. package/dist/cli.js +1 -0
  28. package/dist/cli.js.map +1 -1
  29. package/dist/client.d.ts +6 -1
  30. package/dist/client.d.ts.map +1 -1
  31. package/dist/client.js +120 -9
  32. package/dist/client.js.map +1 -1
  33. package/dist/csrf.d.ts.map +1 -1
  34. package/dist/csrf.js +7 -3
  35. package/dist/csrf.js.map +1 -1
  36. package/dist/http.d.ts.map +1 -1
  37. package/dist/http.js +18 -1
  38. package/dist/http.js.map +1 -1
  39. package/dist/import-policy.d.ts.map +1 -1
  40. package/dist/import-policy.js +7 -3
  41. package/dist/import-policy.js.map +1 -1
  42. package/dist/index.d.ts +4 -3
  43. package/dist/index.d.ts.map +1 -1
  44. package/dist/index.js.map +1 -1
  45. package/dist/link.d.ts +5 -3
  46. package/dist/link.d.ts.map +1 -1
  47. package/dist/link.js +92 -3
  48. package/dist/link.js.map +1 -1
  49. package/dist/logger.d.ts +7 -1
  50. package/dist/logger.d.ts.map +1 -1
  51. package/dist/logger.js.map +1 -1
  52. package/dist/module-runner.d.ts +2 -0
  53. package/dist/module-runner.d.ts.map +1 -1
  54. package/dist/module-runner.js +1 -0
  55. package/dist/module-runner.js.map +1 -1
  56. package/dist/native-route-matcher.d.ts +2 -1
  57. package/dist/native-route-matcher.d.ts.map +1 -1
  58. package/dist/native-route-matcher.js +13 -2
  59. package/dist/native-route-matcher.js.map +1 -1
  60. package/dist/render.d.ts.map +1 -1
  61. package/dist/render.js +121 -6
  62. package/dist/render.js.map +1 -1
  63. package/dist/route-source.d.ts +11 -11
  64. package/dist/route-source.d.ts.map +1 -1
  65. package/dist/route-source.js +32 -25
  66. package/dist/route-source.js.map +1 -1
  67. package/dist/route-styles.d.ts +6 -0
  68. package/dist/route-styles.d.ts.map +1 -1
  69. package/dist/route-styles.js +10 -1
  70. package/dist/route-styles.js.map +1 -1
  71. package/dist/serve.d.ts +5 -0
  72. package/dist/serve.d.ts.map +1 -1
  73. package/dist/serve.js +7 -4
  74. package/dist/serve.js.map +1 -1
  75. package/dist/vite.d.ts.map +1 -1
  76. package/dist/vite.js +32 -5
  77. package/dist/vite.js.map +1 -1
  78. package/package.json +11 -11
  79. package/src/actions.ts +42 -2
  80. package/src/adapters/aws-lambda.ts +33 -16
  81. package/src/adapters/static.ts +25 -0
  82. package/src/build.ts +1605 -421
  83. package/src/bundle-pipeline.ts +136 -70
  84. package/src/cache.ts +13 -8
  85. package/src/cli-options.ts +20 -0
  86. package/src/cli.ts +1 -0
  87. package/src/client.ts +152 -15
  88. package/src/csrf.ts +8 -3
  89. package/src/http.ts +21 -1
  90. package/src/import-policy.ts +8 -3
  91. package/src/index.ts +5 -0
  92. package/src/link.ts +135 -8
  93. package/src/logger.ts +9 -1
  94. package/src/module-runner.ts +4 -0
  95. package/src/native-route-matcher.ts +13 -2
  96. package/src/render.ts +181 -6
  97. package/src/route-source.ts +33 -20
  98. package/src/route-styles.ts +17 -1
  99. package/src/serve.ts +11 -6
  100. package/src/vite.ts +41 -5
package/dist/client.js CHANGED
@@ -16,6 +16,7 @@ import { escapeHtmlQuotedAttribute as escapeHtmlAttribute } from "@reckona/mreac
16
16
  import { workspacePackageFile } from "./workspace-packages.js";
17
17
  const nodeBuiltinPackages = new Set(builtinModules.flatMap((name) => [name, `node:${name}`]));
18
18
  const clientBoundaryInferenceServerOnlyReferenceCode = "MR_CLIENT_BOUNDARY_INFERENCE_SERVER_ONLY_REFERENCE";
19
+ const clientBoundaryInferenceFunctionCallInteractiveCode = "MR_CLIENT_BOUNDARY_INFERENCE_FUNCTION_CALL_INTERACTIVE";
19
20
  const clientBoundaryInferenceUnsupportedReferenceCode = "MR_CLIENT_BOUNDARY_INFERENCE_UNSUPPORTED_REFERENCE";
20
21
  export async function routeToClientManifestEntry(route) {
21
22
  if (route.kind !== "page") {
@@ -76,7 +77,7 @@ export async function inferClientRouteModule(options) {
76
77
  }))
77
78
  : routeInference;
78
79
  if (options.appDir === undefined) {
79
- return mergedRouteInference;
80
+ return withClientRouteDiagnosticPath(mergedRouteInference, options.routePath);
80
81
  }
81
82
  const shellInferences = await inferClientRouteShellModules({
82
83
  appDir: options.appDir,
@@ -84,14 +85,14 @@ export async function inferClientRouteModule(options) {
84
85
  filename: options.filename,
85
86
  sourceTransform,
86
87
  });
87
- return {
88
+ return withClientRouteDiagnosticPath({
88
89
  client: mergedRouteInference.client || shellInferences.some((inference) => inference.client),
89
90
  clientBoundaryImports: mergedRouteInference.clientBoundaryImports,
90
91
  diagnostics: [
91
92
  ...mergedRouteInference.diagnostics,
92
93
  ...shellInferences.flatMap((inference) => inference.diagnostics),
93
94
  ],
94
- };
95
+ }, options.routePath);
95
96
  }
96
97
  catch (error) {
97
98
  throw new Error(`Failed to infer client route for ${options.routePath ?? "<unknown>"} (${options.filename}).\n${errorMessage(error)}`, { cause: error });
@@ -272,18 +273,26 @@ export async function collectClientRouteReferences(options) {
272
273
  clientBoundaryImports: routeInference.clientBoundaryImports,
273
274
  clientReferenceImports,
274
275
  clientReferenceManifest,
275
- diagnostics: sources.flatMap((source) => source.inference.diagnostics),
276
+ diagnostics: sources
277
+ .flatMap((source) => source.inference.diagnostics)
278
+ .map((diagnostic) => withClientRouteDiagnosticPath(diagnostic, options.routePath)),
276
279
  usesNavigationLink: routeInference.usesNavigationLink ||
277
280
  sources.some((source) => source.filename !== options.filename && source.inference.usesNavigationLink),
278
281
  };
279
282
  }
280
283
  export async function resolveNavigationRuntime(options) {
281
284
  const cache = options.cache ?? createClientRouteInferenceCache();
285
+ const sourceTransform = clientRouteSourceTransformForVitePlugins(options.vitePlugins);
286
+ const code = await transformClientRouteSource({
287
+ code: options.code,
288
+ filename: options.filename,
289
+ sourceTransform,
290
+ });
282
291
  // Read the override from the cached module context so the dev server does not
283
292
  // re-parse every page route on each request.
284
293
  const moduleContext = await compilerModuleContextForSource({
285
294
  cache,
286
- code: options.code,
295
+ code,
287
296
  filename: options.filename,
288
297
  });
289
298
  const override = readTopLevelBooleanExportFromContext(moduleContext, "navigationRuntime");
@@ -489,6 +498,10 @@ async function inferClientRouteModuleSource(options) {
489
498
  }
490
499
  }
491
500
  if (renderedByCall && !renderedByJsx) {
501
+ diagnostics.push(functionCallInteractiveImportDiagnostic({
502
+ filename: options.filename,
503
+ reference,
504
+ }));
492
505
  continue;
493
506
  }
494
507
  if (!importedBoundary) {
@@ -729,6 +742,22 @@ function serverOnlyClientImportReferenceDiagnostic(options) {
729
742
  source: options.reference.source,
730
743
  };
731
744
  }
745
+ function functionCallInteractiveImportDiagnostic(options) {
746
+ const localNames = options.reference.localNames.filter(startsUppercase);
747
+ const component = localNames[0] ?? options.reference.localNames[0] ?? options.reference.source;
748
+ const componentUsage = startsUppercase(component) ? `<${component} />` : "JSX";
749
+ return {
750
+ code: clientBoundaryInferenceFunctionCallInteractiveCode,
751
+ filename: options.filename,
752
+ level: "warn",
753
+ localNames: localNames.length === 0 ? options.reference.localNames : localNames,
754
+ message: `${options.filename}: interactive component import ${JSON.stringify(options.reference.source)} ` +
755
+ `is rendered through a function call as ${component}(), so its event handlers or cell() state ` +
756
+ "will not hydrate as a client boundary. Render it through JSX such as " +
757
+ `${componentUsage}, or move the call behind an explicit client boundary.`,
758
+ source: options.reference.source,
759
+ };
760
+ }
732
761
  function unsupportedClientImportReferenceDiagnostic(options) {
733
762
  if (options.reference.sideEffect) {
734
763
  return undefined;
@@ -756,7 +785,23 @@ function startsUppercase(value) {
756
785
  return /^[A-Z]/.test(value);
757
786
  }
758
787
  export function formatClientRouteInferenceDiagnostic(diagnostic) {
759
- return `${diagnostic.code}: ${diagnostic.message}`;
788
+ const route = diagnostic.routePath === undefined ? "" : ` on route ${JSON.stringify(diagnostic.routePath)}`;
789
+ return `${diagnostic.code}: ${diagnostic.message}${route}`;
790
+ }
791
+ function withClientRouteDiagnosticPath(value, routePath) {
792
+ if (routePath === undefined) {
793
+ return value;
794
+ }
795
+ if ("diagnostics" in value) {
796
+ return {
797
+ ...value,
798
+ diagnostics: value.diagnostics.map((diagnostic) => withClientRouteDiagnosticPath(diagnostic, routePath)),
799
+ };
800
+ }
801
+ return {
802
+ ...value,
803
+ routePath: value.routePath ?? routePath,
804
+ };
760
805
  }
761
806
  async function resolveAppLocalModule(options) {
762
807
  if (!options.specifier.startsWith(".")) {
@@ -1015,6 +1060,7 @@ export async function buildClientRouteOutput(options) {
1015
1060
  const dropConsoleFunctions = options.dropConsoleFunctions ?? resolveClientConsolePureFunctions(options.dropClientConsole);
1016
1061
  const bundled = await bundleRouterModule({
1017
1062
  code: entry.code,
1063
+ cacheDir: options.cacheDir,
1018
1064
  define: {
1019
1065
  __MREACT_CLIENT_DEVTOOLS__: "false",
1020
1066
  },
@@ -1046,6 +1092,7 @@ export async function buildClientRouteBatchOutput(options) {
1046
1092
  })));
1047
1093
  const bundled = await bundleRouterModules({
1048
1094
  base: options.assetBaseUrl ?? "/_mreact/client/",
1095
+ cacheDir: options.cacheDir,
1049
1096
  define: {
1050
1097
  __MREACT_CLIENT_DEVTOOLS__: "false",
1051
1098
  },
@@ -1486,6 +1533,10 @@ export async function __mreactPrefetch(url) {
1486
1533
  return false;
1487
1534
  }
1488
1535
 
1536
+ if (__mreactIsCurrentLocationNavigationHref(href)) {
1537
+ return false;
1538
+ }
1539
+
1489
1540
  const script = __mreactRouteScriptForNavigationUrl(href);
1490
1541
 
1491
1542
  if (script === undefined) {
@@ -1505,11 +1556,43 @@ function __mreactPrefetchNavigationHtml(href) {
1505
1556
  return false;
1506
1557
  }
1507
1558
 
1508
- __mreactNavigationState.cache.set(href, html);
1559
+ __mreactRememberNavigationHtml(href, html);
1509
1560
  return true;
1510
1561
  }).catch(() => false);
1511
1562
  }
1512
1563
 
1564
+ const __mreactNavigationHtmlCacheMaxEntries = 64;
1565
+
1566
+ function __mreactCachedNavigationHtml(href) {
1567
+ const html = __mreactNavigationState.cache.get(href);
1568
+
1569
+ if (html === undefined) {
1570
+ return undefined;
1571
+ }
1572
+
1573
+ __mreactNavigationState.cache.delete(href);
1574
+ __mreactNavigationState.cache.set(href, html);
1575
+ return html;
1576
+ }
1577
+
1578
+ function __mreactRememberNavigationHtml(href, html) {
1579
+ if (__mreactNavigationState.cache.has(href)) {
1580
+ __mreactNavigationState.cache.delete(href);
1581
+ }
1582
+
1583
+ __mreactNavigationState.cache.set(href, html);
1584
+
1585
+ while (__mreactNavigationState.cache.size > __mreactNavigationHtmlCacheMaxEntries) {
1586
+ const oldestHref = __mreactNavigationState.cache.keys().next().value;
1587
+
1588
+ if (oldestHref === undefined) {
1589
+ return;
1590
+ }
1591
+
1592
+ __mreactNavigationState.cache.delete(oldestHref);
1593
+ }
1594
+ }
1595
+
1513
1596
  function __mreactPrefetchRouteScript(script) {
1514
1597
  if (typeof document === "undefined") {
1515
1598
  return false;
@@ -1550,14 +1633,14 @@ export async function __mreactNavigate(url, options = {}) {
1550
1633
  __mreactSetNavigationState(__mreactPendingNavigationState(href, options.type ?? "push"));
1551
1634
 
1552
1635
  try {
1553
- const cachedHtml = __mreactNavigationState.cache.get(href);
1636
+ const cachedHtml = __mreactCachedNavigationHtml(href);
1554
1637
  const html = cachedHtml ?? await __mreactFetchNavigationHtml(href);
1555
1638
 
1556
1639
  if (typeof html !== "string") {
1557
1640
  return false;
1558
1641
  }
1559
1642
 
1560
- __mreactNavigationState.cache.set(href, html);
1643
+ __mreactRememberNavigationHtml(href, html);
1561
1644
  return await __mreactApplyNavigationHtmlWithOptionalTransition(html, href, options);
1562
1645
  } finally {
1563
1646
  __mreactSetNavigationState(__mreactIdleNavigationState());
@@ -2223,6 +2306,24 @@ function __mreactIsHashOnlyNavigation(nextUrl) {
2223
2306
  nextUrl.hash !== location.hash;
2224
2307
  }
2225
2308
 
2309
+ function __mreactIsCurrentLocationNavigationHref(href) {
2310
+ if (typeof location === "undefined") {
2311
+ return false;
2312
+ }
2313
+
2314
+ return __mreactIsCurrentLocationNavigation(new URL(href, location.href));
2315
+ }
2316
+
2317
+ function __mreactIsCurrentLocationNavigation(nextUrl) {
2318
+ if (typeof location === "undefined") {
2319
+ return false;
2320
+ }
2321
+
2322
+ return nextUrl.origin === location.origin &&
2323
+ nextUrl.pathname === location.pathname &&
2324
+ nextUrl.search === location.search;
2325
+ }
2326
+
2226
2327
  function __mreactInstallNavigation() {
2227
2328
  if (__mreactNavigationState.installed || typeof document === "undefined") {
2228
2329
  return;
@@ -2285,6 +2386,16 @@ function __mreactInstallNavigation() {
2285
2386
  return;
2286
2387
  }
2287
2388
 
2389
+ if (__mreactIsCurrentLocationNavigation(nextUrl)) {
2390
+ event.preventDefault();
2391
+
2392
+ if (__mreactAnchorScrollMode(anchor) !== false && nextUrl.hash === "") {
2393
+ __mreactScrollTo(0, 0);
2394
+ }
2395
+
2396
+ return;
2397
+ }
2398
+
2288
2399
  event.preventDefault();
2289
2400
  void __mreactNavigate(nextUrl.href, {
2290
2401
  scroll: __mreactAnchorScrollMode(anchor),