diff --git a/lib/Compilation.js b/lib/Compilation.js index 7a2d80fe7..d6da952a6 100644 --- a/lib/Compilation.js +++ b/lib/Compilation.js @@ -6,7 +6,11 @@ const asyncLib = require("async"); const util = require("util"); -const Tapable = require("tapable-old"); +const Tapable = require("tapable").Tapable; +const SyncHook = require("tapable").SyncHook; +const SyncBailHook = require("tapable").SyncBailHook; +const SyncWaterfallHook = require("tapable").SyncWaterfallHook; +const AsyncSeriesHook = require("tapable").AsyncSeriesHook; const EntryModuleNotFoundError = require("./EntryModuleNotFoundError"); const ModuleNotFoundError = require("./ModuleNotFoundError"); const ModuleDependencyWarning = require("./ModuleDependencyWarning"); @@ -58,6 +62,111 @@ function addAllToSet(set, otherSet) { class Compilation extends Tapable { constructor(compiler) { super(); + this.hooks = { + buildModule: new SyncHook(["module"]), + failedModule: new SyncHook(["module", "error"]), + succeedModule: new SyncHook(["module"]), + + finishModules: new SyncHook(["modules"]), + + unseal: new SyncHook([]), + seal: new SyncHook([]), + + optimizeDependenciesBasic: new SyncBailHook(["modules"]), + optimizeDependencies: new SyncBailHook(["modules"]), + optimizeDependenciesAdvanced: new SyncBailHook(["modules"]), + afterOptimizeDependencies: new SyncHook(["modules"]), + + optimize: new SyncHook([]), + + optimizeModulesBasic: new SyncBailHook(["modules"]), + optimizeModules: new SyncBailHook(["modules"]), + optimizeModulesAdvanced: new SyncBailHook(["modules"]), + afterOptimizeModules: new SyncHook(["modules"]), + + optimizeChunksBasic: new SyncBailHook(["chunks"]), + optimizeChunks: new SyncBailHook(["chunks"]), + optimizeChunksAdvanced: new SyncBailHook(["chunks"]), + afterOptimizeChunks: new SyncHook(["chunks"]), + + optimizeTree: new AsyncSeriesHook(["chunks", "modules"]), + afterOptimizeTree: new SyncHook(["chunks", "modules"]), + + optimizeChunkModulesBasic: new SyncBailHook(["chunks", "modules"]), + optimizeChunkModules: new SyncBailHook(["chunks", "modules"]), + optimizeChunkModulesAdvanced: new SyncBailHook(["chunks", "modules"]), + afterOptimizeChunkModules: new SyncHook(["chunks", "modules"]), + shouldRecord: new SyncBailHook([]), + + reviveModules: new SyncHook(["modules", "records"]), + optimizeModuleOrder: new SyncHook(["modules"]), + advancedOptimizeModuleOrder: new SyncHook(["modules"]), + beforeModuleIds: new SyncHook(["modules"]), + moduleIds: new SyncHook(["modules"]), + optimizeModuleIds: new SyncHook(["modules"]), + afterOptimizeModuleIds: new SyncHook(["modules"]), + + reviveChunks: new SyncHook(["chunks", "records"]), + optimizeChunkOrder: new SyncHook(["chunks"]), + beforeChunkIds: new SyncHook(["chunks"]), + optimizeChunkIds: new SyncHook(["chunks"]), + afterOptimizeChunkIds: new SyncHook(["chunks"]), + + recordModules: new SyncHook(["modules", "records"]), + recordChunks: new SyncHook(["chunks", "records"]), + + beforeHash: new SyncHook([]), + afterHash: new SyncHook([]), + + recordHash: new SyncHook(["records"]), + + record: new SyncHook(["compilation", "records"]), + + beforeModuleAssets: new SyncHook([]), + shouldGenerateChunkAssets: new SyncBailHook([]), + beforeChunkAssets: new SyncHook([]), + additionalChunkAssets: new SyncHook(["chunks"]), + + records: new SyncHook(["compilation", "records"]), + + additionalAssets: new AsyncSeriesHook([]), + optimizeChunkAssets: new AsyncSeriesHook(["chunks"]), + afterOptimizeChunkAssets: new SyncHook(["chunks"]), + optimizeAssets: new AsyncSeriesHook(["assets"]), + afterOptimizeAssets: new SyncHook(["assets"]), + + needAdditionalSeal: new SyncBailHook([]), + afterSeal: new AsyncSeriesHook([]), + + chunkHash: new SyncHook(["chunk", "chunkHash"]), + moduleAsset: new SyncHook(["module", "filename"]), + chunkAsset: new SyncHook(["chunk", "filename"]), + + assetPath: new SyncWaterfallHook(["filename", "data"]), // TODO MainTemplate + + needAdditionalPass: new SyncBailHook([]), + childCompiler: new SyncHook(["childCompiler", "compilerName", "compilerIndex"]), + + // TODO the following hooks are weirdly located here + // TODO move them for webpack 5 + normalModuleLoader: new SyncHook(["loaderContext", "module"]), + + optimizeExtractedChunksBasic: new SyncBailHook(["chunks"]), + optimizeExtractedChunks: new SyncBailHook(["chunks"]), + optimizeExtractedChunksAdvanced: new SyncBailHook(["chunks"]), + afterOptimizeExtractedChunks: new SyncHook(["chunks"]), + }; + this._pluginCompat.tap("Compilation", options => { + switch(options.name) { + case "optimize-tree": + case "additional-assets": + case "optimize-chunk-assets": + case "optimize-assets": + case "after-seal": + options.async = true; + break; + } + }); this.compiler = compiler; this.resolverFactory = compiler.resolverFactory; this.inputFileSystem = compiler.inputFileSystem; @@ -163,7 +272,7 @@ class Compilation extends Tapable { } buildModule(module, optional, origin, dependencies, thisCallback) { - this.applyPlugins1("build-module", module); + this.hooks.buildModule.call(module); let callbackList = this._buildingModules.get(module); if(callbackList) { callbackList.push(thisCallback); @@ -197,10 +306,10 @@ class Compilation extends Tapable { } module.dependencies.sort(Dependency.compare); if(error) { - this.applyPlugins2("failed-module", module, error); + this.hooks.failedModule.call(module, error); return callback(error); } - this.applyPlugins1("succeed-module", module); + this.hooks.succeedModule.call(module); return callback(); }); } @@ -601,7 +710,7 @@ class Compilation extends Tapable { finish() { const modules = this.modules; - this.applyPlugins1("finish-modules", modules); + this.hooks.finishModules.call(modules); for(let index = 0; index < modules.length; index++) { const module = modules[index]; @@ -610,7 +719,7 @@ class Compilation extends Tapable { } unseal() { - this.applyPlugins0("unseal"); + this.hooks.unseal.call(); this.chunks.length = 0; this.namedChunks = {}; this.additionalChunkAssets.length = 0; @@ -619,12 +728,12 @@ class Compilation extends Tapable { } seal(callback) { - this.applyPlugins0("seal"); + this.hooks.seal.call(); - while(this.applyPluginsBailResult1("optimize-dependencies-basic", this.modules) || - this.applyPluginsBailResult1("optimize-dependencies", this.modules) || - this.applyPluginsBailResult1("optimize-dependencies-advanced", this.modules)) { /* empty */ } - this.applyPlugins1("after-optimize-dependencies", this.modules); + while(this.hooks.optimizeDependenciesBasic.call(this.modules) || + this.hooks.optimizeDependencies.call(this.modules) || + this.hooks.optimizeDependenciesAdvanced.call(this.modules)) { /* empty */ } + this.hooks.afterOptimizeDependencies.call(this.modules); this.nextFreeModuleIndex = 0; this.nextFreeModuleIndex2 = 0; @@ -642,94 +751,94 @@ class Compilation extends Tapable { }); this.processDependenciesBlocksForChunks(this.chunks.slice()); this.sortModules(this.modules); - this.applyPlugins0("optimize"); + this.hooks.optimize.call(); - while(this.applyPluginsBailResult1("optimize-modules-basic", this.modules) || - this.applyPluginsBailResult1("optimize-modules", this.modules) || - this.applyPluginsBailResult1("optimize-modules-advanced", this.modules)) { /* empty */ } - this.applyPlugins1("after-optimize-modules", this.modules); + while(this.hooks.optimizeModulesBasic.call(this.modules) || + this.hooks.optimizeModules.call(this.modules) || + this.hooks.optimizeModulesAdvanced.call(this.modules)) { /* empty */ } + this.hooks.afterOptimizeModules.call(this.modules); - while(this.applyPluginsBailResult1("optimize-chunks-basic", this.chunks) || - this.applyPluginsBailResult1("optimize-chunks", this.chunks) || - this.applyPluginsBailResult1("optimize-chunks-advanced", this.chunks)) { /* empty */ } - this.applyPlugins1("after-optimize-chunks", this.chunks); + while(this.hooks.optimizeChunksBasic.call(this.chunks) || + this.hooks.optimizeChunks.call(this.chunks) || + this.hooks.optimizeChunksAdvanced.call(this.chunks)) { /* empty */ } + this.hooks.afterOptimizeChunks.call(this.chunks); - this.applyPluginsAsyncSeries("optimize-tree", this.chunks, this.modules, err => { + this.hooks.optimizeTree.callAsync(this.chunks, this.modules, err => { if(err) { return callback(err); } - this.applyPlugins2("after-optimize-tree", this.chunks, this.modules); + this.hooks.afterOptimizeTree.call(this.chunks, this.modules); - while(this.applyPluginsBailResult("optimize-chunk-modules-basic", this.chunks, this.modules) || - this.applyPluginsBailResult("optimize-chunk-modules", this.chunks, this.modules) || - this.applyPluginsBailResult("optimize-chunk-modules-advanced", this.chunks, this.modules)) { /* empty */ } - this.applyPlugins2("after-optimize-chunk-modules", 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)) { /* empty */ } + this.hooks.afterOptimizeChunkModules.call(this.chunks, this.modules); - const shouldRecord = this.applyPluginsBailResult("should-record") !== false; + const shouldRecord = this.hooks.shouldRecord.call() !== false; - this.applyPlugins2("revive-modules", this.modules, this.records); - this.applyPlugins1("optimize-module-order", this.modules); - this.applyPlugins1("advanced-optimize-module-order", this.modules); - this.applyPlugins1("before-module-ids", this.modules); - this.applyPlugins1("module-ids", this.modules); + this.hooks.reviveModules.call(this.modules, this.records); + this.hooks.optimizeModuleOrder.call(this.modules); + this.hooks.advancedOptimizeModuleOrder.call(this.modules); + this.hooks.beforeModuleIds.call(this.modules); + this.hooks.moduleIds.call(this.modules); this.applyModuleIds(); - this.applyPlugins1("optimize-module-ids", this.modules); - this.applyPlugins1("after-optimize-module-ids", this.modules); + this.hooks.optimizeModuleIds.call(this.modules); + this.hooks.afterOptimizeModuleIds.call(this.modules); this.sortItemsWithModuleIds(); - this.applyPlugins2("revive-chunks", this.chunks, this.records); - this.applyPlugins1("optimize-chunk-order", this.chunks); - this.applyPlugins1("before-chunk-ids", this.chunks); + this.hooks.reviveChunks.call(this.chunks, this.records); + this.hooks.optimizeChunkOrder.call(this.chunks); + this.hooks.beforeChunkIds.call(this.chunks); this.applyChunkIds(); - this.applyPlugins1("optimize-chunk-ids", this.chunks); - this.applyPlugins1("after-optimize-chunk-ids", this.chunks); + this.hooks.optimizeChunkIds.call(this.chunks); + this.hooks.afterOptimizeChunkIds.call(this.chunks); this.sortItemsWithChunkIds(); if(shouldRecord) - this.applyPlugins2("record-modules", this.modules, this.records); + this.hooks.recordModules.call(this.modules, this.records); if(shouldRecord) - this.applyPlugins2("record-chunks", this.chunks, this.records); + this.hooks.recordChunks.call(this.chunks, this.records); - this.applyPlugins0("before-hash"); + this.hooks.beforeHash.call(); this.createHash(); - this.applyPlugins0("after-hash"); + this.hooks.afterHash.call(); if(shouldRecord) - this.applyPlugins1("record-hash", this.records); + this.hooks.recordHash.call(this.records); - this.applyPlugins0("before-module-assets"); + this.hooks.beforeModuleAssets.call(); this.createModuleAssets(); - if(this.applyPluginsBailResult("should-generate-chunk-assets") !== false) { - this.applyPlugins0("before-chunk-assets"); + if(this.hooks.shouldGenerateChunkAssets.call() !== false) { + this.hooks.beforeChunkAssets.call(); this.createChunkAssets(); } - this.applyPlugins1("additional-chunk-assets", this.chunks); + this.hooks.additionalChunkAssets.call(this.chunks); this.summarizeDependencies(); if(shouldRecord) - this.applyPlugins2("record", this, this.records); + this.hooks.record.call(this, this.records); - this.applyPluginsAsync("additional-assets", err => { + this.hooks.additionalAssets.callAsync(err => { if(err) { return callback(err); } - this.applyPluginsAsync("optimize-chunk-assets", this.chunks, err => { + this.hooks.optimizeChunkAssets.callAsync(this.chunks, err => { if(err) { return callback(err); } - this.applyPlugins1("after-optimize-chunk-assets", this.chunks); - this.applyPluginsAsync("optimize-assets", this.assets, err => { + this.hooks.afterOptimizeChunkAssets.call(this.chunks); + this.hooks.optimizeAssets.callAsync(this.assets, err => { if(err) { return callback(err); } - this.applyPlugins1("after-optimize-assets", this.assets); - if(this.applyPluginsBailResult("need-additional-seal")) { + this.hooks.afterOptimizeAssets.call(this.assets); + if(this.hooks.needAdditionalSeal.call()) { this.unseal(); return this.seal(callback); } - return this.applyPluginsAsync("after-seal", callback); + return this.hooks.afterSeal.callAsync(callback); }); }); }); @@ -1399,7 +1508,7 @@ class Compilation extends Tapable { } else { this.chunkTemplate.updateHashForChunk(chunkHash, chunk); } - this.applyPlugins2("chunk-hash", chunk, chunkHash); + this.hooks.chunkHash.call(chunk, chunkHash); chunk.hash = chunkHash.digest(hashDigest); hash.update(chunk.hash); chunk.renderedHash = chunk.hash.substr(0, hashDigestLength); @@ -1427,7 +1536,7 @@ class Compilation extends Tapable { Object.keys(module.assets).forEach((assetName) => { const fileName = this.getPath(assetName); this.assets[fileName] = module.assets[assetName]; - this.applyPlugins2("module-asset", module, fileName); + this.hooks.moduleAsset.call(module, fileName); }); } } @@ -1471,7 +1580,7 @@ class Compilation extends Tapable { throw new Error(`Conflict: Multiple assets emit to the same filename ${file}`); this.assets[file] = source; chunk.files.push(file); - this.applyPlugins2("chunk-asset", chunk, file); + this.hooks.chunkAsset.call(chunk, file); } } catch(err) { this.errors.push(new ChunkRenderError(chunk, file || filenameTemplate, err)); @@ -1511,6 +1620,10 @@ class Compilation extends Tapable { chunk.checkConstraints(); } } + + applyPlugins(name, ...args) { + this.hooks[name.replace(/[- ]([a-z])/g, match => match[1].toUpperCase())].call(...args); + } } Object.defineProperty(Compilation.prototype, "moduleTemplate", { diff --git a/lib/Compiler.js b/lib/Compiler.js index 33110a180..17e911d2e 100644 --- a/lib/Compiler.js +++ b/lib/Compiler.js @@ -63,7 +63,7 @@ class Watching { this.compiler.emitRecords(err => { if(err) return this._done(err); - if(compilation.applyPluginsBailResult("need-additional-pass")) { + if(compilation.hooks.needAdditionalPass.call()) { compilation.needAdditionalPass = true; const stats = new Stats(compilation); @@ -298,7 +298,7 @@ class Compiler extends Tapable { this.emitAssets(compilation, err => { if(err) return callback(err); - if(compilation.applyPluginsBailResult("need-additional-pass")) { + if(compilation.hooks.needAdditionalPass.call()) { compilation.needAdditionalPass = true; const stats = new Stats(compilation); @@ -496,7 +496,7 @@ class Compiler extends Tapable { } childCompiler.parentCompilation = compilation; - compilation.applyPlugins("child-compiler", childCompiler, compilerName, compilerIndex); + compilation.hooks.childCompiler.call(childCompiler, compilerName, compilerIndex); return childCompiler; } diff --git a/lib/NormalModule.js b/lib/NormalModule.js index d1d458702..51d3e8232 100644 --- a/lib/NormalModule.js +++ b/lib/NormalModule.js @@ -162,7 +162,7 @@ class NormalModule extends Module { fs: fs, }; - compilation.applyPlugins("normal-module-loader", loaderContext, this); + compilation.hooks.normalModuleLoader.call(loaderContext, this); if(options.loader) Object.assign(loaderContext, options.loader);