diff --git a/packages/utils/src/report/__tests__/__snapshots__/add-row-data.js.snap b/packages/utils/src/report/__tests__/__snapshots__/add-row-data.js.snap index 5c49c1f7f6..320dd4f05e 100644 --- a/packages/utils/src/report/__tests__/__snapshots__/add-row-data.js.snap +++ b/packages/utils/src/report/__tests__/__snapshots__/add-row-data.js.snap @@ -5,29 +5,28 @@ Array [ Object { "biggerIsBetter": false, "changed": true, - "key": "metric1", - "label": "metric1", + "key": "webpack.totalSizeByTypeALL", + "label": "Total Bundle Size", "runs": Array [ Object { "delta": -10, "deltaPercentage": -9.09090909, - "displayDelta": "-10", + "displayDelta": "-10B", "displayDeltaPercentage": "-9.09%", - "displayValue": "100", + "displayValue": "100B", "value": 100, }, Object { - "displayValue": "110", + "displayValue": "110B", "value": 110, }, ], - "type": "METRIC_TYPE_DURATION", }, Object { "biggerIsBetter": false, "changed": true, - "key": "metric2", - "label": "metric2", + "key": "webpack.duplicatePackagesCount", + "label": "Duplicate Packages Count", "runs": Array [ Object { "delta": 10, @@ -39,13 +38,12 @@ Array [ }, null, ], - "type": "METRIC_TYPE_NUMBER", }, Object { "biggerIsBetter": false, "changed": false, - "key": "metric4", - "label": "metric4", + "key": "webpack.mdoulesCount", + "label": "webpack.mdoulesCount", "runs": Array [ Object { "delta": 0, @@ -60,7 +58,61 @@ Array [ "value": 100, }, ], - "type": "METRIC_TYPE_SCORE", + }, + Object { + "biggerIsBetter": false, + "changed": true, + "key": "webpack.cacheInvalidation", + "label": "Cache Invalidation", + "runs": Array [ + null, + Object { + "displayValue": "10%", + "value": 10, + }, + ], + }, +] +`; + +exports[`report / addRowData should add data with metric type 1`] = ` +Array [ + Object { + "biggerIsBetter": false, + "changed": true, + "key": "metric1", + "label": "metric1", + "runs": Array [ + Object { + "delta": -10, + "deltaPercentage": -9.09090909, + "displayDelta": "-10B", + "displayDeltaPercentage": "-9.09%", + "displayValue": "100B", + "value": 100, + }, + Object { + "displayValue": "110B", + "value": 110, + }, + ], + }, + Object { + "biggerIsBetter": false, + "changed": true, + "key": "metric2", + "label": "metric2", + "runs": Array [ + Object { + "delta": 10, + "deltaPercentage": 100, + "displayDelta": "+10B", + "displayDeltaPercentage": "+100%", + "displayValue": "10B", + "value": 10, + }, + null, + ], }, Object { "biggerIsBetter": false, @@ -70,11 +122,30 @@ Array [ "runs": Array [ null, Object { - "displayValue": "10", + "displayValue": "10B", "value": 10, }, ], - "type": "METRIC_TYPE_FILE_SIZE", + }, + Object { + "biggerIsBetter": false, + "changed": false, + "key": "metric4", + "label": "metric4", + "runs": Array [ + Object { + "delta": 0, + "deltaPercentage": 0, + "displayDelta": "0B", + "displayDeltaPercentage": "0%", + "displayValue": "100B", + "value": 100, + }, + Object { + "displayValue": "100B", + "value": 100, + }, + ], }, ] `; diff --git a/packages/utils/src/report/__tests__/__snapshots__/create.js.snap b/packages/utils/src/report/__tests__/__snapshots__/create.js.snap index 75b1b7f596..e5cf36378e 100644 --- a/packages/utils/src/report/__tests__/__snapshots__/create.js.snap +++ b/packages/utils/src/report/__tests__/__snapshots__/create.js.snap @@ -30,7 +30,6 @@ Object { "value": 11000, }, ], - "type": undefined, }, Object { "biggerIsBetter": false, @@ -59,7 +58,6 @@ Object { "value": 49000, }, ], - "type": undefined, }, Object { "biggerIsBetter": false, @@ -88,7 +86,6 @@ Object { "value": 1000, }, ], - "type": undefined, }, Object { "biggerIsBetter": false, @@ -117,7 +114,6 @@ Object { "value": 2000, }, ], - "type": undefined, }, ], "modules": Array [ @@ -148,7 +144,6 @@ Object { "value": 1000, }, ], - "type": undefined, }, Object { "biggerIsBetter": false, @@ -171,7 +166,6 @@ Object { "value": 1500, }, ], - "type": undefined, }, Object { "biggerIsBetter": false, @@ -194,7 +188,6 @@ Object { "value": 1000, }, ], - "type": undefined, }, Object { "biggerIsBetter": false, @@ -213,7 +206,6 @@ Object { }, null, ], - "type": undefined, }, Object { "biggerIsBetter": false, @@ -236,7 +228,6 @@ Object { "value": 1000, }, ], - "type": undefined, }, Object { "biggerIsBetter": false, @@ -259,7 +250,6 @@ Object { "value": 1000, }, ], - "type": undefined, }, ], }, @@ -284,7 +274,6 @@ Object { "value": 1000, }, ], - "type": undefined, }, Object { "biggerIsBetter": false, @@ -302,7 +291,6 @@ Object { }, null, ], - "type": undefined, }, Object { "biggerIsBetter": false, @@ -323,7 +311,6 @@ Object { "value": 1000, }, ], - "type": undefined, }, Object { "biggerIsBetter": false, @@ -344,7 +331,6 @@ Object { "value": 1000, }, ], - "type": undefined, }, ], "runs": Array [ @@ -383,7 +369,6 @@ Object { "value": 11000, }, ], - "type": undefined, }, Object { "biggerIsBetter": false, @@ -404,7 +389,6 @@ Object { "value": 49000, }, ], - "type": undefined, }, Object { "biggerIsBetter": false, @@ -425,7 +409,6 @@ Object { "value": 1000, }, ], - "type": undefined, }, Object { "biggerIsBetter": false, @@ -446,7 +429,6 @@ Object { "value": 0, }, ], - "type": undefined, }, Object { "biggerIsBetter": false, @@ -467,7 +449,6 @@ Object { "value": 0, }, ], - "type": undefined, }, Object { "biggerIsBetter": false, @@ -488,7 +469,6 @@ Object { "value": 2000, }, ], - "type": undefined, }, Object { "biggerIsBetter": false, @@ -509,7 +489,6 @@ Object { "value": 0, }, ], - "type": undefined, }, ], "stats": Array [ @@ -532,7 +511,6 @@ Object { "value": 63000, }, ], - "type": undefined, }, Object { "biggerIsBetter": false, @@ -553,7 +531,6 @@ Object { "value": 49000, }, ], - "type": undefined, }, Object { "biggerIsBetter": false, @@ -574,7 +551,6 @@ Object { "value": 11000, }, ], - "type": undefined, }, Object { "biggerIsBetter": false, @@ -595,7 +571,6 @@ Object { "value": 0, }, ], - "type": undefined, }, Object { "biggerIsBetter": false, @@ -616,7 +591,6 @@ Object { "value": 5, }, ], - "type": undefined, }, Object { "biggerIsBetter": false, @@ -637,7 +611,6 @@ Object { "value": 0, }, ], - "type": undefined, }, Object { "biggerIsBetter": false, @@ -658,7 +631,6 @@ Object { "value": 4, }, ], - "type": undefined, }, Object { "biggerIsBetter": false, @@ -679,7 +651,6 @@ Object { "value": 3, }, ], - "type": undefined, }, Object { "biggerIsBetter": false, @@ -700,7 +671,6 @@ Object { "value": 0, }, ], - "type": undefined, }, ], "warnings": Object { @@ -734,7 +704,6 @@ Object { "value": 10000, }, ], - "type": undefined, }, Object { "biggerIsBetter": false, @@ -751,7 +720,6 @@ Object { "value": 50000, }, ], - "type": undefined, }, Object { "biggerIsBetter": false, @@ -768,7 +736,6 @@ Object { "value": 1000, }, ], - "type": undefined, }, Object { "biggerIsBetter": false, @@ -785,7 +752,6 @@ Object { "value": 2000, }, ], - "type": undefined, }, ], "modules": Array [ @@ -807,7 +773,6 @@ Object { "value": 1000, }, ], - "type": undefined, }, Object { "biggerIsBetter": false, @@ -821,7 +786,6 @@ Object { "value": 2000, }, ], - "type": undefined, }, Object { "biggerIsBetter": false, @@ -835,7 +799,6 @@ Object { "value": 1000, }, ], - "type": undefined, }, Object { "biggerIsBetter": false, @@ -849,7 +812,6 @@ Object { "value": 1000, }, ], - "type": undefined, }, Object { "biggerIsBetter": false, @@ -863,7 +825,6 @@ Object { "value": 1000, }, ], - "type": undefined, }, Object { "biggerIsBetter": false, @@ -877,7 +838,6 @@ Object { "value": 1000, }, ], - "type": undefined, }, ], }, @@ -894,7 +854,6 @@ Object { "value": 1000, }, ], - "type": undefined, }, Object { "biggerIsBetter": false, @@ -907,7 +866,6 @@ Object { "value": 1000, }, ], - "type": undefined, }, Object { "biggerIsBetter": false, @@ -920,7 +878,6 @@ Object { "value": 1000, }, ], - "type": undefined, }, Object { "biggerIsBetter": false, @@ -933,7 +890,6 @@ Object { "value": 1000, }, ], - "type": undefined, }, ], "runs": Array [ @@ -957,7 +913,6 @@ Object { "value": 10000, }, ], - "type": undefined, }, Object { "biggerIsBetter": false, @@ -970,7 +925,6 @@ Object { "value": 50000, }, ], - "type": undefined, }, Object { "biggerIsBetter": false, @@ -983,7 +937,6 @@ Object { "value": 1000, }, ], - "type": undefined, }, Object { "biggerIsBetter": false, @@ -996,7 +949,6 @@ Object { "value": 0, }, ], - "type": undefined, }, Object { "biggerIsBetter": false, @@ -1009,7 +961,6 @@ Object { "value": 0, }, ], - "type": undefined, }, Object { "biggerIsBetter": false, @@ -1022,7 +973,6 @@ Object { "value": 2000, }, ], - "type": undefined, }, Object { "biggerIsBetter": false, @@ -1035,7 +985,6 @@ Object { "value": 0, }, ], - "type": undefined, }, ], "stats": Array [ @@ -1050,7 +999,6 @@ Object { "value": 63000, }, ], - "type": undefined, }, Object { "biggerIsBetter": false, @@ -1063,7 +1011,6 @@ Object { "value": 50000, }, ], - "type": undefined, }, Object { "biggerIsBetter": false, @@ -1076,7 +1023,6 @@ Object { "value": 10000, }, ], - "type": undefined, }, Object { "biggerIsBetter": false, @@ -1089,7 +1035,6 @@ Object { "value": 0, }, ], - "type": undefined, }, Object { "biggerIsBetter": false, @@ -1102,7 +1047,6 @@ Object { "value": 6, }, ], - "type": undefined, }, Object { "biggerIsBetter": false, @@ -1115,7 +1059,6 @@ Object { "value": 0, }, ], - "type": undefined, }, Object { "biggerIsBetter": false, @@ -1128,7 +1071,6 @@ Object { "value": 4, }, ], - "type": undefined, }, Object { "biggerIsBetter": false, @@ -1141,7 +1083,6 @@ Object { "value": 4, }, ], - "type": undefined, }, Object { "biggerIsBetter": false, @@ -1154,7 +1095,6 @@ Object { "value": 1, }, ], - "type": undefined, }, ], "warnings": Object { diff --git a/packages/utils/src/report/__tests__/add-row-data.js b/packages/utils/src/report/__tests__/add-row-data.js index e7b24c35fc..bd74e2970e 100644 --- a/packages/utils/src/report/__tests__/add-row-data.js +++ b/packages/utils/src/report/__tests__/add-row-data.js @@ -1,11 +1,11 @@ +import { METRIC_TYPE_FILE_SIZE } from '../../config/metrics'; import { addRowData } from '../add-row-data'; describe('report / addRowData', () => { test('should add data', () => { - const actual = addRowData([ + const rows = [ { - key: 'metric1', - type: 'METRIC_TYPE_DURATION', + key: 'webpack.totalSizeByTypeALL', runs: [ { value: 100, @@ -16,8 +16,7 @@ describe('report / addRowData', () => { ], }, { - key: 'metric2', - type: 'METRIC_TYPE_NUMBER', + key: 'webpack.duplicatePackagesCount', runs: [ { value: 10, @@ -26,8 +25,7 @@ describe('report / addRowData', () => { ], }, { - key: 'metric4', - type: 'METRIC_TYPE_SCORE', + key: 'webpack.mdoulesCount', runs: [ { value: 100, @@ -37,9 +35,46 @@ describe('report / addRowData', () => { }, ], }, + { + key: 'webpack.cacheInvalidation', + runs: [ + null, + { + value: 10, + }, + ], + }, + ]; + + const actual = rows.map(addRowData); + + expect(actual).toMatchSnapshot(); + }); + + test('should add data with metric type', () => { + const rows = [ + { + key: 'metric1', + runs: [ + { + value: 100, + }, + { + value: 110, + }, + ], + }, + { + key: 'metric2', + runs: [ + { + value: 10, + }, + null, + ], + }, { key: 'metric3', - type: 'METRIC_TYPE_FILE_SIZE', runs: [ null, { @@ -47,7 +82,20 @@ describe('report / addRowData', () => { }, ], }, - ]); + { + key: 'metric4', + runs: [ + { + value: 100, + }, + { + value: 100, + }, + ], + }, + ]; + + const actual = rows.map((row) => addRowData(row, METRIC_TYPE_FILE_SIZE)); expect(actual).toMatchSnapshot(); }); diff --git a/packages/utils/src/report/__tests__/merge-runs-by-id.js b/packages/utils/src/report/__tests__/merge-runs-by-id.js index 57b0b1f760..e83b202251 100644 --- a/packages/utils/src/report/__tests__/merge-runs-by-id.js +++ b/packages/utils/src/report/__tests__/merge-runs-by-id.js @@ -6,29 +6,23 @@ describe('merge runs by ids', () => { { metric1: { value: 100, - type: 'METRIC_TYPE_DURATION', }, metric2: { value: 10, - type: 'METRIC_TYPE_NUMBER', }, metric4: { value: 100, - type: 'METRIC_TYPE_SCORE', }, }, { metric1: { value: 110, - type: 'METRIC_TYPE_DURATION', }, metric3: { value: 10, - type: 'METRIC_TYPE_FILE_SIZE', }, metric4: { value: 100, - type: 'METRIC_TYPE_SCORE', }, }, ]); @@ -36,7 +30,6 @@ describe('merge runs by ids', () => { expect(actual).toEqual([ { key: 'metric1', - type: 'METRIC_TYPE_DURATION', runs: [ { value: 100, @@ -48,7 +41,6 @@ describe('merge runs by ids', () => { }, { key: 'metric2', - type: 'METRIC_TYPE_NUMBER', runs: [ { value: 10, @@ -58,7 +50,6 @@ describe('merge runs by ids', () => { }, { key: 'metric4', - type: 'METRIC_TYPE_SCORE', runs: [ { value: 100, @@ -70,7 +61,6 @@ describe('merge runs by ids', () => { }, { key: 'metric3', - type: 'METRIC_TYPE_FILE_SIZE', runs: [ null, { diff --git a/packages/utils/src/report/add-row-data.js b/packages/utils/src/report/add-row-data.js index f05e7f1902..52022096d2 100644 --- a/packages/utils/src/report/add-row-data.js +++ b/packages/utils/src/report/add-row-data.js @@ -3,16 +3,19 @@ import { formatPercentage } from '../utils/format'; import { getMetricChanged } from '../metrics/get-metric-changed'; import { getMetricType } from '../metrics/get-metric-type'; -export const addRowData = (entries, metricType, metricPrefix = '') => entries.map((entry) => { - const { runs } = entry; +export const addRowData = (row, metricType) => { + const { key, runs } = row; + // Resolve row metric + // - if the key is a predefined metric, use it + // - if the key is not matching an existing metric, use the default metricType const { biggerIsBetter, label, formatter } = getMetricType( - metricPrefix ? [metricPrefix, entry.key].join('.') : entry.key, - metricType, + key, + typeof metricType === 'string' && metricType, // explicit, avoid passing of map cb params ); return { - ...entry, + ...row, // Metric props biggerIsBetter, @@ -46,4 +49,4 @@ export const addRowData = (entries, metricType, metricPrefix = '') => entries.ma }; }), }; -}); +}; diff --git a/packages/utils/src/report/create.js b/packages/utils/src/report/create.js index 5967a88aa5..5442c56c7a 100644 --- a/packages/utils/src/report/create.js +++ b/packages/utils/src/report/create.js @@ -1,5 +1,5 @@ import { - flatMap, get, isEmpty, map, pick, uniq, + flatMap, get, isEmpty, map, uniq, } from 'lodash'; import { METRIC_TYPE_FILE_SIZE } from '../config'; @@ -7,36 +7,30 @@ import * as webpack from '../webpack'; import { mergeRunsById } from './merge-runs-by-id'; import { addRowData } from './add-row-data'; -const getWebpackSizesMetrics = (job) => { - const metrics = get(job, 'metrics.webpack.sizes', {}); - - return Object.entries(metrics).reduce((agg, [key, value]) => ({ - ...agg, - [`webpack.sizes.${key}`]: value, - }), {}); +const compareMetrics = (jobs, selectMetrics, metricType) => { + const data = map(jobs, selectMetrics); + const rows = mergeRunsById(data); + return rows.map((row) => addRowData(row, metricType)); }; -const getWebpackStatsMetrics = (job) => { - const metrics = pick(get(job, 'metrics.webpack', {}), webpack.SUMMARY_METRIC_PATHS); - - return Object.entries(metrics).reduce((agg, [key, value]) => ({ - ...agg, - [`webpack.${key}`]: value, - }), {}); +export const getModulesReport = (jobs) => { + const jobsModuleMetrics = jobs.map(webpack.selectors.modules); + const allChunkIds = uniq(flatMap( + jobsModuleMetrics, (jobModuleMetrics) => Object.keys(jobModuleMetrics), + )); + + return allChunkIds.map((chunkId) => { + const chunksJobs = map(jobsModuleMetrics, (job) => get(job, chunkId)); + const chunkNames = uniq(flatMap(chunksJobs, 'chunkNames')); + + return { + chunkId, + chunkNames, + modules: mergeRunsById(map(chunksJobs, 'modules')).map((row) => addRowData(row, METRIC_TYPE_FILE_SIZE)), + }; + }); }; -export const getModulesReport = (jobs) => map( - uniq(flatMap(jobs, (job) => Object.keys(get(job, 'metrics.webpack.modules', {})))), - - (chunkId) => ({ - chunkId, - chunkNames: uniq(flatMap(jobs, (job) => get(job, ['metrics', 'webpack', 'modules', chunkId, 'chunkNames']))), - modules: addRowData(mergeRunsById( - map(jobs, (job) => get(job, ['metrics', 'webpack', 'modules', chunkId, 'modules'])), - ), METRIC_TYPE_FILE_SIZE), - }), -); - export const createReport = (jobs) => { const warnings = get(jobs, '[0].warnings'); @@ -49,10 +43,10 @@ export const createReport = (jobs) => { // Add warnings if available ...!isEmpty(warnings) ? { warnings } : {}, - stats: addRowData(mergeRunsById(map(jobs, getWebpackStatsMetrics))), - sizes: addRowData(mergeRunsById(map(jobs, getWebpackSizesMetrics))), - assets: addRowData(mergeRunsById(map(jobs, 'metrics.webpack.assets')), METRIC_TYPE_FILE_SIZE), + stats: compareMetrics(jobs, webpack.selectors.stats), + sizes: compareMetrics(jobs, webpack.selectors.sizes), + assets: compareMetrics(jobs, webpack.selectors.assets, METRIC_TYPE_FILE_SIZE), modules: getModulesReport(jobs), - packages: addRowData(mergeRunsById(map(jobs, 'metrics.webpack.packages')), METRIC_TYPE_FILE_SIZE), + packages: compareMetrics(jobs, webpack.selectors.packages, METRIC_TYPE_FILE_SIZE), }; }; diff --git a/packages/utils/src/report/merge-runs-by-id.js b/packages/utils/src/report/merge-runs-by-id.js index ab5169b3c4..13214e21ce 100644 --- a/packages/utils/src/report/merge-runs-by-id.js +++ b/packages/utils/src/report/merge-runs-by-id.js @@ -1,5 +1,5 @@ import { - fill, map, mergeWith, omit, + fill, map, mergeWith, } from 'lodash'; const mergeWithRuns = (index, count) => (objValue, srcValue) => { @@ -8,10 +8,9 @@ const mergeWithRuns = (index, count) => (objValue, srcValue) => { ? [...objValue.runs] : fill(Array(count), null); - res[index] = omit(srcValue, 'type'); + res[index] = srcValue; return { - type: srcValue.type, runs: res, }; }; diff --git a/packages/utils/src/webpack/constants.js b/packages/utils/src/webpack/constants.js new file mode 100644 index 0000000000..1b2daace53 --- /dev/null +++ b/packages/utils/src/webpack/constants.js @@ -0,0 +1,11 @@ +export const SUMMARY_METRIC_PATHS = [ + 'totalSizeByTypeALL', + 'totalInitialSizeJS', + 'totalInitialSizeCSS', + 'cacheInvalidation', + 'moduleCount', + 'chunkCount', + 'assetCount', + 'packageCount', + 'duplicatePackagesCount', +]; diff --git a/packages/utils/src/webpack/index.js b/packages/utils/src/webpack/index.js index f8ff50569b..26228e1486 100644 --- a/packages/utils/src/webpack/index.js +++ b/packages/utils/src/webpack/index.js @@ -1,15 +1,5 @@ +export * from './constants'; export * from './filter'; export * from './extract'; +export * from './selectors'; export * from './utils'; - -export const SUMMARY_METRIC_PATHS = [ - 'totalSizeByTypeALL', - 'totalInitialSizeJS', - 'totalInitialSizeCSS', - 'cacheInvalidation', - 'moduleCount', - 'chunkCount', - 'assetCount', - 'packageCount', - 'duplicatePackagesCount', -]; diff --git a/packages/utils/src/webpack/selectors.js b/packages/utils/src/webpack/selectors.js new file mode 100644 index 0000000000..6bfe959f00 --- /dev/null +++ b/packages/utils/src/webpack/selectors.js @@ -0,0 +1,38 @@ +import { get, pick } from 'lodash'; + +import { SUMMARY_METRIC_PATHS } from './constants'; + +const getStatsMetrics = (job) => { + const data = get(job, 'metrics.webpack'); + const metrics = pick(data, SUMMARY_METRIC_PATHS); + + // Rename metric keys + return Object.entries(metrics).reduce((agg, [key, value]) => ({ + ...agg, + [`webpack.${key}`]: value, + }), {}); +}; + +const getSizeMetrics = (job) => { + const metrics = get(job, 'metrics.webpack.sizes', {}); + + // rename metric keys + return Object.entries(metrics).reduce((agg, [key, value]) => ({ + ...agg, + [`webpack.sizes.${key}`]: value, + }), {}); +}; + +const getAssetsMetrics = (job) => get(job, 'metrics.webpack.assets', {}); + +const getPackageMetrics = (job) => get(job, 'metrics.webpack.packages', {}); + +const getModulesMetrics = (job) => get(job, 'metrics.webpack.modules', {}); + +export const selectors = { + stats: getStatsMetrics, + sizes: getSizeMetrics, + assets: getAssetsMetrics, + packages: getPackageMetrics, + modules: getModulesMetrics, +};