index.js 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. "use strict";
  2. var __importDefault = (this && this.__importDefault) || function (mod) {
  3. return (mod && mod.__esModule) ? mod : { "default": mod };
  4. };
  5. Object.defineProperty(exports, "__esModule", { value: true });
  6. exports.visualizer = void 0;
  7. const fs_1 = require("fs");
  8. const path_1 = __importDefault(require("path"));
  9. const open_1 = __importDefault(require("open"));
  10. const version_1 = require("./version");
  11. const compress_1 = require("./compress");
  12. const module_mapper_1 = require("./module-mapper");
  13. const data_1 = require("./data");
  14. const sourcemap_1 = require("./sourcemap");
  15. const render_template_1 = require("./render-template");
  16. const create_filter_1 = require("../shared/create-filter");
  17. const WARN_SOURCEMAP_DISABLED = "rollup output configuration missing sourcemap = true. You should add output.sourcemap = true or disable sourcemap in this plugin";
  18. const WARN_SOURCEMAP_MISSING = (id) => `${id} missing source map`;
  19. const WARN_JSON_DEPRECATED = 'Option `json` deprecated, please use template: "raw-data"';
  20. const ERR_FILENAME_EMIT = "When using emitFile option, filename must not be path but a filename";
  21. const defaultSizeGetter = () => Promise.resolve(0);
  22. const chooseDefaultFileName = (opts) => {
  23. if (opts.filename)
  24. return opts.filename;
  25. if (opts.json || opts.template === "raw-data")
  26. return "stats.json";
  27. if (opts.template === "list")
  28. return "stats.yml";
  29. return "stats.html";
  30. };
  31. const visualizer = (opts = {}) => {
  32. return {
  33. name: "visualizer",
  34. async generateBundle(outputOptions, outputBundle) {
  35. var _a, _b, _c, _d, _e, _f, _g, _h;
  36. opts = typeof opts === "function" ? opts(outputOptions) : opts;
  37. if ("json" in opts) {
  38. this.warn(WARN_JSON_DEPRECATED);
  39. if (opts.json)
  40. opts.template = "raw-data";
  41. }
  42. const filename = (_a = opts.filename) !== null && _a !== void 0 ? _a : chooseDefaultFileName(opts);
  43. const title = (_b = opts.title) !== null && _b !== void 0 ? _b : "Rollup Visualizer";
  44. const open = !!opts.open;
  45. const openOptions = (_c = opts.openOptions) !== null && _c !== void 0 ? _c : {};
  46. const template = (_d = opts.template) !== null && _d !== void 0 ? _d : "treemap";
  47. const projectRoot = (_e = opts.projectRoot) !== null && _e !== void 0 ? _e : process.cwd();
  48. const filter = (0, create_filter_1.createFilter)(opts.include, opts.exclude);
  49. const gzipSize = !!opts.gzipSize && !opts.sourcemap;
  50. const brotliSize = !!opts.brotliSize && !opts.sourcemap;
  51. const gzipSizeGetter = gzipSize
  52. ? (0, compress_1.createGzipSizeGetter)(typeof opts.gzipSize === "object" ? opts.gzipSize : {})
  53. : defaultSizeGetter;
  54. const brotliSizeGetter = brotliSize
  55. ? (0, compress_1.createBrotliSizeGetter)(typeof opts.brotliSize === "object" ? opts.brotliSize : {})
  56. : defaultSizeGetter;
  57. const ModuleLengths = async ({ id, renderedLength, code, }) => {
  58. const isCodeEmpty = code == null || code == "";
  59. const result = {
  60. id,
  61. gzipLength: isCodeEmpty ? 0 : await gzipSizeGetter(code),
  62. brotliLength: isCodeEmpty ? 0 : await brotliSizeGetter(code),
  63. renderedLength: isCodeEmpty ? renderedLength : Buffer.byteLength(code, "utf-8"),
  64. };
  65. return result;
  66. };
  67. if (opts.sourcemap && !outputOptions.sourcemap) {
  68. this.warn(WARN_SOURCEMAP_DISABLED);
  69. }
  70. const roots = [];
  71. const mapper = new module_mapper_1.ModuleMapper(projectRoot);
  72. // collect trees
  73. for (const [bundleId, bundle] of Object.entries(outputBundle)) {
  74. if (bundle.type !== "chunk")
  75. continue; //only chunks
  76. let tree;
  77. if (opts.sourcemap) {
  78. if (!bundle.map) {
  79. this.warn(WARN_SOURCEMAP_MISSING(bundleId));
  80. }
  81. const modules = await (0, sourcemap_1.getSourcemapModules)(bundleId, bundle, (_g = (_f = outputOptions.dir) !== null && _f !== void 0 ? _f : (outputOptions.file && path_1.default.dirname(outputOptions.file))) !== null && _g !== void 0 ? _g : process.cwd());
  82. const moduleRenderInfo = await Promise.all(Object.values(modules)
  83. .filter(({ id }) => filter(bundleId, id))
  84. .map(({ id, renderedLength }) => {
  85. var _a;
  86. const code = (_a = bundle.modules[id]) === null || _a === void 0 ? void 0 : _a.code;
  87. return ModuleLengths({ id, renderedLength, code });
  88. }));
  89. tree = (0, data_1.buildTree)(bundleId, moduleRenderInfo, mapper);
  90. }
  91. else {
  92. const modules = await Promise.all(Object.entries(bundle.modules)
  93. .filter(([id]) => filter(bundleId, id))
  94. .map(([id, { renderedLength, code }]) => ModuleLengths({ id, renderedLength, code })));
  95. tree = (0, data_1.buildTree)(bundleId, modules, mapper);
  96. }
  97. if (tree.children.length === 0) {
  98. const bundleSizes = await ModuleLengths({
  99. id: bundleId,
  100. renderedLength: bundle.code.length,
  101. code: bundle.code,
  102. });
  103. const facadeModuleId = (_h = bundle.facadeModuleId) !== null && _h !== void 0 ? _h : `${bundleId}-unknown`;
  104. const bundleUid = mapper.setNodePart(bundleId, facadeModuleId, bundleSizes);
  105. mapper.setNodeMeta(facadeModuleId, { isEntry: true });
  106. const leaf = { name: bundleId, uid: bundleUid };
  107. roots.push(leaf);
  108. }
  109. else {
  110. roots.push(tree);
  111. }
  112. }
  113. // after trees we process links (this is mostly for uids)
  114. for (const [, bundle] of Object.entries(outputBundle)) {
  115. if (bundle.type !== "chunk" || bundle.facadeModuleId == null)
  116. continue; //only chunks
  117. (0, data_1.addLinks)(bundle.facadeModuleId, this.getModuleInfo.bind(this), mapper);
  118. }
  119. const tree = (0, data_1.mergeTrees)(roots);
  120. const data = {
  121. version: version_1.version,
  122. tree,
  123. nodeParts: mapper.getNodeParts(),
  124. nodeMetas: mapper.getNodeMetas(),
  125. env: {
  126. rollup: this.meta.rollupVersion,
  127. },
  128. options: {
  129. gzip: gzipSize,
  130. brotli: brotliSize,
  131. sourcemap: !!opts.sourcemap,
  132. },
  133. };
  134. const fileContent = await (0, render_template_1.renderTemplate)(template, {
  135. title,
  136. data,
  137. });
  138. if (opts.emitFile) {
  139. if (path_1.default.isAbsolute(filename) || filename.startsWith(".")) {
  140. this.error(ERR_FILENAME_EMIT);
  141. }
  142. this.emitFile({
  143. type: "asset",
  144. fileName: filename,
  145. source: fileContent,
  146. });
  147. }
  148. else {
  149. await fs_1.promises.mkdir(path_1.default.dirname(filename), { recursive: true });
  150. await fs_1.promises.writeFile(filename, fileContent);
  151. if (open) {
  152. await (0, open_1.default)(filename, openOptions);
  153. }
  154. }
  155. },
  156. };
  157. };
  158. exports.visualizer = visualizer;
  159. exports.default = exports.visualizer;