如何编写wenpack插件

前端精髓

共 14968字,需浏览 30分钟

 · 2021-12-11


源码太多,边听歌曲边看吧!


理解插件的书写格式:

// 简单插件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(); } });


浏览 13
点赞
评论
收藏
分享

手机扫一扫分享

举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

举报