@bundle-stats/utils 4.2.0-beta.1 → 4.2.0-beta.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (116) hide show
  1. package/lib/config/index.js +1 -9
  2. package/lib/config/index.js.map +1 -1
  3. package/lib/config/insights.js +7 -5
  4. package/lib/config/insights.js.map +1 -1
  5. package/lib/constants.js +27 -13
  6. package/lib/constants.js.map +1 -1
  7. package/lib/index.js +1 -0
  8. package/lib/index.js.map +1 -1
  9. package/lib/jobs/create-job.js +23 -12
  10. package/lib/jobs/create-job.js.map +1 -1
  11. package/lib/jobs/create-jobs.js +13 -17
  12. package/lib/jobs/create-jobs.js.map +1 -1
  13. package/lib/jobs/create-summary.js +10 -11
  14. package/lib/jobs/create-summary.js.map +1 -1
  15. package/lib/jobs/index.js.map +1 -1
  16. package/lib/lighthouse/filter.js.map +1 -1
  17. package/lib/report/create.js +11 -16
  18. package/lib/report/create.js.map +1 -1
  19. package/lib/utils/component-links.js +15 -3
  20. package/lib/utils/component-links.js.map +1 -1
  21. package/lib/utils/metrics.js.map +1 -1
  22. package/lib/webpack/constants.js +12 -11
  23. package/lib/webpack/constants.js.map +1 -1
  24. package/lib/webpack/extract/assets-size-total-insight.js +5 -5
  25. package/lib/webpack/extract/assets-size-total-insight.js.map +1 -1
  26. package/lib/webpack/extract/assets-size.js +3 -4
  27. package/lib/webpack/extract/assets-size.js.map +1 -1
  28. package/lib/webpack/extract/modules-packages-duplicate.js +117 -41
  29. package/lib/webpack/extract/modules-packages-duplicate.js.map +1 -1
  30. package/lib/webpack/extract/modules-packages.js.map +1 -1
  31. package/lib/webpack/extract/modules.js +0 -2
  32. package/lib/webpack/extract/modules.js.map +1 -1
  33. package/lib/webpack/metrics.js +27 -25
  34. package/lib/webpack/metrics.js.map +1 -1
  35. package/lib/webpack/types.js +24 -0
  36. package/lib/webpack/types.js.map +1 -1
  37. package/lib-esm/config/index.js +0 -8
  38. package/lib-esm/config/index.js.map +1 -1
  39. package/lib-esm/config/insights.js +6 -4
  40. package/lib-esm/config/insights.js.map +1 -1
  41. package/lib-esm/constants.js +26 -12
  42. package/lib-esm/constants.js.map +1 -1
  43. package/lib-esm/index.js +1 -0
  44. package/lib-esm/index.js.map +1 -1
  45. package/lib-esm/jobs/create-job.js +24 -12
  46. package/lib-esm/jobs/create-job.js.map +1 -1
  47. package/lib-esm/jobs/create-jobs.js +13 -14
  48. package/lib-esm/jobs/create-jobs.js.map +1 -1
  49. package/lib-esm/jobs/create-summary.js +10 -11
  50. package/lib-esm/jobs/create-summary.js.map +1 -1
  51. package/lib-esm/jobs/index.js.map +1 -1
  52. package/lib-esm/lighthouse/filter.js.map +1 -1
  53. package/lib-esm/report/create.js +11 -16
  54. package/lib-esm/report/create.js.map +1 -1
  55. package/lib-esm/utils/component-links.js +14 -2
  56. package/lib-esm/utils/component-links.js.map +1 -1
  57. package/lib-esm/utils/metrics.js.map +1 -1
  58. package/lib-esm/webpack/constants.js +12 -11
  59. package/lib-esm/webpack/constants.js.map +1 -1
  60. package/lib-esm/webpack/extract/assets-size-total-insight.js +6 -6
  61. package/lib-esm/webpack/extract/assets-size-total-insight.js.map +1 -1
  62. package/lib-esm/webpack/extract/assets-size.js +3 -4
  63. package/lib-esm/webpack/extract/assets-size.js.map +1 -1
  64. package/lib-esm/webpack/extract/modules-packages-duplicate.js +119 -41
  65. package/lib-esm/webpack/extract/modules-packages-duplicate.js.map +1 -1
  66. package/lib-esm/webpack/extract/modules-packages.js.map +1 -1
  67. package/lib-esm/webpack/extract/modules.js +0 -3
  68. package/lib-esm/webpack/extract/modules.js.map +1 -1
  69. package/lib-esm/webpack/metrics.js +27 -25
  70. package/lib-esm/webpack/metrics.js.map +1 -1
  71. package/lib-esm/webpack/types.js +23 -1
  72. package/lib-esm/webpack/types.js.map +1 -1
  73. package/package.json +13 -12
  74. package/src/config/index.js +0 -9
  75. package/src/config/insights.ts +5 -0
  76. package/src/constants.ts +82 -15
  77. package/src/index.js +1 -0
  78. package/src/jobs/create-job.ts +61 -0
  79. package/src/jobs/create-jobs.ts +28 -0
  80. package/src/jobs/create-summary.ts +22 -0
  81. package/src/jobs/{index.js → index.ts} +0 -0
  82. package/src/lighthouse/filter.js +8 -5
  83. package/src/report/create.ts +31 -24
  84. package/src/utils/component-links.ts +15 -2
  85. package/src/utils/metrics.js +8 -7
  86. package/src/webpack/constants.js +13 -11
  87. package/src/webpack/extract/assets-size-total-insight.js +6 -7
  88. package/src/webpack/extract/assets-size.js +29 -24
  89. package/src/webpack/extract/modules-packages-duplicate.ts +241 -0
  90. package/src/webpack/extract/modules-packages.ts +1 -1
  91. package/src/webpack/extract/modules.ts +1 -4
  92. package/src/webpack/metrics.js +27 -25
  93. package/src/webpack/types.ts +31 -7
  94. package/types/config/index.d.ts +0 -4
  95. package/types/config/insights.d.ts +5 -4
  96. package/types/constants.d.ts +68 -15
  97. package/types/index.d.ts +1 -0
  98. package/types/jobs/create-job.d.ts +2 -1
  99. package/types/jobs/create-jobs.d.ts +2 -1
  100. package/types/jobs/create-summary.d.ts +4 -1
  101. package/types/jobs/index.d.ts +2 -2
  102. package/types/lighthouse/filter.d.ts +1 -1
  103. package/types/report/add-row-metric-data.d.ts +10 -1
  104. package/types/report/create.d.ts +14 -12
  105. package/types/utils/component-links.d.ts +2 -1
  106. package/types/utils/metrics.d.ts +1 -1
  107. package/types/webpack/constants.d.ts +2 -1
  108. package/types/webpack/extract/assets-size-total-insight.d.ts +3 -2
  109. package/types/webpack/extract/modules-packages-duplicate.d.ts +9 -16
  110. package/types/webpack/extract/modules-packages.d.ts +1 -1
  111. package/types/webpack/types.d.ts +29 -8
  112. package/src/config/insights.js +0 -5
  113. package/src/jobs/create-job.js +0 -46
  114. package/src/jobs/create-jobs.js +0 -26
  115. package/src/jobs/create-summary.js +0 -16
  116. package/src/webpack/extract/modules-packages-duplicate.js +0 -102
