From 1ffd3f49648e0c3b863db78d3e772ea24737e711 Mon Sep 17 00:00:00 2001 From: Alan Date: Tue, 4 Jun 2019 14:47:15 +0200 Subject: [PATCH] fix(@ngtools/webpack): rebuilding project with errors reports cannot find .ts files in JIT When the first build in JIT has an error we are not emitting files. This ends up causing an issue because subsequent builds only trigger partial emits of files and only emits the full set of files if the number of files changed is greater than 20. This logic adds the behavior that we only enter the 'only 20 files' part when the previous build was successful. Fixes #14644 --- .../test/browser/rebuild_spec_large.ts | 46 +++++++++++++++++-- .../webpack/src/angular_compiler_plugin.ts | 2 +- 2 files changed, 43 insertions(+), 5 deletions(-) diff --git a/packages/angular_devkit/build_angular/test/browser/rebuild_spec_large.ts b/packages/angular_devkit/build_angular/test/browser/rebuild_spec_large.ts index ce69a366348f..ea88bef2ab70 100644 --- a/packages/angular_devkit/build_angular/test/browser/rebuild_spec_large.ts +++ b/packages/angular_devkit/build_angular/test/browser/rebuild_spec_large.ts @@ -9,7 +9,7 @@ import { Architect } from '@angular-devkit/architect'; import { TestLogger } from '@angular-devkit/architect/testing'; -import { normalize, virtualFs } from '@angular-devkit/core'; +import { logging, normalize, virtualFs } from '@angular-devkit/core'; import { debounceTime, take, takeWhile, tap } from 'rxjs/operators'; import { createArchitect, host, lazyModuleFiles, lazyModuleStringImport } from '../utils'; @@ -68,14 +68,11 @@ describe('Browser Builder rebuilds', () => { const overrides = { watch: true }; - let buildCount = 0; let phase = 1; const run = await architect.scheduleTarget(target, overrides); await run.output.pipe( tap(result => { expect(result.success).toBe(true, 'build should succeed'); - buildCount++; - const hasLazyChunk = host.scopedSync().exists(normalize('dist/lazy-lazy-module.js')); switch (phase) { case 1: @@ -205,6 +202,47 @@ describe('Browser Builder rebuilds', () => { ).toPromise(); }); + it('rebuilds after errors in JIT', async () => { + const origContent = virtualFs.fileBufferToString( + host.scopedSync().read(normalize('src/app/app.component.ts'))); + host.appendToFile('./src/app/app.component.ts', `console.logg('error')`); + + const overrides = { watch: true, aot: false }; + let buildNumber = 0; + const logger = new logging.Logger(''); + let logs: string[] = []; + logger.subscribe(e => logs.push(e.message)); + + const run = await architect.scheduleTarget(target, overrides, { logger }); + await run.output.pipe( + debounceTime(1000), + tap((buildEvent) => { + buildNumber ++; + switch (buildNumber) { + case 1: + // The first build should error out with an error. + expect(buildEvent.success).toBe(false); + expect(logs.join()).toContain(`Property 'logg' does not exist on type 'Console'`); + logs = []; + // Fix the error. + host.writeMultipleFiles({ 'src/app/app.component.ts': ` + ${origContent} + console.errorr('error'); + `}); + break; + + case 2: + // The second build should have everything fixed. + expect(buildEvent.success).toBe(true); + expect(logs.join()).not.toContain('Module build failed'); + break; + } + }), + take(2), + ).toPromise(); + await run.stop(); + }); + it('rebuilds after errors in AOT', async () => { // Save the original contents of `./src/app/app.component.ts`. const origContent = virtualFs.fileBufferToString( diff --git a/packages/ngtools/webpack/src/angular_compiler_plugin.ts b/packages/ngtools/webpack/src/angular_compiler_plugin.ts index 1d5af7c2626a..31f01c23e79f 100644 --- a/packages/ngtools/webpack/src/angular_compiler_plugin.ts +++ b/packages/ngtools/webpack/src/angular_compiler_plugin.ts @@ -1195,7 +1195,7 @@ export class AngularCompilerPlugin { 'AngularCompilerPlugin._emit.ts', diagMode)); if (!hasErrors(allDiagnostics)) { - if (this._firstRun || changedTsFiles.size > 20) { + if (this._firstRun || changedTsFiles.size > 20 || this._emitSkipped) { emitResult = tsProgram.emit( undefined, undefined,