utils.js 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. const isEqual = (x, y) =>
  2. Array.isArray(x)
  3. ? Array.isArray(y) &&
  4. x.every(xi => y.includes(xi)) &&
  5. y.every(yi => x.includes(yi))
  6. : x === y;
  7. const mergeRanges = rangeList => {
  8. const mergedQueue = [];
  9. const inputQueue = [...rangeList];
  10. while (inputQueue.length) {
  11. const cur = inputQueue.pop();
  12. const overlapIndex = mergedQueue.findIndex(
  13. item =>
  14. (item.start >= cur.start && item.start <= cur.end) ||
  15. (item.end >= cur.start && item.end <= cur.end)
  16. );
  17. if (overlapIndex === -1) {
  18. mergedQueue.push(cur);
  19. } else {
  20. const toMerge = mergedQueue.splice(overlapIndex, 1)[0];
  21. inputQueue.push({
  22. start: Math.min(cur.start, cur.end, toMerge.start, toMerge.end),
  23. end: Math.max(cur.start, cur.end, toMerge.start, toMerge.end),
  24. });
  25. }
  26. }
  27. return mergedQueue;
  28. };
  29. const sqr = x => x * x;
  30. const mean = xs => xs.reduce((acc, x) => acc + x, 0) / xs.length;
  31. const median = xs => xs.sort()[Math.floor(xs.length / 2)];
  32. const variance = (xs, mean) =>
  33. xs.reduce((acc, x) => acc + sqr(x - mean), 0) / (xs.length - 1);
  34. const range = xs =>
  35. xs.reduce(
  36. (acc, x) => ({
  37. start: Math.min(x, acc.start),
  38. end: Math.max(x, acc.end),
  39. }),
  40. { start: Number.POSITIVE_INFINITY, end: Number.NEGATIVE_INFINITY }
  41. );
  42. module.exports.getModuleName = module => module.userRequest;
  43. module.exports.getLoaderNames = loaders =>
  44. loaders && loaders.length
  45. ? loaders
  46. .map(l => l.loader || l)
  47. .map(l =>
  48. l.replace(
  49. /^.*\/node_modules\/(@[a-z0-9][\w-.]+\/[a-z0-9][\w-.]*|[^\/]+).*$/,
  50. (_, m) => m
  51. )
  52. )
  53. .filter(l => !l.includes("speed-measure-webpack-plugin"))
  54. : ["modules with no loaders"];
  55. module.exports.groupBy = (key, arr) => {
  56. const groups = [];
  57. (arr || []).forEach(arrItem => {
  58. const groupItem = groups.find(poss => isEqual(poss[0][key], arrItem[key]));
  59. if (groupItem) groupItem.push(arrItem);
  60. else groups.push([arrItem]);
  61. });
  62. return groups;
  63. };
  64. module.exports.getAverages = group => {
  65. const durationList = group.map(cur => cur.end - cur.start);
  66. const averages = {};
  67. averages.dataPoints = group.length;
  68. averages.median = median(durationList);
  69. averages.mean = Math.round(mean(durationList));
  70. averages.range = range(durationList);
  71. if (group.length > 1)
  72. averages.variance = Math.round(variance(durationList, averages.mean));
  73. return averages;
  74. };
  75. module.exports.getTotalActiveTime = group => {
  76. const mergedRanges = mergeRanges(group);
  77. return mergedRanges.reduce((acc, range) => acc + range.end - range.start, 0);
  78. };
  79. const prependLoader = rules => {
  80. if (!rules) return rules;
  81. if (Array.isArray(rules)) return rules.map(prependLoader);
  82. if (rules.loader) {
  83. rules.use = [rules.loader];
  84. delete rules.loader;
  85. }
  86. if (rules.use) {
  87. if (!Array.isArray(rules.use)) rules.use = [rules.use];
  88. rules.use.unshift("speed-measure-webpack-plugin/loader");
  89. }
  90. if (rules.oneOf) {
  91. rules.oneOf = prependLoader(rules.oneOf);
  92. }
  93. if (rules.rules) {
  94. rules.rules = prependLoader(rules.rules);
  95. }
  96. if (Array.isArray(rules.resource)) {
  97. rules.resource = prependLoader(rules.resource);
  98. }
  99. if (rules.resource && rules.resource.and) {
  100. rules.resource.and = prependLoader(rules.resource.and);
  101. }
  102. if (rules.resource && rules.resource.or) {
  103. rules.resource.or = prependLoader(rules.resource.or);
  104. }
  105. return rules;
  106. };
  107. module.exports.prependLoader = prependLoader;
  108. module.exports.hackWrapLoaders = (loaderPaths, callback) => {
  109. const wrapReq = reqMethod => {
  110. return function() {
  111. const ret = reqMethod.apply(this, arguments);
  112. if (loaderPaths.includes(arguments[0])) {
  113. if (ret.__smpHacked) return ret;
  114. ret.__smpHacked = true;
  115. return callback(ret, arguments[0]);
  116. }
  117. return ret;
  118. };
  119. };
  120. if (typeof System === "object" && typeof System.import === "function") {
  121. System.import = wrapReq(System.import);
  122. }
  123. const Module = require("module");
  124. Module.prototype.require = wrapReq(Module.prototype.require);
  125. };
  126. const toCamelCase = s => s.replace(/(\-\w)/g, m => m[1].toUpperCase());
  127. module.exports.tap = (obj, hookName, func) => {
  128. if (obj.hooks) {
  129. return obj.hooks[toCamelCase(hookName)].tap("smp", func);
  130. }
  131. return obj.plugin(hookName, func);
  132. };