Skip to content

Commit c788d5b

Browse files
alan-agius4clydin
authored andcommitted
fix(@angular-devkit/build-angular): log modified and removed files when using the verbose option
With this change we print out the modified and removed files when running a build in verbose mode. This can be useful to debug builds that rebuilds multiple times without an apparent file change. (cherry picked from commit f0a0b08)
1 parent 651adad commit c788d5b

File tree

3 files changed

+139
-0
lines changed

3 files changed

+139
-0
lines changed
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
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 { logging } from '@angular-devkit/core';
10+
import { concatMap, count, take, timeout } from 'rxjs/operators';
11+
import { BUILD_TIMEOUT, buildWebpackBrowser } from '../../index';
12+
import { BASE_OPTIONS, BROWSER_BUILDER_INFO, describeBuilder } from '../setup';
13+
14+
// The below plugin is only enabled when verbose option is set to true.
15+
const VERBOSE_LOG_TEXT = 'LOG from webpack.';
16+
17+
describeBuilder(buildWebpackBrowser, BROWSER_BUILDER_INFO, (harness) => {
18+
describe('Option: "verbose"', () => {
19+
beforeEach(async () => {
20+
// Application code is not needed for verbose output
21+
await harness.writeFile('src/main.ts', '');
22+
});
23+
24+
it('should include verbose logs when true', async () => {
25+
harness.useTarget('build', {
26+
...BASE_OPTIONS,
27+
verbose: true,
28+
});
29+
30+
const { result, logs } = await harness.executeOnce();
31+
expect(result?.success).toBeTrue();
32+
expect(logs).toContain(
33+
jasmine.objectContaining<logging.LogEntry>({
34+
message: jasmine.stringMatching(VERBOSE_LOG_TEXT),
35+
}),
36+
);
37+
});
38+
39+
it('should not include verbose logs when undefined', async () => {
40+
harness.useTarget('build', {
41+
...BASE_OPTIONS,
42+
verbose: undefined,
43+
});
44+
45+
const { result, logs } = await harness.executeOnce();
46+
expect(result?.success).toBeTrue();
47+
expect(logs).not.toContain(
48+
jasmine.objectContaining<logging.LogEntry>({
49+
message: jasmine.stringMatching(VERBOSE_LOG_TEXT),
50+
}),
51+
);
52+
});
53+
54+
it('should not include verbose logs when false', async () => {
55+
harness.useTarget('build', {
56+
...BASE_OPTIONS,
57+
verbose: false,
58+
});
59+
60+
const { result, logs } = await harness.executeOnce();
61+
expect(result?.success).toBeTrue();
62+
expect(logs).not.toContain(
63+
jasmine.objectContaining<logging.LogEntry>({
64+
message: jasmine.stringMatching(VERBOSE_LOG_TEXT),
65+
}),
66+
);
67+
});
68+
69+
it('should list modified files when verbose is set to true', async () => {
70+
harness.useTarget('build', {
71+
...BASE_OPTIONS,
72+
verbose: true,
73+
watch: true,
74+
});
75+
76+
await harness
77+
.execute()
78+
.pipe(
79+
timeout(BUILD_TIMEOUT),
80+
concatMap(async ({ result, logs }, index) => {
81+
expect(result?.success).toBeTrue();
82+
83+
switch (index) {
84+
case 0:
85+
// Amend file
86+
await harness.appendToFile('/src/main.ts', ' ');
87+
break;
88+
case 1:
89+
expect(logs).toContain(
90+
jasmine.objectContaining<logging.LogEntry>({
91+
message: jasmine.stringMatching(
92+
/angular\.watch-files-logs-plugin\n\s+Modified files:\n.+main\.ts/,
93+
),
94+
}),
95+
);
96+
97+
break;
98+
}
99+
}),
100+
take(2),
101+
count(),
102+
)
103+
.toPromise();
104+
});
105+
});
106+
});

packages/angular_devkit/build_angular/src/webpack/configs/common.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ import { NamedChunksPlugin } from '../plugins/named-chunks-plugin';
3333
import { ProgressPlugin } from '../plugins/progress-plugin';
3434
import { TransferSizePlugin } from '../plugins/transfer-size-plugin';
3535
import { createIvyPlugin } from '../plugins/typescript';
36+
import { WatchFilesLogsPlugin } from '../plugins/watch-files-logs-plugin';
3637
import {
3738
assetPatterns,
3839
externalizePackages,
@@ -204,6 +205,10 @@ export async function getCommonConfig(wco: WebpackConfigOptions): Promise<Config
204205
);
205206
}
206207

208+
if (verbose) {
209+
extraPlugins.push(new WatchFilesLogsPlugin());
210+
}
211+
207212
if (buildOptions.statsJson) {
208213
extraPlugins.push(
209214
new JsonStatsPlugin(path.resolve(root, buildOptions.outputPath, 'stats.json')),
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
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 type { Compiler } from 'webpack';
10+
11+
const PLUGIN_NAME = 'angular.watch-files-logs-plugin';
12+
13+
export class WatchFilesLogsPlugin {
14+
apply(compiler: Compiler) {
15+
compiler.hooks.watchRun.tap(PLUGIN_NAME, ({ modifiedFiles, removedFiles }) => {
16+
compiler.hooks.compilation.tap(PLUGIN_NAME, (compilation) => {
17+
const logger = compilation.getLogger(PLUGIN_NAME);
18+
if (modifiedFiles?.size) {
19+
logger.log(`Modified files:\n${[...modifiedFiles].join('\n')}\n`);
20+
}
21+
22+
if (removedFiles?.size) {
23+
logger.log(`Removed files:\n${[...removedFiles].join('\n')}\n`);
24+
}
25+
});
26+
});
27+
}
28+
}

0 commit comments

Comments
 (0)