Files
react/scripts/bench/build.js
Dominic Gannaway a7d8ebd2b5 Add React benchmarking infrastructure (#9465)
* Initial commit for WIP benchmarking infrastructure

* fixed lint issues and ran prettier

* added <rootDir>/scripts/bench/ to ignore paths for Jest

* tidied up code and fixed a few bugs in the runner.js

* fixed eslint

* improved the benchmark output from the runner

* fixed typo

* tided up print output in runner.js

* throw error if chrome canary is not installed on mac

* added better bench stats output (tables)

* added benchmark diff to table results

* adds bundle size comparisons to results

* tidied up the results

* fixed prettier output

* attempt to trigger bech for circleci build

* fixes flow exlclusion for lighthouse module

* added class components benchmark

* cleaned up stats.js

* stability changes

* circleci node version to 7

* added another benchmark

* added colours to the different benchmarks to check if being cached

* force no-cache headers

* added more info messages

* refactor chrome launching.

* fixed an issue where launcher.kill might fail

* Move server to runner. Launch it only once.

* tidy up

* changes the logic in how the remote repo is checked out

* removes bench from circleci build

* removed colors from benchmarks (no longer needed)

* added CI integration comment

* added hacker news benchmark

* added skipBuild functionality

* relabelled remote

* Add confidence intervals

* added first meaningful paint

* removed some unused code

* reverted code.json

* updated benchmark runs back to 10

* no longer breaks when results contain missing bundles

* adds CPU throttling

* renamed build to remote-repo

* small fix to build

* fixed bad merge

* upped runs to 10 from 2 again

* properly pulls master

* removes old-bench

* runs benchmarks in headless mode

* adds a --headless option

* improved the git build process

* added README

* updated based feedback from review

* adds merge base commit sha

* addressing more PR feedback

* remove built JS react files

* updated .gitignore

* added combined bundle load times to the metrics
2017-05-09 17:13:54 +01:00

129 lines
3.5 KiB
JavaScript

'use strict';
const Git = require('nodegit');
const rimraf = require('rimraf');
const ncp = require('ncp').ncp;
const {
existsSync,
} = require('fs');
const exec = require('child_process').exec;
const {
join,
} = require('path');
const reactUrl = 'https://github.com/facebook/react.git';
function cleanDir() {
return new Promise(_resolve => rimraf('remote-repo', _resolve));
}
function executeCommand(command) {
return new Promise(_resolve => exec(command, (error) => {
if (!error) {
_resolve();
} else {
console.error(error);
process.exit(1);
}
}));
}
function asyncCopyTo(from, to) {
return new Promise(_resolve => {
ncp(from, to, error => {
if (error) {
console.error(error);
process.exit(1);
}
_resolve();
});
});
}
function getDefaultReactPath() {
return join(__dirname, 'remote-repo');
}
async function buldAllBundles(reactPath = getDefaultReactPath()) {
// build the react FB bundles in the build
await executeCommand(`cd ${reactPath} && yarn && yarn build`);
}
async function buildBenchmark(reactPath = getDefaultReactPath(), benchmark) {
// get the build.js from the benchmark directory and execute it
await require(
join(__dirname, 'benchmarks', benchmark, 'build.js')
)(reactPath, asyncCopyTo);
}
function getBundleResults(reactPath = getDefaultReactPath()) {
return require(join(reactPath, 'scripts', 'rollup', 'results.json'));
}
async function getMergeBaseFromLocalGitRepo(localRepo) {
const repo = await Git.Repository.open(localRepo);
return await Git.Merge.base(
repo,
await repo.getHeadCommit(),
await repo.getBranchCommit('master')
);
}
async function buildBenchmarkBundlesFromGitRepo(commitId, skipBuild, url = reactUrl, clean) {
let repo;
const remoteRepoDir = getDefaultReactPath();
if (!skipBuild) {
if (clean) {
//clear remote-repo folder
await cleanDir(remoteRepoDir);
}
// check if remote-repo diretory already exists
if (existsSync(join(__dirname, 'remote-repo'))) {
repo = await Git.Repository.open(remoteRepoDir);
// fetch all the latest remote changes
await repo.fetchAll();
} else {
// if not, clone the repo to remote-repo folder
repo = await Git.Clone(url, remoteRepoDir);
}
let commit = await repo.getBranchCommit('master');
// reset hard to this remote head
await Git.Reset.reset(repo, commit, Git.Reset.TYPE.HARD);
// then we checkout the latest master head
await repo.checkoutBranch('master');
// make sure we pull in the latest changes
await repo.mergeBranches('master', 'origin/master');
// then we check if we need to move the HEAD to the merge base
if (commitId && commitId !== 'master') {
// as the commitId probably came from our local repo
// we use it to lookup the right commit in our remote repo
commit = await Git.Commit.lookup(repo, commitId);
// then we checkout the merge base
await Git.Checkout.tree(repo, commit);
}
await buildAllBundles();
}
return getBundleResults();
}
async function buildAllBundles(reactPath, skipBuild) {
if (!skipBuild) {
// build all bundles so we can get all stats and use bundles for benchmarks
await buldAllBundles(reactPath);
}
return getBundleResults(reactPath);
}
// if run directly via CLI
if (require.main === module) {
buildBenchmarkBundlesFromGitRepo();
}
module.exports = {
buildAllBundles,
buildBenchmark,
buildBenchmarkBundlesFromGitRepo,
getMergeBaseFromLocalGitRepo,
};