From 6e9514b5129ddb95d2acfafefad1b9146e5704f6 Mon Sep 17 00:00:00 2001 From: Alan Agius Date: Thu, 1 Aug 2019 19:19:14 +0200 Subject: [PATCH] fix(@ngtools/webpack): display unused file warning once per file --- .../unused-files-warning_spec_large.ts | 54 ++++++++++++++++++- .../webpack/src/angular_compiler_plugin.ts | 17 ++++-- 2 files changed, 65 insertions(+), 6 deletions(-) diff --git a/packages/angular_devkit/build_angular/test/browser/unused-files-warning_spec_large.ts b/packages/angular_devkit/build_angular/test/browser/unused-files-warning_spec_large.ts index d341876d3218..3fc077a71a16 100644 --- a/packages/angular_devkit/build_angular/test/browser/unused-files-warning_spec_large.ts +++ b/packages/angular_devkit/build_angular/test/browser/unused-files-warning_spec_large.ts @@ -11,7 +11,7 @@ import { debounceTime, take, tap } from 'rxjs/operators'; import { BrowserBuilderOutput } from '../../src/browser/index'; import { createArchitect, host, ivyEnabled } from '../utils'; - +// tslint:disable-next-line:no-big-function describe('Browser Builder unused files warnings', () => { const warningMessageSuffix = `is part of the TypeScript compilation but it's unused`; const targetSpec = { project: 'app', target: 'build' }; @@ -162,4 +162,56 @@ describe('Browser Builder unused files warnings', () => { await run.stop(); }); + it('should only show warning once per file', async () => { + if (!ivyEnabled) { + // TODO: https://github.com/angular/angular-cli/issues/15056 + pending('Only supported in Ivy.'); + + return; + } + + host.replaceInFile( + 'src/tsconfig.app.json', + '"**/*.d.ts"', + '"**/*.d.ts", "testing/**/*.ts"', + ); + + // Write a used file + host.writeMultipleFiles({ + 'src/testing/type.ts': 'export type MyType = number;', + }); + + const logger = new TestLogger('unused-files-warnings'); + let buildNumber = 0; + const run = await architect.scheduleTarget(targetSpec, { watch: true }, { logger }); + + await run.output + .pipe( + debounceTime(1000), + tap(buildEvent => { + expect(buildEvent.success).toBe(true); + + buildNumber ++; + switch (buildNumber) { + case 1: + // The first should have type.ts as unused. + expect(logger.includes(`type.ts ${warningMessageSuffix}`)).toBe(true, `Case ${buildNumber} failed.`); + + // touch a file to trigger a rebuild + host.appendToFile('src/main.ts', ''); + break; + case 2: + // The second should should have type.ts as unused but shouldn't warn. + expect(logger.includes(warningMessageSuffix)).toBe(false, `Case ${buildNumber} failed.`); + break; + } + + logger.clear(); + }), + take(2), + ) + .toPromise(); + await run.stop(); + }); + }); diff --git a/packages/ngtools/webpack/src/angular_compiler_plugin.ts b/packages/ngtools/webpack/src/angular_compiler_plugin.ts index 6962bd7bb04d..7a9e642d2d94 100644 --- a/packages/ngtools/webpack/src/angular_compiler_plugin.ts +++ b/packages/ngtools/webpack/src/angular_compiler_plugin.ts @@ -111,6 +111,7 @@ export class AngularCompilerPlugin { // This is needed because if the first build fails we need to do a full emit // even whe only a single file gets updated. private _hadFullJitEmit: boolean | undefined; + private _unusedFiles = new Set(); private _changedFileExtensions = new Set(['ts', 'tsx', 'html', 'css', 'js', 'json']); // Webpack plugin. @@ -626,12 +627,18 @@ export class AngularCompilerPlugin { } } - const unusedFilesWarning = program.getSourceFiles() - .filter(({ fileName }) => !fileExcludeRegExp.test(fileName) && !usedFiles.has(fileName)) - .map(({ fileName }) => `${fileName} is part of the TypeScript compilation but it's unused.`); + const sourceFiles = program.getSourceFiles(); + for (const { fileName } of sourceFiles) { + if ( + fileExcludeRegExp.test(fileName) + || usedFiles.has(fileName) + || this._unusedFiles.has(fileName) + ) { + continue; + } - if (unusedFilesWarning.length) { - compilation.warnings.push(...unusedFilesWarning); + compilation.warnings.push(`${fileName} is part of the TypeScript compilation but it's unused.`); + this._unusedFiles.add(fileName); } }