@bleedingdev/modern-js-create 3.5.0-ultramodern.2 → 3.5.0-ultramodern.20

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 (32) hide show
  1. package/README.md +20 -14
  2. package/dist/cjs/ultramodern-tooling/commands.cjs +357 -3
  3. package/dist/cjs/ultramodern-workspace/app-files.cjs +8 -11
  4. package/dist/cjs/ultramodern-workspace/module-federation.cjs +13 -6
  5. package/dist/cjs/ultramodern-workspace/package-json.cjs +15 -8
  6. package/dist/cjs/ultramodern-workspace/versions.cjs +5 -0
  7. package/dist/cjs/ultramodern-workspace/workspace-scripts.cjs +2 -0
  8. package/dist/cjs/ultramodern-workspace/write-workspace.cjs +2 -0
  9. package/dist/esm/ultramodern-tooling/commands.js +357 -3
  10. package/dist/esm/ultramodern-workspace/app-files.js +8 -11
  11. package/dist/esm/ultramodern-workspace/module-federation.js +13 -6
  12. package/dist/esm/ultramodern-workspace/package-json.js +5 -8
  13. package/dist/esm/ultramodern-workspace/versions.js +3 -1
  14. package/dist/esm/ultramodern-workspace/workspace-scripts.js +3 -1
  15. package/dist/esm/ultramodern-workspace/write-workspace.js +3 -1
  16. package/dist/esm-node/ultramodern-tooling/commands.js +357 -3
  17. package/dist/esm-node/ultramodern-workspace/app-files.js +8 -11
  18. package/dist/esm-node/ultramodern-workspace/module-federation.js +13 -6
  19. package/dist/esm-node/ultramodern-workspace/package-json.js +5 -8
  20. package/dist/esm-node/ultramodern-workspace/versions.js +3 -1
  21. package/dist/esm-node/ultramodern-workspace/workspace-scripts.js +3 -1
  22. package/dist/esm-node/ultramodern-workspace/write-workspace.js +3 -1
  23. package/dist/types/ultramodern-workspace/versions.d.ts +2 -0
  24. package/package.json +3 -3
  25. package/template-workspace/.gitignore.handlebars +3 -0
  26. package/template-workspace/README.md.handlebars +19 -13
  27. package/template-workspace/patches/@module-federation__bridge-react@2.6.0.patch +140 -0
  28. package/template-workspace/patches/@module-federation__modern-js-v3@2.6.0.patch +57 -0
  29. package/template-workspace/patches/drizzle-orm-ts7-strict-declarations.patch +452 -0
  30. package/template-workspace/patches/effect-schema-error-type-id.patch +18 -0
  31. package/template-workspace/pnpm-workspace.yaml.handlebars +8 -0
  32. package/templates/workspace-scripts/validate-ultramodern-workspace.mjs.handlebars +87 -5
