1717 * under the License.
1818 */
1919
20+ import Fs from 'fs' ;
21+ import Path from 'path' ;
22+
2023import { materialize , mergeMap , dematerialize } from 'rxjs/operators' ;
2124import { CiStatsReporter } from '@kbn/dev-utils' ;
2225
2326import { OptimizerUpdate$ } from './run_optimizer' ;
2427import { OptimizerState , OptimizerConfig } from './optimizer' ;
2528import { pipeClosure } from './common' ;
2629
30+ const flatten = < T > ( arr : Array < T | T [ ] > ) : T [ ] =>
31+ arr . reduce ( ( acc : T [ ] , item ) => acc . concat ( item ) , [ ] ) ;
32+
33+ interface Entry {
34+ relPath : string ;
35+ stats : Fs . Stats ;
36+ }
37+
38+ const getFiles = ( dir : string , parent ?: string ) =>
39+ flatten (
40+ Fs . readdirSync ( dir ) . map ( ( name ) : Entry | Entry [ ] => {
41+ const absPath = Path . join ( dir , name ) ;
42+ const relPath = parent ? Path . join ( parent , name ) : name ;
43+ const stats = Fs . statSync ( absPath ) ;
44+
45+ if ( stats . isDirectory ( ) ) {
46+ return getFiles ( absPath , relPath ) ;
47+ }
48+
49+ return {
50+ relPath,
51+ stats,
52+ } ;
53+ } )
54+ ) ;
55+
2756export function reportOptimizerStats ( reporter : CiStatsReporter , config : OptimizerConfig ) {
2857 return pipeClosure ( ( update$ : OptimizerUpdate$ ) => {
2958 let lastState : OptimizerState | undefined ;
@@ -36,16 +65,55 @@ export function reportOptimizerStats(reporter: CiStatsReporter, config: Optimize
3665
3766 if ( n . kind === 'C' && lastState ) {
3867 await reporter . metrics (
39- config . bundles . map ( ( bundle ) => {
40- // make the cache read from the cache file since it was likely updated by the worker
41- bundle . cache . refresh ( ) ;
42-
43- return {
44- group : `@kbn/optimizer bundle module count` ,
45- id : bundle . id ,
46- value : bundle . cache . getModuleCount ( ) || 0 ,
47- } ;
48- } )
68+ flatten (
69+ config . bundles . map ( ( bundle ) => {
70+ // make the cache read from the cache file since it was likely updated by the worker
71+ bundle . cache . refresh ( ) ;
72+
73+ const outputFiles = getFiles ( bundle . outputDir ) . filter (
74+ ( file ) => ! ( file . relPath . startsWith ( '.' ) || file . relPath . endsWith ( '.map' ) )
75+ ) ;
76+
77+ const entryName = `${ bundle . id } .${ bundle . type } .js` ;
78+ const entry = outputFiles . find ( ( f ) => f . relPath === entryName ) ;
79+ if ( ! entry ) {
80+ throw new Error (
81+ `Unable to find bundle entry named [${ entryName } ] in [${ bundle . outputDir } ]`
82+ ) ;
83+ }
84+
85+ const chunkPrefix = `${ bundle . id } .chunk.` ;
86+ const asyncChunks = outputFiles . filter ( ( f ) => f . relPath . startsWith ( chunkPrefix ) ) ;
87+ const miscFiles = outputFiles . filter (
88+ ( f ) => f !== entry && ! asyncChunks . includes ( f )
89+ ) ;
90+ const sumSize = ( files : Entry [ ] ) =>
91+ files . reduce ( ( acc : number , f ) => acc + f . stats ! . size , 0 ) ;
92+
93+ return [
94+ {
95+ group : `@kbn/optimizer bundle module count` ,
96+ id : bundle . id ,
97+ value : bundle . cache . getModuleCount ( ) || 0 ,
98+ } ,
99+ {
100+ group : `page load bundle size` ,
101+ id : bundle . id ,
102+ value : entry . stats ! . size ,
103+ } ,
104+ {
105+ group : `async chunks size` ,
106+ id : bundle . id ,
107+ value : sumSize ( asyncChunks ) ,
108+ } ,
109+ {
110+ group : `miscellaneous assets size` ,
111+ id : bundle . id ,
112+ value : sumSize ( miscFiles ) ,
113+ } ,
114+ ] ;
115+ } )
116+ )
49117 ) ;
50118 }
51119
0 commit comments