@reckona/mreact-router 0.0.132 → 0.0.135

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 (49) hide show
  1. package/README.md +1 -1
  2. package/dist/adapters/cloudflare.js +1 -1
  3. package/dist/adapters/cloudflare.js.map +1 -1
  4. package/dist/adapters/static.js +5 -1
  5. package/dist/adapters/static.js.map +1 -1
  6. package/dist/build.d.ts +1 -0
  7. package/dist/build.d.ts.map +1 -1
  8. package/dist/build.js +136 -41
  9. package/dist/build.js.map +1 -1
  10. package/dist/client.d.ts.map +1 -1
  11. package/dist/client.js +167 -8
  12. package/dist/client.js.map +1 -1
  13. package/dist/http.d.ts +1 -0
  14. package/dist/http.d.ts.map +1 -1
  15. package/dist/http.js +7 -1
  16. package/dist/http.js.map +1 -1
  17. package/dist/module-runner.d.ts +4 -1
  18. package/dist/module-runner.d.ts.map +1 -1
  19. package/dist/module-runner.js +3 -2
  20. package/dist/module-runner.js.map +1 -1
  21. package/dist/render.d.ts +6 -1
  22. package/dist/render.d.ts.map +1 -1
  23. package/dist/render.js +84 -46
  24. package/dist/render.js.map +1 -1
  25. package/dist/routes.js +1 -1
  26. package/dist/routes.js.map +1 -1
  27. package/dist/serve.d.ts.map +1 -1
  28. package/dist/serve.js +110 -17
  29. package/dist/serve.js.map +1 -1
  30. package/dist/vite-plugin-cache-key.d.ts +2 -1
  31. package/dist/vite-plugin-cache-key.d.ts.map +1 -1
  32. package/dist/vite-plugin-cache-key.js +9 -0
  33. package/dist/vite-plugin-cache-key.js.map +1 -1
  34. package/dist/vite.d.ts +2 -1
  35. package/dist/vite.d.ts.map +1 -1
  36. package/dist/vite.js +2 -0
  37. package/dist/vite.js.map +1 -1
  38. package/package.json +11 -11
  39. package/src/adapters/cloudflare.ts +1 -1
  40. package/src/adapters/static.ts +7 -1
  41. package/src/build.ts +201 -53
  42. package/src/client.ts +288 -17
  43. package/src/http.ts +9 -1
  44. package/src/module-runner.ts +8 -2
  45. package/src/render.ts +117 -21
  46. package/src/routes.ts +1 -1
  47. package/src/serve.ts +167 -18
  48. package/src/vite-plugin-cache-key.ts +12 -1
  49. package/src/vite.ts +4 -0
package/dist/build.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { createHash } from "node:crypto";
2
- import { copyFile, cp, mkdir, readdir, readFile, rm, stat, writeFile } from "node:fs/promises";
2
+ import { copyFile, cp, lstat, mkdir, readdir, readFile, rm, stat, writeFile, } from "node:fs/promises";
3
3
  import { builtinModules } from "node:module";
4
4
  import { availableParallelism } from "node:os";
5
5
  import { dirname, join, relative, resolve, sep } from "node:path";
@@ -21,7 +21,7 @@ import { collectRouteCssFilesFromSources, collectSpecialBoundaryFiles } from "./
21
21
  import { existingRouteShellCandidates } from "./route-shells.js";
22
22
  import { sourceModuleCandidates } from "./source-modules.js";
23
23
  import { collectBuildInferredServerActions } from "./server-action-inference.js";
24
- import { vitePluginsCacheKey } from "./vite-plugin-cache-key.js";
24
+ import { viteDefineCacheKey, vitePluginsCacheKey } from "./vite-plugin-cache-key.js";
25
25
  import { workspacePackageFile } from "./workspace-packages.js";
