diff --git a/e2e/js/src/js-node.test.ts b/e2e/js/src/js-node.test.ts new file mode 100644 index 0000000000000..5e071f907d564 --- /dev/null +++ b/e2e/js/src/js-node.test.ts @@ -0,0 +1,48 @@ +import { + cleanupProject, + newProject, + runCLI, + uniq, + updateFile, + updateProjectConfig, +} from '@nx/e2e/utils'; + +describe('js:node error handling', () => { + let scope: string; + + beforeEach(() => { + scope = newProject(); + }); + + afterEach(() => cleanupProject()); + + it('should log out the error', () => { + const esbuildLib = uniq('esbuildlib'); + + runCLI( + `generate @nx/js:lib ${esbuildLib} --bundler=esbuild --no-interactive` + ); + + updateFile(`libs/${esbuildLib}/src/index.ts`, () => { + return ` + console.log('Hello from my library!'); + throw new Error('This is an error'); + `; + }); + + updateProjectConfig(esbuildLib, (config) => { + config.targets['run-node'] = { + executor: '@nx/js:node', + options: { + buildTarget: `${esbuildLib}:build`, + watch: false, + }, + }; + return config; + }); + + const output = runCLI(`run ${esbuildLib}:run-node`); + expect(output).toContain('Hello from my library!'); + expect(output).toContain('This is an error'); + }, 240_000); +}); diff --git a/e2e/utils/command-utils.ts b/e2e/utils/command-utils.ts index 9146ff67e91a8..eed28c892ad6e 100644 --- a/e2e/utils/command-utils.ts +++ b/e2e/utils/command-utils.ts @@ -332,7 +332,7 @@ export function runCLI( const logs = execSync( `${pm.runNxSilent} ${command} ${ opts.verbose ?? isVerboseE2ERun() ? ' --verbose' : '' - }`, + } 2>&1`, { cwd: opts.cwd || tmpProjPath(), env: { diff --git a/packages/js/src/executors/node/node.impl.ts b/packages/js/src/executors/node/node.impl.ts index a186f149174a4..ad7f60a99d42e 100644 --- a/packages/js/src/executors/node/node.impl.ts +++ b/packages/js/src/executors/node/node.impl.ts @@ -10,11 +10,13 @@ import { import { daemonClient } from 'nx/src/daemon/client/client'; import { randomUUID } from 'crypto'; import { join } from 'path'; +import * as path from 'path'; import { InspectType, NodeExecutorOptions } from './schema'; import { createAsyncIterable } from '@nx/devkit/src/utils/async-iterable'; import { calculateProjectDependencies } from '../../utils/buildable-libs-utils'; import { killTree } from './lib/kill-tree'; +import { fileExists } from 'nx/src/utils/fileutils'; interface ActiveTask { id: string; @@ -71,12 +73,11 @@ export async function* nodeExecutor( // Re-map buildable workspace projects to their output directory. const mappings = calculateResolveMappings(context, options); - const fileToRun = join( - context.root, - buildOptions.outputPath, - buildOptions.outputFileName ?? 'main.js' - ); + const outputFileName = + buildOptions.outputFileName ?? `${path.parse(buildOptions.main).name}.js`; + + const fileToRun = join(context.root, buildOptions.outputPath, outputFileName); const tasks: ActiveTask[] = []; let currentTask: ActiveTask = null; @@ -168,7 +169,8 @@ export async function* nodeExecutor( task.childProcess.stderr.on('data', (data) => { // Don't log out error if task is killed and new one has started. // This could happen if a new build is triggered while new process is starting, since the operation is not atomic. - if (options.watch && !task.killed) { + // Log the error in normal mode + if (!options.watch || !task.killed) { logger.error(data.toString()); } });