diff --git a/dangerfile.js b/dangerfile.js
index cb7f9a190c..515e09536e 100644
--- a/dangerfile.js
+++ b/dangerfile.js
@@ -7,6 +7,8 @@
'use strict';
+/* eslint-disable no-for-of-loops/no-for-of-loops */
+
// Hi, if this is your first time editing/reading a Dangerfile, here's a summary:
// It's a JS runtime which helps you provide continuous feedback inside GitHub.
//
@@ -26,169 +28,65 @@
// `DANGER_GITHUB_API_TOKEN=[ENV_ABOVE] yarn danger pr https://github.com/facebook/react/pull/11865
const {markdown, danger, warn} = require('danger');
+const {promisify} = require('util');
+const glob = promisify(require('glob'));
+const gzipSize = require('gzip-size');
-const {generateResultsArray} = require('./scripts/rollup/stats');
-const {readFileSync, readdirSync} = require('fs');
-const path = require('path');
+const {readFileSync, statSync} = require('fs');
-/**
- * Generates a Markdown table
- * @param {string[]} headers
- * @param {string[][]} body
- */
-function generateMDTable(headers, body) {
- const tableHeaders = [
- headers.join(' | '),
- headers.map(() => ' --- ').join(' | '),
- ];
+const BASE_DIR = 'base-build';
+const HEAD_DIR = 'build2';
- const tablebody = body.map(r => r.join(' | '));
- return tableHeaders.join('\n') + '\n' + tablebody.join('\n');
+const CRITICAL_THRESHOLD = 0.02;
+const SIGNIFICANCE_THRESHOLD = 0.002;
+const CRITICAL_ARTIFACT_PATHS = new Set([
+ // We always report changes to these bundles, even if the change is
+ // insiginificant or non-existent.
+ 'oss-stable/react-dom/cjs/react-dom.production.min.js',
+ 'oss-experimental/react-dom/cjs/react-dom.production.min.js',
+ 'facebook-www/ReactDOM-prod.classic.js',
+ 'facebook-www/ReactDOM-prod.modern.js',
+ 'facebook-www/ReactDOMForked-prod.classic.js',
+]);
+
+const kilobyteFormatter = new Intl.NumberFormat('en', {
+ style: 'unit',
+ unit: 'kilobyte',
+ minimumFractionDigits: 2,
+ maximumFractionDigits: 2,
+});
+
+function kbs(bytes) {
+ return kilobyteFormatter.format(bytes / 1000);
}
-/**
- * Generates a user-readable string from a percentage change
- * @param {number} change
- * @param {boolean} includeEmoji
- */
-function addPercent(change, includeEmoji) {
- if (!isFinite(change)) {
- // When a new package is created
- return 'n/a';
+const percentFormatter = new Intl.NumberFormat('en', {
+ style: 'percent',
+ signDisplay: 'exceptZero',
+ minimumFractionDigits: 2,
+ maximumFractionDigits: 2,
+});
+
+function change(decimal) {
+ if (Number === Infinity) {
+ return 'New file';
}
- const formatted = (change * 100).toFixed(1);
- if (/^-|^0(?:\.0+)$/.test(formatted)) {
- return `${formatted}%`;
- } else {
- if (includeEmoji) {
- return `:small_red_triangle:+${formatted}%`;
- } else {
- return `+${formatted}%`;
- }
+ if (decimal === -1) {
+ return 'Deleted';
}
+ if (decimal < 0.0001) {
+ return '=';
+ }
+ return percentFormatter.format(decimal);
}
-function setBoldness(row, isBold) {
- if (isBold) {
- return row.map(element => `**${element}**`);
- } else {
- return row;
- }
-}
+const header = `
+ | Name | +/- | Base | Current | +/- gzip | Base gzip | Current gzip |
+ | ---- | --- | ---- | ------- | -------- | --------- | ------------ |`;
-function getBundleSizes(pathToSizesDir) {
- const filenames = readdirSync(pathToSizesDir);
- let bundleSizes = [];
- for (let i = 0; i < filenames.length; i++) {
- const filename = filenames[i];
- if (filename.endsWith('.json')) {
- const json = readFileSync(path.join(pathToSizesDir, filename));
- bundleSizes.push(...JSON.parse(json).bundleSizes);
- }
- }
- return {bundleSizes};
-}
-
-async function printResultsForChannel(baseResults, headResults) {
- // Take the JSON of the build response and
- // make an array comparing the results for printing
- const results = generateResultsArray(headResults, baseResults);
-
- const packagesToShow = results
- .filter(
- r =>
- Math.abs(r.prevFileSizeAbsoluteChange) >= 300 || // bytes
- Math.abs(r.prevGzipSizeAbsoluteChange) >= 100 // bytes
- )
- .map(r => r.packageName);
-
- if (packagesToShow.length) {
- let allTables = [];
-
- // Highlight React and React DOM changes inline
- // e.g. react: `react.production.min.js`: -3%, `react.development.js`: +4%
-
- if (packagesToShow.includes('react')) {
- const reactProd = results.find(
- r => r.bundleType === 'UMD_PROD' && r.packageName === 'react'
- );
- if (
- reactProd.prevFileSizeChange !== 0 ||
- reactProd.prevGzipSizeChange !== 0
- ) {
- const changeSize = addPercent(reactProd.prevFileSizeChange, true);
- const changeGzip = addPercent(reactProd.prevGzipSizeChange, true);
- markdown(`React: size: ${changeSize}, gzip: ${changeGzip}`);
- }
- }
-
- if (packagesToShow.includes('react-dom')) {
- const reactDOMProd = results.find(
- r => r.bundleType === 'UMD_PROD' && r.packageName === 'react-dom'
- );
- if (
- reactDOMProd.prevFileSizeChange !== 0 ||
- reactDOMProd.prevGzipSizeChange !== 0
- ) {
- const changeSize = addPercent(reactDOMProd.prevFileSizeChange, true);
- const changeGzip = addPercent(reactDOMProd.prevGzipSizeChange, true);
- markdown(`ReactDOM: size: ${changeSize}, gzip: ${changeGzip}`);
- }
- }
-
- // Show a hidden summary table for all diffs
-
- // eslint-disable-next-line no-var,no-for-of-loops/no-for-of-loops
- for (var name of new Set(packagesToShow)) {
- const thisBundleResults = results.filter(r => r.packageName === name);
- const changedFiles = thisBundleResults.filter(
- r => r.prevFileSizeChange !== 0 || r.prevGzipSizeChange !== 0
- );
-
- const mdHeaders = [
- 'File',
- 'Filesize Diff',
- 'Gzip Diff',
- 'Prev Size',
- 'Current Size',
- 'Prev Gzip',
- 'Current Gzip',
- 'ENV',
- ];
-
- const mdRows = changedFiles.map(r => {
- const isProd = r.bundleType.includes('PROD');
- return setBoldness(
- [
- r.filename,
- addPercent(r.prevFileSizeChange, isProd),
- addPercent(r.prevGzipSizeChange, isProd),
- r.prevSize,
- r.prevFileSize,
- r.prevGzip,
- r.prevGzipSize,
- r.bundleType,
- ],
- isProd
- );
- });
-
- allTables.push(`\n## ${name}`);
- allTables.push(generateMDTable(mdHeaders, mdRows));
- }
-
- const summary = `
- Details of bundled changes.
-
- ${allTables.join('\n')}
-
-
Comparing: ${baseSha}...${headSha}
+## Critical size changes -### Stable channel +Includes critical production bundles, as well as any change greater than ${CRITICAL_THRESHOLD * + 100}%: -${await printResultsForChannel(baseSizesStable, headSizesStable)} +${header} +${criticalResults.join('\n')} -### Experimental channel +## Significant size changes -${await printResultsForChannel(baseSizesExperimental, headSizesExperimental)} +Includes any change greater than ${SIGNIFICANCE_THRESHOLD * 100}%: + +${ + significantResults.length > 0 + ? ` +