voluptasmollitia
Version:
Monorepo for the Firebase JavaScript SDK
173 lines (151 loc) • 4.61 kB
text/typescript
/**
* @license
* Copyright 2020 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import * as fs from 'fs';
import * as path from 'path';
import * as rollup from 'rollup';
import * as terser from 'terser';
import { execSync } from 'child_process';
import {
upload,
runId,
RequestBody,
RequestEndpoint
} from './size_report_helper';
import { glob } from 'glob';
import commonjs from '@rollup/plugin-commonjs';
interface Report {
sdk: string;
type: string;
value: number;
}
interface BinarySizeRequestBody extends RequestBody {
metric: string;
results: Report[];
}
function generateReportForCDNScripts(): Report[] {
const reports = [];
const firebaseRoot = path.resolve(__dirname, '../../packages/firebase');
const pkgJson = require(`${firebaseRoot}/package.json`);
const special_files = [
'firebase-performance-standalone.es2017.js',
'firebase-performance-standalone.js',
'firebase-firestore.memory.js',
'firebase.js'
];
const files = [
...special_files.map((file: string) => `${firebaseRoot}/${file}`),
...pkgJson.components.map(
(component: string) => `${firebaseRoot}/firebase-${component}.js`
)
];
for (const file of files) {
const { size } = fs.statSync(file);
const fileName = file.split('/').slice(-1)[0];
reports.push({ sdk: 'firebase', type: fileName, value: size });
}
return reports;
}
async function generateReportForNPMPackages(): Promise<Report[]> {
const reports: Report[] = [];
const packageInfo = JSON.parse(
execSync('npx lerna ls --json --scope @firebase/*').toString()
);
for (const info of packageInfo) {
const packages = await findAllPackages(info.location);
for (const pkg of packages) {
reports.push(...(await collectBinarySize(pkg)));
}
}
return reports;
}
async function findAllPackages(root: string): Promise<string[]> {
return new Promise((resolve, reject) => {
glob(
'**/package.json',
{ cwd: root, ignore: '**/node_modules/**' },
(err, files) => {
if (err) {
reject(err);
} else {
resolve(files.map(x => path.resolve(root, x)));
}
}
);
});
}
async function collectBinarySize(pkg: string): Promise<Report[]> {
const reports: Report[] = [];
const fields = [
'main',
'module',
'esm2017',
'browser',
'react-native',
'lite',
'lite-esm2017'
];
const json = require(pkg);
for (const field of fields) {
if (json[field]) {
const artifact = path.resolve(path.dirname(pkg), json[field]);
// Need to create a bundle and get the size of the bundle instead of reading the size of the file directly.
// It is because some packages might be split into multiple files in order to share code between entry points.
const bundle = await rollup.rollup({
input: artifact,
plugins: [commonjs()]
});
const { output } = await bundle.generate({ format: 'es' });
const rawCode = output[0].code;
// remove comments and whitespaces, then get size
const { code } = await terser.minify(rawCode, {
format: {
comments: false
},
mangle: false,
compress: false
});
const size = Buffer.byteLength(code!, 'utf-8');
reports.push({ sdk: json.name, type: field, value: size });
}
}
return reports;
}
async function generateSizeReport(): Promise<BinarySizeRequestBody> {
const reports: Report[] = [
...generateReportForCDNScripts(),
...(await generateReportForNPMPackages())
];
for (const r of reports) {
console.log(r.sdk, r.type, r.value);
}
console.log(
`Github Action URL: https://github.com/${process.env.GITHUB_REPOSITORY}/actions/runs/${runId}`
);
return {
log: `https://github.com/${process.env.GITHUB_REPOSITORY}/actions/runs/${runId}`,
metric: 'BinarySize',
results: reports
};
}
generateSizeReport()
.then(report => {
upload(report, RequestEndpoint.BINARY_SIZE);
})
.catch(err => {
console.error(err);
process.exit(1);
});