| | |
| | | const asyncLib = require("neo-async"); |
| | | const ChunkGraph = require("../ChunkGraph"); |
| | | const ModuleGraph = require("../ModuleGraph"); |
| | | const { JS_TYPE } = require("../ModuleSourceTypesConstants"); |
| | | const { JAVASCRIPT_TYPE } = require("../ModuleSourceTypeConstants"); |
| | | const { STAGE_DEFAULT } = require("../OptimizationStages"); |
| | | const HarmonyImportDependency = require("../dependencies/HarmonyImportDependency"); |
| | | const { compareModulesByIdentifier } = require("../util/comparators"); |
| | |
| | | /** @typedef {import("../RequestShortener")} RequestShortener */ |
| | | /** @typedef {import("../util/runtime").RuntimeSpec} RuntimeSpec */ |
| | | |
| | | /** @typedef {Module | ((requestShortener: RequestShortener) => string)} Problem */ |
| | | |
| | | /** |
| | | * Defines the statistics type used by this module. |
| | | * @typedef {object} Statistics |
| | | * @property {number} cached |
| | | * @property {number} alreadyInConfig |
| | |
| | | */ |
| | | |
| | | /** |
| | | * Format bailout reason. |
| | | * @param {string} msg message |
| | | * @returns {string} formatted message |
| | | */ |
| | |
| | | |
| | | class ModuleConcatenationPlugin { |
| | | /** |
| | | * Apply the plugin |
| | | * Applies the plugin by registering its hooks on the compiler. |
| | | * @param {Compiler} compiler the compiler instance |
| | | * @returns {void} |
| | | */ |
| | |
| | | const bailoutReasonMap = new Map(); |
| | | |
| | | /** |
| | | * Sets bailout reason. |
| | | * @param {Module} module the module |
| | | * @param {string | ((requestShortener: RequestShortener) => string)} reason the reason |
| | | */ |
| | |
| | | }; |
| | | |
| | | /** |
| | | * Sets inner bailout reason. |
| | | * @param {Module} module the module |
| | | * @param {string | ((requestShortener: RequestShortener) => string)} reason the reason |
| | | */ |
| | |
| | | }; |
| | | |
| | | /** |
| | | * Gets inner bailout reason. |
| | | * @param {Module} module the module |
| | | * @param {RequestShortener} requestShortener the request shortener |
| | | * @returns {string | ((requestShortener: RequestShortener) => string) | undefined} the reason |
| | |
| | | }; |
| | | |
| | | /** |
| | | * Format bailout warning. |
| | | * @param {Module} module the module |
| | | * @param {Module | ((requestShortener: RequestShortener) => string)} problem the problem |
| | | * @param {Problem} problem the problem |
| | | * @returns {(requestShortener: RequestShortener) => string} the reason |
| | | */ |
| | | const formatBailoutWarning = (module, problem) => (requestShortener) => { |
| | |
| | | "webpack.ModuleConcatenationPlugin" |
| | | ); |
| | | const { chunkGraph, moduleGraph } = compilation; |
| | | /** @type {Module[]} */ |
| | | const relevantModules = []; |
| | | /** @type {Set<Module>} */ |
| | | const possibleInners = new Set(); |
| | | const context = { |
| | | chunkGraph, |
| | |
| | | let statsEmptyConfigurations = 0; |
| | | |
| | | logger.time("find modules to concatenate"); |
| | | /** @type {ConcatConfiguration[]} */ |
| | | const concatConfigurations = []; |
| | | /** @type {Set<Module>} */ |
| | | const usedAsInner = new Set(); |
| | | for (const currentRoot of relevantModules) { |
| | | // when used by another configuration as inner: |
| | |
| | | // TODO reconsider that when it's only used in a different runtime |
| | | if (usedAsInner.has(currentRoot)) continue; |
| | | |
| | | /** @type {RuntimeSpec} */ |
| | | let chunkRuntime; |
| | | for (const r of chunkGraph.getModuleRuntimes(currentRoot)) { |
| | | chunkRuntime = mergeRuntimeOwned(chunkRuntime, r); |
| | |
| | | ); |
| | | |
| | | // cache failures to add modules |
| | | /** @type {Map<Module, Problem>} */ |
| | | const failureCache = new Map(); |
| | | |
| | | // potential optional import candidates |
| | |
| | | } |
| | | |
| | | for (const imp of candidates) { |
| | | /** @type {Set<Module>} */ |
| | | const impCandidates = new Set(); |
| | | const problem = this._tryToAdd( |
| | | compilation, |
| | |
| | | logger.time("sort concat configurations"); |
| | | concatConfigurations.sort((a, b) => b.modules.size - a.modules.size); |
| | | logger.timeEnd("sort concat configurations"); |
| | | /** @type {Set<Module>} */ |
| | | const usedModules = new Set(); |
| | | |
| | | logger.time("create concatenated modules"); |
| | |
| | | chunk, |
| | | m |
| | | ); |
| | | if (sourceTypes.size === 1) { |
| | | if ( |
| | | sourceTypes.size === 1 && |
| | | sourceTypes.has(JAVASCRIPT_TYPE) |
| | | ) { |
| | | chunkGraph.disconnectChunkAndModule(chunk, m); |
| | | } else { |
| | | const newSourceTypes = new Set(sourceTypes); |
| | | newSourceTypes.delete(JS_TYPE); |
| | | newSourceTypes.delete(JAVASCRIPT_TYPE); |
| | | chunkGraph.setChunkModuleSourceTypes( |
| | | chunk, |
| | | m, |
| | |
| | | } |
| | | |
| | | /** |
| | | * Returns the imported modules. |
| | | * @param {Compilation} compilation the compilation |
| | | * @param {Module} module the module to be added |
| | | * @param {RuntimeSpec} runtime the runtime scope |
| | |
| | | */ |
| | | _getImports(compilation, module, runtime) { |
| | | const moduleGraph = compilation.moduleGraph; |
| | | /** @type {Set<Module>} */ |
| | | const set = new Set(); |
| | | for (const dep of module.dependencies) { |
| | | // Get reference info only for harmony Dependencies |
| | |
| | | } |
| | | |
| | | /** |
| | | * Returns the problematic module. |
| | | * @param {Compilation} compilation webpack compilation |
| | | * @param {ConcatConfiguration} config concat configuration (will be modified when added) |
| | | * @param {Module} module the module to be added |
| | |
| | | * @param {RuntimeSpec} activeRuntime the runtime scope of the root module |
| | | * @param {Set<Module>} possibleModules modules that are candidates |
| | | * @param {Set<Module>} candidates list of potential candidates (will be added to) |
| | | * @param {Map<Module, Module | ((requestShortener: RequestShortener) => string)>} failureCache cache for problematic modules to be more performant |
| | | * @param {Map<Module, Problem>} failureCache cache for problematic modules to be more performant |
| | | * @param {ChunkGraph} chunkGraph the chunk graph |
| | | * @param {boolean} avoidMutateOnFailure avoid mutating the config when adding fails |
| | | * @param {Statistics} statistics gathering metrics |
| | | * @returns {null | Module | ((requestShortener: RequestShortener) => string)} the problematic module |
| | | * @returns {null | Problem} the problematic module |
| | | */ |
| | | _tryToAdd( |
| | | compilation, |
| | |
| | | ].filter((chunk) => !chunkGraph.isModuleInChunk(module, chunk)); |
| | | if (missingChunks.length > 0) { |
| | | /** |
| | | * Returns problem description. |
| | | * @param {RequestShortener} requestShortener request shortener |
| | | * @returns {string} problem description |
| | | */ |
| | |
| | | ); |
| | | if (activeNonModulesConnections.length > 0) { |
| | | /** |
| | | * Returns problem description. |
| | | * @param {RequestShortener} requestShortener request shortener |
| | | * @returns {string} problem description |
| | | */ |
| | | const problem = (requestShortener) => { |
| | | /** @type {Set<string>} */ |
| | | const importingExplanations = new Set( |
| | | activeNonModulesConnections |
| | | .map((c) => c.explanation) |
| | |
| | | if (chunkGraph.getNumberOfModuleChunks(originModule) === 0) continue; |
| | | |
| | | // We don't care for connections from other runtimes |
| | | /** @type {RuntimeSpec} */ |
| | | let originRuntime; |
| | | for (const r of chunkGraph.getModuleRuntimes(originModule)) { |
| | | originRuntime = mergeRuntimeOwned(originRuntime, r); |
| | |
| | | }); |
| | | if (otherChunkModules.length > 0) { |
| | | /** |
| | | * Returns problem description. |
| | | * @param {RequestShortener} requestShortener request shortener |
| | | * @returns {string} problem description |
| | | */ |
| | |
| | | } |
| | | if (nonHarmonyConnections.size > 0) { |
| | | /** |
| | | * Returns problem description. |
| | | * @param {RequestShortener} requestShortener request shortener |
| | | * @returns {string} problem description |
| | | */ |
| | |
| | | } |
| | | if (otherRuntimeConnections.length > 0) { |
| | | /** |
| | | * Returns problem description. |
| | | * @param {RequestShortener} requestShortener request shortener |
| | | * @returns {string} problem description |
| | | */ |
| | |
| | | } |
| | | } |
| | | |
| | | /** @type {undefined | number} */ |
| | | let backup; |
| | | if (avoidMutateOnFailure) { |
| | | backup = config.snapshot(); |
| | |
| | | } |
| | | } |
| | | |
| | | /** @typedef {Module | ((requestShortener: RequestShortener) => string)} Problem */ |
| | | /** @typedef {Map<Module, Problem>} Warnings */ |
| | | |
| | | class ConcatConfiguration { |
| | | /** |
| | | * Creates an instance of ConcatConfiguration. |
| | | * @param {Module} rootModule the root module |
| | | * @param {RuntimeSpec} runtime the runtime |
| | | */ |
| | | constructor(rootModule, runtime) { |
| | | /** @type {Module} */ |
| | | this.rootModule = rootModule; |
| | | /** @type {RuntimeSpec} */ |
| | | this.runtime = runtime; |
| | | /** @type {Set<Module>} */ |
| | | this.modules = new Set(); |
| | | this.modules.add(rootModule); |
| | | /** @type {Map<Module, Problem>} */ |
| | | /** @type {Warnings} */ |
| | | this.warnings = new Map(); |
| | | } |
| | | |
| | | /** |
| | | * Processes the provided module. |
| | | * @param {Module} module the module |
| | | */ |
| | | add(module) { |
| | |
| | | } |
| | | |
| | | /** |
| | | * Returns true, when the module is in the module set. |
| | | * @param {Module} module the module |
| | | * @returns {boolean} true, when the module is in the module set |
| | | */ |
| | |
| | | } |
| | | |
| | | /** |
| | | * Adds the provided module to the concat configuration. |
| | | * @param {Module} module the module |
| | | * @param {Problem} problem the problem |
| | | */ |
| | |
| | | } |
| | | |
| | | /** |
| | | * @returns {Map<Module, Problem>} warnings |
| | | * Gets warnings sorted. |
| | | * @returns {Warnings} warnings |
| | | */ |
| | | getWarningsSorted() { |
| | | return new Map( |
| | |
| | | } |
| | | |
| | | /** |
| | | * Returns modules as set. |
| | | * @returns {Set<Module>} modules as set |
| | | */ |
| | | getModules() { |
| | |
| | | } |
| | | |
| | | /** |
| | | * Processes the provided snapshot. |
| | | * @param {number} snapshot snapshot |
| | | */ |
| | | rollback(snapshot) { |