From 7b02084bc55ac9f2c2cb1aab4e8814ce47c4686d Mon Sep 17 00:00:00 2001 From: Florent Cailhol Date: Mon, 30 Jul 2018 22:30:27 +0200 Subject: [PATCH] Replace Basic and Advanced optimzation hooks by stages --- lib/Compilation.js | 40 ++-------------- lib/FlagDependencyUsagePlugin.js | 6 ++- lib/OptimizationStages.js | 10 ++++ lib/ProgressPlugin.js | 8 ---- lib/optimize/AggressiveMergingPlugin.js | 9 +++- lib/optimize/AggressiveSplittingPlugin.js | 8 +++- lib/optimize/EnsureChunkConditionsPlugin.js | 9 +++- lib/optimize/LimitChunkCountPlugin.js | 8 +++- lib/optimize/MergeDuplicateChunksPlugin.js | 9 +++- lib/optimize/MinChunkSizePlugin.js | 8 +++- lib/optimize/ModuleConcatenationPlugin.js | 6 ++- lib/optimize/RemoveEmptyChunksPlugin.js | 18 +++++-- lib/optimize/RemoveParentModulesPlugin.js | 8 +++- lib/optimize/RuntimeChunkPlugin.js | 52 ++++++++++++--------- lib/optimize/SideEffectsFlagPlugin.js | 6 ++- lib/optimize/SplitChunksPlugin.js | 8 +++- test/StatsTestCases.test.js | 4 +- test/TestCases.template.js | 4 +- 18 files changed, 129 insertions(+), 92 deletions(-) create mode 100644 lib/OptimizationStages.js diff --git a/lib/Compilation.js b/lib/Compilation.js index 47f990530..c88ec29c9 100644 --- a/lib/Compilation.js +++ b/lib/Compilation.js @@ -220,32 +220,20 @@ class Compilation { /** @type {SyncHook} */ afterChunks: new SyncHook(["chunks"]), - /** @type {SyncBailHook} */ - optimizeDependenciesBasic: new SyncBailHook(["modules"]), /** @type {SyncBailHook} */ optimizeDependencies: new SyncBailHook(["modules"]), /** @type {SyncBailHook} */ - optimizeDependenciesAdvanced: new SyncBailHook(["modules"]), - /** @type {SyncBailHook} */ afterOptimizeDependencies: new SyncHook(["modules"]), /** @type {SyncHook} */ optimize: new SyncHook([]), /** @type {SyncBailHook} */ - optimizeModulesBasic: new SyncBailHook(["modules"]), - /** @type {SyncBailHook} */ optimizeModules: new SyncBailHook(["modules"]), - /** @type {SyncBailHook} */ - optimizeModulesAdvanced: new SyncBailHook(["modules"]), /** @type {SyncHook} */ afterOptimizeModules: new SyncHook(["modules"]), - /** @type {SyncBailHook} */ - optimizeChunksBasic: new SyncBailHook(["chunks", "chunkGroups"]), /** @type {SyncBailHook} */ optimizeChunks: new SyncBailHook(["chunks", "chunkGroups"]), - /** @type {SyncBailHook} */ - optimizeChunksAdvanced: new SyncBailHook(["chunks", "chunkGroups"]), /** @type {SyncHook} */ afterOptimizeChunks: new SyncHook(["chunks", "chunkGroups"]), @@ -254,12 +242,8 @@ class Compilation { /** @type {SyncHook} */ afterOptimizeTree: new SyncHook(["chunks", "modules"]), - /** @type {SyncBailHook} */ - optimizeChunkModulesBasic: new SyncBailHook(["chunks", "modules"]), /** @type {SyncBailHook} */ optimizeChunkModules: new SyncBailHook(["chunks", "modules"]), - /** @type {SyncBailHook} */ - optimizeChunkModulesAdvanced: new SyncBailHook(["chunks", "modules"]), /** @type {SyncHook} */ afterOptimizeChunkModules: new SyncHook(["chunks", "modules"]), /** @type {SyncBailHook} */ @@ -1098,11 +1082,7 @@ class Compilation { this.hooks.seal.call(); - while ( - this.hooks.optimizeDependenciesBasic.call(this.modules) || - this.hooks.optimizeDependencies.call(this.modules) || - this.hooks.optimizeDependenciesAdvanced.call(this.modules) - ) { + while (this.hooks.optimizeDependencies.call(this.modules)) { /* empty */ } this.hooks.afterOptimizeDependencies.call(this.modules); @@ -1135,20 +1115,12 @@ class Compilation { this.hooks.optimize.call(); - while ( - this.hooks.optimizeModulesBasic.call(this.modules) || - this.hooks.optimizeModules.call(this.modules) || - this.hooks.optimizeModulesAdvanced.call(this.modules) - ) { + while (this.hooks.optimizeModules.call(this.modules)) { /* empty */ } this.hooks.afterOptimizeModules.call(this.modules); - while ( - this.hooks.optimizeChunksBasic.call(this.chunks, this.chunkGroups) || - this.hooks.optimizeChunks.call(this.chunks, this.chunkGroups) || - this.hooks.optimizeChunksAdvanced.call(this.chunks, this.chunkGroups) - ) { + while (this.hooks.optimizeChunks.call(this.chunks, this.chunkGroups)) { /* empty */ } this.hooks.afterOptimizeChunks.call(this.chunks, this.chunkGroups); @@ -1160,11 +1132,7 @@ class Compilation { this.hooks.afterOptimizeTree.call(this.chunks, this.modules); - while ( - this.hooks.optimizeChunkModulesBasic.call(this.chunks, this.modules) || - this.hooks.optimizeChunkModules.call(this.chunks, this.modules) || - this.hooks.optimizeChunkModulesAdvanced.call(this.chunks, this.modules) - ) { + while (this.hooks.optimizeChunkModules.call(this.chunks, this.modules)) { /* empty */ } this.hooks.afterOptimizeChunkModules.call(this.chunks, this.modules); diff --git a/lib/FlagDependencyUsagePlugin.js b/lib/FlagDependencyUsagePlugin.js index b987af57f..69efb7905 100644 --- a/lib/FlagDependencyUsagePlugin.js +++ b/lib/FlagDependencyUsagePlugin.js @@ -5,6 +5,7 @@ "use strict"; +const { STAGE_DEFAULT } = require("./OptimizationStages"); const SortableSet = require("./util/SortableSet"); /** @typedef {import("./Compiler")} Compiler */ @@ -38,7 +39,10 @@ class FlagDependencyUsagePlugin { compiler.hooks.compilation.tap("FlagDependencyUsagePlugin", compilation => { const moduleGraph = compilation.moduleGraph; compilation.hooks.optimizeDependencies.tap( - "FlagDependencyUsagePlugin", + /** @type {TODO} */ ({ + name: "FlagDependencyUsagePlugin", + stage: STAGE_DEFAULT + }), modules => { /** * diff --git a/lib/OptimizationStages.js b/lib/OptimizationStages.js new file mode 100644 index 000000000..c8337c3f0 --- /dev/null +++ b/lib/OptimizationStages.js @@ -0,0 +1,10 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Florent Cailhol @ooflorent +*/ + +"use strict"; + +exports.STAGE_BASIC = 0; +exports.STAGE_DEFAULT = 10; +exports.STAGE_ADVANCED = 20; diff --git a/lib/ProgressPlugin.js b/lib/ProgressPlugin.js index 6ee3773e0..3f8d88d53 100644 --- a/lib/ProgressPlugin.js +++ b/lib/ProgressPlugin.js @@ -138,24 +138,16 @@ class ProgressPlugin { const hooks = { finishModules: "finish module graph", seal: "sealing", - optimizeDependenciesBasic: "basic dependencies optimization", optimizeDependencies: "dependencies optimization", - optimizeDependenciesAdvanced: "advanced dependencies optimization", afterOptimizeDependencies: "after dependencies optimization", optimize: "optimizing", - optimizeModulesBasic: "basic module optimization", optimizeModules: "module optimization", - optimizeModulesAdvanced: "advanced module optimization", afterOptimizeModules: "after module optimization", - optimizeChunksBasic: "basic chunk optimization", optimizeChunks: "chunk optimization", - optimizeChunksAdvanced: "advanced chunk optimization", afterOptimizeChunks: "after chunk optimization", optimizeTree: "module and chunk tree optimization", afterOptimizeTree: "after module and chunk tree optimization", - optimizeChunkModulesBasic: "basic chunk modules optimization", optimizeChunkModules: "chunk modules optimization", - optimizeChunkModulesAdvanced: "advanced chunk modules optimization", afterOptimizeChunkModules: "after chunk modules optimization", reviveModules: "module reviving", optimizeModuleOrder: "module order optimization", diff --git a/lib/optimize/AggressiveMergingPlugin.js b/lib/optimize/AggressiveMergingPlugin.js index 5ce063701..5e957d1f6 100644 --- a/lib/optimize/AggressiveMergingPlugin.js +++ b/lib/optimize/AggressiveMergingPlugin.js @@ -5,6 +5,8 @@ "use strict"; +const { STAGE_ADVANCED } = require("../OptimizationStages"); + /** @typedef {import("../Chunk")} Chunk */ /** @typedef {import("../Compiler")} Compiler */ @@ -32,8 +34,11 @@ class AggressiveMergingPlugin { compiler.hooks.thisCompilation.tap( "AggressiveMergingPlugin", compilation => { - compilation.hooks.optimizeChunksAdvanced.tap( - "AggressiveMergingPlugin", + compilation.hooks.optimizeChunks.tap( + /** @type {TODO} */ ({ + name: "AggressiveMergingPlugin", + stage: STAGE_ADVANCED + }), chunks => { const chunkGraph = compilation.chunkGraph; /** @type {{a: Chunk, b: Chunk, improvement: number}[]} */ diff --git a/lib/optimize/AggressiveSplittingPlugin.js b/lib/optimize/AggressiveSplittingPlugin.js index c8144d569..171986ce6 100644 --- a/lib/optimize/AggressiveSplittingPlugin.js +++ b/lib/optimize/AggressiveSplittingPlugin.js @@ -7,6 +7,7 @@ const validateOptions = require("schema-utils"); const schema = require("../../schemas/plugins/optimize/AggressiveSplittingPlugin.json"); +const { STAGE_ADVANCED } = require("../OptimizationStages"); const { intersect } = require("../util/SetHelpers"); const { compareModulesById } = require("../util/comparators"); const identifierUtils = require("../util/identifier"); @@ -81,8 +82,11 @@ class AggressiveSplittingPlugin { fromAggressiveSplittingSet = new Set(); chunkSplitDataMap = new Map(); }); - compilation.hooks.optimizeChunksAdvanced.tap( - "AggressiveSplittingPlugin", + compilation.hooks.optimizeChunks.tap( + /** @type {TODO} */ ({ + name: "AggressiveSplittingPlugin", + stage: STAGE_ADVANCED + }), chunks => { const chunkGraph = compilation.chunkGraph; // Precompute stuff diff --git a/lib/optimize/EnsureChunkConditionsPlugin.js b/lib/optimize/EnsureChunkConditionsPlugin.js index 7041154a4..6a8f0f951 100644 --- a/lib/optimize/EnsureChunkConditionsPlugin.js +++ b/lib/optimize/EnsureChunkConditionsPlugin.js @@ -5,6 +5,8 @@ "use strict"; +const { STAGE_BASIC } = require("../OptimizationStages"); + class EnsureChunkConditionsPlugin { apply(compiler) { compiler.hooks.compilation.tap( @@ -58,8 +60,11 @@ class EnsureChunkConditionsPlugin { } if (changed) return true; }; - compilation.hooks.optimizeChunksBasic.tap( - "EnsureChunkConditionsPlugin", + compilation.hooks.optimizeChunks.tap( + /** @type {TODO} */ ({ + name: "EnsureChunkConditionsPlugin", + stage: STAGE_BASIC + }), handler ); } diff --git a/lib/optimize/LimitChunkCountPlugin.js b/lib/optimize/LimitChunkCountPlugin.js index b52611143..759fb7956 100644 --- a/lib/optimize/LimitChunkCountPlugin.js +++ b/lib/optimize/LimitChunkCountPlugin.js @@ -7,6 +7,7 @@ const validateOptions = require("schema-utils"); const schema = require("../../schemas/plugins/optimize/LimitChunkCountPlugin.json"); +const { STAGE_ADVANCED } = require("../OptimizationStages"); /** @typedef {import("../Chunk")} Chunk */ /** @typedef {import("../Compiler")} Compiler */ @@ -24,8 +25,11 @@ class LimitChunkCountPlugin { apply(compiler) { const options = this.options; compiler.hooks.compilation.tap("LimitChunkCountPlugin", compilation => { - compilation.hooks.optimizeChunksAdvanced.tap( - "LimitChunkCountPlugin", + compilation.hooks.optimizeChunks.tap( + /** @type {TODO} */ ({ + name: "LimitChunkCountPlugin", + stage: STAGE_ADVANCED + }), chunks => { const chunkGraph = compilation.chunkGraph; const maxChunks = options.maxChunks; diff --git a/lib/optimize/MergeDuplicateChunksPlugin.js b/lib/optimize/MergeDuplicateChunksPlugin.js index 50e1e59ba..0762e39d2 100644 --- a/lib/optimize/MergeDuplicateChunksPlugin.js +++ b/lib/optimize/MergeDuplicateChunksPlugin.js @@ -5,6 +5,8 @@ "use strict"; +const { STAGE_BASIC } = require("../OptimizationStages"); + /** @typedef {import("../Compiler")} Compiler */ class MergeDuplicateChunksPlugin { @@ -16,8 +18,11 @@ class MergeDuplicateChunksPlugin { compiler.hooks.compilation.tap( "MergeDuplicateChunksPlugin", compilation => { - compilation.hooks.optimizeChunksBasic.tap( - "MergeDuplicateChunksPlugin", + compilation.hooks.optimizeChunks.tap( + /** @type {TODO} */ ({ + name: "MergeDuplicateChunksPlugin", + stage: STAGE_BASIC + }), chunks => { const chunkGraph = compilation.chunkGraph; diff --git a/lib/optimize/MinChunkSizePlugin.js b/lib/optimize/MinChunkSizePlugin.js index 5edd41178..535a92b89 100644 --- a/lib/optimize/MinChunkSizePlugin.js +++ b/lib/optimize/MinChunkSizePlugin.js @@ -7,6 +7,7 @@ const validateOptions = require("schema-utils"); const schema = require("../../schemas/plugins/optimize/MinChunkSizePlugin.json"); +const { STAGE_ADVANCED } = require("../OptimizationStages"); /** @typedef {import("../Chunk")} Chunk */ /** @typedef {import("../Compiler")} Compiler */ @@ -25,8 +26,11 @@ class MinChunkSizePlugin { const options = this.options; const minChunkSize = options.minChunkSize; compiler.hooks.compilation.tap("MinChunkSizePlugin", compilation => { - compilation.hooks.optimizeChunksAdvanced.tap( - "MinChunkSizePlugin", + compilation.hooks.optimizeChunks.tap( + /** @type {TODO} */ ({ + name: "MinChunkSizePlugin", + stage: STAGE_ADVANCED + }), chunks => { const chunkGraph = compilation.chunkGraph; const equalOptions = { diff --git a/lib/optimize/ModuleConcatenationPlugin.js b/lib/optimize/ModuleConcatenationPlugin.js index c4d2080e2..f0bd9dd15 100644 --- a/lib/optimize/ModuleConcatenationPlugin.js +++ b/lib/optimize/ModuleConcatenationPlugin.js @@ -5,6 +5,7 @@ "use strict"; +const { STAGE_DEFAULT } = require("../OptimizationStages"); const HarmonyCompatibilityDependency = require("../dependencies/HarmonyCompatibilityDependency"); const HarmonyImportDependency = require("../dependencies/HarmonyImportDependency"); const ModuleHotAcceptDependency = require("../dependencies/ModuleHotAcceptDependency"); @@ -97,7 +98,10 @@ class ModuleConcatenationPlugin { }; compilation.hooks.optimizeChunkModules.tap( - "ModuleConcatenationPlugin", + /** @type {TODO} */ ({ + name: "ModuleConcatenationPlugin", + stage: STAGE_DEFAULT + }), (chunks, modules) => { const chunkGraph = compilation.chunkGraph; const relevantModules = []; diff --git a/lib/optimize/RemoveEmptyChunksPlugin.js b/lib/optimize/RemoveEmptyChunksPlugin.js index 2838a74d2..1bfe9ac5b 100644 --- a/lib/optimize/RemoveEmptyChunksPlugin.js +++ b/lib/optimize/RemoveEmptyChunksPlugin.js @@ -5,6 +5,8 @@ "use strict"; +const { STAGE_BASIC, STAGE_ADVANCED } = require("../OptimizationStages"); + /** @typedef {import("../Chunk")} Chunk */ /** @typedef {import("../Compiler")} Compiler */ @@ -33,12 +35,20 @@ class RemoveEmptyChunksPlugin { } } }; - compilation.hooks.optimizeChunksBasic.tap( - "RemoveEmptyChunksPlugin", + + // TODO do it once + compilation.hooks.optimizeChunks.tap( + /** @type {TODO} */ ({ + name: "RemoveEmptyChunksPlugin", + stage: STAGE_BASIC + }), handler ); - compilation.hooks.optimizeChunksAdvanced.tap( - "RemoveEmptyChunksPlugin", + compilation.hooks.optimizeChunks.tap( + /** @type {TODO} */ ({ + name: "RemoveEmptyChunksPlugin", + stage: STAGE_ADVANCED + }), handler ); }); diff --git a/lib/optimize/RemoveParentModulesPlugin.js b/lib/optimize/RemoveParentModulesPlugin.js index 64a06289b..699ae2281 100644 --- a/lib/optimize/RemoveParentModulesPlugin.js +++ b/lib/optimize/RemoveParentModulesPlugin.js @@ -5,6 +5,7 @@ "use strict"; +const { STAGE_BASIC } = require("../OptimizationStages"); const Queue = require("../util/Queue"); const { intersect } = require("../util/SetHelpers"); @@ -100,8 +101,11 @@ class RemoveParentModulesPlugin { } } }; - compilation.hooks.optimizeChunksBasic.tap( - "RemoveParentModulesPlugin", + compilation.hooks.optimizeChunks.tap( + /** @type {TODO} */ ({ + name: "RemoveParentModulesPlugin", + stage: STAGE_BASIC + }), handler ); }); diff --git a/lib/optimize/RuntimeChunkPlugin.js b/lib/optimize/RuntimeChunkPlugin.js index 0b0d9da9d..eee44b5a7 100644 --- a/lib/optimize/RuntimeChunkPlugin.js +++ b/lib/optimize/RuntimeChunkPlugin.js @@ -5,7 +5,9 @@ "use strict"; -module.exports = class RuntimeChunkPlugin { +const { STAGE_ADVANCED } = require("../OptimizationStages"); + +class RuntimeChunkPlugin { constructor(options) { this.options = Object.assign( { @@ -17,27 +19,35 @@ module.exports = class RuntimeChunkPlugin { apply(compiler) { compiler.hooks.thisCompilation.tap("RuntimeChunkPlugin", compilation => { - compilation.hooks.optimizeChunksAdvanced.tap("RuntimeChunkPlugin", () => { - const chunkGraph = compilation.chunkGraph; - for (const entrypoint of compilation.entrypoints.values()) { - const chunk = entrypoint.getRuntimeChunk(); - let name = this.options.name; - if (typeof name === "function") { - name = name(entrypoint); - } - if ( - chunkGraph.getNumberOfChunkModules(chunk) > 0 || - !chunk.preventIntegration || - chunk.name !== name - ) { - const newChunk = compilation.addChunk(name); - newChunk.preventIntegration = true; - entrypoint.unshiftChunk(newChunk); - newChunk.addGroup(entrypoint); - entrypoint.setRuntimeChunk(newChunk); + compilation.hooks.optimizeChunks.tap( + /** @type {TODO} */ ({ + name: "RuntimeChunkPlugin", + stage: STAGE_ADVANCED + }), + () => { + const chunkGraph = compilation.chunkGraph; + for (const entrypoint of compilation.entrypoints.values()) { + const chunk = entrypoint.getRuntimeChunk(); + let name = this.options.name; + if (typeof name === "function") { + name = name(entrypoint); + } + if ( + chunkGraph.getNumberOfChunkModules(chunk) > 0 || + !chunk.preventIntegration || + chunk.name !== name + ) { + const newChunk = compilation.addChunk(name); + newChunk.preventIntegration = true; + entrypoint.unshiftChunk(newChunk); + newChunk.addGroup(entrypoint); + entrypoint.setRuntimeChunk(newChunk); + } } } - }); + ); }); } -}; +} + +module.exports = RuntimeChunkPlugin; diff --git a/lib/optimize/SideEffectsFlagPlugin.js b/lib/optimize/SideEffectsFlagPlugin.js index 1fca54fa3..0547602fe 100644 --- a/lib/optimize/SideEffectsFlagPlugin.js +++ b/lib/optimize/SideEffectsFlagPlugin.js @@ -6,6 +6,7 @@ "use strict"; const mm = require("micromatch"); +const { STAGE_DEFAULT } = require("../OptimizationStages"); const HarmonyExportImportedSpecifierDependency = require("../dependencies/HarmonyExportImportedSpecifierDependency"); const HarmonyImportSpecifierDependency = require("../dependencies/HarmonyImportSpecifierDependency"); @@ -56,7 +57,10 @@ class SideEffectsFlagPlugin { compiler.hooks.compilation.tap("SideEffectsFlagPlugin", compilation => { const moduleGraph = compilation.moduleGraph; compilation.hooks.optimizeDependencies.tap( - "SideEffectsFlagPlugin", + /** @type {TODO} */ ({ + name: "SideEffectsFlagPlugin", + stage: STAGE_DEFAULT + }), modules => { /** @type {Map>} */ const reexportMaps = new Map(); diff --git a/lib/optimize/SplitChunksPlugin.js b/lib/optimize/SplitChunksPlugin.js index 220278911..8023b503c 100644 --- a/lib/optimize/SplitChunksPlugin.js +++ b/lib/optimize/SplitChunksPlugin.js @@ -6,6 +6,7 @@ "use strict"; const crypto = require("crypto"); +const { STAGE_ADVANCED } = require("../OptimizationStages"); const { isSubset } = require("../util/SetHelpers"); const SortableSet = require("../util/SortableSet"); const deterministicGrouping = require("../util/deterministicGrouping"); @@ -335,8 +336,11 @@ module.exports = class SplitChunksPlugin { compilation.hooks.unseal.tap("SplitChunksPlugin", () => { alreadyOptimized = false; }); - compilation.hooks.optimizeChunksAdvanced.tap( - "SplitChunksPlugin", + compilation.hooks.optimizeChunks.tap( + /** @type {TODO} */ ({ + name: "SplitChunksPlugin", + stage: STAGE_ADVANCED + }), chunks => { if (alreadyOptimized) return; alreadyOptimized = true; diff --git a/test/StatsTestCases.test.js b/test/StatsTestCases.test.js index bb2bc092e..762fddbc4 100644 --- a/test/StatsTestCases.test.js +++ b/test/StatsTestCases.test.js @@ -71,8 +71,8 @@ describe("StatsTestCases", () => { c.hooks.compilation.tap("StatsTestCasesTest", compilation => { [ "optimize", - "optimizeModulesBasic", - "optimizeChunksBasic", + "optimizeModules", + "optimizeChunks", "afterOptimizeTree", "afterOptimizeAssets", "beforeHash" diff --git a/test/TestCases.template.js b/test/TestCases.template.js index 8e00b4991..7aa01693a 100644 --- a/test/TestCases.template.js +++ b/test/TestCases.template.js @@ -156,8 +156,8 @@ const describeCases = config => { this.hooks.compilation.tap("TestCasesTest", compilation => { [ "optimize", - "optimizeModulesBasic", - "optimizeChunksBasic", + "optimizeModules", + "optimizeChunks", "afterOptimizeTree", "afterOptimizeAssets" ].forEach(hook => {