15
15
* limitations under the License.
16
16
*/
17
17
18
- import { resolve as pathResolve } from 'path' ;
19
18
import * as fs from 'fs' ;
20
- import { execSync } from 'child_process' ;
19
+ import * as path from 'path' ;
20
+ import * as rollup from 'rollup' ;
21
21
import * as terser from 'terser' ;
22
+
23
+ import { execSync } from 'child_process' ;
22
24
import {
23
25
upload ,
24
26
runId ,
25
27
RequestBody ,
26
28
RequestEndpoint
27
29
} from './size_report_helper' ;
28
- import * as rollup from 'rollup' ;
30
+ import { glob } from 'glob' ;
31
+
29
32
import commonjs from '@rollup/plugin-commonjs' ;
30
33
31
34
interface Report {
@@ -37,10 +40,10 @@ interface BinarySizeRequestBody extends RequestBody {
37
40
metric : string ;
38
41
results : Report [ ] ;
39
42
}
40
- // CDN scripts
43
+
41
44
function generateReportForCDNScripts ( ) : Report [ ] {
42
45
const reports = [ ] ;
43
- const firebaseRoot = pathResolve ( __dirname , '../../packages/firebase' ) ;
46
+ const firebaseRoot = path . resolve ( __dirname , '../../packages/firebase' ) ;
44
47
const pkgJson = require ( `${ firebaseRoot } /package.json` ) ;
45
48
46
49
const special_files = [
@@ -60,109 +63,82 @@ function generateReportForCDNScripts(): Report[] {
60
63
for ( const file of files ) {
61
64
const { size } = fs . statSync ( file ) ;
62
65
const fileName = file . split ( '/' ) . slice ( - 1 ) [ 0 ] ;
63
- reports . push ( makeReportObject ( 'firebase' , fileName , size ) ) ;
66
+ reports . push ( { sdk : 'firebase' , type : fileName , value : size } ) ;
64
67
}
65
68
66
69
return reports ;
67
70
}
68
71
69
- // NPM packages
70
72
async function generateReportForNPMPackages ( ) : Promise < Report [ ] > {
71
73
const reports : Report [ ] = [ ] ;
72
- const fields = [
73
- 'main' ,
74
- 'module' ,
75
- 'esm2017' ,
76
- 'browser' ,
77
- 'react-native' ,
78
- 'lite' ,
79
- 'lite-esm2017'
80
- ] ;
81
-
82
74
const packageInfo = JSON . parse (
83
75
execSync ( 'npx lerna ls --json --scope @firebase/*' ) . toString ( )
84
76
) ;
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
+ }
91
82
}
92
-
93
- await Promise . all ( taskPromises ) ;
94
-
95
83
return reports ;
84
+ }
96
85
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 ) ) ) ;
130
96
}
131
97
}
132
-
133
- resolve ( ) ;
134
- } ) ;
135
- taskPromises . push ( promise ) ;
136
- }
98
+ ) ;
99
+ } ) ;
137
100
}
138
101
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 } ) ;
156
139
}
157
140
}
158
- }
159
-
160
- function makeReportObject ( sdk : string , type : string , value : number ) : Report {
161
- return {
162
- sdk,
163
- type,
164
- value
165
- } ;
141
+ return reports ;
166
142
}
167
143
168
144
async function generateSizeReport ( ) : Promise < BinarySizeRequestBody > {
0 commit comments