Skip to content

Commit 0003420

Browse files
committed
fix(@angular-devkit/build-angular): deleteOutputPath when using esbuild-builder
Prior to this change the `deleteOutputPath` was not being used in the esbuild-builder. Closes #26308
1 parent c7b7e59 commit 0003420

File tree

4 files changed

+120
-24
lines changed

4 files changed

+120
-24
lines changed

packages/angular_devkit/build_angular/src/builders/application/build-action.ts

Lines changed: 3 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,13 @@
88

99
import { BuilderOutput } from '@angular-devkit/architect';
1010
import type { logging } from '@angular-devkit/core';
11-
import fs from 'node:fs/promises';
1211
import path from 'node:path';
1312
import { BuildOutputFile } from '../../tools/esbuild/bundler-context';
1413
import { ExecutionResult, RebuildState } from '../../tools/esbuild/bundler-execution-result';
1514
import { shutdownSassWorkerPool } from '../../tools/esbuild/stylesheets/sass-language';
1615
import { withNoProgress, withSpinner, writeResultFiles } from '../../tools/esbuild/utils';
16+
import { deleteOutputDir } from '../../utils/delete-output-dir';
1717
import { shouldWatchRoot } from '../../utils/environment-options';
18-
import { assertIsError } from '../../utils/error';
1918
import { NormalizedCachedOptions } from '../../utils/normalize-cache';
2019