26
26
  const nativeEscapeTransform = {
27
27
  batchImportName: "escapeHtmlBatch",
@@ -133,6 +133,7 @@ export async function buildApp(options) {
133
133
  ? buildServerModuleArtifacts({
134
134
  bundleCache: new Map(),
135
135
  clientRouteInferenceCache: serverClientRouteInferenceCache,
136
+ define: viteDefine,
136
137
  files,
137
138
  prebundleServerComponents: buildTargets.includes("node") || shouldBuildAwsLambda,
138
139
  project,
@@ -145,6 +146,7 @@ export async function buildApp(options) {
145
146
  : timeBuildPhase(timingSink, "serverModules", () => buildServerModuleArtifacts({
146
147
  bundleCache: new Map(),
147
148
  clientRouteInferenceCache: serverClientRouteInferenceCache,
149
+ define: viteDefine,
148
150
  files,
149
151
  prebundleServerComponents: buildTargets.includes("node") || shouldBuildAwsLambda,
150
152
  project,
@@ -225,6 +227,7 @@ export async function buildApp(options) {
225
227
  appDir: project.routesDir,
226
228
  assetBaseUrl: project.assetBaseUrl,
227
229
  clientRoutes: clientManifestRoutes,
230
+ define: viteDefine,
228
231
  project,
229
232
  routes,
230
233
  serverModules,
@@ -235,6 +238,7 @@ export async function buildApp(options) {
235
238
  appDir: project.routesDir,
236
239
  assetBaseUrl: project.assetBaseUrl,
237
240
  clientRoutes: clientManifestRoutes,
241
+ define: viteDefine,
238
242
  project,
239
243
  routes,
240
244
  serverModules,
@@ -712,7 +716,12 @@ async function collectRuntimeOptionalPackages(options) {
712
716
  const queue = [
713
717
  { packageName: options.packageName, optional: false, startDir: options.projectRoot },
714
718
  ];
715
- for (let index = 0; index < queue.length && seenPackageJson.size < maxRuntimePackageManifestReads; index += 1) {
719
+ let stoppedAtManifestReadCap = false;
720
+ for (let index = 0; index < queue.length; index += 1) {
721
+ if (seenPackageJson.size >= maxRuntimePackageManifestReads) {
722
+ stoppedAtManifestReadCap = true;
723
+ break;
724
+ }
716
725
  const item = queue[index];
717
726
  if (item === undefined || !isValidRuntimePackageName(item.packageName)) {
718
727
  continue;
@@ -741,6 +750,14 @@ async function collectRuntimeOptionalPackages(options) {
741
750
  }
742
751
  }
743
752
  }
753
+ if (stoppedAtManifestReadCap) {
754
+ console.warn([
755
+ "MR_RUNTIME_PACKAGE_MANIFEST_SCAN_LIMIT:",
756
+ `stopped scanning optional runtime package manifests after ${maxRuntimePackageManifestReads} files`,
757
+ `while collecting transitive optional dependencies for ${options.packageName}.`,
758
+ "Generated import-policy.json may omit deeper optional runtime packages.",
759
+ ].join(" "));
760
+ }
744
761
  return [...optionalPackages].sort();
745
762
  }
746
763
  async function readRuntimePackageManifest(options) {
@@ -880,32 +897,30 @@ function moduleIdForBuildFile(file, relativeRoutesDir) {
880
897
  return relativeRoutesDir === "" ? file : file.slice(relativeRoutesDir.length + 1);
881
898
  }
882
899
  async function copyPublicAssets(publicDir, outDir) {
883
- try {
884
- await cp(publicDir, outDir, { force: true, recursive: true });
885
- }
886
- catch (error) {
887
- if (isNodeError(error) && error.code === "ENOENT") {
888
- return;
889
- }
890
- throw error;
900
+ if (!(await isPublicAssetDirectory(publicDir))) {
901
+ return;
891
902
  }
903
+ await copyPublicAssetsInner(publicDir, "", outDir);
892
904
  }
893
905
  async function collectPublicAssetPaths(publicDir) {
906
+ if (!(await isPublicAssetDirectory(publicDir))) {
907
+ return [];
908
+ }
909
+ const paths = [];
910
+ await collectPublicAssetPathsInner(publicDir, "", paths);
911
+ return paths.sort();
912
+ }
913
+ async function isPublicAssetDirectory(publicDir) {
894
914
  try {
895
- const info = await stat(publicDir);
896
- if (!info.isDirectory()) {
897
- return [];
898
- }
915
+ const info = await lstat(publicDir);
916
+ return info.isDirectory();
899
917
  }
900
918
  catch (error) {
901
919
  if (isNodeError(error) && error.code === "ENOENT") {
902
- return [];
920
+ return false;
903
921
  }
904
922
  throw error;
905
923
  }
906
- const paths = [];
907
- await collectPublicAssetPathsInner(publicDir, "", paths);
908
- return paths.sort();
909
924
  }
910
925
  async function copyAppFileConventionAssets(appDir, outDir) {
911
926
  let entries;
@@ -938,20 +953,46 @@ async function collectPublicAssetPathsInner(publicDir, relativeDir, paths) {
938
953
  const entries = await readdir(join(publicDir, relativeDir), { withFileTypes: true });
939
954
  for (const entry of entries) {
940
955
  const relativePath = relativeDir === "" ? entry.name : `${relativeDir}/${entry.name}`;
956
+ const publicPath = `/${relativePath}`;
957
+ if (isReservedPublicAssetPath(publicPath)) {
958
+ continue;
959
+ }
941
960
  if (entry.isDirectory()) {
942
961
  await collectPublicAssetPathsInner(publicDir, relativePath, paths);
943
962
  continue;
944
963
  }
945
964
  if (entry.isFile()) {
946
- paths.push(`/${relativePath}`);
965
+ paths.push(publicPath);
947
966
  }
948
967
  }
949
968
  }
969
+ async function copyPublicAssetsInner(publicDir, relativeDir, outDir) {
970
+ const entries = await readdir(join(publicDir, relativeDir), { withFileTypes: true });
971
+ for (const entry of entries) {
972
+ const relativePath = relativeDir === "" ? entry.name : `${relativeDir}/${entry.name}`;
973
+ if (isReservedPublicAssetPath(`/${relativePath}`)) {
974
+ continue;
975
+ }
976
+ if (entry.isDirectory()) {
977
+ await copyPublicAssetsInner(publicDir, relativePath, outDir);
978
+ continue;
979
+ }
980
+ if (entry.isFile()) {
981
+ const destination = join(outDir, relativePath);
982
+ await mkdir(dirname(destination), { recursive: true });
983
+ await copyFile(join(publicDir, relativePath), destination);
984
+ }
985
+ }
986
+ }
987
+ function isReservedPublicAssetPath(pathname) {
988
+ return pathname === "/_mreact" || pathname.startsWith("/_mreact/");
989
+ }
950
990
  function isNodeError(error) {
951
991
  return error instanceof Error && "code" in error;
952
992
  }
953
993
  async function prerenderStaticRoutes(options) {
954
994
  const clientScripts = new Map(options.clientRoutes.flatMap((route) => route.client && route.script !== undefined ? [[route.path, route.script]] : []));
995
+ const clientStyles = new Map(options.clientRoutes.flatMap((route) => route.css !== undefined && route.css.length > 0 ? [[route.path, route.css]] : []));
955
996
  const prerendered = {};
956
997
  const importPolicy = {
957
998
  allowedPackages: await readDeclaredProjectPackages(options.project.projectRoot),
@@ -974,6 +1015,8 @@ async function prerenderStaticRoutes(options) {
974
1015
  appDir: options.appDir,
975
1016
  assetBaseUrl: options.assetBaseUrl,
976
1017
  clientScripts,
1018
+ clientStyles,
1019
+ define: options.define,
977
1020
  importPolicy,
978
1021
  request: new Request(`http://mreact.local${pathname}`),
979
1022
  serverModules: serverModuleMap,
@@ -1105,6 +1148,7 @@ async function buildServerModuleArtifacts(options) {
1105
1148
  cacheDir: options.cacheDir,
1106
1149
  entries: requestBatchEntries,
1107
1150
  importPolicy: requestModuleImportPolicy,
1151
+ define: options.define,
1108
1152
  vitePlugins: options.vitePlugins,
1109
1153
  })
1110
1154
  : new Map();
@@ -1125,6 +1169,7 @@ async function buildServerModuleArtifacts(options) {
1125
1169
  code: stripRouteLoaderOnlyExports(source, absoluteFile),
1126
1170
  filename: absoluteFile,
1127
1171
  importPolicy: requestModuleImportPolicy,
1172
+ define: options.define,
1128
1173
  vitePlugins: options.vitePlugins,
1129
1174
  }));
1130
1175
  artifact.loader = {
@@ -1142,6 +1187,7 @@ async function buildServerModuleArtifacts(options) {
1142
1187
  filename: absoluteFile,
1143
1188
  importPolicy: requestModuleImportPolicy,
1144
1189
  label: "Metadata",
1190
+ define: options.define,
1145
1191
  vitePlugins: options.vitePlugins,
1146
1192
  }));
1147
1193
  artifact.routeMetadata = {
@@ -1159,6 +1205,7 @@ async function buildServerModuleArtifacts(options) {
1159
1205
  cacheDir: options.cacheDir,
1160
1206
  filename: absoluteFile,
1161
1207
  importPolicy: requestModuleImportPolicy,
1208
+ define: options.define,
1162
1209
  routeKind: route?.kind,
1163
1210
  source,
1164
1211
  vitePlugins: options.vitePlugins,
@@ -1246,6 +1293,7 @@ async function buildServerModuleArtifacts(options) {
1246
1293
  clientRouteInferenceCache: options.clientRouteInferenceCache,
1247
1294
  code: output.code,
1248
1295
  filename: absoluteFile,
1296
+ define: options.define,
1249
1297
  root: options.projectRoot,
1250
1298
  serverOutput,
1251
1299
  vitePlugins: options.vitePlugins,
@@ -1275,11 +1323,13 @@ async function buildServerModuleArtifacts(options) {
1275
1323
  async function buildServerComponentBundleArtifactCode(options) {
1276
1324
  return await bundleAppRouterSourceModule({
1277
1325
  code: options.code,
1326
+ define: options.define,
1278
1327
  label: `server-component:${options.filename}`,
1279
1328
  resolveDir: dirname(options.filename),
1280
1329
  root: options.root,
1281
1330
  serverSourceTransform: {
1282
1331
  clientRouteInferenceCache: options.clientRouteInferenceCache,
1332
+ define: options.define,
1283
1333
  dev: false,
1284
1334
  serverOutput: options.serverOutput,
1285
1335
  vitePlugins: options.vitePlugins,
@@ -1377,6 +1427,7 @@ async function buildRequestModuleArtifactCode(options) {
1377
1427
  return await bundleMiddlewareModuleCode({
1378
1428
  appDir: options.appDir,
1379
1429
  code: options.source,
1430
+ define: options.define,
1380
1431
  file: options.filename,
1381
1432
  importPolicy: options.importPolicy,
1382
1433
  vitePlugins: options.vitePlugins,
@@ -1385,6 +1436,7 @@ async function buildRequestModuleArtifactCode(options) {
1385
1436
  if (options.routeKind === "server" || options.routeKind === "metadata") {
1386
1437
  return await bundleAppRouterSourceModule({
1387
1438
  code: options.source,
1439
+ define: options.define,
1388
1440
  label: `server-route:${options.filename}`,
1389
1441
  plugins: [fileImportMetaUrlPlugin()],
1390
1442
  resolveDir: dirname(options.filename),
@@ -1398,6 +1450,7 @@ async function buildRequestModuleArtifactCode(options) {
1398
1450
  bundleCache: options.bundleCache,
1399
1451
  cacheDir: options.cacheDir,
1400
1452
  code: stripRouteRequestOnlyExports(options.source, options.filename),
1453
+ define: options.define,
1401
1454
  filename: options.filename,
1402
1455
  importPolicy: options.importPolicy,
1403
1456
  vitePlugins: options.vitePlugins,
@@ -1426,6 +1479,7 @@ async function bundleRouteRequestModuleBatchCode(options) {
1426
1479
  bundleCache: options.bundleCache,
1427
1480
  cacheDir: options.cacheDir,
1428
1481
  code: entry.code,
1482
+ define: options.define,
1429
1483
  filename: entry.filename,
1430
1484
  importPolicy: options.importPolicy,
1431
1485
  label: entry.label,
@@ -1447,6 +1501,7 @@ async function bundleRouteRequestModuleBatchCode(options) {
1447
1501
  name: namesByKey.get(entry.key) ?? hashText(entry.key).slice(0, 8),
1448
1502
  })),
1449
1503
  entryFileNames: "request/[name].js",
1504
+ define: options.define,
1450
1505
  platform: "node",
1451
1506
  plugins: [
1452
1507
  fileImportMetaUrlPlugin(),
@@ -1467,6 +1522,7 @@ async function bundleRouteRequestModuleBatchCode(options) {
1467
1522
  bundleCache: options.bundleCache,
1468
1523
  cacheDir: options.cacheDir,
1469
1524
  code: entry.code,
1525
+ define: options.define,
1470
1526
  filename: entry.filename,
1471
1527
  importPolicy: options.importPolicy,
1472
1528
  label: entry.label,
@@ -1489,6 +1545,7 @@ export async function __bundleRouteRequestModuleBatchForTests(options) {
1489
1545
  return Object.fromEntries(await bundleRouteRequestModuleBatchCode({
1490
1546
  appDir: options.appDir,
1491
1547
  cacheDir: options.cacheDir,
1548
+ define: options.define,
1492
1549
  entries: options.entries,
1493
1550
  importPolicy: options.importPolicy,
1494
1551
  vitePlugins: options.vitePlugins,
@@ -1500,6 +1557,7 @@ async function bundleRouteRequestModuleCode(options) {
1500
1557
  cacheDir: options.cacheDir,
1501
1558
  cacheKey: routeRequestBundleCacheKey(options),
1502
1559
  code: options.code,
1560
+ define: options.define,
1503
1561
  filename: options.filename,
1504
1562
  platform: "node",
1505
1563
  root: options.importPolicy?.projectRoot,
@@ -1538,6 +1596,7 @@ function routeRequestBundleCacheKey(options) {
1538
1596
  label: options.label,
1539
1597
  platform: "node",
1540
1598
  target: "es2022",
1599
+ viteDefine: viteDefineCacheKey(options.define),
1541
1600
  vitePlugins: vitePluginsCacheKey(options.vitePlugins),
1542
1601
  });
1543
1602
  }
@@ -2420,7 +2479,12 @@ function cloudflareHydrationMarkerParts(props) {
2420
2479
  }
2421
2480
 
2422
2481
  function escapeScriptJson(json) {
2423
- return json.replaceAll("<", "\\\\u003c");
2482
+ return json
2483
+ .replaceAll("&", "\\\\u0026")
2484
+ .replaceAll("<", "\\\\u003c")
2485
+ .replaceAll(">", "\\\\u003e")
2486
+ .replaceAll("\\u2028", "\\\\u2028")
2487
+ .replaceAll("\\u2029", "\\\\u2029");
2424
2488
  }
2425
2489
 
2426
2490
  function cloudflareRouteIdForPath(path) {
@@ -3066,6 +3130,7 @@ async function writeClientRouteBundles(options) {
3066
3130
  const pageRoutes = options.routes.filter((route) => route.kind === "page");
3067
3131
  const routeCssAssets = await writeRouteCssAssetBatches({
3068
3132
  appDir: options.appDir,
3133
+ assetBaseUrl: options.assetBaseUrl,
3069
3134
  cacheDir: options.cacheDir,
3070
3135
  clientDir: options.clientDir,
3071
3136
  pageRoutes,
@@ -3075,6 +3140,7 @@ async function writeClientRouteBundles(options) {
3075
3140
  });
3076
3141
  const specialCssAssets = await writeSpecialRouteCssAssetBatches({
3077
3142
  appDir: options.appDir,
3143
+ assetBaseUrl: options.assetBaseUrl,
3078
3144
  cacheDir: options.cacheDir,
3079
3145
  clientDir: options.clientDir,
3080
3146
  projectRoot: options.projectRoot,
@@ -3087,7 +3153,7 @@ async function writeClientRouteBundles(options) {
3087
3153
  manifest: { path: route.path, kind: route.kind, client: false },
3088
3154
  };
3089
3155
  }
3090
- const css = routeCssAssets.get(route.file) ?? [];
3156
+ const css = routeCssAssets.byRoute.get(route.file) ?? [];
3091
3157
  const source = buildSourceAnalysisForFile(options.sourceAnalysis, options.projectRoot, route.file)?.source;
3092
3158
  if (source === undefined) {
3093
3159
  return {
@@ -3147,9 +3213,9 @@ async function writeClientRouteBundles(options) {
3147
3213
  const clientEntries = entries.filter((entry) => "build" in entry);
3148
3214
  if (clientEntries.length === 0) {
3149
3215
  return {
3150
- assets: [],
3216
+ assets: [...routeCssAssets.assets, ...specialCssAssets.assets].sort(),
3151
3217
  routes: entries.flatMap((entry) => ("manifest" in entry ? [entry.manifest] : [])),
3152
- styles: specialCssAssets,
3218
+ styles: specialCssAssets.styles,
3153
3219
  };
3154
3220
  }
3155
3221
  let output;
@@ -3195,7 +3261,10 @@ async function writeClientRouteBundles(options) {
3195
3261
  await mkdir(dirname(join(options.clientDir, asset.fileName)), { recursive: true });
3196
3262
  await writeFile(join(options.clientDir, asset.fileName), source);
3197
3263
  }
3198
- const generatedAssets = new Set();
3264
+ const generatedAssets = new Set([
3265
+ ...routeCssAssets.assets,
3266
+ ...specialCssAssets.assets,
3267
+ ]);
3199
3268
  for (const chunk of output.chunks) {
3200
3269
  generatedAssets.add(chunk.fileName);
3201
3270
  if (options.sourceMaps === "linked" && chunk.map !== undefined) {
@@ -3241,7 +3310,7 @@ async function writeClientRouteBundles(options) {
3241
3310
  return {
3242
3311
  assets: Array.from(generatedAssets).sort(),
3243
3312
  routes,
3244
- styles: specialCssAssets,
3313
+ styles: specialCssAssets.styles,
3245
3314
  };
3246
3315
  }
3247
3316
  async function writeSpecialRouteCssAssetBatches(options) {
@@ -3256,7 +3325,8 @@ async function writeSpecialRouteCssAssetBatches(options) {
3256
3325
  if (cssFiles.length === 0) {
3257
3326
  return undefined;
3258
3327
  }
3259
- const css = await writeRouteCssAssetsForFiles({
3328
+ const batch = await writeRouteCssAssetsForFiles({
3329
+ assetBaseUrl: options.assetBaseUrl,
3260
3330
  cacheDir: options.cacheDir,
3261
3331
  clientDir: options.clientDir,
3262
3332
  cssFiles,
@@ -3265,16 +3335,22 @@ async function writeSpecialRouteCssAssetBatches(options) {
3265
3335
  routeIds: [specialBoundaryRouteId(options.appDir, file)],
3266
3336
  vitePlugins: options.vitePlugins,
3267
3337
  });
3268
- return css.length === 0
3338
+ return batch.css.length === 0
3269
3339
  ? undefined
3270
- : {
3271
- css,
3272
- file: relative(options.appDir, file).split(sep).join("/"),
3273
- };
3340
+ : ({
3341
+ assets: batch.assets,
3342
+ style: {
3343
+ css: batch.css,
3344
+ file: relative(options.appDir, file).split(sep).join("/"),
3345
+ },
3346
+ });
3274
3347
  });
3275
- return entries
3276
- .filter((entry) => entry !== undefined)
3277
- .sort((left, right) => left.file.localeCompare(right.file));
3348
+ return {
3349
+ assets: entries.flatMap((entry) => entry?.assets ?? []).sort(),
3350
+ styles: entries
3351
+ .flatMap((entry) => (entry === undefined ? [] : [entry.style]))
3352
+ .sort((left, right) => left.file.localeCompare(right.file)),
3353
+ };
3278
3354
  }
3279
3355
  function specialBoundaryRouteId(appDir, file) {
3280
3356
  const relativeFile = relative(appDir, file).split(sep);
@@ -3308,6 +3384,7 @@ async function writeRouteCssAssetBatches(options) {
3308
3384
  const writtenGroups = await mapWithBuildConcurrency([...groups.entries()], async ([key, group]) => [
3309
3385
  key,
3310
3386
  await writeRouteCssAssetsForFiles({
3387
+ assetBaseUrl: options.assetBaseUrl,
3311
3388
  cacheDir: options.cacheDir,
3312
3389
  clientDir: options.clientDir,
3313
3390
  cssFiles: group.cssFiles,
@@ -3319,24 +3396,30 @@ async function writeRouteCssAssetBatches(options) {
3319
3396
  ]);
3320
3397
  const cssByGroup = new Map(writtenGroups);
3321
3398
  const cssByRoute = new Map();
3399
+ const assets = new Set();
3322
3400
  for (const [key, group] of groups) {
3323
- const css = cssByGroup.get(key) ?? [];
3401
+ const batch = cssByGroup.get(key);
3402
+ const css = batch?.css ?? [];
3403
+ for (const asset of batch?.assets ?? []) {
3404
+ assets.add(asset);
3405
+ }
3324
3406
  for (const routeFile of group.routeFiles) {
3325
3407
  cssByRoute.set(routeFile, css);
3326
3408
  }
3327
3409
  }
3328
- return cssByRoute;
3410
+ return { assets: [...assets].sort(), byRoute: cssByRoute };
3329
3411
  }
3330
3412
  async function writeRouteCssAssetsForFiles(options) {
3331
3413
  const cssFiles = [...options.cssFiles];
3332
3414
  if (cssFiles.length === 0) {
3333
- return [];
3415
+ return { assets: [], css: [] };
3334
3416
  }
3335
3417
  const code = [
3336
3418
  ...cssFiles.map((file) => `import ${JSON.stringify(file)};`),
3337
3419
  "export default undefined;",
3338
3420
  ].join("\n");
3339
3421
  const output = await bundleRouterModule({
3422
+ base: options.assetBaseUrl ?? "/_mreact/client/",
3340
3423
  cacheDir: options.cacheDir,
3341
3424
  code,
3342
3425
  filename: options.pageFile,
@@ -3346,6 +3429,8 @@ async function writeRouteCssAssetsForFiles(options) {
3346
3429
  vitePlugins: options.vitePlugins,
3347
3430
  });
3348
3431
  const cssAssets = (output.assets ?? []).filter((asset) => asset.fileName.endsWith(".css"));
3432
+ const nonCssAssets = (output.assets ?? []).filter((asset) => !asset.fileName.endsWith(".css"));
3433
+ const writtenAssets = [];
3349
3434
  const written = [];
3350
3435
  const routeStem = options.routeIds.length === 1
3351
3436
  ? (options.routeIds[0] ?? "index")
@@ -3358,7 +3443,12 @@ async function writeRouteCssAssetsForFiles(options) {
3358
3443
  await writeFile(join(options.clientDir, cssFile), source);
3359
3444
  written.push(cssFile);
3360
3445
  }
3361
- return written;
3446
+ for (const asset of nonCssAssets) {
3447
+ await mkdir(dirname(join(options.clientDir, asset.fileName)), { recursive: true });
3448
+ await writeFile(join(options.clientDir, asset.fileName), typeof asset.source === "string" ? asset.source : Buffer.from(asset.source));
3449
+ writtenAssets.push(asset.fileName);
3450
+ }
3451
+ return { assets: writtenAssets.sort(), css: written };
3362
3452
  }
3363
3453
  function applyClientSourceMapReference(options) {
3364
3454
  const sourceMappingUrlPattern = /\n?\/\/# sourceMappingURL=route\.js\.map\s*$/;
@@ -3552,7 +3642,11 @@ function assertPackageOutputDoesNotReplaceBuildOutput(options) {
3552
3642
  }
3553
3643
  async function copyCloudflarePagesPublicAssets(options) {
3554
3644
  for (const asset of options.publicAssets) {
3555
- if (!asset.startsWith("/") || asset.startsWith("//") || asset.includes("..")) {
3645
+ if (!asset.startsWith("/") ||
3646
+ asset.startsWith("//") ||
3647
+ asset.includes("..") ||
3648
+ asset === "/_mreact" ||
3649
+ asset.startsWith("/_mreact/")) {
3556
3650
  continue;
3557
3651
  }
3558
3652
  const relativeAsset = asset.slice(1);
@@ -3658,7 +3752,8 @@ async function collectBuildFiles(projectRoot, allowedSourceDirs, appDir) {
3658
3752
  return files;
3659
3753
  }
3660
3754
  function isProductionBuildIgnoredSourceFile(relativeFile) {
3661
- return /(?:^|[/\\])[^/\\]+\.(?:spec|test)\.[cm]?[jt]sx?$/u.test(relativeFile);
3755
+ return (/(?:^|[/\\])__tests__(?:[/\\]|$)/u.test(relativeFile) ||
3756
+ /(?:^|[/\\])[^/\\]+\.(?:spec|test)\.[cm]?[jt]sx?$/u.test(relativeFile));
3662
3757
  }
3663
3758
  function isAppFileConventionAsset(file, appDir) {
3664
3759
  const relativeFile = relative(appDir, file);