@@ -486,7 +486,7 @@ const createAppConfigContract = app => ({
486
486
  'zephyrRspackPlugin',
487
487
  ],
488
488
  dev: {
489
- assetPrefix: '/',
489
+ assetPrefix: app.kind === 'shell' ? '/' : 'app-public-origin',
490
490
  },
491
491
  output: {
492
492
  assetPrefix: {
@@ -1116,6 +1116,7 @@ const assertProjectReferenceEmitConfig = (tsConfig, packagePath) => {
1116
1116
  );
1117
1117
  };
1118
1118
  const assertTsConfigReferenceGraph = () => {
1119
+ const baseTsConfig = readJson('tsconfig.base.json');
1119
1120
  const rootTsConfig = readJson('tsconfig.json');
1120
1121
  const shellTsConfig = readJson('apps/shell-super-app/tsconfig.json');
1121
1122
  const shellMfTypesTsConfig = readJson(
@@ -1151,6 +1152,13 @@ const assertTsConfigReferenceGraph = () => {
1151
1152
  'apps/shell-super-app/tsconfig.json references',
1152
1153
  'restore the generated shell project-reference graph',
1153
1154
  );
1155
+ assert(baseTsConfig.compilerOptions?.skipLibCheck !== true, 'tsconfig.base.json must not use skipLibCheck');
1156
+ assertSameJson(
1157
+ shellTsConfig.include ?? [],
1158
+ ['src', 'locales/**/*.json', 'package.json', 'shared'],
1159
+ 'apps/shell-super-app/tsconfig.json include',
1160
+ 'restore the generated shell typecheck boundary',
1161
+ );
1154
1162
  assertProjectReferenceEmitConfig(
1155
1163
  shellTsConfig,
1156
1164
  'apps/shell-super-app',
@@ -1158,7 +1166,7 @@ const assertTsConfigReferenceGraph = () => {
1158
1166
  assertSameJson(
1159
1167
  shellMfTypesTsConfig,
1160
1168
  {
1161
- extends: './tsconfig.json',
1169
+ extends: '../../tsconfig.base.json',
1162
1170
  include: ['src/modern-app-env.d.ts'],
1163
1171
  },
1164
1172
  'apps/shell-super-app/tsconfig.mf-types.json',
@@ -1191,11 +1199,17 @@ const assertTsConfigReferenceGraph = () => {
1191
1199
  `${vertical.path}/tsconfig.json references`,
1192
1200
  'restore the generated MicroVertical project-reference graph',
1193
1201
  );
1202
+ assertSameJson(
1203
+ verticalTsConfig.include ?? [],
1204
+ ['src', 'locales/**/*.json', 'package.json', 'shared', 'api'],
1205
+ `${vertical.path}/tsconfig.json include`,
1206
+ 'restore the generated MicroVertical typecheck boundary',
1207
+ );
1194
1208
  assertProjectReferenceEmitConfig(verticalTsConfig, vertical.path);
1195
1209
  assertSameJson(
1196
1210
  verticalMfTypesTsConfig,
1197
1211
  {
1198
- extends: './tsconfig.json',
1212
+ extends: '../../tsconfig.base.json',
1199
1213
  include: [
1200
1214
  'src/federation-entry.tsx',
1201
1215
  ...vertical.componentPaths.map(componentPath =>
@@ -1349,6 +1363,33 @@ const extractAssetPrefixExpression = modernConfig => {
1349
1363
  assert(match?.groups?.expression, 'modern.config.ts must assign assetPrefix');
1350
1364
  return match.groups.expression;
1351
1365
  };
1366
+ const assertTargetIsolatedBuildArtifacts = (appId, modernConfig) => {
1367
+ assert(
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],') &&
1375
+ modernConfig.includes('cacheDirectory: buildCacheDirectory,'),
1376
+ `${appId} must isolate build output, Modern temp files, and Rspack cache by app and build target`,
1377
+ );
1378
+ };
1379
+ const assertCloudflareBuildSkipsDeployRebuild = (appId, packageJson) => {
1380
+ assert(
1381
+ packageJson.scripts?.['cloudflare:build']?.includes(
1382
+ 'ULTRAMODERN_ZEPHYR=false MODERNJS_DEPLOY=cloudflare modern deploy --skip-build',
1383
+ ),
1384
+ `${appId} cloudflare:build must deploy with --skip-build after the explicit Cloudflare build`,
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
+ );
1392
+ };
1352
1393
  const stripYamlInlineComment = value => {
1353
1394
  let quote = undefined;
1354
1395
  for (let index = 0; index < value.length; index += 1) {
@@ -1462,6 +1503,9 @@ const requiredPaths = [
1462
1503
  '.gitignore',
1463
1504
  'package.json',
1464
1505
  'pnpm-workspace.yaml',
1506
+ 'patches/@module-federation__modern-js-v3@{{moduleFederationVersion}}.patch',
1507
+ 'patches/@module-federation__bridge-react@{{moduleFederationVersion}}.patch',
1508
+ 'patches/effect-schema-error-type-id.patch',
1465
1509
  'tsconfig.json',
1466
1510
  'tsconfig.base.json',
1467
1511
  'oxlint.config.ts',
@@ -1537,6 +1581,25 @@ for (const vertical of fullStackVerticals) {
1537
1581
  for (const requiredPath of requiredPaths) {
1538
1582
  assertExists(requiredPath);
1539
1583
  }
1584
+ const pnpmWorkspace = readText('pnpm-workspace.yaml');
1585
+ assert(
1586
+ pnpmWorkspace.includes(
1587
+ "'@module-federation/modern-js-v3@{{moduleFederationVersion}}': patches/@module-federation__modern-js-v3@{{moduleFederationVersion}}.patch",
1588
+ ),
1589
+ 'pnpm-workspace.yaml must patch the generated Module Federation Modern.js integration cohort',
1590
+ );
1591
+ assert(
1592
+ pnpmWorkspace.includes(
1593
+ "'@module-federation/bridge-react@{{moduleFederationVersion}}': patches/@module-federation__bridge-react@{{moduleFederationVersion}}.patch",
1594
+ ),
1595
+ 'pnpm-workspace.yaml must patch the generated Module Federation React bridge cohort',
1596
+ );
1597
+ assert(
1598
+ pnpmWorkspace.includes(
1599
+ "'effect@{{effectVersion}}': patches/effect-schema-error-type-id.patch",
1600
+ ),
1601
+ 'pnpm-workspace.yaml must patch the generated Effect declaration cohort',
1602
+ );
1540
1603
  for (const oldRemotePath of oldRemotePaths) {
1541
1604
  assertNotExists(oldRemotePath);
1542
1605
  }
@@ -1751,8 +1814,17 @@ assert(JSON.stringify(generatedContract.performanceReadiness?.signals?.map(signa
1751
1814
 
1752
1815
  const shellModernConfig = readText('apps/shell-super-app/modern.config.ts');
1753
1816
  const shellModuleFederationConfig = readText('apps/shell-super-app/module-federation.config.ts');
1817
+ const shellModernAppEnv = readText('apps/shell-super-app/src/modern-app-env.d.ts');
1818
+ const gitignore = readText('.gitignore');
1754
1819
  const shellRouteHead = readText('apps/shell-super-app/src/routes/ultramodern-route-head.tsx');
1755
1820
  const shellRouteMetadata = readText('apps/shell-super-app/src/routes/ultramodern-route-metadata.ts');
1821
+ assert(/^\.mf\/$/mu.test(gitignore), 'Generated .gitignore must ignore root Module Federation diagnostics');
1822
+ assert(/^\*\*\/\.mf\/$/mu.test(gitignore), 'Generated .gitignore must ignore per-app Module Federation diagnostics');
1823
+ assert(/^dist-cloudflare\/$/mu.test(gitignore), 'Generated .gitignore must ignore Cloudflare build output');
1824
+ assert(shellModernAppEnv.includes("import '@modern-js/app-tools/types';"), 'Shell app env must import the framework-owned app ambient type bundle through module resolution');
1825
+ 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');
1826
+ assert(!shellModernAppEnv.includes("declare module '*.svg'"), 'Shell app env must not redeclare framework-owned svg asset modules');
1827
+ assert(!shellModernAppEnv.includes("declare module '*.css'"), 'Shell app env must not redeclare framework-owned css asset modules');
1756
1828
  assert(shellRouteMetadata.includes('@generated by @modern-js/create'), 'Shell route metadata compatibility manifest must be marked generated');
1757
1829
  assert(shellRouteMetadata.includes("authoring: 'colocated-route-meta'"), 'Shell route metadata manifest must advertise colocated authoring');
1758
1830
  const expectedZephyrDependencies = Object.fromEntries(
@@ -1771,6 +1843,9 @@ assert(shellPackage.dependencies?.['@modern-js/plugin-bff'] === expectedModernPa
1771
1843
  assert(shellPackage.dependencies?.['@modern-js/plugin-i18n'] === expectedModernPackageSpecifier('@modern-js/plugin-i18n'), 'Shell plugin-i18n dependency must match package source metadata');
1772
1844
  assert(shellPackage.dependencies?.['@modern-js/plugin-tanstack'] === expectedModernPackageSpecifier('@modern-js/plugin-tanstack'), 'Shell plugin-tanstack dependency must match package source metadata');
1773
1845
  assert(shellPackage.dependencies?.['@modern-js/runtime'] === expectedModernPackageSpecifier('@modern-js/runtime'), 'Shell runtime dependency must match package source metadata');
1846
+ 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');
1847
+ assertTargetIsolatedBuildArtifacts('shell-super-app', shellModernConfig);
1848
+ assertCloudflareBuildSkipsDeployRebuild('shell-super-app', shellPackage);
1774
1849
  const shellContract = generatedContract.apps?.find(app => app.id === 'shell-super-app');
1775
1850
  assert(shellContract?.deploy?.cloudflare?.workerName === expectedWorkerName('shell-super-app'), 'Shell Cloudflare workerName is incorrect');
1776
1851
  assert(shellContract?.deploy?.cloudflare?.publicUrlEnv === 'ULTRAMODERN_PUBLIC_URL_SHELL_SUPER_APP', 'Shell Cloudflare public URL env is incorrect');
@@ -1841,12 +1916,19 @@ for (const vertical of fullStackVerticals) {
1841
1916
  const packageJson = readJson(`${vertical.path}/package.json`);
1842
1917
  const modernConfig = readText(`${vertical.path}/modern.config.ts`);
1843
1918
  const moduleFederationConfig = readText(`${vertical.path}/module-federation.config.ts`);
1919
+ const modernAppEnv = readText(`${vertical.path}/src/modern-app-env.d.ts`);
1844
1920
  const routeHead = readText(`${vertical.path}/src/routes/ultramodern-route-head.tsx`);
1845
1921
  const routeMetadata = readText(`${vertical.path}/src/routes/ultramodern-route-metadata.ts`);
1922
+ assert(modernAppEnv.includes("import '@modern-js/app-tools/types';"), `${vertical.id} app env must import the framework-owned app ambient type bundle through module resolution`);
1923
+ assert(/declare global \{\s*const ULTRAMODERN_SITE_URL: string;\s*\}/u.test(modernAppEnv), `${vertical.id} app env must keep generated globals explicit after importing app ambient types`);
1924
+ assert(!modernAppEnv.includes("declare module '*.svg'"), `${vertical.id} app env must not redeclare framework-owned svg asset modules`);
1925
+ assert(!modernAppEnv.includes("declare module '*.css'"), `${vertical.id} app env must not redeclare framework-owned css asset modules`);
1846
1926
  assert(routeMetadata.includes('@generated by @modern-js/create'), `${vertical.id} route metadata compatibility manifest must be marked generated`);
1847
1927
  assert(routeMetadata.includes("authoring: 'colocated-route-meta'"), `${vertical.id} route metadata manifest must advertise colocated authoring`);
1848
1928
  assert(packageJson.name === vertical.packageName, `${vertical.id} package name is incorrect`);
1849
1929
  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`);
1930
+ assertTargetIsolatedBuildArtifacts(vertical.id, modernConfig);
1931
+ assertCloudflareBuildSkipsDeployRebuild(vertical.id, packageJson);
1850
1932
  assert(packageJson.scripts?.['cloudflare:proof']?.includes(`--app ${vertical.id}`), `${vertical.id} must expose cloudflare:proof`);
1851
1933
  assert(packageJson.devDependencies?.['@modern-js/app-tools'] === expectedModernPackageSpecifier('@modern-js/app-tools'), `${vertical.id} app-tools dependency must match package source metadata`);
1852
1934
  assert(packageJson.dependencies?.['@modern-js/plugin-bff'] === expectedModernPackageSpecifier('@modern-js/plugin-bff'), `${vertical.id} plugin-bff dependency must match package source metadata`);
@@ -1892,9 +1974,9 @@ for (const vertical of fullStackVerticals) {
1892
1974
  assert(!verticalAssetPrefixExpression.includes('configuredSiteUrl') && !verticalAssetPrefixExpression.includes('MODERN_PUBLIC_SITE_URL'), `${vertical.id} asset prefix must not fall back to MODERN_PUBLIC_SITE_URL`);
1893
1975
  assert(modernConfig.includes(`envValue('ULTRAMODERN_PUBLIC_URL_${vertical.id.replace(/-/g, '_').toUpperCase()}')`), `${vertical.id} asset prefix must read its per-app public URL`);
1894
1976
  assert(modernConfig.includes('inferredCloudflareUrl'), `${vertical.id} asset prefix must support workers.dev origin inference`);
1895
- assert(modernConfig.includes("assetPrefix: '/'"), `${vertical.id} modern.config.ts must keep dev assets origin-relative`);
1977
+ assert(/dev:\s*\{\s*\/\/ Remote dev manifests must publish an absolute publicPath[\s\S]*?assetPrefix,\s*\}/u.test(modernConfig), `${vertical.id} modern.config.ts must publish dev assets from its own remote origin`);
1896
1978
  assert(modernConfig.includes('assetPrefix,'), `${vertical.id} modern.config.ts must wire output.assetPrefix to the derived asset prefix`);
1897
- assert(contractEntry?.config?.dev?.assetPrefix === '/', `${vertical.id} dev asset prefix must stay origin-relative`);
1979
+ assert(contractEntry?.config?.dev?.assetPrefix === 'app-public-origin', `${vertical.id} dev asset prefix must default to its app public origin`);
1898
1980
  assert(contractEntry?.config?.output?.assetPrefix?.default === 'app-public-origin', `${vertical.id} asset prefix must default to its app public origin`);
1899
1981
  assert(JSON.stringify(contractEntry?.config?.output?.assetPrefix?.envFallbackOrder) === JSON.stringify(['MODERN_ASSET_PREFIX', 'ULTRAMODERN_ASSET_PREFIX']), `${vertical.id} asset prefix env fallback order is incorrect`);
1900
1982
  assert(contractEntry?.config?.output?.disableTsChecker === false, `${vertical.id} must keep the framework TypeScript checker enabled`);