1515 * limitations under the License.
1616 */
1717
18- import { resolve as pathResolve } from 'path' ;
1918import * as fs from 'fs' ;
20- import { execSync } from 'child_process' ;
19+ import * as path from 'path' ;
20+ import * as rollup from 'rollup' ;
2121import * as terser from 'terser' ;
22+
23+ import { execSync } from 'child_process' ;
2224import {
2325 upload ,
2426 runId ,
2527 RequestBody ,
2628 RequestEndpoint
2729} from './size_report_helper' ;
28- import * as rollup from 'rollup' ;
30+ import { glob } from 'glob' ;
31+
2932import commonjs from '@rollup/plugin-commonjs' ;
3033
3134interface Report {
@@ -37,10 +40,10 @@ interface BinarySizeRequestBody extends RequestBody {
3740 metric : string ;
3841 results : Report [ ] ;
3942}
40- // CDN scripts
43+
4144function generateReportForCDNScripts ( ) : Report [ ] {
4245 const reports = [ ] ;
43- const firebaseRoot = pathResolve ( __dirname , '../../packages/firebase' ) ;
46+ const firebaseRoot = path . resolve ( __dirname , '../../packages/firebase' ) ;
4447 const pkgJson = require ( `${ firebaseRoot } /package.json` ) ;
4548
4649 const special_files = [
@@ -60,109 +63,82 @@ function generateReportForCDNScripts(): Report[] {
6063 for ( const file of files ) {
6164 const { size } = fs . statSync ( file ) ;
6265 const fileName = file . split ( '/' ) . slice ( - 1 ) [ 0 ] ;
63- reports . push ( makeReportObject ( 'firebase' , fileName , size ) ) ;
66+ reports . push ( { sdk : 'firebase' , type : fileName , value : size } ) ;
6467 }
6568
6669 return reports ;
6770}
6871
69- // NPM packages
7072async function generateReportForNPMPackages ( ) : Promise < Report [ ] > {
7173 const reports : Report [ ] = [ ] ;
72- const fields = [
73- 'main' ,
74- 'module' ,
75- 'esm2017' ,
76- 'browser' ,
77- 'react-native' ,
78- 'lite' ,
79- 'lite-esm2017'
80- ] ;
81-
8274 const packageInfo = JSON . parse (
8375 execSync ( 'npx lerna ls --json --scope @firebase/*' ) . toString ( )
8476 ) ;
85-
86- const taskPromises : Promise < void > [ ] = [ ] ;
87- for ( const pkg of packageInfo ) {
88- // we traverse the dir in order to include binaries for submodules, e.g. @firebase/firestore/memory
89- // Currently we only traverse 1 level deep because we don't have any submodule deeper than that.
90- traverseDirs ( pkg . location , collectBinarySize , 0 , 1 ) ;
77+ for ( const info of packageInfo ) {
78+ const packages = await findAllPackages ( info . location ) ;
79+ for ( const pkg of packages ) {
80+ reports . push ( ...( await collectBinarySize ( pkg ) ) ) ;
81+ }
9182 }
92-
93- await Promise . all ( taskPromises ) ;
94-
9583 return reports ;
84+ }
9685
97- function collectBinarySize ( path : string ) {
98- const packageJsonPath = `${ path } /package.json` ;
99- if ( ! fs . existsSync ( packageJsonPath ) ) {
100- return ;
101- }
102-
103- const promise = new Promise < void > ( async resolve => {
104- const packageJson = require ( packageJsonPath ) ;
105-
106- for ( const field of fields ) {
107- if ( packageJson [ field ] ) {
108- const filePath = pathResolve ( path , packageJson [ field ] ) ;
109- // Need to create a bundle and get the size of the bundle instead of reading the size of the file directly.
110- // It is because some packages might be split into multiple files in order to share code between entry points.
111- const bundle = await rollup . rollup ( {
112- input : filePath ,
113- plugins : [ commonjs ( ) ]
114- } ) ;
115-
116- const { output } = await bundle . generate ( { format : 'es' } ) ;
117- const rawCode = output [ 0 ] . code ;
118-
119- // remove comments and whitespaces, then get size
120- const { code } = await terser . minify ( rawCode , {
121- format : {
122- comments : false
123- } ,
124- mangle : false ,
125- compress : false
126- } ) ;
127-
128- const size = Buffer . byteLength ( code ! , 'utf-8' ) ;
129- reports . push ( makeReportObject ( packageJson . name , field , size ) ) ;
86+ async function findAllPackages ( root : string ) : Promise < string [ ] > {
87+ return new Promise ( ( resolve , reject ) => {
88+ glob (
89+ '**/package.json' ,
90+ { cwd : root , ignore : '**/node_modules/**' } ,
91+ ( err , files ) => {
92+ if ( err ) {
93+ reject ( err ) ;
94+ } else {
95+ resolve ( files . map ( x => path . resolve ( root , x ) ) ) ;
13096 }
13197 }
132-
133- resolve ( ) ;
134- } ) ;
135- taskPromises . push ( promise ) ;
136- }
98+ ) ;
99+ } ) ;
137100}
138101
139- function traverseDirs (
140- path : string ,
141- executor : Function ,
142- level : number ,
143- levelLimit : number
144- ) {
145- if ( level > levelLimit ) {
146- return ;
147- }
148-
149- executor ( path ) ;
150-
151- for ( const name of fs . readdirSync ( path ) ) {
152- const p = `${ path } /${ name } ` ;
153-
154- if ( fs . lstatSync ( p ) . isDirectory ( ) ) {
155- traverseDirs ( p , executor , level + 1 , levelLimit ) ;
102+ async function collectBinarySize ( pkg : string ) : Promise < Report [ ] > {
103+ const reports : Report [ ] = [ ] ;
104+ const fields = [
105+ 'main' ,
106+ 'module' ,
107+ 'esm2017' ,
108+ 'browser' ,
109+ 'react-native' ,
110+ 'lite' ,
111+ 'lite-esm2017'
112+ ] ;
113+ const json = require ( pkg ) ;
114+ for ( const field of fields ) {
115+ if ( json [ field ] ) {
116+ const artifact = path . resolve ( path . dirname ( pkg ) , json [ field ] ) ;
117+
118+ // Need to create a bundle and get the size of the bundle instead of reading the size of the file directly.
119+ // It is because some packages might be split into multiple files in order to share code between entry points.
120+ const bundle = await rollup . rollup ( {
121+ input : artifact ,
122+ plugins : [ commonjs ( ) ]
123+ } ) ;
124+
125+ const { output } = await bundle . generate ( { format : 'es' } ) ;
126+ const rawCode = output [ 0 ] . code ;
127+
128+ // remove comments and whitespaces, then get size
129+ const { code } = await terser . minify ( rawCode , {
130+ format : {
131+ comments : false
132+ } ,
133+ mangle : false ,
134+ compress : false
135+ } ) ;
136+
137+ const size = Buffer . byteLength ( code ! , 'utf-8' ) ;
138+ reports . push ( { sdk : json . name , type : field , value : size } ) ;
156139 }
157140 }
158- }
159-
160- function makeReportObject ( sdk : string , type : string , value : number ) : Report {
161- return {
162- sdk,
163- type,
164- value
165- } ;
141+ return reports ;
166142}
167143
168144async function generateSizeReport ( ) : Promise < BinarySizeRequestBody > {
0 commit comments