Skip to content

Commit

Permalink
feat(node): add deleteOutputPath option to @nrwl/node:webpack executor (
Browse files Browse the repository at this point in the history
  • Loading branch information
jaytavares committed Jun 8, 2022
1 parent 7418ae1 commit 99b245b
Show file tree
Hide file tree
Showing 7 changed files with 97 additions and 29 deletions.
5 changes: 5 additions & 0 deletions docs/generated/packages/node.json
Expand Up @@ -291,6 +291,11 @@
"type": "string",
"description": "The output path of the generated files."
},
"deleteOutputPath": {
"type": "boolean",
"description": "Delete the output path before building.",
"default": true
},
"watch": {
"type": "boolean",
"description": "Run build when files change.",
Expand Down
94 changes: 65 additions & 29 deletions e2e/node/src/node.test.ts
@@ -1,5 +1,6 @@
import { stripIndents } from '@angular-devkit/core/src/utils/literals';
import {
createFile,
checkFilesDoNotExist,
checkFilesExist,
expectJestTestsToPass,
Expand Down Expand Up @@ -309,6 +310,41 @@ ${jslib}();
expect(nodeAppPackageJson['dependencies']['tslib']).toBeTruthy();
}, 300000);

it('should remove previous output before building with the --deleteOutputPath option set', async () => {
const appName = uniq('app');

runCLI(`generate @nrwl/node:app ${appName} --no-interactive`);

// deleteOutputPath should default to true
createFile(`dist/apps/${appName}/_should_remove.txt`);
createFile(`dist/apps/_should_not_remove.txt`);
checkFilesExist(
`dist/apps/${appName}/_should_remove.txt`,
`dist/apps/_should_not_remove.txt`
);
runCLI(`build ${appName} --outputHashing none`); // no explicit deleteOutputPath option set
checkFilesDoNotExist(`dist/apps/${appName}/_should_remove.txt`);
checkFilesExist(`dist/apps/_should_not_remove.txt`);

// Explicitly set `deleteOutputPath` to true
createFile(`dist/apps/${appName}/_should_remove.txt`);
createFile(`dist/apps/_should_not_remove.txt`);
checkFilesExist(
`dist/apps/${appName}/_should_remove.txt`,
`dist/apps/_should_not_remove.txt`
);
runCLI(`build ${appName} --outputHashing none --deleteOutputPath`);
checkFilesDoNotExist(`dist/apps/${appName}/_should_remove.txt`);
checkFilesExist(`dist/apps/_should_not_remove.txt`);

// Explicitly set `deleteOutputPath` to false
createFile(`dist/apps/${appName}/_should_keep.txt`);
createFile(`dist/apps/_should_keep.txt`);
runCLI(`build ${appName} --deleteOutputPath=false --outputHashing none`);
checkFilesExist(`dist/apps/${appName}/_should_keep.txt`);
checkFilesExist(`dist/apps/_should_keep.txt`);
}, 120000);

describe('NestJS', () => {
it('should have plugin output if specified in `tsPlugins`', async () => {
newProject();
Expand All @@ -325,49 +361,49 @@ ${jslib}();
updateFile(
`apps/${nestapp}/src/app/foo.dto.ts`,
`
export class FooDto {
foo: string;
bar: number;
}`
export class FooDto {
foo: string;
bar: number;
}`
);
updateFile(
`apps/${nestapp}/src/app/app.controller.ts`,
`
import { Controller, Get } from '@nestjs/common';
import { FooDto } from './foo.dto';
import { AppService } from './app.service';
import { Controller, Get } from '@nestjs/common';
import { FooDto } from './foo.dto';
import { AppService } from './app.service';
@Controller()
export class AppController {
constructor(private readonly appService: AppService) {}
@Controller()
export class AppController {
constructor(private readonly appService: AppService) {}
@Get()
getData() {
return this.appService.getData();
}
@Get()
getData() {
return this.appService.getData();
}
@Get('foo')
getFoo(): Promise<FooDto> {
return Promise.resolve({
foo: 'foo',
bar: 123
})
}
}`
@Get('foo')
getFoo(): Promise<FooDto> {
return Promise.resolve({
foo: 'foo',
bar: 123
})
}
}`
);

await runCLIAsync(`build ${nestapp}`);

const mainJs = readFile(`dist/apps/${nestapp}/main.js`);
expect(stripIndents`${mainJs}`).toContain(
stripIndents`
class FooDto {
static _OPENAPI_METADATA_FACTORY() {
return { foo: { required: true, type: () => String }, bar: { required: true, type: () => Number } };
}
}
exports.FooDto = FooDto;
`
class FooDto {
static _OPENAPI_METADATA_FACTORY() {
return { foo: { required: true, type: () => String }, bar: { required: true, type: () => Number } };
}
}
exports.FooDto = FooDto;
`
);
}, 300000);
});
Expand Down
5 changes: 5 additions & 0 deletions packages/node/src/executors/webpack/schema.json
Expand Up @@ -16,6 +16,11 @@
"type": "string",
"description": "The output path of the generated files."
},
"deleteOutputPath": {
"type": "boolean",
"description": "Delete the output path before building.",
"default": true
},
"watch": {
"type": "boolean",
"description": "Run build when files change.",
Expand Down
6 changes: 6 additions & 0 deletions packages/node/src/executors/webpack/webpack.impl.ts
Expand Up @@ -17,6 +17,7 @@ import { register } from 'ts-node';
import { getNodeWebpackConfig } from '../../utils/node.config';
import { BuildNodeBuilderOptions } from '../../utils/types';
import { normalizeBuildOptions } from '../../utils/normalize';
import { deleteOutputDir } from '../../utils/fs';
import { runWebpack } from '../../utils/run-webpack';

export type NodeBuildEvent = {
Expand Down Expand Up @@ -77,6 +78,11 @@ export async function* webpackExecutor(
}
}

// Delete output path before bundling
if (options.deleteOutputPath) {
deleteOutputDir(context.root, options.outputPath);
}

const config = await options.webpackConfig.reduce(
async (currentConfig, plugin) => {
return require(plugin)(await currentConfig, {
Expand Down
14 changes: 14 additions & 0 deletions packages/node/src/utils/fs.ts
@@ -0,0 +1,14 @@
import * as path from 'path';
import { removeSync } from 'fs-extra';

/**
* Delete an output directory, but error out if it's the root of the project.
*/
export function deleteOutputDir(root: string, outputPath: string) {
const resolvedOutputPath = path.resolve(root, outputPath);
if (resolvedOutputPath === root) {
throw new Error('Output path MUST not be project root directory!');
}

removeSync(resolvedOutputPath);
}
1 change: 1 addition & 0 deletions packages/node/src/utils/normalize.ts
Expand Up @@ -37,6 +37,7 @@ export function normalizeBuildOptions(
options.additionalEntryPoints ?? []
),
outputFileName: options.outputFileName ?? 'main.js',
deleteOutputPath: options.deleteOutputPath ?? true,
};
}

Expand Down
1 change: 1 addition & 0 deletions packages/node/src/utils/types.ts
Expand Up @@ -96,6 +96,7 @@ export interface BuildNodeBuilderOptions extends BuildBuilderOptions {
externalDependencies: 'all' | 'none' | string[];
buildLibsFromSource?: boolean;
generatePackageJson?: boolean;
deleteOutputPath?: boolean;
}

export interface NormalizedBuildNodeBuilderOptions
Expand Down

0 comments on commit 99b245b

Please sign in to comment.