如何编写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<Module>]>} */
            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<Chunk>]>} */
            afterChunks: new SyncHook(["chunks"]),


            /** @type {SyncBailHook<[Iterable<Module>]>} */
            optimizeDependencies: new SyncBailHook(["modules"]),
            /** @type {SyncHook<[Iterable<Module>]>} */
            afterOptimizeDependencies: new SyncHook(["modules"]),


            /** @type {SyncHook<[]>} */
            optimize: new SyncHook([]),
            /** @type {SyncBailHook<[Iterable<Module>]>} */
            optimizeModules: new SyncBailHook(["modules"]),
            /** @type {SyncHook<[Iterable<Module>]>} */
            afterOptimizeModules: new SyncHook(["modules"]),


            /** @type {SyncBailHook<[Iterable<Chunk>, ChunkGroup[]]>} */
            optimizeChunks: new SyncBailHook(["chunks", "chunkGroups"]),
            /** @type {SyncHook<[Iterable<Chunk>, ChunkGroup[]]>} */
            afterOptimizeChunks: new SyncHook(["chunks", "chunkGroups"]),


            /** @type {AsyncSeriesHook<[Iterable<Chunk>, Iterable<Module>]>} */
            optimizeTree: new AsyncSeriesHook(["chunks", "modules"]),
            /** @type {SyncHook<[Iterable<Chunk>, Iterable<Module>]>} */
            afterOptimizeTree: new SyncHook(["chunks", "modules"]),


            /** @type {AsyncSeriesBailHook<[Iterable<Chunk>, Iterable<Module>]>} */
            optimizeChunkModules: new AsyncSeriesBailHook(["chunks", "modules"]),
            /** @type {SyncHook<[Iterable<Chunk>, Iterable<Module>]>} */
            afterOptimizeChunkModules: new SyncHook(["chunks", "modules"]),
            /** @type {SyncBailHook<[], boolean>} */
            shouldRecord: new SyncBailHook([]),


            /** @type {SyncHook<[Chunk, Set<string>, RuntimeRequirementsContext]>} */
            additionalChunkRuntimeRequirements: new SyncHook([
                "chunk",
                "runtimeRequirements",
                "context"
            ]),
            /** @type {HookMap<SyncBailHook<[Chunk, Set<string>, RuntimeRequirementsContext]>>} */
            runtimeRequirementInChunk: new HookMap(
                () => new SyncBailHook(["chunk", "runtimeRequirements", "context"])
            ),
            /** @type {SyncHook<[Module, Set<string>, RuntimeRequirementsContext]>} */
            additionalModuleRuntimeRequirements: new SyncHook([
                "module",
                "runtimeRequirements",
                "context"
            ]),
            /** @type {HookMap<SyncBailHook<[Module, Set<string>, RuntimeRequirementsContext]>>} */
            runtimeRequirementInModule: new HookMap(
                () => new SyncBailHook(["module", "runtimeRequirements", "context"])
            ),
            /** @type {SyncHook<[Chunk, Set<string>, RuntimeRequirementsContext]>} */
            additionalTreeRuntimeRequirements: new SyncHook([
                "chunk",
                "runtimeRequirements",
                "context"
            ]),
            /** @type {HookMap<SyncBailHook<[Chunk, Set<string>, RuntimeRequirementsContext]>>} */
            runtimeRequirementInTree: new HookMap(
                () => new SyncBailHook(["chunk", "runtimeRequirements", "context"])
            ),


            /** @type {SyncHook<[RuntimeModule, Chunk]>} */
            runtimeModule: new SyncHook(["module", "chunk"]),


            /** @type {SyncHook<[Iterable<Module>, any]>} */
            reviveModules: new SyncHook(["modules", "records"]),
            /** @type {SyncHook<[Iterable<Module>]>} */
            beforeModuleIds: new SyncHook(["modules"]),
            /** @type {SyncHook<[Iterable<Module>]>} */
            moduleIds: new SyncHook(["modules"]),
            /** @type {SyncHook<[Iterable<Module>]>} */
            optimizeModuleIds: new SyncHook(["modules"]),
            /** @type {SyncHook<[Iterable<Module>]>} */
            afterOptimizeModuleIds: new SyncHook(["modules"]),


            /** @type {SyncHook<[Iterable<Chunk>, any]>} */
            reviveChunks: new SyncHook(["chunks", "records"]),
            /** @type {SyncHook<[Iterable<Chunk>]>} */
            beforeChunkIds: new SyncHook(["chunks"]),
            /** @type {SyncHook<[Iterable<Chunk>]>} */
            chunkIds: new SyncHook(["chunks"]),
            /** @type {SyncHook<[Iterable<Chunk>]>} */
            optimizeChunkIds: new SyncHook(["chunks"]),
            /** @type {SyncHook<[Iterable<Chunk>]>} */
            afterOptimizeChunkIds: new SyncHook(["chunks"]),


            /** @type {SyncHook<[Iterable<Module>, any]>} */
            recordModules: new SyncHook(["modules", "records"]),
            /** @type {SyncHook<[Iterable<Chunk>, any]>} */
            recordChunks: new SyncHook(["chunks", "records"]),


            /** @type {SyncHook<[Iterable<Module>]>} */
            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<SyncHook<[Partial<NormalizedStatsOptions>, CreateStatsOptionsContext]>>} */
            statsPreset: new HookMap(() => new SyncHook(["options", "context"])),
            /** @type {SyncHook<[Partial<NormalizedStatsOptions>, 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();
            }
        });
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值