fix(js): node executor should always log error (#17622)
This commit is contained in:
parent
bfe8e47d23
commit
36838d6211
50
e2e/js/src/js-node.test.ts
Normal file
50
e2e/js/src/js-node.test.ts
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
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`, {
|
||||||
|
redirectStderr: true,
|
||||||
|
});
|
||||||
|
expect(output).toContain('Hello from my library!');
|
||||||
|
expect(output).toContain('This is an error');
|
||||||
|
}, 240_000);
|
||||||
|
});
|
||||||
@ -23,6 +23,7 @@ export interface RunCmdOpts {
|
|||||||
cwd?: string;
|
cwd?: string;
|
||||||
silent?: boolean;
|
silent?: boolean;
|
||||||
verbose?: boolean;
|
verbose?: boolean;
|
||||||
|
redirectStderr?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -325,26 +326,25 @@ export function runCLI(
|
|||||||
silenceError: false,
|
silenceError: false,
|
||||||
env: undefined,
|
env: undefined,
|
||||||
verbose: undefined,
|
verbose: undefined,
|
||||||
|
redirectStderr: undefined,
|
||||||
}
|
}
|
||||||
): string {
|
): string {
|
||||||
try {
|
try {
|
||||||
const pm = getPackageManagerCommand();
|
const pm = getPackageManagerCommand();
|
||||||
const logs = execSync(
|
const commandToRun = `${pm.runNxSilent} ${command} ${
|
||||||
`${pm.runNxSilent} ${command} ${
|
opts.verbose ?? isVerboseE2ERun() ? ' --verbose' : ''
|
||||||
opts.verbose ?? isVerboseE2ERun() ? ' --verbose' : ''
|
}${opts.redirectStderr ? ' 2>&1' : ''}`;
|
||||||
}`,
|
const logs = execSync(commandToRun, {
|
||||||
{
|
cwd: opts.cwd || tmpProjPath(),
|
||||||
cwd: opts.cwd || tmpProjPath(),
|
env: {
|
||||||
env: {
|
CI: 'true',
|
||||||
CI: 'true',
|
...getStrippedEnvironmentVariables(),
|
||||||
...getStrippedEnvironmentVariables(),
|
...opts.env,
|
||||||
...opts.env,
|
},
|
||||||
},
|
encoding: 'utf-8',
|
||||||
encoding: 'utf-8',
|
stdio: 'pipe',
|
||||||
stdio: 'pipe',
|
maxBuffer: 50 * 1024 * 1024,
|
||||||
maxBuffer: 50 * 1024 * 1024,
|
});
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
if (opts.verbose ?? isVerboseE2ERun()) {
|
if (opts.verbose ?? isVerboseE2ERun()) {
|
||||||
output.log({
|
output.log({
|
||||||
|
|||||||
@ -10,11 +10,13 @@ import {
|
|||||||
import { daemonClient } from 'nx/src/daemon/client/client';
|
import { daemonClient } from 'nx/src/daemon/client/client';
|
||||||
import { randomUUID } from 'crypto';
|
import { randomUUID } from 'crypto';
|
||||||
import { join } from 'path';
|
import { join } from 'path';
|
||||||
|
import * as path from 'path';
|
||||||
|
|
||||||
import { InspectType, NodeExecutorOptions } from './schema';
|
import { InspectType, NodeExecutorOptions } from './schema';
|
||||||
import { createAsyncIterable } from '@nx/devkit/src/utils/async-iterable';
|
import { createAsyncIterable } from '@nx/devkit/src/utils/async-iterable';
|
||||||
import { calculateProjectDependencies } from '../../utils/buildable-libs-utils';
|
import { calculateProjectDependencies } from '../../utils/buildable-libs-utils';
|
||||||
import { killTree } from './lib/kill-tree';
|
import { killTree } from './lib/kill-tree';
|
||||||
|
import { fileExists } from 'nx/src/utils/fileutils';
|
||||||
|
|
||||||
interface ActiveTask {
|
interface ActiveTask {
|
||||||
id: string;
|
id: string;
|
||||||
@ -71,12 +73,11 @@ export async function* nodeExecutor(
|
|||||||
|
|
||||||
// Re-map buildable workspace projects to their output directory.
|
// Re-map buildable workspace projects to their output directory.
|
||||||
const mappings = calculateResolveMappings(context, options);
|
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[] = [];
|
const tasks: ActiveTask[] = [];
|
||||||
let currentTask: ActiveTask = null;
|
let currentTask: ActiveTask = null;
|
||||||
|
|
||||||
@ -159,7 +160,7 @@ export async function* nodeExecutor(
|
|||||||
stdio: [0, 1, 'pipe', 'ipc'],
|
stdio: [0, 1, 'pipe', 'ipc'],
|
||||||
env: {
|
env: {
|
||||||
...process.env,
|
...process.env,
|
||||||
NX_FILE_TO_RUN: fileToRun,
|
NX_FILE_TO_RUN: fileToRunCorrectPath(fileToRun),
|
||||||
NX_MAPPINGS: JSON.stringify(mappings),
|
NX_MAPPINGS: JSON.stringify(mappings),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@ -168,7 +169,8 @@ export async function* nodeExecutor(
|
|||||||
task.childProcess.stderr.on('data', (data) => {
|
task.childProcess.stderr.on('data', (data) => {
|
||||||
// Don't log out error if task is killed and new one has started.
|
// 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.
|
// 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());
|
logger.error(data.toString());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -304,4 +306,23 @@ function runWaitUntilTargets(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function fileToRunCorrectPath(fileToRun: string): string {
|
||||||
|
if (!fileExists(fileToRun)) {
|
||||||
|
const cjsFile = fileToRun.replace(/\.js$/, '.cjs');
|
||||||
|
if (fileExists(cjsFile)) {
|
||||||
|
fileToRun = cjsFile;
|
||||||
|
} else {
|
||||||
|
const mjsFile = fileToRun.replace(/\.js$/, '.mjs');
|
||||||
|
if (fileExists(mjsFile)) {
|
||||||
|
fileToRun = mjsFile;
|
||||||
|
} else {
|
||||||
|
throw new Error(
|
||||||
|
`Could not find ${fileToRun}. Make sure your build succeeded.`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return fileToRun;
|
||||||
|
}
|
||||||
|
|
||||||
export default nodeExecutor;
|
export default nodeExecutor;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user