chushihua
This commit is contained in:
+168
@@ -0,0 +1,168 @@
|
||||
'use strict';
|
||||
|
||||
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
|
||||
|
||||
function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; }
|
||||
|
||||
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
|
||||
|
||||
var bfj = require('bfj-node4');
|
||||
var path = require('path');
|
||||
var mkdir = require('mkdirp');
|
||||
|
||||
var _require = require('chalk'),
|
||||
bold = _require.bold;
|
||||
|
||||
var Logger = require('./Logger');
|
||||
var viewer = require('./viewer');
|
||||
|
||||
var BundleAnalyzerPlugin = function () {
|
||||
function BundleAnalyzerPlugin(opts) {
|
||||
_classCallCheck(this, BundleAnalyzerPlugin);
|
||||
|
||||
this.opts = Object.assign({
|
||||
analyzerMode: 'server',
|
||||
analyzerHost: '127.0.0.1',
|
||||
analyzerPort: 8888,
|
||||
reportFilename: 'report.html',
|
||||
defaultSizes: 'parsed',
|
||||
openAnalyzer: true,
|
||||
generateStatsFile: false,
|
||||
statsFilename: 'stats.json',
|
||||
statsOptions: null,
|
||||
excludeAssets: null,
|
||||
logLevel: 'info',
|
||||
// deprecated
|
||||
startAnalyzer: true
|
||||
}, opts);
|
||||
|
||||
this.server = null;
|
||||
this.logger = new Logger(this.opts.logLevel);
|
||||
}
|
||||
|
||||
_createClass(BundleAnalyzerPlugin, [{
|
||||
key: 'apply',
|
||||
value: function apply(compiler) {
|
||||
var _this = this;
|
||||
|
||||
this.compiler = compiler;
|
||||
|
||||
var done = function done(stats) {
|
||||
stats = stats.toJson(_this.opts.statsOptions);
|
||||
|
||||
var actions = [];
|
||||
|
||||
if (_this.opts.generateStatsFile) {
|
||||
actions.push(function () {
|
||||
return _this.generateStatsFile(stats);
|
||||
});
|
||||
}
|
||||
|
||||
// Handling deprecated `startAnalyzer` flag
|
||||
if (_this.opts.analyzerMode === 'server' && !_this.opts.startAnalyzer) {
|
||||
_this.opts.analyzerMode = 'disabled';
|
||||
}
|
||||
|
||||
if (_this.opts.analyzerMode === 'server') {
|
||||
actions.push(function () {
|
||||
return _this.startAnalyzerServer(stats);
|
||||
});
|
||||
} else if (_this.opts.analyzerMode === 'static') {
|
||||
actions.push(function () {
|
||||
return _this.generateStaticReport(stats);
|
||||
});
|
||||
}
|
||||
|
||||
if (actions.length) {
|
||||
// Making analyzer logs to be after all webpack logs in the console
|
||||
setImmediate(function () {
|
||||
actions.forEach(function (action) {
|
||||
return action();
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
if (compiler.hooks) {
|
||||
compiler.hooks.done.tap('webpack-bundle-analyzer', done);
|
||||
} else {
|
||||
compiler.plugin('done', done);
|
||||
}
|
||||
}
|
||||
}, {
|
||||
key: 'generateStatsFile',
|
||||
value: function () {
|
||||
var _ref = _asyncToGenerator(function* (stats) {
|
||||
var statsFilepath = path.resolve(this.compiler.outputPath, this.opts.statsFilename);
|
||||
mkdir.sync(path.dirname(statsFilepath));
|
||||
|
||||
try {
|
||||
yield bfj.write(statsFilepath, stats, {
|
||||
space: 2,
|
||||
promises: 'ignore',
|
||||
buffers: 'ignore',
|
||||
maps: 'ignore',
|
||||
iterables: 'ignore',
|
||||
circular: 'ignore'
|
||||
});
|
||||
|
||||
this.logger.info(`${bold('Webpack Bundle Analyzer')} saved stats file to ${bold(statsFilepath)}`);
|
||||
} catch (error) {
|
||||
this.logger.error(`${bold('Webpack Bundle Analyzer')} error saving stats file to ${bold(statsFilepath)}: ${error}`);
|
||||
}
|
||||
});
|
||||
|
||||
function generateStatsFile(_x) {
|
||||
return _ref.apply(this, arguments);
|
||||
}
|
||||
|
||||
return generateStatsFile;
|
||||
}()
|
||||
}, {
|
||||
key: 'startAnalyzerServer',
|
||||
value: function () {
|
||||
var _ref2 = _asyncToGenerator(function* (stats) {
|
||||
if (this.server) {
|
||||
(yield this.server).updateChartData(stats);
|
||||
} else {
|
||||
this.server = viewer.startServer(stats, {
|
||||
openBrowser: this.opts.openAnalyzer,
|
||||
host: this.opts.analyzerHost,
|
||||
port: this.opts.analyzerPort,
|
||||
bundleDir: this.getBundleDirFromCompiler(),
|
||||
logger: this.logger,
|
||||
defaultSizes: this.opts.defaultSizes,
|
||||
excludeAssets: this.opts.excludeAssets
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
function startAnalyzerServer(_x2) {
|
||||
return _ref2.apply(this, arguments);
|
||||
}
|
||||
|
||||
return startAnalyzerServer;
|
||||
}()
|
||||
}, {
|
||||
key: 'generateStaticReport',
|
||||
value: function generateStaticReport(stats) {
|
||||
viewer.generateReport(stats, {
|
||||
openBrowser: this.opts.openAnalyzer,
|
||||
reportFilename: path.resolve(this.compiler.outputPath, this.opts.reportFilename),
|
||||
bundleDir: this.getBundleDirFromCompiler(),
|
||||
logger: this.logger,
|
||||
defaultSizes: this.opts.defaultSizes,
|
||||
excludeAssets: this.opts.excludeAssets
|
||||
});
|
||||
}
|
||||
}, {
|
||||
key: 'getBundleDirFromCompiler',
|
||||
value: function getBundleDirFromCompiler() {
|
||||
return this.compiler.outputFileSystem.constructor.name === 'MemoryFileSystem' ? null : this.compiler.outputPath;
|
||||
}
|
||||
}]);
|
||||
|
||||
return BundleAnalyzerPlugin;
|
||||
}();
|
||||
|
||||
module.exports = BundleAnalyzerPlugin;
|
||||
+94
@@ -0,0 +1,94 @@
|
||||
'use strict';
|
||||
|
||||
var _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }();
|
||||
|
||||
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
|
||||
|
||||
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
|
||||
|
||||
var LEVELS = ['debug', 'info', 'warn', 'error', 'silent'];
|
||||
|
||||
var LEVEL_TO_CONSOLE_METHOD = new Map([['debug', 'log'], ['info', 'log'], ['warn', 'log']]);
|
||||
|
||||
var Logger = function () {
|
||||
function Logger() {
|
||||
var level = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : Logger.defaultLevel;
|
||||
|
||||
_classCallCheck(this, Logger);
|
||||
|
||||
this.activeLevels = new Set();
|
||||
this.setLogLevel(level);
|
||||
}
|
||||
|
||||
_createClass(Logger, [{
|
||||
key: 'setLogLevel',
|
||||
value: function setLogLevel(level) {
|
||||
var levelIndex = LEVELS.indexOf(level);
|
||||
|
||||
if (levelIndex === -1) throw new Error(`Invalid log level "${level}". Use one of these: ${LEVELS.join(', ')}`);
|
||||
|
||||
this.activeLevels.clear();
|
||||
|
||||
var _iteratorNormalCompletion = true;
|
||||
var _didIteratorError = false;
|
||||
var _iteratorError = undefined;
|
||||
|
||||
try {
|
||||
for (var _iterator = LEVELS.entries()[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
|
||||
var _ref = _step.value;
|
||||
|
||||
var _ref2 = _slicedToArray(_ref, 2);
|
||||
|
||||
var i = _ref2[0];
|
||||
var _level = _ref2[1];
|
||||
|
||||
if (i >= levelIndex) this.activeLevels.add(_level);
|
||||
}
|
||||
} catch (err) {
|
||||
_didIteratorError = true;
|
||||
_iteratorError = err;
|
||||
} finally {
|
||||
try {
|
||||
if (!_iteratorNormalCompletion && _iterator.return) {
|
||||
_iterator.return();
|
||||
}
|
||||
} finally {
|
||||
if (_didIteratorError) {
|
||||
throw _iteratorError;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}, {
|
||||
key: '_log',
|
||||
value: function _log(level) {
|
||||
var _console;
|
||||
|
||||
for (var _len = arguments.length, args = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
|
||||
args[_key - 1] = arguments[_key];
|
||||
}
|
||||
|
||||
(_console = console)[LEVEL_TO_CONSOLE_METHOD.get(level) || level].apply(_console, args);
|
||||
}
|
||||
}]);
|
||||
|
||||
return Logger;
|
||||
}();
|
||||
|
||||
Logger.levels = LEVELS;
|
||||
Logger.defaultLevel = 'info';
|
||||
;
|
||||
|
||||
LEVELS.forEach(function (level) {
|
||||
if (level === 'silent') return;
|
||||
|
||||
Logger.prototype[level] = function () {
|
||||
for (var _len2 = arguments.length, args = Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
|
||||
args[_key2] = arguments[_key2];
|
||||
}
|
||||
|
||||
if (this.activeLevels.has(level)) this._log.apply(this, [level].concat(args));
|
||||
};
|
||||
});
|
||||
|
||||
module.exports = Logger;
|
||||
+159
@@ -0,0 +1,159 @@
|
||||
'use strict';
|
||||
|
||||
var fs = require('fs');
|
||||
var path = require('path');
|
||||
|
||||
var _ = require('lodash');
|
||||
var gzipSize = require('gzip-size');
|
||||
|
||||
var Logger = require('./Logger');
|
||||
var Folder = require('./tree/Folder').default;
|
||||
|
||||
var _require = require('./parseUtils'),
|
||||
parseBundle = _require.parseBundle;
|
||||
|
||||
var _require2 = require('./utils'),
|
||||
createAssetsFilter = _require2.createAssetsFilter;
|
||||
|
||||
var FILENAME_QUERY_REGEXP = /\?.*$/;
|
||||
|
||||
module.exports = {
|
||||
getViewerData,
|
||||
readStatsFromFile
|
||||
};
|
||||
|
||||
function getViewerData(bundleStats, bundleDir, opts) {
|
||||
var _ref = opts || {},
|
||||
_ref$logger = _ref.logger,
|
||||
logger = _ref$logger === undefined ? new Logger() : _ref$logger,
|
||||
_ref$excludeAssets = _ref.excludeAssets,
|
||||
excludeAssets = _ref$excludeAssets === undefined ? null : _ref$excludeAssets;
|
||||
|
||||
var isAssetIncluded = createAssetsFilter(excludeAssets);
|
||||
|
||||
// Sometimes all the information is located in `children` array (e.g. problem in #10)
|
||||
if (_.isEmpty(bundleStats.assets) && !_.isEmpty(bundleStats.children)) {
|
||||
bundleStats = bundleStats.children[0];
|
||||
}
|
||||
|
||||
// Picking only `*.js` assets from bundle that has non-empty `chunks` array
|
||||
bundleStats.assets = _.filter(bundleStats.assets, function (asset) {
|
||||
// Removing query part from filename (yes, somebody uses it for some reason and Webpack supports it)
|
||||
// See #22
|
||||
asset.name = asset.name.replace(FILENAME_QUERY_REGEXP, '');
|
||||
|
||||
return _.endsWith(asset.name, '.js') && !_.isEmpty(asset.chunks) && isAssetIncluded(asset.name);
|
||||
});
|
||||
|
||||
// Trying to parse bundle assets and get real module sizes if `bundleDir` is provided
|
||||
var bundlesSources = null;
|
||||
var parsedModules = null;
|
||||
|
||||
if (bundleDir) {
|
||||
bundlesSources = {};
|
||||
parsedModules = {};
|
||||
|
||||
var _iteratorNormalCompletion = true;
|
||||
var _didIteratorError = false;
|
||||
var _iteratorError = undefined;
|
||||
|
||||
try {
|
||||
for (var _iterator = bundleStats.assets[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
|
||||
var statAsset = _step.value;
|
||||
|
||||
var assetFile = path.join(bundleDir, statAsset.name);
|
||||
var bundleInfo = void 0;
|
||||
|
||||
try {
|
||||
bundleInfo = parseBundle(assetFile);
|
||||
} catch (err) {
|
||||
var msg = err.code === 'ENOENT' ? 'no such file' : err.message;
|
||||
logger.warn(`Error parsing bundle asset "${assetFile}": ${msg}`);
|
||||
continue;
|
||||
}
|
||||
|
||||
bundlesSources[statAsset.name] = bundleInfo.src;
|
||||
_.assign(parsedModules, bundleInfo.modules);
|
||||
}
|
||||
} catch (err) {
|
||||
_didIteratorError = true;
|
||||
_iteratorError = err;
|
||||
} finally {
|
||||
try {
|
||||
if (!_iteratorNormalCompletion && _iterator.return) {
|
||||
_iterator.return();
|
||||
}
|
||||
} finally {
|
||||
if (_didIteratorError) {
|
||||
throw _iteratorError;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (_.isEmpty(bundlesSources)) {
|
||||
bundlesSources = null;
|
||||
parsedModules = null;
|
||||
logger.warn('\nNo bundles were parsed. Analyzer will show only original module sizes from stats file.\n');
|
||||
}
|
||||
}
|
||||
|
||||
var modules = getBundleModules(bundleStats);
|
||||
var assets = _.transform(bundleStats.assets, function (result, statAsset) {
|
||||
var asset = result[statAsset.name] = _.pick(statAsset, 'size');
|
||||
|
||||
if (bundlesSources && _.has(bundlesSources, statAsset.name)) {
|
||||
asset.parsedSize = bundlesSources[statAsset.name].length;
|
||||
asset.gzipSize = gzipSize.sync(bundlesSources[statAsset.name]);
|
||||
}
|
||||
|
||||
// Picking modules from current bundle script
|
||||
asset.modules = _(modules).filter(function (statModule) {
|
||||
return assetHasModule(statAsset, statModule);
|
||||
}).each(function (statModule) {
|
||||
if (parsedModules) {
|
||||
statModule.parsedSrc = parsedModules[statModule.id];
|
||||
}
|
||||
});
|
||||
|
||||
asset.tree = createModulesTree(asset.modules);
|
||||
}, {});
|
||||
|
||||
return _.transform(assets, function (result, asset, filename) {
|
||||
result.push({
|
||||
label: filename,
|
||||
// Not using `asset.size` here provided by Webpack because it can be very confusing when `UglifyJsPlugin` is used.
|
||||
// In this case all module sizes from stats file will represent unminified module sizes, but `asset.size` will
|
||||
// be the size of minified bundle.
|
||||
// Using `asset.size` only if current asset doesn't contain any modules (resulting size equals 0)
|
||||
statSize: asset.tree.size || asset.size,
|
||||
parsedSize: asset.parsedSize,
|
||||
gzipSize: asset.gzipSize,
|
||||
groups: _.invokeMap(asset.tree.children, 'toChartData')
|
||||
});
|
||||
}, []);
|
||||
}
|
||||
|
||||
function readStatsFromFile(filename) {
|
||||
return JSON.parse(fs.readFileSync(filename, 'utf8'));
|
||||
}
|
||||
|
||||
function getBundleModules(bundleStats) {
|
||||
return _(bundleStats.chunks).map('modules').concat(bundleStats.modules).compact().flatten().uniqBy('id').value();
|
||||
}
|
||||
|
||||
function assetHasModule(statAsset, statModule) {
|
||||
// Checking if this module is the part of asset chunks
|
||||
return _.some(statModule.chunks, function (moduleChunk) {
|
||||
return _.includes(statAsset.chunks, moduleChunk);
|
||||
});
|
||||
}
|
||||
|
||||
function createModulesTree(modules) {
|
||||
var root = new Folder('.');
|
||||
|
||||
_.each(modules, function (module) {
|
||||
return root.addModule(module);
|
||||
});
|
||||
|
||||
return root;
|
||||
}
|
||||
+103
@@ -0,0 +1,103 @@
|
||||
#! /usr/bin/env node
|
||||
'use strict';
|
||||
|
||||
var _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }();
|
||||
|
||||
function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }
|
||||
|
||||
var _require = require('path'),
|
||||
resolve = _require.resolve,
|
||||
dirname = _require.dirname;
|
||||
|
||||
var _ = require('lodash');
|
||||
var commander = require('commander');
|
||||
|
||||
var _require2 = require('chalk'),
|
||||
magenta = _require2.magenta;
|
||||
|
||||
var analyzer = require('../analyzer');
|
||||
var viewer = require('../viewer');
|
||||
var Logger = require('../Logger');
|
||||
|
||||
var SIZES = new Set(['stat', 'parsed', 'gzip']);
|
||||
|
||||
var program = commander.version(require('../../package.json').version).usage(`<bundleStatsFile> [bundleDir] [options]
|
||||
|
||||
Arguments:
|
||||
|
||||
bundleStatsFile Path to Webpack Stats JSON file.
|
||||
bundleDir Directory containing all generated bundles.
|
||||
You should provided it if you want analyzer to show you the real parsed module sizes.
|
||||
By default a directory of stats file is used.`).option('-m, --mode <mode>', 'Analyzer mode. Should be `server` or `static`.' + br('In `server` mode analyzer will start HTTP server to show bundle report.') + br('In `static` mode single HTML file with bundle report will be generated.'), 'server').option('-h, --host <host>', 'Host that will be used in `server` mode to start HTTP server.', '127.0.0.1').option('-p, --port <n>', 'Port that will be used in `server` mode to start HTTP server.', Number, 8888).option('-r, --report <file>', 'Path to bundle report file that will be generated in `static` mode.', 'report.html').option('-s, --default-sizes <type>', 'Module sizes to show in treemap by default.' + br(`Possible values: ${[].concat(_toConsumableArray(SIZES)).join(', ')}`), 'parsed').option('-O, --no-open', "Don't open report in default browser automatically.").option('-e, --exclude <regexp>', 'Assets that should be excluded from the report.' + br('Can be specified multiple times.'), array()).option('-l, --log-level <level>', 'Log level.' + br(`Possible values: ${[].concat(_toConsumableArray(Logger.levels)).join(', ')}`), Logger.defaultLevel).parse(process.argv);
|
||||
|
||||
var mode = program.mode,
|
||||
host = program.host,
|
||||
port = program.port,
|
||||
reportFilename = program.report,
|
||||
defaultSizes = program.defaultSizes,
|
||||
logLevel = program.logLevel,
|
||||
openBrowser = program.open,
|
||||
excludeAssets = program.exclude,
|
||||
_program$args = _slicedToArray(program.args, 2),
|
||||
bundleStatsFile = _program$args[0],
|
||||
bundleDir = _program$args[1];
|
||||
|
||||
var logger = new Logger(logLevel);
|
||||
|
||||
if (!bundleStatsFile) showHelp('Provide path to Webpack Stats file as first argument');
|
||||
if (mode !== 'server' && mode !== 'static') showHelp('Invalid mode. Should be either `server` or `static`.');
|
||||
if (mode === 'server' && !host) showHelp('Invalid host name');
|
||||
if (mode === 'server' && isNaN(port)) showHelp('Invalid port number');
|
||||
if (!SIZES.has(defaultSizes)) showHelp(`Invalid default sizes option. Possible values are: ${[].concat(_toConsumableArray(SIZES)).join(', ')}`);
|
||||
|
||||
bundleStatsFile = resolve(bundleStatsFile);
|
||||
|
||||
if (!bundleDir) bundleDir = dirname(bundleStatsFile);
|
||||
|
||||
var bundleStats = void 0;
|
||||
try {
|
||||
bundleStats = analyzer.readStatsFromFile(bundleStatsFile);
|
||||
} catch (err) {
|
||||
logger.error(`Could't read webpack bundle stats from "${bundleStatsFile}":\n${err}`);
|
||||
logger.debug(err.stack);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
if (mode === 'server') {
|
||||
viewer.startServer(bundleStats, {
|
||||
openBrowser,
|
||||
port,
|
||||
host,
|
||||
defaultSizes,
|
||||
bundleDir,
|
||||
excludeAssets,
|
||||
logger: new Logger(logLevel)
|
||||
});
|
||||
} else {
|
||||
viewer.generateReport(bundleStats, {
|
||||
openBrowser,
|
||||
reportFilename: resolve(reportFilename),
|
||||
defaultSizes,
|
||||
bundleDir,
|
||||
excludeAssets,
|
||||
logger: new Logger(logLevel)
|
||||
});
|
||||
}
|
||||
|
||||
function showHelp(error) {
|
||||
if (error) console.log(`\n ${magenta(error)}`);
|
||||
program.outputHelp();
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
function br(str) {
|
||||
return `\n${_.repeat(' ', 28)}${str}`;
|
||||
}
|
||||
|
||||
function array() {
|
||||
var arr = [];
|
||||
return function (val) {
|
||||
arr.push(val);
|
||||
return arr;
|
||||
};
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
'use strict';
|
||||
|
||||
var _require = require('./viewer'),
|
||||
start = _require.start;
|
||||
|
||||
module.exports = {
|
||||
start,
|
||||
BundleAnalyzerPlugin: require('./BundleAnalyzerPlugin')
|
||||
};
|
||||
+198
@@ -0,0 +1,198 @@
|
||||
'use strict';
|
||||
|
||||
var fs = require('fs');
|
||||
var _ = require('lodash');
|
||||
var acorn = require('acorn');
|
||||
var walk = require('acorn/dist/walk');
|
||||
|
||||
module.exports = {
|
||||
parseBundle
|
||||
};
|
||||
|
||||
function parseBundle(bundlePath) {
|
||||
var content = fs.readFileSync(bundlePath, 'utf8');
|
||||
var ast = acorn.parse(content, {
|
||||
sourceType: 'script',
|
||||
// I believe in a bright future of ECMAScript!
|
||||
// Actually, it's set to `2050` to support the latest ECMAScript version that currently exists.
|
||||
// Seems like `acorn` supports such weird option value.
|
||||
ecmaVersion: 2050
|
||||
});
|
||||
|
||||
var walkState = {
|
||||
locations: null
|
||||
};
|
||||
|
||||
walk.recursive(ast, walkState, {
|
||||
CallExpression(node, state, c) {
|
||||
if (state.locations) return;
|
||||
|
||||
var args = node.arguments;
|
||||
|
||||
// Main chunk with webpack loader.
|
||||
// Modules are stored in first argument:
|
||||
// (function (...) {...})(<modules>)
|
||||
if (node.callee.type === 'FunctionExpression' && !node.callee.id && args.length === 1 && isSimpleModulesList(args[0])) {
|
||||
state.locations = getModulesLocations(args[0]);
|
||||
return;
|
||||
}
|
||||
|
||||
// Async Webpack < v4 chunk without webpack loader.
|
||||
// webpackJsonp([<chunks>], <modules>, ...)
|
||||
// As function name may be changed with `output.jsonpFunction` option we can't rely on it's default name.
|
||||
if (node.callee.type === 'Identifier' && mayBeAsyncChunkArguments(args) && isModulesList(args[1])) {
|
||||
state.locations = getModulesLocations(args[1]);
|
||||
return;
|
||||
}
|
||||
|
||||
// Async Webpack v4 chunk without webpack loader.
|
||||
// (window.webpackJsonp=window.webpackJsonp||[]).push([[<chunks>], <modules>, ...]);
|
||||
// As function name may be changed with `output.jsonpFunction` option we can't rely on it's default name.
|
||||
if (isAsyncChunkPushExpression(node)) {
|
||||
state.locations = getModulesLocations(args[0].elements[1]);
|
||||
return;
|
||||
}
|
||||
|
||||
// Walking into arguments because some of plugins (e.g. `DedupePlugin`) or some Webpack
|
||||
// features (e.g. `umd` library output) can wrap modules list into additional IIFE.
|
||||
_.each(args, function (arg) {
|
||||
return c(arg, state);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
var modules = void 0;
|
||||
|
||||
if (walkState.locations) {
|
||||
modules = _.mapValues(walkState.locations, function (loc) {
|
||||
return content.slice(loc.start, loc.end);
|
||||
});
|
||||
} else {
|
||||
modules = {};
|
||||
}
|
||||
|
||||
return {
|
||||
src: content,
|
||||
modules
|
||||
};
|
||||
}
|
||||
|
||||
function isModulesList(node) {
|
||||
return isSimpleModulesList(node) ||
|
||||
// Modules are contained in expression `Array([minimum ID]).concat([<module>, <module>, ...])`
|
||||
isOptimizedModulesArray(node);
|
||||
}
|
||||
|
||||
function isSimpleModulesList(node) {
|
||||
return (
|
||||
// Modules are contained in hash. Keys are module ids.
|
||||
isModulesHash(node) ||
|
||||
// Modules are contained in array. Indexes are module ids.
|
||||
isModulesArray(node)
|
||||
);
|
||||
}
|
||||
|
||||
function isModulesHash(node) {
|
||||
return node.type === 'ObjectExpression' && _(node.properties).map('value').every(isModuleWrapper);
|
||||
}
|
||||
|
||||
function isModulesArray(node) {
|
||||
return node.type === 'ArrayExpression' && _.every(node.elements, function (elem) {
|
||||
return (
|
||||
// Some of array items may be skipped because there is no module with such id
|
||||
!elem || isModuleWrapper(elem)
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
function isOptimizedModulesArray(node) {
|
||||
// Checking whether modules are contained in `Array(<minimum ID>).concat(...modules)` array:
|
||||
// https://github.com/webpack/webpack/blob/v1.14.0/lib/Template.js#L91
|
||||
// The `<minimum ID>` + array indexes are module ids
|
||||
return node.type === 'CallExpression' && node.callee.type === 'MemberExpression' &&
|
||||
// Make sure the object called is `Array(<some number>)`
|
||||
node.callee.object.type === 'CallExpression' && node.callee.object.callee.type === 'Identifier' && node.callee.object.callee.name === 'Array' && node.callee.object.arguments.length === 1 && isNumericId(node.callee.object.arguments[0]) &&
|
||||
// Make sure the property X called for `Array(<some number>).X` is `concat`
|
||||
node.callee.property.type === 'Identifier' && node.callee.property.name === 'concat' &&
|
||||
// Make sure exactly one array is passed in to `concat`
|
||||
node.arguments.length === 1 && isModulesArray(node.arguments[0]);
|
||||
}
|
||||
|
||||
function isModuleWrapper(node) {
|
||||
return (
|
||||
// It's an anonymous function expression that wraps module
|
||||
(node.type === 'FunctionExpression' || node.type === 'ArrowFunctionExpression') && !node.id ||
|
||||
// If `DedupePlugin` is used it can be an ID of duplicated module...
|
||||
isModuleId(node) ||
|
||||
// or an array of shape [<module_id>, ...args]
|
||||
node.type === 'ArrayExpression' && node.elements.length > 1 && isModuleId(node.elements[0])
|
||||
);
|
||||
}
|
||||
|
||||
function isModuleId(node) {
|
||||
return node.type === 'Literal' && (isNumericId(node) || typeof node.value === 'string');
|
||||
}
|
||||
|
||||
function isNumericId(node) {
|
||||
return node.type === 'Literal' && Number.isInteger(node.value) && node.value >= 0;
|
||||
}
|
||||
|
||||
function isChunkIds(node) {
|
||||
// Array of numeric or string ids. Chunk IDs are strings when NamedChunksPlugin is used
|
||||
return node.type === 'ArrayExpression' && _.every(node.elements, isModuleId);
|
||||
}
|
||||
|
||||
function isAsyncChunkPushExpression(node) {
|
||||
var callee = node.callee,
|
||||
args = node.arguments;
|
||||
|
||||
|
||||
return callee.type === 'MemberExpression' && callee.property.name === 'push' && callee.object.type === 'AssignmentExpression' && callee.object.left.object && (callee.object.left.object.name === 'window' ||
|
||||
// Webpack 4 uses `this` instead of `window`
|
||||
callee.object.left.object.type === 'ThisExpression') && args.length === 1 && args[0].type === 'ArrayExpression' && mayBeAsyncChunkArguments(args[0].elements) && isModulesList(args[0].elements[1]);
|
||||
}
|
||||
|
||||
function mayBeAsyncChunkArguments(args) {
|
||||
return args.length >= 2 && isChunkIds(args[0]);
|
||||
}
|
||||
|
||||
function getModulesLocations(node) {
|
||||
if (node.type === 'ObjectExpression') {
|
||||
// Modules hash
|
||||
var modulesNodes = node.properties;
|
||||
|
||||
return _.transform(modulesNodes, function (result, moduleNode) {
|
||||
var moduleId = moduleNode.key.name || moduleNode.key.value;
|
||||
|
||||
result[moduleId] = getModuleLocation(moduleNode.value);
|
||||
}, {});
|
||||
}
|
||||
|
||||
var isOptimizedArray = node.type === 'CallExpression';
|
||||
|
||||
if (node.type === 'ArrayExpression' || isOptimizedArray) {
|
||||
// Modules array or optimized array
|
||||
var minId = isOptimizedArray ?
|
||||
// Get the [minId] value from the Array() call first argument literal value
|
||||
node.callee.object.arguments[0].value :
|
||||
// `0` for simple array
|
||||
0;
|
||||
var _modulesNodes = isOptimizedArray ?
|
||||
// The modules reside in the `concat()` function call arguments
|
||||
node.arguments[0].elements : node.elements;
|
||||
|
||||
return _.transform(_modulesNodes, function (result, moduleNode, i) {
|
||||
if (!moduleNode) return;
|
||||
result[i + minId] = getModuleLocation(moduleNode);
|
||||
}, {});
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
function getModuleLocation(node) {
|
||||
return {
|
||||
start: node.start,
|
||||
end: node.end
|
||||
};
|
||||
}
|
||||
+138
@@ -0,0 +1,138 @@
|
||||
'use strict';
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
|
||||
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
|
||||
|
||||
var _lodash = require('lodash');
|
||||
|
||||
var _lodash2 = _interopRequireDefault(_lodash);
|
||||
|
||||
var _Node2 = require('./Node');
|
||||
|
||||
var _Node3 = _interopRequireDefault(_Node2);
|
||||
|
||||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
||||
|
||||
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
|
||||
|
||||
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
|
||||
|
||||
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
|
||||
|
||||
var BaseFolder = function (_Node) {
|
||||
_inherits(BaseFolder, _Node);
|
||||
|
||||
function BaseFolder(name, parent) {
|
||||
_classCallCheck(this, BaseFolder);
|
||||
|
||||
var _this = _possibleConstructorReturn(this, (BaseFolder.__proto__ || Object.getPrototypeOf(BaseFolder)).call(this, name, parent));
|
||||
|
||||
_this.children = Object.create(null);
|
||||
return _this;
|
||||
}
|
||||
|
||||
_createClass(BaseFolder, [{
|
||||
key: 'getChild',
|
||||
value: function getChild(name) {
|
||||
return this.children[name];
|
||||
}
|
||||
}, {
|
||||
key: 'addChildModule',
|
||||
value: function addChildModule(module) {
|
||||
var name = module.name;
|
||||
|
||||
var currentChild = this.children[name];
|
||||
|
||||
// For some reason we already have this node in children and it's a folder.
|
||||
if (currentChild && currentChild instanceof BaseFolder) return;
|
||||
|
||||
if (currentChild) {
|
||||
// We already have this node in children and it's a module.
|
||||
// Merging it's data.
|
||||
currentChild.mergeData(module.data);
|
||||
} else {
|
||||
// Pushing new module
|
||||
module.parent = this;
|
||||
this.children[name] = module;
|
||||
}
|
||||
|
||||
delete this._size;
|
||||
delete this._src;
|
||||
}
|
||||
}, {
|
||||
key: 'addChildFolder',
|
||||
value: function addChildFolder(folder) {
|
||||
folder.parent = this;
|
||||
this.children[folder.name] = folder;
|
||||
delete this._size;
|
||||
delete this._src;
|
||||
|
||||
return folder;
|
||||
}
|
||||
}, {
|
||||
key: 'walk',
|
||||
value: function walk(walker) {
|
||||
var state = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
||||
var deep = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;
|
||||
|
||||
var stopped = false;
|
||||
|
||||
_lodash2.default.each(this.children, function (child) {
|
||||
if (deep && child.walk) {
|
||||
state = child.walk(walker, state, stop);
|
||||
} else {
|
||||
state = walker(child, state, stop);
|
||||
}
|
||||
|
||||
if (stopped) return false;
|
||||
});
|
||||
|
||||
return state;
|
||||
|
||||
function stop(finalState) {
|
||||
stopped = true;
|
||||
return finalState;
|
||||
}
|
||||
}
|
||||
}, {
|
||||
key: 'toChartData',
|
||||
value: function toChartData() {
|
||||
return {
|
||||
label: this.name,
|
||||
path: this.path,
|
||||
statSize: this.size,
|
||||
groups: _lodash2.default.invokeMap(this.children, 'toChartData')
|
||||
};
|
||||
}
|
||||
}, {
|
||||
key: 'src',
|
||||
get: function get() {
|
||||
if (!_lodash2.default.has(this, '_src')) {
|
||||
this._src = this.walk(function (node, src) {
|
||||
return src += node.src || '';
|
||||
}, '', false);
|
||||
}
|
||||
|
||||
return this._src;
|
||||
}
|
||||
}, {
|
||||
key: 'size',
|
||||
get: function get() {
|
||||
if (!_lodash2.default.has(this, '_size')) {
|
||||
this._size = this.walk(function (node, size) {
|
||||
return size + node.size;
|
||||
}, 0, false);
|
||||
}
|
||||
|
||||
return this._size;
|
||||
}
|
||||
}]);
|
||||
|
||||
return BaseFolder;
|
||||
}(_Node3.default);
|
||||
|
||||
exports.default = BaseFolder;
|
||||
;
|
||||
+122
@@ -0,0 +1,122 @@
|
||||
'use strict';
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
|
||||
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
|
||||
|
||||
var _get = function get(object, property, receiver) { if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { return get(parent, property, receiver); } } else if ("value" in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } };
|
||||
|
||||
var _lodash = require('lodash');
|
||||
|
||||
var _lodash2 = _interopRequireDefault(_lodash);
|
||||
|
||||
var _Module2 = require('./Module');
|
||||
|
||||
var _Module3 = _interopRequireDefault(_Module2);
|
||||
|
||||
var _ContentModule = require('./ContentModule');
|
||||
|
||||
var _ContentModule2 = _interopRequireDefault(_ContentModule);
|
||||
|
||||
var _ContentFolder = require('./ContentFolder');
|
||||
|
||||
var _ContentFolder2 = _interopRequireDefault(_ContentFolder);
|
||||
|
||||
var _utils = require('./utils');
|
||||
|
||||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
||||
|
||||
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
|
||||
|
||||
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
|
||||
|
||||
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
|
||||
|
||||
var ConcatenatedModule = function (_Module) {
|
||||
_inherits(ConcatenatedModule, _Module);
|
||||
|
||||
function ConcatenatedModule(name, data, parent) {
|
||||
_classCallCheck(this, ConcatenatedModule);
|
||||
|
||||
var _this = _possibleConstructorReturn(this, (ConcatenatedModule.__proto__ || Object.getPrototypeOf(ConcatenatedModule)).call(this, name, data, parent));
|
||||
|
||||
_this.name += ' (concatenated)';
|
||||
_this.children = Object.create(null);
|
||||
_this.fillContentModules();
|
||||
return _this;
|
||||
}
|
||||
|
||||
_createClass(ConcatenatedModule, [{
|
||||
key: 'fillContentModules',
|
||||
value: function fillContentModules() {
|
||||
var _this2 = this;
|
||||
|
||||
_lodash2.default.each(this.data.modules, function (moduleData) {
|
||||
return _this2.addContentModule(moduleData);
|
||||
});
|
||||
}
|
||||
}, {
|
||||
key: 'addContentModule',
|
||||
value: function addContentModule(moduleData) {
|
||||
var _this3 = this;
|
||||
|
||||
var pathParts = (0, _utils.getModulePathParts)(moduleData);
|
||||
|
||||
if (!pathParts) {
|
||||
return;
|
||||
}
|
||||
|
||||
var _ref = [pathParts.slice(0, -1), _lodash2.default.last(pathParts)],
|
||||
folders = _ref[0],
|
||||
fileName = _ref[1];
|
||||
|
||||
var currentFolder = this;
|
||||
|
||||
_lodash2.default.each(folders, function (folderName) {
|
||||
var childFolder = currentFolder.getChild(folderName);
|
||||
|
||||
if (!childFolder) {
|
||||
childFolder = currentFolder.addChildFolder(new _ContentFolder2.default(folderName, _this3));
|
||||
}
|
||||
|
||||
currentFolder = childFolder;
|
||||
});
|
||||
|
||||
var module = new _ContentModule2.default(fileName, moduleData, this);
|
||||
currentFolder.addChildModule(module);
|
||||
}
|
||||
}, {
|
||||
key: 'getChild',
|
||||
value: function getChild(name) {
|
||||
return this.children[name];
|
||||
}
|
||||
}, {
|
||||
key: 'addChildModule',
|
||||
value: function addChildModule(module) {
|
||||
module.parent = this;
|
||||
this.children[module.name] = module;
|
||||
}
|
||||
}, {
|
||||
key: 'addChildFolder',
|
||||
value: function addChildFolder(folder) {
|
||||
folder.parent = this;
|
||||
this.children[folder.name] = folder;
|
||||
return folder;
|
||||
}
|
||||
}, {
|
||||
key: 'toChartData',
|
||||
value: function toChartData() {
|
||||
return Object.assign({}, _get(ConcatenatedModule.prototype.__proto__ || Object.getPrototypeOf(ConcatenatedModule.prototype), 'toChartData', this).call(this), {
|
||||
concatenated: true,
|
||||
groups: _lodash2.default.invokeMap(this.children, 'toChartData')
|
||||
});
|
||||
}
|
||||
}]);
|
||||
|
||||
return ConcatenatedModule;
|
||||
}(_Module3.default);
|
||||
|
||||
exports.default = ConcatenatedModule;
|
||||
;
|
||||
+69
@@ -0,0 +1,69 @@
|
||||
'use strict';
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
|
||||
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
|
||||
|
||||
var _get = function get(object, property, receiver) { if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { return get(parent, property, receiver); } } else if ("value" in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } };
|
||||
|
||||
var _BaseFolder2 = require('./BaseFolder');
|
||||
|
||||
var _BaseFolder3 = _interopRequireDefault(_BaseFolder2);
|
||||
|
||||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
||||
|
||||
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
|
||||
|
||||
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
|
||||
|
||||
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
|
||||
|
||||
var ContentFolder = function (_BaseFolder) {
|
||||
_inherits(ContentFolder, _BaseFolder);
|
||||
|
||||
function ContentFolder(name, ownerModule, parent) {
|
||||
_classCallCheck(this, ContentFolder);
|
||||
|
||||
var _this = _possibleConstructorReturn(this, (ContentFolder.__proto__ || Object.getPrototypeOf(ContentFolder)).call(this, name, parent));
|
||||
|
||||
_this.ownerModule = ownerModule;
|
||||
return _this;
|
||||
}
|
||||
|
||||
_createClass(ContentFolder, [{
|
||||
key: 'getSize',
|
||||
value: function getSize(sizeType) {
|
||||
var ownerModuleSize = this.ownerModule[sizeType];
|
||||
|
||||
if (ownerModuleSize !== undefined) {
|
||||
return Math.floor(this.size / this.ownerModule.size * ownerModuleSize);
|
||||
}
|
||||
}
|
||||
}, {
|
||||
key: 'toChartData',
|
||||
value: function toChartData() {
|
||||
return Object.assign({}, _get(ContentFolder.prototype.__proto__ || Object.getPrototypeOf(ContentFolder.prototype), 'toChartData', this).call(this), {
|
||||
parsedSize: this.parsedSize,
|
||||
gzipSize: this.gzipSize,
|
||||
inaccurateSizes: true
|
||||
});
|
||||
}
|
||||
}, {
|
||||
key: 'parsedSize',
|
||||
get: function get() {
|
||||
return this.getSize('parsedSize');
|
||||
}
|
||||
}, {
|
||||
key: 'gzipSize',
|
||||
get: function get() {
|
||||
return this.getSize('gzipSize');
|
||||
}
|
||||
}]);
|
||||
|
||||
return ContentFolder;
|
||||
}(_BaseFolder3.default);
|
||||
|
||||
exports.default = ContentFolder;
|
||||
;
|
||||
+67
@@ -0,0 +1,67 @@
|
||||
'use strict';
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
|
||||
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
|
||||
|
||||
var _get = function get(object, property, receiver) { if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { return get(parent, property, receiver); } } else if ("value" in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } };
|
||||
|
||||
var _Module2 = require('./Module');
|
||||
|
||||
var _Module3 = _interopRequireDefault(_Module2);
|
||||
|
||||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
||||
|
||||
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
|
||||
|
||||
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
|
||||
|
||||
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
|
||||
|
||||
var ContentModule = function (_Module) {
|
||||
_inherits(ContentModule, _Module);
|
||||
|
||||
function ContentModule(name, data, ownerModule, parent) {
|
||||
_classCallCheck(this, ContentModule);
|
||||
|
||||
var _this = _possibleConstructorReturn(this, (ContentModule.__proto__ || Object.getPrototypeOf(ContentModule)).call(this, name, data, parent));
|
||||
|
||||
_this.ownerModule = ownerModule;
|
||||
return _this;
|
||||
}
|
||||
|
||||
_createClass(ContentModule, [{
|
||||
key: 'getSize',
|
||||
value: function getSize(sizeType) {
|
||||
var ownerModuleSize = this.ownerModule[sizeType];
|
||||
|
||||
if (ownerModuleSize !== undefined) {
|
||||
return Math.floor(this.size / this.ownerModule.size * ownerModuleSize);
|
||||
}
|
||||
}
|
||||
}, {
|
||||
key: 'toChartData',
|
||||
value: function toChartData() {
|
||||
return Object.assign({}, _get(ContentModule.prototype.__proto__ || Object.getPrototypeOf(ContentModule.prototype), 'toChartData', this).call(this), {
|
||||
inaccurateSizes: true
|
||||
});
|
||||
}
|
||||
}, {
|
||||
key: 'parsedSize',
|
||||
get: function get() {
|
||||
return this.getSize('parsedSize');
|
||||
}
|
||||
}, {
|
||||
key: 'gzipSize',
|
||||
get: function get() {
|
||||
return this.getSize('gzipSize');
|
||||
}
|
||||
}]);
|
||||
|
||||
return ContentModule;
|
||||
}(_Module3.default);
|
||||
|
||||
exports.default = ContentModule;
|
||||
;
|
||||
+114
@@ -0,0 +1,114 @@
|
||||
'use strict';
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
|
||||
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
|
||||
|
||||
var _get = function get(object, property, receiver) { if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { return get(parent, property, receiver); } } else if ("value" in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } };
|
||||
|
||||
var _lodash = require('lodash');
|
||||
|
||||
var _lodash2 = _interopRequireDefault(_lodash);
|
||||
|
||||
var _gzipSize = require('gzip-size');
|
||||
|
||||
var _gzipSize2 = _interopRequireDefault(_gzipSize);
|
||||
|
||||
var _Module = require('./Module');
|
||||
|
||||
var _Module2 = _interopRequireDefault(_Module);
|
||||
|
||||
var _BaseFolder2 = require('./BaseFolder');
|
||||
|
||||
var _BaseFolder3 = _interopRequireDefault(_BaseFolder2);
|
||||
|
||||
var _ConcatenatedModule = require('./ConcatenatedModule');
|
||||
|
||||
var _ConcatenatedModule2 = _interopRequireDefault(_ConcatenatedModule);
|
||||
|
||||
var _utils = require('./utils');
|
||||
|
||||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
||||
|
||||
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
|
||||
|
||||
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
|
||||
|
||||
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
|
||||
|
||||
var Folder = function (_BaseFolder) {
|
||||
_inherits(Folder, _BaseFolder);
|
||||
|
||||
function Folder() {
|
||||
_classCallCheck(this, Folder);
|
||||
|
||||
return _possibleConstructorReturn(this, (Folder.__proto__ || Object.getPrototypeOf(Folder)).apply(this, arguments));
|
||||
}
|
||||
|
||||
_createClass(Folder, [{
|
||||
key: 'addModule',
|
||||
value: function addModule(moduleData) {
|
||||
var pathParts = (0, _utils.getModulePathParts)(moduleData);
|
||||
|
||||
if (!pathParts) {
|
||||
return;
|
||||
}
|
||||
|
||||
var _ref = [pathParts.slice(0, -1), _lodash2.default.last(pathParts)],
|
||||
folders = _ref[0],
|
||||
fileName = _ref[1];
|
||||
|
||||
var currentFolder = this;
|
||||
|
||||
_lodash2.default.each(folders, function (folderName) {
|
||||
var childNode = currentFolder.getChild(folderName);
|
||||
|
||||
if (
|
||||
// Folder is not created yet
|
||||
!childNode ||
|
||||
// In some situations (invalid usage of dynamic `require()`) webpack generates a module with empty require
|
||||
// context, but it's moduleId points to a directory in filesystem.
|
||||
// In this case we replace this `File` node with `Folder`.
|
||||
// See `test/stats/with-invalid-dynamic-require.json` as an example.
|
||||
!(childNode instanceof Folder)) {
|
||||
childNode = currentFolder.addChildFolder(new Folder(folderName));
|
||||
}
|
||||
|
||||
currentFolder = childNode;
|
||||
});
|
||||
|
||||
var ModuleConstructor = moduleData.modules ? _ConcatenatedModule2.default : _Module2.default;
|
||||
var module = new ModuleConstructor(fileName, moduleData, this);
|
||||
currentFolder.addChildModule(module);
|
||||
}
|
||||
}, {
|
||||
key: 'toChartData',
|
||||
value: function toChartData() {
|
||||
return Object.assign({}, _get(Folder.prototype.__proto__ || Object.getPrototypeOf(Folder.prototype), 'toChartData', this).call(this), {
|
||||
parsedSize: this.parsedSize,
|
||||
gzipSize: this.gzipSize
|
||||
});
|
||||
}
|
||||
}, {
|
||||
key: 'parsedSize',
|
||||
get: function get() {
|
||||
return this.src ? this.src.length : 0;
|
||||
}
|
||||
}, {
|
||||
key: 'gzipSize',
|
||||
get: function get() {
|
||||
if (!_lodash2.default.has(this, '_gzipSize')) {
|
||||
this._gzipSize = this.src ? _gzipSize2.default.sync(this.src) : 0;
|
||||
}
|
||||
|
||||
return this._gzipSize;
|
||||
}
|
||||
}]);
|
||||
|
||||
return Folder;
|
||||
}(_BaseFolder3.default);
|
||||
|
||||
exports.default = Folder;
|
||||
;
|
||||
+101
@@ -0,0 +1,101 @@
|
||||
'use strict';
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
|
||||
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
|
||||
|
||||
var _lodash = require('lodash');
|
||||
|
||||
var _lodash2 = _interopRequireDefault(_lodash);
|
||||
|
||||
var _gzipSize = require('gzip-size');
|
||||
|
||||
var _gzipSize2 = _interopRequireDefault(_gzipSize);
|
||||
|
||||
var _Node2 = require('./Node');
|
||||
|
||||
var _Node3 = _interopRequireDefault(_Node2);
|
||||
|
||||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
||||
|
||||
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
|
||||
|
||||
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
|
||||
|
||||
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
|
||||
|
||||
var Module = function (_Node) {
|
||||
_inherits(Module, _Node);
|
||||
|
||||
function Module(name, data, parent) {
|
||||
_classCallCheck(this, Module);
|
||||
|
||||
var _this = _possibleConstructorReturn(this, (Module.__proto__ || Object.getPrototypeOf(Module)).call(this, name, parent));
|
||||
|
||||
_this.data = data;
|
||||
return _this;
|
||||
}
|
||||
|
||||
_createClass(Module, [{
|
||||
key: 'mergeData',
|
||||
value: function mergeData(data) {
|
||||
if (data.size) {
|
||||
this.size += data.size;
|
||||
}
|
||||
|
||||
if (data.parsedSrc) {
|
||||
this.src = (this.src || '') + data.parsedSrc;
|
||||
}
|
||||
}
|
||||
}, {
|
||||
key: 'toChartData',
|
||||
value: function toChartData() {
|
||||
return {
|
||||
id: this.data.id,
|
||||
label: this.name,
|
||||
path: this.path,
|
||||
statSize: this.size,
|
||||
parsedSize: this.parsedSize,
|
||||
gzipSize: this.gzipSize
|
||||
};
|
||||
}
|
||||
}, {
|
||||
key: 'src',
|
||||
get: function get() {
|
||||
return this.data.parsedSrc;
|
||||
},
|
||||
set: function set(value) {
|
||||
this.data.parsedSrc = value;
|
||||
delete this._gzipSize;
|
||||
}
|
||||
}, {
|
||||
key: 'size',
|
||||
get: function get() {
|
||||
return this.data.size;
|
||||
},
|
||||
set: function set(value) {
|
||||
this.data.size = value;
|
||||
}
|
||||
}, {
|
||||
key: 'parsedSize',
|
||||
get: function get() {
|
||||
return this.src ? this.src.length : undefined;
|
||||
}
|
||||
}, {
|
||||
key: 'gzipSize',
|
||||
get: function get() {
|
||||
if (!_lodash2.default.has(this, '_gzipSize')) {
|
||||
this._gzipSize = this.src ? _gzipSize2.default.sync(this.src) : undefined;
|
||||
}
|
||||
|
||||
return this._gzipSize;
|
||||
}
|
||||
}]);
|
||||
|
||||
return Module;
|
||||
}(_Node3.default);
|
||||
|
||||
exports.default = Module;
|
||||
;
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
'use strict';
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
|
||||
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
|
||||
|
||||
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
|
||||
|
||||
var Node = function () {
|
||||
function Node(name, parent) {
|
||||
_classCallCheck(this, Node);
|
||||
|
||||
this.name = name;
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
_createClass(Node, [{
|
||||
key: 'path',
|
||||
get: function get() {
|
||||
var path = [];
|
||||
var node = this;
|
||||
|
||||
while (node) {
|
||||
path.push(node.name);
|
||||
node = node.parent;
|
||||
}
|
||||
|
||||
return path.reverse().join('/');
|
||||
}
|
||||
}]);
|
||||
|
||||
return Node;
|
||||
}();
|
||||
|
||||
exports.default = Node;
|
||||
;
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
'use strict';
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.getModulePathParts = getModulePathParts;
|
||||
|
||||
var _lodash = require('lodash');
|
||||
|
||||
var _lodash2 = _interopRequireDefault(_lodash);
|
||||
|
||||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
||||
|
||||
var MULTI_MODULE_REGEXP = /^multi /;
|
||||
|
||||
function getModulePathParts(moduleData) {
|
||||
if (MULTI_MODULE_REGEXP.test(moduleData.identifier)) {
|
||||
return [moduleData.identifier];
|
||||
}
|
||||
|
||||
var parsedPath = _lodash2.default
|
||||
// Removing loaders from module path: they're joined by `!` and the last part is a raw module path
|
||||
.last(moduleData.name.split('!'))
|
||||
// Splitting module path into parts
|
||||
.split('/')
|
||||
// Removing first `.`
|
||||
.slice(1)
|
||||
// Replacing `~` with `node_modules`
|
||||
.map(function (part) {
|
||||
return part === '~' ? 'node_modules' : part;
|
||||
});
|
||||
|
||||
return parsedPath.length ? parsedPath : null;
|
||||
}
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
'use strict';
|
||||
|
||||
var _require = require('util'),
|
||||
inspect = _require.inspect;
|
||||
|
||||
var _ = require('lodash');
|
||||
|
||||
exports.createAssetsFilter = createAssetsFilter;
|
||||
|
||||
function createAssetsFilter(excludePatterns) {
|
||||
var excludeFunctions = _(excludePatterns).castArray().compact().map(function (pattern) {
|
||||
if (typeof pattern === 'string') {
|
||||
pattern = new RegExp(pattern);
|
||||
}
|
||||
|
||||
if (_.isRegExp(pattern)) {
|
||||
return function (asset) {
|
||||
return pattern.test(asset);
|
||||
};
|
||||
}
|
||||
|
||||
if (!_.isFunction(pattern)) {
|
||||
throw new TypeError(`Pattern should be either string, RegExp or a function, but "${inspect(pattern, { depth: 0 })}" got.`);
|
||||
}
|
||||
|
||||
return pattern;
|
||||
}).value();
|
||||
|
||||
if (excludeFunctions.length) {
|
||||
return function (asset) {
|
||||
return _.every(excludeFunctions, function (fn) {
|
||||
return fn(asset) !== true;
|
||||
});
|
||||
};
|
||||
} else {
|
||||
return function () {
|
||||
return true;
|
||||
};
|
||||
}
|
||||
}
|
||||
+197
@@ -0,0 +1,197 @@
|
||||
'use strict';
|
||||
|
||||
var startServer = function () {
|
||||
var _ref = _asyncToGenerator(function* (bundleStats, opts) {
|
||||
var _ref2 = opts || {},
|
||||
_ref2$port = _ref2.port,
|
||||
port = _ref2$port === undefined ? 8888 : _ref2$port,
|
||||
_ref2$host = _ref2.host,
|
||||
host = _ref2$host === undefined ? '127.0.0.1' : _ref2$host,
|
||||
_ref2$openBrowser = _ref2.openBrowser,
|
||||
openBrowser = _ref2$openBrowser === undefined ? true : _ref2$openBrowser,
|
||||
_ref2$bundleDir = _ref2.bundleDir,
|
||||
bundleDir = _ref2$bundleDir === undefined ? null : _ref2$bundleDir,
|
||||
_ref2$logger = _ref2.logger,
|
||||
logger = _ref2$logger === undefined ? new Logger() : _ref2$logger,
|
||||
_ref2$defaultSizes = _ref2.defaultSizes,
|
||||
defaultSizes = _ref2$defaultSizes === undefined ? 'parsed' : _ref2$defaultSizes,
|
||||
_ref2$excludeAssets = _ref2.excludeAssets,
|
||||
excludeAssets = _ref2$excludeAssets === undefined ? null : _ref2$excludeAssets;
|
||||
|
||||
var analyzerOpts = { logger, excludeAssets };
|
||||
|
||||
var chartData = getChartData(analyzerOpts, bundleStats, bundleDir);
|
||||
|
||||
if (!chartData) return;
|
||||
|
||||
var app = express();
|
||||
|
||||
// Explicitly using our `ejs` dependency to render templates
|
||||
// Fixes #17
|
||||
app.engine('ejs', require('ejs').renderFile);
|
||||
app.set('view engine', 'ejs');
|
||||
app.set('views', `${projectRoot}/views`);
|
||||
app.use(express.static(`${projectRoot}/public`));
|
||||
|
||||
app.use('/', function (req, res) {
|
||||
res.render('viewer', {
|
||||
mode: 'server',
|
||||
get chartData() {
|
||||
return JSON.stringify(chartData);
|
||||
},
|
||||
defaultSizes: JSON.stringify(defaultSizes)
|
||||
});
|
||||
});
|
||||
|
||||
var server = http.createServer(app);
|
||||
|
||||
yield new Promise(function (resolve) {
|
||||
server.listen(port, host, function () {
|
||||
resolve();
|
||||
|
||||
var url = `http://${host}:${server.address().port}`;
|
||||
|
||||
logger.info(`${bold('Webpack Bundle Analyzer')} is started at ${bold(url)}\n` + `Use ${bold('Ctrl+C')} to close it`);
|
||||
|
||||
if (openBrowser) {
|
||||
opener(url);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
var wss = new WebSocket.Server({ server });
|
||||
|
||||
wss.on('connection', function (ws) {
|
||||
ws.on('error', function (err) {
|
||||
// Ignore network errors like `ECONNRESET`, `EPIPE`, etc.
|
||||
if (err.errno) return;
|
||||
|
||||
logger.info(err.message);
|
||||
});
|
||||
});
|
||||
|
||||
return {
|
||||
ws: wss,
|
||||
http: server,
|
||||
updateChartData
|
||||
};
|
||||
|
||||
function updateChartData(bundleStats) {
|
||||
var newChartData = getChartData(analyzerOpts, bundleStats, bundleDir);
|
||||
|
||||
if (!newChartData) return;
|
||||
|
||||
chartData = newChartData;
|
||||
|
||||
wss.clients.forEach(function (client) {
|
||||
if (client.readyState === WebSocket.OPEN) {
|
||||
client.send(JSON.stringify({
|
||||
event: 'chartDataUpdated',
|
||||
data: newChartData
|
||||
}));
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
return function startServer(_x, _x2) {
|
||||
return _ref.apply(this, arguments);
|
||||
};
|
||||
}();
|
||||
|
||||
function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; }
|
||||
|
||||
var path = require('path');
|
||||
var fs = require('fs');
|
||||
var http = require('http');
|
||||
|
||||
var WebSocket = require('ws');
|
||||
var _ = require('lodash');
|
||||
var express = require('express');
|
||||
var ejs = require('ejs');
|
||||
var opener = require('opener');
|
||||
var mkdir = require('mkdirp');
|
||||
|
||||
var _require = require('chalk'),
|
||||
bold = _require.bold;
|
||||
|
||||
var Logger = require('./Logger');
|
||||
var analyzer = require('./analyzer');
|
||||
|
||||
var projectRoot = path.resolve(__dirname, '..');
|
||||
|
||||
module.exports = {
|
||||
startServer,
|
||||
generateReport,
|
||||
// deprecated
|
||||
start: startServer
|
||||
};
|
||||
|
||||
function generateReport(bundleStats, opts) {
|
||||
var _ref3 = opts || {},
|
||||
_ref3$openBrowser = _ref3.openBrowser,
|
||||
openBrowser = _ref3$openBrowser === undefined ? true : _ref3$openBrowser,
|
||||
_ref3$reportFilename = _ref3.reportFilename,
|
||||
reportFilename = _ref3$reportFilename === undefined ? 'report.html' : _ref3$reportFilename,
|
||||
_ref3$bundleDir = _ref3.bundleDir,
|
||||
bundleDir = _ref3$bundleDir === undefined ? null : _ref3$bundleDir,
|
||||
_ref3$logger = _ref3.logger,
|
||||
logger = _ref3$logger === undefined ? new Logger() : _ref3$logger,
|
||||
_ref3$defaultSizes = _ref3.defaultSizes,
|
||||
defaultSizes = _ref3$defaultSizes === undefined ? 'parsed' : _ref3$defaultSizes,
|
||||
_ref3$excludeAssets = _ref3.excludeAssets,
|
||||
excludeAssets = _ref3$excludeAssets === undefined ? null : _ref3$excludeAssets;
|
||||
|
||||
var chartData = getChartData({ logger, excludeAssets }, bundleStats, bundleDir);
|
||||
|
||||
if (!chartData) return;
|
||||
|
||||
ejs.renderFile(`${projectRoot}/views/viewer.ejs`, {
|
||||
mode: 'static',
|
||||
chartData: JSON.stringify(chartData),
|
||||
assetContent: getAssetContent,
|
||||
defaultSizes: JSON.stringify(defaultSizes)
|
||||
}, function (err, reportHtml) {
|
||||
if (err) return logger.error(err);
|
||||
|
||||
var reportFilepath = path.resolve(bundleDir || process.cwd(), reportFilename);
|
||||
|
||||
mkdir.sync(path.dirname(reportFilepath));
|
||||
fs.writeFileSync(reportFilepath, reportHtml);
|
||||
|
||||
logger.info(`${bold('Webpack Bundle Analyzer')} saved report to ${bold(reportFilepath)}`);
|
||||
|
||||
if (openBrowser) {
|
||||
opener(`file://${reportFilepath}`);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function getAssetContent(filename) {
|
||||
return fs.readFileSync(`${projectRoot}/public/${filename}`, 'utf8');
|
||||
}
|
||||
|
||||
function getChartData(analyzerOpts) {
|
||||
var chartData = void 0;
|
||||
var logger = analyzerOpts.logger;
|
||||
|
||||
|
||||
try {
|
||||
for (var _len = arguments.length, args = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
|
||||
args[_key - 1] = arguments[_key];
|
||||
}
|
||||
|
||||
chartData = analyzer.getViewerData.apply(analyzer, args.concat([analyzerOpts]));
|
||||
} catch (err) {
|
||||
logger.error(`Could't analyze webpack bundle:\n${err}`);
|
||||
logger.debug(err.stack);
|
||||
chartData = null;
|
||||
}
|
||||
|
||||
if (_.isPlainObject(chartData) && _.isEmpty(chartData)) {
|
||||
logger.error("Could't find any javascript bundles in provided stats file");
|
||||
chartData = null;
|
||||
}
|
||||
|
||||
return chartData;
|
||||
}
|
||||
Reference in New Issue
Block a user