BundleAnalyzerPlugin.js 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. "use strict";
  2. function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } }
  3. function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; }
  4. function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; }
  5. function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
  6. function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
  7. const bfj = require('bfj');
  8. const path = require('path');
  9. const mkdir = require('mkdirp');
  10. const {
  11. bold
  12. } = require('chalk');
  13. const Logger = require('./Logger');
  14. const viewer = require('./viewer');
  15. const utils = require('./utils');
  16. class BundleAnalyzerPlugin {
  17. constructor(opts = {}) {
  18. this.opts = _objectSpread({
  19. analyzerMode: 'server',
  20. analyzerHost: '127.0.0.1',
  21. reportFilename: null,
  22. reportTitle: utils.defaultTitle,
  23. defaultSizes: 'parsed',
  24. openAnalyzer: true,
  25. generateStatsFile: false,
  26. statsFilename: 'stats.json',
  27. statsOptions: null,
  28. excludeAssets: null,
  29. logLevel: 'info',
  30. // deprecated
  31. startAnalyzer: true
  32. }, opts, {
  33. analyzerPort: 'analyzerPort' in opts ? opts.analyzerPort === 'auto' ? 0 : opts.analyzerPort : 8888
  34. });
  35. this.server = null;
  36. this.logger = new Logger(this.opts.logLevel);
  37. }
  38. apply(compiler) {
  39. this.compiler = compiler;
  40. const done = (stats, callback) => {
  41. callback = callback || (() => {});
  42. const actions = [];
  43. if (this.opts.generateStatsFile) {
  44. actions.push(() => this.generateStatsFile(stats.toJson(this.opts.statsOptions)));
  45. } // Handling deprecated `startAnalyzer` flag
  46. if (this.opts.analyzerMode === 'server' && !this.opts.startAnalyzer) {
  47. this.opts.analyzerMode = 'disabled';
  48. }
  49. if (this.opts.analyzerMode === 'server') {
  50. actions.push(() => this.startAnalyzerServer(stats.toJson()));
  51. } else if (this.opts.analyzerMode === 'static') {
  52. actions.push(() => this.generateStaticReport(stats.toJson()));
  53. } else if (this.opts.analyzerMode === 'json') {
  54. actions.push(() => this.generateJSONReport(stats.toJson()));
  55. }
  56. if (actions.length) {
  57. // Making analyzer logs to be after all webpack logs in the console
  58. setImmediate( /*#__PURE__*/_asyncToGenerator(function* () {
  59. try {
  60. yield Promise.all(actions.map(action => action()));
  61. callback();
  62. } catch (e) {
  63. callback(e);
  64. }
  65. }));
  66. } else {
  67. callback();
  68. }
  69. };
  70. if (compiler.hooks) {
  71. compiler.hooks.done.tapAsync('webpack-bundle-analyzer', done);
  72. } else {
  73. compiler.plugin('done', done);
  74. }
  75. }
  76. generateStatsFile(stats) {
  77. var _this = this;
  78. return _asyncToGenerator(function* () {
  79. const statsFilepath = path.resolve(_this.compiler.outputPath, _this.opts.statsFilename);
  80. mkdir.sync(path.dirname(statsFilepath));
  81. try {
  82. yield bfj.write(statsFilepath, stats, {
  83. space: 2,
  84. promises: 'ignore',
  85. buffers: 'ignore',
  86. maps: 'ignore',
  87. iterables: 'ignore',
  88. circular: 'ignore'
  89. });
  90. _this.logger.info(`${bold('Webpack Bundle Analyzer')} saved stats file to ${bold(statsFilepath)}`);
  91. } catch (error) {
  92. _this.logger.error(`${bold('Webpack Bundle Analyzer')} error saving stats file to ${bold(statsFilepath)}: ${error}`);
  93. }
  94. })();
  95. }
  96. startAnalyzerServer(stats) {
  97. var _this2 = this;
  98. return _asyncToGenerator(function* () {
  99. if (_this2.server) {
  100. (yield _this2.server).updateChartData(stats);
  101. } else {
  102. _this2.server = viewer.startServer(stats, {
  103. openBrowser: _this2.opts.openAnalyzer,
  104. host: _this2.opts.analyzerHost,
  105. port: _this2.opts.analyzerPort,
  106. reportTitle: _this2.opts.reportTitle,
  107. bundleDir: _this2.getBundleDirFromCompiler(),
  108. logger: _this2.logger,
  109. defaultSizes: _this2.opts.defaultSizes,
  110. excludeAssets: _this2.opts.excludeAssets
  111. });
  112. }
  113. })();
  114. }
  115. generateJSONReport(stats) {
  116. var _this3 = this;
  117. return _asyncToGenerator(function* () {
  118. yield viewer.generateJSONReport(stats, {
  119. reportFilename: path.resolve(_this3.compiler.outputPath, _this3.opts.reportFilename || 'report.json'),
  120. bundleDir: _this3.getBundleDirFromCompiler(),
  121. logger: _this3.logger,
  122. excludeAssets: _this3.opts.excludeAssets
  123. });
  124. })();
  125. }
  126. generateStaticReport(stats) {
  127. var _this4 = this;
  128. return _asyncToGenerator(function* () {
  129. yield viewer.generateReport(stats, {
  130. openBrowser: _this4.opts.openAnalyzer,
  131. reportFilename: path.resolve(_this4.compiler.outputPath, _this4.opts.reportFilename || 'report.html'),
  132. reportTitle: _this4.opts.reportTitle,
  133. bundleDir: _this4.getBundleDirFromCompiler(),
  134. logger: _this4.logger,
  135. defaultSizes: _this4.opts.defaultSizes,
  136. excludeAssets: _this4.opts.excludeAssets
  137. });
  138. })();
  139. }
  140. getBundleDirFromCompiler() {
  141. switch (this.compiler.outputFileSystem.constructor.name) {
  142. case 'MemoryFileSystem':
  143. return null;
  144. // Detect AsyncMFS used by Nuxt 2.5 that replaces webpack's MFS during development
  145. // Related: #274
  146. case 'AsyncMFS':
  147. return null;
  148. default:
  149. return this.compiler.outputPath;
  150. }
  151. }
  152. }
  153. module.exports = BundleAnalyzerPlugin;