【前端必会】tapable、hook,webpack的灵魂( 二 )

我们简单看一下Compiler类的一些hooks
const { SyncHook, SyncBailHook, AsyncParallelHook, AsyncSeriesHook} = require("tapable");......class Compiler { /*** @param {string} context the compilation path* @param {WebpackOptions} options options*/ constructor(context, options = /** @type {WebpackOptions} */ ({})) {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"]),每个hook都是一个 tapable包里对应后hook的实例
在回到创建编译器那里,这时创建一个插件的实例,并且执行apply方法,插件就会向自己关系的hook添加事件处理函数(其实还是一个事件监听),NodeEnvironmentPlugin代码可以自行在源码中查看
【【前端必会】tapable、hook,webpack的灵魂】new NodeEnvironmentPlugin({infrastructureLogging: options.infrastructureLogging }).apply(compiler);一切都准备好了之后,我们再看一下编译器的run方法
/*** @param {Callback<Stats>} callback signals when the call finishes* @returns {void}*/ run(callback) {if (this.running) {return callback(new ConcurrentCompilationError());}let logger;const finalCallback = (err, stats) => {if (logger) logger.time("beginIdle");this.idle = true;this.cache.beginIdle();this.idle = true;if (logger) logger.timeEnd("beginIdle");this.running = false;if (err) {this.hooks.failed.call(err);}if (callback !== undefined) callback(err, stats);this.hooks.afterDone.call(stats);};const startTime = Date.now();this.running = true;const onCompiled = (err, compilation) => {if (err) return finalCallback(err);if (this.hooks.shouldEmit.call(compilation) === false) {compilation.startTime = startTime;compilation.endTime = Date.now();const stats = new Stats(compilation);this.hooks.done.callAsync(stats, err => {if (err) return finalCallback(err);return finalCallback(null, stats);});return;}process.nextTick(() => {logger = compilation.getLogger("webpack.Compiler");logger.time("emitAssets");this.emitAssets(compilation, err => {logger.timeEnd("emitAssets");if (err) return finalCallback(err);if (compilation.hooks.needAdditionalPass.call()) {compilation.needAdditionalPass = true;compilation.startTime = startTime;compilation.endTime = Date.now();logger.time("done hook");const stats = new Stats(compilation);this.hooks.done.callAsync(stats, err => {logger.timeEnd("done hook");if (err) return finalCallback(err);this.hooks.additionalPass.callAsync(err => {if (err) return finalCallback(err);this.compile(onCompiled);});});return;}logger.time("emitRecords");this.emitRecords(err => {logger.timeEnd("emitRecords");if (err) return finalCallback(err);compilation.startTime = startTime;compilation.endTime = Date.now();logger.time("done hook");const stats = new Stats(compilation);this.hooks.done.callAsync(stats, err => {logger.timeEnd("done hook");if (err) return finalCallback(err);this.cache.storeBuildDependencies(compilation.buildDependencies,err => {if (err) return finalCallback(err);return finalCallback(null, stats);});});});});});};const run = () => {this.hooks.beforeRun.callAsync(this, err => {if (err) return finalCallback(err);this.hooks.run.callAsync(this, err => {if (err) return finalCallback(err);this.readRecords(err => {if (err) return finalCallback(err);this.compile(onCompiled);});});});};if (this.idle) {this.cache.endIdle(err => {if (err) return finalCallback(err);this.idle = false;run();});} else {run();} }

经验总结扩展阅读