@bleedingdev/modern-js-create 3.5.0-ultramodern.11 → 3.5.0-ultramodern.13

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.
@@ -54,6 +54,7 @@ const external_create_package_root_cjs_namespaceObject = require("../create-pack
54
54
  const external_ultramodern_package_source_cjs_namespaceObject = require("../ultramodern-package-source.cjs");
55
55
  const app_files_cjs_namespaceObject = require("../ultramodern-workspace/app-files.cjs");
56
56
  const mf_validation_cjs_namespaceObject = require("../ultramodern-workspace/mf-validation.cjs");
57
+ const module_federation_cjs_namespaceObject = require("../ultramodern-workspace/module-federation.cjs");
57
58
  const package_json_cjs_namespaceObject = require("../ultramodern-workspace/package-json.cjs");
58
59
  const versions_cjs_namespaceObject = require("../ultramodern-workspace/versions.cjs");
59
60
  const workspace_scripts_cjs_namespaceObject = require("../ultramodern-workspace/workspace-scripts.cjs");
@@ -266,9 +267,14 @@ function updateGeneratedPackageScripts(packageJson) {
266
267
  if (!scripts || 'object' != typeof scripts || Array.isArray(scripts)) return false;
267
268
  let changed = false;
268
269
  const cloudflareBuild = scripts['cloudflare:build'];
269
- if ('string' == typeof cloudflareBuild && cloudflareBuild.includes(cloudflareModernDeployCommand) && !cloudflareBuild.includes(cloudflareModernDeploySkipBuildCommand)) {
270
- scripts['cloudflare:build'] = cloudflareBuild.replace(cloudflareModernDeployCommand, cloudflareModernDeploySkipBuildCommand);
271
- changed = true;
270
+ if ('string' == typeof cloudflareBuild) {
271
+ let nextCloudflareBuild = cloudflareBuild;
272
+ if (nextCloudflareBuild.includes(cloudflareModernDeployCommand) && !nextCloudflareBuild.includes(cloudflareModernDeploySkipBuildCommand)) nextCloudflareBuild = nextCloudflareBuild.replace(cloudflareModernDeployCommand, cloudflareModernDeploySkipBuildCommand);
273
+ nextCloudflareBuild = nextCloudflareBuild.replace(/ && node \S*scripts\/generate-public-surface-assets\.m[ct]s --app [^&]+ --target dist(?= && ULTRAMODERN_ZEPHYR=false MODERNJS_DEPLOY=cloudflare modern deploy --skip-build)/u, '');
274
+ if (nextCloudflareBuild !== cloudflareBuild) {
275
+ scripts['cloudflare:build'] = nextCloudflareBuild;
276
+ changed = true;
277
+ }
272
278
  }
273
279
  const cloudflareDeploy = scripts['cloudflare:deploy'];
274
280
  if ('string' == typeof cloudflareDeploy && cloudflareDeploy.includes(cloudflareWranglerDeployInvalidSkipBuildCommand)) {
@@ -407,6 +413,19 @@ function ensureYamlMapEntry(source, key, entryKey, value) {
407
413
  changed: true
408
414
  };
409
415
  }
416
+ function removeYamlMapEntry(source, entryKey) {
417
+ const packageName = entryKey.includes('@') ? entryKey.slice(0, entryKey.lastIndexOf('@')) : entryKey;
418
+ const escapedPackageName = packageName.replace(/[.*+?^${}()|[\]\\]/gu, '\\$&');
419
+ const currentEntryPattern = new RegExp(`^ {2}'${escapedPackageName}@[^']+': .+\\n?`, 'mu');
420
+ if (!currentEntryPattern.test(source)) return {
421
+ source,
422
+ changed: false
423
+ };
424
+ return {
425
+ source: source.replace(currentEntryPattern, ''),
426
+ changed: true
427
+ };
428
+ }
410
429
  function ensureGeneratedPatchFile(workspaceRoot, relativePatchPath, sourcePatchPath) {
411
430
  const targetPath = external_node_path_default().join(workspaceRoot, relativePatchPath);
412
431
  const patch = external_node_fs_default().readFileSync(sourcePatchPath, 'utf-8');
@@ -417,10 +436,53 @@ function ensureGeneratedPatchFile(workspaceRoot, relativePatchPath, sourcePatchP
417
436
  external_node_fs_default().writeFileSync(targetPath, patch, 'utf-8');
418
437
  return true;
419
438
  }
420
- function ensureGeneratedDeclarationPatches(workspaceRoot) {
439
+ function removeGeneratedPatchFileIfUnchanged(workspaceRoot, relativePatchPath, sourcePatchPath) {
440
+ const targetPath = external_node_path_default().join(workspaceRoot, relativePatchPath);
441
+ if (!external_node_fs_default().existsSync(targetPath)) return false;
442
+ const patch = external_node_fs_default().readFileSync(sourcePatchPath, 'utf-8');
443
+ if (external_node_fs_default().readFileSync(targetPath, 'utf-8') !== patch) return false;
444
+ external_node_fs_default().rmSync(targetPath);
445
+ return true;
446
+ }
447
+ function workspaceUsesDependency(workspaceRoot, packageName) {
448
+ const packageJsonPaths = [
449
+ external_node_path_default().join(workspaceRoot, 'package.json')
450
+ ];
451
+ for (const workspaceDir of [
452
+ 'apps',
453
+ 'verticals',
454
+ 'packages'
455
+ ]){
456
+ const absoluteWorkspaceDir = external_node_path_default().join(workspaceRoot, workspaceDir);
457
+ if (external_node_fs_default().existsSync(absoluteWorkspaceDir)) for (const entry of external_node_fs_default().readdirSync(absoluteWorkspaceDir, {
458
+ withFileTypes: true
459
+ })){
460
+ if (!entry.isDirectory()) continue;
461
+ const packageJsonPath = external_node_path_default().join(absoluteWorkspaceDir, entry.name, 'package.json');
462
+ if (external_node_fs_default().existsSync(packageJsonPath)) packageJsonPaths.push(packageJsonPath);
463
+ }
464
+ }
465
+ for (const packageJsonPath of packageJsonPaths){
466
+ const packageJson = JSON.parse(external_node_fs_default().readFileSync(packageJsonPath, 'utf-8'));
467
+ for (const field of [
468
+ 'dependencies',
469
+ 'devDependencies',
470
+ 'peerDependencies',
471
+ 'optionalDependencies'
472
+ ]){
473
+ const dependencies = packageJson[field];
474
+ if (dependencies && 'object' == typeof dependencies) {
475
+ if (Object.prototype.hasOwnProperty.call(dependencies, packageName)) return true;
476
+ for (const specifier of Object.values(dependencies))if ('string' == typeof specifier && specifier.startsWith(`npm:${packageName}@`)) return true;
477
+ }
478
+ }
479
+ }
480
+ return false;
481
+ }
482
+ function ensureGeneratedDeclarationPatches(workspaceRoot, options) {
421
483
  let changed = false;
422
484
  changed = ensureGeneratedPatchFile(workspaceRoot, effectDeclarationPatchPath, effectDeclarationPatchSourcePath) || changed;
423
- changed = ensureGeneratedPatchFile(workspaceRoot, drizzleOrmDeclarationPatchPath, drizzleOrmDeclarationPatchSourcePath) || changed;
485
+ changed = options.includeDrizzleOrmPatch ? ensureGeneratedPatchFile(workspaceRoot, drizzleOrmDeclarationPatchPath, drizzleOrmDeclarationPatchSourcePath) || changed : removeGeneratedPatchFileIfUnchanged(workspaceRoot, drizzleOrmDeclarationPatchPath, drizzleOrmDeclarationPatchSourcePath) || changed;
424
486
  return changed;
425
487
  }
426
488
  function updateGeneratedPnpmWorkspacePolicy(workspaceRoot) {
@@ -428,6 +490,7 @@ function updateGeneratedPnpmWorkspacePolicy(workspaceRoot) {
428
490
  if (!external_node_fs_default().existsSync(workspaceFile)) return false;
429
491
  let source = external_node_fs_default().readFileSync(workspaceFile, 'utf-8');
430
492
  let changed = false;
493
+ const usesDrizzleOrm = workspaceUsesDependency(workspaceRoot, 'drizzle-orm');
431
494
  const replacements = [
432
495
  [
433
496
  /^ {4}'@effect\/vitest>effect': .+$/mu,
@@ -465,7 +528,7 @@ function updateGeneratedPnpmWorkspacePolicy(workspaceRoot) {
465
528
  const effectPatch = ensureYamlMapEntry(source, 'patchedDependencies', `effect@${versions_cjs_namespaceObject.EFFECT_VERSION}`, effectDeclarationPatchPath);
466
529
  source = effectPatch.source;
467
530
  changed = effectPatch.changed || changed;
468
- const drizzleOrmPatch = ensureYamlMapEntry(source, 'patchedDependencies', `drizzle-orm@${versions_cjs_namespaceObject.DRIZZLE_ORM_VERSION}`, drizzleOrmDeclarationPatchPath);
531
+ const drizzleOrmPatch = usesDrizzleOrm ? ensureYamlMapEntry(source, 'patchedDependencies', `drizzle-orm@${versions_cjs_namespaceObject.DRIZZLE_ORM_VERSION}`, drizzleOrmDeclarationPatchPath) : removeYamlMapEntry(source, `drizzle-orm@${versions_cjs_namespaceObject.DRIZZLE_ORM_VERSION}`);
469
532
  source = drizzleOrmPatch.source;
470
533
  changed = drizzleOrmPatch.changed || changed;
471
534
  if (changed) external_node_fs_default().writeFileSync(workspaceFile, source, 'utf-8');
@@ -514,7 +577,8 @@ function ensureGeneratedIgnoreRules(workspaceRoot) {
514
577
  let changed = false;
515
578
  for (const rule of [
516
579
  '.mf/',
517
- '**/.mf/'
580
+ '**/.mf/',
581
+ 'dist-cloudflare/'
518
582
  ])if (!lines.includes(rule)) {
519
583
  lines.push(rule);
520
584
  changed = true;
@@ -541,6 +605,12 @@ function updateGeneratedTypeScriptSurfaces(workspaceRoot, config) {
541
605
  }
542
606
  return changed;
543
607
  }
608
+ function updateGeneratedModernConfigs(workspaceRoot, config) {
609
+ let changed = false;
610
+ const apps = (0, external_config_cjs_namespaceObject.workspaceAppsFromToolingConfig)(config);
611
+ for (const app of apps)changed = writeTextIfChanged(external_node_path_default().join(workspaceRoot, app.directory, 'modern.config.ts'), (0, module_federation_cjs_namespaceObject.createAppModernConfig)(config.workspace.packageScope, app)) || changed;
612
+ return changed;
613
+ }
544
614
  function updateReferenceTopology(workspaceRoot) {
545
615
  const topologyPath = external_node_path_default().join(workspaceRoot, 'topology/reference-topology.json');
546
616
  if (!external_node_fs_default().existsSync(topologyPath)) return false;
@@ -614,7 +684,9 @@ and pnpm contract:check.
614
684
  const packageSource = createMigrationPackageSource(args, current);
615
685
  updateUltramodernConfig(context.workspaceRoot, packageSource);
616
686
  updateReferenceTopology(context.workspaceRoot);
617
- updateGeneratedTypeScriptSurfaces(context.workspaceRoot, current);
687
+ const migrated = (0, external_config_cjs_namespaceObject.readUltramodernConfig)(context.workspaceRoot);
688
+ updateGeneratedTypeScriptSurfaces(context.workspaceRoot, migrated);
689
+ updateGeneratedModernConfigs(context.workspaceRoot, migrated);
618
690
  for (const relativePackageFile of listWorkspacePackageFiles(context.workspaceRoot)){
619
691
  const packageFile = external_node_path_default().join(context.workspaceRoot, relativePackageFile);
620
692
  const packageJson = readJsonFile(packageFile);
@@ -633,7 +705,9 @@ and pnpm contract:check.
633
705
  else if ('package.json' === relativePackageFile) writeJsonFile(packageFile, packageJson);
634
706
  }
635
707
  updateGeneratedPnpmWorkspacePolicy(context.workspaceRoot);
636
- ensureGeneratedDeclarationPatches(context.workspaceRoot);
708
+ ensureGeneratedDeclarationPatches(context.workspaceRoot, {
709
+ includeDrizzleOrmPatch: workspaceUsesDependency(context.workspaceRoot, 'drizzle-orm')
710
+ });
637
711
  if (!hasFlag(args, '--skip-install')) {
638
712
  const status = runPnpmLockfileRefresh(context);
639
713
  if (0 !== status) return status;
@@ -144,8 +144,10 @@ ${defaultAssetPrefixSource}
144
144
  // load remoteEntry.js and exposed chunks from the remote origin, not the host.
145
145
  const assetPrefix =
146
146
  configuredModernAssetPrefix || configuredUltramodernAssetPrefix || defaultAssetPrefix;
147
- const buildCacheTarget = cloudflareDeployEnabled ? 'cloudflare' : 'web';
148
- const buildCacheDirectory = \`node_modules/.cache/rspack-\${appId}-\${buildCacheTarget}\`;
147
+ const buildTarget = cloudflareDeployEnabled ? 'cloudflare' : 'web';
148
+ const buildOutputRoot = cloudflareDeployEnabled ? 'dist-cloudflare' : 'dist';
149
+ const buildTempDirectory = \`node_modules/.modern-js-\${appId}-\${buildTarget}\`;
150
+ const buildCacheDirectory = \`node_modules/.cache/rspack-\${appId}-\${buildTarget}\`;
149
151
 
150
152
  if (
151
153
  cloudflareDeployEnabled &&
@@ -187,13 +189,15 @@ ${bffConfig} ...(cloudflareDeployEnabled
187
189
  disableTsChecker: false,
188
190
  distPath: {
189
191
  html: './',
192
+ root: buildOutputRoot,
190
193
  },
191
194
  polyfill: 'off',
192
195
  splitRouteChunks: true,
196
+ tempDir: buildTempDirectory,
193
197
  },
194
198
  performance: {
195
199
  buildCache: {
196
- cacheDigest: [appId, buildCacheTarget],
200
+ cacheDigest: [appId, buildTarget],
197
201
  cacheDirectory: buildCacheDirectory,
198
202
  },
199
203
  rsdoctor: {
@@ -412,7 +412,6 @@ function createRootTsConfig(apps = []) {
412
412
  }
413
413
  function createAppPackage(scope, app, packageSource, enableTailwind, remotes = [], bridge) {
414
414
  const publicSurfaceBuildCommand = (0, external_public_surface_cjs_namespaceObject.createPublicSurfaceGenerationCommand)(app, 'dist');
415
- const publicSurfaceCloudflareBuildCommand = (0, external_public_surface_cjs_namespaceObject.createPublicSurfaceGenerationCommand)(app, 'dist');
416
415
  const publicSurfaceCloudflareOutputCommand = (0, external_public_surface_cjs_namespaceObject.createPublicSurfaceGenerationCommand)(app, 'cloudflare');
417
416
  const packageExports = Object.fromEntries(Object.entries(app.exposes ?? {}).map(([expose, source])=>[
418
417
  expose,
@@ -425,7 +424,7 @@ function createAppPackage(scope, app, packageSource, enableTailwind, remotes = [
425
424
  scripts: {
426
425
  dev: 'modern dev',
427
426
  build: app.exposes ? `ULTRAMODERN_ZEPHYR=false modern build && ${publicSurfaceBuildCommand} && node ${(0, external_naming_cjs_namespaceObject.relativeRootFor)(app.directory)}/scripts/assert-mf-types.mts` : `ULTRAMODERN_ZEPHYR=false modern build && ${publicSurfaceBuildCommand}`,
428
- 'cloudflare:build': `ULTRAMODERN_ZEPHYR=false MODERNJS_DEPLOY=cloudflare modern build && ${publicSurfaceCloudflareBuildCommand} && ULTRAMODERN_ZEPHYR=false MODERNJS_DEPLOY=cloudflare modern deploy --skip-build && ${publicSurfaceCloudflareOutputCommand}`,
427
+ 'cloudflare:build': `ULTRAMODERN_ZEPHYR=false MODERNJS_DEPLOY=cloudflare modern build && ULTRAMODERN_ZEPHYR=false MODERNJS_DEPLOY=cloudflare modern deploy --skip-build && ${publicSurfaceCloudflareOutputCommand}`,
429
428
  'cloudflare:deploy': 'ULTRAMODERN_CLOUDFLARE_REQUIRE_PUBLIC_URLS=true pnpm run cloudflare:build && wrangler deploy --config .output/wrangler.json',
430
429
  'cloudflare:preview': 'pnpm run cloudflare:build && wrangler dev --config .output/wrangler.json',
431
430
  'cloudflare:proof': `node ${(0, external_naming_cjs_namespaceObject.relativeRootFor)(app.directory)}/scripts/proof-cloudflare-version.mts --app ${app.id}`,
@@ -7,6 +7,7 @@ import { resolveCreatePackageRoot } from "../create-package-root.js";
7
7
  import { BLEEDINGDEV_PACKAGE_NAME_PREFIX, BLEEDINGDEV_PACKAGE_SCOPE, ULTRAMODERN_SINGLE_APP_MODERN_PACKAGES, ULTRAMODERN_WORKSPACE_MODERN_PACKAGES, WORKSPACE_PACKAGE_VERSION, modernPackageSpecifier } from "../ultramodern-package-source.js";
8
8
  import { createAppEnvDts } from "../ultramodern-workspace/app-files.js";
9
9
  import { validateModuleFederationTypes } from "../ultramodern-workspace/mf-validation.js";
10
+ import { createAppModernConfig } from "../ultramodern-workspace/module-federation.js";
10
11
  import { createAppMfTypesTsConfig, createAppTsConfig, createSharedPackageTsConfig, createTsConfigBase } from "../ultramodern-workspace/package-json.js";
11
12
  import { DRIZZLE_ORM_VERSION, EFFECT_TSGO_VERSION, EFFECT_VERSION, EFFECT_VITEST_VERSION, OXFMT_VERSION, OXLINT_VERSION, TYPESCRIPT_NATIVE_PREVIEW_VERSION, WRANGLER_VERSION, ZEPHYR_AGENT_VERSION, ZEPHYR_RSPACK_PLUGIN_VERSION } from "../ultramodern-workspace/versions.js";
12
13
  import { createWorkspaceValidationScript } from "../ultramodern-workspace/workspace-scripts.js";
@@ -219,9 +220,14 @@ function updateGeneratedPackageScripts(packageJson) {
219
220
  if (!scripts || 'object' != typeof scripts || Array.isArray(scripts)) return false;
220
221
  let changed = false;
221
222
  const cloudflareBuild = scripts['cloudflare:build'];
222
- if ('string' == typeof cloudflareBuild && cloudflareBuild.includes(cloudflareModernDeployCommand) && !cloudflareBuild.includes(cloudflareModernDeploySkipBuildCommand)) {
223
- scripts['cloudflare:build'] = cloudflareBuild.replace(cloudflareModernDeployCommand, cloudflareModernDeploySkipBuildCommand);
224
- changed = true;
223
+ if ('string' == typeof cloudflareBuild) {
224
+ let nextCloudflareBuild = cloudflareBuild;
225
+ if (nextCloudflareBuild.includes(cloudflareModernDeployCommand) && !nextCloudflareBuild.includes(cloudflareModernDeploySkipBuildCommand)) nextCloudflareBuild = nextCloudflareBuild.replace(cloudflareModernDeployCommand, cloudflareModernDeploySkipBuildCommand);
226
+ nextCloudflareBuild = nextCloudflareBuild.replace(/ && node \S*scripts\/generate-public-surface-assets\.m[ct]s --app [^&]+ --target dist(?= && ULTRAMODERN_ZEPHYR=false MODERNJS_DEPLOY=cloudflare modern deploy --skip-build)/u, '');
227
+ if (nextCloudflareBuild !== cloudflareBuild) {
228
+ scripts['cloudflare:build'] = nextCloudflareBuild;
229
+ changed = true;
230
+ }
225
231
  }
226
232
  const cloudflareDeploy = scripts['cloudflare:deploy'];
227
233
  if ('string' == typeof cloudflareDeploy && cloudflareDeploy.includes(cloudflareWranglerDeployInvalidSkipBuildCommand)) {
@@ -360,6 +366,19 @@ function ensureYamlMapEntry(source, key, entryKey, value) {
360
366
  changed: true
361
367
  };
362
368
  }
369
+ function removeYamlMapEntry(source, entryKey) {
370
+ const packageName = entryKey.includes('@') ? entryKey.slice(0, entryKey.lastIndexOf('@')) : entryKey;
371
+ const escapedPackageName = packageName.replace(/[.*+?^${}()|[\]\\]/gu, '\\$&');
372
+ const currentEntryPattern = new RegExp(`^ {2}'${escapedPackageName}@[^']+': .+\\n?`, 'mu');
373
+ if (!currentEntryPattern.test(source)) return {
374
+ source,
375
+ changed: false
376
+ };
377
+ return {
378
+ source: source.replace(currentEntryPattern, ''),
379
+ changed: true
380
+ };
381
+ }
363
382
  function ensureGeneratedPatchFile(workspaceRoot, relativePatchPath, sourcePatchPath) {
364
383
  const targetPath = node_path.join(workspaceRoot, relativePatchPath);
365
384
  const patch = node_fs.readFileSync(sourcePatchPath, 'utf-8');
@@ -370,10 +389,53 @@ function ensureGeneratedPatchFile(workspaceRoot, relativePatchPath, sourcePatchP
370
389
  node_fs.writeFileSync(targetPath, patch, 'utf-8');
371
390
  return true;
372
391
  }
373
- function ensureGeneratedDeclarationPatches(workspaceRoot) {
392
+ function removeGeneratedPatchFileIfUnchanged(workspaceRoot, relativePatchPath, sourcePatchPath) {
393
+ const targetPath = node_path.join(workspaceRoot, relativePatchPath);
394
+ if (!node_fs.existsSync(targetPath)) return false;
395
+ const patch = node_fs.readFileSync(sourcePatchPath, 'utf-8');
396
+ if (node_fs.readFileSync(targetPath, 'utf-8') !== patch) return false;
397
+ node_fs.rmSync(targetPath);
398
+ return true;
399
+ }
400
+ function workspaceUsesDependency(workspaceRoot, packageName) {
401
+ const packageJsonPaths = [
402
+ node_path.join(workspaceRoot, 'package.json')
403
+ ];
404
+ for (const workspaceDir of [
405
+ 'apps',
406
+ 'verticals',
407
+ 'packages'
408
+ ]){
409
+ const absoluteWorkspaceDir = node_path.join(workspaceRoot, workspaceDir);
410
+ if (node_fs.existsSync(absoluteWorkspaceDir)) for (const entry of node_fs.readdirSync(absoluteWorkspaceDir, {
411
+ withFileTypes: true
412
+ })){
413
+ if (!entry.isDirectory()) continue;
414
+ const packageJsonPath = node_path.join(absoluteWorkspaceDir, entry.name, 'package.json');
415
+ if (node_fs.existsSync(packageJsonPath)) packageJsonPaths.push(packageJsonPath);
416
+ }
417
+ }
418
+ for (const packageJsonPath of packageJsonPaths){
419
+ const packageJson = JSON.parse(node_fs.readFileSync(packageJsonPath, 'utf-8'));
420
+ for (const field of [
421
+ 'dependencies',
422
+ 'devDependencies',
423
+ 'peerDependencies',
424
+ 'optionalDependencies'
425
+ ]){
426
+ const dependencies = packageJson[field];
427
+ if (dependencies && 'object' == typeof dependencies) {
428
+ if (Object.prototype.hasOwnProperty.call(dependencies, packageName)) return true;
429
+ for (const specifier of Object.values(dependencies))if ('string' == typeof specifier && specifier.startsWith(`npm:${packageName}@`)) return true;
430
+ }
431
+ }
432
+ }
433
+ return false;
434
+ }
435
+ function ensureGeneratedDeclarationPatches(workspaceRoot, options) {
374
436
  let changed = false;
375
437
  changed = ensureGeneratedPatchFile(workspaceRoot, effectDeclarationPatchPath, effectDeclarationPatchSourcePath) || changed;
376
- changed = ensureGeneratedPatchFile(workspaceRoot, drizzleOrmDeclarationPatchPath, drizzleOrmDeclarationPatchSourcePath) || changed;
438
+ changed = options.includeDrizzleOrmPatch ? ensureGeneratedPatchFile(workspaceRoot, drizzleOrmDeclarationPatchPath, drizzleOrmDeclarationPatchSourcePath) || changed : removeGeneratedPatchFileIfUnchanged(workspaceRoot, drizzleOrmDeclarationPatchPath, drizzleOrmDeclarationPatchSourcePath) || changed;
377
439
  return changed;
378
440
  }
379
441
  function updateGeneratedPnpmWorkspacePolicy(workspaceRoot) {
@@ -381,6 +443,7 @@ function updateGeneratedPnpmWorkspacePolicy(workspaceRoot) {
381
443
  if (!node_fs.existsSync(workspaceFile)) return false;
382
444
  let source = node_fs.readFileSync(workspaceFile, 'utf-8');
383
445
  let changed = false;
446
+ const usesDrizzleOrm = workspaceUsesDependency(workspaceRoot, 'drizzle-orm');
384
447
  const replacements = [
385
448
  [
386
449
  /^ {4}'@effect\/vitest>effect': .+$/mu,
@@ -418,7 +481,7 @@ function updateGeneratedPnpmWorkspacePolicy(workspaceRoot) {
418
481
  const effectPatch = ensureYamlMapEntry(source, 'patchedDependencies', `effect@${EFFECT_VERSION}`, effectDeclarationPatchPath);
419
482
  source = effectPatch.source;
420
483
  changed = effectPatch.changed || changed;
421
- const drizzleOrmPatch = ensureYamlMapEntry(source, 'patchedDependencies', `drizzle-orm@${DRIZZLE_ORM_VERSION}`, drizzleOrmDeclarationPatchPath);
484
+ const drizzleOrmPatch = usesDrizzleOrm ? ensureYamlMapEntry(source, 'patchedDependencies', `drizzle-orm@${DRIZZLE_ORM_VERSION}`, drizzleOrmDeclarationPatchPath) : removeYamlMapEntry(source, `drizzle-orm@${DRIZZLE_ORM_VERSION}`);
422
485
  source = drizzleOrmPatch.source;
423
486
  changed = drizzleOrmPatch.changed || changed;
424
487
  if (changed) node_fs.writeFileSync(workspaceFile, source, 'utf-8');
@@ -467,7 +530,8 @@ function ensureGeneratedIgnoreRules(workspaceRoot) {
467
530
  let changed = false;
468
531
  for (const rule of [
469
532
  '.mf/',
470
- '**/.mf/'
533
+ '**/.mf/',
534
+ 'dist-cloudflare/'
471
535
  ])if (!lines.includes(rule)) {
472
536
  lines.push(rule);
473
537
  changed = true;
@@ -494,6 +558,12 @@ function updateGeneratedTypeScriptSurfaces(workspaceRoot, config) {
494
558
  }
495
559
  return changed;
496
560
  }
561
+ function updateGeneratedModernConfigs(workspaceRoot, config) {
562
+ let changed = false;
563
+ const apps = workspaceAppsFromToolingConfig(config);
564
+ for (const app of apps)changed = writeTextIfChanged(node_path.join(workspaceRoot, app.directory, 'modern.config.ts'), createAppModernConfig(config.workspace.packageScope, app)) || changed;
565
+ return changed;
566
+ }
497
567
  function updateReferenceTopology(workspaceRoot) {
498
568
  const topologyPath = node_path.join(workspaceRoot, 'topology/reference-topology.json');
499
569
  if (!node_fs.existsSync(topologyPath)) return false;
@@ -567,7 +637,9 @@ and pnpm contract:check.
567
637
  const packageSource = createMigrationPackageSource(args, current);
568
638
  updateUltramodernConfig(context.workspaceRoot, packageSource);
569
639
  updateReferenceTopology(context.workspaceRoot);
570
- updateGeneratedTypeScriptSurfaces(context.workspaceRoot, current);
640
+ const migrated = readUltramodernConfig(context.workspaceRoot);
641
+ updateGeneratedTypeScriptSurfaces(context.workspaceRoot, migrated);
642
+ updateGeneratedModernConfigs(context.workspaceRoot, migrated);
571
643
  for (const relativePackageFile of listWorkspacePackageFiles(context.workspaceRoot)){
572
644
  const packageFile = node_path.join(context.workspaceRoot, relativePackageFile);
573
645
  const packageJson = readJsonFile(packageFile);
@@ -586,7 +658,9 @@ and pnpm contract:check.
586
658
  else if ('package.json' === relativePackageFile) writeJsonFile(packageFile, packageJson);
587
659
  }
588
660
  updateGeneratedPnpmWorkspacePolicy(context.workspaceRoot);
589
- ensureGeneratedDeclarationPatches(context.workspaceRoot);
661
+ ensureGeneratedDeclarationPatches(context.workspaceRoot, {
662
+ includeDrizzleOrmPatch: workspaceUsesDependency(context.workspaceRoot, 'drizzle-orm')
663
+ });
590
664
  if (!hasFlag(args, '--skip-install')) {
591
665
  const status = runPnpmLockfileRefresh(context);
592
666
  if (0 !== status) return status;
@@ -93,8 +93,10 @@ ${defaultAssetPrefixSource}
93
93
  // load remoteEntry.js and exposed chunks from the remote origin, not the host.
94
94
  const assetPrefix =
95
95
  configuredModernAssetPrefix || configuredUltramodernAssetPrefix || defaultAssetPrefix;
96
- const buildCacheTarget = cloudflareDeployEnabled ? 'cloudflare' : 'web';
97
- const buildCacheDirectory = \`node_modules/.cache/rspack-\${appId}-\${buildCacheTarget}\`;
96
+ const buildTarget = cloudflareDeployEnabled ? 'cloudflare' : 'web';
97
+ const buildOutputRoot = cloudflareDeployEnabled ? 'dist-cloudflare' : 'dist';
98
+ const buildTempDirectory = \`node_modules/.modern-js-\${appId}-\${buildTarget}\`;
99
+ const buildCacheDirectory = \`node_modules/.cache/rspack-\${appId}-\${buildTarget}\`;
98
100
 
99
101
  if (
100
102
  cloudflareDeployEnabled &&
@@ -136,13 +138,15 @@ ${bffConfig} ...(cloudflareDeployEnabled
136
138
  disableTsChecker: false,
137
139
  distPath: {
138
140
  html: './',
141
+ root: buildOutputRoot,
139
142
  },
140
143
  polyfill: 'off',
141
144
  splitRouteChunks: true,
145
+ tempDir: buildTempDirectory,
142
146
  },
143
147
  performance: {
144
148
  buildCache: {
145
- cacheDigest: [appId, buildCacheTarget],
149
+ cacheDigest: [appId, buildTarget],
146
150
  cacheDirectory: buildCacheDirectory,
147
151
  },
148
152
  rsdoctor: {
@@ -356,7 +356,6 @@ function createRootTsConfig(apps = []) {
356
356
  }
357
357
  function createAppPackage(scope, app, packageSource, enableTailwind, remotes = [], bridge) {
358
358
  const publicSurfaceBuildCommand = createPublicSurfaceGenerationCommand(app, 'dist');
359
- const publicSurfaceCloudflareBuildCommand = createPublicSurfaceGenerationCommand(app, 'dist');
360
359
  const publicSurfaceCloudflareOutputCommand = createPublicSurfaceGenerationCommand(app, 'cloudflare');
361
360
  const packageExports = Object.fromEntries(Object.entries(app.exposes ?? {}).map(([expose, source])=>[
362
361
  expose,
@@ -369,7 +368,7 @@ function createAppPackage(scope, app, packageSource, enableTailwind, remotes = [
369
368
  scripts: {
370
369
  dev: 'modern dev',
371
370
  build: app.exposes ? `ULTRAMODERN_ZEPHYR=false modern build && ${publicSurfaceBuildCommand} && node ${relativeRootFor(app.directory)}/scripts/assert-mf-types.mts` : `ULTRAMODERN_ZEPHYR=false modern build && ${publicSurfaceBuildCommand}`,
372
- 'cloudflare:build': `ULTRAMODERN_ZEPHYR=false MODERNJS_DEPLOY=cloudflare modern build && ${publicSurfaceCloudflareBuildCommand} && ULTRAMODERN_ZEPHYR=false MODERNJS_DEPLOY=cloudflare modern deploy --skip-build && ${publicSurfaceCloudflareOutputCommand}`,
371
+ 'cloudflare:build': `ULTRAMODERN_ZEPHYR=false MODERNJS_DEPLOY=cloudflare modern build && ULTRAMODERN_ZEPHYR=false MODERNJS_DEPLOY=cloudflare modern deploy --skip-build && ${publicSurfaceCloudflareOutputCommand}`,
373
372
  'cloudflare:deploy': 'ULTRAMODERN_CLOUDFLARE_REQUIRE_PUBLIC_URLS=true pnpm run cloudflare:build && wrangler deploy --config .output/wrangler.json',
374
373
  'cloudflare:preview': 'pnpm run cloudflare:build && wrangler dev --config .output/wrangler.json',
375
374
  'cloudflare:proof': `node ${relativeRootFor(app.directory)}/scripts/proof-cloudflare-version.mts --app ${app.id}`,
@@ -8,6 +8,7 @@ import { resolveCreatePackageRoot } from "../create-package-root.js";
8
8
  import { BLEEDINGDEV_PACKAGE_NAME_PREFIX, BLEEDINGDEV_PACKAGE_SCOPE, ULTRAMODERN_SINGLE_APP_MODERN_PACKAGES, ULTRAMODERN_WORKSPACE_MODERN_PACKAGES, WORKSPACE_PACKAGE_VERSION, modernPackageSpecifier } from "../ultramodern-package-source.js";
9
9
  import { createAppEnvDts } from "../ultramodern-workspace/app-files.js";
10
10
  import { validateModuleFederationTypes } from "../ultramodern-workspace/mf-validation.js";
11
+ import { createAppModernConfig } from "../ultramodern-workspace/module-federation.js";
11
12
  import { createAppMfTypesTsConfig, createAppTsConfig, createSharedPackageTsConfig, createTsConfigBase } from "../ultramodern-workspace/package-json.js";
12
13
  import { DRIZZLE_ORM_VERSION, EFFECT_TSGO_VERSION, EFFECT_VERSION, EFFECT_VITEST_VERSION, OXFMT_VERSION, OXLINT_VERSION, TYPESCRIPT_NATIVE_PREVIEW_VERSION, WRANGLER_VERSION, ZEPHYR_AGENT_VERSION, ZEPHYR_RSPACK_PLUGIN_VERSION } from "../ultramodern-workspace/versions.js";
13
14
  import { createWorkspaceValidationScript } from "../ultramodern-workspace/workspace-scripts.js";
@@ -220,9 +221,14 @@ function updateGeneratedPackageScripts(packageJson) {
220
221
  if (!scripts || 'object' != typeof scripts || Array.isArray(scripts)) return false;
221
222
  let changed = false;
222
223
  const cloudflareBuild = scripts['cloudflare:build'];
223
- if ('string' == typeof cloudflareBuild && cloudflareBuild.includes(cloudflareModernDeployCommand) && !cloudflareBuild.includes(cloudflareModernDeploySkipBuildCommand)) {
224
- scripts['cloudflare:build'] = cloudflareBuild.replace(cloudflareModernDeployCommand, cloudflareModernDeploySkipBuildCommand);
225
- changed = true;
224
+ if ('string' == typeof cloudflareBuild) {
225
+ let nextCloudflareBuild = cloudflareBuild;
226
+ if (nextCloudflareBuild.includes(cloudflareModernDeployCommand) && !nextCloudflareBuild.includes(cloudflareModernDeploySkipBuildCommand)) nextCloudflareBuild = nextCloudflareBuild.replace(cloudflareModernDeployCommand, cloudflareModernDeploySkipBuildCommand);
227
+ nextCloudflareBuild = nextCloudflareBuild.replace(/ && node \S*scripts\/generate-public-surface-assets\.m[ct]s --app [^&]+ --target dist(?= && ULTRAMODERN_ZEPHYR=false MODERNJS_DEPLOY=cloudflare modern deploy --skip-build)/u, '');
228
+ if (nextCloudflareBuild !== cloudflareBuild) {
229
+ scripts['cloudflare:build'] = nextCloudflareBuild;
230
+ changed = true;
231
+ }
226
232
  }
227
233
  const cloudflareDeploy = scripts['cloudflare:deploy'];
228
234
  if ('string' == typeof cloudflareDeploy && cloudflareDeploy.includes(cloudflareWranglerDeployInvalidSkipBuildCommand)) {
@@ -361,6 +367,19 @@ function ensureYamlMapEntry(source, key, entryKey, value) {
361
367
  changed: true
362
368
  };
363
369
  }
370
+ function removeYamlMapEntry(source, entryKey) {
371
+ const packageName = entryKey.includes('@') ? entryKey.slice(0, entryKey.lastIndexOf('@')) : entryKey;
372
+ const escapedPackageName = packageName.replace(/[.*+?^${}()|[\]\\]/gu, '\\$&');
373
+ const currentEntryPattern = new RegExp(`^ {2}'${escapedPackageName}@[^']+': .+\\n?`, 'mu');
374
+ if (!currentEntryPattern.test(source)) return {
375
+ source,
376
+ changed: false
377
+ };
378
+ return {
379
+ source: source.replace(currentEntryPattern, ''),
380
+ changed: true
381
+ };
382
+ }
364
383
  function ensureGeneratedPatchFile(workspaceRoot, relativePatchPath, sourcePatchPath) {
365
384
  const targetPath = node_path.join(workspaceRoot, relativePatchPath);
366
385
  const patch = node_fs.readFileSync(sourcePatchPath, 'utf-8');
@@ -371,10 +390,53 @@ function ensureGeneratedPatchFile(workspaceRoot, relativePatchPath, sourcePatchP
371
390
  node_fs.writeFileSync(targetPath, patch, 'utf-8');
372
391
  return true;
373
392
  }
374
- function ensureGeneratedDeclarationPatches(workspaceRoot) {
393
+ function removeGeneratedPatchFileIfUnchanged(workspaceRoot, relativePatchPath, sourcePatchPath) {
394
+ const targetPath = node_path.join(workspaceRoot, relativePatchPath);
395
+ if (!node_fs.existsSync(targetPath)) return false;
396
+ const patch = node_fs.readFileSync(sourcePatchPath, 'utf-8');
397
+ if (node_fs.readFileSync(targetPath, 'utf-8') !== patch) return false;
398
+ node_fs.rmSync(targetPath);
399
+ return true;
400
+ }
401
+ function workspaceUsesDependency(workspaceRoot, packageName) {
402
+ const packageJsonPaths = [
403
+ node_path.join(workspaceRoot, 'package.json')
404
+ ];
405
+ for (const workspaceDir of [
406
+ 'apps',
407
+ 'verticals',
408
+ 'packages'
409
+ ]){
410
+ const absoluteWorkspaceDir = node_path.join(workspaceRoot, workspaceDir);
411
+ if (node_fs.existsSync(absoluteWorkspaceDir)) for (const entry of node_fs.readdirSync(absoluteWorkspaceDir, {
412
+ withFileTypes: true
413
+ })){
414
+ if (!entry.isDirectory()) continue;
415
+ const packageJsonPath = node_path.join(absoluteWorkspaceDir, entry.name, 'package.json');
416
+ if (node_fs.existsSync(packageJsonPath)) packageJsonPaths.push(packageJsonPath);
417
+ }
418
+ }
419
+ for (const packageJsonPath of packageJsonPaths){
420
+ const packageJson = JSON.parse(node_fs.readFileSync(packageJsonPath, 'utf-8'));
421
+ for (const field of [
422
+ 'dependencies',
423
+ 'devDependencies',
424
+ 'peerDependencies',
425
+ 'optionalDependencies'
426
+ ]){
427
+ const dependencies = packageJson[field];
428
+ if (dependencies && 'object' == typeof dependencies) {
429
+ if (Object.prototype.hasOwnProperty.call(dependencies, packageName)) return true;
430
+ for (const specifier of Object.values(dependencies))if ('string' == typeof specifier && specifier.startsWith(`npm:${packageName}@`)) return true;
431
+ }
432
+ }
433
+ }
434
+ return false;
435
+ }
436
+ function ensureGeneratedDeclarationPatches(workspaceRoot, options) {
375
437
  let changed = false;
376
438
  changed = ensureGeneratedPatchFile(workspaceRoot, effectDeclarationPatchPath, effectDeclarationPatchSourcePath) || changed;
377
- changed = ensureGeneratedPatchFile(workspaceRoot, drizzleOrmDeclarationPatchPath, drizzleOrmDeclarationPatchSourcePath) || changed;
439
+ changed = options.includeDrizzleOrmPatch ? ensureGeneratedPatchFile(workspaceRoot, drizzleOrmDeclarationPatchPath, drizzleOrmDeclarationPatchSourcePath) || changed : removeGeneratedPatchFileIfUnchanged(workspaceRoot, drizzleOrmDeclarationPatchPath, drizzleOrmDeclarationPatchSourcePath) || changed;
378
440
  return changed;
379
441
  }
380
442
  function updateGeneratedPnpmWorkspacePolicy(workspaceRoot) {
@@ -382,6 +444,7 @@ function updateGeneratedPnpmWorkspacePolicy(workspaceRoot) {
382
444
  if (!node_fs.existsSync(workspaceFile)) return false;
383
445
  let source = node_fs.readFileSync(workspaceFile, 'utf-8');
384
446
  let changed = false;
447
+ const usesDrizzleOrm = workspaceUsesDependency(workspaceRoot, 'drizzle-orm');
385
448
  const replacements = [
386
449
  [
387
450
  /^ {4}'@effect\/vitest>effect': .+$/mu,
@@ -419,7 +482,7 @@ function updateGeneratedPnpmWorkspacePolicy(workspaceRoot) {
419
482
  const effectPatch = ensureYamlMapEntry(source, 'patchedDependencies', `effect@${EFFECT_VERSION}`, effectDeclarationPatchPath);
420
483
  source = effectPatch.source;
421
484
  changed = effectPatch.changed || changed;
422
- const drizzleOrmPatch = ensureYamlMapEntry(source, 'patchedDependencies', `drizzle-orm@${DRIZZLE_ORM_VERSION}`, drizzleOrmDeclarationPatchPath);
485
+ const drizzleOrmPatch = usesDrizzleOrm ? ensureYamlMapEntry(source, 'patchedDependencies', `drizzle-orm@${DRIZZLE_ORM_VERSION}`, drizzleOrmDeclarationPatchPath) : removeYamlMapEntry(source, `drizzle-orm@${DRIZZLE_ORM_VERSION}`);
423
486
  source = drizzleOrmPatch.source;
424
487
  changed = drizzleOrmPatch.changed || changed;
425
488
  if (changed) node_fs.writeFileSync(workspaceFile, source, 'utf-8');
@@ -468,7 +531,8 @@ function ensureGeneratedIgnoreRules(workspaceRoot) {
468
531
  let changed = false;
469
532
  for (const rule of [
470
533
  '.mf/',
471
- '**/.mf/'
534
+ '**/.mf/',
535
+ 'dist-cloudflare/'
472
536
  ])if (!lines.includes(rule)) {
473
537
  lines.push(rule);
474
538
  changed = true;
@@ -495,6 +559,12 @@ function updateGeneratedTypeScriptSurfaces(workspaceRoot, config) {
495
559
  }
496
560
  return changed;
497
561
  }
562
+ function updateGeneratedModernConfigs(workspaceRoot, config) {
563
+ let changed = false;
564
+ const apps = workspaceAppsFromToolingConfig(config);
565
+ for (const app of apps)changed = writeTextIfChanged(node_path.join(workspaceRoot, app.directory, 'modern.config.ts'), createAppModernConfig(config.workspace.packageScope, app)) || changed;
566
+ return changed;
567
+ }
498
568
  function updateReferenceTopology(workspaceRoot) {
499
569
  const topologyPath = node_path.join(workspaceRoot, 'topology/reference-topology.json');
500
570
  if (!node_fs.existsSync(topologyPath)) return false;
@@ -568,7 +638,9 @@ and pnpm contract:check.
568
638
  const packageSource = createMigrationPackageSource(args, current);
569
639
  updateUltramodernConfig(context.workspaceRoot, packageSource);
570
640
  updateReferenceTopology(context.workspaceRoot);
571
- updateGeneratedTypeScriptSurfaces(context.workspaceRoot, current);
641
+ const migrated = readUltramodernConfig(context.workspaceRoot);
642
+ updateGeneratedTypeScriptSurfaces(context.workspaceRoot, migrated);
643
+ updateGeneratedModernConfigs(context.workspaceRoot, migrated);
572
644
  for (const relativePackageFile of listWorkspacePackageFiles(context.workspaceRoot)){
573
645
  const packageFile = node_path.join(context.workspaceRoot, relativePackageFile);
574
646
  const packageJson = readJsonFile(packageFile);
@@ -587,7 +659,9 @@ and pnpm contract:check.
587
659
  else if ('package.json' === relativePackageFile) writeJsonFile(packageFile, packageJson);
588
660
  }
589
661
  updateGeneratedPnpmWorkspacePolicy(context.workspaceRoot);
590
- ensureGeneratedDeclarationPatches(context.workspaceRoot);
662
+ ensureGeneratedDeclarationPatches(context.workspaceRoot, {
663
+ includeDrizzleOrmPatch: workspaceUsesDependency(context.workspaceRoot, 'drizzle-orm')
664
+ });
591
665
  if (!hasFlag(args, '--skip-install')) {
592
666
  const status = runPnpmLockfileRefresh(context);
593
667
  if (0 !== status) return status;
@@ -94,8 +94,10 @@ ${defaultAssetPrefixSource}
94
94
  // load remoteEntry.js and exposed chunks from the remote origin, not the host.
95
95
  const assetPrefix =
96
96
  configuredModernAssetPrefix || configuredUltramodernAssetPrefix || defaultAssetPrefix;
97
- const buildCacheTarget = cloudflareDeployEnabled ? 'cloudflare' : 'web';
98
- const buildCacheDirectory = \`node_modules/.cache/rspack-\${appId}-\${buildCacheTarget}\`;
97
+ const buildTarget = cloudflareDeployEnabled ? 'cloudflare' : 'web';
98
+ const buildOutputRoot = cloudflareDeployEnabled ? 'dist-cloudflare' : 'dist';
99
+ const buildTempDirectory = \`node_modules/.modern-js-\${appId}-\${buildTarget}\`;
100
+ const buildCacheDirectory = \`node_modules/.cache/rspack-\${appId}-\${buildTarget}\`;
99
101
 
100
102
  if (
101
103
  cloudflareDeployEnabled &&
@@ -137,13 +139,15 @@ ${bffConfig} ...(cloudflareDeployEnabled
137
139
  disableTsChecker: false,
138
140
  distPath: {
139
141
  html: './',
142
+ root: buildOutputRoot,
140
143
  },
141
144
  polyfill: 'off',
142
145
  splitRouteChunks: true,
146
+ tempDir: buildTempDirectory,
143
147
  },
144
148
  performance: {
145
149
  buildCache: {
146
- cacheDigest: [appId, buildCacheTarget],
150
+ cacheDigest: [appId, buildTarget],
147
151
  cacheDirectory: buildCacheDirectory,
148
152
  },
149
153
  rsdoctor: {
@@ -357,7 +357,6 @@ function createRootTsConfig(apps = []) {
357
357
  }
358
358
  function createAppPackage(scope, app, packageSource, enableTailwind, remotes = [], bridge) {
359
359
  const publicSurfaceBuildCommand = createPublicSurfaceGenerationCommand(app, 'dist');
360
- const publicSurfaceCloudflareBuildCommand = createPublicSurfaceGenerationCommand(app, 'dist');
361
360
  const publicSurfaceCloudflareOutputCommand = createPublicSurfaceGenerationCommand(app, 'cloudflare');
362
361
  const packageExports = Object.fromEntries(Object.entries(app.exposes ?? {}).map(([expose, source])=>[
363
362
  expose,
@@ -370,7 +369,7 @@ function createAppPackage(scope, app, packageSource, enableTailwind, remotes = [
370
369
  scripts: {
371
370
  dev: 'modern dev',
372
371
  build: app.exposes ? `ULTRAMODERN_ZEPHYR=false modern build && ${publicSurfaceBuildCommand} && node ${relativeRootFor(app.directory)}/scripts/assert-mf-types.mts` : `ULTRAMODERN_ZEPHYR=false modern build && ${publicSurfaceBuildCommand}`,
373
- 'cloudflare:build': `ULTRAMODERN_ZEPHYR=false MODERNJS_DEPLOY=cloudflare modern build && ${publicSurfaceCloudflareBuildCommand} && ULTRAMODERN_ZEPHYR=false MODERNJS_DEPLOY=cloudflare modern deploy --skip-build && ${publicSurfaceCloudflareOutputCommand}`,
372
+ 'cloudflare:build': `ULTRAMODERN_ZEPHYR=false MODERNJS_DEPLOY=cloudflare modern build && ULTRAMODERN_ZEPHYR=false MODERNJS_DEPLOY=cloudflare modern deploy --skip-build && ${publicSurfaceCloudflareOutputCommand}`,
374
373
  'cloudflare:deploy': 'ULTRAMODERN_CLOUDFLARE_REQUIRE_PUBLIC_URLS=true pnpm run cloudflare:build && wrangler deploy --config .output/wrangler.json',
375
374
  'cloudflare:preview': 'pnpm run cloudflare:build && wrangler dev --config .output/wrangler.json',
376
375
  'cloudflare:proof': `node ${relativeRootFor(app.directory)}/scripts/proof-cloudflare-version.mts --app ${app.id}`,
package/package.json CHANGED
@@ -21,7 +21,7 @@
21
21
  "engines": {
22
22
  "node": ">=20"
23
23
  },
24
- "version": "3.5.0-ultramodern.11",
24
+ "version": "3.5.0-ultramodern.13",
25
25
  "types": "./dist/types/index.d.ts",
26
26
  "main": "./dist/esm-node/index.js",
27
27
  "bin": {
@@ -77,7 +77,7 @@
77
77
  "@modern-js/codesmith": "2.6.9",
78
78
  "oxfmt": "0.56.0",
79
79
  "ultracite": "7.8.3",
80
- "@modern-js/i18n-utils": "npm:@bleedingdev/modern-js-i18n-utils@3.5.0-ultramodern.11"
80
+ "@modern-js/i18n-utils": "npm:@bleedingdev/modern-js-i18n-utils@3.5.0-ultramodern.13"
81
81
  },
82
82
  "devDependencies": {
83
83
  "@rslib/core": "0.23.1",
@@ -99,6 +99,6 @@
99
99
  "test": "rm -rf dist && rslib build -c rslibconfig.mts && rstest --passWithNoTests"
100
100
  },
101
101
  "ultramodern": {
102
- "frameworkVersion": "3.5.0-ultramodern.11"
102
+ "frameworkVersion": "3.5.0-ultramodern.13"
103
103
  }
104
104
  }
@@ -1,5 +1,6 @@
1
1
  node_modules/
2
2
  dist/
3
+ dist-cloudflare/
3
4
  build/
4
5
  .modernjs/cache/
5
6
  .modern-js/
@@ -63,5 +63,4 @@ allowBuilds:
63
63
 
64
64
  patchedDependencies:
65
65
  '@tanstack/router-core@{{tanstackRouterCoreVersion}}': patches/@tanstack__router-core@{{tanstackRouterCoreVersion}}.patch
66
- 'drizzle-orm@{{drizzleOrmVersion}}': patches/drizzle-orm-ts7-strict-declarations.patch
67
66
  'effect@{{effectVersion}}': patches/effect-schema-error-type-id.patch
@@ -1363,12 +1363,17 @@ const extractAssetPrefixExpression = modernConfig => {
1363
1363
  assert(match?.groups?.expression, 'modern.config.ts must assign assetPrefix');
1364
1364
  return match.groups.expression;
1365
1365
  };
1366
- const assertBuildCacheBase = (appId, modernConfig) => {
1366
+ const assertTargetIsolatedBuildArtifacts = (appId, modernConfig) => {
1367
1367
  assert(
1368
- modernConfig.includes("const buildCacheTarget = cloudflareDeployEnabled ? 'cloudflare' : 'web';") &&
1369
- modernConfig.includes('const buildCacheDirectory = `node_modules/.cache/rspack-${appId}-${buildCacheTarget}`;') &&
1368
+ modernConfig.includes("const buildTarget = cloudflareDeployEnabled ? 'cloudflare' : 'web';") &&
1369
+ modernConfig.includes("const buildOutputRoot = cloudflareDeployEnabled ? 'dist-cloudflare' : 'dist';") &&
1370
+ modernConfig.includes('const buildTempDirectory = `node_modules/.modern-js-${appId}-${buildTarget}`;') &&
1371
+ modernConfig.includes('const buildCacheDirectory = `node_modules/.cache/rspack-${appId}-${buildTarget}`;') &&
1372
+ modernConfig.includes('root: buildOutputRoot,') &&
1373
+ modernConfig.includes('tempDir: buildTempDirectory,') &&
1374
+ modernConfig.includes('cacheDigest: [appId, buildTarget],') &&
1370
1375
  modernConfig.includes('cacheDirectory: buildCacheDirectory,'),
1371
- `${appId} must provide a per-app/per-target Rspack cache base directory`,
1376
+ `${appId} must isolate build output, Modern temp files, and Rspack cache by app and build target`,
1372
1377
  );
1373
1378
  };
1374
1379
  const assertCloudflareBuildSkipsDeployRebuild = (appId, packageJson) => {
@@ -1378,6 +1383,12 @@ const assertCloudflareBuildSkipsDeployRebuild = (appId, packageJson) => {
1378
1383
  ),
1379
1384
  `${appId} cloudflare:build must deploy with --skip-build after the explicit Cloudflare build`,
1380
1385
  );
1386
+ assert(
1387
+ !packageJson.scripts?.['cloudflare:build']?.includes(
1388
+ '--target dist && ULTRAMODERN_ZEPHYR=false MODERNJS_DEPLOY=cloudflare modern deploy',
1389
+ ),
1390
+ `${appId} cloudflare:build must not write public-surface assets into the normal web dist before deploy`,
1391
+ );
1381
1392
  };
1382
1393
  const stripYamlInlineComment = value => {
1383
1394
  let quote = undefined;
@@ -1795,6 +1806,7 @@ const shellRouteHead = readText('apps/shell-super-app/src/routes/ultramodern-rou
1795
1806
  const shellRouteMetadata = readText('apps/shell-super-app/src/routes/ultramodern-route-metadata.ts');
1796
1807
  assert(/^\.mf\/$/mu.test(gitignore), 'Generated .gitignore must ignore root Module Federation diagnostics');
1797
1808
  assert(/^\*\*\/\.mf\/$/mu.test(gitignore), 'Generated .gitignore must ignore per-app Module Federation diagnostics');
1809
+ assert(/^dist-cloudflare\/$/mu.test(gitignore), 'Generated .gitignore must ignore Cloudflare build output');
1798
1810
  assert(shellModernAppEnv.includes("import '@modern-js/app-tools/types';"), 'Shell app env must import the framework-owned app ambient type bundle through module resolution');
1799
1811
  assert(/declare global \{\s*const ULTRAMODERN_SITE_URL: string;\s*\}/u.test(shellModernAppEnv), 'Shell app env must keep generated globals explicit after importing app ambient types');
1800
1812
  assert(!shellModernAppEnv.includes("declare module '*.svg'"), 'Shell app env must not redeclare framework-owned svg asset modules');
@@ -1818,7 +1830,7 @@ assert(shellPackage.dependencies?.['@modern-js/plugin-i18n'] === expectedModernP
1818
1830
  assert(shellPackage.dependencies?.['@modern-js/plugin-tanstack'] === expectedModernPackageSpecifier('@modern-js/plugin-tanstack'), 'Shell plugin-tanstack dependency must match package source metadata');
1819
1831
  assert(shellPackage.dependencies?.['@modern-js/runtime'] === expectedModernPackageSpecifier('@modern-js/runtime'), 'Shell runtime dependency must match package source metadata');
1820
1832
  assert(shellPackage.scripts?.['cloudflare:deploy'] === 'ULTRAMODERN_CLOUDFLARE_REQUIRE_PUBLIC_URLS=true pnpm run cloudflare:build && wrangler deploy --config .output/wrangler.json', 'Shell must expose cloudflare:deploy');
1821
- assertBuildCacheBase('shell-super-app', shellModernConfig);
1833
+ assertTargetIsolatedBuildArtifacts('shell-super-app', shellModernConfig);
1822
1834
  assertCloudflareBuildSkipsDeployRebuild('shell-super-app', shellPackage);
1823
1835
  const shellContract = generatedContract.apps?.find(app => app.id === 'shell-super-app');
1824
1836
  assert(shellContract?.deploy?.cloudflare?.workerName === expectedWorkerName('shell-super-app'), 'Shell Cloudflare workerName is incorrect');
@@ -1901,7 +1913,7 @@ for (const vertical of fullStackVerticals) {
1901
1913
  assert(routeMetadata.includes("authoring: 'colocated-route-meta'"), `${vertical.id} route metadata manifest must advertise colocated authoring`);
1902
1914
  assert(packageJson.name === vertical.packageName, `${vertical.id} package name is incorrect`);
1903
1915
  assert(packageJson.scripts?.['cloudflare:deploy'] === 'ULTRAMODERN_CLOUDFLARE_REQUIRE_PUBLIC_URLS=true pnpm run cloudflare:build && wrangler deploy --config .output/wrangler.json', `${vertical.id} must expose cloudflare:deploy`);
1904
- assertBuildCacheBase(vertical.id, modernConfig);
1916
+ assertTargetIsolatedBuildArtifacts(vertical.id, modernConfig);
1905
1917
  assertCloudflareBuildSkipsDeployRebuild(vertical.id, packageJson);
1906
1918
  assert(packageJson.scripts?.['cloudflare:proof']?.includes(`--app ${vertical.id}`), `${vertical.id} must expose cloudflare:proof`);
1907
1919
  assert(packageJson.devDependencies?.['@modern-js/app-tools'] === expectedModernPackageSpecifier('@modern-js/app-tools'), `${vertical.id} app-tools dependency must match package source metadata`);