如何编写wenpack插件
源码太多,边听歌曲边看吧!
理解插件的书写格式:
// 简单插件class MyPlugin {constructor (options) {console.log(options)}apply (compiler) {compiler.hooks.done.tap('MyPlugin', () => {console.log('构建结束')})}}
// 复杂插件class AssetPlugin {constructor(options) {this.options = options;}apply(compiler) {compiler.hooks.compilation.tap('AssetPlugin', (compilation) => {compilation.hooks.chunkAsset.tap('AssetPlugin', (chunk, filename) => {console.log(chunk.name || chunk.id, filename);});});}}
compiler 对象代表了完整的 webpack 环境配置,这个对象在启动 webpack 时被一次性建立。compilation 对象代表了一次资源版本构建,每次 watch 会重新生成。
compiler.hooks.done.tap 这个怎么来的,我们怎么知道有哪些钩子?
class Compiler {/*** @param {string} context the compilation path*/constructor(context) {this.hooks = Object.freeze({/** @type {SyncHook<[]>} */initialize: new SyncHook([]),/** @type {SyncBailHook<[Compilation], boolean>} */shouldEmit: new SyncBailHook(["compilation"]),/** @type {AsyncSeriesHook<[Stats]>} */done: new AsyncSeriesHook(["stats"]),/** @type {SyncHook<[Stats]>} */afterDone: new SyncHook(["stats"]),/** @type {AsyncSeriesHook<[]>} */additionalPass: new AsyncSeriesHook([]),/** @type {AsyncSeriesHook<[Compiler]>} */beforeRun: new AsyncSeriesHook(["compiler"]),/** @type {AsyncSeriesHook<[Compiler]>} */run: new AsyncSeriesHook(["compiler"]),/** @type {AsyncSeriesHook<[Compilation]>} */emit: new AsyncSeriesHook(["compilation"]),/** @type {AsyncSeriesHook<[string, AssetEmittedInfo]>} */assetEmitted: new AsyncSeriesHook(["file", "info"]),/** @type {AsyncSeriesHook<[Compilation]>} */afterEmit: new AsyncSeriesHook(["compilation"]),/** @type {SyncHook<[Compilation, CompilationParams]>} */thisCompilation: new SyncHook(["compilation", "params"]),/** @type {SyncHook<[Compilation, CompilationParams]>} */compilation: new SyncHook(["compilation", "params"]),/** @type {SyncHook<[NormalModuleFactory]>} */normalModuleFactory: new SyncHook(["normalModuleFactory"]),/** @type {SyncHook<[ContextModuleFactory]>} */contextModuleFactory: new SyncHook(["contextModuleFactory"]),/** @type {AsyncSeriesHook<[CompilationParams]>} */beforeCompile: new AsyncSeriesHook(["params"]),/** @type {SyncHook<[CompilationParams]>} */compile: new SyncHook(["params"]),/** @type {AsyncParallelHook<[Compilation]>} */make: new AsyncParallelHook(["compilation"]),/** @type {AsyncParallelHook<[Compilation]>} */finishMake: new AsyncSeriesHook(["compilation"]),/** @type {AsyncSeriesHook<[Compilation]>} */afterCompile: new AsyncSeriesHook(["compilation"]),/** @type {AsyncSeriesHook<[Compiler]>} */watchRun: new AsyncSeriesHook(["compiler"]),/** @type {SyncHook<[Error]>} */failed: new SyncHook(["error"]),/** @type {SyncHook<[string | null, number]>} */invalid: new SyncHook(["filename", "changeTime"]),/** @type {SyncHook<[]>} */watchClose: new SyncHook([]),/** @type {AsyncSeriesHook<[]>} */shutdown: new AsyncSeriesHook([]),/** @type {SyncBailHook<[string, string, any[]], true>} */infrastructureLog: new SyncBailHook(["origin", "type", "args"]),// TODO the following hooks are weirdly located here// TODO move them for webpack 5/** @type {SyncHook<[]>} */environment: new SyncHook([]),/** @type {SyncHook<[]>} */afterEnvironment: new SyncHook([]),/** @type {SyncHook<[Compiler]>} */afterPlugins: new SyncHook(["compiler"]),/** @type {SyncHook<[Compiler]>} */afterResolvers: new SyncHook(["compiler"]),/** @type {SyncBailHook<[string, Entry], boolean>} */entryOption: new SyncBailHook(["context", "entry"])});
打开源码看到如此多的钩子,我们看到的 SyncHook 和 SyncBailHook 等等这样的 hook 又来自哪里,这个是 tapable 库里面的。
每当 compiler 开始一次新的构建,创建一个新的 compilation 实例,会触发一次钩子事件,所以必须在 compiler.hooks.compilation.tap 里面拿到 compilation。
class Compilation {createCompilation() {this._cleanupLastCompilation();return (this._lastCompilation = new Compilation(this));}/*** @param {CompilationParams} params the compilation parameters* @returns {Compilation} the created compilation*/newCompilation(params) {const compilation = this.createCompilation();compilation.name = this.name;compilation.records = this.records;this.hooks.thisCompilation.call(compilation, params);this.hooks.compilation.call(compilation, params);return compilation;}
那么 compilation 里面有哪些钩子呢?
class Compilation {this.hooks = Object.freeze({/** @type {SyncHook<[Module]>} */buildModule: new SyncHook(["module"]),/** @type {SyncHook<[Module]>} */rebuildModule: new SyncHook(["module"]),/** @type {SyncHook<[Module, WebpackError]>} */failedModule: new SyncHook(["module", "error"]),/** @type {SyncHook<[Module]>} */succeedModule: new SyncHook(["module"]),/** @type {SyncHook<[Module]>} */stillValidModule: new SyncHook(["module"]),/** @type {SyncHook<[Dependency, EntryOptions]>} */addEntry: new SyncHook(["entry", "options"]),/** @type {SyncHook<[Dependency, EntryOptions, Error]>} */failedEntry: new SyncHook(["entry", "options", "error"]),/** @type {SyncHook<[Dependency, EntryOptions, Module]>} */succeedEntry: new SyncHook(["entry", "options", "module"]),/** @type {SyncWaterfallHook<[(string[] | ReferencedExport)[], Dependency, RuntimeSpec]>} */dependencyReferencedExports: new SyncWaterfallHook(["referencedExports","dependency","runtime"]),/** @type {SyncHook<[ExecuteModuleArgument, ExecuteModuleContext]>} */executeModule: new SyncHook(["options", "context"]),/** @type {AsyncParallelHook<[ExecuteModuleArgument, ExecuteModuleContext]>} */prepareModuleExecution: new AsyncParallelHook(["options", "context"]),/** @type {AsyncSeriesHook<[Iterable]>} */ finishModules: new AsyncSeriesHook(["modules"]),/** @type {AsyncSeriesHook<[Module]>} */finishRebuildingModule: new AsyncSeriesHook(["module"]),/** @type {SyncHook<[]>} */unseal: new SyncHook([]),/** @type {SyncHook<[]>} */seal: new SyncHook([]),/** @type {SyncHook<[]>} */beforeChunks: new SyncHook([]),/** @type {SyncHook<[Iterable]>} */ afterChunks: new SyncHook(["chunks"]),/** @type {SyncBailHook<[Iterable]>} */ optimizeDependencies: new SyncBailHook(["modules"]),/** @type {SyncHook<[Iterable]>} */ afterOptimizeDependencies: new SyncHook(["modules"]),/** @type {SyncHook<[]>} */optimize: new SyncHook([]),/** @type {SyncBailHook<[Iterable]>} */ optimizeModules: new SyncBailHook(["modules"]),/** @type {SyncHook<[Iterable]>} */ afterOptimizeModules: new SyncHook(["modules"]),/** @type {SyncBailHook<[Iterable, ChunkGroup[]]>} */ optimizeChunks: new SyncBailHook(["chunks", "chunkGroups"]),/** @type {SyncHook<[Iterable, ChunkGroup[]]>} */ afterOptimizeChunks: new SyncHook(["chunks", "chunkGroups"]),/** @type {AsyncSeriesHook<[Iterable, Iterable ]>} */ optimizeTree: new AsyncSeriesHook(["chunks", "modules"]),/** @type {SyncHook<[Iterable, Iterable ]>} */ afterOptimizeTree: new SyncHook(["chunks", "modules"]),/** @type {AsyncSeriesBailHook<[Iterable, Iterable ]>} */ optimizeChunkModules: new AsyncSeriesBailHook(["chunks", "modules"]),/** @type {SyncHook<[Iterable, Iterable ]>} */ afterOptimizeChunkModules: new SyncHook(["chunks", "modules"]),/** @type {SyncBailHook<[], boolean>} */shouldRecord: new SyncBailHook([]),/** @type {SyncHook<[Chunk, Set, RuntimeRequirementsContext]>} */ additionalChunkRuntimeRequirements: new SyncHook(["chunk","runtimeRequirements","context"]),/** @type {HookMap, RuntimeRequirementsContext]>>} */ runtimeRequirementInChunk: new HookMap(() => new SyncBailHook(["chunk", "runtimeRequirements", "context"])),/** @type {SyncHook<[Module, Set, RuntimeRequirementsContext]>} */ additionalModuleRuntimeRequirements: new SyncHook(["module","runtimeRequirements","context"]),/** @type {HookMap, RuntimeRequirementsContext]>>} */ runtimeRequirementInModule: new HookMap(() => new SyncBailHook(["module", "runtimeRequirements", "context"])),/** @type {SyncHook<[Chunk, Set, RuntimeRequirementsContext]>} */ additionalTreeRuntimeRequirements: new SyncHook(["chunk","runtimeRequirements","context"]),/** @type {HookMap, RuntimeRequirementsContext]>>} */ runtimeRequirementInTree: new HookMap(() => new SyncBailHook(["chunk", "runtimeRequirements", "context"])),/** @type {SyncHook<[RuntimeModule, Chunk]>} */runtimeModule: new SyncHook(["module", "chunk"]),/** @type {SyncHook<[Iterable, any]>} */ reviveModules: new SyncHook(["modules", "records"]),/** @type {SyncHook<[Iterable]>} */ beforeModuleIds: new SyncHook(["modules"]),/** @type {SyncHook<[Iterable]>} */ moduleIds: new SyncHook(["modules"]),/** @type {SyncHook<[Iterable]>} */ optimizeModuleIds: new SyncHook(["modules"]),/** @type {SyncHook<[Iterable]>} */ afterOptimizeModuleIds: new SyncHook(["modules"]),/** @type {SyncHook<[Iterable, any]>} */ reviveChunks: new SyncHook(["chunks", "records"]),/** @type {SyncHook<[Iterable]>} */ beforeChunkIds: new SyncHook(["chunks"]),/** @type {SyncHook<[Iterable]>} */ chunkIds: new SyncHook(["chunks"]),/** @type {SyncHook<[Iterable]>} */ optimizeChunkIds: new SyncHook(["chunks"]),/** @type {SyncHook<[Iterable]>} */ afterOptimizeChunkIds: new SyncHook(["chunks"]),/** @type {SyncHook<[Iterable, any]>} */ recordModules: new SyncHook(["modules", "records"]),/** @type {SyncHook<[Iterable, any]>} */ recordChunks: new SyncHook(["chunks", "records"]),/** @type {SyncHook<[Iterable]>} */ optimizeCodeGeneration: new SyncHook(["modules"]),/** @type {SyncHook<[]>} */beforeModuleHash: new SyncHook([]),/** @type {SyncHook<[]>} */afterModuleHash: new SyncHook([]),/** @type {SyncHook<[]>} */beforeCodeGeneration: new SyncHook([]),/** @type {SyncHook<[]>} */afterCodeGeneration: new SyncHook([]),/** @type {SyncHook<[]>} */beforeRuntimeRequirements: new SyncHook([]),/** @type {SyncHook<[]>} */afterRuntimeRequirements: new SyncHook([]),/** @type {SyncHook<[]>} */beforeHash: new SyncHook([]),/** @type {SyncHook<[Chunk]>} */contentHash: new SyncHook(["chunk"]),/** @type {SyncHook<[]>} */afterHash: new SyncHook([]),/** @type {SyncHook<[any]>} */recordHash: new SyncHook(["records"]),/** @type {SyncHook<[Compilation, any]>} */record: new SyncHook(["compilation", "records"]),/** @type {SyncHook<[]>} */beforeModuleAssets: new SyncHook([]),/** @type {SyncBailHook<[], boolean>} */shouldGenerateChunkAssets: new SyncBailHook([]),/** @type {SyncHook<[]>} */beforeChunkAssets: new SyncHook([]),// TODO webpack 6 remove/** @deprecated */additionalChunkAssets: createProcessAssetsHook("additionalChunkAssets",Compilation.PROCESS_ASSETS_STAGE_ADDITIONAL,() => [this.chunks],"DEP_WEBPACK_COMPILATION_ADDITIONAL_CHUNK_ASSETS"),// TODO webpack 6 deprecate/** @deprecated */additionalAssets: createProcessAssetsHook("additionalAssets",Compilation.PROCESS_ASSETS_STAGE_ADDITIONAL,() => []),// TODO webpack 6 remove/** @deprecated */optimizeChunkAssets: createProcessAssetsHook("optimizeChunkAssets",Compilation.PROCESS_ASSETS_STAGE_OPTIMIZE,() => [this.chunks],"DEP_WEBPACK_COMPILATION_OPTIMIZE_CHUNK_ASSETS"),// TODO webpack 6 remove/** @deprecated */afterOptimizeChunkAssets: createProcessAssetsHook("afterOptimizeChunkAssets",Compilation.PROCESS_ASSETS_STAGE_OPTIMIZE + 1,() => [this.chunks],"DEP_WEBPACK_COMPILATION_AFTER_OPTIMIZE_CHUNK_ASSETS"),// TODO webpack 6 deprecate/** @deprecated */optimizeAssets: processAssetsHook,// TODO webpack 6 deprecate/** @deprecated */afterOptimizeAssets: afterProcessAssetsHook,processAssets: processAssetsHook,afterProcessAssets: afterProcessAssetsHook,/** @type {AsyncSeriesHook<[CompilationAssets]>} */processAdditionalAssets: new AsyncSeriesHook(["assets"]),/** @type {SyncBailHook<[], boolean>} */needAdditionalSeal: new SyncBailHook([]),/** @type {AsyncSeriesHook<[]>} */afterSeal: new AsyncSeriesHook([]),/** @type {SyncWaterfallHook<[RenderManifestEntry[], RenderManifestOptions]>} */renderManifest: new SyncWaterfallHook(["result", "options"]),/** @type {SyncHook<[Hash]>} */fullHash: new SyncHook(["hash"]),/** @type {SyncHook<[Chunk, Hash, ChunkHashContext]>} */chunkHash: new SyncHook(["chunk", "chunkHash", "ChunkHashContext"]),/** @type {SyncHook<[Module, string]>} */moduleAsset: new SyncHook(["module", "filename"]),/** @type {SyncHook<[Chunk, string]>} */chunkAsset: new SyncHook(["chunk", "filename"]),/** @type {SyncWaterfallHook<[string, object, AssetInfo]>} */assetPath: new SyncWaterfallHook(["path", "options", "assetInfo"]),/** @type {SyncBailHook<[], boolean>} */needAdditionalPass: new SyncBailHook([]),/** @type {SyncHook<[Compiler, string, number]>} */childCompiler: new SyncHook(["childCompiler","compilerName","compilerIndex"]),/** @type {SyncBailHook<[string, LogEntry], true>} */log: new SyncBailHook(["origin", "logEntry"]),/** @type {SyncWaterfallHook<[WebpackError[]]>} */processWarnings: new SyncWaterfallHook(["warnings"]),/** @type {SyncWaterfallHook<[WebpackError[]]>} */processErrors: new SyncWaterfallHook(["errors"]),/** @type {HookMap, CreateStatsOptionsContext]>>} */ statsPreset: new HookMap(() => new SyncHook(["options", "context"])),/** @type {SyncHook<[Partial, CreateStatsOptionsContext]>} */ statsNormalize: new SyncHook(["options", "context"]),/** @type {SyncHook<[StatsFactory, NormalizedStatsOptions]>} */statsFactory: new SyncHook(["statsFactory", "options"]),/** @type {SyncHook<[StatsPrinter, NormalizedStatsOptions]>} */statsPrinter: new SyncHook(["statsPrinter", "options"]),get normalModuleLoader() {return getNormalModuleLoader();}});
评论
