@reckona/mreact-router 0.0.73 → 0.0.74

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/dist/build.js CHANGED
@@ -2,7 +2,7 @@ import { createHash } from "node:crypto";
2
2
  import { copyFile, cp, mkdir, readdir, readFile, rm, stat, writeFile } from "node:fs/promises";
3
3
  import { builtinModules } from "node:module";
4
4
  import { dirname, join, relative, sep } from "node:path";
5
- import { collectFormActionReferenceNames, collectStaticImportReferences, collectTopLevelValueExportNames, formatDiagnostic, hasModuleDirective, transform, } from "@reckona/mreact-compiler";
5
+ import { collectStaticImportReferences, collectTopLevelValueExportNames, formatDiagnostic, hasModuleDirective, transform, } from "@reckona/mreact-compiler";
6
6
  import { transformCompilerModuleContext } from "@reckona/mreact-compiler/internal";
7
7
  import { buildClientRouteBatchOutput, buildNavigationRuntimeBundle, clientScriptForPath, compilerModuleContextForSource, collectClientRouteReferences, createClientRouteInferenceCache, detectClientNavigationHint, detectNavigationRuntimeHint, formatClientRouteInferenceDiagnostic, inferClientRouteModule, routeIdForPath, } from "./client.js";
8
8
  import { bundleAppRouterSourceModule, importAppRouterSourceModule } from "./module-runner.js";
@@ -12,11 +12,12 @@ import { resolveAppRouterProjectOptions, resolveBuildTargets, } from "./config.j
12
12
  import { routeCachePolicyFromSource } from "./cache.js";
13
13
  import { bundleMiddlewareModuleCode, renderAppRequest } from "./render.js";
14
14
  import { createAppRouterImportPolicyPlugin } from "./import-policy.js";
15
- import { hasGenerateStaticParamsExport, hasLoaderExport, hasPrerenderExport, isStreamRouteSource, routeClosureMayUseAwaitBoundary, stripRouteBuildExports, stripRouteClientOnlyExports, stripRouteLoaderOnlyExports, stripRouteMetadataOnlyExports, stripRouteRequestOnlyExports, } from "./route-source.js";
15
+ import { hasGenerateStaticParamsExport, hasLoaderExport, hasPrerenderExport, isStreamRouteSource, routeClosureMayUseAwaitBoundary, stripRouteBuildExports, stripRouteClientOnlyExports, stripRouteClientSource, stripRouteLoaderOnlyExports, stripRouteMetadataOnlyExports, stripRouteRequestOnlyExports, } from "./route-source.js";
16
16
  import { bundleRouterModule, } from "./bundle-pipeline.js";
17
17
  import { collectRouteCssFiles } from "./route-styles.js";
18
18
  import { existingRouteShellCandidates } from "./route-shells.js";
19
19
  import { sourceModuleCandidates } from "./source-modules.js";
20
+ import { collectBuildInferredServerActions } from "./server-action-inference.js";
20
21
  import { workspacePackageFile } from "./workspace-packages.js";