@@ -14,17 +14,18 @@ import { metrics as browsertimeMeticTypes } from '../browsertime/metrics';
14
14
  * @param {Object} metrics
15
15
  * @return {Function}
16
16
  */
17
- export const createGetMetricType = (metrics) =>
17
+ export const createGetMetricType =
18
+ (metrics) =>
18
19
  /**
19
20
  * Get metric type data
20
21
  *
21
22
  * @param {String} key Metric key
22
23
  * @param {String} [type] Default metric type
23
- * @return {import('../../types').MetricType}
24
+ * @return {import('../constants').MetricType}
24
25
  */
25
26
  // eslint-disable-next-line implicit-arrow-linebreak
26
27
  (key, type) => {
27
- /** @type {import('../../types').MetricTypeConfig} */
28
+ /** @type {import('../constants').MetricTypeConfig} */
28
29
  const metric = get(metrics, key);
29
30
 
30
31
  if (metric && metric.type) {
@@ -47,8 +48,8 @@ export const createGetMetricType = (metrics) =>
47
48
  * Get global metric type
48
49
  *
49
50
  * @param {String} key Metric key
50
- * @param {import('../../types').MetricTypeType} [type] Default metric type
51
- * @return {import('../../types').MetricType}
51
+ * @param {import('../constants').MetricTypeType} [type] Default metric type
52
+ * @return {import('../constants').MetricType}
52
53
  */
53
54
  export const getGlobalMetricType = createGetMetricType({
54
55
  webpack: webpackMetricTypes,
@@ -60,11 +61,11 @@ export const getGlobalMetricType = createGetMetricType({
60
61
  *
61
62
  * Get metric information
62
63
  *
63
- * @param {import('../../types').MetricType} metric Metric data
64
+ * @param {import('../constants').MetricType} metric Metric data
64
65
  * @param {number} currentValue Current value
65
66
  * @param {number} baselineValue Baseline value
66
67
  *
67
- * @return {import('../../types').MetricRunInfo}
68
+ * @return {import('../constants').MetricRunInfo}
68
69
  */
69
70
  export const getMetricRunInfo = (metric, currentValue, baselineValue) => {
70
71
  const { formatter, biggerIsBetter } = metric;
@@ -1,3 +1,5 @@
1
+ import { Metric } from './types';
2
+
1
3
  export const SECTION_WEBPACK_STATS = 'stats';
2
4
  export const SECTION_WEBPACK_SIZES = 'sizes';
3
5
  export const SECTION_WEBPACK_ASSETS = 'assets';
@@ -13,17 +15,17 @@ export const SECTIONS = [
13
15
  ];
14
16
 
15
17
  export const SUMMARY_METRIC_PATHS = [
16
- 'totalSizeByTypeALL',
17
- 'totalInitialSizeJS',
18
- 'totalInitialSizeCSS',
19
- 'cacheInvalidation',
20
- 'moduleCount',
21
- 'duplicateModulesCount',
22
- 'duplicateCode',
23
- 'chunkCount',
24
- 'assetCount',
25
- 'packageCount',
26
- 'duplicatePackagesCount',
18
+ Metric.BUNDLE_SIZE,
19
+ Metric.INITIAL_SIZE_JS,
20
+ Metric.INITIAL_SIZE_CSS,
21
+ Metric.CACHE_INVALIDATION,
22
+ Metric.MODULE_COUNT,
23
+ Metric.DUPLICATE_MODULES_COUNT,
24
+ Metric.DUPLICATE_CODE,
25
+ Metric.CHUNK_COUNT,
26
+ Metric.ASSET_COUNT,
27
+ Metric.PACKAGE_COUNT,
28
+ Metric.DUPLICATE_PACKAGES_COUNT,
27
29
  ];
28
30
 
29
31
  const PACKAGE_PREFIX = /(?:node_modules|~)(?:\/\.pnpm)?/;
@@ -1,24 +1,23 @@
1
- import { INSIGHT_INFO } from '../../config/insights';
1
+ import { InsightType } from '../../config/insights';
2
2
  import { getMetricRunInfo } from '../../utils/metrics';
3
3
  import { getMetricType } from '../utils';
4
-
5
- const METRIC_NAME = 'totalSizeByTypeALL';
4
+ import { Metric } from '../types';
6
5
 
7
6
  const getText = ({ metric, displayValue, displayDeltaPercentage }) =>
8
7
  `${metric} — ${displayValue} (${displayDeltaPercentage}).`;
9
8
 
10
9
  export const extractAssetsSizeTotalInsight = (_, currentExtractedData, baselineBundleStats) => {
11
- const currentValue = currentExtractedData?.metrics?.[METRIC_NAME]?.value || 0;
12
- const baselineValue = baselineBundleStats?.metrics?.webpack?.[METRIC_NAME]?.value || 0;
10
+ const currentValue = currentExtractedData?.metrics?.[Metric.BUNDLE_SIZE]?.value || 0;
11
+ const baselineValue = baselineBundleStats?.metrics?.webpack?.[Metric.BUNDLE_SIZE]?.value || 0;
13
12
 
14
- const metric = getMetricType(METRIC_NAME);
13
+ const metric = getMetricType(Metric.BUNDLE_SIZE);
15
14
  const info = getMetricRunInfo(metric, currentValue, baselineValue);
16
15
  const { displayDeltaPercentage, displayValue } = info;
17
16
 
18
17
  return {
19
18
  insights: {
20
19
  assetsSizeTotal: {
21
- type: INSIGHT_INFO,
20
+ type: InsightType.INFO,
22
21
  data: {
23
22
  text: getText({ metric: metric.label, displayValue, displayDeltaPercentage }),
24
23
  md: getText({
@@ -4,34 +4,39 @@ import sum from 'lodash/sum';
4
4
 
5
5
  import { FILE_TYPE_CSS, FILE_TYPE_JS, FILE_TYPES } from '../../config/file-types';
6
6
  import { getFileType } from '../../utils/file-types';
7
+ import { METRIC_TOTALS_PREFIX, METRIC_TOTALS_SUFIX_ALL } from '../types';
7
8
 
8
- const METRIC_NAME_ALL = 'ALL';
9
- const METRIC_NAME_PREFIX = 'totalSizeByType';
9
+ const getMetricName = (fileType) => `${METRIC_TOTALS_PREFIX}${fileType}`;
10
10
 
11
- const getMetricName = (fileType) => `${METRIC_NAME_PREFIX}${fileType}`;
11
+ const generateInitialSizeByType = () =>
12
+ FILE_TYPES.reduce(
13
+ (accumulator, fileType) => ({
14
+ ...accumulator,
15
+ [getMetricName(fileType)]: {
16
+ value: 0,
17
+ },
18
+ }),
19
+ {},
20
+ );
12
21
 
13
- const generateInitialSizeByType = () => FILE_TYPES.reduce((accumulator, fileType) => ({
14
- ...accumulator,
15
- [getMetricName(fileType)]: {
16
- value: 0,
17
- },
18
- }), {});
22
+ const calculateTotalByType = (assets) =>
23
+ assets.reduce((accumulator, current) => {
24
+ const fileType = getFileType(current.name);
25
+ const statName = getMetricName(fileType);
26
+ const value = accumulator[statName].value + current.value;
19
27
 
20
- const calculateTotalByType = (assets) => assets.reduce((accumulator, current) => {
21
- const fileType = getFileType(current.name);
22
- const statName = getMetricName(fileType);
23
- const value = accumulator[statName].value + current.value;
28
+ return {
29
+ ...accumulator,
30
+ [statName]: {
31
+ value,
32
+ },
33
+ };
34
+ }, generateInitialSizeByType());
24
35
 
25
- return {
26
- ...accumulator,
27
- [statName]: {
28
- value,
29
- },
30
- };
31
- }, generateInitialSizeByType());
32
-
33
- const getFilterInitialAssetsByType = (fileType) => ({ name, isInitial }) =>
34
- getFileType(name) === fileType && isInitial; // eslint-disable-line implicit-arrow-linebreak
36
+ const getFilterInitialAssetsByType =
37
+ (fileType) =>
38
+ ({ name, isInitial }) =>
39
+ getFileType(name) === fileType && isInitial; // eslint-disable-line implicit-arrow-linebreak
35
40
 
36
41
  const calculateInitialTotals = (assets) => {
37
42
  const cssAssets = assets.filter(getFilterInitialAssetsByType(FILE_TYPE_CSS));
@@ -52,7 +57,7 @@ export const extractAssetsSize = (webpackStats, currentExtractedData) => {
52
57
 
53
58
  const sizes = calculateTotalByType(bundleAssets);
54
59
  const generic = {
55
- [getMetricName(METRIC_NAME_ALL)]: {
60
+ [getMetricName(METRIC_TOTALS_SUFIX_ALL)]: {
56
61
  value: sum(map(bundleAssets, 'value')),
57
62
  },
58
63
  ...calculateInitialTotals(bundleAssets),
@@ -0,0 +1,241 @@
1
+ import map from 'lodash/map';
2
+ import orderBy from 'lodash/orderBy';
3
+ import sum from 'lodash/sum';
4
+
5
+ import { InsightType } from '../../config';
6
+ import {
7
+ Job,
8
+ JobInsight,
9
+ JobInsightDuplicatePackagesData,
10
+ JobInsightDuplicatePackagesV3Data,
11
+ JobInsights,
12
+ MetricRun,
13
+ } from '../../constants';
14
+ import { Packages } from '../types';
15
+
16
+ interface DuplicatePackage {
17
+ id: string;
18
+ value: number;
19
+ }
20
+
21
+ interface DuplicatePackageGroup {
22
+ name: string;
23
+ value: number;
24
+ children: Array<DuplicatePackage>;
25
+ }
26
+
27
+ interface ModulesPackagesDuplicateData {
28
+ insights: {
29
+ duplicatePackages?: JobInsights['webpack']['duplicatePackages'];
30
+ duplicatePackagesV3: JobInsights['webpack']['duplicatePackagesV3'];
31
+ };
32
+ metrics: {
33
+ duplicatePackagesCount: MetricRun;
34
+ };
35
+ }
36
+
37
+ export const getDuplicatePackagesInsight = (
38
+ duplicatePackagesMap: Record<string, Array<string>>,
39
+ baselineDuplicatePackagesMap?: Record<string, Array<string>>,
40
+ ): JobInsight<JobInsightDuplicatePackagesV3Data> => {
41
+ const duplicateInstances: Array<string> = [];
42
+ const baselineDuplicateInstances: Array<string> = [];
43
+ const newDuplicateInstances: Array<string> = [];
44
+ const removedDuplicateInstances: Array<string> = [];
45
+
46
+ Object.entries(duplicatePackagesMap).forEach(([id, instances]) => {
47
+ instances.forEach((duplicateInstance) => {
48
+ if (duplicateInstance === id) {
49
+ return;
50
+ }
51
+
52
+ duplicateInstances.push(duplicateInstance);
53
+
54
+ if (baselineDuplicatePackagesMap?.[id]?.includes(duplicateInstance)) {
55
+ return;
56
+ }
57
+
58
+ newDuplicateInstances.push(duplicateInstance);
59
+ });
60
+ });
61
+
62
+ if (baselineDuplicatePackagesMap) {
63
+ Object.entries(baselineDuplicatePackagesMap).forEach(([id, instances]) => {
64
+ instances.forEach((duplicateInstance) => {
65
+ if (duplicateInstance === id) {
66
+ return;
67
+ }
68
+
69
+ baselineDuplicateInstances.push(duplicateInstance);
70
+
71
+ if (duplicatePackagesMap?.[id]?.includes(duplicateInstance)) {
72
+ return;
73
+ }
74
+
75
+ removedDuplicateInstances.push(duplicateInstance);
76
+ });
77
+ });
78
+ }
79
+
80
+ const duplicateInstancesCount = duplicateInstances.length;
81
+ const newDuplicateInstancesCount = newDuplicateInstances.length;
82
+ const removedDuplicateInstancesCount = removedDuplicateInstances.length;
83
+
84
+ let text: string;
85
+ let insightType: InsightType;
86
+
87
+ if (newDuplicateInstancesCount > 0 && removedDuplicateInstancesCount > 0) {
88
+ // New duplicate packages and removed duplicates
89
+ const item =
90
+ newDuplicateInstancesCount > 1 || removedDuplicateInstancesCount > 1 ? 'packages' : 'package';
91
+ text = `Bundle introduced ${newDuplicateInstancesCount} and removed ${removedDuplicateInstancesCount} duplicate ${item}`;
92
+ insightType = InsightType.ERROR;
93
+ } else if (newDuplicateInstancesCount > 0 && baselineDuplicatePackagesMap) {
94
+ // New duplicate packages and baseline comparison
95
+ const item = newDuplicateInstancesCount > 1 ? 'packages' : 'package';
96
+ text = `Bundle introduced ${newDuplicateInstancesCount} duplicate ${item}`;
97
+ insightType = InsightType.ERROR;
98
+ } else if (newDuplicateInstancesCount > 0) {
99
+ // New duplicate packages and no baseline
100
+ const item = newDuplicateInstancesCount > 1 ? 'packages' : 'package';
101
+ text = `Bundle contains ${newDuplicateInstancesCount} duplicate ${item}`;
102
+ insightType = InsightType.WARNING;
103
+ } else if (removedDuplicateInstancesCount > 0) {
104
+ // Removed duplicate packages
105
+ const item = removedDuplicateInstancesCount > 1 ? 'packages' : 'package';
106
+ text = `Bundle removed ${removedDuplicateInstancesCount} duplicate ${item}`;
107
+ insightType = InsightType.INFO;
108
+ } else if (
109
+ newDuplicateInstancesCount === 0 &&
110
+ removedDuplicateInstancesCount === 0 &&
111
+ duplicateInstancesCount > 0
112
+ ) {
113
+ // No change comparred with the baseline
114
+ const item = duplicateInstancesCount > 1 ? 'packages' : 'package';
115
+ text = `Bundle contains ${duplicateInstancesCount} duplicate ${item}`;
116
+ insightType = InsightType.WARNING;
117
+ } else {
118
+ // No change
119
+ text = 'Bundle does not contain duplicate packages';
120
+ insightType = InsightType.INFO;
121
+ }
122
+
123
+ return {
124
+ type: insightType,
125
+ data: {
126
+ text,
127
+ packages: duplicatePackagesMap,
128
+ },
129
+ };
130
+ };
131
+
132
+ export const extractModulesPackagesDuplicate = (
133
+ _: any,
134
+ currentExtractedData: any,
135
+ baselineJob?: Job,
136
+ ): ModulesPackagesDuplicateData => {
137
+ const source: Packages = currentExtractedData?.metrics?.packages || {};
138
+
139
+ // Group packages by name(uniq)
140
+ const packagesByName: Record<string, DuplicatePackageGroup> = {};
141
+
142
+ Object.entries(source).forEach(([packageId, packageData]) => {
143
+ const { name, value } = packageData;
144
+ const existingPackageData: DuplicatePackageGroup = packagesByName[name] || {
145
+ name,
146
+ value,
147
+ children: [],
148
+ };
149
+
150
+ existingPackageData.children.push({ id: packageId, value });
151
+
152
+ packagesByName[name] = existingPackageData;
153
+ });
154
+
155
+ // Filter, count and sum the duplicate packages
156
+ let count = 0;
157
+ const duplicatePackages: Array<DuplicatePackageGroup> = [];
158
+
159
+ Object.entries(packagesByName).forEach(([packageGroupName, packageGroupData]) => {
160
+ // Count duplicate instances (substract the initial instance)
161
+ // example: package-a, package-b:package-a -> duplicateInstances = 1
162
+ const duplicateInstances = packageGroupData.children.length - 1;
163
+
164
+ // No duplicates, skip
165
+ if (duplicateInstances === 0) {
166
+ return;
167
+ }
168
+
169
+ count += duplicateInstances;
170
+
171
+ duplicatePackages.push({
172
+ name: packageGroupName,
173
+ value: sum(map(packageGroupData.children, 'value')),
174
+ children: packageGroupData.children,
175
+ });
176
+ });
177
+
178
+ const baselineDuplicatePackages =
179
+ baselineJob?.insights?.webpack?.duplicatePackagesV3?.data?.packages ||
180
+ baselineJob?.insights?.webpack?.duplicatePackages?.data ||
181
+ {};
182
+
183
+ if (!count) {
184
+ return {
185
+ insights: {
186
+ duplicatePackagesV3: getDuplicatePackagesInsight({}, baselineDuplicatePackages),
187
+ },
188
+ metrics: {
189
+ duplicatePackagesCount: {
190
+ value: count,
191
+ },
192
+ },
193
+ };
194
+ }
195
+
196
+ // Group duplicate packages by name and order children by value
197
+ const duplicatePackagesByName: Record<string, DuplicatePackageGroup> = orderBy(
198
+ duplicatePackages,
199
+ 'value',
200
+ 'desc',
201
+ ).reduce(
202
+ (agg, { name, ...duplicatePackageData }: DuplicatePackageGroup) => ({
203
+ ...agg,
204
+ [name]: {
205
+ ...duplicatePackageData,
206
+ children: orderBy(duplicatePackageData.children, 'value', 'desc'),
207
+ },
208
+ }),
209
+ {},
210
+ );
211
+
212
+ // Generate v2 data structure
213
+ // @TODO remove in v5.0
214
+ const duplicatePackagesData: JobInsightDuplicatePackagesData = {};
215
+
216
+ Object.entries(duplicatePackagesByName).forEach(([packageName, packageData]) => {
217
+ if (!duplicatePackagesData[packageName]) {
218
+ duplicatePackagesData[packageName] = [];
219
+ }
220
+
221
+ duplicatePackagesData[packageName] = packageData.children.map(({ id }) => id);
222
+ });
223
+
224
+ return {
225
+ insights: {
226
+ duplicatePackages: {
227
+ type: InsightType.WARNING,
228
+ data: duplicatePackagesData,
229
+ },
230
+ duplicatePackagesV3: getDuplicatePackagesInsight(
231
+ duplicatePackagesData,
232
+ baselineDuplicatePackages,
233
+ ),
234
+ },
235
+ metrics: {
236
+ duplicatePackagesCount: {
237
+ value: count,
238
+ },
239
+ },
240
+ };
241
+ };
@@ -51,7 +51,7 @@ export const getPackageMetaFromModulePath = (modulePath: string) => {
51
51
  return null;
52
52
  }
53
53
 
54
- const name = last(names);
54
+ const name = last(names) as string;
55
55
 
56
56
  // Get package full path
57
57
  // @NOTE use the last path to prevent getting incorrect results on packages with similar names
@@ -51,7 +51,7 @@ export const extractModules = (webpackStats?: WebpackStatsFiltered): MetricsModu
51
51
  const { name, size = 0, chunks } = moduleEntry;
52
52
  const normalizedName = getModuleName(name);
53
53
 
54
- // skip modules that are orphane(do not belong to any chunk)
54
+ // skip modules that do not belong to any chunk
55
55
  if (!chunks || chunks?.length === 0) {
56
56
  return agg;
57
57
  }
@@ -64,15 +64,12 @@ export const extractModules = (webpackStats?: WebpackStatsFiltered): MetricsModu
64
64
  duplicateCodeSize += duplicateInstances * size;
65
65
  totalCodeSize += instances * size;
66
66
 
67
- const reasons = moduleEntry.reasons?.map((reason) => getModuleName(reason.module));
68
-
69
67
  // eslint-disable-next-line no-param-reassign
70
68
  agg[normalizedName] = {
71
69
  name,
72
70
  value: size,
73
71
  chunkIds: chunks.map(normalizeChunkId),
74
72
  duplicated: Boolean(duplicateInstances),
75
- ...(reasons && { reasons }),
76
73
  };
77
74
 
78
75
  return agg;
@@ -3,76 +3,78 @@ import {
3
3
  METRIC_TYPE_NUMERIC,
4
4
  METRIC_TYPE_PERCENTAGE,
5
5
  } from '../config/metrics';
6
+ import { FILE_TYPE_LABELS } from '../config/file-types';
7
+ import { Metric } from './types';
6
8
 
7
9
  export const metrics = {
8
- totalSizeByTypeALL: {
10
+ [Metric.BUNDLE_SIZE]: {
9
11
  label: 'Bundle Size',
10
12
  description: 'The total size of the assets produced by webpack',
11
13
  url: 'https://relative-ci.com/documentation/metrics-and-data#assets',
12
14
  type: METRIC_TYPE_FILE_SIZE,
13
15
  },
14
- totalInitialSizeJS: {
16
+ [Metric.INITIAL_SIZE_JS]: {
15
17
  label: 'Initial JS',
16
18
  description: 'The total size of JavaScript initial chunks',
17
19
  url: 'https://relative-ci.com/documentation/metrics-and-data#assets',
18
20
  type: METRIC_TYPE_FILE_SIZE,
19
21
  },
20
- totalInitialSizeCSS: {
22
+ [Metric.INITIAL_SIZE_CSS]: {
21
23
  label: 'Initial CSS',
22
24
  description: 'The total size of CSS initial chunks',
23
25
  url: 'https://relative-ci.com/documentation/metrics-and-data#assets',
24
26
  type: METRIC_TYPE_FILE_SIZE,
25
27
  },
26
- cacheInvalidation: {
28
+ [Metric.CACHE_INVALIDATION]: {
27
29
  label: 'Cache Invalidation',
28
30
  description: 'The ratio between the total changed assets and total assets size(Bundle Size)',
29
31
  url: 'https://relative-ci.com/documentation/metrics-and-data#assets',
30
32
  type: METRIC_TYPE_PERCENTAGE,
31
33
  biggerIsBetter: false,
32
34
  },
33
- chunkCount: {
35
+ [Metric.CHUNK_COUNT]: {
34
36
  label: 'Chunks',
35
37
  description: 'The total number of chunks',
36
38
  url: 'https://relative-ci.com/documentation/metrics-and-data#assets',
37
39
  type: METRIC_TYPE_NUMERIC,
38
40
  biggerIsBetter: false,
39
41
  },
40
- assetCount: {
42
+ [Metric.ASSET_COUNT]: {
41
43
  label: 'Assets',
42
44
  description: 'Total number of assets',
43
45
  url: 'https://relative-ci.com/documentation/metrics-and-data#assets',
44
46
  type: METRIC_TYPE_NUMERIC,
45
47
  biggerIsBetter: false,
46
48
  },
47
- moduleCount: {
49
+ [Metric.MODULE_COUNT]: {
48
50
  label: 'Modules',
49
51
  description: 'The total number of modules bundled by webpack',
50
52
  url: 'https://relative-ci.com/documentation/metrics-and-data#modules-1',
51
53
  type: METRIC_TYPE_NUMERIC,
52
54
  biggerIsBetter: false,
53
55
  },
54
- duplicateModulesCount: {
56
+ [Metric.DUPLICATE_MODULES_COUNT]: {
55
57
  label: 'Duplicate Modules',
56
58
  description: 'The total number of modules that belong to more than one chunk',
57
59
  url: 'https://relative-ci.com/documentation/metrics-and-data#modules-1',
58
60
  type: METRIC_TYPE_NUMERIC,
59
61
  biggerIsBetter: false,
60
62
  },
61
- duplicateCode: {
63
+ [Metric.DUPLICATE_CODE]: {
62
64
  label: 'Duplicate Code',
63
65
  description: 'The percentage of total duplicate module size from the total module size',
64
66
  url: 'https://relative-ci.com/documentation/metrics-and-data#modules-1',
65
67
  type: METRIC_TYPE_PERCENTAGE,
66
68
  biggerIsBetter: false,
67
69
  },
68
- packageCount: {
70
+ [Metric.PACKAGE_COUNT]: {
69
71
  label: 'Packages',
70
72
  description: 'The total number of packages bundled by webpack',
71
73
  url: 'https://relative-ci.com/documentation/metrics-and-data#packages',
72
74
  type: METRIC_TYPE_NUMERIC,
73
75
  biggerIsBetter: false,
74
76
  },
75
- duplicatePackagesCount: {
77
+ [Metric.DUPLICATE_PACKAGES_COUNT]: {
76
78
  label: 'Duplicate Packages',
77
79
  description: 'The total number of duplicate packages',
78
80
  url: 'https://relative-ci.com/documentation/metrics-and-data#packages',
@@ -80,32 +82,32 @@ export const metrics = {
80
82
  biggerIsBetter: false,
81
83
  },
82
84
  sizes: {
83
- totalSizeByTypeJS: {
84
- label: 'JS',
85
+ [Metric.TOTAL_SIZE_JS]: {
86
+ label: FILE_TYPE_LABELS.JS,
85
87
  type: METRIC_TYPE_FILE_SIZE,
86
88
  },
87
- totalSizeByTypeCSS: {
88
- label: 'CSS',
89
+ [Metric.TOTAL_SIZE_CSS]: {
90
+ label: FILE_TYPE_LABELS.CSS,
89
91
  type: METRIC_TYPE_FILE_SIZE,
90
92
  },
91
- totalSizeByTypeIMG: {
92
- label: 'IMG',
93
+ [Metric.TOTAL_SIZE_IMG]: {
94
+ label: FILE_TYPE_LABELS.IMG,
93
95
  type: METRIC_TYPE_FILE_SIZE,
94
96
  },
95
- totalSizeByTypeMEDIA: {
96
- label: 'Media',
97
+ [Metric.TOTAL_SIZE_MEDIA]: {
98
+ label: FILE_TYPE_LABELS.MEDIA,
97
99
  type: METRIC_TYPE_FILE_SIZE,
98
100
  },
99
- totalSizeByTypeFONT: {
100
- label: 'Fonts',
101
+ [Metric.TOTAL_SIZE_FONT]: {
102
+ label: FILE_TYPE_LABELS.FONT,
101
103
  type: METRIC_TYPE_FILE_SIZE,
102
104
  },
103
- totalSizeByTypeHTML: {
104
- label: 'HTML',
105
+ [Metric.TOTAL_SIZE_HTML]: {
106
+ label: FILE_TYPE_LABELS.HTML,
105
107
  type: METRIC_TYPE_FILE_SIZE,
106
108
  },
107
- totalSizeByTypeOTHER: {
108
- label: 'Other',
109
+ [Metric.TOTAL_SIZE_OTHER]: {
110
+ label: FILE_TYPE_LABELS.OTHER,
109
111
  type: METRIC_TYPE_FILE_SIZE,
110
112
  },
111
113
  },
@@ -1,11 +1,35 @@
1
- import { Metric, MetricRun } from '../constants';
1
+ import { MetricRun } from '../constants';
2
2
 
3
- interface MetaChunk {
3
+ export const METRIC_TOTALS_SUFIX_ALL = 'ALL';
4
+ export const METRIC_TOTALS_PREFIX = 'totalSizeByType';
5
+
6
+ export enum Metric {
7
+ BUNDLE_SIZE = 'totalSizeByTypeALL',
8
+ INITIAL_SIZE_JS = 'totalInitialSizeJS',
9
+ INITIAL_SIZE_CSS = 'totalInitialSizeCSS',
10
+ CACHE_INVALIDATION = 'cacheInvalidation',
11
+ ASSET_COUNT = 'assetCount',
12
+ CHUNK_COUNT = 'chunkCount',
13
+ MODULE_COUNT = 'moduleCount',
14
+ DUPLICATE_MODULES_COUNT = 'duplicateModulesCount',
15
+ DUPLICATE_CODE = 'duplicateCode',
16
+ PACKAGE_COUNT = 'packageCount',
17
+ DUPLICATE_PACKAGES_COUNT = 'duplicatePackagesCount',
18
+ TOTAL_SIZE_JS = 'totalSizeByTypeJS',
19
+ TOTAL_SIZE_CSS = 'totalSizeByTypeCSS',
20
+ TOTAL_SIZE_IMG = 'totalSizeByTypeIMG',
21
+ TOTAL_SIZE_MEDIA = 'totalSizeByTypeMEDIA',
22
+ TOTAL_SIZE_FONT = 'totalSizeByTypeFONT',
23
+ TOTAL_SIZE_HTML = 'totalSizeByTypeHTML',
24
+ TOTAL_SIZE_OTHER = 'totalSizeByTypeOTHER',
25
+ }
26
+
27
+ export interface MetaChunk {
4
28
  id: string;
5
29
  name: string;
6
30
  }
7
31
 
8
- export interface Asset extends Metric {
32
+ export interface Asset extends MetricRun {
9
33
  name: string;
10
34
  isEntry: boolean;
11
35
  isInitial: boolean;
@@ -24,11 +48,10 @@ export interface MetricsAssets {
24
48
  };
25
49
  }
26
50
 
27
- export interface Module extends Metric {
51
+ export interface Module extends MetricRun {
28
52
  name: string;
29
- chunkIds: Array<string>;
53
+ chunkIds: Array<String>;
30
54
  duplicated: boolean;
31
- reasons?: Array<string>;
32
55
  }
33
56
 
34
57
  export type Modules = Record<string, Module>;
@@ -42,7 +65,8 @@ export interface MetricsModules {
42
65
  };
43
66
  }
44
67
 
45
- export interface Package extends Metric {
68
+ export interface Package extends MetricRun {
69
+ name: string;
46
70
  path: string;
47
71
  }
48
72
 
@@ -5,7 +5,3 @@ export * from "./metrics";
5
5
  export * from "./delta";
6
6
  export const PACKAGES_SEPARATOR: ":";
7
7
  export const PACKAGE_ID_SEPARATOR: "~";
8
- export const SOURCE_PATH_WEBPACK_STATS: "webpack";
9
- export const SOURCE_PATH_LIGHTHOUSE: "lighthouse";
10
- export const SOURCE_PATH_BROWSERTIME: "browsertime";
11
- export const SOURCE_PATHS: string[];
@@ -1,4 +1,5 @@
1
- export const INSIGHT_ERROR: "ERROR";
2
- export const INSIGHT_INFO: "INFO";
3
- export const INSIGHT_WARNING: "WARNING";
4
- export const INSIGHTS: string[];
1
+ export declare enum InsightType {
2
+ ERROR = "ERROR",
3
+ INFO = "INFO",
4
+ WARNING = "WARNING"
5
+ }