diff --git a/e2e/node/src/node.test.ts b/e2e/node/src/node.test.ts index 95e0068f65..e34416f235 100644 --- a/e2e/node/src/node.test.ts +++ b/e2e/node/src/node.test.ts @@ -264,7 +264,7 @@ module.exports = { } }, 120_000); - xit('should be able to generate a nest application', async () => { + it('should be able to generate a nest application', async () => { const nestapp = uniq('nestapp'); const port = 3335; runCLI(`generate @nx/nest:app ${nestapp} --linter=eslint`); @@ -278,49 +278,32 @@ module.exports = { 'Test Suites: 2 passed, 2 total' ); - await runCLIAsync(`build ${nestapp}`); + const buildResult = runCLI(`build ${nestapp}`); checkFilesExist( `dist/apps/${nestapp}/main.js`, - `dist/apps/${nestapp}/assets/file.txt`, - `dist/apps/${nestapp}/main.js.map` + `dist/apps/${nestapp}/assets/file.txt` ); - const server = exec(`node ./dist/apps/${nestapp}/main.js`, { - cwd: tmpProjPath(), - }); - expect(server).toBeTruthy(); - - // checking build - await new Promise((resolve) => { - server.stdout.on('data', async (data) => { - const message = data.toString(); - if (message.includes(`Listening at http://localhost:${port}`)) { - const result = await getData(port); - - expect(result.message).toEqual(`Welcome to ${nestapp}!`); - server.kill(); - resolve(null); - } - }); - }); + expect(buildResult).toContain( + `Successfully ran target build for project ${nestapp}` + ); // checking serve const p = await runCommandUntil( `serve ${nestapp} --port=${port}`, (output) => { process.stdout.write(output); - return output.includes(`Listening at http://localhost:${port}`); + return output.includes(`listening on ws://localhost:${port}`); } ); - const result = await getData(port); - expect(result.message).toEqual(`Welcome to ${nestapp}!`); - try { - await promisifiedTreeKill(p.pid, 'SIGKILL'); - expect(await killPorts(port)).toBeTruthy(); - } catch (err) { - expect(err).toBeFalsy(); - } + + const e2eRsult = await runCLIAsync(`e2e ${nestapp}-e2e`); + + expect(e2eRsult.combinedOutput).toContain('Test Suites: 1 passed, 1 total'); + + await killPorts(port); + p.kill(); }, 120000); // TODO(crystal, @ndcunningham): how do we handle this now? diff --git a/packages/js/src/executors/node/node.impl.ts b/packages/js/src/executors/node/node.impl.ts index db76e58ba9..b2f0648dea 100644 --- a/packages/js/src/executors/node/node.impl.ts +++ b/packages/js/src/executors/node/node.impl.ts @@ -21,6 +21,7 @@ import { calculateProjectBuildableDependencies } from '../../utils/buildable-lib import { killTree } from './lib/kill-tree'; import { fileExists } from 'nx/src/utils/fileutils'; import { getRelativeDirectoryToProjectRoot } from '../../utils/get-main-file-dir'; +import { interpolate } from 'nx/src/tasks-runner/utils'; interface ActiveTask { id: string; @@ -69,6 +70,7 @@ export async function* nodeExecutor( const buildOptions: Record = { ...readTargetOptions(buildTarget, context), ...options.buildTargetOptions, + target: buildTarget.target, }; if (options.waitUntilTargets && options.waitUntilTargets.length > 0) { @@ -364,7 +366,21 @@ function getFileToRun( // If using run-commands or another custom executor, then user should set // outputFileName, but we can try the default value that we use. if (!buildOptions?.outputPath && !buildOptions?.outputFileName) { + // If we are using crystal for infering the target, we can use the output path from the target. + // Since the output path has a token for the project name, we need to interpolate it. + // {workspaceRoot}/dist/{projectRoot} -> dist/my-app + const outputPath = project.data.targets[buildOptions.target]?.outputs?.[0]; + + if (outputPath) { + const outputFilePath = interpolate(outputPath, { + projectName: project.name, + projectRoot: project.data.root, + workspaceRoot: '', + }); + return path.join(outputFilePath, 'main.js'); + } const fallbackFile = path.join('dist', project.data.root, 'main.js'); + logger.warn( `Build option ${chalk.bold('outputFileName')} not set for ${chalk.bold( project.name diff --git a/packages/webpack/src/plugins/plugin.ts b/packages/webpack/src/plugins/plugin.ts index 1ce11bddcd..c733b193ae 100644 --- a/packages/webpack/src/plugins/plugin.ts +++ b/packages/webpack/src/plugins/plugin.ts @@ -8,7 +8,7 @@ import { workspaceRoot, writeJsonFile, } from '@nx/devkit'; -import { dirname, isAbsolute, join, relative } from 'path'; +import { dirname, isAbsolute, join, relative, resolve } from 'path'; import { getNamedInputs } from '@nx/devkit/src/utils/get-named-inputs'; import { WebpackExecutorOptions } from '../executors/webpack/schema'; import { WebDevServerOptions } from '../executors/dev-server/schema'; @@ -187,7 +187,14 @@ function normalizeOutputPath( } } else { if (isAbsolute(outputPath)) { - return `{workspaceRoot}/${relative(workspaceRoot, outputPath)}`; + /** + * If outputPath is absolute, we need to resolve it relative to the workspaceRoot first. + * After that, we can use the relative path to the workspaceRoot token {workspaceRoot} to generate the output path. + */ + return `{workspaceRoot}/${relative( + workspaceRoot, + resolve(workspaceRoot, outputPath) + )}`; } else { if (outputPath.startsWith('..')) { return join('{workspaceRoot}', join(projectRoot, outputPath));