@reckona/mreact-router 0.0.97 → 0.0.99

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 (92) 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/build.d.ts +38 -1
  10. package/dist/build.d.ts.map +1 -1
  11. package/dist/build.js +1087 -304
  12. package/dist/build.js.map +1 -1
  13. package/dist/bundle-pipeline.d.ts +7 -0
  14. package/dist/bundle-pipeline.d.ts.map +1 -1
  15. package/dist/bundle-pipeline.js +121 -87
  16. package/dist/bundle-pipeline.js.map +1 -1
  17. package/dist/cache.d.ts.map +1 -1
  18. package/dist/cache.js +10 -8
  19. package/dist/cache.js.map +1 -1
  20. package/dist/cli-options.d.ts +1 -0
  21. package/dist/cli-options.d.ts.map +1 -1
  22. package/dist/cli-options.js +16 -0
  23. package/dist/cli-options.js.map +1 -1
  24. package/dist/cli.js +1 -0
  25. package/dist/cli.js.map +1 -1
  26. package/dist/client.d.ts +6 -1
  27. package/dist/client.d.ts.map +1 -1
  28. package/dist/client.js +113 -8
  29. package/dist/client.js.map +1 -1
  30. package/dist/csrf.d.ts.map +1 -1
  31. package/dist/csrf.js +7 -3
  32. package/dist/csrf.js.map +1 -1
  33. package/dist/http.d.ts.map +1 -1
  34. package/dist/http.js +18 -1
  35. package/dist/http.js.map +1 -1
  36. package/dist/import-policy.d.ts.map +1 -1
  37. package/dist/import-policy.js +7 -3
  38. package/dist/import-policy.js.map +1 -1
  39. package/dist/index.d.ts +4 -3
  40. package/dist/index.d.ts.map +1 -1
  41. package/dist/index.js.map +1 -1
  42. package/dist/link.d.ts +5 -2
  43. package/dist/link.d.ts.map +1 -1
  44. package/dist/link.js +92 -3
  45. package/dist/link.js.map +1 -1
  46. package/dist/logger.d.ts +7 -1
  47. package/dist/logger.d.ts.map +1 -1
  48. package/dist/logger.js.map +1 -1
  49. package/dist/module-runner.d.ts +2 -0
  50. package/dist/module-runner.d.ts.map +1 -1
  51. package/dist/module-runner.js +1 -0
  52. package/dist/module-runner.js.map +1 -1
  53. package/dist/native-route-matcher.d.ts +2 -1
  54. package/dist/native-route-matcher.d.ts.map +1 -1
  55. package/dist/native-route-matcher.js +13 -2
  56. package/dist/native-route-matcher.js.map +1 -1
  57. package/dist/render.d.ts.map +1 -1
  58. package/dist/render.js +117 -2
  59. package/dist/render.js.map +1 -1
  60. package/dist/route-source.d.ts +4 -4
  61. package/dist/route-source.d.ts.map +1 -1
  62. package/dist/route-source.js +8 -8
  63. package/dist/route-source.js.map +1 -1
  64. package/dist/route-styles.d.ts +6 -0
  65. package/dist/route-styles.d.ts.map +1 -1
  66. package/dist/route-styles.js +10 -1
  67. package/dist/route-styles.js.map +1 -1
  68. package/dist/serve.d.ts +5 -0
  69. package/dist/serve.d.ts.map +1 -1
  70. package/dist/serve.js +7 -4
  71. package/dist/serve.js.map +1 -1
  72. package/package.json +11 -11
  73. package/src/actions.ts +42 -2
  74. package/src/adapters/aws-lambda.ts +33 -16
  75. package/src/build.ts +1578 -397
  76. package/src/bundle-pipeline.ts +136 -88
  77. package/src/cache.ts +13 -8
  78. package/src/cli-options.ts +20 -0
  79. package/src/cli.ts +1 -0
  80. package/src/client.ts +145 -14
  81. package/src/csrf.ts +8 -3
  82. package/src/http.ts +21 -1
  83. package/src/import-policy.ts +8 -3
  84. package/src/index.ts +5 -0
  85. package/src/link.ts +129 -8
  86. package/src/logger.ts +9 -1
  87. package/src/module-runner.ts +4 -0
  88. package/src/native-route-matcher.ts +13 -2
  89. package/src/render.ts +177 -2
  90. package/src/route-source.ts +8 -8
  91. package/src/route-styles.ts +17 -1
  92. package/src/serve.ts +11 -6
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,7 +273,9 @@ 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
  };
@@ -495,6 +498,10 @@ async function inferClientRouteModuleSource(options) {
495
498
  }
496
499
  }
