@bleedingdev/modern-js-ultramodern-app-tools 3.9.3-ultramodern.1 → 3.9.3-ultramodern.11

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 (149) hide show
  1. package/README.md +3 -1
  2. package/bin/ultramodern.mjs +1 -1
  3. package/dist/cjs/native-composition/config-metadata.js +76 -4
  4. package/dist/cjs/native-composition/module-federation-renderer-plugin.js +1 -1
  5. package/dist/cjs/native-composition/native-development.js +132 -27
  6. package/dist/cjs/native-composition/native-entry.js +84 -19
  7. package/dist/cjs/native-composition/native-federation-dev-assets.js +143 -10
  8. package/dist/cjs/native-composition/native-federation-dev-public-path.js +46 -0
  9. package/dist/cjs/native-composition/native-infrastructure.js +92 -2
  10. package/dist/cjs/native-composition/native-module-federation.js +109 -25
  11. package/dist/cjs/native-composition/native-routes.js +120 -5
  12. package/dist/cjs/native-composition/native-worker-context-profiles.js +112 -0
  13. package/dist/cjs/native-composition/native-worker-federation-config.js +215 -0
  14. package/dist/cjs/native-composition/native-worker-federation-policy.js +102 -0
  15. package/dist/cjs/native-composition/native-worker-federation.js +226 -0
  16. package/dist/cjs/native-composition/native-worker-publication.js +107 -0
  17. package/dist/cjs/native-composition/native-worker.js +37 -3
  18. package/dist/cjs/native-composition/preset.js +35 -15
  19. package/dist/cjs/native-composition/renderer-build-resolution.js +5 -1
  20. package/dist/cjs/native-composition/renderer-installed-profile.js +61 -2
  21. package/dist/cjs/native-composition/renderer-release-identity.js +95 -0
  22. package/dist/cjs/native-composition/renderer-selection.js +2 -1
  23. package/dist/cjs/native-composition/server-minify.js +73 -0
  24. package/dist/cjs/native-composition/type-checker.js +14 -4
  25. package/dist/cjs/native-composition/workspace-preset.js +29 -9
  26. package/dist/cjs/renderers/react/build-metadata.js +2 -40
  27. package/dist/cjs/renderers/react/profile.js +4 -4
  28. package/dist/cjs/renderers/react/router-bindings.js +2 -2
  29. package/dist/cjs/renderers/react/ssr-integration-plugin.js +11 -3
  30. package/dist/esm/native-composition/config-metadata.mjs +76 -4
  31. package/dist/esm/native-composition/module-federation-renderer-plugin.mjs +2 -2
  32. package/dist/esm/native-composition/native-development.mjs +133 -28
  33. package/dist/esm/native-composition/native-entry.mjs +85 -20
  34. package/dist/esm/native-composition/native-federation-dev-assets.mjs +124 -9
  35. package/dist/esm/native-composition/native-federation-dev-public-path.mjs +38 -1
  36. package/dist/esm/native-composition/native-infrastructure.mjs +92 -2
  37. package/dist/esm/native-composition/native-module-federation.mjs +108 -27
  38. package/dist/esm/native-composition/native-routes.mjs +110 -4
  39. package/dist/esm/native-composition/native-worker-context-profiles.mjs +63 -0
  40. package/dist/esm/native-composition/native-worker-federation-config.mjs +164 -0
  41. package/dist/esm/native-composition/native-worker-federation-policy.mjs +53 -0
  42. package/dist/esm/native-composition/native-worker-federation.mjs +166 -0
  43. package/dist/esm/native-composition/native-worker-publication.mjs +66 -0
  44. package/dist/esm/native-composition/native-worker.mjs +37 -3
  45. package/dist/esm/native-composition/preset.mjs +28 -14
  46. package/dist/esm/native-composition/renderer-build-resolution.mjs +5 -1
  47. package/dist/esm/native-composition/renderer-installed-profile.mjs +54 -1
  48. package/dist/esm/native-composition/renderer-release-identity.mjs +54 -0
  49. package/dist/esm/native-composition/renderer-selection.mjs +2 -1
  50. package/dist/esm/native-composition/server-minify.mjs +32 -0
  51. package/dist/esm/native-composition/type-checker.mjs +4 -4
  52. package/dist/esm/native-composition/workspace-preset.mjs +29 -9
  53. package/dist/esm/renderers/react/build-metadata.mjs +2 -40
  54. package/dist/esm/renderers/react/profile.mjs +4 -4
  55. package/dist/esm/renderers/react/router-bindings.mjs +2 -2
  56. package/dist/esm/renderers/react/ssr-integration-plugin.mjs +11 -3
  57. package/dist/esm-node/native-composition/config-metadata.mjs +76 -4
  58. package/dist/esm-node/native-composition/module-federation-renderer-plugin.mjs +2 -2
  59. package/dist/esm-node/native-composition/native-development.mjs +133 -28
  60. package/dist/esm-node/native-composition/native-entry.mjs +85 -20
  61. package/dist/esm-node/native-composition/native-federation-dev-assets.mjs +124 -9
  62. package/dist/esm-node/native-composition/native-federation-dev-public-path.mjs +38 -1
  63. package/dist/esm-node/native-composition/native-infrastructure.mjs +92 -2
  64. package/dist/esm-node/native-composition/native-module-federation.mjs +108 -27
  65. package/dist/esm-node/native-composition/native-routes.mjs +110 -4
  66. package/dist/esm-node/native-composition/native-worker-context-profiles.mjs +64 -0
  67. package/dist/esm-node/native-composition/native-worker-federation-config.mjs +165 -0
  68. package/dist/esm-node/native-composition/native-worker-federation-policy.mjs +54 -0
  69. package/dist/esm-node/native-composition/native-worker-federation.mjs +167 -0
  70. package/dist/esm-node/native-composition/native-worker-publication.mjs +67 -0
  71. package/dist/esm-node/native-composition/native-worker.mjs +37 -3
  72. package/dist/esm-node/native-composition/preset.mjs +28 -14
  73. package/dist/esm-node/native-composition/renderer-build-resolution.mjs +5 -1
  74. package/dist/esm-node/native-composition/renderer-installed-profile.mjs +54 -1
  75. package/dist/esm-node/native-composition/renderer-release-identity.mjs +55 -0
  76. package/dist/esm-node/native-composition/renderer-selection.mjs +2 -1
  77. package/dist/esm-node/native-composition/server-minify.mjs +33 -0
  78. package/dist/esm-node/native-composition/type-checker.mjs +4 -4
  79. package/dist/esm-node/native-composition/workspace-preset.mjs +29 -9
  80. package/dist/esm-node/renderers/react/build-metadata.mjs +2 -40
  81. package/dist/esm-node/renderers/react/profile.mjs +4 -4
  82. package/dist/esm-node/renderers/react/router-bindings.mjs +2 -2
  83. package/dist/esm-node/renderers/react/ssr-integration-plugin.mjs +11 -3
  84. package/dist/types/native-composition/config-metadata.d.ts +6 -0
  85. package/dist/types/native-composition/native-development.d.ts +8 -0
  86. package/dist/types/native-composition/native-entry.d.ts +1 -1
  87. package/dist/types/native-composition/native-federation-dev-assets.d.ts +26 -2
  88. package/dist/types/native-composition/native-federation-dev-public-path.d.ts +9 -0
  89. package/dist/types/native-composition/native-infrastructure.d.ts +10 -0
  90. package/dist/types/native-composition/native-module-federation.d.ts +8 -4
  91. package/dist/types/native-composition/native-routes.d.ts +11 -0
  92. package/dist/types/native-composition/native-worker-context-profiles.d.ts +2 -0
  93. package/dist/types/native-composition/native-worker-federation-config.d.ts +46 -0
  94. package/dist/types/native-composition/native-worker-federation-policy.d.ts +8 -0
  95. package/dist/types/native-composition/native-worker-federation.d.ts +57 -0
  96. package/dist/types/native-composition/native-worker-publication.d.ts +12 -0
  97. package/dist/types/native-composition/native-worker.d.ts +14 -1
  98. package/dist/types/native-composition/preset.d.ts +16 -1
  99. package/dist/types/native-composition/renderer-installed-profile.d.ts +6 -0
  100. package/dist/types/native-composition/renderer-release-identity.d.ts +11 -0
  101. package/dist/types/native-composition/server-minify.d.ts +33 -0
  102. package/dist/types-esm/native-composition/config-metadata.d.mts +6 -0
  103. package/dist/types-esm/native-composition/native-development.d.mts +8 -0
  104. package/dist/types-esm/native-composition/native-entry.d.mts +1 -1
  105. package/dist/types-esm/native-composition/native-federation-dev-assets.d.mts +26 -2
  106. package/dist/types-esm/native-composition/native-federation-dev-public-path.d.mts +9 -0
  107. package/dist/types-esm/native-composition/native-infrastructure.d.mts +10 -0
  108. package/dist/types-esm/native-composition/native-module-federation.d.mts +8 -4
  109. package/dist/types-esm/native-composition/native-routes.d.mts +11 -0
  110. package/dist/types-esm/native-composition/native-worker-context-profiles.d.mts +2 -0
  111. package/dist/types-esm/native-composition/native-worker-federation-config.d.mts +46 -0
  112. package/dist/types-esm/native-composition/native-worker-federation-policy.d.mts +8 -0
  113. package/dist/types-esm/native-composition/native-worker-federation.d.mts +57 -0
  114. package/dist/types-esm/native-composition/native-worker-publication.d.mts +12 -0
  115. package/dist/types-esm/native-composition/native-worker.d.mts +14 -1
  116. package/dist/types-esm/native-composition/preset.d.mts +16 -1
  117. package/dist/types-esm/native-composition/renderer-installed-profile.d.mts +6 -0
  118. package/dist/types-esm/native-composition/renderer-release-identity.d.mts +11 -0
  119. package/dist/types-esm/native-composition/server-minify.d.mts +33 -0
  120. package/lib/build-target.d.ts +17 -0
  121. package/lib/react-types.d.ts +1 -0
  122. package/package.json +39 -37
  123. package/src/native-composition/config-metadata.ts +114 -12
  124. package/src/native-composition/module-federation-renderer-plugin.ts +6 -2
  125. package/src/native-composition/native-development.ts +256 -46
  126. package/src/native-composition/native-entry.ts +116 -21
  127. package/src/native-composition/native-federation-dev-assets.ts +240 -13
  128. package/src/native-composition/native-federation-dev-public-path.ts +96 -0
  129. package/src/native-composition/native-infrastructure.ts +176 -2
  130. package/src/native-composition/native-module-federation.ts +178 -55
  131. package/src/native-composition/native-routes.ts +167 -3
  132. package/src/native-composition/native-worker-context-profiles.ts +119 -0
  133. package/src/native-composition/native-worker-federation-config.ts +343 -0
  134. package/src/native-composition/native-worker-federation-policy.ts +119 -0
  135. package/src/native-composition/native-worker-federation.ts +401 -0
  136. package/src/native-composition/native-worker-publication.ts +151 -0
  137. package/src/native-composition/native-worker.ts +71 -3
  138. package/src/native-composition/preset.ts +54 -23
  139. package/src/native-composition/renderer-build-resolution.ts +6 -1
  140. package/src/native-composition/renderer-installed-profile.ts +67 -0
  141. package/src/native-composition/renderer-release-identity.ts +78 -0
  142. package/src/native-composition/renderer-selection.ts +3 -1
  143. package/src/native-composition/server-minify.ts +48 -0
  144. package/src/native-composition/type-checker.ts +8 -8
  145. package/src/native-composition/workspace-preset.ts +65 -24
  146. package/src/renderers/react/build-metadata.ts +3 -46
  147. package/src/renderers/react/profile.ts +4 -4
  148. package/src/renderers/react/router-bindings.ts +2 -2
  149. package/src/renderers/react/ssr-integration-plugin.ts +14 -4
