@@ -51,6 +51,8 @@ import {
51
51
import { readTsconfig } from '../angular-cli-files/utilities/read-tsconfig' ;
52
52
import { augmentAppWithServiceWorker } from '../angular-cli-files/utilities/service-worker' ;
53
53
import {
54
+ generateBuildStats ,
55
+ generateBundleStats ,
54
56
statsErrorsToString ,
55
57
statsToString ,
56
58
statsWarningsToString ,
@@ -64,7 +66,12 @@ import {
64
66
normalizeSourceMaps ,
65
67
} from '../utils' ;
66
68
import { manglingDisabled } from '../utils/mangle-options' ;
67
- import { CacheKey , ProcessBundleOptions , ProcessBundleResult } from '../utils/process-bundle' ;
69
+ import {
70
+ CacheKey ,
71
+ ProcessBundleFile ,
72
+ ProcessBundleOptions ,
73
+ ProcessBundleResult ,
74
+ } from '../utils/process-bundle' ;
68
75
import { assertCompatibleAngularVersion } from '../utils/version' ;
69
76
import {
70
77
generateBrowserWebpackConfigFromContext ,
@@ -202,9 +209,6 @@ export function buildWebpackBrowser(
202
209
// Check Angular version.
203
210
assertCompatibleAngularVersion ( context . workspaceRoot , context . logger ) ;
204
211
205
- const loggingFn =
206
- transforms . logging || createBrowserLoggingCallback ( ! ! options . verbose , context . logger ) ;
207
-
208
212
return from ( initialize ( options , context , host , transforms . webpackConfiguration ) ) . pipe (
209
213
// tslint:disable-next-line: no-big-function
210
214
switchMap ( ( { config : configs , projectRoot } ) => {
@@ -222,14 +226,24 @@ export function buildWebpackBrowser(
222
226
` ) ;
223
227
}
224
228
229
+ const useBundleDownleveling =
230
+ isDifferentialLoadingNeeded && ! ( fullDifferential || options . watch ) ;
231
+ const startTime = Date . now ( ) ;
232
+
225
233
return from ( configs ) . pipe (
226
234
// the concurrency parameter (3rd parameter of mergeScan) is deliberately
227
235
// set to 1 to make sure the build steps are executed in sequence.
228
236
mergeScan (
229
237
( lastResult , config ) => {
230
238
// Make sure to only run the 2nd build step, if 1st one succeeded
231
239
if ( lastResult . success ) {
232
- return runWebpack ( config , context , { logging : loggingFn } ) ;
240
+ return runWebpack ( config , context , {
241
+ logging :
242
+ transforms . logging ||
243
+ ( useBundleDownleveling
244
+ ? ( ) => { }
245
+ : createBrowserLoggingCallback ( ! ! options . verbose , context . logger ) ) ,
246
+ } ) ;
233
247
} else {
234
248
return of ( ) ;
235
249
}
@@ -242,7 +256,19 @@ export function buildWebpackBrowser(
242
256
switchMap ( async buildEvents => {
243
257
configs . length = 0 ;
244
258
const success = buildEvents . every ( r => r . success ) ;
245
- if ( success ) {
259
+ if ( ! success && useBundleDownleveling ) {
260
+ // If using bundle downleveling then there is only one build
261
+ // If it fails show any diagnostic messages and bail
262
+ const webpackStats = buildEvents [ 0 ] . webpackStats ;
263
+ if ( webpackStats && webpackStats . warnings . length > 0 ) {
264
+ context . logger . warn ( statsWarningsToString ( webpackStats , { colors : true } ) ) ;
265
+ }
266
+ if ( webpackStats && webpackStats . errors . length > 0 ) {
267
+ context . logger . error ( statsErrorsToString ( webpackStats , { colors : true } ) ) ;
268
+ }
269
+
270
+ return { success } ;
271
+ } else if ( success ) {
246
272
let noModuleFiles : EmittedFiles [ ] | undefined ;
247
273
let moduleFiles : EmittedFiles [ ] | undefined ;
248
274
let files : EmittedFiles [ ] | undefined ;
@@ -263,7 +289,7 @@ export function buildWebpackBrowser(
263
289
noModuleFiles = secondBuild . emittedFiles ;
264
290
}
265
291
} else if ( isDifferentialLoadingNeeded && ! fullDifferential ) {
266
- const { emittedFiles = [ ] } = firstBuild ;
292
+ const { emittedFiles = [ ] , webpackStats } = firstBuild ;
267
293
moduleFiles = [ ] ;
268
294
noModuleFiles = [ ] ;
269
295
@@ -342,7 +368,9 @@ export function buildWebpackBrowser(
342
368
filename,
343
369
code,
344
370
map,
345
- name : file . name ,
371
+ // id is always present for non-assets
372
+ // tslint:disable-next-line: no-non-null-assertion
373
+ name : file . id ! ,
346
374
optimizeOnly : true ,
347
375
} ) ;
348
376
@@ -356,7 +384,9 @@ export function buildWebpackBrowser(
356
384
filename,
357
385
code,
358
386
map,
359
- name : file . name ,
387
+ // id is always present for non-assets
388
+ // tslint:disable-next-line: no-non-null-assertion
389
+ name : file . id ! ,
360
390
runtime : file . file . startsWith ( 'runtime' ) ,
361
391
ignoreOriginal : es5Polyfills ,
362
392
} ) ;
@@ -600,6 +630,73 @@ export function buildWebpackBrowser(
600
630
}
601
631
602
632
context . logger . info ( 'ES5 bundle generation complete.' ) ;
633
+
634
+ type ArrayElement < A > = A extends ReadonlyArray < infer T > ? T : never ;
635
+ function generateBundleInfoStats (
636
+ id : string | number ,
637
+ bundle : ProcessBundleFile ,
638
+ chunk : ArrayElement < webpack . Stats . ToJsonOutput [ 'chunks' ] > | undefined ,
639
+ ) : string {
640
+ return generateBundleStats (
641
+ {
642
+ id,
643
+ size : bundle . size ,
644
+ files : bundle . map ? [ bundle . filename , bundle . map . filename ] : [ bundle . filename ] ,
645
+ names : chunk && chunk . names ,
646
+ entry : ! ! chunk && chunk . names . includes ( 'runtime' ) ,
647
+ initial : ! ! chunk && chunk . initial ,
648
+ rendered : true ,
649
+ } ,
650
+ true ,
651
+ ) ;
652
+ }
653
+
654
+ let bundleInfoText = '' ;
655
+ const processedNames = new Set < string > ( ) ;
656
+ for ( const result of processResults ) {
657
+ processedNames . add ( result . name ) ;
658
+
659
+ const chunk =
660
+ webpackStats &&
661
+ webpackStats . chunks &&
662
+ webpackStats . chunks . find ( c => result . name === c . id . toString ( ) ) ;
663
+ if ( result . original ) {
664
+ bundleInfoText +=
665
+ '\n' + generateBundleInfoStats ( result . name , result . original , chunk ) ;
666
+ }
667
+ if ( result . downlevel ) {
668
+ bundleInfoText +=
669
+ '\n' + generateBundleInfoStats ( result . name , result . downlevel , chunk ) ;
670
+ }
671
+ }
672
+
673
+ if ( webpackStats && webpackStats . chunks ) {
674
+ for ( const chunk of webpackStats . chunks ) {
675
+ if ( processedNames . has ( chunk . id . toString ( ) ) ) {
676
+ continue ;
677
+ }
678
+
679
+ const asset =
680
+ webpackStats . assets && webpackStats . assets . find ( a => a . name === chunk . files [ 0 ] ) ;
681
+ bundleInfoText +=
682
+ '\n' + generateBundleStats ( { ...chunk , size : asset && asset . size } , true ) ;
683
+ }
684
+ }
685
+
686
+ bundleInfoText +=
687
+ '\n' +
688
+ generateBuildStats (
689
+ ( webpackStats && webpackStats . hash ) || '<unknown>' ,
690
+ Date . now ( ) - startTime ,
691
+ true ,
692
+ ) ;
693
+ context . logger . info ( bundleInfoText ) ;
694
+ if ( webpackStats && webpackStats . warnings . length > 0 ) {
695
+ context . logger . warn ( statsWarningsToString ( webpackStats , { colors : true } ) ) ;
696
+ }
697
+ if ( webpackStats && webpackStats . errors . length > 0 ) {
698
+ context . logger . error ( statsErrorsToString ( webpackStats , { colors : true } ) ) ;
699
+ }
603
700
} else {
604
701
const { emittedFiles = [ ] } = firstBuild ;
605
702
files = emittedFiles . filter ( x => x . name !== 'polyfills-es5' ) ;
0 commit comments