From ef6a0e448a083d70b60995302a729537d4296e3c Mon Sep 17 00:00:00 2001 From: Colum Ferry Date: Fri, 29 Nov 2024 16:51:43 +0000 Subject: [PATCH 1/3] fix(core): use fork to execute nx generate workspace:preset --- .../src/generators/new/generate-preset.ts | 34 ++++++++++++------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/packages/workspace/src/generators/new/generate-preset.ts b/packages/workspace/src/generators/new/generate-preset.ts index 6824da637cc09..cb18fc145f96e 100644 --- a/packages/workspace/src/generators/new/generate-preset.ts +++ b/packages/workspace/src/generators/new/generate-preset.ts @@ -13,7 +13,7 @@ import { getNpmPackageVersion } from '../utils/get-npm-package-version'; import { NormalizedSchema } from './new'; import { join } from 'path'; import * as yargsParser from 'yargs-parser'; -import { spawn, SpawnOptions } from 'child_process'; +import { fork, ForkOptions } from 'child_process'; export function addPresetDependencies(host: Tree, options: NormalizedSchema) { const { dependencies, dev } = getPresetDependencies(options); @@ -32,25 +32,33 @@ export function generatePreset(host: Tree, opts: NormalizedSchema) { interactive: true, }, }); - const spawnOptions: SpawnOptions = { + + const newWorkspaceRoot = join(host.root, opts.directory); + const spawnOptions: ForkOptions = { stdio: 'inherit', - shell: true, - cwd: join(host.root, opts.directory), - windowsHide: false, + cwd: newWorkspaceRoot, }; const pmc = getPackageManagerCommand(); - const executable = `${pmc.exec} nx`; + const nxBinForNewWorkspaceRoot = require.resolve('nx/bin/nx', { + paths: [join(newWorkspaceRoot, 'node_modules')], + }); const args = getPresetArgs(opts); return new Promise((resolve, reject) => { - spawn(executable, args, spawnOptions).on('close', (code: number) => { - if (code === 0) { - resolve(); - } else { - const message = 'Workspace creation failed, see above.'; - reject(new Error(message)); + // This needs to be `fork` instead of `spawn` because `spawn` is failing on Windows with pnpm + yarn + // The root cause is unclear. Spawn causes the `@nx/workspace:preset` generator to be called twice + // and the second time it fails with `Project {projectName} already exists.` + fork(nxBinForNewWorkspaceRoot, args, spawnOptions).on( + 'close', + (code: number) => { + if (code === 0) { + resolve(); + } else { + const message = 'Workspace creation failed, see above.'; + reject(new Error(message)); + } } - }); + ); }); function getPresetArgs(options: NormalizedSchema) { From ac25f687880f69f7a02937b14484a46cd3faa9ea Mon Sep 17 00:00:00 2001 From: Colum Ferry Date: Mon, 2 Dec 2024 15:09:35 +0000 Subject: [PATCH 2/3] fix(core): rename spawnOptions to forkOptions to reflect method for creating process --- packages/workspace/src/generators/new/generate-preset.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/workspace/src/generators/new/generate-preset.ts b/packages/workspace/src/generators/new/generate-preset.ts index cb18fc145f96e..f69cd2b577c49 100644 --- a/packages/workspace/src/generators/new/generate-preset.ts +++ b/packages/workspace/src/generators/new/generate-preset.ts @@ -34,7 +34,7 @@ export function generatePreset(host: Tree, opts: NormalizedSchema) { }); const newWorkspaceRoot = join(host.root, opts.directory); - const spawnOptions: ForkOptions = { + const forkOptions: ForkOptions = { stdio: 'inherit', cwd: newWorkspaceRoot, }; @@ -48,7 +48,7 @@ export function generatePreset(host: Tree, opts: NormalizedSchema) { // This needs to be `fork` instead of `spawn` because `spawn` is failing on Windows with pnpm + yarn // The root cause is unclear. Spawn causes the `@nx/workspace:preset` generator to be called twice // and the second time it fails with `Project {projectName} already exists.` - fork(nxBinForNewWorkspaceRoot, args, spawnOptions).on( + fork(nxBinForNewWorkspaceRoot, args, forkOptions).on( 'close', (code: number) => { if (code === 0) { From a03c5fa4f6a1a6eac7e8216ae2d0b93fefe806f4 Mon Sep 17 00:00:00 2001 From: Colum Ferry Date: Tue, 3 Dec 2024 10:10:11 +0000 Subject: [PATCH 3/3] fix(core): use getNxRequirePaths for more accurate locations of node_modules --- packages/workspace/src/generators/new/generate-preset.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/workspace/src/generators/new/generate-preset.ts b/packages/workspace/src/generators/new/generate-preset.ts index f69cd2b577c49..1b4ff94db1fcc 100644 --- a/packages/workspace/src/generators/new/generate-preset.ts +++ b/packages/workspace/src/generators/new/generate-preset.ts @@ -14,6 +14,7 @@ import { NormalizedSchema } from './new'; import { join } from 'path'; import * as yargsParser from 'yargs-parser'; import { fork, ForkOptions } from 'child_process'; +import { getNxRequirePaths } from 'nx/src/utils/installation-directory'; export function addPresetDependencies(host: Tree, options: NormalizedSchema) { const { dependencies, dev } = getPresetDependencies(options); @@ -39,8 +40,9 @@ export function generatePreset(host: Tree, opts: NormalizedSchema) { cwd: newWorkspaceRoot, }; const pmc = getPackageManagerCommand(); + const nxInstallationPaths = getNxRequirePaths(newWorkspaceRoot); const nxBinForNewWorkspaceRoot = require.resolve('nx/bin/nx', { - paths: [join(newWorkspaceRoot, 'node_modules')], + paths: nxInstallationPaths, }); const args = getPresetArgs(opts);