21
22
  const nativeEscapeTransform = {
22
23
  batchImportName: "escapeHtmlBatch",
@@ -48,7 +49,7 @@ export async function buildApp(options) {
48
49
  const publicAssets = [
49
50
  ...new Set([...(await collectPublicAssetPaths(project.publicDir)), ...appConventionPublicAssets]),
50
51
  ].sort();
51
- const serverActionManifest = collectBuildServerActionManifest({
52
+ const serverActionManifest = await collectBuildServerActionManifest({
52
53
  files,
53
54
  projectRoot: project.projectRoot,
54
55
  routes,
@@ -116,6 +117,7 @@ export async function buildApp(options) {
116
117
  vitePlugins,
117
118
  });
118
119
  }
120
+ const routeServerActionReferences = Object.fromEntries([...serverActionManifest.routeReferences.entries()].sort(([left], [right]) => left.localeCompare(right)));
119
121
  const serverManifest = {
120
122
  allowedSourceDirs: project.allowedSourceDirs.map((directory) => relative(project.projectRoot, directory)),
121
123
  ...(project.assetBaseUrl === undefined ? {} : { assetBaseUrl: project.assetBaseUrl }),
@@ -127,7 +129,12 @@ export async function buildApp(options) {
127
129
  ...(project.publicAssetBaseUrl === undefined
128
130
  ? {}
129
131
  : { publicAssetBaseUrl: project.publicAssetBaseUrl }),
130
- ...(serverActionManifest.length === 0 ? {} : { serverActionManifest }),
132
+ ...(Object.keys(routeServerActionReferences).length === 0
133
+ ? {}
134
+ : { routeServerActionReferences }),
135
+ ...(serverActionManifest.allowedActions.length === 0
136
+ ? {}
137
+ : { serverActionManifest: serverActionManifest.allowedActions }),
131
138
  ...(Object.keys(serverModuleArtifacts.files).length === 0
132
139
  ? {}
133
140
  : { serverModuleFiles: serverModuleArtifacts.files }),
@@ -343,8 +350,9 @@ function runtimePackageNameForSpecifier(specifier) {
343
350
  const [scope, name] = specifier.split("/");
344
351
  return scope !== undefined && name !== undefined ? `${scope}/${name}` : specifier;
345
352
  }
346
- function collectBuildServerActionManifest(options) {
353
+ async function collectBuildServerActionManifest(options) {
347
354
  const entries = new Map();
355
+ const routeReferences = new Map();
348
356
  const relativeRoutesDir = relative(options.projectRoot, options.routesDir);
349
357
  const routeSourceFiles = new Set(options.routes
350
358
  .filter((route) => route.kind === "page")
@@ -360,56 +368,46 @@ function collectBuildServerActionManifest(options) {
360
368
  }
361
369
  }
362
370
  if (routeSourceFiles.has(file)) {
363
- for (const reference of collectBuildInferredServerActionReferences({
371
+ const inference = await collectBuildInferredServerActionReferences({
364
372
  file,
365
373
  files: options.files,
366
374
  relativeRoutesDir,
367
375
  source: code,
368
- })) {
376
+ });
377
+ for (const diagnostic of inference.diagnostics) {
378
+ console.warn(formatServerActionInferenceDiagnostic(diagnostic));
379
+ }
380
+ routeReferences.set(file, inference.references);
381
+ for (const reference of inference.references) {
369
382
  const key = `${reference.moduleId}#${reference.exportName}`;
370
383
  if (!entries.has(key)) {
371
- entries.set(key, reference);
384
+ entries.set(key, {
385
+ exportName: reference.exportName,
386
+ inferred: reference.inferred,
387
+ moduleId: reference.moduleId,
388
+ });
372
389
  }
373
390
  }
374
391
  }
375
392
  }
376
- return [...entries.values()].sort((left, right) => left.moduleId === right.moduleId
377
- ? left.exportName.localeCompare(right.exportName)
378
- : left.moduleId.localeCompare(right.moduleId));
393
+ return {
394
+ allowedActions: [...entries.values()].sort((left, right) => left.moduleId === right.moduleId
395
+ ? left.exportName.localeCompare(right.exportName)
396
+ : left.moduleId.localeCompare(right.moduleId)),
397
+ routeReferences,
398
+ };
379
399
  }
380
400
  function collectBuildInferredServerActionReferences(options) {
381
- const actionNames = collectFormActionNames(options.source);
382
- if (actionNames.size === 0) {
383
- return [];
384
- }
385
- const references = [];
386
- for (const match of options.source.matchAll(/^import\s+\{\s*(?<specifiers>[^}]+)\s*\}\s+from\s+["'](?<source>[^"']+)["'];?/gm)) {
387
- const source = match.groups?.source;
388
- const specifiers = match.groups?.specifiers;
389
- if (source === undefined || specifiers === undefined || !source.startsWith(".")) {
390
- continue;
391
- }
392
- const localFile = resolveBuildLocalSourceImport(options.files, options.file, source);
393
- if (localFile === undefined) {
394
- continue;
395
- }
396
- const moduleId = moduleIdForBuildFile(localFile, options.relativeRoutesDir);
397
- for (const specifier of specifiers.split(",")) {
398
- const [exportName, localName] = specifier.trim().split(/\s+as\s+/);
399
- const imported = exportName?.trim();
400
- const local = localName?.trim() ?? imported;
401
- if (imported !== undefined &&
402
- imported.length > 0 &&
403
- local !== undefined &&
404
- actionNames.has(local)) {
405
- references.push({ moduleId, exportName: imported, inferred: true });
406
- }
407
- }
408
- }
409
- return references;
401
+ return collectBuildInferredServerActions({
402
+ file: options.file,
403
+ files: options.files,
404
+ relativeRoutesDir: options.relativeRoutesDir,
405
+ resolveSourceImport: (importer, source) => resolveBuildLocalSourceImport(options.files, importer, source),
406
+ source: options.source,
407
+ });
410
408
  }
411
- function collectFormActionNames(code) {
412
- return new Set(collectFormActionReferenceNames({ code }));
409
+ function formatServerActionInferenceDiagnostic(diagnostic) {
410
+ return `${diagnostic.code}: ${diagnostic.message}`;
413
411
  }
414
412
  function isSourceModuleFile(file) {
415
413
  return /\.(?:mreact\.tsx|tsx?|jsx?|mjs|mts|cjs|cts)$/.test(file);
@@ -667,7 +665,9 @@ async function buildServerModuleArtifacts(options) {
667
665
  const clientInference = await inferClientRouteModule({
668
666
  ...(route === undefined ? {} : { appDir: options.project.routesDir }),
669
667
  cache: options.clientRouteInferenceCache,
670
- code: stripRouteClientOnlyExports(source),
668
+ code: route === undefined
669
+ ? stripRouteClientOnlyExports(source)
670
+ : stripRouteClientSource({ code: source, filename: route.file }),
671
671
  filename: join(options.projectRoot, file),
672
672
  ...(route === undefined ? {} : { routePath: route.path }),
673
673
  vitePlugins: options.vitePlugins,
@@ -1781,7 +1781,7 @@ async function writeClientRouteBundles(options) {
1781
1781
  vitePlugins: options.vitePlugins,
1782
1782
  });
1783
1783
  const source = await readFile(route.file, "utf8");
1784
- const clientSource = stripRouteClientOnlyExports(source);
1784
+ const clientSource = stripRouteClientSource({ code: source, filename: route.file });
1785
1785
  const navigation = detectNavigationRuntimeHint(source);
1786
1786
  const references = await collectClientRouteReferences({
1787
1787
  appDir: options.appDir,