const { rimraf, chalk } = require('@umijs/utils'); const path = require('path'); const zlib = require('zlib'); const fs = require('fs'); const WARN_AFTER_BUNDLE_GZIP_SIZE = 1.8 * 1024 * 1024; const WARN_AFTER_CHUNK_GZIP_SIZE = 1 * 1024 * 1024; function printFileSizes(stats, dir) { const ui = require('cliui')({ width: 120 }); const json = stats.toJson({ hash: false, modules: false, chunks: false, }); const filesize = bytes => { bytes = Math.abs(bytes); const radix = 1024; const unit = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']; let loop = 0; // calculate while (bytes >= radix) { bytes /= radix; ++loop; } return `${bytes.toFixed(1)} ${unit[loop]}`; }; const assets = json.assets ? json.assets : json && json.children.reduce((acc, child) => acc.concat(child.assets), []); const seenNames = new Map(); const isJS = val => /\.js$/.test(val); const isCSS = val => /\.css$/.test(val); const orderedAssets = assets && assets .map(a => { a.name = a.name.split('?')[0]; const isMainBundle = a.name.indexOf('main.') === 0; const maxRecommendedSize = isMainBundle ? WARN_AFTER_BUNDLE_GZIP_SIZE : WARN_AFTER_CHUNK_GZIP_SIZE; const isLarge = maxRecommendedSize && a.size > maxRecommendedSize; return { ...a, suggested: isLarge && isJS(a.name), }; }) .filter(a => { if (seenNames.has(a.name)) { return false; } seenNames.set(a.name, true); return isJS(a.name) || isCSS(a.name); }) .sort((a, b) => { if (isJS(a.name) && isCSS(b.name)) return -1; if (isCSS(a.name) && isJS(b.name)) return 1; return b.size - a.size; }); function getGzippedSize(asset) { const filepath = path.resolve(path.join(dir, asset.name)); if (fs.existsSync(filepath)) { const buffer = fs.readFileSync(filepath); return filesize(zlib.gzipSync(buffer).length); } return filesize(0); } function makeRow(a, b, c) { return ` ${a}\t ${b}\t ${c}`; } ui.div( makeRow( chalk.cyan.bold(`File`), chalk.cyan.bold(`Size`), chalk.cyan.bold(`Gzipped`), ) + `\n\n` + orderedAssets && orderedAssets .map(asset => makeRow( /js$/.test(asset.name) ? asset.suggested ? chalk.yellow(path.join(dir, asset.name)) : chalk.green(path.join(dir, asset.name)) : chalk.blue(path.join(dir, asset.name)), filesize(asset.size), getGzippedSize(asset), ), ) .join(`\n`), ); console.log( `${ui.toString()}\n\n ${chalk.gray( `Images and other types of assets omitted.`, )}\n`, ); if (orderedAssets && orderedAssets.some((asset) => asset.suggested)) { // We'll warn for bundles exceeding them. console.log(); console.log( chalk.yellow('The bundle size is significantly larger than recommended.'), ); console.log( chalk.yellow( 'You can also analyze the project dependencies using ANALYZE=1', ), ); console.log(); } } module.exports = { printFileSizes }