diff --git a/packages/html-templates/src/app/__snapshots__/app.stories.storyshot b/packages/html-templates/src/app/__snapshots__/app.stories.storyshot index 4e6f05a92c..1400e5337a 100644 --- a/packages/html-templates/src/app/__snapshots__/app.stories.storyshot +++ b/packages/html-templates/src/app/__snapshots__/app.stories.storyshot @@ -72,6 +72,27 @@ exports[`Storyshots App default 1`] = ` }, "type": "error", }, + "newAssets": Object { + "data": Object { + "assets": Array [ + "assets/auth.js", + "assets/auth.css", + "assets/home.css", + "assets/home.js", + "assets/home~organization~project.css", + "assets/home~organization~project.js", + "assets/organization~project~setup.js", + "assets/organization~setup.js", + "assets/organization~setup.css", + "assets/runtime~main.js", + "assets/setup.css", + "assets/setup.js", + "index.html", + ], + "text": "Bundle introduced 13 new assets", + }, + "type": "warning", + }, "newPackages": Object { "changes": true, "data": Object { @@ -89802,6 +89823,40 @@ exports[`Storyshots App multiple baselines 1`] = ` }, "type": "error", }, + "newAssets": Object { + "data": Object { + "assets": Array [ + "404.html", + "android-chrome-192x192.png", + "android-chrome-512x512.png", + "apple-touch-icon.png", + "assets/auth.js", + "assets/auth.css", + "assets/home.css", + "assets/home.js", + "assets/home~organization~project.css", + "assets/home~organization~project.js", + "assets/organization~project~setup.js", + "assets/organization~setup.js", + "assets/organization~setup.css", + "assets/runtime~main.js", + "assets/setup.css", + "assets/setup.js", + "browserconfig.xml", + "favicon-16x16.png", + "favicon-32x32.png", + "favicon.ico", + "index.html", + "mstile-150x150.png", + "logo.svg", + "robots.txt", + "safari-pinned-tab.svg", + "site.webmanifest", + ], + "text": "Bundle introduced 26 new assets", + }, + "type": "warning", + }, "newPackages": Object { "changes": true, "data": Object { @@ -119618,6 +119673,27 @@ exports[`Storyshots App multiple baselines 1`] = ` }, "type": "error", }, + "newAssets": Object { + "data": Object { + "assets": Array [ + "404.html", + "android-chrome-192x192.png", + "android-chrome-512x512.png", + "apple-touch-icon.png", + "browserconfig.xml", + "favicon-16x16.png", + "favicon-32x32.png", + "favicon.ico", + "mstile-150x150.png", + "logo.svg", + "robots.txt", + "safari-pinned-tab.svg", + "site.webmanifest", + ], + "text": "Bundle introduced 13 new assets", + }, + "type": "warning", + }, "newPackages": Object { "changes": true, "data": Object { @@ -153049,6 +153125,27 @@ exports[`Storyshots App no baseline 1`] = ` }, "type": "error", }, + "newAssets": Object { + "data": Object { + "assets": Array [ + "assets/auth.js", + "assets/auth.css", + "assets/home.css", + "assets/home.js", + "assets/home~organization~project.css", + "assets/home~organization~project.js", + "assets/organization~project~setup.js", + "assets/organization~setup.js", + "assets/organization~setup.css", + "assets/runtime~main.js", + "assets/setup.css", + "assets/setup.js", + "index.html", + ], + "text": "Bundle introduced 13 new assets", + }, + "type": "warning", + }, "newPackages": Object { "changes": true, "data": Object { diff --git a/packages/utils/src/constants.ts b/packages/utils/src/constants.ts index c84ec2ca51..edd2291d1f 100644 --- a/packages/utils/src/constants.ts +++ b/packages/utils/src/constants.ts @@ -99,6 +99,10 @@ export interface JobInsightNewPackagesData { packages: Array; } +export interface JobInsightNewAssetsData { + assets: Array; +} + export type JobSummarySource = Record; export type JobSummary = JobSection; @@ -108,6 +112,7 @@ export interface JobInsights { duplicatePackages?: JobInsight; duplicatePackagesV3?: JobInsight; newPackages?: JobInsight; + newAssets?: JobInsight; }; } diff --git a/packages/utils/src/webpack/extract/__tests__/assets-new-insight.ts b/packages/utils/src/webpack/extract/__tests__/assets-new-insight.ts new file mode 100644 index 0000000000..176e63282f --- /dev/null +++ b/packages/utils/src/webpack/extract/__tests__/assets-new-insight.ts @@ -0,0 +1,130 @@ +import { extractAssetsNewInsight } from '../assets-new-insight'; + +describe('Webpack/extracts/extractAssetsNewInsight', () => { + test('should return null when there is no baseline', () => { + const actual = extractAssetsNewInsight(null, { + metrics: { + assets: { + './main.js': { + size: 100, + }, + }, + }, + }); + + expect(actual).toEqual(null); + }); + + test('should return null when there are no new assets', () => { + const actual = extractAssetsNewInsight( + null, + { + metrics: { + assets: { + './main.js': { + size: 100, + }, + }, + }, + }, + { + metrics: { + webpack: { + assets: { + './main.js': { + size: 100, + }, + }, + }, + }, + } as any, + ); + + expect(actual).toEqual(null); + }); + + test('should return insights when there is a new assets', () => { + const actual = extractAssetsNewInsight( + null, + { + metrics: { + assets: { + './main.js': { + size: 100, + }, + './main.css': { + size: 100, + }, + }, + }, + }, + { + metrics: { + webpack: { + assets: { + './main.js': { + size: 100, + }, + }, + }, + }, + } as any, + ); + + expect(actual).toEqual({ + insights: { + newAssets: { + type: 'warning', + data: { + text: 'Bundle introduced one new asset', + assets: ['./main.css'], + }, + }, + }, + }); + }); + + test('should return insights when there are new packages', () => { + const actual = extractAssetsNewInsight( + null, + { + metrics: { + assets: { + './main.js': { + size: 100, + }, + './main.css': { + size: 100, + }, + './logo.png': { + size: 100, + }, + }, + }, + }, + { + metrics: { + webpack: { + assets: { + './main.js': { + size: 100, + }, + }, + }, + }, + } as any, + ); + + expect(actual).toEqual({ + insights: { + newAssets: { + type: 'warning', + data: { + text: 'Bundle introduced 2 new assets', + assets: ['./main.css', './logo.png'], + }, + }, + }, + }); + }); +}); diff --git a/packages/utils/src/webpack/extract/assets-new-insight.ts b/packages/utils/src/webpack/extract/assets-new-insight.ts new file mode 100644 index 0000000000..c2f8f1a04c --- /dev/null +++ b/packages/utils/src/webpack/extract/assets-new-insight.ts @@ -0,0 +1,51 @@ +import { InsightType, Job, JobInsights } from '../../constants'; +import { Assets } from '../types'; + +const getAssetNames = (assets: Assets) => new Set(Object.keys(assets)); + +interface AssetsNewInsight { + insights?: { + newAssets: JobInsights['webpack']['newAssets']; + }; +} + +export const extractAssetsNewInsight = ( + _: any, + currentExtractedData: any, + baselineJob?: Job, +): AssetsNewInsight | null => { + const currentAssets = currentExtractedData.metrics?.assets as Assets; + const baselineAssets = baselineJob?.metrics?.webpack?.assets as Assets; + + if (!baselineAssets) { + return null; + } + + const currentAssetNames = getAssetNames(currentAssets); + const baselineAssetNames = getAssetNames(baselineAssets); + + const newAssets: Array = []; + currentAssetNames.forEach((assetName) => { + if (!baselineAssetNames.has(assetName)) { + newAssets.push(assetName); + } + }); + + if (newAssets.length === 0) { + return null; + } + + const text = `Bundle introduced ${newAssets.length > 1 ? `${newAssets.length} new assets` : 'one new asset' }`; + + return { + insights: { + newAssets: { + type: InsightType.WARNING, + data: { + text, + assets: newAssets, + }, + }, + }, + }; +}; diff --git a/packages/utils/src/webpack/extract/index.js b/packages/utils/src/webpack/extract/index.js index 7901e89a5e..46907eaca7 100644 --- a/packages/utils/src/webpack/extract/index.js +++ b/packages/utils/src/webpack/extract/index.js @@ -5,6 +5,7 @@ import { extractAssetsCacheInvalidation } from './assets-cache-invalidation'; import { extractAssetsChunkCount } from './assets-chunk-count'; import { extractAssetsCount } from './assets-count'; import { extractAssetsSize } from './assets-size'; +import { extractAssetsNewInsight } from './assets-new-insight'; import { extractAssetsSizeTotalInsight } from './assets-size-total-insight'; import { extractMeta } from './meta'; import { extractModules } from './modules'; @@ -19,6 +20,7 @@ const extractFns = [ extractAssetsChunkCount, extractAssetsCount, extractAssetsSize, + extractAssetsNewInsight, extractAssetsSizeTotalInsight, extractMeta, extractModules,