@bundle-stats/utils 4.2.2 → 4.2.3-beta.1
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.
- package/README.md +15 -10
- package/lib/browsertime/metrics.js +22 -22
- package/lib/browsertime/metrics.js.map +1 -1
- package/lib/config/component-links.js +7 -1
- package/lib/config/component-links.js.map +1 -1
- package/lib/config/file-types.js +3 -3
- package/lib/config/file-types.js.map +1 -1
- package/lib/config/index.js +1 -2
- package/lib/config/index.js.map +1 -1
- package/lib/config/metric-types.js +28 -0
- package/lib/config/metric-types.js.map +1 -0
- package/lib/constants.js +23 -22
- package/lib/constants.js.map +1 -1
- package/lib/i18n.js +15 -10
- package/lib/i18n.js.map +1 -1
- package/lib/jobs/create-job.js +17 -7
- package/lib/jobs/create-job.js.map +1 -1
- package/lib/jobs/create-jobs.js.map +1 -1
- package/lib/lighthouse/metrics.js +13 -13
- package/lib/lighthouse/metrics.js.map +1 -1
- package/lib/report/add-row-metric-data.js +4 -4
- package/lib/report/add-row-metric-data.js.map +1 -1
- package/lib/report/compare-metrics.js +4 -1
- package/lib/report/compare-metrics.js.map +1 -1
- package/lib/report/create.js +17 -7
- package/lib/report/create.js.map +1 -1
- package/lib/report/get-metric-changed.js.map +1 -1
- package/lib/report/index.js +1 -0
- package/lib/report/index.js.map +1 -1
- package/lib/report/merge-metrics-by-key.js +1 -1
- package/lib/report/merge-metrics-by-key.js.map +1 -1
- package/lib/utils/component-links.js +191 -27
- package/lib/utils/component-links.js.map +1 -1
- package/lib/utils/date.js.map +1 -1
- package/lib/utils/delta.js +35 -30
- package/lib/utils/delta.js.map +1 -1
- package/lib/utils/format.js +5 -6
- package/lib/utils/format.js.map +1 -1
- package/lib/utils/insights.js.map +1 -1
- package/lib/utils/metrics.js +49 -32
- package/lib/utils/metrics.js.map +1 -1
- package/lib/webpack/compare.js +16 -12
- package/lib/webpack/compare.js.map +1 -1
- package/lib/webpack/extract/assets.js +7 -1
- package/lib/webpack/extract/assets.js.map +1 -1
- package/lib/webpack/extract/meta.js.map +1 -1
- package/lib/webpack/extract/modules-packages-duplicate.js +13 -8
- package/lib/webpack/extract/modules-packages-duplicate.js.map +1 -1
- package/lib/webpack/extract/modules-packages-new-insight.js.map +1 -1
- package/lib/webpack/extract/modules-packages.js +8 -1
- package/lib/webpack/extract/modules-packages.js.map +1 -1
- package/lib/webpack/extract/modules.js +45 -20
- package/lib/webpack/extract/modules.js.map +1 -1
- package/lib/webpack/metrics.js +35 -34
- package/lib/webpack/metrics.js.map +1 -1
- package/lib/webpack/selectors.js +40 -3
- package/lib/webpack/selectors.js.map +1 -1
- package/lib/webpack/types.js +1 -1
- package/lib/webpack/types.js.map +1 -1
- package/lib/webpack/utils.js +37 -25
- package/lib/webpack/utils.js.map +1 -1
- package/lib-esm/browsertime/metrics.js +22 -22
- package/lib-esm/browsertime/metrics.js.map +1 -1
- package/lib-esm/config/component-links.js +6 -0
- package/lib-esm/config/component-links.js.map +1 -1
- package/lib-esm/config/file-types.js +3 -3
- package/lib-esm/config/file-types.js.map +1 -1
- package/lib-esm/config/index.js +1 -2
- package/lib-esm/config/index.js.map +1 -1
- package/lib-esm/config/metric-types.js +25 -0
- package/lib-esm/config/metric-types.js.map +1 -0
- package/lib-esm/constants.js +19 -18
- package/lib-esm/constants.js.map +1 -1
- package/lib-esm/i18n.js +15 -10
- package/lib-esm/i18n.js.map +1 -1
- package/lib-esm/jobs/create-job.js.map +1 -1
- package/lib-esm/jobs/create-jobs.js.map +1 -1
- package/lib-esm/lighthouse/metrics.js +13 -13
- package/lib-esm/lighthouse/metrics.js.map +1 -1
- package/lib-esm/report/add-row-metric-data.js +4 -4
- package/lib-esm/report/add-row-metric-data.js.map +1 -1
- package/lib-esm/report/compare-metrics.js +4 -1
- package/lib-esm/report/compare-metrics.js.map +1 -1
- package/lib-esm/report/create.js.map +1 -1
- package/lib-esm/report/get-metric-changed.js.map +1 -1
- package/lib-esm/report/index.js +1 -0
- package/lib-esm/report/index.js.map +1 -1
- package/lib-esm/report/merge-metrics-by-key.js +1 -1
- package/lib-esm/report/merge-metrics-by-key.js.map +1 -1
- package/lib-esm/utils/component-links.js +185 -27
- package/lib-esm/utils/component-links.js.map +1 -1
- package/lib-esm/utils/date.js.map +1 -1
- package/lib-esm/utils/delta.js +32 -26
- package/lib-esm/utils/delta.js.map +1 -1
- package/lib-esm/utils/format.js.map +1 -1
- package/lib-esm/utils/insights.js.map +1 -1
- package/lib-esm/utils/metrics.js +44 -27
- package/lib-esm/utils/metrics.js.map +1 -1
- package/lib-esm/webpack/compare.js +7 -5
- package/lib-esm/webpack/compare.js.map +1 -1
- package/lib-esm/webpack/extract/assets.js +7 -1
- package/lib-esm/webpack/extract/assets.js.map +1 -1
- package/lib-esm/webpack/extract/meta.js.map +1 -1
- package/lib-esm/webpack/extract/modules-packages-duplicate.js +13 -8
- package/lib-esm/webpack/extract/modules-packages-duplicate.js.map +1 -1
- package/lib-esm/webpack/extract/modules-packages-new-insight.js.map +1 -1
- package/lib-esm/webpack/extract/modules-packages.js +8 -1
- package/lib-esm/webpack/extract/modules-packages.js.map +1 -1
- package/lib-esm/webpack/extract/modules.js +45 -20
- package/lib-esm/webpack/extract/modules.js.map +1 -1
- package/lib-esm/webpack/metrics.js +35 -34
- package/lib-esm/webpack/metrics.js.map +1 -1
- package/lib-esm/webpack/selectors.js +35 -1
- package/lib-esm/webpack/selectors.js.map +1 -1
- package/lib-esm/webpack/utils.js +37 -25
- package/lib-esm/webpack/utils.js.map +1 -1
- package/package.json +20 -22
- package/src/browsertime/metrics.js +22 -22
- package/src/config/component-links.js +7 -0
- package/src/config/file-types.js +3 -3
- package/src/config/index.js +1 -2
- package/src/config/metric-types.ts +25 -0
- package/src/constants.ts +94 -34
- package/src/i18n.js +15 -10
- package/src/lighthouse/metrics.js +13 -15
- package/src/report/add-row-metric-data.ts +42 -38
- package/src/report/compare-metrics.ts +7 -4
- package/src/report/create.ts +1 -1
- package/src/report/index.js +1 -0
- package/src/report/merge-metrics-by-key.ts +7 -5
- package/src/report/types.ts +17 -0
- package/src/utils/component-links.ts +276 -35
- package/src/utils/delta.ts +98 -0
- package/src/utils/metrics.ts +88 -0
- package/src/webpack/compare.ts +62 -0
- package/src/webpack/extract/assets.ts +13 -7
- package/src/webpack/extract/modules-packages-duplicate.ts +23 -15
- package/src/webpack/extract/modules-packages.ts +74 -61
- package/src/webpack/extract/modules.ts +66 -33
- package/src/webpack/{metrics.js → metrics.ts} +41 -39
- package/src/webpack/selectors.js +82 -9
- package/src/webpack/types.ts +13 -4
- package/src/webpack/utils.ts +173 -0
- package/types/browsertime/compare.d.ts +1 -1
- package/types/browsertime/metrics.d.ts +63 -43
- package/types/config/component-links.d.ts +26 -18
- package/types/config/file-types.d.ts +17 -17
- package/types/config/index.d.ts +1 -2
- package/types/config/metric-types.d.ts +2 -0
- package/types/constants.d.ts +52 -29
- package/types/i18n.d.ts +19 -14
- package/types/lighthouse/compare.d.ts +1 -1
- package/types/lighthouse/filter.d.ts +1 -1
- package/types/lighthouse/metrics.d.ts +36 -28
- package/types/report/add-row-metric-data.d.ts +1 -16
- package/types/report/compare-metrics.d.ts +1 -1
- package/types/report/index.d.ts +1 -0
- package/types/report/merge-metrics-by-key.d.ts +1 -1
- package/types/report/types.d.ts +12 -0
- package/types/utils/component-links.d.ts +24 -8
- package/types/utils/delta.d.ts +4 -6
- package/types/utils/metrics.d.ts +4 -3
- package/types/webpack/compare.d.ts +11 -14
- package/types/webpack/constants.d.ts +1 -1
- package/types/webpack/extract/assets-size-total-insight.d.ts +2 -2
- package/types/webpack/extract/modules-packages-duplicate.d.ts +3 -3
- package/types/webpack/extract/modules.d.ts +1 -1
- package/types/webpack/metrics.d.ts +7 -153
- package/types/webpack/selectors.d.ts +21 -7
- package/types/webpack/types.d.ts +4 -4
- package/types/webpack/utils.d.ts +8 -8
- package/CHANGELOG.md +0 -333
- package/lib/config/delta.js +0 -13
- package/lib/config/delta.js.map +0 -1
- package/lib/config/metrics.js +0 -32
- package/lib/config/metrics.js.map +0 -1
- package/lib-esm/config/delta.js +0 -10
- package/lib-esm/config/delta.js.map +0 -1
- package/lib-esm/config/metrics.js +0 -29
- package/lib-esm/config/metrics.js.map +0 -1
- package/src/config/delta.js +0 -11
- package/src/config/metrics.js +0 -35
- package/src/utils/delta.js +0 -94
- package/src/utils/metrics.js +0 -92
- package/src/webpack/compare.js +0 -81
- package/src/webpack/utils.js +0 -155
- package/types/config/delta.d.ts +0 -9
- package/types/config/metrics.d.ts +0 -35
package/src/i18n.js
CHANGED
|
@@ -1,17 +1,22 @@
|
|
|
1
1
|
export default {
|
|
2
2
|
COMPONENT_LINK_TOTALS: 'View total size by type',
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
3
|
+
COMPONENT_LINK_BUNDLE_ASSET_DETAILS: 'View asset details',
|
|
4
|
+
COMPONENT_LINK_BUNDLE_ASSETS_INITIAL_JS: 'View initial JS assets',
|
|
5
|
+
COMPONENT_LINK_BUNDLE_ASSETS_INITIAL_CSS: 'View initial CSS assets',
|
|
6
|
+
COMPONENT_LINK_BUNDLE_ASSETS_CACHE_INVALIDATION: 'View changed assets',
|
|
7
|
+
COMPONENT_LINK_BUNDLE_ASSETS_COUNT: 'View assets',
|
|
8
|
+
COMPONENT_LINK_BUNDLE_ASSETS_CHUNK_COUNT: 'View chunks',
|
|
9
|
+
COMPONENT_LINK_BUNDLE_ASSETS_CHUNKS: 'View chunk assets',
|
|
8
10
|
COMPONENT_LINK_MODULES: 'View modules',
|
|
9
11
|
COMPONENT_LINK_MODULES_DUPLICATE: 'View duplicate modules',
|
|
12
|
+
COMPONENT_LINK_MODULES_BY_FILE_TYPE: (fileType) => `View ${fileType} modules`,
|
|
13
|
+
COMPONENT_LINK_MODULES_BY_SOURCE: (source) => `View ${source} modules`,
|
|
10
14
|
COMPONENT_LINK_CHUNK_MODULES: 'View chunk modules',
|
|
11
|
-
COMPONENT_LINK_PACKAGES_COUNT: 'View
|
|
12
|
-
COMPONENT_LINK_PACKAGES_CHANGED: 'View
|
|
13
|
-
COMPONENT_LINK_PACKAGES_DUPLICATE: 'View
|
|
14
|
-
COMPONENT_LINK_PACKAGES_DUPLICATE_CHANGED: 'View
|
|
15
|
+
COMPONENT_LINK_PACKAGES_COUNT: 'View packages',
|
|
16
|
+
COMPONENT_LINK_PACKAGES_CHANGED: 'View changed packages',
|
|
17
|
+
COMPONENT_LINK_PACKAGES_DUPLICATE: 'View duplicate packages',
|
|
18
|
+
COMPONENT_LINK_PACKAGES_DUPLICATE_CHANGED: 'View changed duplicate packages',
|
|
15
19
|
COMPONENT_LINK_VIEW_PACKAGE: 'View package',
|
|
16
|
-
COMPONENT_LINK_BUNDLE_ASSETS_BY_FILE_TYPE: ({ label }) => `View
|
|
20
|
+
COMPONENT_LINK_BUNDLE_ASSETS_BY_FILE_TYPE: ({ label }) => `View ${label} assets`,
|
|
21
|
+
COMPONENT_LINK_BUNDLE_ASSETS_BY_ENTRY_TYPE: (assetType) => `View ${assetType} assets`,
|
|
17
22
|
};
|
|
@@ -1,55 +1,53 @@
|
|
|
1
|
-
import {
|
|
2
|
-
METRIC_TYPE_SCORE, METRIC_TYPE_DURATION, METRIC_TYPE_FILE_SIZE, METRIC_TYPE_NUMERIC,
|
|
3
|
-
} from '../config/metrics';
|
|
1
|
+
import { MetricTypes } from '../constants';
|
|
4
2
|
|
|
5
3
|
export const metrics = {
|
|
6
4
|
score: {
|
|
7
5
|
label: 'Score',
|
|
8
|
-
type:
|
|
6
|
+
type: MetricTypes.Score,
|
|
9
7
|
},
|
|
10
8
|
performanceScore: {
|
|
11
9
|
label: 'Performance',
|
|
12
|
-
type:
|
|
10
|
+
type: MetricTypes.Score,
|
|
13
11
|
},
|
|
14
12
|
accessibilityScore: {
|
|
15
13
|
label: 'Accessibility',
|
|
16
|
-
type:
|
|
14
|
+
type: MetricTypes.Score,
|
|
17
15
|
},
|
|
18
16
|
bestPracticesScore: {
|
|
19
17
|
label: 'Best Practices',
|
|
20
|
-
type:
|
|
18
|
+
type: MetricTypes.Score,
|
|
21
19
|
},
|
|
22
20
|
seoScore: {
|
|
23
21
|
label: 'SEO',
|
|
24
|
-
type:
|
|
22
|
+
type: MetricTypes.Score,
|
|
25
23
|
},
|
|
26
24
|
pwaScore: {
|
|
27
25
|
label: 'PWA',
|
|
28
|
-
type:
|
|
26
|
+
type: MetricTypes.Score,
|
|
29
27
|
},
|
|
30
28
|
|
|
31
29
|
speedIndex: {
|
|
32
30
|
label: 'Perceptual Speed Index',
|
|
33
|
-
type:
|
|
31
|
+
type: MetricTypes.Duration,
|
|
34
32
|
},
|
|
35
33
|
firstMeaningfulPaint: {
|
|
36
34
|
label: 'First Meaningful Paint',
|
|
37
|
-
type:
|
|
35
|
+
type: MetricTypes.Duration,
|
|
38
36
|
},
|
|
39
37
|
timeToFirstByte: {
|
|
40
38
|
label: 'Time To First Byte',
|
|
41
|
-
type:
|
|
39
|
+
type: MetricTypes.Duration,
|
|
42
40
|
},
|
|
43
41
|
firstInteractive: {
|
|
44
42
|
label: 'First Interactive',
|
|
45
|
-
type:
|
|
43
|
+
type: MetricTypes.Duration,
|
|
46
44
|
},
|
|
47
45
|
totalByteWeight: {
|
|
48
46
|
label: 'Total Weight',
|
|
49
|
-
type:
|
|
47
|
+
type: MetricTypes.FileSize,
|
|
50
48
|
},
|
|
51
49
|
domSize: {
|
|
52
50
|
label: 'DOM Size',
|
|
53
|
-
type:
|
|
51
|
+
type: MetricTypes.Numeric,
|
|
54
52
|
},
|
|
55
53
|
};
|
|
@@ -1,53 +1,57 @@
|
|
|
1
1
|
import get from 'lodash/get';
|
|
2
2
|
|
|
3
3
|
import { getGlobalMetricType, getMetricRunInfo } from '../utils/metrics';
|
|
4
|
+
import { MetricTypes } from '../constants';
|
|
4
5
|
import { getMetricChanged } from './get-metric-changed';
|
|
5
6
|
import * as types from './types';
|
|
6
7
|
|
|
8
|
+
/* eslint-disable prettier/prettier */
|
|
7
9
|
/**
|
|
8
|
-
* Add
|
|
10
|
+
* Add metric item data
|
|
9
11
|
*/
|
|
10
|
-
export const getAddRowMetricData =
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
const { biggerIsBetter, label } = metric;
|
|
21
|
-
|
|
22
|
-
const processedRuns = runs.map((run, index) => {
|
|
23
|
-
if (!run || typeof run.value === 'undefined' || run.value === null) {
|
|
24
|
-
return null;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
const metricRunInfo = getMetricRunInfo(
|
|
28
|
-
metric,
|
|
29
|
-
run.value,
|
|
30
|
-
// Get baseline value only if not the latest run
|
|
31
|
-
(index + 1 < runs.length) ? get(runs, [index + 1, 'value'], 0) : undefined,
|
|
12
|
+
export const getAddRowMetricData =
|
|
13
|
+
(metricType?: string) => (row: types.ReportRow): types.ReportMetricRow => {
|
|
14
|
+
const { key, runs } = row;
|
|
15
|
+
|
|
16
|
+
// Resolve row metric
|
|
17
|
+
// - if the key is a predefined metric, use it
|
|
18
|
+
// - if the key is not matching an existing metric, use the default metricType
|
|
19
|
+
const metric = getGlobalMetricType(
|
|
20
|
+
key,
|
|
21
|
+
typeof metricType === 'string' ? (metricType as MetricTypes) : undefined, // explicit, avoid passing of map cb params
|
|
32
22
|
);
|
|
23
|
+
const { biggerIsBetter, label } = metric;
|
|
24
|
+
|
|
25
|
+
const processedRuns = runs.map((run, index) => {
|
|
26
|
+
if (!run || typeof run.value === 'undefined' || run.value === null) {
|
|
27
|
+
return null;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const metricRunInfo = getMetricRunInfo(
|
|
31
|
+
metric,
|
|
32
|
+
run.value,
|
|
33
|
+
// Get baseline value only if not the latest run
|
|
34
|
+
index + 1 < runs.length ? get(runs, [index + 1, 'value'], 0) : undefined,
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
return {
|
|
38
|
+
...run,
|
|
39
|
+
...metricRunInfo,
|
|
40
|
+
};
|
|
41
|
+
});
|
|
33
42
|
|
|
34
43
|
return {
|
|
35
|
-
|
|
36
|
-
...metricRunInfo,
|
|
37
|
-
};
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
return {
|
|
41
|
-
...row,
|
|
44
|
+
key: row.key,
|
|
42
45
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
+
// Metric props
|
|
47
|
+
label,
|
|
48
|
+
biggerIsBetter,
|
|
46
49
|
|
|
47
|
-
|
|
48
|
-
|
|
50
|
+
// Row props
|
|
51
|
+
changed: getMetricChanged(runs),
|
|
49
52
|
|
|
50
|
-
|
|
51
|
-
|
|
53
|
+
// Runs
|
|
54
|
+
runs: processedRuns,
|
|
55
|
+
};
|
|
52
56
|
};
|
|
53
|
-
|
|
57
|
+
/* eslint-enable prettier/prettier */
|
|
@@ -7,9 +7,12 @@ import * as types from './types';
|
|
|
7
7
|
export const compareMetrics = (
|
|
8
8
|
jobs: Array<any>,
|
|
9
9
|
selectMetrics: (job: any) => any,
|
|
10
|
-
metricType
|
|
11
|
-
rowTransformers?: Array<
|
|
12
|
-
) => {
|
|
10
|
+
metricType?: string,
|
|
11
|
+
rowTransformers?: Array<types.MetricReportRowTransformFn>,
|
|
12
|
+
): Array<types.ReportMetricRow> => {
|
|
13
13
|
const data = map(jobs, selectMetrics);
|
|
14
|
-
return mergeMetricsByKey(data, [
|
|
14
|
+
return mergeMetricsByKey(data, [
|
|
15
|
+
getAddRowMetricData(metricType),
|
|
16
|
+
...(rowTransformers || []),
|
|
17
|
+
]) as Array<types.ReportMetricRow>;
|
|
15
18
|
};
|
package/src/report/create.ts
CHANGED
|
@@ -44,7 +44,7 @@ export const createReport = (jobs: Array<Job>): Report => {
|
|
|
44
44
|
return Object.assign(data, { label: metric.label });
|
|
45
45
|
});
|
|
46
46
|
|
|
47
|
-
summary[sourceId] = summaryEntries;
|
|
47
|
+
summary[sourceId] = summaryEntries as any;
|
|
48
48
|
}, {});
|
|
49
49
|
|
|
50
50
|
const sectionsData = webpack.compare(jobs);
|
package/src/report/index.js
CHANGED
|
@@ -4,18 +4,20 @@ import * as types from './types';
|
|
|
4
4
|
|
|
5
5
|
type RunMetrics = Record<string, types.MetricValue>;
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
7
|
+
/* eslint-disable prettier/prettier */
|
|
8
|
+
const mergeWithRuns =
|
|
9
|
+
(runIndex: number, runsCount: number) => (aggregated: any, currentRun: any): Array<types.MetricValue | null> => {
|
|
10
|
+
// if there are no runs, just create an array with empty values
|
|
11
|
+
const runs = aggregated || Array(runsCount).fill({ value: 0 });
|
|
11
12
|
runs[runIndex] = currentRun;
|
|
12
13
|
|
|
13
14
|
return runs;
|
|
14
15
|
};
|
|
16
|
+
/* eslint-enable prettier/prettier */
|
|
15
17
|
|
|
16
18
|
export const mergeMetricsByKey = (
|
|
17
19
|
runs: Array<RunMetrics>,
|
|
18
|
-
rowTransformers?: Array<
|
|
20
|
+
rowTransformers?: Array<types.MetricReportRowTransformFn>,
|
|
19
21
|
): Array<types.ReportRow> => {
|
|
20
22
|
const runsCount = runs.length;
|
|
21
23
|
|
package/src/report/types.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import type { MetricRunInfo, MetricRunInfoBaseline, MetricTypeConfig } from '../constants';
|
|
2
|
+
|
|
1
3
|
export interface MetricValue {
|
|
2
4
|
value: number;
|
|
3
5
|
name?: string;
|
|
@@ -7,3 +9,18 @@ export interface ReportRow {
|
|
|
7
9
|
key: string;
|
|
8
10
|
runs: Array<MetricValue | null>;
|
|
9
11
|
}
|
|
12
|
+
|
|
13
|
+
export type ReportMetricRun = { name?: MetricValue['name'] } & (
|
|
14
|
+
| MetricRunInfo
|
|
15
|
+
| MetricRunInfoBaseline
|
|
16
|
+
);
|
|
17
|
+
|
|
18
|
+
export interface ReportMetricRow {
|
|
19
|
+
key: string;
|
|
20
|
+
label: string;
|
|
21
|
+
biggerIsBetter: MetricTypeConfig['biggerIsBetter'];
|
|
22
|
+
changed: boolean;
|
|
23
|
+
runs: Array<ReportMetricRun | null>;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export type MetricReportRowTransformFn = (row: ReportRow) => ReportMetricRow;
|
|
@@ -1,5 +1,13 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import {
|
|
2
|
+
BooleanParam,
|
|
3
|
+
JsonParam,
|
|
4
|
+
ObjectParam,
|
|
5
|
+
QueryParamConfig,
|
|
6
|
+
StringParam,
|
|
7
|
+
decodeQueryParams,
|
|
8
|
+
encodeQueryParams,
|
|
9
|
+
} from 'serialize-query-params';
|
|
10
|
+
import isEmpty from 'lodash/isEmpty';
|
|
3
11
|
|
|
4
12
|
import {
|
|
5
13
|
FILE_TYPES,
|
|
@@ -8,6 +16,7 @@ import {
|
|
|
8
16
|
MODULE_SOURCE_FILE_TYPES,
|
|
9
17
|
} from '../config/file-types';
|
|
10
18
|
import {
|
|
19
|
+
ASSET_CHUNK,
|
|
11
20
|
ASSET_ENTRY_TYPE,
|
|
12
21
|
ASSET_FILE_TYPE,
|
|
13
22
|
ASSET_FILTERS,
|
|
@@ -21,11 +30,15 @@ import {
|
|
|
21
30
|
} from '../config/component-links';
|
|
22
31
|
import I18N from '../i18n';
|
|
23
32
|
|
|
24
|
-
export type ComponentLinkFilters = Record<string, boolean>;
|
|
33
|
+
export type ComponentLinkFilters = Record<string, boolean | string>;
|
|
25
34
|
|
|
26
35
|
export interface ComponentLinkParams {
|
|
27
36
|
search?: string;
|
|
28
|
-
|
|
37
|
+
entryId?: string;
|
|
38
|
+
metric?: string;
|
|
39
|
+
filters?: ComponentLinkFilters;
|
|
40
|
+
sortBy?: string;
|
|
41
|
+
direction?: string;
|
|
29
42
|
}
|
|
30
43
|
|
|
31
44
|
export interface ComponentLink {
|
|
@@ -159,6 +172,68 @@ export const BUNDLE_ASSETS_CHUNK_COUNT: ComponentLink = {
|
|
|
159
172
|
},
|
|
160
173
|
};
|
|
161
174
|
|
|
175
|
+
export const getBundleAsset = (entryId: string): ComponentLink => ({
|
|
176
|
+
section: SECTIONS.ASSETS,
|
|
177
|
+
title: I18N.COMPONENT_LINK_BUNDLE_ASSET_DETAILS,
|
|
178
|
+
params: {
|
|
179
|
+
[COMPONENT.BUNDLE_ASSETS]: {
|
|
180
|
+
entryId,
|
|
181
|
+
filters: {},
|
|
182
|
+
},
|
|
183
|
+
},
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
export const getBundleAssetsByEntryType = (
|
|
187
|
+
assetType: 'entry' | 'initial' | 'chunk',
|
|
188
|
+
): ComponentLink => ({
|
|
189
|
+
section: SECTIONS.ASSETS,
|
|
190
|
+
title: I18N.COMPONENT_LINK_BUNDLE_ASSETS_BY_ENTRY_TYPE(assetType),
|
|
191
|
+
params: {
|
|
192
|
+
[COMPONENT.BUNDLE_ASSETS]: {
|
|
193
|
+
filters: {
|
|
194
|
+
[ASSET_FILTERS.CHANGED]: false,
|
|
195
|
+
...getAssetEntryTypeFilters(false),
|
|
196
|
+
[`${ASSET_ENTRY_TYPE}.${ASSET_FILTERS.ENTRY}`]: assetType === 'entry',
|
|
197
|
+
[`${ASSET_ENTRY_TYPE}.${ASSET_FILTERS.INITIAL}`]: assetType === 'initial',
|
|
198
|
+
[`${ASSET_ENTRY_TYPE}.${ASSET_FILTERS.CHUNK}`]: assetType === 'chunk',
|
|
199
|
+
},
|
|
200
|
+
},
|
|
201
|
+
},
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
export const getBundleAssetsFileTypeComponentLink = (
|
|
205
|
+
fileType: string,
|
|
206
|
+
label: string = fileType,
|
|
207
|
+
): ComponentLink => ({
|
|
208
|
+
section: SECTIONS.ASSETS,
|
|
209
|
+
title: I18N.COMPONENT_LINK_BUNDLE_ASSETS_BY_FILE_TYPE({ label }),
|
|
210
|
+
params: {
|
|
211
|
+
[COMPONENT.BUNDLE_ASSETS]: {
|
|
212
|
+
filters: {
|
|
213
|
+
...getAssetFileTypeFilters(false),
|
|
214
|
+
[`${ASSET_FILE_TYPE}.${fileType}`]: true,
|
|
215
|
+
},
|
|
216
|
+
},
|
|
217
|
+
},
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
export const getBundleAssetsByChunk = (
|
|
221
|
+
chunkIds: Array<string>,
|
|
222
|
+
chunkId: string,
|
|
223
|
+
): ComponentLink => ({
|
|
224
|
+
section: SECTIONS.ASSETS,
|
|
225
|
+
title: I18N.COMPONENT_LINK_BUNDLE_ASSETS_CHUNKS,
|
|
226
|
+
params: {
|
|
227
|
+
[COMPONENT.BUNDLE_ASSETS]: {
|
|
228
|
+
filters: {
|
|
229
|
+
[ASSET_FILTERS.CHUNK]: false,
|
|
230
|
+
...getModuleChunkFilters(chunkIds, false),
|
|
231
|
+
[`${ASSET_CHUNK}.${chunkId}`]: true,
|
|
232
|
+
},
|
|
233
|
+
},
|
|
234
|
+
},
|
|
235
|
+
});
|
|
236
|
+
|
|
162
237
|
export const BUNDLE_MODULES: ComponentLink = {
|
|
163
238
|
section: SECTIONS.MODULES,
|
|
164
239
|
title: I18N.COMPONENT_LINK_MODULES,
|
|
@@ -168,6 +243,7 @@ export const BUNDLE_MODULES: ComponentLink = {
|
|
|
168
243
|
// Keep a filter to allow the merge and skip default
|
|
169
244
|
[MODULE_FILTERS.CHANGED]: false,
|
|
170
245
|
},
|
|
246
|
+
[MODULE_FILTERS.METRIC]: 'totalSize',
|
|
171
247
|
},
|
|
172
248
|
},
|
|
173
249
|
};
|
|
@@ -181,6 +257,7 @@ export const BUNDLE_MODULES_DUPLICATE: ComponentLink = {
|
|
|
181
257
|
[MODULE_FILTERS.CHANGED]: false,
|
|
182
258
|
[MODULE_FILTERS.DUPLICATED]: true,
|
|
183
259
|
},
|
|
260
|
+
[MODULE_FILTERS.METRIC]: 'duplicateSize',
|
|
184
261
|
},
|
|
185
262
|
},
|
|
186
263
|
};
|
|
@@ -221,6 +298,35 @@ export const getBundleModulesByChunk = (
|
|
|
221
298
|
},
|
|
222
299
|
});
|
|
223
300
|
|
|
301
|
+
export const getBundleModulesByFileTpe = (
|
|
302
|
+
fileType: string,
|
|
303
|
+
fileTypeLabel?: string,
|
|
304
|
+
): ComponentLink => ({
|
|
305
|
+
section: SECTIONS.MODULES,
|
|
306
|
+
title: I18N.COMPONENT_LINK_MODULES_BY_FILE_TYPE(fileTypeLabel || fileType),
|
|
307
|
+
params: {
|
|
308
|
+
[COMPONENT.BUNDLE_MODULES]: {
|
|
309
|
+
filters: {
|
|
310
|
+
...getModuleFileTypeFilters(false),
|
|
311
|
+
[`${MODULE_FILE_TYPE}.${fileType}`]: true,
|
|
312
|
+
},
|
|
313
|
+
},
|
|
314
|
+
},
|
|
315
|
+
});
|
|
316
|
+
|
|
317
|
+
export const getBundleModulesBySource = (thirdParty: boolean, label = ''): ComponentLink => ({
|
|
318
|
+
section: SECTIONS.MODULES,
|
|
319
|
+
title: I18N.COMPONENT_LINK_MODULES_BY_SOURCE(label),
|
|
320
|
+
params: {
|
|
321
|
+
[COMPONENT.BUNDLE_MODULES]: {
|
|
322
|
+
filters: {
|
|
323
|
+
[`${MODULE_SOURCE_TYPE}.${MODULE_FILTERS.THIRD_PARTY}`]: thirdParty,
|
|
324
|
+
[`${MODULE_SOURCE_TYPE}.${MODULE_FILTERS.FIRST_PARTY}`]: !thirdParty,
|
|
325
|
+
},
|
|
326
|
+
},
|
|
327
|
+
},
|
|
328
|
+
});
|
|
329
|
+
|
|
224
330
|
export const BUNDLE_PACKAGES_COUNT: ComponentLink = {
|
|
225
331
|
section: SECTIONS.PACKAGES,
|
|
226
332
|
title: I18N.COMPONENT_LINK_PACKAGES_COUNT,
|
|
@@ -272,22 +378,6 @@ export const BUNDLE_PACKAGES_DUPLICATE_CHANGED: ComponentLink = {
|
|
|
272
378
|
},
|
|
273
379
|
};
|
|
274
380
|
|
|
275
|
-
export const getBundleAssetsFileTypeComponentLink = (
|
|
276
|
-
fileType: string,
|
|
277
|
-
label: string,
|
|
278
|
-
): ComponentLink => ({
|
|
279
|
-
section: SECTIONS.ASSETS,
|
|
280
|
-
title: I18N.COMPONENT_LINK_BUNDLE_ASSETS_BY_FILE_TYPE({ label }),
|
|
281
|
-
params: {
|
|
282
|
-
[COMPONENT.BUNDLE_ASSETS]: {
|
|
283
|
-
filters: {
|
|
284
|
-
...getAssetFileTypeFilters(false),
|
|
285
|
-
[`${ASSET_FILE_TYPE}.${fileType}`]: true,
|
|
286
|
-
},
|
|
287
|
-
},
|
|
288
|
-
},
|
|
289
|
-
});
|
|
290
|
-
|
|
291
381
|
export const getBundlePackagesByNameComponentLink = (search: string): ComponentLink => ({
|
|
292
382
|
section: SECTIONS.PACKAGES,
|
|
293
383
|
title: I18N.COMPONENT_LINK_VIEW_PACKAGE,
|
|
@@ -301,29 +391,180 @@ export const getBundlePackagesByNameComponentLink = (search: string): ComponentL
|
|
|
301
391
|
},
|
|
302
392
|
});
|
|
303
393
|
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
394
|
+
/**
|
|
395
|
+
* Custom URI ecoding/decoding that encodes the params used by ObjectParam as separators: `_`, `-`
|
|
396
|
+
*/
|
|
397
|
+
const CUSTOM_ENCODING_URI_CHARS_PATTERN = /(_|-)/g;
|
|
398
|
+
const CUSTOM_ENCODING_URI_CODE_PATTERN = /(%(?:2D|5F))/g;
|
|
399
|
+
|
|
400
|
+
function customEncodeURIComponent(value: string): string {
|
|
401
|
+
return encodeURIComponent(value).replace(
|
|
402
|
+
CUSTOM_ENCODING_URI_CHARS_PATTERN,
|
|
403
|
+
(char) => `%${char.charCodeAt(0).toString(16).toUpperCase()}`,
|
|
404
|
+
);
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
function customDecodeURIComponent(value: string): string {
|
|
408
|
+
const encodedURI = value.replace(CUSTOM_ENCODING_URI_CODE_PATTERN, (code) =>
|
|
409
|
+
String.fromCharCode(parseInt(code.replace(/^%/, ''), 16)),
|
|
311
410
|
);
|
|
312
411
|
|
|
313
|
-
return
|
|
412
|
+
return decodeURIComponent(encodedURI);
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
/**
|
|
416
|
+
* Custom section params encoder/decoder
|
|
417
|
+
*
|
|
418
|
+
* @NOTE To keep the length of the query string small when using a lot of filters (ex: chunks)
|
|
419
|
+
* we use different encoding/decoding algorithms depending on the property type:
|
|
420
|
+
*
|
|
421
|
+
* - section: JsonParam
|
|
422
|
+
* - search: StringParam
|
|
423
|
+
* - entryId: StringParam
|
|
424
|
+
* - metric: StringParam
|
|
425
|
+
* - sortBy: StringParam
|
|
426
|
+
* - direction: StringParam
|
|
427
|
+
* - filters: ObjectParam
|
|
428
|
+
* - value: BooleanParam
|
|
429
|
+
*/
|
|
430
|
+
export const ComponentStateParam: QueryParamConfig<any, any> = {
|
|
431
|
+
encode: (sectionState) => {
|
|
432
|
+
if (!sectionState) {
|
|
433
|
+
return undefined;
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
const search = StringParam.encode(sectionState.search);
|
|
437
|
+
const entryId = StringParam.encode(sectionState.entryId);
|
|
438
|
+
const metric = StringParam.encode(sectionState.metric);
|
|
439
|
+
const sortBy = StringParam.encode(sectionState.sortBy);
|
|
440
|
+
const direction = StringParam.encode(sectionState.direction);
|
|
441
|
+
|
|
442
|
+
const filtersEncodedValues: Record<string, string> = {};
|
|
443
|
+
Object.entries(sectionState.filters || {}).forEach(([key, val]) => {
|
|
444
|
+
filtersEncodedValues[customEncodeURIComponent(key)] = BooleanParam.encode(!!val) as string;
|
|
445
|
+
});
|
|
446
|
+
const filters = ObjectParam.encode(filtersEncodedValues);
|
|
447
|
+
|
|
448
|
+
const data = {} as any;
|
|
449
|
+
|
|
450
|
+
if (search) {
|
|
451
|
+
data.search = search;
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
if (entryId) {
|
|
455
|
+
data.entryId = entryId;
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
if (metric) {
|
|
459
|
+
data.metric = metric;
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
if (sortBy) {
|
|
463
|
+
data.sortBy = sortBy;
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
if (direction) {
|
|
467
|
+
data.direction = direction;
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
if (!isEmpty(filters)) {
|
|
471
|
+
data.filters = filters;
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
return JsonParam.encode(data);
|
|
475
|
+
},
|
|
476
|
+
decode: (queryString) => {
|
|
477
|
+
const params = JsonParam.decode(queryString);
|
|
478
|
+
|
|
479
|
+
if (isEmpty(params)) {
|
|
480
|
+
return undefined;
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
const search = StringParam.decode(params.search);
|
|
484
|
+
const entryId = StringParam.decode(params.entryId);
|
|
485
|
+
const metric = StringParam.decode(params.metric);
|
|
486
|
+
const sortBy = StringParam.decode(params.sortBy);
|
|
487
|
+
const direction = StringParam.decode(params.direction);
|
|
488
|
+
|
|
489
|
+
let filters: Record<string, boolean> = {};
|
|
490
|
+
|
|
491
|
+
// Decode filters if typeof is string (mixed encoding)
|
|
492
|
+
// .1 ObjectParam
|
|
493
|
+
// .2 BooleanParam
|
|
494
|
+
if (typeof params.filters === 'string') {
|
|
495
|
+
const decodedFilters = ObjectParam.decode(params.filters);
|
|
496
|
+
|
|
497
|
+
Object.entries(decodedFilters || {}).forEach(([key, value]) => {
|
|
498
|
+
const filterDecodedValue = BooleanParam.decode(value);
|
|
499
|
+
|
|
500
|
+
if (typeof filterDecodedValue !== 'undefined' && filterDecodedValue !== null) {
|
|
501
|
+
filters[customDecodeURIComponent(key)] = filterDecodedValue;
|
|
502
|
+
}
|
|
503
|
+
});
|
|
504
|
+
} else if (typeof params.filters === 'object') {
|
|
505
|
+
// Use directly if already decoded (JSON encoding - obsolete)
|
|
506
|
+
filters = params.filters;
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
// Include only the truthy values
|
|
510
|
+
const result: Record<string, any> = {};
|
|
511
|
+
|
|
512
|
+
if (search) {
|
|
513
|
+
result.search = search;
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
if (entryId) {
|
|
517
|
+
result.entryId = entryId;
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
if (metric) {
|
|
521
|
+
result.metric = metric;
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
if (sortBy) {
|
|
525
|
+
result.sortBy = sortBy;
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
if (direction) {
|
|
529
|
+
result.direction = direction;
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
if (!isEmpty(filters)) {
|
|
533
|
+
result.filters = filters;
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
if (isEmpty(result)) {
|
|
537
|
+
return undefined;
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
return result;
|
|
541
|
+
},
|
|
542
|
+
};
|
|
543
|
+
|
|
544
|
+
export const COMPONENT_STATE_META = {
|
|
545
|
+
[COMPONENT.BUNDLE_ASSETS]: ComponentStateParam,
|
|
546
|
+
[COMPONENT.BUNDLE_MODULES]: ComponentStateParam,
|
|
547
|
+
[COMPONENT.BUNDLE_PACKAGES]: ComponentStateParam,
|
|
548
|
+
} as const;
|
|
549
|
+
|
|
550
|
+
type ComponentStateQueryStringParams = Record<string, ComponentLinkParams>;
|
|
551
|
+
|
|
552
|
+
export const getComponentStateQueryString = (params: ComponentStateQueryStringParams = {}) => {
|
|
553
|
+
const data = encodeQueryParams(COMPONENT_STATE_META, params);
|
|
554
|
+
const searchParams = new URLSearchParams(data as Record<string, string>);
|
|
555
|
+
return searchParams.toString();
|
|
556
|
+
};
|
|
557
|
+
|
|
558
|
+
export const getComponentStateData = (queryString: string): ComponentStateQueryStringParams => {
|
|
559
|
+
const params = new URLSearchParams(queryString);
|
|
560
|
+
return decodeQueryParams(COMPONENT_STATE_META, Object.fromEntries(params.entries()));
|
|
314
561
|
};
|
|
315
562
|
|
|
316
563
|
export const METRIC_COMPONENT_LINKS = new Map([
|
|
317
564
|
['webpack.totalSizeByTypeALL', { link: TOTALS }],
|
|
318
565
|
['webpack.totalInitialSizeJS', { link: BUNDLE_ASSETS_INITIAL_JS }],
|
|
319
566
|
['webpack.totalInitialSizeCSS', { link: BUNDLE_ASSETS_INITIAL_CSS }],
|
|
320
|
-
[
|
|
321
|
-
'webpack.cacheInvalidation',
|
|
322
|
-
{
|
|
323
|
-
link: BUNDLE_ASSETS_CACHE_INVALIDATION,
|
|
324
|
-
showDelta: false,
|
|
325
|
-
},
|
|
326
|
-
],
|
|
567
|
+
['webpack.cacheInvalidation', { link: BUNDLE_ASSETS_CACHE_INVALIDATION }],
|
|
327
568
|
['webpack.assetCount', { link: BUNDLE_ASSETS_COUNT }],
|
|
328
569
|
['webpack.chunkCount', { link: BUNDLE_ASSETS_CHUNK_COUNT }],
|
|
329
570
|
['webpack.moduleCount', { link: BUNDLE_MODULES }],
|