2120
export async function* runEsBuildBuildAction(
@@ -51,27 +50,8 @@ export async function* runEsBuildBuildAction(
5150
progress,
5251
} = options;
5352

54-
if (writeToFileSystem) {
55-
// Clean output path if enabled
56-
if (deleteOutputPath) {
57-
if (outputPath === workspaceRoot) {
58-
logger.error('Output path MUST not be workspace root directory!');
59-
60-
return;
61-
}
62-
63-
await fs.rm(outputPath, { force: true, recursive: true, maxRetries: 3 });
64-
}
65-
66-
// Create output directory if needed
67-
try {
68-
await fs.mkdir(outputPath, { recursive: true });
69-
} catch (e) {
70-
assertIsError(e);
71-
logger.error('Unable to create output directory: ' + e.message);
72-
73-
return;
74-
}
53+
if (deleteOutputPath && writeToFileSystem) {
54+
await deleteOutputDir(workspaceRoot, outputPath);
7555
}
7656

7757
const withProgress: typeof withSpinner = progress ? withSpinner : withNoProgress;
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
/**
2+
* @license
3+
* Copyright Google LLC All Rights Reserved.
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.io/license
7+
*/
8+
9+
import { buildApplication } from '../../index';
10+
import { APPLICATION_BUILDER_INFO, BASE_OPTIONS, describeBuilder } from '../setup';
11+
12+
describeBuilder(buildApplication, APPLICATION_BUILDER_INFO, (harness) => {
13+
describe('Option: "deleteOutputPath"', () => {
14+
beforeEach(async () => {
15+
// Application code is not needed for asset tests
16+
await harness.writeFile('src/main.ts', 'console.log("TEST");');
17+
18+
// Add file in output
19+
await harness.writeFile('dist/dummy.txt', '');
20+
});
21+
22+
it(`should delete the output files when 'deleteOutputPath' is true`, async () => {
23+
harness.useTarget('build', {
24+
...BASE_OPTIONS,
25+
deleteOutputPath: true,
26+
});
27+
28+
const { result } = await harness.executeOnce();
29+
expect(result?.success).toBeTrue();
30+
harness.expectFile('dist/dummy.txt').toNotExist();
31+
});
32+
33+
it(`should delete the output files when 'deleteOutputPath' is not set`, async () => {
34+
harness.useTarget('build', {
35+
...BASE_OPTIONS,
36+
deleteOutputPath: undefined,
37+
});
38+
39+
const { result } = await harness.executeOnce();
40+
expect(result?.success).toBeTrue();
41+
harness.expectFile('dist/dummy.txt').toNotExist();
42+
});
43+
44+
it(`should not delete the output files when 'deleteOutputPath' is false`, async () => {
45+
harness.useTarget('build', {
46+
...BASE_OPTIONS,
47+
deleteOutputPath: false,
48+
});
49+
50+
const { result } = await harness.executeOnce();
51+
expect(result?.success).toBeTrue();
52+
harness.expectFile('dist/dummy.txt').toExist();
53+
});
54+
});
55+
});

packages/angular_devkit/build_angular/src/builders/browser-esbuild/index.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import path from 'node:path';
1414
import { BuildOutputFile } from '../../tools/esbuild/bundler-context';
1515
import { BuildOutputAsset } from '../../tools/esbuild/bundler-execution-result';
1616
import { emitFilesToDisk } from '../../tools/esbuild/utils';
17+
import { deleteOutputDir } from '../../utils';
1718
import { buildApplicationInternal } from '../application';
1819
import { Schema as ApplicationBuilderOptions } from '../application/schema';
1920
import { logBuilderStatusWarnings } from './builder-status-warnings';
@@ -42,7 +43,12 @@ export async function* buildEsbuildBrowser(
4243
// Inform user of status of builder and options
4344
logBuilderStatusWarnings(userOptions, context);
4445
const normalizedOptions = normalizeOptions(userOptions);
45-
const fullOutputPath = path.join(context.workspaceRoot, normalizedOptions.outputPath);
46+
const { deleteOutputPath, outputPath } = normalizedOptions;
47+
const fullOutputPath = path.join(context.workspaceRoot, outputPath);
48+
49+
if (deleteOutputPath && infrastructureSettings?.write !== false) {
50+
await deleteOutputDir(context.workspaceRoot, outputPath);
51+
}
4652

4753
for await (const result of buildApplicationInternal(
4854
normalizedOptions,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
/**
2+
* @license
3+
* Copyright Google LLC All Rights Reserved.
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.io/license
7+
*/
8+
9+
import { buildEsbuildBrowser } from '../../index';
10+
import { BASE_OPTIONS, BROWSER_BUILDER_INFO, describeBuilder } from '../setup';
11+
12+
describeBuilder(buildEsbuildBrowser, BROWSER_BUILDER_INFO, (harness) => {
13+
describe('Option: "deleteOutputPath"', () => {
14+
beforeEach(async () => {
15+
// Application code is not needed for asset tests
16+
await harness.writeFile('src/main.ts', 'console.log("TEST");');
17+
18+
// Add file in output
19+
await harness.writeFile('dist/dummy.txt', '');
20+
});
21+
22+
it(`should delete the output files when 'deleteOutputPath' is true`, async () => {
23+
harness.useTarget('build', {
24+
...BASE_OPTIONS,
25+
deleteOutputPath: true,
26+
});
27+
28+
const { result } = await harness.executeOnce();
29+
expect(result?.success).toBeTrue();
30+
harness.expectFile('dist/dummy.txt').toNotExist();
31+
});
32+
33+
it(`should delete the output files when 'deleteOutputPath' is not set`, async () => {
34+
harness.useTarget('build', {
35+
...BASE_OPTIONS,
36+
deleteOutputPath: undefined,
37+
});
38+
39+
const { result } = await harness.executeOnce();
40+
expect(result?.success).toBeTrue();
41+
harness.expectFile('dist/dummy.txt').toNotExist();
42+
});
43+
44+
it(`should not delete the output files when 'deleteOutputPath' is false`, async () => {
45+
harness.useTarget('build', {
46+
...BASE_OPTIONS,
47+
deleteOutputPath: false,
48+
});
49+
50+
const { result } = await harness.executeOnce();
51+
expect(result?.success).toBeTrue();
52+
harness.expectFile('dist/dummy.txt').toExist();
53+
});
54+
});
55+
});

0 commit comments

Comments
 (0)