add grouping of assets
This commit is contained in:
parent
bdeea6ec2f
commit
3ea9400505
|
@ -1861,6 +1861,10 @@ export interface StatsOptions {
|
|||
* Sort the assets by that field.
|
||||
*/
|
||||
assetsSort?: string;
|
||||
/**
|
||||
* Space to display assets (groups will be collapsed to fit this space).
|
||||
*/
|
||||
assetsSpace?: number;
|
||||
/**
|
||||
* Add built at time information.
|
||||
*/
|
||||
|
@ -1976,6 +1980,26 @@ export interface StatsOptions {
|
|||
* Suppress modules that match the specified filters. Filters can be Strings, RegExps, Booleans or Functions.
|
||||
*/
|
||||
excludeModules?: boolean | FilterTypes;
|
||||
/**
|
||||
* Group assets by how their are related to chunks.
|
||||
*/
|
||||
groupAssetsByChunk?: boolean;
|
||||
/**
|
||||
* Group assets by their extension.
|
||||
*/
|
||||
groupAssetsByExtension?: boolean;
|
||||
/**
|
||||
* Group assets by their asset info (immutable, development, hotModuleReplacement, etc).
|
||||
*/
|
||||
groupAssetsByInfo?: boolean;
|
||||
/**
|
||||
* Group assets by their path.
|
||||
*/
|
||||
groupAssetsByPath?: boolean;
|
||||
/**
|
||||
* Group assets by their status (emitted, compared for emit or cached).
|
||||
*/
|
||||
groupAssetsByStatus?: boolean;
|
||||
/**
|
||||
* Add the hash of the compilation.
|
||||
*/
|
||||
|
|
|
@ -38,6 +38,7 @@ const identifierUtils = require("../util/identifier");
|
|||
/** @typedef {import("../WebpackError")} WebpackError */
|
||||
/** @template T @typedef {import("../util/comparators").Comparator<T>} Comparator<T> */
|
||||
/** @typedef {import("../util/runtime").RuntimeSpec} RuntimeSpec */
|
||||
/** @typedef {import("../util/smartGrouping").GroupConfig<any, object>} GroupConfig */
|
||||
/** @typedef {import("./StatsFactory")} StatsFactory */
|
||||
|
||||
/** @typedef {Asset & { type: string, related: ExtendedAsset[] }} ExtendedAsset */
|
||||
|
@ -63,6 +64,11 @@ const identifierUtils = require("../util/identifier");
|
|||
* @property {string} chunkModulesSort
|
||||
* @property {string} nestedModulesSort
|
||||
* @property {string} assetsSort
|
||||
* @property {boolean} cachedAssets
|
||||
* @property {boolean} groupAssetsByStatus
|
||||
* @property {boolean} groupAssetsByPath
|
||||
* @property {boolean} groupAssetsByExtension
|
||||
* @property {number} assetsSpace
|
||||
* @property {Function[]} excludeAssets
|
||||
* @property {Function[]} excludeModules
|
||||
* @property {Function[]} warningsFilter
|
||||
|
@ -311,15 +317,12 @@ const SIMPLE_EXTRACTORS = {
|
|||
}
|
||||
}
|
||||
}
|
||||
object.assets = factory.create(`${type}.assets`, Array.from(assets), {
|
||||
...context,
|
||||
compilationFileToChunks,
|
||||
compilationAuxiliaryFileToChunks
|
||||
});
|
||||
object.filteredAssets = assets.size - object.assets.length;
|
||||
|
||||
object.assetsByChunkName = {};
|
||||
for (const asset of object.assets) {
|
||||
for (const name of asset.chunkNames) {
|
||||
for (const [file, chunks] of compilationFileToChunks) {
|
||||
for (const chunk of chunks) {
|
||||
const name = chunk.name;
|
||||
if (!name) continue;
|
||||
if (
|
||||
!Object.prototype.hasOwnProperty.call(
|
||||
object.assetsByChunkName,
|
||||
|
@ -328,9 +331,22 @@ const SIMPLE_EXTRACTORS = {
|
|||
) {
|
||||
object.assetsByChunkName[name] = [];
|
||||
}
|
||||
object.assetsByChunkName[name].push(asset.name);
|
||||
object.assetsByChunkName[name].push(file);
|
||||
}
|
||||
}
|
||||
|
||||
const groupedAssets = factory.create(
|
||||
`${type}.assets`,
|
||||
Array.from(assets),
|
||||
{
|
||||
...context,
|
||||
compilationFileToChunks,
|
||||
compilationAuxiliaryFileToChunks
|
||||
}
|
||||
);
|
||||
const limited = spaceLimited(groupedAssets, options.assetsSpace);
|
||||
object.assets = limited.children;
|
||||
object.filteredAssets = limited.filteredChildren;
|
||||
},
|
||||
chunks: (object, compilation, context, options, factory) => {
|
||||
const { type } = context;
|
||||
|
@ -560,6 +576,7 @@ const SIMPLE_EXTRACTORS = {
|
|||
object.comparedForEmit = compilation.comparedForEmitAssets.has(
|
||||
asset.name
|
||||
);
|
||||
object.cached = !object.emitted && !object.comparedForEmit;
|
||||
object.info = asset.info;
|
||||
object.filteredRelated = asset.related ? asset.related.length : undefined;
|
||||
},
|
||||
|
@ -1033,26 +1050,8 @@ const BASE_MODULES_FILTER = {
|
|||
}
|
||||
};
|
||||
|
||||
const ASSETS_FILTER = {
|
||||
excludeAssets: (asset, context, { excludeAssets }) => {
|
||||
const ident = asset.name;
|
||||
const excluded = excludeAssets.some(fn => fn(ident, asset));
|
||||
if (excluded) return false;
|
||||
},
|
||||
"!cachedAssets": (asset, { compilation }) => {
|
||||
if (
|
||||
!compilation.emittedAssets.has(asset.name) &&
|
||||
!compilation.comparedForEmitAssets.has(asset.name)
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/** @type {Record<string, Record<string, (thing: any, context: UsualContext, options: UsualOptions) => boolean | undefined>>} */
|
||||
const FILTER = {
|
||||
"compilation.assets": ASSETS_FILTER,
|
||||
"asset.related": ASSETS_FILTER,
|
||||
"compilation.modules": {
|
||||
excludeModules: EXCLUDE_MODULES_FILTER("module"),
|
||||
"!orphanModules": (module, { compilation: { chunkGraph } }) => {
|
||||
|
@ -1195,6 +1194,271 @@ const SORTERS = {
|
|||
}
|
||||
};
|
||||
|
||||
const getTotalSize = children => {
|
||||
let size = 0;
|
||||
for (const child of children) {
|
||||
size++;
|
||||
if (child.children) size += getTotalSize(child.children);
|
||||
}
|
||||
return size;
|
||||
};
|
||||
|
||||
const getTotalItems = children => {
|
||||
let count = 0;
|
||||
for (const child of children) {
|
||||
if (child.children) count += getTotalItems(child.children);
|
||||
else if (child.filteredChildren) count += child.filteredChildren;
|
||||
else count++;
|
||||
}
|
||||
return count;
|
||||
};
|
||||
|
||||
const collapse = children => {
|
||||
const newChildren = [];
|
||||
for (const child of children) {
|
||||
let filteredChildren = child.filteredChildren || 0;
|
||||
if (child.children) {
|
||||
filteredChildren += getTotalItems(child.children);
|
||||
}
|
||||
newChildren.push(
|
||||
filteredChildren
|
||||
? {
|
||||
...child,
|
||||
children: undefined,
|
||||
filteredChildren
|
||||
}
|
||||
: child
|
||||
);
|
||||
}
|
||||
return newChildren;
|
||||
};
|
||||
|
||||
const spaceLimited = (children, max) => {
|
||||
const groups = children.filter(c => c.children || c.filteredChildren);
|
||||
const groupSizes = groups.map(g =>
|
||||
g.children ? getTotalSize(g.children) + 1 : 1
|
||||
);
|
||||
const items = children.filter(c => !c.children && !c.filteredChildren);
|
||||
let groupsSize = groupSizes.reduce((a, b) => a + b, 0);
|
||||
if (groupsSize + items.length <= max) {
|
||||
// keep all
|
||||
return {
|
||||
children: groups.concat(items),
|
||||
filteredChildren: undefined
|
||||
};
|
||||
} else if (children.length < max) {
|
||||
// collapse some groups, keep items
|
||||
while (groupsSize + items.length > max) {
|
||||
const oversize = items.length + groupsSize - max;
|
||||
const maxGroupSize = Math.max(...groupSizes);
|
||||
for (let i = 0; i < groups.length; i++) {
|
||||
if (groupSizes[i] === maxGroupSize) {
|
||||
const group = groups[i];
|
||||
const limited = spaceLimited(
|
||||
group.children,
|
||||
groupSizes[i] - 1 - oversize / groups.length
|
||||
);
|
||||
groups[i] = {
|
||||
...group,
|
||||
children: limited.children,
|
||||
filteredChildren:
|
||||
(group.filteredChildren || 0) + limited.filteredChildren
|
||||
};
|
||||
const newSize = groups[i].children
|
||||
? getTotalSize(groups[i].children) + 1
|
||||
: 1;
|
||||
groupsSize -= groupSizes[i] - newSize;
|
||||
groupSizes[i] = newSize;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return {
|
||||
children: groups.concat(items),
|
||||
filteredChildren: undefined
|
||||
};
|
||||
} else if (children.length === max) {
|
||||
// collapse all groups and keep items
|
||||
return {
|
||||
children: collapse(groups).concat(items),
|
||||
filteredChildren: undefined
|
||||
};
|
||||
} else if (groups.length + 1 <= max) {
|
||||
// collapse all groups and items
|
||||
return {
|
||||
children: collapse(groups),
|
||||
filteredChildren: items.length
|
||||
};
|
||||
} else {
|
||||
// collapse complete group
|
||||
return {
|
||||
children: undefined,
|
||||
filteredChildren: getTotalItems(children)
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
const assetGroup = assets => {
|
||||
let size = 0;
|
||||
for (const asset of assets) {
|
||||
size += asset.size;
|
||||
}
|
||||
return {
|
||||
size
|
||||
};
|
||||
};
|
||||
|
||||
/** @type {Record<string, (groupConfigs: GroupConfig[], context: UsualContext, options: UsualOptions) => void>} */
|
||||
const ASSETS_GROUPERS = {
|
||||
_: (groupConfigs, context, options) => {
|
||||
const groupByFlag = (name, exclude, greedy) => {
|
||||
groupConfigs.push({
|
||||
getKeys: asset => {
|
||||
return asset[name] ? ["1"] : undefined;
|
||||
},
|
||||
getOptions: () => {
|
||||
return {
|
||||
groupChildren: !exclude,
|
||||
force: exclude,
|
||||
greedy
|
||||
};
|
||||
},
|
||||
createGroup: (key, children, assets) => {
|
||||
return exclude
|
||||
? {
|
||||
type: "assets by status",
|
||||
[name]: !!key,
|
||||
filteredChildren: assets.length,
|
||||
...assetGroup(assets)
|
||||
}
|
||||
: {
|
||||
type: "assets by status",
|
||||
[name]: !!key,
|
||||
children, //...spaceLimited(children, options.assetsSpace),
|
||||
...assetGroup(assets)
|
||||
};
|
||||
}
|
||||
});
|
||||
};
|
||||
const {
|
||||
groupAssetsByStatus,
|
||||
groupAssetsByPath,
|
||||
groupAssetsByExtension
|
||||
} = options;
|
||||
if (groupAssetsByStatus) {
|
||||
groupByFlag("emitted", false, true);
|
||||
groupByFlag("comparedForEmit", false, true);
|
||||
groupByFlag("isOverSizeLimit", false, true);
|
||||
}
|
||||
if (groupAssetsByStatus || !options.cachedAssets) {
|
||||
groupByFlag("cached", !options.cachedAssets, true);
|
||||
}
|
||||
if (groupAssetsByPath || groupAssetsByExtension) {
|
||||
groupConfigs.push({
|
||||
getKeys: asset => {
|
||||
const extensionMatch =
|
||||
groupAssetsByExtension && /(\.[^.]+)(?:\?.*|$)/.exec(asset.name);
|
||||
const extension = extensionMatch ? extensionMatch[1] : "";
|
||||
const pathMatch =
|
||||
groupAssetsByPath && /(.+)[/\\][^/\\]+(?:\?.*|$)/.exec(asset.name);
|
||||
const path = pathMatch ? pathMatch[1].split(/[/\\]/) : ["."];
|
||||
const keys = [];
|
||||
if (groupAssetsByPath) {
|
||||
keys.push(`${path.join("/")}/`);
|
||||
if (extension) keys.push(`${path.join("/")}/*${extension}`);
|
||||
path.pop();
|
||||
while (path.length > 0) {
|
||||
keys.push(`${path.join("/")}/`);
|
||||
if (extension) keys.push(`${path.join("/")}/**/*${extension}`);
|
||||
path.pop();
|
||||
}
|
||||
if (extension) keys.push(`**/*${extension}`);
|
||||
} else {
|
||||
if (extension) keys.push(`*${extension}`);
|
||||
}
|
||||
return keys;
|
||||
},
|
||||
createGroup: (key, children, assets) => {
|
||||
return {
|
||||
type: "assets by path",
|
||||
name: key,
|
||||
children, //...spaceLimited(children, options.assetsSpace),
|
||||
...assetGroup(assets)
|
||||
};
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
groupAssetsByInfo: (groupConfigs, context, options) => {
|
||||
const groupByAssetInfoFlag = name => {
|
||||
groupConfigs.push({
|
||||
getKeys: asset => {
|
||||
return asset.info && asset.info[name] ? ["1"] : undefined;
|
||||
},
|
||||
createGroup: (key, children, assets) => {
|
||||
return {
|
||||
type: "assets by info",
|
||||
info: {
|
||||
[name]: !!key
|
||||
},
|
||||
children, //...spaceLimited(children, options.assetsSpace),
|
||||
...assetGroup(assets)
|
||||
};
|
||||
}
|
||||
});
|
||||
};
|
||||
groupByAssetInfoFlag("immutable");
|
||||
groupByAssetInfoFlag("development");
|
||||
groupByAssetInfoFlag("hotModuleReplacement");
|
||||
},
|
||||
groupAssetsByChunk: (groupConfigs, context, options) => {
|
||||
const groupByNames = name => {
|
||||
groupConfigs.push({
|
||||
getKeys: asset => {
|
||||
return asset[name];
|
||||
},
|
||||
createGroup: (key, children, assets) => {
|
||||
return {
|
||||
type: "assets by chunk",
|
||||
[name]: [key],
|
||||
children, //...spaceLimited(children, options.assetsSpace),
|
||||
...assetGroup(assets)
|
||||
};
|
||||
}
|
||||
});
|
||||
};
|
||||
groupByNames("chunkNames");
|
||||
groupByNames("auxiliaryChunkNames");
|
||||
groupByNames("chunkIdHints");
|
||||
groupByNames("auxiliaryChunkIdHints");
|
||||
},
|
||||
excludeAssets: (groupConfigs, context, { excludeAssets }) => {
|
||||
groupConfigs.push({
|
||||
getKeys: asset => {
|
||||
const ident = asset.name;
|
||||
const excluded = excludeAssets.some(fn => fn(ident, asset));
|
||||
if (excluded) return ["excluded"];
|
||||
},
|
||||
getOptions: () => ({
|
||||
groupChildren: false,
|
||||
force: true,
|
||||
greedy: true
|
||||
}),
|
||||
createGroup: (key, assets) => ({
|
||||
type: "excluded assets",
|
||||
filteredChildren: assets.length,
|
||||
...assetGroup(assets)
|
||||
})
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/** @type {Record<string, Record<string, (groupConfigs: GroupConfig[], context: UsualContext, options: UsualOptions) => void>>} */
|
||||
const RESULT_GROUPERS = {
|
||||
"compilation.assets": ASSETS_GROUPERS,
|
||||
"asset.related": ASSETS_GROUPERS
|
||||
};
|
||||
|
||||
// remove a prefixed "!" that can be specified to reverse sort order
|
||||
const normalizeFieldKey = field => {
|
||||
if (field[0] === "!") {
|
||||
|
@ -1394,6 +1658,13 @@ class DefaultStatsFactoryPlugin {
|
|||
fn(comparators, ctx, options)
|
||||
);
|
||||
});
|
||||
iterateConfig(RESULT_GROUPERS, options, (hookFor, fn) => {
|
||||
stats.hooks.groupResults
|
||||
.for(hookFor)
|
||||
.tap("DefaultStatsFactoryPlugin", (groupConfigs, ctx) =>
|
||||
fn(groupConfigs, ctx, options)
|
||||
);
|
||||
});
|
||||
iterateConfig(RESULT_SORTERS, options, (hookFor, fn) => {
|
||||
stats.hooks.sortResults
|
||||
.for(hookFor)
|
||||
|
|
|
@ -94,6 +94,8 @@ const NAMED_PRESETS = {
|
|||
|
||||
const NORMAL_ON = ({ all }) => all !== false;
|
||||
const NORMAL_OFF = ({ all }) => all === true;
|
||||
const ON_FOR_TO_STRING = ({ all }, { forToString }) =>
|
||||
forToString ? all !== false : all === true;
|
||||
const OFF_FOR_TO_STRING = ({ all }, { forToString }) =>
|
||||
forToString ? all === true : all !== false;
|
||||
|
||||
|
@ -136,6 +138,12 @@ const DEFAULTS = {
|
|||
},
|
||||
nestedModules: OFF_FOR_TO_STRING,
|
||||
relatedAssets: OFF_FOR_TO_STRING,
|
||||
groupAssetsByStatus: ON_FOR_TO_STRING,
|
||||
groupAssetsByInfo: ON_FOR_TO_STRING,
|
||||
groupAssetsByPath: ON_FOR_TO_STRING,
|
||||
groupAssetsByExtension: ON_FOR_TO_STRING,
|
||||
groupAssetsByChunk: ON_FOR_TO_STRING,
|
||||
assetsSpace: (o, { forToString }) => (forToString ? 15 : Infinity),
|
||||
orphanModules: NORMAL_OFF,
|
||||
moduleAssets: OFF_FOR_TO_STRING,
|
||||
depth: OFF_FOR_TO_STRING,
|
||||
|
|
|
@ -127,11 +127,7 @@ const SIMPLE_PRINTERS = {
|
|||
: undefined,
|
||||
"compilation.filteredAssets": (filteredAssets, { compilation: { assets } }) =>
|
||||
filteredAssets > 0
|
||||
? `${
|
||||
assets && assets.length > 0
|
||||
? ` + ${filteredAssets} hidden`
|
||||
: filteredAssets
|
||||
} ${plural(filteredAssets, "asset", "assets")}`
|
||||
? `${filteredAssets} ${plural(filteredAssets, "asset", "assets")}`
|
||||
: undefined,
|
||||
"compilation.logging": (logging, context, printer) =>
|
||||
Array.isArray(logging)
|
||||
|
@ -155,6 +151,8 @@ const SIMPLE_PRINTERS = {
|
|||
emitted ? green(formatFlag("emitted")) : undefined,
|
||||
"asset.comparedForEmit": (comparedForEmit, { yellow, formatFlag }) =>
|
||||
comparedForEmit ? yellow(formatFlag("compared for emit")) : undefined,
|
||||
"asset.cached": (cached, { green, formatFlag }) =>
|
||||
cached ? green(formatFlag("cached")) : undefined,
|
||||
"asset.isOverSizeLimit": (isOverSizeLimit, { yellow, formatFlag }) =>
|
||||
isOverSizeLimit ? yellow(formatFlag("big")) : undefined,
|
||||
|
||||
|
@ -169,11 +167,15 @@ const SIMPLE_PRINTERS = {
|
|||
"asset.separator!": () => "\n",
|
||||
"asset.filteredRelated": (filteredRelated, { asset: { related } }) =>
|
||||
filteredRelated > 0
|
||||
? `${
|
||||
related && related.length > 0
|
||||
? ` + ${filteredRelated} hidden`
|
||||
: filteredRelated
|
||||
} ${plural(filteredRelated, "related asset", "related assets")}`
|
||||
? `${filteredRelated} related ${plural(
|
||||
filteredRelated,
|
||||
"asset",
|
||||
"assets"
|
||||
)}`
|
||||
: undefined,
|
||||
"asset.filteredChildren": (filteredChildren, { asset: { children } }) =>
|
||||
filteredChildren > 0
|
||||
? `${filteredChildren} ${plural(filteredChildren, "asset", "assets")}`
|
||||
: undefined,
|
||||
|
||||
assetChunk: (id, { formatChunkId }) => formatChunkId(id),
|
||||
|
@ -490,6 +492,7 @@ const ITEM_NAMES = {
|
|||
"compilation.logging[]": "loggingGroup",
|
||||
"compilation.children[]": "compilation",
|
||||
"asset.related[]": "asset",
|
||||
"asset.children[]": "asset",
|
||||
"asset.chunks[]": "assetChunk",
|
||||
"asset.auxiliaryChunks[]": "assetChunk",
|
||||
"asset.chunkNames[]": "assetChunkName",
|
||||
|
@ -562,6 +565,7 @@ const PREFERRED_ORDERS = {
|
|||
"auxiliaryChunks",
|
||||
"emitted",
|
||||
"comparedForEmit",
|
||||
"cached",
|
||||
"info",
|
||||
"isOverSizeLimit",
|
||||
"chunkNames",
|
||||
|
@ -569,6 +573,8 @@ const PREFERRED_ORDERS = {
|
|||
"chunkIdHints",
|
||||
"auxiliaryChunkIdHints",
|
||||
"related",
|
||||
"filteredRelated",
|
||||
"children",
|
||||
"filteredChildren"
|
||||
],
|
||||
"asset.info": ["immutable", "development", "hotModuleReplacement"],
|
||||
|
@ -833,7 +839,10 @@ const SIMPLE_ELEMENT_JOINERS = {
|
|||
asset: items =>
|
||||
joinExplicitNewLine(
|
||||
items.map(item => {
|
||||
if (item.element === "related" && item.content) {
|
||||
if (
|
||||
(item.element === "related" || item.element === "children") &&
|
||||
item.content
|
||||
) {
|
||||
return {
|
||||
content: `\n${item.content}\n`
|
||||
};
|
||||
|
|
|
@ -7,6 +7,9 @@
|
|||
|
||||
const { HookMap, SyncBailHook, SyncWaterfallHook } = require("tapable");
|
||||
const { concatComparators, keepOriginalOrder } = require("../util/comparators");
|
||||
const smartGrouping = require("../util/smartGrouping");
|
||||
|
||||
/** @typedef {import("../util/smartGrouping").GroupConfig<any, object>} GroupConfig */
|
||||
|
||||
class StatsFactory {
|
||||
constructor() {
|
||||
|
@ -25,6 +28,10 @@ class StatsFactory {
|
|||
filterSorted: new HookMap(
|
||||
() => new SyncBailHook(["item", "context", "index", "unfilteredIndex"])
|
||||
),
|
||||
/** @type {HookMap<SyncBailHook<[GroupConfig[], Object]>>} */
|
||||
groupResults: new HookMap(
|
||||
() => new SyncBailHook(["groupConfigs", "context"])
|
||||
),
|
||||
/** @type {HookMap<SyncBailHook<[(function(any, any): number)[], Object]>>} */
|
||||
sortResults: new HookMap(
|
||||
() => new SyncBailHook(["comparators", "context"])
|
||||
|
@ -151,7 +158,7 @@ class StatsFactory {
|
|||
);
|
||||
|
||||
// for each item
|
||||
const resultItems = items2.map((item, i) => {
|
||||
let resultItems = items2.map((item, i) => {
|
||||
const itemContext = {
|
||||
...context,
|
||||
_index: i
|
||||
|
@ -176,6 +183,15 @@ class StatsFactory {
|
|||
return itemFactory.create(innerType, item, itemContext);
|
||||
});
|
||||
|
||||
// group result items
|
||||
const groupConfigs = [];
|
||||
this._forEachLevel(this.hooks.groupResults, type, h =>
|
||||
h.call(groupConfigs, context)
|
||||
);
|
||||
if (groupConfigs.length > 0) {
|
||||
resultItems = smartGrouping(resultItems, groupConfigs);
|
||||
}
|
||||
|
||||
// sort result items
|
||||
const comparators2 = [];
|
||||
this._forEachLevel(this.hooks.sortResults, type, h =>
|
||||
|
|
|
@ -0,0 +1,161 @@
|
|||
/*
|
||||
MIT License http://www.opensource.org/licenses/mit-license.php
|
||||
Author Tobias Koppers @sokra
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* @typedef {Object} GroupOptions
|
||||
* @property {boolean=} groupChildren
|
||||
* @property {boolean=} force
|
||||
* @property {boolean=} greedy
|
||||
*/
|
||||
|
||||
/**
|
||||
* @template T
|
||||
* @template R
|
||||
* @typedef {Object} GroupConfig
|
||||
* @property {function(T): string[]} getKeys
|
||||
* @property {function(string, (R | T)[], T[]): R} createGroup
|
||||
* @property {function(string, T[]): GroupOptions=} getOptions
|
||||
*/
|
||||
|
||||
/**
|
||||
* @template T
|
||||
* @typedef {Object} ItemWithGroups
|
||||
* @property {T} item
|
||||
* @property {Set<string>} groups
|
||||
*/
|
||||
|
||||
/**
|
||||
* @template T
|
||||
* @template R
|
||||
* @param {T[]} items the list of items
|
||||
* @param {GroupConfig<T, R>[]} groupConfigs configuration
|
||||
* @returns {(R | T)[]} grouped items
|
||||
*/
|
||||
const smartGrouping = (items, groupConfigs) => {
|
||||
/** @type {Set<ItemWithGroups<T>>} */
|
||||
const itemsWithGroups = new Set();
|
||||
/** @type {Map<string, [GroupConfig<T, R>, string]>} */
|
||||
const groupConfigMap = new Map();
|
||||
for (const item of items) {
|
||||
const groups = new Set();
|
||||
for (let i = 0; i < groupConfigs.length; i++) {
|
||||
const groupConfig = groupConfigs[i];
|
||||
const keys = groupConfig.getKeys(item);
|
||||
if (keys) {
|
||||
for (const group of keys) {
|
||||
const fullGroup = `${i}:${group}`;
|
||||
if (!groupConfigMap.has(fullGroup)) {
|
||||
groupConfigMap.set(fullGroup, [groupConfig, group]);
|
||||
}
|
||||
groups.add(fullGroup);
|
||||
}
|
||||
}
|
||||
}
|
||||
itemsWithGroups.add({
|
||||
item,
|
||||
groups
|
||||
});
|
||||
}
|
||||
const alreadyGrouped = new Set();
|
||||
/**
|
||||
* @param {Set<ItemWithGroups<T>>} itemsWithGroups input items with groups
|
||||
* @returns {(T | R)[]} groups items
|
||||
*/
|
||||
const runGrouping = itemsWithGroups => {
|
||||
const totalSize = itemsWithGroups.size;
|
||||
/** @type {Map<string, Set<ItemWithGroups<T>>>} */
|
||||
const groupMap = new Map();
|
||||
for (const entry of itemsWithGroups) {
|
||||
for (const group of entry.groups) {
|
||||
if (alreadyGrouped.has(group)) continue;
|
||||
const list = groupMap.get(group);
|
||||
if (list === undefined) {
|
||||
groupMap.set(group, new Set([entry]));
|
||||
} else {
|
||||
list.add(entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
/** @type {Set<string>} */
|
||||
const usedGroups = new Set();
|
||||
/** @type {(T | R)[]} */
|
||||
const results = [];
|
||||
for (;;) {
|
||||
let bestGroup = undefined;
|
||||
let bestGroupSize = -1;
|
||||
let bestGroupItems = undefined;
|
||||
let bestGroupOptions = undefined;
|
||||
for (const [group, items] of groupMap) {
|
||||
const [groupConfig, groupKey] = groupConfigMap.get(group);
|
||||
const options =
|
||||
groupConfig.getOptions &&
|
||||
groupConfig.getOptions(
|
||||
groupKey,
|
||||
Array.from(items, ({ item }) => item)
|
||||
);
|
||||
if (items.size === 0) continue;
|
||||
const force = options && options.force;
|
||||
if (!force) {
|
||||
if (usedGroups.has(group)) continue;
|
||||
if (items.size <= 1 || totalSize - items.size <= 1) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
const greedy = options && options.greedy;
|
||||
let sizeValue = greedy
|
||||
? items.size
|
||||
: Math.min(items.size, totalSize - items.size);
|
||||
if (sizeValue > bestGroupSize) {
|
||||
bestGroup = group;
|
||||
bestGroupSize = sizeValue;
|
||||
bestGroupItems = items;
|
||||
bestGroupOptions = options;
|
||||
}
|
||||
}
|
||||
if (bestGroup === undefined) {
|
||||
break;
|
||||
}
|
||||
const items = new Set(bestGroupItems);
|
||||
for (const item of items) {
|
||||
itemsWithGroups.delete(item);
|
||||
// Remove all groups that items have from the map to not select them again
|
||||
for (const group of item.groups) {
|
||||
const list = groupMap.get(group);
|
||||
if (list !== undefined) list.delete(item);
|
||||
usedGroups.add(group);
|
||||
}
|
||||
}
|
||||
const idx = bestGroup.indexOf(":");
|
||||
const configKey = bestGroup.slice(0, idx);
|
||||
const key = bestGroup.slice(idx + 1);
|
||||
const groupConfig = groupConfigs[+configKey];
|
||||
const options = bestGroupOptions;
|
||||
|
||||
alreadyGrouped.add(bestGroup);
|
||||
const children =
|
||||
options && options.groupChildren === false
|
||||
? Array.from(items, ({ item }) => item)
|
||||
: runGrouping(items);
|
||||
alreadyGrouped.delete(bestGroup);
|
||||
|
||||
results.push(
|
||||
groupConfig.createGroup(
|
||||
key,
|
||||
children,
|
||||
Array.from(items, ({ item }) => item)
|
||||
)
|
||||
);
|
||||
}
|
||||
for (const { item } of itemsWithGroups) {
|
||||
results.push(item);
|
||||
}
|
||||
return results;
|
||||
};
|
||||
return runGrouping(itemsWithGroups);
|
||||
};
|
||||
|
||||
module.exports = smartGrouping;
|
|
@ -2964,6 +2964,10 @@
|
|||
"description": "Sort the assets by that field.",
|
||||
"type": "string"
|
||||
},
|
||||
"assetsSpace": {
|
||||
"description": "Space to display assets (groups will be collapsed to fit this space).",
|
||||
"type": "number"
|
||||
},
|
||||
"builtAt": {
|
||||
"description": "Add built at time information.",
|
||||
"type": "boolean"
|
||||
|
@ -3109,6 +3113,26 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
"groupAssetsByChunk": {
|
||||
"description": "Group assets by how their are related to chunks.",
|
||||
"type": "boolean"
|
||||
},
|
||||
"groupAssetsByExtension": {
|
||||
"description": "Group assets by their extension.",
|
||||
"type": "boolean"
|
||||
},
|
||||
"groupAssetsByInfo": {
|
||||
"description": "Group assets by their asset info (immutable, development, hotModuleReplacement, etc).",
|
||||
"type": "boolean"
|
||||
},
|
||||
"groupAssetsByPath": {
|
||||
"description": "Group assets by their path.",
|
||||
"type": "boolean"
|
||||
},
|
||||
"groupAssetsByStatus": {
|
||||
"description": "Group assets by their status (emitted, compared for emit or cached).",
|
||||
"type": "boolean"
|
||||
},
|
||||
"hash": {
|
||||
"description": "Add the hash of the compilation.",
|
||||
"type": "boolean"
|
||||
|
|
|
@ -180,6 +180,7 @@ describe("Stats", () => {
|
|||
Object {
|
||||
"auxiliaryChunkIdHints": Array [],
|
||||
"auxiliaryChunkNames": Array [],
|
||||
"cached": false,
|
||||
"chunkIdHints": Array [],
|
||||
"chunkNames": Array [
|
||||
"chunkB",
|
||||
|
@ -198,6 +199,7 @@ describe("Stats", () => {
|
|||
Object {
|
||||
"auxiliaryChunkIdHints": Array [],
|
||||
"auxiliaryChunkNames": Array [],
|
||||
"cached": false,
|
||||
"chunkIdHints": Array [],
|
||||
"chunkNames": Array [
|
||||
"entryA",
|
||||
|
@ -216,6 +218,7 @@ describe("Stats", () => {
|
|||
Object {
|
||||
"auxiliaryChunkIdHints": Array [],
|
||||
"auxiliaryChunkNames": Array [],
|
||||
"cached": false,
|
||||
"chunkIdHints": Array [],
|
||||
"chunkNames": Array [
|
||||
"entryB",
|
||||
|
@ -243,7 +246,7 @@ describe("Stats", () => {
|
|||
"entryB.js",
|
||||
],
|
||||
},
|
||||
"filteredAssets": 0,
|
||||
"filteredAssets": undefined,
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
|
|
@ -3889,6 +3889,19 @@ Object {
|
|||
"multiple": false,
|
||||
"simpleType": "string",
|
||||
},
|
||||
"stats-assets-space": Object {
|
||||
"configs": Array [
|
||||
Object {
|
||||
"description": "Space to display assets (groups will be collapsed to fit this space).",
|
||||
"multiple": false,
|
||||
"path": "stats.assetsSpace",
|
||||
"type": "number",
|
||||
},
|
||||
],
|
||||
"description": "Space to display assets (groups will be collapsed to fit this space).",
|
||||
"multiple": false,
|
||||
"simpleType": "number",
|
||||
},
|
||||
"stats-built-at": Object {
|
||||
"configs": Array [
|
||||
Object {
|
||||
|
@ -4284,6 +4297,71 @@ Object {
|
|||
"multiple": false,
|
||||
"simpleType": "boolean",
|
||||
},
|
||||
"stats-group-assets-by-chunk": Object {
|
||||
"configs": Array [
|
||||
Object {
|
||||
"description": "Group assets by how their are related to chunks.",
|
||||
"multiple": false,
|
||||
"path": "stats.groupAssetsByChunk",
|
||||
"type": "boolean",
|
||||
},
|
||||
],
|
||||
"description": "Group assets by how their are related to chunks.",
|
||||
"multiple": false,
|
||||
"simpleType": "boolean",
|
||||
},
|
||||
"stats-group-assets-by-extension": Object {
|
||||
"configs": Array [
|
||||
Object {
|
||||
"description": "Group assets by their extension.",
|
||||
"multiple": false,
|
||||
"path": "stats.groupAssetsByExtension",
|
||||
"type": "boolean",
|
||||
},
|
||||
],
|
||||
"description": "Group assets by their extension.",
|
||||
"multiple": false,
|
||||
"simpleType": "boolean",
|
||||
},
|
||||
"stats-group-assets-by-info": Object {
|
||||
"configs": Array [
|
||||
Object {
|
||||
"description": "Group assets by their asset info (immutable, development, hotModuleReplacement, etc).",
|
||||
"multiple": false,
|
||||
"path": "stats.groupAssetsByInfo",
|
||||
"type": "boolean",
|
||||
},
|
||||
],
|
||||
"description": "Group assets by their asset info (immutable, development, hotModuleReplacement, etc).",
|
||||
"multiple": false,
|
||||
"simpleType": "boolean",
|
||||
},
|
||||
"stats-group-assets-by-path": Object {
|
||||
"configs": Array [
|
||||
Object {
|
||||
"description": "Group assets by their path.",
|
||||
"multiple": false,
|
||||
"path": "stats.groupAssetsByPath",
|
||||
"type": "boolean",
|
||||
},
|
||||
],
|
||||
"description": "Group assets by their path.",
|
||||
"multiple": false,
|
||||
"simpleType": "boolean",
|
||||
},
|
||||
"stats-group-assets-by-status": Object {
|
||||
"configs": Array [
|
||||
Object {
|
||||
"description": "Group assets by their status (emitted, compared for emit or cached).",
|
||||
"multiple": false,
|
||||
"path": "stats.groupAssetsByStatus",
|
||||
"type": "boolean",
|
||||
},
|
||||
],
|
||||
"description": "Group assets by their status (emitted, compared for emit or cached).",
|
||||
"multiple": false,
|
||||
"simpleType": "boolean",
|
||||
},
|
||||
"stats-hash": Object {
|
||||
"configs": Array [
|
||||
Object {
|
||||
|
|
|
@ -787,7 +787,7 @@ exports[`StatsTestCases should print correct stats for dll-reference-plugin-issu
|
|||
"Hash: b838deba915153e63f86
|
||||
Time: X ms
|
||||
Built at: 1970-04-20 12:42:42
|
||||
1 asset
|
||||
assets by status 83 bytes [cached] 1 asset
|
||||
Entrypoint main = bundle.js
|
||||
./entry.js 29 bytes [built]
|
||||
|
||||
|
@ -823,8 +823,8 @@ exports[`StatsTestCases should print correct stats for exclude-with-loader 1`] =
|
|||
"Hash: 0f9eb63e65113c4a3960
|
||||
Time: X ms
|
||||
Built at: 1970-04-20 12:42:42
|
||||
excluded assets 34 bytes 1 asset
|
||||
asset bundle.js 3.73 KiB [emitted] (name: main)
|
||||
+ 1 hidden asset
|
||||
Entrypoint main = bundle.js (89245aae14d2d745f85a29195aa6ffc1.json)
|
||||
./index.js 77 bytes [built]
|
||||
./a.txt 42 bytes [built]
|
||||
|
@ -1020,8 +1020,9 @@ Child
|
|||
Hash: 79ce0ce957b373f01199
|
||||
Time: X ms
|
||||
Built at: 1970-04-20 12:42:42
|
||||
asset c-all-b_js-5d2ee8f74cbe1c7c24e8.js 502 bytes [emitted] [immutable] (id hint: all)
|
||||
asset c-all-c_js-3f22b3dd1aa1ecb5f45e.js 393 bytes [emitted] [immutable] (id hint: all)
|
||||
assets by chunk 895 bytes (id hint: all)
|
||||
asset c-all-c_js-3f22b3dd1aa1ecb5f45e.js 393 bytes [emitted] [immutable] (id hint: all)
|
||||
asset c-all-b_js-5d2ee8f74cbe1c7c24e8.js 502 bytes [emitted] [immutable] (id hint: all)
|
||||
asset c-main-3737497cd09f5bd99fe3.js 603 bytes [emitted] [immutable] (name: main)
|
||||
asset c-runtime~main-2769e1f5da93c44c8a70.js 12.4 KiB [emitted] [immutable] (name: runtime~main)
|
||||
asset c-vendors-node_modules_vendor_js-93fc2ac2d261c82b4448.js 185 bytes [emitted] [immutable] (id hint: vendors)
|
||||
|
@ -1228,11 +1229,13 @@ exports[`StatsTestCases should print correct stats for module-assets 1`] = `
|
|||
"Hash: 7ef32e0d65af21479a68
|
||||
Time: X ms
|
||||
Built at: 1970-04-20 12:42:42
|
||||
asset 1.png 21 KiB [emitted] (auxiliary name: a)
|
||||
asset 2.png 21 KiB [emitted] (auxiliary name: a, b)
|
||||
asset a.js 749 bytes [emitted] (name: a)
|
||||
asset b.js 567 bytes [emitted] (name: b)
|
||||
asset main.js 8.92 KiB [emitted] (name: main)
|
||||
assets by path ./*.js 10.2 KiB
|
||||
asset main.js 8.92 KiB [emitted] (name: main)
|
||||
asset a.js 749 bytes [emitted] (name: a)
|
||||
asset b.js 567 bytes [emitted] (name: b)
|
||||
assets by path ./*.png 42 KiB
|
||||
asset 1.png 21 KiB [emitted] (auxiliary name: a)
|
||||
asset 2.png 21 KiB [emitted] (auxiliary name: a, b)
|
||||
Entrypoint main = main.js
|
||||
Chunk Group a = a.js (1.png 2.png)
|
||||
Chunk Group b = b.js (2.png)
|
||||
|
@ -1387,7 +1390,7 @@ Entrypoint main = main.js
|
|||
exports[`StatsTestCases should print correct stats for module-trace-disabled-in-error 1`] = `
|
||||
"Time: X ms
|
||||
Built at: 1970-04-20 12:42:42
|
||||
1 asset
|
||||
assets by status 1.83 KiB [cached] 1 asset
|
||||
Entrypoint main = main.js
|
||||
./index.js 19 bytes [built]
|
||||
./inner.js 53 bytes [built]
|
||||
|
@ -1411,7 +1414,7 @@ You may need an appropriate loader to handle this file type, currently no loader
|
|||
exports[`StatsTestCases should print correct stats for module-trace-enabled-in-error 1`] = `
|
||||
"Time: X ms
|
||||
Built at: 1970-04-20 12:42:42
|
||||
1 asset
|
||||
assets by status 1.83 KiB [cached] 1 asset
|
||||
Entrypoint main = main.js
|
||||
./index.js 19 bytes [built]
|
||||
./inner.js 53 bytes [built]
|
||||
|
@ -1523,7 +1526,7 @@ exports[`StatsTestCases should print correct stats for no-emit-on-errors-plugin-
|
|||
"Hash: f140966bfd98188578d5
|
||||
Time: X ms
|
||||
Built at: 1970-04-20 12:42:42
|
||||
2 assets
|
||||
assets by status 108 bytes [cached] 2 assets
|
||||
Entrypoint main = bundle.js
|
||||
./index.js 1 bytes [built]
|
||||
|
||||
|
@ -1582,7 +1585,7 @@ chunk {753} (runtime: main) ac in ab.js (ac in ab) 1 bytes <{90}> >{284}< [rende
|
|||
`;
|
||||
|
||||
exports[`StatsTestCases should print correct stats for parse-error 1`] = `
|
||||
"1 asset
|
||||
"assets by status 1.53 KiB [cached] 1 asset
|
||||
Entrypoint main = main.js
|
||||
./index.js + 1 modules 30 bytes [built]
|
||||
./b.js 55 bytes [built] [failed] [1 error]
|
||||
|
@ -2323,11 +2326,12 @@ Child a-normal:
|
|||
Hash: dc13e801b7da230b06ce
|
||||
Time: X ms
|
||||
Built at: 1970-04-20 12:42:42
|
||||
asset 3cc8faad16137711c07e-3cc8fa.js 210 bytes [emitted] [immutable] [minimized] (name: main)
|
||||
asset 603191853c81e758567a-603191.js 2.09 KiB [emitted] [immutable] [minimized] (name: runtime~main)
|
||||
assets by path ./*.js 2.48 KiB
|
||||
asset 3cc8faad16137711c07e-3cc8fa.js 210 bytes [emitted] [immutable] [minimized] (name: main)
|
||||
asset 603191853c81e758567a-603191.js 2.09 KiB [emitted] [immutable] [minimized] (name: runtime~main)
|
||||
asset b6f77787a670e97d47b5-b6f777.js 193 bytes [emitted] [immutable] [minimized] (name: lazy)
|
||||
asset 7382fad5b015914e0811.jpg 5.89 KiB [emitted] [immutable] (auxiliary name: main)
|
||||
asset 89a353e9c515885abd8e.png 14.6 KiB [emitted] [immutable] (auxiliary name: lazy)
|
||||
asset b6f77787a670e97d47b5-b6f777.js 193 bytes [emitted] [immutable] [minimized] (name: lazy)
|
||||
Entrypoint main = 603191853c81e758567a-603191.js 3cc8faad16137711c07e-3cc8fa.js (7382fad5b015914e0811.jpg)
|
||||
./a/index.js 150 bytes [built]
|
||||
./a/file.jpg 42 bytes (javascript) 5.89 KiB (asset) [built]
|
||||
|
@ -2338,11 +2342,12 @@ Child b-normal:
|
|||
Hash: 5782ba854a23a6c889d0
|
||||
Time: X ms
|
||||
Built at: 1970-04-20 12:42:42
|
||||
asset 3cc8faad16137711c07e-3cc8fa.js 210 bytes [emitted] [immutable] [minimized] (name: main)
|
||||
asset 724d7409f0fb4e0b3145-724d74.js 2.09 KiB [emitted] [immutable] [minimized] (name: runtime~main)
|
||||
assets by path ./*.js 2.48 KiB
|
||||
asset 3cc8faad16137711c07e-3cc8fa.js 210 bytes [emitted] [immutable] [minimized] (name: main)
|
||||
asset 724d7409f0fb4e0b3145-724d74.js 2.09 KiB [emitted] [immutable] [minimized] (name: runtime~main)
|
||||
asset b6f77787a670e97d47b5-b6f777.js 193 bytes [emitted] [immutable] [minimized] (name: lazy)
|
||||
asset 7382fad5b015914e0811.jpg 5.89 KiB [emitted] [immutable] (auxiliary name: main)
|
||||
asset 89a353e9c515885abd8e.png 14.6 KiB [emitted] [immutable] (auxiliary name: lazy)
|
||||
asset b6f77787a670e97d47b5-b6f777.js 193 bytes [emitted] [immutable] [minimized] (name: lazy)
|
||||
Entrypoint main = 724d7409f0fb4e0b3145-724d74.js 3cc8faad16137711c07e-3cc8fa.js (7382fad5b015914e0811.jpg)
|
||||
./b/index.js 109 bytes [built]
|
||||
./b/file.jpg 42 bytes (javascript) 5.89 KiB (asset) [built]
|
||||
|
@ -2353,14 +2358,15 @@ Child a-source-map:
|
|||
Hash: dc13e801b7da230b06ce
|
||||
Time: X ms
|
||||
Built at: 1970-04-20 12:42:42
|
||||
asset 2d2b84d5cc58d8742e65-2d2b84.js 2.14 KiB [emitted] [immutable] [minimized] (name: runtime~main)
|
||||
sourceMap 2d2b84d5cc58d8742e65-2d2b84.js.map 12.6 KiB [emitted] [dev]
|
||||
assets by path ./*.js 2.65 KiB
|
||||
asset b8bfcec62cdd15c9a840-b8bfce.js 266 bytes [emitted] [immutable] [minimized] (name: main)
|
||||
sourceMap b8bfcec62cdd15c9a840-b8bfce.js.map 366 bytes [emitted] [dev]
|
||||
asset 2d2b84d5cc58d8742e65-2d2b84.js 2.14 KiB [emitted] [immutable] [minimized] (name: runtime~main)
|
||||
sourceMap 2d2b84d5cc58d8742e65-2d2b84.js.map 12.6 KiB [emitted] [dev]
|
||||
asset c7c0f8bb2e61b59a89f5-c7c0f8.js 249 bytes [emitted] [immutable] [minimized] (name: lazy)
|
||||
sourceMap c7c0f8bb2e61b59a89f5-c7c0f8.js.map 331 bytes [emitted] [dev]
|
||||
asset 7382fad5b015914e0811.jpg 5.89 KiB [emitted] [immutable] (auxiliary name: main)
|
||||
asset 89a353e9c515885abd8e.png 14.6 KiB [emitted] [immutable] (auxiliary name: lazy)
|
||||
asset b8bfcec62cdd15c9a840-b8bfce.js 266 bytes [emitted] [immutable] [minimized] (name: main)
|
||||
sourceMap b8bfcec62cdd15c9a840-b8bfce.js.map 366 bytes [emitted] [dev]
|
||||
asset c7c0f8bb2e61b59a89f5-c7c0f8.js 249 bytes [emitted] [immutable] [minimized] (name: lazy)
|
||||
sourceMap c7c0f8bb2e61b59a89f5-c7c0f8.js.map 331 bytes [emitted] [dev]
|
||||
Entrypoint main = 2d2b84d5cc58d8742e65-2d2b84.js b8bfcec62cdd15c9a840-b8bfce.js (608a3931b5c0c7b2c21f-608a39.js.map 7382fad5b015914e0811.jpg aff11f17e02d24be34cc-aff11f.js.map)
|
||||
./a/index.js 150 bytes [built]
|
||||
./a/file.jpg 42 bytes (javascript) 5.89 KiB (asset) [built]
|
||||
|
@ -2371,14 +2377,15 @@ Child b-source-map:
|
|||
Hash: 5782ba854a23a6c889d0
|
||||
Time: X ms
|
||||
Built at: 1970-04-20 12:42:42
|
||||
assets by path ./*.js 2.65 KiB
|
||||
asset b8bfcec62cdd15c9a840-b8bfce.js 266 bytes [emitted] [immutable] [minimized] (name: main)
|
||||
sourceMap b8bfcec62cdd15c9a840-b8bfce.js.map 323 bytes [emitted] [dev]
|
||||
asset ffe92bc2786746a99419-ffe92b.js 2.14 KiB [emitted] [immutable] [minimized] (name: runtime~main)
|
||||
sourceMap ffe92bc2786746a99419-ffe92b.js.map 12.6 KiB [emitted] [dev]
|
||||
asset c7c0f8bb2e61b59a89f5-c7c0f8.js 249 bytes [emitted] [immutable] [minimized] (name: lazy)
|
||||
sourceMap c7c0f8bb2e61b59a89f5-c7c0f8.js.map 327 bytes [emitted] [dev]
|
||||
asset 7382fad5b015914e0811.jpg 5.89 KiB [emitted] [immutable] (auxiliary name: main)
|
||||
asset 89a353e9c515885abd8e.png 14.6 KiB [emitted] [immutable] (auxiliary name: lazy)
|
||||
asset b8bfcec62cdd15c9a840-b8bfce.js 266 bytes [emitted] [immutable] [minimized] (name: main)
|
||||
sourceMap b8bfcec62cdd15c9a840-b8bfce.js.map 323 bytes [emitted] [dev]
|
||||
asset c7c0f8bb2e61b59a89f5-c7c0f8.js 249 bytes [emitted] [immutable] [minimized] (name: lazy)
|
||||
sourceMap c7c0f8bb2e61b59a89f5-c7c0f8.js.map 327 bytes [emitted] [dev]
|
||||
asset ffe92bc2786746a99419-ffe92b.js 2.14 KiB [emitted] [immutable] [minimized] (name: runtime~main)
|
||||
sourceMap ffe92bc2786746a99419-ffe92b.js.map 12.6 KiB [emitted] [dev]
|
||||
Entrypoint main = ffe92bc2786746a99419-ffe92b.js b8bfcec62cdd15c9a840-b8bfce.js (342ff4b0850c24f24b15-342ff4.js.map 6625d7a5b3c0dfc493c6-6625d7.js.map 7382fad5b015914e0811.jpg)
|
||||
./b/index.js 109 bytes [built]
|
||||
./b/file.jpg 42 bytes (javascript) 5.89 KiB (asset) [built]
|
||||
|
@ -2389,79 +2396,102 @@ Child b-source-map:
|
|||
|
||||
exports[`StatsTestCases should print correct stats for related-assets 1`] = `
|
||||
"Child default:
|
||||
asset default-chunk_js.css 73 bytes [emitted] 3 related assets
|
||||
asset default-chunk_js.js 1.11 KiB [emitted] 3 related assets
|
||||
asset default-main.css 69 bytes [emitted] (name: main) 3 related assets
|
||||
asset default-main.js 13.3 KiB [emitted] (name: main) 3 related assets
|
||||
assets by path ./*.css 142 bytes
|
||||
asset default-main.css 69 bytes [emitted] (name: main) 3 related assets
|
||||
asset default-chunk_js.css 73 bytes [emitted] 3 related assets
|
||||
assets by path ./*.js 14.4 KiB
|
||||
asset default-main.js 13.3 KiB [emitted] (name: main) 3 related assets
|
||||
asset default-chunk_js.js 1.11 KiB [emitted] 3 related assets
|
||||
Child relatedAssets:
|
||||
asset relatedAssets-chunk_js.css 79 bytes [emitted]
|
||||
compressed relatedAssets-chunk_js.css.br 79 bytes [emitted]
|
||||
compressed relatedAssets-chunk_js.css.gz 79 bytes [emitted]
|
||||
sourceMap relatedAssets-chunk_js.css.map 197 bytes [emitted] [dev]
|
||||
compressed relatedAssets-chunk_js.css.map.br 197 bytes [emitted]
|
||||
compressed relatedAssets-chunk_js.css.map.gz 197 bytes [emitted]
|
||||
asset relatedAssets-chunk_js.js 1.12 KiB [emitted]
|
||||
compressed relatedAssets-chunk_js.js.br 1.12 KiB [emitted]
|
||||
compressed relatedAssets-chunk_js.js.gz 1.12 KiB [emitted]
|
||||
sourceMap relatedAssets-chunk_js.js.map 295 bytes [emitted] [dev]
|
||||
compressed relatedAssets-chunk_js.js.map.br 295 bytes [emitted]
|
||||
compressed relatedAssets-chunk_js.js.map.gz 295 bytes [emitted]
|
||||
asset relatedAssets-main.css 75 bytes [emitted] (name: main)
|
||||
compressed relatedAssets-main.css.br 75 bytes [emitted]
|
||||
compressed relatedAssets-main.css.gz 75 bytes [emitted]
|
||||
sourceMap relatedAssets-main.css.map 187 bytes [emitted] [dev] (auxiliary name: main)
|
||||
compressed relatedAssets-main.css.map.br 187 bytes [emitted]
|
||||
compressed relatedAssets-main.css.map.gz 187 bytes [emitted]
|
||||
asset relatedAssets-main.js 13.3 KiB [emitted] (name: main)
|
||||
compressed relatedAssets-main.js.br 13.3 KiB [emitted]
|
||||
compressed relatedAssets-main.js.gz 13.3 KiB [emitted]
|
||||
sourceMap relatedAssets-main.js.map 11.3 KiB [emitted] [dev] (auxiliary name: main)
|
||||
compressed relatedAssets-main.js.map.br 11.3 KiB [emitted]
|
||||
compressed relatedAssets-main.js.map.gz 11.3 KiB [emitted]
|
||||
assets by path ./*.css 154 bytes
|
||||
asset relatedAssets-main.css 75 bytes [emitted] (name: main)
|
||||
compressed relatedAssets-main.css.br 75 bytes [emitted]
|
||||
compressed relatedAssets-main.css.gz 75 bytes [emitted]
|
||||
sourceMap relatedAssets-main.css.map 187 bytes [emitted] [dev] (auxiliary name: main)
|
||||
compressed relatedAssets-main.css.map.br 187 bytes [emitted]
|
||||
compressed relatedAssets-main.css.map.gz 187 bytes [emitted]
|
||||
asset relatedAssets-chunk_js.css 79 bytes [emitted]
|
||||
compressed relatedAssets-chunk_js.css.br 79 bytes [emitted]
|
||||
compressed relatedAssets-chunk_js.css.gz 79 bytes [emitted]
|
||||
sourceMap relatedAssets-chunk_js.css.map 197 bytes [emitted] [dev]
|
||||
compressed relatedAssets-chunk_js.css.map.br 197 bytes [emitted]
|
||||
compressed relatedAssets-chunk_js.css.map.gz 197 bytes [emitted]
|
||||
assets by path ./*.js 14.4 KiB
|
||||
asset relatedAssets-main.js 13.3 KiB [emitted] (name: main)
|
||||
compressed relatedAssets-main.js.br 13.3 KiB [emitted]
|
||||
compressed relatedAssets-main.js.gz 13.3 KiB [emitted]
|
||||
sourceMap relatedAssets-main.js.map 11.3 KiB [emitted] [dev] (auxiliary name: main)
|
||||
compressed relatedAssets-main.js.map.br 11.3 KiB [emitted]
|
||||
compressed relatedAssets-main.js.map.gz 11.3 KiB [emitted]
|
||||
asset relatedAssets-chunk_js.js 1.12 KiB [emitted]
|
||||
compressed relatedAssets-chunk_js.js.br 1.12 KiB [emitted]
|
||||
compressed relatedAssets-chunk_js.js.gz 1.12 KiB [emitted]
|
||||
sourceMap relatedAssets-chunk_js.js.map 295 bytes [emitted] [dev]
|
||||
compressed relatedAssets-chunk_js.js.map.br 295 bytes [emitted]
|
||||
compressed relatedAssets-chunk_js.js.map.gz 295 bytes [emitted]
|
||||
Child exclude1:
|
||||
asset exclude1-chunk_js.css 74 bytes [emitted]
|
||||
sourceMap exclude1-chunk_js.css.map 192 bytes [emitted] [dev] 2 related assets
|
||||
+ 2 hidden related assets
|
||||
asset exclude1-chunk_js.js 1.11 KiB [emitted]
|
||||
sourceMap exclude1-chunk_js.js.map 290 bytes [emitted] [dev] 2 related assets
|
||||
+ 2 hidden related assets
|
||||
asset exclude1-main.css 70 bytes [emitted] (name: main)
|
||||
sourceMap exclude1-main.css.map 182 bytes [emitted] [dev] (auxiliary name: main) 2 related assets
|
||||
+ 2 hidden related assets
|
||||
asset exclude1-main.js 13.3 KiB [emitted] (name: main)
|
||||
sourceMap exclude1-main.js.map 11.3 KiB [emitted] [dev] (auxiliary name: main) 2 related assets
|
||||
+ 2 hidden related assets
|
||||
assets by path ./*.css 144 bytes
|
||||
asset exclude1-main.css 70 bytes [emitted] (name: main)
|
||||
sourceMap exclude1-main.css.map 182 bytes [emitted] [dev] (auxiliary name: main)
|
||||
excluded assets 364 bytes 2 assets
|
||||
1 related asset
|
||||
excluded assets 140 bytes 2 assets
|
||||
1 related asset
|
||||
asset exclude1-chunk_js.css 74 bytes [emitted]
|
||||
sourceMap exclude1-chunk_js.css.map 192 bytes [emitted] [dev]
|
||||
excluded assets 384 bytes 2 assets
|
||||
1 related asset
|
||||
excluded assets 148 bytes 2 assets
|
||||
1 related asset
|
||||
assets by path ./*.js 14.4 KiB
|
||||
asset exclude1-main.js 13.3 KiB [emitted] (name: main)
|
||||
sourceMap exclude1-main.js.map 11.3 KiB [emitted] [dev] (auxiliary name: main)
|
||||
excluded assets 22.7 KiB 2 assets
|
||||
1 related asset
|
||||
excluded assets 26.6 KiB 2 assets
|
||||
1 related asset
|
||||
asset exclude1-chunk_js.js 1.11 KiB [emitted]
|
||||
sourceMap exclude1-chunk_js.js.map 290 bytes [emitted] [dev]
|
||||
excluded assets 580 bytes 2 assets
|
||||
1 related asset
|
||||
excluded assets 2.22 KiB 2 assets
|
||||
1 related asset
|
||||
Child exclude2:
|
||||
asset exclude2-chunk_js.css 74 bytes [emitted]
|
||||
compressed exclude2-chunk_js.css.br 74 bytes [emitted]
|
||||
compressed exclude2-chunk_js.css.gz 74 bytes [emitted]
|
||||
+ 1 hidden related asset
|
||||
asset exclude2-chunk_js.js 1.11 KiB [emitted]
|
||||
compressed exclude2-chunk_js.js.br 1.11 KiB [emitted]
|
||||
compressed exclude2-chunk_js.js.gz 1.11 KiB [emitted]
|
||||
+ 1 hidden related asset
|
||||
asset exclude2-main.css 70 bytes [emitted] (name: main)
|
||||
compressed exclude2-main.css.br 70 bytes [emitted]
|
||||
compressed exclude2-main.css.gz 70 bytes [emitted]
|
||||
+ 1 hidden related asset
|
||||
asset exclude2-main.js 13.3 KiB [emitted] (name: main)
|
||||
compressed exclude2-main.js.br 13.3 KiB [emitted]
|
||||
compressed exclude2-main.js.gz 13.3 KiB [emitted]
|
||||
+ 1 hidden related asset
|
||||
assets by path ./*.css 144 bytes
|
||||
asset exclude2-main.css 70 bytes [emitted] (name: main)
|
||||
compressed exclude2-main.css.br 70 bytes [emitted]
|
||||
compressed exclude2-main.css.gz 70 bytes [emitted]
|
||||
excluded assets 182 bytes 1 asset
|
||||
asset exclude2-chunk_js.css 74 bytes [emitted]
|
||||
compressed exclude2-chunk_js.css.br 74 bytes [emitted]
|
||||
compressed exclude2-chunk_js.css.gz 74 bytes [emitted]
|
||||
excluded assets 192 bytes 1 asset
|
||||
assets by path ./*.js 14.4 KiB
|
||||
asset exclude2-main.js 13.3 KiB [emitted] (name: main)
|
||||
compressed exclude2-main.js.br 13.3 KiB [emitted]
|
||||
compressed exclude2-main.js.gz 13.3 KiB [emitted]
|
||||
excluded assets 11.3 KiB 1 asset
|
||||
asset exclude2-chunk_js.js 1.11 KiB [emitted]
|
||||
compressed exclude2-chunk_js.js.br 1.11 KiB [emitted]
|
||||
compressed exclude2-chunk_js.js.gz 1.11 KiB [emitted]
|
||||
excluded assets 290 bytes 1 asset
|
||||
Child exclude3:
|
||||
asset exclude3-main.css 70 bytes [emitted] (name: main)
|
||||
compressed exclude3-main.css.br 70 bytes [emitted]
|
||||
compressed exclude3-main.css.gz 70 bytes [emitted]
|
||||
sourceMap exclude3-main.css.map 182 bytes [emitted] [dev] (auxiliary name: main)
|
||||
compressed exclude3-main.css.map.br 182 bytes [emitted]
|
||||
compressed exclude3-main.css.map.gz 182 bytes [emitted]
|
||||
asset exclude3-main.js 13.3 KiB [emitted] (name: main)
|
||||
compressed exclude3-main.js.br 13.3 KiB [emitted]
|
||||
compressed exclude3-main.js.gz 13.3 KiB [emitted]
|
||||
sourceMap exclude3-main.js.map 11.3 KiB [emitted] [dev] (auxiliary name: main)
|
||||
compressed exclude3-main.js.map.br 11.3 KiB [emitted]
|
||||
compressed exclude3-main.js.map.gz 11.3 KiB [emitted]
|
||||
+ 2 hidden assets"
|
||||
assets by path ./*.css 70 bytes
|
||||
excluded assets 74 bytes 1 asset
|
||||
asset exclude3-main.css 70 bytes [emitted] (name: main)
|
||||
compressed exclude3-main.css.br 70 bytes [emitted]
|
||||
compressed exclude3-main.css.gz 70 bytes [emitted]
|
||||
sourceMap exclude3-main.css.map 182 bytes [emitted] [dev] (auxiliary name: main)
|
||||
compressed exclude3-main.css.map.br 182 bytes [emitted]
|
||||
compressed exclude3-main.css.map.gz 182 bytes [emitted]
|
||||
assets by path ./*.js 13.3 KiB
|
||||
excluded assets 1.11 KiB 1 asset
|
||||
asset exclude3-main.js 13.3 KiB [emitted] (name: main)
|
||||
compressed exclude3-main.js.br 13.3 KiB [emitted]
|
||||
compressed exclude3-main.js.gz 13.3 KiB [emitted]
|
||||
sourceMap exclude3-main.js.map 11.3 KiB [emitted] [dev] (auxiliary name: main)
|
||||
compressed exclude3-main.js.map.br 11.3 KiB [emitted]
|
||||
compressed exclude3-main.js.map.gz 11.3 KiB [emitted]"
|
||||
`;
|
||||
|
||||
exports[`StatsTestCases should print correct stats for resolve-plugin-context 1`] = `
|
||||
|
@ -4204,18 +4234,20 @@ exports[`StatsTestCases should print correct stats for wasm-explorer-examples-sy
|
|||
"Hash: c96673e79f37716c681c
|
||||
Time: X ms
|
||||
Built at: 1970-04-20 12:42:42
|
||||
asset 230.bundle.js 242 bytes [emitted]
|
||||
asset 325.bundle.js 3.78 KiB [emitted]
|
||||
asset 32796a220f44b00723d7.module.wasm 156 bytes [emitted] [immutable]
|
||||
asset 526.bundle.js 364 bytes [emitted] (id hint: vendors)
|
||||
asset 52ce624dd5de9c91cd19.module.wasm 531 bytes [emitted] [immutable]
|
||||
asset 71ba3c2b7af4ee0e4b5c.module.wasm 120 bytes [emitted] [immutable]
|
||||
asset 780.bundle.js 569 bytes [emitted]
|
||||
asset 86f222634054d2a3b20f.module.wasm 154 bytes [emitted] [immutable]
|
||||
asset 986b1b3cbdd7749989ee.module.wasm 290 bytes [emitted] [immutable]
|
||||
asset 99.bundle.js 240 bytes [emitted]
|
||||
asset a938d40645ba21696ec8.module.wasm 154 bytes [emitted] [immutable]
|
||||
asset bundle.js 11.7 KiB [emitted] (name: main)
|
||||
assets by path ./*.js 16.8 KiB
|
||||
asset bundle.js 11.7 KiB [emitted] (name: main)
|
||||
asset 325.bundle.js 3.78 KiB [emitted]
|
||||
asset 526.bundle.js 364 bytes [emitted] (id hint: vendors)
|
||||
asset 230.bundle.js 242 bytes [emitted]
|
||||
asset 99.bundle.js 240 bytes [emitted]
|
||||
asset 780.bundle.js 569 bytes [emitted]
|
||||
assets by path ./*.wasm 1.37 KiB
|
||||
asset 71ba3c2b7af4ee0e4b5c.module.wasm 120 bytes [emitted] [immutable]
|
||||
asset a938d40645ba21696ec8.module.wasm 154 bytes [emitted] [immutable]
|
||||
asset 32796a220f44b00723d7.module.wasm 156 bytes [emitted] [immutable]
|
||||
asset 52ce624dd5de9c91cd19.module.wasm 531 bytes [emitted] [immutable]
|
||||
asset 86f222634054d2a3b20f.module.wasm 154 bytes [emitted] [immutable]
|
||||
asset 986b1b3cbdd7749989ee.module.wasm 290 bytes [emitted] [immutable]
|
||||
Entrypoint main = bundle.js
|
||||
chunk (runtime: main) 99.bundle.js 50 bytes (javascript) 531 bytes (webassembly) [rendered]
|
||||
./duff.wasm 50 bytes (javascript) 531 bytes (webassembly) [built]
|
||||
|
|
|
@ -0,0 +1,84 @@
|
|||
"use strict";
|
||||
|
||||
const smartGrouping = require("../lib/util/smartGrouping");
|
||||
|
||||
describe("util/smartGrouping", () => {
|
||||
it("should group correctly", () => {
|
||||
const groupConfigs = [
|
||||
{
|
||||
getKeys(item) {
|
||||
return item.match(/\d+/g);
|
||||
},
|
||||
createGroup(key, items) {
|
||||
return {
|
||||
name: `has number ${key}`,
|
||||
items
|
||||
};
|
||||
}
|
||||
},
|
||||
{
|
||||
getKeys(item) {
|
||||
return item.match(/\w+/g);
|
||||
},
|
||||
createGroup(key, items) {
|
||||
return {
|
||||
name: `has word ${key}`,
|
||||
items
|
||||
};
|
||||
}
|
||||
}
|
||||
];
|
||||
expect(
|
||||
smartGrouping(
|
||||
[
|
||||
"hello world a",
|
||||
"hello world b 2",
|
||||
"hello world c",
|
||||
"hello world d",
|
||||
"hello test",
|
||||
"hello more test",
|
||||
"more test",
|
||||
"more tests",
|
||||
"1 2 3",
|
||||
"2 3 4",
|
||||
"3 4 5"
|
||||
],
|
||||
groupConfigs
|
||||
)
|
||||
).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
Object {
|
||||
"items": Array [
|
||||
Object {
|
||||
"items": Array [
|
||||
"hello world a",
|
||||
"hello world b 2",
|
||||
"hello world c",
|
||||
"hello world d",
|
||||
],
|
||||
"name": "has word world",
|
||||
},
|
||||
Object {
|
||||
"items": Array [
|
||||
"hello test",
|
||||
"hello more test",
|
||||
],
|
||||
"name": "has word test",
|
||||
},
|
||||
],
|
||||
"name": "has word hello",
|
||||
},
|
||||
Object {
|
||||
"items": Array [
|
||||
"1 2 3",
|
||||
"2 3 4",
|
||||
"3 4 5",
|
||||
],
|
||||
"name": "has number 3",
|
||||
},
|
||||
"more test",
|
||||
"more tests",
|
||||
]
|
||||
`);
|
||||
});
|
||||
});
|
|
@ -3195,6 +3195,16 @@ declare class Generator {
|
|||
updateHash(hash: Hash, __1: UpdateHashContextGenerator): void;
|
||||
static byType(map?: any): ByTypeGenerator;
|
||||
}
|
||||
declare interface GroupConfig<T, R> {
|
||||
getKeys: (arg0: T) => string[];
|
||||
createGroup: (arg0: string, arg1: (T | R)[], arg2: T[]) => R;
|
||||
getOptions?: (arg0: string, arg1: T[]) => GroupOptions;
|
||||
}
|
||||
declare interface GroupOptions {
|
||||
groupChildren?: boolean;
|
||||
force?: boolean;
|
||||
greedy?: boolean;
|
||||
}
|
||||
declare interface HMRJavascriptParserHooks {
|
||||
hotAcceptCallback: SyncBailHook<[any, string[]], void>;
|
||||
hotAcceptWithoutCallback: SyncBailHook<[any, string[]], void>;
|
||||
|
@ -8227,6 +8237,7 @@ declare abstract class StatsFactory {
|
|||
SyncBailHook<[((arg0?: any, arg1?: any) => number)[], any], any>
|
||||
>;
|
||||
filterSorted: HookMap<SyncBailHook<[any, any, number, number], any>>;
|
||||
groupResults: HookMap<SyncBailHook<[GroupConfig<any, any>[], any], any>>;
|
||||
sortResults: HookMap<
|
||||
SyncBailHook<[((arg0?: any, arg1?: any) => number)[], any], any>
|
||||
>;
|
||||
|
@ -8258,6 +8269,11 @@ declare interface StatsOptions {
|
|||
*/
|
||||
assetsSort?: string;
|
||||
|
||||
/**
|
||||
* Space to display assets (groups will be collapsed to fit this space).
|
||||
*/
|
||||
assetsSpace?: number;
|
||||
|
||||
/**
|
||||
* Add built at time information.
|
||||
*/
|
||||
|
@ -8405,6 +8421,31 @@ declare interface StatsOptions {
|
|||
| FilterItemTypes[]
|
||||
| ((value: string) => boolean);
|
||||
|
||||
/**
|
||||
* Group assets by how their are related to chunks.
|
||||
*/
|
||||
groupAssetsByChunk?: boolean;
|
||||
|
||||
/**
|
||||
* Group assets by their extension.
|
||||
*/
|
||||
groupAssetsByExtension?: boolean;
|
||||
|
||||
/**
|
||||
* Group assets by their asset info (immutable, development, hotModuleReplacement, etc).
|
||||
*/
|
||||
groupAssetsByInfo?: boolean;
|
||||
|
||||
/**
|
||||
* Group assets by their path.
|
||||
*/
|
||||
groupAssetsByPath?: boolean;
|
||||
|
||||
/**
|
||||
* Group assets by their status (emitted, compared for emit or cached).
|
||||
*/
|
||||
groupAssetsByStatus?: boolean;
|
||||
|
||||
/**
|
||||
* Add the hash of the compilation.
|
||||
*/
|
||||
|
|
Loading…
Reference in New Issue