Skip to content

Commit

Permalink
feat(node): Add output path to setup docker (#26365)
Browse files Browse the repository at this point in the history
This PR updates how we generate a DockerFile for inferred and non
inferred projects.

Now you need to provide a output path.
  • Loading branch information
ndcunningham authored Jun 6, 2024
1 parent 88161e0 commit 9eebe49
Show file tree
Hide file tree
Showing 6 changed files with 27 additions and 96 deletions.
4 changes: 4 additions & 0 deletions docs/generated/packages/node/generators/setup-docker.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@
"description": "The name of the build target",
"type": "string",
"default": "build"
},
"outputPath": {
"description": "The output path for the node application",
"type": "string"
}
},
"presets": []
Expand Down
20 changes: 8 additions & 12 deletions packages/node/src/generators/application/application.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ import { logShowProjectCommand } from '@nx/devkit/src/utils/log-show-project-com
export interface NormalizedSchema extends Schema {
appProjectRoot: string;
parsedTags: string[];
outputPath: string;
}

function getWebpackBuildConfig(
Expand All @@ -67,10 +68,7 @@ function getWebpackBuildConfig(
options: {
target: 'node',
compiler: 'tsc',
outputPath: joinPathFragments(
'dist',
options.rootProject ? options.name : options.appProjectRoot
),
outputPath: options.outputPath,
main: joinPathFragments(
project.sourceRoot,
'main' + (options.js ? '.js' : '.ts')
Expand Down Expand Up @@ -101,10 +99,7 @@ function getEsBuildConfig(
defaultConfiguration: 'production',
options: {
platform: 'node',
outputPath: joinPathFragments(
'dist',
options.rootProject ? options.name : options.appProjectRoot
),
outputPath: options.outputPath,
// Use CJS for Node apps for widest compatibility.
format: ['cjs'],
bundle: false,
Expand Down Expand Up @@ -199,10 +194,7 @@ function addAppFiles(tree: Tree, options: NormalizedSchema) {
),
webpackPluginOptions: hasWebpackPlugin(tree)
? {
outputPath: joinPathFragments(
'dist',
options.rootProject ? options.name : options.appProjectRoot
),
outputPath: options.outputPath,
main: './src/main' + (options.js ? '.js' : '.ts'),
tsConfig: './tsconfig.app.json',
assets: ['./src/assets'],
Expand Down Expand Up @@ -562,6 +554,10 @@ async function normalizeOptions(
unitTestRunner: options.unitTestRunner ?? 'jest',
rootProject: options.rootProject ?? false,
port: options.port ?? 3000,
outputPath: joinPathFragments(
'dist',
options.rootProject ? options.name : appProjectRoot
),
};
}

Expand Down
1 change: 1 addition & 0 deletions packages/node/src/generators/setup-docker/schema.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ export interface SetUpDockerOptions {
targetName?: string;
buildTarget?: string;
skipFormat?: boolean;
outputPath: string;
}
4 changes: 4 additions & 0 deletions packages/node/src/generators/setup-docker/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@
"description": "The name of the build target",
"type": "string",
"default": "build"
},
"outputPath": {
"description": "The output path for the node application",
"type": "string"
}
}
}
42 changes: 2 additions & 40 deletions packages/node/src/generators/setup-docker/setup-docker.spec.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,6 @@
import 'nx/src/internal-testing-utils/mock-project-graph';

import {
ProjectConfiguration,
readProjectConfiguration,
Tree,
} from '@nx/devkit';
import { readProjectConfiguration, Tree } from '@nx/devkit';
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
import { applicationGenerator } from '../application/application';

describe('setupDockerGenerator', () => {
let tree: Tree;
Expand All @@ -18,15 +13,6 @@ describe('setupDockerGenerator', () => {
describe('integrated', () => {
it('should create docker assets when --docker is passed', async () => {
const projectName = 'integreated-api';
// Since we mock the project graph, we need to mock the project configuration as well
mockReadCachedProjectConfiguration({
name: projectName,
root: projectName,
});

const { applicationGenerator } = await import(
'../application/application'
);

await applicationGenerator(tree, {
name: projectName,
Expand Down Expand Up @@ -56,11 +42,7 @@ describe('setupDockerGenerator', () => {
describe('standalone', () => {
it('should create docker assets when --docker is passed', async () => {
const projectName = 'standalone-api';
mockReadCachedProjectConfiguration({ name: projectName, root: '' });

const { applicationGenerator } = await import(
'../application/application'
);
await applicationGenerator(tree, {
name: projectName,
framework: 'fastify',
Expand All @@ -86,23 +68,3 @@ describe('setupDockerGenerator', () => {
});
});
});

const mockReadCachedProjectConfiguration = (
projectConfig: ProjectConfiguration
) => {
jest.mock('nx/src/project-graph/project-graph', () => {
return {
...jest.requireActual('nx/src/project-graph/project-graph'),
readCachedProjectConfiguration: jest.fn(() => {
return {
root: projectConfig.root,
targets: {
build: {
outputs: [`dist/${projectConfig.name}`],
},
},
};
}),
};
});
};
52 changes: 8 additions & 44 deletions packages/node/src/generators/setup-docker/setup-docker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@ import {
generateFiles,
GeneratorCallback,
joinPathFragments,
logger,
ProjectConfiguration,
readNxJson,
readProjectConfiguration,
runTasksInSerial,
Expand All @@ -14,8 +12,6 @@ import {

import { SetUpDockerOptions } from './schema';
import { join } from 'path';
import { interpolate } from 'nx/src/tasks-runner/utils';
import { readCachedProjectConfiguration } from 'nx/src/project-graph/project-graph';

function normalizeOptions(
tree: Tree,
Expand All @@ -30,47 +26,15 @@ function normalizeOptions(
}

function addDocker(tree: Tree, options: SetUpDockerOptions) {
// Inferred targets are only available in the project graph
const projectConfig = readCachedProjectConfiguration(options.project);

if (
!projectConfig ||
!projectConfig.targets ||
!projectConfig.targets[options.buildTarget]
) {
return;
}

// Returns an string like {workspaceRoot}/dist/apps/{projectName}
// Non crystalized projects would return {options.outputPath}
const tokenizedOutputPath =
projectConfig.targets[`${options.buildTarget}`]?.outputs?.[0];
const maybeBuildOptions =
projectConfig.targets[`${options.buildTarget}`]?.options;

if (tree.exists(joinPathFragments(projectConfig.root, 'DockerFile'))) {
logger.info(
`Skipping setup since a Dockerfile already exists inside ${projectConfig.root}`
);
} else if (!tokenizedOutputPath) {
logger.error(
`Skipping setup since the output path for the build target ${options.buildTarget} is not defined.`
);
} else {
const outputPath = interpolate(tokenizedOutputPath, {
projectName: projectConfig.name,
projectRoot: projectConfig.root,
workspaceRoot: '',
options: maybeBuildOptions || '',
});

generateFiles(tree, join(__dirname, './files'), projectConfig.root, {
tmpl: '',
app: projectConfig.sourceRoot,
buildLocation: outputPath,
project: options.project,
});
const projectConfig = readProjectConfiguration(tree, options.project);
if (!projectConfig) {
throw new Error(`Cannot find project configuration for ${options.project}`);
}
generateFiles(tree, join(__dirname, './files'), projectConfig.root, {
tmpl: '',
buildLocation: options.outputPath,
project: options.project,
});
}

export function updateProjectConfig(tree: Tree, options: SetUpDockerOptions) {
Expand Down

0 comments on commit 9eebe49

Please # to comment.