From 09b94b923ca1456456c4120012f6e6d2af9b0433 Mon Sep 17 00:00:00 2001 From: Colum Ferry Date: Fri, 5 Apr 2024 11:21:54 +0100 Subject: [PATCH] fix(angular): serve dynamic remotes statically in their own processes --- .../lib/start-dev-remotes.ts | 33 +++++++++---------- .../module-federation-dev-server.impl.ts | 18 +++++++--- .../module-federation/get-remotes-for-host.ts | 28 ++++++++++++---- 3 files changed, 50 insertions(+), 29 deletions(-) diff --git a/packages/angular/src/executors/module-federation-dev-server/lib/start-dev-remotes.ts b/packages/angular/src/executors/module-federation-dev-server/lib/start-dev-remotes.ts index 1cacd71014892..3bda86f5ee58b 100644 --- a/packages/angular/src/executors/module-federation-dev-server/lib/start-dev-remotes.ts +++ b/packages/angular/src/executors/module-federation-dev-server/lib/start-dev-remotes.ts @@ -5,41 +5,38 @@ import { runExecutor, } from '@nx/devkit'; -export async function startDevRemotes( - remotes: { - remotePorts: any[]; - staticRemotes: string[]; - devRemotes: string[]; - }, +export async function startRemotes( + remotes: string[], workspaceProjects: Record, options: Schema, - context: ExecutorContext + context: ExecutorContext, + target: 'serve' | 'serve-static' = 'serve' ) { - const devRemotesIters: AsyncIterable<{ success: boolean }>[] = []; - for (const app of remotes.devRemotes) { - if (!workspaceProjects[app].targets?.['serve']) { - throw new Error(`Could not find "serve" target in "${app}" project.`); - } else if (!workspaceProjects[app].targets?.['serve'].executor) { + const remoteIters: AsyncIterable<{ success: boolean }>[] = []; + for (const app of remotes) { + if (!workspaceProjects[app].targets?.[target]) { + throw new Error(`Could not find "${target}" target in "${app}" project.`); + } else if (!workspaceProjects[app].targets?.[target].executor) { throw new Error( - `Could not find executor for "serve" target in "${app}" project.` + `Could not find executor for "${target}" target in "${app}" project.` ); } const [collection, executor] = - workspaceProjects[app].targets['serve'].executor.split(':'); + workspaceProjects[app].targets[target].executor.split(':'); const isUsingModuleFederationDevServerExecutor = executor.includes( 'module-federation-dev-server' ); - devRemotesIters.push( + remoteIters.push( await runExecutor( { project: app, - target: 'serve', + target, configuration: context.configurationName, }, { - verbose: options.verbose ?? false, + ...(target === 'serve' ? { verbose: options.verbose ?? false } : {}), ...(isUsingModuleFederationDevServerExecutor ? { isInitialHost: false } : {}), @@ -48,5 +45,5 @@ export async function startDevRemotes( ) ); } - return devRemotesIters; + return remoteIters; } diff --git a/packages/angular/src/executors/module-federation-dev-server/module-federation-dev-server.impl.ts b/packages/angular/src/executors/module-federation-dev-server/module-federation-dev-server.impl.ts index 3e2e6fc466cb5..bd9af8c9336cc 100644 --- a/packages/angular/src/executors/module-federation-dev-server/module-federation-dev-server.impl.ts +++ b/packages/angular/src/executors/module-federation-dev-server/module-federation-dev-server.impl.ts @@ -8,7 +8,7 @@ import { buildStaticRemotes, normalizeOptions, parseStaticRemotesConfig, - startDevRemotes, + startRemotes, startStaticRemotesFileServer, } from './lib'; import { eachValueFrom } from '@nx/devkit/src/utils/rxjs-for-await'; @@ -138,11 +138,20 @@ export async function* moduleFederationDevServerExecutor( ); await buildStaticRemotes(staticRemotesConfig, nxBin, context, options); - const devRemoteIters = await startDevRemotes( - remotes, + const devRemoteIters = await startRemotes( + remotes.devRemotes, workspaceProjects, options, - context + context, + 'serve' + ); + + const dynamicRemoteIters = await startRemotes( + remotes.dynamicRemotes, + workspaceProjects, + options, + context, + 'serve-static' ); const staticRemotesIter = @@ -159,6 +168,7 @@ export async function* moduleFederationDevServerExecutor( return yield* combineAsyncIterables( removeBaseUrlEmission(currIter), ...devRemoteIters.map(removeBaseUrlEmission), + ...dynamicRemoteIters.map(removeBaseUrlEmission), ...(staticRemotesIter ? [removeBaseUrlEmission(staticRemotesIter)] : []), createAsyncIterable<{ success: true; baseUrl: string }>( async ({ next, done }) => { diff --git a/packages/webpack/src/utils/module-federation/get-remotes-for-host.ts b/packages/webpack/src/utils/module-federation/get-remotes-for-host.ts index 79888303d4d8c..2b84a32a7df7b 100644 --- a/packages/webpack/src/utils/module-federation/get-remotes-for-host.ts +++ b/packages/webpack/src/utils/module-federation/get-remotes-for-host.ts @@ -17,6 +17,7 @@ function extractRemoteProjectsFromConfig( pathToManifestFile?: string ) { const remotes = []; + const dynamicRemotes = []; if (pathToManifestFile && existsSync(pathToManifestFile)) { const moduleFederationManifestJson = readFileSync( pathToManifestFile, @@ -35,14 +36,14 @@ function extractRemoteProjectsFromConfig( typeof key === 'string' && typeof parsedManifest[key] === 'string' ) ) { - remotes.push(...Object.keys(parsedManifest)); + dynamicRemotes.push(...Object.keys(parsedManifest)); } } } const staticRemotes = config.remotes?.map((r) => (Array.isArray(r) ? r[0] : r)) ?? []; remotes.push(...staticRemotes); - return remotes; + return { remotes, dynamicRemotes }; } function collectRemoteProjects( @@ -64,7 +65,7 @@ function collectRemoteProjects( context.root, remoteProjectRoot ); - const remoteProjectRemotes = + const { remotes: remoteProjectRemotes } = extractRemoteProjectsFromConfig(remoteProjectConfig); remoteProjectRemotes.forEach((r) => @@ -80,7 +81,10 @@ export function getRemotes( pathToManifestFile?: string ) { const collectedRemotes = new Set(); - const remotes = extractRemoteProjectsFromConfig(config, pathToManifestFile); + const { remotes, dynamicRemotes } = extractRemoteProjectsFromConfig( + config, + pathToManifestFile + ); remotes.forEach((r) => collectRemoteProjects(r, collectedRemotes, context)); const remotesToSkip = new Set( findMatchingProjects(skipRemotes, context.projectGraph.nodes) ?? [] @@ -98,10 +102,14 @@ export function getRemotes( (r) => !remotesToSkip.has(r) ); + const knownDynamicRemotes = dynamicRemotes.filter( + (r) => !remotesToSkip.has(r) + ); + logger.info( `NX Starting module federation dev-server for ${chalk.bold( context.projectName - )} with ${knownRemotes.length} remotes` + )} with ${[...knownRemotes, ...knownDynamicRemotes].length} remotes` ); const devServeApps = new Set( @@ -113,14 +121,20 @@ export function getRemotes( ); const staticRemotes = knownRemotes.filter((r) => !devServeApps.has(r)); - const devServeRemotes = knownRemotes.filter((r) => devServeApps.has(r)); - const remotePorts = devServeRemotes.map( + const devServeRemotes = [...knownRemotes, ...dynamicRemotes].filter((r) => + devServeApps.has(r) + ); + const staticDynamicRemotes = knownDynamicRemotes.filter( + (r) => !devServeApps.has(r) + ); + const remotePorts = [...devServeRemotes, ...staticDynamicRemotes].map( (r) => context.projectGraph.nodes[r].data.targets['serve'].options.port ); return { staticRemotes, devRemotes: devServeRemotes, + dynamicRemotes: staticDynamicRemotes, remotePorts, }; }