mirror of
https://github.com/zhigang1992/create-react-app.git
synced 2026-01-12 22:46:30 +08:00
extract generic build functions to react-dev-utils (#1726)
* Temp rename * Rename to change the case * extract generic build functions to react-dev-utils * tweak package json files and move removeFileNameHash * revert removeFileNameHash * use paths.appBuild in printFileSizes * use paths.appBuild in removeFileNameHash * change curried functions to regular functions * add fs-extra to react-dev-utils deps * move getDifferenceLabel inside printFileSizes * inline copyPublicFolder * combine printFileSizes and removeFileNameHash to fileSizeReporter * fix typo * Tweak APIs and fix issues * Fix heading * Remove missing file * Newline * Newline * Trailing space * Update FileSizeReporter.js * Update build.js
This commit is contained in:
committed by
Dan Abramov
parent
3fa5e8e7d7
commit
fbdff9d722
109
packages/react-dev-utils/FileSizeReporter.js
vendored
Normal file
109
packages/react-dev-utils/FileSizeReporter.js
vendored
Normal file
@@ -0,0 +1,109 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
var fs = require('fs');
|
||||
var path = require('path');
|
||||
var chalk = require('chalk');
|
||||
var filesize = require('filesize');
|
||||
var recursive = require('recursive-readdir');
|
||||
var stripAnsi = require('strip-ansi');
|
||||
var gzipSize = require('gzip-size').sync;
|
||||
|
||||
// Prints a detailed summary of build files.
|
||||
function printFileSizesAfterBuild(webpackStats, previousSizeMap) {
|
||||
var root = previousSizeMap.root;
|
||||
var sizes = previousSizeMap.sizes;
|
||||
var assets = webpackStats
|
||||
.toJson()
|
||||
.assets.filter(asset => /\.(js|css)$/.test(asset.name))
|
||||
.map(asset => {
|
||||
var fileContents = fs.readFileSync(path.join(root, asset.name));
|
||||
var size = gzipSize(fileContents);
|
||||
var previousSize = sizes[removeFileNameHash(root, asset.name)];
|
||||
var difference = getDifferenceLabel(size, previousSize);
|
||||
return {
|
||||
folder: path.join('build', path.dirname(asset.name)),
|
||||
name: path.basename(asset.name),
|
||||
size: size,
|
||||
sizeLabel: filesize(size) + (difference ? ' (' + difference + ')' : '')
|
||||
};
|
||||
});
|
||||
assets.sort((a, b) => b.size - a.size);
|
||||
var longestSizeLabelLength = Math.max.apply(
|
||||
null,
|
||||
assets.map(a => stripAnsi(a.sizeLabel).length)
|
||||
);
|
||||
assets.forEach(asset => {
|
||||
var sizeLabel = asset.sizeLabel;
|
||||
var sizeLength = stripAnsi(sizeLabel).length;
|
||||
if (sizeLength < longestSizeLabelLength) {
|
||||
var rightPadding = ' '.repeat(longestSizeLabelLength - sizeLength);
|
||||
sizeLabel += rightPadding;
|
||||
}
|
||||
console.log(
|
||||
' ' +
|
||||
sizeLabel +
|
||||
' ' +
|
||||
chalk.dim(asset.folder + path.sep) +
|
||||
chalk.cyan(asset.name)
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
function removeFileNameHash(buildFolder, fileName) {
|
||||
return fileName
|
||||
.replace(buildFolder, '')
|
||||
.replace(/\/?(.*)(\.\w+)(\.js|\.css)/, (match, p1, p2, p3) => p1 + p3);
|
||||
}
|
||||
|
||||
// Input: 1024, 2048
|
||||
// Output: "(+1 KB)"
|
||||
function getDifferenceLabel(currentSize, previousSize) {
|
||||
var FIFTY_KILOBYTES = 1024 * 50;
|
||||
var difference = currentSize - previousSize;
|
||||
var fileSize = !Number.isNaN(difference) ? filesize(difference) : 0;
|
||||
if (difference >= FIFTY_KILOBYTES) {
|
||||
return chalk.red('+' + fileSize);
|
||||
} else if (difference < FIFTY_KILOBYTES && difference > 0) {
|
||||
return chalk.yellow('+' + fileSize);
|
||||
} else if (difference < 0) {
|
||||
return chalk.green(fileSize);
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
function measureFileSizesBeforeBuild(buildFolder) {
|
||||
return new Promise(resolve => {
|
||||
recursive(buildFolder, (err, fileNames) => {
|
||||
var sizes;
|
||||
if (!err && fileNames) {
|
||||
sizes = fileNames
|
||||
.filter(fileName => /\.(js|css)$/.test(fileName))
|
||||
.reduce((memo, fileName) => {
|
||||
var contents = fs.readFileSync(fileName);
|
||||
var key = removeFileNameHash(buildFolder, fileName);
|
||||
memo[key] = gzipSize(contents);
|
||||
return memo;
|
||||
}, {});
|
||||
}
|
||||
resolve({
|
||||
root: buildFolder,
|
||||
sizes: sizes || {},
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
measureFileSizesBeforeBuild: measureFileSizesBeforeBuild,
|
||||
printFileSizesAfterBuild: printFileSizesAfterBuild,
|
||||
};
|
||||
@@ -110,6 +110,29 @@ clearConsole();
|
||||
console.log('Just cleared the screen!');
|
||||
```
|
||||
|
||||
#### `FileSizeReporter`
|
||||
|
||||
##### `measureFileSizesBeforeBuild(buildFolder: string): Promise<OpaqueFileSizes>`
|
||||
|
||||
Captures JS and CSS asset sizes inside the passed `buildFolder`. Save the result value to compare it after the build.
|
||||
|
||||
##### `printFileSizesAfterBuild(webpackStats: WebpackStats, previousFileSizes: OpaqueFileSizes)`
|
||||
|
||||
Prints the JS and CSS asset sizes after the build, and includes a size comparison with `previousFileSizes` that were captured earlier using `measureFileSizesBeforeBuild()`.
|
||||
|
||||
```js
|
||||
var {
|
||||
measureFileSizesBeforeBuild,
|
||||
printFileSizesAfterBuild,
|
||||
} = require('react-dev-utils/FileSizeReporter');
|
||||
|
||||
measureFileSizesBeforeBuild(buildFolder).then(previousFileSizes => {
|
||||
return cleanAndRebuild().then(webpackStats => {
|
||||
printFileSizesAfterBuild(webpackStats, previousFileSizes);
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
#### `formatWebpackMessages({errors: Array<string>, warnings: Array<string>}): {errors: Array<string>, warnings: Array<string>}`
|
||||
|
||||
Extracts and prettifies warning and error messages from webpack [stats](https://github.com/webpack/docs/wiki/node.js-api#stats) object.
|
||||
|
||||
@@ -11,13 +11,14 @@
|
||||
"node": ">=4"
|
||||
},
|
||||
"files": [
|
||||
"clearConsole.js",
|
||||
"checkRequiredFiles.js",
|
||||
"clearConsole.js",
|
||||
"FileSizeReporter.js",
|
||||
"formatWebpackMessages.js",
|
||||
"getProcessForPort.js",
|
||||
"InterpolateHtmlPlugin.js",
|
||||
"openChrome.applescript",
|
||||
"openBrowser.js",
|
||||
"openChrome.applescript",
|
||||
"prompt.js",
|
||||
"WatchMissingNodeModulesPlugin.js",
|
||||
"webpackHotDevClient.js"
|
||||
@@ -26,8 +27,11 @@
|
||||
"ansi-html": "0.0.5",
|
||||
"chalk": "1.1.3",
|
||||
"escape-string-regexp": "1.0.5",
|
||||
"filesize": "3.3.0",
|
||||
"gzip-size": "3.0.0",
|
||||
"html-entities": "1.2.0",
|
||||
"opn": "4.0.2",
|
||||
"recursive-readdir": "2.1.1",
|
||||
"sockjs-client": "1.1.2",
|
||||
"strip-ansi": "3.0.1"
|
||||
}
|
||||
|
||||
@@ -46,9 +46,7 @@
|
||||
"eslint-plugin-react": "6.4.1",
|
||||
"extract-text-webpack-plugin": "2.0.0",
|
||||
"file-loader": "0.10.0",
|
||||
"filesize": "3.3.0",
|
||||
"fs-extra": "0.30.0",
|
||||
"gzip-size": "3.0.0",
|
||||
"html-webpack-plugin": "2.28.0",
|
||||
"http-proxy-middleware": "0.17.3",
|
||||
"jest": "18.1.0",
|
||||
@@ -56,8 +54,6 @@
|
||||
"postcss-loader": "1.3.1",
|
||||
"promise": "7.1.1",
|
||||
"react-dev-utils": "^0.5.1",
|
||||
"recursive-readdir": "2.1.1",
|
||||
"strip-ansi": "3.0.1",
|
||||
"style-loader": "0.13.1",
|
||||
"url-loader": "0.5.7",
|
||||
"webpack": "2.2.1",
|
||||
|
||||
83
packages/react-scripts/scripts/build.js
vendored
83
packages/react-scripts/scripts/build.js
vendored
@@ -22,14 +22,13 @@ var chalk = require('chalk');
|
||||
var fs = require('fs-extra');
|
||||
var path = require('path');
|
||||
var url = require('url');
|
||||
var filesize = require('filesize');
|
||||
var gzipSize = require('gzip-size').sync;
|
||||
var webpack = require('webpack');
|
||||
var config = require('../config/webpack.config.prod');
|
||||
var paths = require('../config/paths');
|
||||
var checkRequiredFiles = require('react-dev-utils/checkRequiredFiles');
|
||||
var recursive = require('recursive-readdir');
|
||||
var stripAnsi = require('strip-ansi');
|
||||
var FileSizeReporter = require('react-dev-utils/FileSizeReporter');
|
||||
var measureFileSizesBeforeBuild = FileSizeReporter.measureFileSizesBeforeBuild;
|
||||
var printFileSizesAfterBuild = FileSizeReporter.printFileSizesAfterBuild;
|
||||
|
||||
var useYarn = fs.existsSync(paths.yarnLockFile);
|
||||
|
||||
@@ -38,88 +37,20 @@ if (!checkRequiredFiles([paths.appHtml, paths.appIndexJs])) {
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// Input: /User/dan/app/build/static/js/main.82be8.js
|
||||
// Output: /static/js/main.js
|
||||
function removeFileNameHash(fileName) {
|
||||
return fileName
|
||||
.replace(paths.appBuild, '')
|
||||
.replace(/\/?(.*)(\.\w+)(\.js|\.css)/, (match, p1, p2, p3) => p1 + p3);
|
||||
}
|
||||
|
||||
// Input: 1024, 2048
|
||||
// Output: "(+1 KB)"
|
||||
function getDifferenceLabel(currentSize, previousSize) {
|
||||
var FIFTY_KILOBYTES = 1024 * 50;
|
||||
var difference = currentSize - previousSize;
|
||||
var fileSize = !Number.isNaN(difference) ? filesize(difference) : 0;
|
||||
if (difference >= FIFTY_KILOBYTES) {
|
||||
return chalk.red('+' + fileSize);
|
||||
} else if (difference < FIFTY_KILOBYTES && difference > 0) {
|
||||
return chalk.yellow('+' + fileSize);
|
||||
} else if (difference < 0) {
|
||||
return chalk.green(fileSize);
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
// First, read the current file sizes in build directory.
|
||||
// This lets us display how much they changed later.
|
||||
recursive(paths.appBuild, (err, fileNames) => {
|
||||
var previousSizeMap = (fileNames || [])
|
||||
.filter(fileName => /\.(js|css)$/.test(fileName))
|
||||
.reduce((memo, fileName) => {
|
||||
var contents = fs.readFileSync(fileName);
|
||||
var key = removeFileNameHash(fileName);
|
||||
memo[key] = gzipSize(contents);
|
||||
return memo;
|
||||
}, {});
|
||||
|
||||
measureFileSizesBeforeBuild(paths.appBuild).then(previousFileSizes => {
|
||||
// Remove all content but keep the directory so that
|
||||
// if you're in it, you don't end up in Trash
|
||||
fs.emptyDirSync(paths.appBuild);
|
||||
|
||||
// Start the webpack build
|
||||
build(previousSizeMap);
|
||||
build(previousFileSizes);
|
||||
|
||||
// Merge with the public folder
|
||||
copyPublicFolder();
|
||||
});
|
||||
|
||||
// Print a detailed summary of build files.
|
||||
function printFileSizes(stats, previousSizeMap) {
|
||||
var assets = stats.toJson().assets
|
||||
.filter(asset => /\.(js|css)$/.test(asset.name))
|
||||
.map(asset => {
|
||||
var fileContents = fs.readFileSync(paths.appBuild + '/' + asset.name);
|
||||
var size = gzipSize(fileContents);
|
||||
var previousSize = previousSizeMap[removeFileNameHash(asset.name)];
|
||||
var difference = getDifferenceLabel(size, previousSize);
|
||||
return {
|
||||
folder: path.join('build', path.dirname(asset.name)),
|
||||
name: path.basename(asset.name),
|
||||
size: size,
|
||||
sizeLabel: filesize(size) + (difference ? ' (' + difference + ')' : '')
|
||||
};
|
||||
});
|
||||
assets.sort((a, b) => b.size - a.size);
|
||||
var longestSizeLabelLength = Math.max.apply(null,
|
||||
assets.map(a => stripAnsi(a.sizeLabel).length)
|
||||
);
|
||||
assets.forEach(asset => {
|
||||
var sizeLabel = asset.sizeLabel;
|
||||
var sizeLength = stripAnsi(sizeLabel).length;
|
||||
if (sizeLength < longestSizeLabelLength) {
|
||||
var rightPadding = ' '.repeat(longestSizeLabelLength - sizeLength);
|
||||
sizeLabel += rightPadding;
|
||||
}
|
||||
console.log(
|
||||
' ' + sizeLabel +
|
||||
' ' + chalk.dim(asset.folder + path.sep) + chalk.cyan(asset.name)
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
// Print out errors
|
||||
function printErrors(summary, errors) {
|
||||
console.log(chalk.red(summary));
|
||||
@@ -131,7 +62,7 @@ function printErrors(summary, errors) {
|
||||
}
|
||||
|
||||
// Create the production build and print the deployment instructions.
|
||||
function build(previousSizeMap) {
|
||||
function build(previousFileSizes) {
|
||||
console.log('Creating an optimized production build...');
|
||||
|
||||
var compiler;
|
||||
@@ -163,7 +94,7 @@ function build(previousSizeMap) {
|
||||
|
||||
console.log('File sizes after gzip:');
|
||||
console.log();
|
||||
printFileSizes(stats, previousSizeMap);
|
||||
printFileSizesAfterBuild(stats, previousFileSizes);
|
||||
console.log();
|
||||
|
||||
var openCommand = process.platform === 'win32' ? 'start' : 'open';
|
||||
|
||||
Reference in New Issue
Block a user