diff --git a/e2e/node/src/node-server.test.ts b/e2e/node/src/node-server.test.ts index 25c18b45bc..1ea42f516a 100644 --- a/e2e/node/src/node-server.test.ts +++ b/e2e/node/src/node-server.test.ts @@ -9,6 +9,7 @@ import { runCLI, runCommandUntil, uniq, + updateProjectConfig, updateFile, } from '@nx/e2e/utils'; @@ -140,4 +141,24 @@ describe('Node Applications + webpack', () => { checkFilesExist(`apps/${expressApp}/Dockerfile`); }, 300_000); + + it('should support waitUntilTargets for serve target', async () => { + const nodeApp1 = uniq('nodeapp1'); + const nodeApp2 = uniq('nodeapp2'); + runCLI( + `generate @nx/node:app ${nodeApp1} --framework=none --no-interactive` + ); + runCLI( + `generate @nx/node:app ${nodeApp2} --framework=none --no-interactive` + ); + updateProjectConfig(nodeApp1, (config) => { + config.targets.serve.options.waitUntilTargets = [`${nodeApp2}:build`]; + return config; + }); + + runCLI(`serve ${nodeApp1} --watch=false`); + + checkFilesExist(`dist/apps/${nodeApp1}/main.js`); + checkFilesExist(`dist/apps/${nodeApp2}/main.js`); + }, 300_000); }); diff --git a/packages/js/src/executors/node/node.impl.ts b/packages/js/src/executors/node/node.impl.ts index 0e883e09c8..a186f14917 100644 --- a/packages/js/src/executors/node/node.impl.ts +++ b/packages/js/src/executors/node/node.impl.ts @@ -5,6 +5,7 @@ import { joinPathFragments, logger, parseTargetString, + runExecutor, } from '@nx/devkit'; import { daemonClient } from 'nx/src/daemon/client/client'; import { randomUUID } from 'crypto'; @@ -57,6 +58,17 @@ export async function* nodeExecutor( ); } + if (options.waitUntilTargets && options.waitUntilTargets.length > 0) { + const results = await runWaitUntilTargets(options, context); + for (const [i, result] of results.entries()) { + if (!result.success) { + throw new Error( + `Wait until target failed: ${options.waitUntilTargets[i]}.` + ); + } + } + } + // Re-map buildable workspace projects to their output directory. const mappings = calculateResolveMappings(context, options); const fileToRun = join( @@ -270,5 +282,26 @@ function calculateResolveMappings( return m; }, {}); } +function runWaitUntilTargets( + options: NodeExecutorOptions, + context: ExecutorContext +): Promise<{ success: boolean }[]> { + return Promise.all( + options.waitUntilTargets.map(async (waitUntilTarget) => { + const target = parseTargetString(waitUntilTarget, context.projectGraph); + const output = await runExecutor(target, {}, context); + return new Promise<{ success: boolean }>(async (resolve) => { + let event = await output.next(); + // Resolve after first event + resolve(event.value as { success: boolean }); + + // Continue iterating + while (!event.done) { + event = await output.next(); + } + }); + }) + ); +} export default nodeExecutor;