feat(node): Add output path to setup docker (#26365)

This PR updates how we generate a DockerFile for inferred and non
inferred projects.

Now you need to provide a output path.
This commit is contained in:
Nicholas Cunningham 2024-06-06 10:42:50 -06:00 committed by GitHub
parent 88161e00c0
commit 9eebe4980a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 27 additions and 96 deletions

View File

@ -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": []

View File

@ -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(
@ -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')
@ -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,
@ -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'],
@ -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
),
};
}

View File

@ -3,4 +3,5 @@ export interface SetUpDockerOptions {
targetName?: string;
buildTarget?: string;
skipFormat?: boolean;
outputPath: string;
}

View File

@ -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"
}
}
}

View File

@ -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;
@ -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,
@ -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',
@ -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}`],
},
},
};
}),
};
});
};

View File

@ -3,8 +3,6 @@ import {
generateFiles,
GeneratorCallback,
joinPathFragments,
logger,
ProjectConfiguration,
readNxJson,
readProjectConfiguration,
runTasksInSerial,
@ -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,
@ -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) {