From 5a78e96dc9952fc1e2b48cbd6d33260c960bb275 Mon Sep 17 00:00:00 2001 From: Tobias Koppers Date: Tue, 21 Aug 2018 16:15:48 +0200 Subject: [PATCH] add backward-compat layer for ModuleGraph and ChunkGraph --- lib/Chunk.js | 165 +++++++++++++++++++++- lib/ChunkGraph.js | 102 ++++++++++++- lib/Compilation.js | 7 +- lib/Module.js | 121 +++++++++++++++- lib/ModuleGraph.js | 48 +++++++ lib/optimize/ModuleConcatenationPlugin.js | 4 + 6 files changed, 440 insertions(+), 7 deletions(-) diff --git a/lib/Chunk.js b/lib/Chunk.js index 9470c3a4a..80d5a77d9 100644 --- a/lib/Chunk.js +++ b/lib/Chunk.js @@ -5,13 +5,13 @@ "use strict"; +const ChunkGraph = require("./ChunkGraph"); const Entrypoint = require("./Entrypoint"); const { intersect } = require("./util/SetHelpers"); const SortableSet = require("./util/SortableSet"); const { compareModulesById } = require("./util/comparators"); /** @typedef {import("webpack-sources").Source} Source */ -/** @typedef {import("./ChunkGraph")} ChunkGraph */ /** @typedef {import("./ChunkGroup")} ChunkGroup */ /** @typedef {import("./Compilation")} Compilation */ /** @typedef {import("./Module")} Module */ @@ -89,6 +89,169 @@ class Chunk { this.removedModules = undefined; } + // TODO remove in webpack 6 + // BACKWARD-COMPAT START + get entryModule() { + const entryModules = Array.from( + ChunkGraph.getChunkGraphForChunk( + this, + "Chunk.entryModule" + ).getChunkEntryModulesIterable(this) + ); + if (entryModules.length === 0) { + return undefined; + } else if (entryModules.length === 1) { + return entryModules[0]; + } else { + throw new Error( + "Module.entryModule: Multiple entry modules are not supported by the deprecated API (Use the new ChunkGroup API)" + ); + } + } + + hasEntryModule() { + return ( + ChunkGraph.getChunkGraphForChunk( + this, + "Chunk.hasEntryModule" + ).getNumberOfEntryModules(this) > 0 + ); + } + + addModule(module) { + return ChunkGraph.getChunkGraphForChunk( + this, + "Chunk.addModule" + ).connectChunkAndModule(this, module); + } + + removeModule(module) { + return ChunkGraph.getChunkGraphForChunk( + this, + "Chunk.removeModule" + ).disconnectChunkAndModule(this, module); + } + + getNumberOfModules() { + return ChunkGraph.getChunkGraphForChunk( + this, + "Chunk.getNumberOfModules" + ).getNumberOfChunkModules(this); + } + + get modulesIterable() { + const chunkGraph = ChunkGraph.getChunkGraphForChunk( + this, + "Chunk.modulesIterable" + ); + return chunkGraph.getOrderedChunkModulesIterable( + this, + compareModulesById(chunkGraph._moduleGraph) + ); + } + + compareTo(otherChunk) { + const chunkGraph = ChunkGraph.getChunkGraphForChunk( + this, + "Chunk.compareTo" + ); + return chunkGraph.compareChunks(chunkGraph._moduleGraph, this, otherChunk); + } + + containsModule(module) { + return ChunkGraph.getChunkGraphForChunk( + this, + "Chunk.containsModule" + ).isModuleInChunk(module, this); + } + + getModules() { + return ChunkGraph.getChunkGraphForChunk( + this, + "Chunk.getModules" + ).getChunkModules(this); + } + + remove() { + const chunkGraph = ChunkGraph.getChunkGraphForChunk(this, "Chunk.remove"); + chunkGraph.disconnectChunk(this); + this.disconnectFromGroups(); + } + + moveModule(module, otherChunk) { + const chunkGraph = ChunkGraph.getChunkGraphForChunk( + this, + "Chunk.moveModule" + ); + chunkGraph.disconnectChunkAndModule(this, module); + chunkGraph.connectChunkAndModule(otherChunk, module); + } + + integrate(otherChunk) { + const chunkGraph = ChunkGraph.getChunkGraphForChunk( + this, + "Chunk.integrate" + ); + if (!chunkGraph.canChunksBeIntegrated(this, otherChunk)) return false; + chunkGraph.integrateChunks(this, otherChunk); + return true; + } + + canBeIntegrated(otherChunk) { + const chunkGraph = ChunkGraph.getChunkGraphForChunk( + this, + "Chunk.canBeIntegrated" + ); + return chunkGraph.canChunksBeIntegrated(this, otherChunk); + } + + isEmpty() { + const chunkGraph = ChunkGraph.getChunkGraphForChunk(this, "Chunk.isEmpty"); + return chunkGraph.getNumberOfChunkModules(this) === 0; + } + + modulesSize() { + const chunkGraph = ChunkGraph.getChunkGraphForChunk( + this, + "Chunk.modulesSize" + ); + return chunkGraph.getChunkModulesSize(this); + } + + size(options) { + const chunkGraph = ChunkGraph.getChunkGraphForChunk(this, "Chunk.size"); + return chunkGraph.getChunkSize(this, options); + } + + integratedSize(otherChunk, options) { + const chunkGraph = ChunkGraph.getChunkGraphForChunk( + this, + "Chunk.integratedSize" + ); + return chunkGraph.getIntegratedChunksSize(this, otherChunk, options); + } + + getChunkModuleMaps(filterFn) { + const chunkGraph = ChunkGraph.getChunkGraphForChunk( + this, + "Chunk.getChunkModuleMaps" + ); + return chunkGraph.getChunkModuleMaps( + chunkGraph._moduleGraph, + this, + filterFn + ); + } + + hasModuleInGraph(filterFn, filterChunkFn) { + const chunkGraph = ChunkGraph.getChunkGraphForChunk( + this, + "Chunk.hasModuleInGraph" + ); + return chunkGraph.hasModuleInGraph(this, filterFn, filterChunkFn); + } + // BACKWARD-COMPAT END + /** * @returns {boolean} whether or not the Chunk will have a runtime */ diff --git a/lib/ChunkGraph.js b/lib/ChunkGraph.js index 6bad5e847..3996a6078 100644 --- a/lib/ChunkGraph.js +++ b/lib/ChunkGraph.js @@ -5,6 +5,7 @@ "use strict"; +const util = require("util"); const SortableSet = require("./util/SortableSet"); const { compareModulesById } = require("./util/comparators"); @@ -86,11 +87,16 @@ class ChunkGraphChunk { } class ChunkGraph { - constructor() { + /** + * @param {ModuleGraph} moduleGraph the module graph + */ + constructor(moduleGraph) { /** @private @type {WeakMap} */ this._modules = new WeakMap(); /** @private @type {WeakMap} */ this._chunks = new WeakMap(); + /** @private @type {ModuleGraph} */ + this._moduleGraph = moduleGraph; } /** @@ -669,6 +675,100 @@ class ChunkGraph { const cgc = this._getChunkGraphChunk(chunk); return cgc.entryModules; } + + // TODO remove in webpack 6 + /** + * @param {Module} module the module + * @param {string} deprecateMessage message for the deprecation message + * @returns {ChunkGraph} the chunk graph + */ + static getChunkGraphForModule(module, deprecateMessage) { + const fn = deprecateGetChunkGraphForModuleMap.get(deprecateMessage); + if (fn) return fn(module); + const newFn = util.deprecate( + /** + * @param {Module} module the module + * @returns {ChunkGraph} the chunk graph + */ + module => { + const chunkGraph = chunkGraphForModuleMap.get(module); + if (!chunkGraph) + throw new Error( + deprecateMessage + + ": There was no ChunkGraph assigned to the Module for backward-compat (Use the new API)" + ); + return chunkGraph; + }, + deprecateMessage + ": Use new ChunkGraph API" + ); + deprecateGetChunkGraphForModuleMap.set(deprecateMessage, newFn); + return newFn(module); + } + + // TODO remove in webpack 6 + /** + * @param {Module} module the module + * @param {ChunkGraph} chunkGraph the chunk graph + * @returns {void} + */ + static setChunkGraphForModule(module, chunkGraph) { + chunkGraphForModuleMap.set(module, chunkGraph); + } + + // TODO remove in webpack 6 + /** + * @param {Chunk} chunk the chunk + * @param {string} deprecateMessage message for the deprecation message + * @returns {ChunkGraph} the chunk graph + */ + static getChunkGraphForChunk(chunk, deprecateMessage) { + const fn = deprecateGetChunkGraphForChunkMap.get(deprecateMessage); + if (fn) return fn(chunk); + const newFn = util.deprecate( + /** + * @param {Chunk} chunk the chunk + * @returns {ChunkGraph} the chunk graph + */ + chunk => { + const chunkGraph = chunkGraphForChunkMap.get(chunk); + if (!chunkGraph) + throw new Error( + deprecateMessage + + "There was no ChunkGraph assigned to the Chunk for backward-compat (Use the new API)" + ); + return chunkGraph; + }, + deprecateMessage + ": Use new ChunkGraph API" + ); + deprecateGetChunkGraphForChunkMap.set(deprecateMessage, newFn); + return newFn(chunk); + } + + // TODO remove in webpack 6 + /** + * @param {Chunk} chunk the chunk + * @param {ChunkGraph} chunkGraph the chunk graph + * @returns {void} + */ + static setChunkGraphForChunk(chunk, chunkGraph) { + chunkGraphForChunkMap.set(chunk, chunkGraph); + } } +// TODO remove in webpack 6 +/** @type {WeakMap} */ +const chunkGraphForModuleMap = new WeakMap(); + +// TODO remove in webpack 6 +/** @type {WeakMap} */ +const chunkGraphForChunkMap = new WeakMap(); + +// TODO remove in webpack 6 +/** @type {Map ChunkGraph>} */ +const deprecateGetChunkGraphForModuleMap = new Map(); + +// TODO remove in webpack 6 +/** @type {Map ChunkGraph>} */ +const deprecateGetChunkGraphForChunkMap = new Map(); + module.exports = ChunkGraph; diff --git a/lib/Compilation.js b/lib/Compilation.js index a56f55a23..ead808e39 100644 --- a/lib/Compilation.js +++ b/lib/Compilation.js @@ -1064,9 +1064,13 @@ class Compilation { * @returns {void} */ seal(callback) { - const chunkGraph = new ChunkGraph(); + const chunkGraph = new ChunkGraph(this.moduleGraph); this.chunkGraph = chunkGraph; + for (const module of this.modules) { + ChunkGraph.setChunkGraphForModule(module, chunkGraph); + } + this.hooks.seal.call(); while (this.hooks.optimizeDependencies.call(this.modules)) { @@ -1295,6 +1299,7 @@ class Compilation { } const chunk = new Chunk(name); this.chunks.push(chunk); + ChunkGraph.setChunkGraphForChunk(chunk, this.chunkGraph); if (name) { this.namedChunks.set(name, chunk); } diff --git a/lib/Module.js b/lib/Module.js index 0373fe434..25dca9600 100644 --- a/lib/Module.js +++ b/lib/Module.js @@ -5,17 +5,18 @@ "use strict"; +const ChunkGraph = require("./ChunkGraph"); const DependenciesBlock = require("./DependenciesBlock"); +const ModuleGraph = require("./ModuleGraph"); const Template = require("./Template"); +const { compareChunksById } = require("./util/comparators"); /** @typedef {import("webpack-sources").Source} Source */ /** @typedef {import("./Chunk")} Chunk */ -/** @typedef {import("./ChunkGraph")} ChunkGraph */ /** @typedef {import("./ChunkGroup")} ChunkGroup */ /** @typedef {import("./Compilation")} Compilation */ /** @typedef {import("./Dependency")} Dependency */ /** @typedef {import("./DependencyTemplates")} DependencyTemplates */ -/** @typedef {import("./ModuleGraph")} ModuleGraph */ /** @typedef {import("./RequestShortener")} RequestShortener */ /** @typedef {import("./RuntimeTemplate")} RuntimeTemplate */ /** @typedef {import("./WebpackError")} WebpackError */ @@ -115,14 +116,126 @@ class Module extends DependenciesBlock { this.useSourceMap = false; } + // TODO remove in webpack 6 + // BACKWARD-COMPAT START get index() { - throw new Error(); + return ModuleGraph.getModuleGraphForModule( + this, + "Module.index" + ).getPreOrderIndex(this); + } + + set index(value) { + ModuleGraph.getModuleGraphForModule(this, "Module.index").setPreOrderIndex( + this, + value + ); } get index2() { - throw new Error(); + return ModuleGraph.getModuleGraphForModule( + this, + "Module.index2" + ).getPostOrderIndex(this); } + set index2(value) { + ModuleGraph.getModuleGraphForModule( + this, + "Module.index2" + ).setPostOrderIndex(this, value); + } + + get issuer() { + return ModuleGraph.getModuleGraphForModule(this, "Module.issuer").getIssuer( + this + ); + } + + set issuer(value) { + ModuleGraph.getModuleGraphForModule(this, "Module.issuer").setIssuer( + this, + value + ); + } + + get usedExports() { + return ModuleGraph.getModuleGraphForModule( + this, + "Module.usedExports" + ).getUsedExports(this); + } + + set usedExports(value) { + ModuleGraph.getModuleGraphForModule( + this, + "Module.usedExports" + ).setUsedExports(this, value); + } + + get optimizationBailout() { + return ModuleGraph.getModuleGraphForModule( + this, + "Module.optimizationBailout" + ).getOptimizationBailout(this); + } + + get optional() { + return this.isOptional( + ModuleGraph.getModuleGraphForModule(this, "Module.optional") + ); + } + + addChunk(chunk) { + return ChunkGraph.getChunkGraphForModule( + this, + "Module.addChunk" + ).connectChunkAndModule(chunk, this); + } + + removeChunk(chunk) { + return ChunkGraph.getChunkGraphForModule( + this, + "Module.removeChunk" + ).disconnectChunkAndModule(chunk, this); + } + + isInChunk(chunk) { + return ChunkGraph.getChunkGraphForModule( + this, + "Module.isInChunk" + ).isModuleInChunk(this, chunk); + } + + isEntryModule() { + return ChunkGraph.getChunkGraphForModule( + this, + "Module.isEntryModule" + ).isEntryModule(this); + } + + getChunks() { + return ChunkGraph.getChunkGraphForModule( + this, + "Module.getChunks" + ).getModuleChunks(this); + } + + getNumberOfChunks() { + return ChunkGraph.getChunkGraphForModule( + this, + "Module.getNumberOfChunks" + ).getNumberOfModuleChunks(this); + } + + get chunksIterable() { + return ChunkGraph.getChunkGraphForModule( + this, + "Module.chunksIterable" + ).getOrderedModuleChunksIterable(this, compareChunksById); + } + // BACKWARD-COMPAT END + /** * @deprecated moved to .buildInfo.exportsArgument * @returns {string} name of the exports argument diff --git a/lib/ModuleGraph.js b/lib/ModuleGraph.js index bf46247b6..63d757184 100644 --- a/lib/ModuleGraph.js +++ b/lib/ModuleGraph.js @@ -5,6 +5,7 @@ "use strict"; +const util = require("util"); const ModuleGraphConnection = require("./ModuleGraphConnection"); /** @typedef {import("./DependenciesBlock")} DependenciesBlock */ @@ -428,7 +429,54 @@ class ModuleGraph { } return meta; } + + // TODO remove in webpack 6 + /** + * @param {Module} module the module + * @param {string} deprecateMessage message for the deprecation message + * @returns {ModuleGraph} the module graph + */ + static getModuleGraphForModule(module, deprecateMessage) { + const fn = deprecateMap.get(deprecateMessage); + if (fn) return fn(module); + const newFn = util.deprecate( + /** + * @param {Module} module the module + * @returns {ModuleGraph} the module graph + */ + module => { + const moduleGraph = moduleGraphForModuleMap.get(module); + if (!moduleGraph) + throw new Error( + deprecateMessage + + "There was no ModuleGraph assigned to the Module for backward-compat (Use the new API)" + ); + return moduleGraph; + }, + deprecateMessage + ": Use new ModuleGraph API" + ); + deprecateMap.set(deprecateMessage, newFn); + return newFn(module); + } + + // TODO remove in webpack 6 + /** + * @param {Module} module the module + * @param {ModuleGraph} moduleGraph the module graph + * @returns {void} + */ + static setModuleGraphForModule(module, moduleGraph) { + moduleGraphForModuleMap.set(module, moduleGraph); + } } +// TODO remove in webpack 6 +/** @type {WeakMap} */ +const moduleGraphForModuleMap = new WeakMap(); + +// TODO remove in webpack 6 +/** @type {Map ModuleGraph>} */ +const deprecateMap = new Map(); + module.exports = ModuleGraph; module.exports.ModuleGraphConnection = ModuleGraphConnection; diff --git a/lib/optimize/ModuleConcatenationPlugin.js b/lib/optimize/ModuleConcatenationPlugin.js index d44555a63..e597d05f9 100644 --- a/lib/optimize/ModuleConcatenationPlugin.js +++ b/lib/optimize/ModuleConcatenationPlugin.js @@ -5,6 +5,8 @@ "use strict"; +const ChunkGraph = require("../ChunkGraph"); +const ModuleGraph = require("../ModuleGraph"); const { STAGE_DEFAULT } = require("../OptimizationStages"); const HarmonyCompatibilityDependency = require("../dependencies/HarmonyCompatibilityDependency"); const HarmonyImportDependency = require("../dependencies/HarmonyImportDependency"); @@ -331,6 +333,8 @@ class ModuleConcatenationPlugin { modules, compilation ); + ChunkGraph.setChunkGraphForModule(newModule, chunkGraph); + ModuleGraph.setModuleGraphForModule(newModule, moduleGraph); for (const warning of concatConfiguration.getWarningsSorted()) { moduleGraph .getOptimizationBailout(newModule)