UNPKG

4.61 kBJavaScriptView Raw
1/**
2 * Copyright (c) 2015-present, Facebook, Inc.
3 *
4 * This source code is licensed under the MIT license found in the
5 * LICENSE file in the root directory of this source tree.
6 */
7
8'use strict';
9
10var fs = require('fs');
11var path = require('path');
12var chalk = require('chalk');
13var filesize = require('filesize');
14var recursive = require('recursive-readdir');
15var stripAnsi = require('strip-ansi');
16var gzipSize = require('gzip-size').sync;
17
18function canReadAsset(asset) {
19 return (
20 /\.(js|css)$/.test(asset) &&
21 !/service-worker\.js/.test(asset) &&
22 !/precache-manifest\.[0-9a-f]+\.js/.test(asset)
23 );
24}
25
26// Prints a detailed summary of build files.
27function printFileSizesAfterBuild(
28 webpackStats,
29 previousSizeMap,
30 buildFolder,
31 maxBundleGzipSize,
32 maxChunkGzipSize
33) {
34 var root = previousSizeMap.root;
35 var sizes = previousSizeMap.sizes;
36 var assets = (webpackStats.stats || [webpackStats])
37 .map(stats =>
38 stats
39 .toJson({ all: false, assets: true })
40 .assets.filter(asset => canReadAsset(asset.name))
41 .map(asset => {
42 var fileContents = fs.readFileSync(path.join(root, asset.name));
43 var size = gzipSize(fileContents);
44 var previousSize = sizes[removeFileNameHash(root, asset.name)];
45 var difference = getDifferenceLabel(size, previousSize);
46 return {
47 folder: path.join(
48 path.basename(buildFolder),
49 path.dirname(asset.name)
50 ),
51 name: path.basename(asset.name),
52 size: size,
53 sizeLabel:
54 filesize(size) + (difference ? ' (' + difference + ')' : ''),
55 };
56 })
57 )
58 .reduce((single, all) => all.concat(single), []);
59 assets.sort((a, b) => b.size - a.size);
60 var longestSizeLabelLength = Math.max.apply(
61 null,
62 assets.map(a => stripAnsi(a.sizeLabel).length)
63 );
64 var suggestBundleSplitting = false;
65 assets.forEach(asset => {
66 var sizeLabel = asset.sizeLabel;
67 var sizeLength = stripAnsi(sizeLabel).length;
68 if (sizeLength < longestSizeLabelLength) {
69 var rightPadding = ' '.repeat(longestSizeLabelLength - sizeLength);
70 sizeLabel += rightPadding;
71 }
72 var isMainBundle = asset.name.indexOf('main.') === 0;
73 var maxRecommendedSize = isMainBundle
74 ? maxBundleGzipSize
75 : maxChunkGzipSize;
76 var isLarge = maxRecommendedSize && asset.size > maxRecommendedSize;
77 if (isLarge && path.extname(asset.name) === '.js') {
78 suggestBundleSplitting = true;
79 }
80 console.log(
81 ' ' +
82 (isLarge ? chalk.yellow(sizeLabel) : sizeLabel) +
83 ' ' +
84 chalk.dim(asset.folder + path.sep) +
85 chalk.cyan(asset.name)
86 );
87 });
88 if (suggestBundleSplitting) {
89 console.log();
90 console.log(
91 chalk.yellow('The bundle size is significantly larger than recommended.')
92 );
93 console.log(
94 chalk.yellow(
95 'Consider reducing it with code splitting: https://goo.gl/9VhYWB'
96 )
97 );
98 console.log(
99 chalk.yellow(
100 'You can also analyze the project dependencies: https://goo.gl/LeUzfb'
101 )
102 );
103 }
104}
105
106function removeFileNameHash(buildFolder, fileName) {
107 return fileName
108 .replace(buildFolder, '')
109 .replace(/\\/g, '/')
110 .replace(
111 /\/?(.*)(\.[0-9a-f]+)(\.chunk)?(\.js|\.css)/,
112 (match, p1, p2, p3, p4) => p1 + p4
113 );
114}
115
116// Input: 1024, 2048
117// Output: "(+1 KB)"
118function getDifferenceLabel(currentSize, previousSize) {
119 var FIFTY_KILOBYTES = 1024 * 50;
120 var difference = currentSize - previousSize;
121 var fileSize = !Number.isNaN(difference) ? filesize(difference) : 0;
122 if (difference >= FIFTY_KILOBYTES) {
123 return chalk.red('+' + fileSize);
124 } else if (difference < FIFTY_KILOBYTES && difference > 0) {
125 return chalk.yellow('+' + fileSize);
126 } else if (difference < 0) {
127 return chalk.green(fileSize);
128 } else {
129 return '';
130 }
131}
132
133function measureFileSizesBeforeBuild(buildFolder) {
134 return new Promise(resolve => {
135 recursive(buildFolder, (err, fileNames) => {
136 var sizes;
137 if (!err && fileNames) {
138 sizes = fileNames.filter(canReadAsset).reduce((memo, fileName) => {
139 var contents = fs.readFileSync(fileName);
140 var key = removeFileNameHash(buildFolder, fileName);
141 memo[key] = gzipSize(contents);
142 return memo;
143 }, {});
144 }
145 resolve({
146 root: buildFolder,
147 sizes: sizes || {},
148 });
149 });
150 });
151}
152
153module.exports = {
154 measureFileSizesBeforeBuild: measureFileSizesBeforeBuild,
155 printFileSizesAfterBuild: printFileSizesAfterBuild,
156};