@statoscope/webpack-model
Advanced tools
Comparing version
import type { Size } from '@statoscope/stats-extension-compressed/dist/generator'; | ||
import type { Instance } from '@statoscope/stats-extension-package-info/dist/generator'; | ||
import Graph, { PathSolution } from '@statoscope/helpers/dist/graph'; | ||
import { Webpack } from '../webpack'; | ||
import { moduleNameResource, moduleReasonResource, moduleResource, nodeModule } from './module'; | ||
import { HandledCompilation, NormalizedAsset, NormalizedChunk, NormalizedCompilation, NormalizedFile, NormalizedModule, NormalizedPackage } from './normalize'; | ||
import { Node } from './modules-to-foam-tree'; | ||
import { HandledCompilation, ModuleGraphNodeData, NormalizedAsset, NormalizedChunk, NormalizedCompilation, NormalizedEntrypointItem, NormalizedFile, NormalizedModule, NormalizedPackage } from './normalize'; | ||
import { Node as FoamTreeNode } from './modules-to-foam-tree'; | ||
import ChunkID = Webpack.ChunkID; | ||
@@ -31,3 +32,6 @@ export declare type ResolvedStats = { | ||
statName(stat?: ResolvedStats | undefined): string; | ||
modulesToFoamTree(modules: NormalizedModule[], compressed?: boolean | undefined, hash?: string | undefined): Node; | ||
getModuleGraph(hash: string): Graph<ModuleGraphNodeData> | null; | ||
moduleGraph_getEntrypoints(module?: NormalizedModule | null | undefined, graph?: Graph<ModuleGraphNodeData> | undefined, entrypoints?: NormalizedEntrypointItem[] | undefined, max?: number): NormalizedEntrypointItem[]; | ||
moduleGraph_getPaths(from?: NormalizedModule | undefined, graph?: Graph<ModuleGraphNodeData> | undefined, to?: NormalizedModule | undefined, max?: number): PathSolution<ModuleGraphNodeData> | null; | ||
modulesToFoamTree(modules: NormalizedModule[], compressed?: boolean | undefined, hash?: string | undefined): FoamTreeNode; | ||
}; |
@@ -117,2 +117,49 @@ "use strict"; | ||
}, | ||
getModuleGraph(hash) { | ||
var _a, _b; | ||
return (_b = (_a = resolveCompilation(hash)) === null || _a === void 0 ? void 0 : _a.graph.module) !== null && _b !== void 0 ? _b : null; | ||
}, | ||
moduleGraph_getEntrypoints(module, graph, entrypoints, max = Infinity) { | ||
if (!module || !graph || !entrypoints) { | ||
return []; | ||
} | ||
const moduleNode = graph.getNode(module.name); | ||
if (!moduleNode) { | ||
return []; | ||
} | ||
let total = 0; | ||
return entrypoints.filter( | ||
// @ts-ignore | ||
(entry) => { | ||
var _a; | ||
if (total === max) { | ||
return false; | ||
} | ||
const entryModuleName = (_a = entry.data.dep) === null || _a === void 0 ? void 0 : _a.module.name; | ||
const entryModule = graph.getNode(entryModuleName); | ||
if (entryModule) { | ||
if (moduleNode === entryModule) { | ||
total++; | ||
return true; | ||
} | ||
const solution = graph.findPaths(moduleNode, entryModule, 1); | ||
if (solution.children.length) { | ||
total++; | ||
return true; | ||
} | ||
} | ||
return false; | ||
}); | ||
}, | ||
moduleGraph_getPaths(from, graph, to, max = Infinity) { | ||
if (!from || !to || !graph) { | ||
return null; | ||
} | ||
const fromNode = graph.getNode(from.name); | ||
const toNode = graph.getNode(to.name); | ||
if (!fromNode || !toNode) { | ||
return null; | ||
} | ||
return graph.findPaths(fromNode, toNode, max); | ||
}, | ||
modulesToFoamTree(modules, compressed, hash) { | ||
@@ -119,0 +166,0 @@ if (compressed && !hash) { |
import { StatsDescriptor } from '@statoscope/stats'; | ||
import { Extension } from '@statoscope/stats/spec/extension'; | ||
import { Resolver } from '@statoscope/helpers/dist/entity-resolver'; | ||
import Graph from '@statoscope/helpers/dist/graph'; | ||
import { Webpack } from '../webpack'; | ||
@@ -22,2 +23,3 @@ import { ValidationResult } from './validate'; | ||
assets: NormalizedAsset[]; | ||
dep?: NormalizedModuleDependency; | ||
}; | ||
@@ -30,6 +32,15 @@ export declare type NormalizedAsset = Omit<Webpack.Asset, 'chunks' | 'files'> & { | ||
resolvedModule: NormalizedModule | null; | ||
resolvedEntry?: NormalizedEntrypointItem | null; | ||
resolvedEntryName?: string | null; | ||
}; | ||
export declare type NormalizedReason = Webpack.Reason & { | ||
resolvedModule: NormalizedModule | null; | ||
resolvedEntry?: NormalizedEntrypointItem | null; | ||
resolvedEntryName?: string | null; | ||
}; | ||
export declare type NormalizedModuleDependency = { | ||
type: 'module'; | ||
module: NormalizedModule; | ||
reason: NormalizedReason; | ||
}; | ||
export declare type NormalizedModule = Omit<Webpack.Module, 'chunks' | 'reasons' | 'modules'> & { | ||
@@ -42,2 +53,3 @@ resolvedResource: string | null; | ||
modules: NormalizedModule[]; | ||
deps?: NormalizedModuleDependency[]; | ||
}; | ||
@@ -51,6 +63,6 @@ export declare type NormalizedPackage = { | ||
isRoot: boolean; | ||
reasons: { | ||
type: 'module'; | ||
reasons: Array<{ | ||
type: 'module' | 'entry'; | ||
data: NormalizedReason; | ||
}[]; | ||
}>; | ||
modules: NormalizedModule[]; | ||
@@ -100,2 +112,3 @@ version?: string; | ||
resolvePackage: Resolver<string, NormalizedPackage>; | ||
resolveEntrypoint: Resolver<string, NormalizedEntrypointItem>; | ||
resolveExtension: Resolver<string, NormalizedExtension<unknown, unknown> | null>; | ||
@@ -106,2 +119,5 @@ }; | ||
resolvers: CompilationResolvers; | ||
graph: { | ||
module: Graph<ModuleGraphNodeData>; | ||
}; | ||
file: NormalizedFile; | ||
@@ -115,1 +131,5 @@ }; | ||
export declare function handleRawFile(rawStatsFileDescriptor: RawStatsFileDescriptor): HandledStats; | ||
export declare type ModuleGraphNodeData = { | ||
module: NormalizedModule; | ||
entries?: NormalizedEntrypointItem[]; | ||
}; |
@@ -14,2 +14,3 @@ "use strict"; | ||
const package_json_2 = __importDefault(require("@statoscope/stats-extension-package-info/package.json")); | ||
const graph_1 = __importDefault(require("@statoscope/helpers/dist/graph")); | ||
const validate_1 = __importDefault(require("./validate")); | ||
@@ -75,2 +76,39 @@ const module_1 = require("./module"); | ||
exports.handleRawFile = handleRawFile; | ||
function buildGraph(compilation) { | ||
var _a; | ||
const moduleGraph = new graph_1.default(); | ||
const globalHandled = new Set(); | ||
for (const entry of compilation.entrypoints) { | ||
if ((_a = entry.data.dep) === null || _a === void 0 ? void 0 : _a.module) { | ||
handleModuleNode(moduleGraph, entry.data.dep.module); | ||
} | ||
} | ||
return { | ||
module: moduleGraph, | ||
}; | ||
function handleModuleNode(graph, module) { | ||
var _a, _b; | ||
if (globalHandled.has(module)) { | ||
return graph.getNode(module.name); | ||
} | ||
globalHandled.add(module); | ||
const entries = module.reasons | ||
.filter((r) => r.resolvedEntry) | ||
.map((r) => r.resolvedEntry); | ||
const node = (_a = graph.getNode(module.name)) !== null && _a !== void 0 ? _a : graph.makeNode(module.name, { module, entries }); | ||
const handled = new WeakSet(); | ||
for (const innerModule of module.modules) { | ||
handled.add(innerModule); | ||
node.addChild(handleModuleNode(graph, innerModule)); | ||
} | ||
for (const dep of (_b = module.deps) !== null && _b !== void 0 ? _b : []) { | ||
if (handled.has(dep.module)) { | ||
continue; | ||
} | ||
handled.add(dep.module); | ||
node.addChild(handleModuleNode(graph, dep.module)); | ||
} | ||
return node; | ||
} | ||
} | ||
function handleCompilation(compilation, file, parent) { | ||
@@ -108,2 +146,4 @@ var _a, _b; | ||
const resolveExtension = entity_resolver_1.default(extensions, (ext) => ext === null || ext === void 0 ? void 0 : ext.data.descriptor.name); | ||
normalized.entrypoints = prepareEntries(compilation, resolveChunk, resolveAsset); | ||
const resolveEntrypoint = entity_resolver_1.default(normalized.entrypoints, ({ name }) => name); | ||
const resolvers = { | ||
@@ -114,2 +154,3 @@ resolveModule, | ||
resolvePackage, | ||
resolveEntrypoint, | ||
resolveExtension, | ||
@@ -120,7 +161,10 @@ }; | ||
prepareAssets(compilation, resolvers); | ||
normalized.entrypoints = prepareEntries(compilation, resolvers); | ||
extractPackages(normalized, resolvers); | ||
const graph = buildGraph(normalized); | ||
return { | ||
data: normalized, | ||
resolvers, | ||
graph: { | ||
module: graph.module, | ||
}, | ||
file, | ||
@@ -154,3 +198,4 @@ }; | ||
} | ||
function prepareModule(module, { resolveChunk, resolveModule }) { | ||
function prepareModule(module, resolvers) { | ||
var _a, _b; | ||
// @ts-ignore | ||
@@ -162,2 +207,3 @@ if (module[exports.normalizedSymbol]) { | ||
module[exports.normalizedSymbol] = true; | ||
const { resolveChunk, resolveModule } = resolvers; | ||
module.resolvedResource = module_1.moduleResource(module); | ||
@@ -177,5 +223,22 @@ if (module.issuerPath) { | ||
module.reasons = module.reasons.filter((r) => r.moduleName !== module.name); | ||
module.reasons.forEach((r) => (r.resolvedModule = r.moduleName | ||
? resolveModule(r.moduleName) | ||
: null)); | ||
for (const reason of module.reasons) { | ||
normalizeReason(reason, resolvers); | ||
const resolvedModule = reason.resolvedModule; | ||
const resolvedEntry = reason.resolvedEntry; | ||
if (resolvedModule) { | ||
(_a = resolvedModule.deps) !== null && _a !== void 0 ? _a : (resolvedModule.deps = []); | ||
resolvedModule.deps.push({ | ||
type: 'module', | ||
module: module, | ||
reason: reason, | ||
}); | ||
} | ||
if (resolvedEntry) { | ||
resolvedEntry.data.dep = { | ||
type: 'module', | ||
module: (_b = reason.resolvedModule) !== null && _b !== void 0 ? _b : module, | ||
reason: reason, | ||
}; | ||
} | ||
} | ||
} | ||
@@ -186,2 +249,23 @@ else { | ||
} | ||
function normalizeReason(reason, { resolveEntrypoint, resolveModule }) { | ||
var _a; | ||
reason.resolvedModule = reason.moduleName | ||
? resolveModule(reason.moduleName) | ||
: null; | ||
if (/(?:.+ )?entry$/.test((_a = reason.type) !== null && _a !== void 0 ? _a : '')) { | ||
if (reason.loc) { | ||
let resolvedName = reason.loc; | ||
let resolved = resolveEntrypoint(resolvedName); | ||
if (!resolved) { | ||
// handle foo[0] for webpack 4 single entry | ||
resolvedName = reason.loc.slice(0, -3); | ||
resolved = resolveEntrypoint(resolvedName); | ||
} | ||
if (resolved) { | ||
reason.resolvedEntryName = resolvedName; | ||
reason.resolvedEntry = resolved; | ||
} | ||
} | ||
} | ||
} | ||
function prepareModules(compilation, resolvers) { | ||
@@ -195,2 +279,5 @@ for (const module of compilation.modules || []) { | ||
} | ||
else { | ||
module.modules = []; | ||
} | ||
} | ||
@@ -217,2 +304,5 @@ } | ||
} | ||
else { | ||
module.modules = []; | ||
} | ||
} | ||
@@ -287,3 +377,3 @@ } | ||
} | ||
function prepareEntries(compilation, { resolveChunk, resolveAsset }) { | ||
function prepareEntries(compilation, resolveChunk, resolveAsset) { | ||
const entrypoints = []; | ||
@@ -311,3 +401,3 @@ for (const name in compilation.entrypoints) { | ||
const extractModulePackages = (module) => { | ||
var _a, _b; | ||
var _a, _b, _c; | ||
const resource = module_1.moduleResource(module); | ||
@@ -344,4 +434,4 @@ if (!resource) { | ||
const instanceReasonsKeys = new Set(instance.reasons.map((reason) => { | ||
var _a; | ||
return buildReasonKey(reason.type, (_a = reason.data.moduleName) !== null && _a !== void 0 ? _a : 'unknown', reason.data.loc); | ||
var _a, _b; | ||
return buildReasonKey(reason.type, (_a = reason.data.moduleName) !== null && _a !== void 0 ? _a : 'unknown', (_b = reason.data.loc) !== null && _b !== void 0 ? _b : 'unknown'); | ||
})); | ||
@@ -354,3 +444,3 @@ for (const reason of module.reasons) { | ||
const reasonType = 'module'; | ||
const reasonKey = buildReasonKey(reasonType, (_b = reason.moduleName) !== null && _b !== void 0 ? _b : 'unknown', reason.loc); | ||
const reasonKey = buildReasonKey(reasonType, (_b = reason.moduleName) !== null && _b !== void 0 ? _b : 'unknown', (_c = reason.loc) !== null && _c !== void 0 ? _c : 'unknown'); | ||
if (!instanceReasonsKeys.has(reasonKey)) { | ||
@@ -371,2 +461,5 @@ instance.reasons.push({ type: reasonType, data: reason }); | ||
} | ||
else { | ||
module.modules = []; | ||
} | ||
} | ||
@@ -373,0 +466,0 @@ } |
{ | ||
"name": "@statoscope/webpack-model", | ||
"version": "5.5.1", | ||
"version": "5.6.0", | ||
"description": "This package contains helpers to process webpack stats", | ||
@@ -26,6 +26,6 @@ "main": "./dist/index.js", | ||
"@statoscope/extensions": "^5.5.1", | ||
"@statoscope/helpers": "^5.5.1", | ||
"@statoscope/helpers": "^5.6.0", | ||
"@statoscope/stats": "^5.3.0", | ||
"@statoscope/stats-extension-compressed": "^5.5.1", | ||
"@statoscope/stats-extension-package-info": "^5.5.1", | ||
"@statoscope/stats-extension-compressed": "^5.6.0", | ||
"@statoscope/stats-extension-package-info": "^5.6.0", | ||
"ajv": "^8.5.0", | ||
@@ -39,3 +39,3 @@ "jora": "^1.0.0-beta.5", | ||
}, | ||
"gitHead": "f89a3ff2fd4eb15c07c592b22e2dd228038de4bb" | ||
"gitHead": "08038bf4c32ec3c28b28ffee2dfb3dbe0526a630" | ||
} |
@@ -26,8 +26,9 @@ import { StatsDescriptor } from '@statoscope/stats'; | ||
type Reason = { | ||
type?: string; | ||
moduleName: string | null; | ||
loc: string; | ||
loc?: string; | ||
}; | ||
type Entrypoint = { | ||
name: string; | ||
name?: string; | ||
chunks?: Array<ChunkID | Chunk>; | ||
@@ -34,0 +35,0 @@ assets?: Array<string | File>; |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
82555
9.03%1349
7.66%23
-11.54%