Skip to content

Commit 1d8c113

Browse files
authored
Refactor binary size script. (#4399)
Fixes the issue where the size job fails silently on CI due to unhandled promises.
1 parent e3c55b2 commit 1d8c113

File tree

1 file changed

+65
-89
lines changed

1 file changed

+65
-89
lines changed

scripts/size_report/report_binary_size.ts

Lines changed: 65 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -15,17 +15,20 @@
1515
* limitations under the License.
1616
*/
1717

18-
import { resolve as pathResolve } from 'path';
1918
import * as fs from 'fs';
20-
import { execSync } from 'child_process';
19+
import * as path from 'path';
20+
import * as rollup from 'rollup';
2121
import * as terser from 'terser';
22+
23+
import { execSync } from 'child_process';
2224
import {
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+
2932
import commonjs from '@rollup/plugin-commonjs';
3033

3134
interface Report {
@@ -37,10 +40,10 @@ interface BinarySizeRequestBody extends RequestBody {
3740
metric: string;
3841
results: Report[];
3942
}
40-
// CDN scripts
43+
4144
function 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
7072
async 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

168144
async function generateSizeReport(): Promise<BinarySizeRequestBody> {

0 commit comments

Comments
 (0)