497
500
  if (renderedByCall && !renderedByJsx) {
501
+ diagnostics.push(functionCallInteractiveImportDiagnostic({
502
+ filename: options.filename,
503
+ reference,
504
+ }));
498
505
  continue;
499
506
  }
500
507
  if (!importedBoundary) {
@@ -735,6 +742,22 @@ function serverOnlyClientImportReferenceDiagnostic(options) {
735
742
  source: options.reference.source,
736
743
  };
737
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
+ }
738
761
  function unsupportedClientImportReferenceDiagnostic(options) {
739
762
  if (options.reference.sideEffect) {
740
763
  return undefined;
@@ -762,7 +785,23 @@ function startsUppercase(value) {
762
785
  return /^[A-Z]/.test(value);
763
786
  }
764
787
  export function formatClientRouteInferenceDiagnostic(diagnostic) {
765
- 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
+ };
766
805
  }
767
806
  async function resolveAppLocalModule(options) {
768
807
  if (!options.specifier.startsWith(".")) {
@@ -1021,6 +1060,7 @@ export async function buildClientRouteOutput(options) {
1021
1060
  const dropConsoleFunctions = options.dropConsoleFunctions ?? resolveClientConsolePureFunctions(options.dropClientConsole);
1022
1061
  const bundled = await bundleRouterModule({
1023
1062
  code: entry.code,
1063
+ cacheDir: options.cacheDir,
1024
1064
  define: {
1025
1065
  __MREACT_CLIENT_DEVTOOLS__: "false",
1026
1066
  },
@@ -1052,6 +1092,7 @@ export async function buildClientRouteBatchOutput(options) {
1052
1092
  })));
1053
1093
  const bundled = await bundleRouterModules({
1054
1094
  base: options.assetBaseUrl ?? "/_mreact/client/",
1095
+ cacheDir: options.cacheDir,
1055
1096
  define: {
1056
1097
  __MREACT_CLIENT_DEVTOOLS__: "false",
1057
1098
  },
@@ -1492,6 +1533,10 @@ export async function __mreactPrefetch(url) {
1492
1533
  return false;
1493
1534
  }
1494
1535
 
1536
+ if (__mreactIsCurrentLocationNavigationHref(href)) {
1537
+ return false;
1538
+ }
1539
+
1495
1540
  const script = __mreactRouteScriptForNavigationUrl(href);
1496
1541
 
1497
1542
  if (script === undefined) {
@@ -1511,11 +1556,43 @@ function __mreactPrefetchNavigationHtml(href) {
1511
1556
  return false;
1512
1557
  }
1513
1558
 
1514
- __mreactNavigationState.cache.set(href, html);
1559
+ __mreactRememberNavigationHtml(href, html);
1515
1560
  return true;
1516
1561
  }).catch(() => false);
1517
1562
  }
1518
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
+
1519
1596
  function __mreactPrefetchRouteScript(script) {
1520
1597
  if (typeof document === "undefined") {
1521
1598
  return false;
@@ -1556,14 +1633,14 @@ export async function __mreactNavigate(url, options = {}) {
1556
1633
  __mreactSetNavigationState(__mreactPendingNavigationState(href, options.type ?? "push"));
1557
1634
 
1558
1635
  try {
1559
- const cachedHtml = __mreactNavigationState.cache.get(href);
1636
+ const cachedHtml = __mreactCachedNavigationHtml(href);
1560
1637
  const html = cachedHtml ?? await __mreactFetchNavigationHtml(href);
1561
1638
 
1562
1639
  if (typeof html !== "string") {
1563
1640
  return false;
1564
1641
  }
1565
1642
 
1566
- __mreactNavigationState.cache.set(href, html);
1643
+ __mreactRememberNavigationHtml(href, html);
1567
1644
  return await __mreactApplyNavigationHtmlWithOptionalTransition(html, href, options);
1568
1645
  } finally {
1569
1646
  __mreactSetNavigationState(__mreactIdleNavigationState());
@@ -2229,6 +2306,24 @@ function __mreactIsHashOnlyNavigation(nextUrl) {
2229
2306
  nextUrl.hash !== location.hash;
2230
2307
  }
2231
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
+
2232
2327
  function __mreactInstallNavigation() {
2233
2328
  if (__mreactNavigationState.installed || typeof document === "undefined") {
2234
2329
  return;
@@ -2291,6 +2386,16 @@ function __mreactInstallNavigation() {
2291
2386
  return;
2292
2387
  }
2293
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
+
2294
2399
  event.preventDefault();
2295
2400
  void __mreactNavigate(nextUrl.href, {
2296
2401
  scroll: __mreactAnchorScrollMode(anchor),