package/README.md CHANGED
@@ -142,7 +142,9 @@ export default defineConfig(
142
142
  The workspace preset reads `topology/reference-topology.json` and
143
143
  `topology/local-overlays/development.json` relative to that config. Those records
144
144
  provide app identity, renderer, development ports, composed remote references
145
- and delivery unit identity. An authored `renderer` must match the topology.
145
+ and delivery unit identity. An authored `renderer` must match the topology. A
146
+ headless (API-only) unit declares renderer `none` and no Module Federation
147
+ name; its config selects no `renderer`.
146
148
  Adding a shell or vertical changes the records; existing application configs
147
149
  keep their authored contents.
148
150
 
@@ -4,7 +4,7 @@ import { readFile } from 'node:fs/promises';
4
4
  const [major, minor] = process.versions.node.split('.').map(Number);
5
5
  if (major < 26 || (major === 26 && minor < 10)) {
6
6
  console.error(
7
- `UltraModern.js requires Node.js >=26.10.0; detected v${process.versions.node}.`,
7
+ `UltraModern.js requires Node.js >=26.12.0; detected v${process.versions.node}.`,
8
8
  );
9
9
  process.exit(1);
10
10
  }
@@ -47,8 +47,12 @@ const external_node_module_namespaceObject = require("node:module");
47
47
  const external_node_path_namespaceObject = require("node:path");
48
48
  var external_node_path_default = /*#__PURE__*/ __webpack_require__.n(external_node_path_namespaceObject);
49
49
  const external_node_url_namespaceObject = require("node:url");
50
+ const cli_namespaceObject = require("@modern-js/plugin/cli");
50
51
  const core_namespaceObject = require("@rsbuild/core");
51
52
  const external_config_js_namespaceObject = require("./config.js");
53
+ const external_config_read_context_js_namespaceObject = require("./config-read-context.js");
54
+ const external_native_i18n_js_namespaceObject = require("./native-i18n.js");
55
+ const external_renderer_router_resolution_js_namespaceObject = require("./renderer-router-resolution.js");
52
56
  function inside(directory, file) {
53
57
  const relative = external_node_path_default().relative(directory, file);
54
58
  return '' !== relative && !relative.startsWith(`..${external_node_path_default().sep}`) && '..' !== relative && !external_node_path_default().isAbsolute(relative);
@@ -115,11 +119,76 @@ async function readUltramodernConfigMetadata(options) {
115
119
  appDirectory,
116
120
  configFile: options.configFile,
117
121
  env: options.env,
118
- command: options.command
122
+ command: options.analyzeServerRoutes ? 'metadata' : options.command
119
123
  });
124
+ const installedAppDirectory = options.stagedWorkspace && (appDirectory === external_node_path_default().resolve(options.stagedWorkspace.root) || inside(external_node_path_default().resolve(options.stagedWorkspace.root), appDirectory)) ? external_node_path_default().resolve(options.stagedWorkspace.originalRoot, external_node_path_default().relative(options.stagedWorkspace.root, appDirectory)) : appDirectory;
125
+ if (options.analyzeServerRoutes) {
126
+ const previousArgv = process.env.MODERN_ARGV;
127
+ process.env.MODERN_ARGV = 'node modern metadata';
128
+ const cli = (0, cli_namespaceObject.createCli)();
129
+ let cleanup;
130
+ try {
131
+ return await (0, external_config_read_context_js_namespaceObject.withEntryMetadataRead)(async ()=>{
132
+ const { appContext } = await cli.init({
133
+ cwd: appDirectory,
134
+ configFile: false,
135
+ config: loaded.config,
136
+ command: 'metadata',
137
+ internalPlugins: [
138
+ {
139
+ name: '@modern-js/ultramodern-route-metadata-context',
140
+ setup (api) {
141
+ api.updateAppContext({
142
+ configFile: loaded.configFile
143
+ });
144
+ cleanup = ()=>api.getHooks().onBeforeExit.call();
145
+ }
146
+ }
147
+ ]
148
+ });
149
+ const context = appContext.pluginAPI.getAppContext();
150
+ const entrypoints = context.entrypoints ?? [];
151
+ if (!entrypoints.length) throw new Error('UltraModern analyzed configuration has no application entries');
152
+ const entryBasePaths = {};
153
+ for (const entry of entrypoints){
154
+ const prefixes = [
155
+ ...new Set((context.serverRoutes ?? []).filter((route)=>route.entryName === entry.entryName && !route.isApi).map((route)=>route.urlPath))
156
+ ];
157
+ if (1 !== prefixes.length || 'string' != typeof prefixes[0]) throw new Error(`Native Worker federation entry ${entry.entryName} requires exactly one analyzed public route prefix.`);
158
+ entryBasePaths[entry.entryName] = prefixes[0];
159
+ }
160
+ const entries = entrypoints.map(({ entryName, isMainEntry })=>({
161
+ entryName,
162
+ isMainEntry
163
+ }));
164
+ const primary = entries.find((entry)=>entry.isMainEntry) ?? entries[0];
165
+ const renderer = loaded.config.renderer;
166
+ const routerBindings = await (0, external_renderer_router_resolution_js_namespaceObject.resolveEntrypointRouterBindings)(renderer, entrypoints, context.plugins.map((plugin)=>plugin.name), void 0, installedAppDirectory);
167
+ const i18n = (0, external_native_i18n_js_namespaceObject.findNativeI18nConfig)(loaded.config.plugins ?? []);
168
+ return {
169
+ renderer,
170
+ entries,
171
+ primaryEntryName: primary.entryName,
172
+ routerBindings,
173
+ entryBasePaths,
174
+ ...i18n ? {
175
+ i18n
176
+ } : {}
177
+ };
178
+ });
179
+ } finally{
180
+ try {
181
+ await cleanup?.();
182
+ } finally{
183
+ cli.dispose();
184
+ if (void 0 === previousArgv) delete process.env.MODERN_ARGV;
185
+ else process.env.MODERN_ARGV = previousArgv;
186
+ }
187
+ }
188
+ }
120
189
  const resolution = await (0, external_config_js_namespaceObject.resolveUltramodernEntryIdentities)({
121
190
  appDirectory,
122
- installedAppDirectory: options.stagedWorkspace && (appDirectory === external_node_path_default().resolve(options.stagedWorkspace.root) || inside(external_node_path_default().resolve(options.stagedWorkspace.root), appDirectory)) ? external_node_path_default().resolve(options.stagedWorkspace.originalRoot, external_node_path_default().relative(options.stagedWorkspace.root, appDirectory)) : appDirectory,
191
+ installedAppDirectory,
123
192
  config: loaded.config,
124
193
  command: options.command,
125
194
  configFile: loaded.configFile
@@ -140,7 +209,7 @@ function workerFile() {
140
209
  if (parent === directory) throw new Error('Cannot find the UltraModern app tools package root');
141
210
  directory = parent;
142
211
  }
143
- return external_node_path_default().join(directory, 'dist/cjs/native-composition/config-metadata-worker.js');
212
+ return external_node_path_default().join(directory, 'dist/esm-node/native-composition/config-metadata-worker.mjs');
144
213
  }
145
214
  function loadUltramodernConfigMetadata(options) {
146
215
  const appDirectory = external_node_path_default().resolve(options.appDirectory);
@@ -150,7 +219,10 @@ function loadUltramodernConfigMetadata(options) {
150
219
  execArgv: [],
151
220
  env: {
152
221
  ...process.env,
153
- NODE_ENV: options.env
222
+ NODE_ENV: options.env,
223
+ ...options.analyzeServerRoutes ? {
224
+ MODERN_ARGV: 'node modern metadata'
225
+ } : {}
154
226
  },
155
227
  stdio: [
156
228
  'ignore',
@@ -83,7 +83,7 @@ function resolveRendererFederationCompatibility(renderer) {
83
83
  specifier: owners.package,
84
84
  filename: (0, external_node_module_namespaceObject.createRequire)(`${bootstrap.directory}/package.json`).resolve(owners.package)
85
85
  });
86
- const { protocolVersion, compiler, hydration, router } = metadata.profile;
86
+ const { protocolVersion, compiler, hydration, router } = (0, external_renderer_installed_profile_js_namespaceObject.projectInstalledFederationProfile)(metadata.profile, bootstrap);
87
87
  return (0, renderer_contract_namespaceObject.readRendererFederationCompatibility)({
88
88
  profile: {
89
89
  renderer,
@@ -56,6 +56,7 @@ const server_namespaceObject = require("@modern-js/renderer-core/server");
56
56
  const utils_namespaceObject = require("@modern-js/utils");
57
57
  const external_native_build_manifest_js_namespaceObject = require("./native-build-manifest.js");
58
58
  const external_native_federation_dev_assets_js_namespaceObject = require("./native-federation-dev-assets.js");
59
+ const external_native_federation_dev_public_path_js_namespaceObject = require("./native-federation-dev-public-path.js");
59
60
  const external_renderer_registration_js_namespaceObject = require("./renderer-registration.js");
60
61
  const allowsOrigin = (allowed, origin)=>Array.isArray(allowed) ? allowed.some((entry)=>allowsOrigin(entry, origin)) : allowed instanceof RegExp ? allowed.test(origin) : 'string' == typeof allowed ? allowed === origin : Boolean(allowed);
61
62
  async function applyDevServerHeaders(request, response, server) {
@@ -124,6 +125,15 @@ class NativeDevelopment {
124
125
  (0, identity_namespaceObject.assertRendererIdentity)(snapshot.manifest.rendererIdentity, identity);
125
126
  return snapshot;
126
127
  }
128
+ await this.waitForPublication(signal);
129
+ }
130
+ }
131
+ async waitForPublication(signal) {
132
+ for(;;){
133
+ signal.throwIfAborted();
134
+ if (this.closed) throw new Error('Native development compiler is closed');
135
+ if (this.failure) throw this.failure.error;
136
+ if (this.ready) return;
127
137
  await new Promise((resolve, reject)=>{
128
138
  const resumed = ()=>{
129
139
  signal.removeEventListener('abort', aborted);
@@ -150,11 +160,26 @@ class NativeDevelopment {
150
160
  if (!client?.compilation.hash || !server?.compilation.hash || !serverRoot) throw new Error('Native development requires completed client and server compilations');
151
161
  const session = this.options.getSessionIdentities();
152
162
  const entryNames = Object.keys(session.identities);
153
- const federationAssets = await (0, external_native_federation_dev_assets_js_namespaceObject.collectNativeFederationDevAssets)(server, entryNames, (name)=>emittedBytes(server, name));
163
+ const federationAssets = new Map([
164
+ ...await (0, external_native_federation_dev_assets_js_namespaceObject.collectNativeFederationDevAssets)(server, entryNames, (name)=>emittedBytes(server, name)),
165
+ ...await (0, external_native_federation_dev_assets_js_namespaceObject.collectNativeFederationDevAssets)(client, entryNames, (name)=>emittedBytes(client, name))
166
+ ]);
167
+ const federationGraph = (0, external_native_federation_dev_assets_js_namespaceObject.nativeFederationDevGraph)(client);
168
+ const federationRevision = federationAssets.size ? (0, external_native_federation_dev_assets_js_namespaceObject.nativeFederationDevRevision)(federationAssets) : void 0;
169
+ const retainedFederationAssets = (0, external_native_federation_dev_assets_js_namespaceObject.retainNativeFederationDevAssets)(this.retainedFederationAssets, new Map([
170
+ ...federationAssets
171
+ ].map(([url, asset])=>[
172
+ url,
173
+ {
174
+ ...asset,
175
+ revision: federationRevision,
176
+ graphManifest: federationGraph?.immutableManifest
177
+ }
178
+ ])));
154
179
  const publicPath = client.compilation.outputOptions.publicPath;
155
180
  const prefix = 'string' == typeof publicPath && 'auto' !== publicPath ? publicPath.endsWith('/') ? publicPath : `${publicPath}/` : '/';
156
181
  for (const asset of client.compilation.getAssets()){
157
- if (asset.info.hotModuleReplacement || this.mutableClientAssets.has(asset.name) || this.compilerArtifacts.isMutableDevelopmentAsset(asset.name, entryNames)) continue;
182
+ if (true !== asset.info.immutable || asset.info.hotModuleReplacement || this.mutableClientAssets.has(asset.name) || this.compilerArtifacts.isMutableDevelopmentAsset(asset.name, entryNames)) continue;
158
183
  const pathname = new URL(`${prefix}${asset.name}`, 'http://native-dev.invalid').pathname;
159
184
  if (!this.retained.has(pathname)) this.retained.set(pathname, {
160
185
  bytes: await emittedBytes(client, asset.name),
@@ -218,7 +243,10 @@ class NativeDevelopment {
218
243
  await promises_default().rename(temporary, manifestFile);
219
244
  return {
220
245
  entries,
221
- federationAssets
246
+ federationAssets,
247
+ federationGraph,
248
+ federationRevision,
249
+ retainedFederationAssets
222
250
  };
223
251
  }
224
252
  async close() {
@@ -226,8 +254,13 @@ class NativeDevelopment {
226
254
  this.closed = true;
227
255
  this.ready = void 0;
228
256
  this.notify();
257
+ await this.publication.catch(()=>{});
229
258
  this.retained.clear();
230
259
  this.federationAssets = new Map();
260
+ this.federationRevision = void 0;
261
+ this.federationGraph = void 0;
262
+ this.federationCompilers.clear();
263
+ this.retainedFederationAssets = new Map();
231
264
  if (this.manifestFile) await promises_default().rm(this.manifestFile, {
232
265
  force: true
233
266
  });
@@ -238,9 +271,12 @@ class NativeDevelopment {
238
271
  this.compilerVersions = new WeakMap();
239
272
  this.compilationVersions = new WeakMap();
240
273
  this.generation = 0;
274
+ this.publication = Promise.resolve();
241
275
  this.closed = false;
242
276
  this.retained = new Map();
243
277
  this.federationAssets = new Map();
278
+ this.federationCompilers = new Set();
279
+ this.retainedFederationAssets = new Map();
244
280
  this.mutableClientAssets = new Set([
245
281
  'renderer-assets.json'
246
282
  ]);
@@ -279,16 +315,73 @@ class NativeDevelopment {
279
315
  config.mode = 'development';
280
316
  const previous = config.dev?.setupMiddlewares;
281
317
  const retain = (middlewares)=>{
282
- middlewares.unshift((request, response, next)=>{
318
+ const owner = this;
319
+ middlewares.unshift(function serve(request, response, next) {
320
+ if (owner.closed) return next();
283
321
  if ('GET' !== request.method && 'HEAD' !== request.method) return next();
284
322
  const pathname = URL.parse(request.url ?? '/', 'http://native-dev.invalid')?.pathname;
285
323
  const protocol = request.socket instanceof external_node_tls_namespaceObject.TLSSocket ? 'https:' : 'http:';
286
- const asset = (0, external_native_federation_dev_assets_js_namespaceObject.resolveNativeFederationDevAsset)(this.federationAssets, request.url ?? '/', `${protocol}//${request.headers.host}`) || pathname && this.retained.get(pathname);
287
- if (!asset) return next();
324
+ const origin = `${protocol}//${request.headers.host}`;
325
+ const afterPublication = (resume)=>{
326
+ const pending = new AbortController();
327
+ const aborted = ()=>pending.abort(new Error('Native graph request closed'));
328
+ request.once('aborted', aborted);
329
+ response.once('close', aborted);
330
+ if (request.aborted || response.destroyed) aborted();
331
+ const cleanup = ()=>{
332
+ request.removeListener('aborted', aborted);
333
+ response.removeListener('close', aborted);
334
+ };
335
+ owner.waitForPublication(pending.signal).then(()=>{
336
+ cleanup();
337
+ if (!pending.signal.aborted) resume();
338
+ }, (error)=>{
339
+ cleanup();
340
+ if (!pending.signal.aborted) next(error);
341
+ });
342
+ };
343
+ if (!owner.federationGraph && [
344
+ ...owner.federationCompilers
345
+ ].some((compiler)=>{
346
+ const manifest = (0, external_native_federation_dev_assets_js_namespaceObject.nativeFederationDevManifest)(compiler);
347
+ return manifest && URL.parse(manifest)?.pathname === pathname;
348
+ })) return void afterPublication(()=>{
349
+ if (!owner.federationGraph) return next(new Error('Native browser manifest was not published'));
350
+ serve(request, response, next);
351
+ });
352
+ const hotUpdate = owner.federationGraph && (0, external_native_federation_dev_public_path_js_namespaceObject.nativeFederationDevHotUpdateTarget)(owner.federationGraph.publicPath, request.url ?? '/', origin);
353
+ if (hotUpdate) {
354
+ request.url = hotUpdate;
355
+ return next();
356
+ }
357
+ const federationAsset = (0, external_native_federation_dev_assets_js_namespaceObject.resolveNativeFederationDevAsset)(owner.federationAssets, request.url ?? '/', origin) ?? (owner.federationGraph && (0, external_native_federation_dev_assets_js_namespaceObject.resolveNativeFederationDevManifest)(owner.federationAssets, request.url ?? '/', owner.federationGraph.manifest));
358
+ const revision = owner.federationRevision;
359
+ const asset = federationAsset || pathname && owner.retained.get(pathname);
360
+ if (!asset) {
361
+ if (owner.federationGraph && !owner.ready && !owner.failure && (0, external_native_federation_dev_public_path_js_namespaceObject.isNativeFederationDevGraphAsset)(owner.federationGraph.publicPath, request.url ?? '/', origin)) return void afterPublication(()=>serve(request, response, next));
362
+ return next();
363
+ }
288
364
  applyDevServerHeaders(request, response, api.getNormalizedConfig().server).then(()=>{
289
365
  response.setHeader('Content-Type', asset.contentType);
290
366
  response.setHeader('Content-Length', asset.bytes.length);
291
- response.setHeader('Cache-Control', 'no-store');
367
+ response.setHeader('Cache-Control', asset.immutable ? 'public, max-age=31536000, immutable' : 'no-store');
368
+ if (federationAsset) {
369
+ const graphManifest = asset.graphManifest ?? owner.federationGraph?.immutableManifest;
370
+ if (graphManifest) response.setHeader('Link', `<${graphManifest}>; rel="ultramodern-completed-graph"`);
371
+ const graphRevision = asset.revision ?? revision;
372
+ if (graphRevision) response.setHeader(external_native_federation_dev_assets_js_namespaceObject.NATIVE_FEDERATION_DEV_REVISION_HEADER, graphRevision);
373
+ if (api.getNormalizedConfig().server.cors) {
374
+ const previous = response.getHeader('Access-Control-Expose-Headers');
375
+ const exposed = new Set([
376
+ ...Array.isArray(previous) ? previous : String(previous ?? '').split(','),
377
+ 'Link',
378
+ external_native_federation_dev_assets_js_namespaceObject.NATIVE_FEDERATION_DEV_REVISION_HEADER
379
+ ].map((value)=>value.trim()).filter(Boolean));
380
+ response.setHeader('Access-Control-Expose-Headers', [
381
+ ...exposed
382
+ ].join(','));
383
+ }
384
+ }
292
385
  response.end('HEAD' === request.method ? void 0 : asset.bytes);
293
386
  }, next);
294
387
  });
@@ -309,6 +402,7 @@ class NativeDevelopment {
309
402
  compiler
310
403
  ];
311
404
  for (const candidate of compilers){
405
+ this.federationCompilers.add(candidate);
312
406
  this.compilerVersions.set(candidate, 0);
313
407
  let runVersion = 0;
314
408
  const captureRun = ()=>{
@@ -330,28 +424,39 @@ class NativeDevelopment {
330
424
  candidate.hooks.failed.tap('UltraModernNativeDevelopment', (error)=>this.fail(error));
331
425
  }
332
426
  });
333
- api.onDevCompileDone(async ({ stats })=>{
427
+ api.onDevCompileDone(({ stats })=>{
334
428
  const epoch = this.epoch;
335
- const results = 'stats' in stats ? stats.stats : [
336
- stats
337
- ];
338
- if (this.closed || results.some((result)=>{
339
- const version = this.compilationVersions.get(result.compilation);
340
- return void 0 === version || version !== this.compilerVersions.get(result.compilation.compiler);
341
- })) return;
342
- if (stats.hasErrors()) return this.fail(new Error('Native development compilation failed'));
343
- try {
344
- const publication = await this.publish(stats);
345
- if (this.closed || epoch !== this.epoch) return;
346
- this.federationAssets = publication.federationAssets;
347
- this.ready = publication.entries;
348
- this.failure = void 0;
349
- this.notify();
350
- } catch (error) {
429
+ const publishNext = async ()=>{
351
430
  if (this.closed || epoch !== this.epoch) return;
352
- this.fail(error);
353
- api.logger.error('Native development could not load the compiled application.', error);
354
- }
431
+ const results = 'stats' in stats ? stats.stats : [
432
+ stats
433
+ ];
434
+ if (results.some((result)=>{
435
+ const version = this.compilationVersions.get(result.compilation);
436
+ return void 0 === version || version !== this.compilerVersions.get(result.compilation.compiler);
437
+ })) return;
438
+ if (stats.hasErrors()) return this.fail(new Error('Native development compilation failed'));
439
+ try {
440
+ const publication = await this.publish(stats);
441
+ if (this.closed || epoch !== this.epoch) return;
442
+ this.retainedFederationAssets = publication.retainedFederationAssets;
443
+ this.federationAssets = new Map([
444
+ ...publication.federationAssets,
445
+ ...this.retainedFederationAssets
446
+ ]);
447
+ this.federationRevision = publication.federationRevision;
448
+ this.federationGraph = publication.federationGraph;
449
+ this.ready = publication.entries;
450
+ this.failure = void 0;
451
+ this.notify();
452
+ } catch (error) {
453
+ if (this.closed || epoch !== this.epoch) return;
454
+ this.fail(error);
455
+ api.logger.error('Native development could not load the compiled application.', error);
456
+ }
457
+ };
458
+ this.publication = this.publication.then(publishNext, publishNext);
459
+ return this.publication;
355
460
  });
356
461
  api.onCloseDevServer(()=>this.close());
357
462
  }
@@ -51,6 +51,8 @@ const external_native_federation_files_js_namespaceObject = require("./native-fe
51
51
  const external_native_i18n_js_namespaceObject = require("./native-i18n.js");
52
52
  const external_native_module_federation_js_namespaceObject = require("./native-module-federation.js");
53
53
  const external_native_routes_js_namespaceObject = require("./native-routes.js");
54
+ const external_native_worker_js_namespaceObject = require("./native-worker.js");
55
+ const external_native_worker_federation_js_namespaceObject = require("./native-worker-federation.js");
54
56
  const external_renderer_registration_js_namespaceObject = require("./renderer-registration.js");
55
57
  const entryRoutes = new WeakMap();
56
58
  function resolveNativeEntryIdentity(context, renderer) {
@@ -88,13 +90,18 @@ async function emitNativeEntryApplication(context, mode) {
88
90
  entryRoutes.set(context, discovery);
89
91
  }
90
92
  const routes = await discovery;
93
+ const sourceRequests = await (0, external_native_routes_js_namespaceObject.resolveNativeApplicationSourceRequests)(routes, context.profile.sourceExtensions, 'server' === mode ? 'node' : mode);
91
94
  if (context.i18n) (0, external_native_i18n_js_namespaceObject.validateNativeLocalisedUrls)(context.i18n, routes);
92
95
  sources[`app.${mode}.ts`] = (0, external_native_routes_js_namespaceObject.emitNativeApplicationModule)({
93
96
  routes,
94
- mode,
95
- basePath: context.basePath
97
+ mode: 'client' === mode ? 'client' : 'server',
98
+ basePath: context.basePath,
99
+ sourceRequests
96
100
  });
97
- } else sources[`app.${mode}.ts`] = `export { default } from ${JSON.stringify(source)};\n`;
101
+ } else {
102
+ const sourceRequest = await (0, external_native_routes_js_namespaceObject.resolveNativeApplicationSourceRequest)(source, context.profile.sourceExtensions, 'server' === mode ? 'node' : mode);
103
+ sources[`app.${mode}.ts`] = `export { default } from ${JSON.stringify(sourceRequest)};\n`;
104
+ }
98
105
  await writeNativeEntryModules(directory, sources);
99
106
  return {
100
107
  routed,
@@ -105,11 +112,36 @@ const NATIVE_APPLICATION_CLIENT_REQUEST = './app.client';
105
112
  function createNativeEntryStubGenerator(adapter) {
106
113
  const renderer = adapter.name;
107
114
  const extra = adapter.entryClient;
115
+ const serverSource = async (context, worker = false)=>{
116
+ const identity = resolveNativeEntryIdentity(context, renderer);
117
+ const { directory, routed } = await emitNativeEntryApplication(context, worker ? 'worker' : 'server');
118
+ const federated = Boolean(!worker && (0, external_native_federation_files_js_namespaceObject.findNativeFederationConfig)(context.appDirectory));
119
+ const server = `import { createNativeServerEntry } from ${JSON.stringify(adapter.runtime.entryServer)};
120
+ ${worker && !context.workerFederation?.plan ? workerContextStartup(context, routed) : ''}${context.i18n ? 'import { i18n } from "./i18n";\n' : ''}${federated ? nativeFederationDeclaration : ''}
121
+ export const { ${nativeServerHandlers.join(', ')} } = createNativeServerEntry({
122
+ identity: ${JSON.stringify(identity)},
123
+ app: () => import("./app.${worker ? 'worker' : 'server'}"),${worker && context.workerFederation ? `\n workerFederationLocale: ${JSON.stringify(context.i18n?.fallbackLanguage ?? 'default')},` : ''}${federated ? `\n federation: ${nativeServerFederationBinding},` : ''}${context.i18n ? '\n i18n,' : ''}
124
+ });
125
+ `;
126
+ if (!federated) return {
127
+ source: server,
128
+ directory,
129
+ routed
130
+ };
131
+ await writeNativeEntryModules(directory, {
132
+ 'handlers.server.ts': server
133
+ });
134
+ return {
135
+ source: federatedServerSource(identity),
136
+ directory,
137
+ routed
138
+ };
139
+ };
108
140
  return {
109
141
  async client (context) {
110
142
  const identity = resolveNativeEntryIdentity(context, renderer);
111
143
  const federated = Boolean((0, external_native_federation_files_js_namespaceObject.findNativeFederationConfig)(context.appDirectory));
112
- await emitNativeEntryApplication(context, 'client');
144
+ const { routed } = await emitNativeEntryApplication(context, 'client');
113
145
  const fields = {
114
146
  identity: JSON.stringify(identity),
115
147
  load: `() => import(${JSON.stringify(NATIVE_APPLICATION_CLIENT_REQUEST)})`,
@@ -120,34 +152,47 @@ function createNativeEntryStubGenerator(adapter) {
120
152
  ...federated ? {
121
153
  federation: nativeFederationBinding
122
154
  } : {},
155
+ ...context.workerFederation ? {
156
+ workerFederation: 'workerFederation'
157
+ } : {},
123
158
  ...extra?.fields
124
159
  };
125
160
  return `import { startNativeClient } from ${JSON.stringify(adapter.runtime.entryClient)};
126
- ${context.i18n ? 'import { i18n } from "./i18n";\n' : ''}${extra?.declarations ?? ''}${federated ? nativeFederationDeclaration : ''}
161
+ ${workerContextStartup(context, routed)}${context.workerFederation ? nativeWorkerClientTransportSource(context) : ''}${context.i18n ? 'import { i18n } from "./i18n";\n' : ''}${extra?.declarations ?? ''}${federated ? nativeFederationDeclaration : ''}
127
162
  startNativeClient({
128
163
  ${Object.entries(fields).map(([name, value])=>` ${name === value ? name : `${name}: ${value}`},`).join('\n')}
129
164
  });
130
165
  `;
131
166
  },
132
- async server (context) {
133
- const identity = resolveNativeEntryIdentity(context, renderer);
134
- const { directory } = await emitNativeEntryApplication(context, 'server');
135
- const federated = Boolean((0, external_native_federation_files_js_namespaceObject.findNativeFederationConfig)(context.appDirectory));
136
- const server = `import { createNativeServerEntry } from ${JSON.stringify(adapter.runtime.entryServer)};
137
- ${context.i18n ? 'import { i18n } from "./i18n";\n' : ''}${federated ? nativeFederationDeclaration : ''}
138
- export const { ${nativeServerHandlers.join(', ')} } = createNativeServerEntry({
139
- identity: ${JSON.stringify(identity)},
140
- app: () => import("./app.server"),${federated ? `\n federation: ${nativeServerFederationBinding},` : ''}${context.i18n ? '\n i18n,' : ''}
141
- });
142
- `;
143
- if (!federated) return server;
167
+ server: async (context)=>(await serverSource(context)).source,
168
+ async worker (context) {
169
+ const { source, directory, routed } = await serverSource(context, true);
170
+ const federation = context.workerFederation;
144
171
  await writeNativeEntryModules(directory, {
145
- 'handlers.server.ts': server
172
+ 'handlers.worker.ts': source,
173
+ ...federation?.plan ? {
174
+ 'federation.worker.ts': (0, external_native_worker_federation_js_namespaceObject.nativeWorkerFederationRegistrySource)(federation.plan, workerContextOptions(context, routed))
175
+ } : {}
146
176
  });
147
- return federatedServerSource(identity);
177
+ return (0, external_native_worker_js_namespaceObject.nativeWorkerEntrySource)('./handlers.worker', federation ? {
178
+ runtime: adapter.runtime.entryServer,
179
+ compatibility: federation.compatibility,
180
+ registry: federation.plan ? './federation.worker' : void 0
181
+ } : void 0);
148
182
  }
149
183
  };
150
184
  }
185
+ function workerContextOptions(context, routed) {
186
+ return 'octane' === context.renderer && context.workerFederation ? {
187
+ router: routed,
188
+ i18n: Boolean(context.i18n),
189
+ contextProfiles: context.workerFederation.contextProfiles
190
+ } : {};
191
+ }
192
+ function workerContextStartup(context, routed) {
193
+ const source = (0, external_native_worker_federation_js_namespaceObject.nativeWorkerContextStartupSource)(workerContextOptions(context, routed));
194
+ return source ? `${source}\n` : '';
195
+ }
151
196
  const nativeFederationBinding = '{ instance: () => __webpack_require__.federation.instance }';
152
197
  const nativeServerFederationBinding = `{ instance: () => __webpack_require__.federation.instance, hydrationModule: ${JSON.stringify(external_native_module_federation_js_namespaceObject.NATIVE_FEDERATION_HYDRATION_MODULE)} }`;
153
198
  const nativeFederationDeclaration = 'declare const __webpack_require__: { federation: { instance: import("@modern-js/renderer-core/federation").FederationInstance } };\n';
@@ -169,6 +214,26 @@ ${nativeServerHandlers.slice(1).map((name)=>`export async function ${name}(reque
169
214
  function createNativeEntryGenerator(renderer) {
170
215
  return createNativeEntryStubGenerator((0, external_renderer_registration_js_namespaceObject.resolveNativeRendererAdapter)(renderer));
171
216
  }
217
+ function nativeWorkerClientTransportSource(context) {
218
+ const federation = context.workerFederation;
219
+ return `import { createWorkerFederationTransport } from '@modern-js/renderer-core/worker-federation';
220
+ import { assertRendererFederationCompatibility, readRendererFederationContract } from '@modern-js/federation-runtime/renderer-contract';
221
+ const expectedWorkerRenderer = ${JSON.stringify(federation.compatibility)};
222
+ const workerFederation = signal => ({
223
+ locale: ${JSON.stringify(context.i18n?.fallbackLanguage ?? 'default')},
224
+ signal,
225
+ transport: createWorkerFederationTransport({
226
+ signal,
227
+ services: ${JSON.stringify(federation.services)}.map(service => ({...service, fetch: request => globalThis.fetch(request)})),
228
+ admitRendererContract(value) {
229
+ const contract = readRendererFederationContract(value);
230
+ assertRendererFederationCompatibility(expectedWorkerRenderer, contract);
231
+ return contract;
232
+ },
233
+ }),
234
+ });
235
+ `;
236
+ }
172
237
  exports.NATIVE_APPLICATION_CLIENT_REQUEST = __webpack_exports__.NATIVE_APPLICATION_CLIENT_REQUEST;
173
238
  exports.createNativeEntryGenerator = __webpack_exports__.createNativeEntryGenerator;
174
239
  exports.createNativeEntryStubGenerator = __webpack_exports__.createNativeEntryStubGenerator;