compilation事件流中,依然只是针对细节步骤做事件流注入,代码流程如图:
// apply => this-compilation// apply => compilation // return compialtionconst compilation = this.newCompilation(params);this.applyPluginsParallel("make", compilation, err => { ???// callback...});
触发完compilation事件流后,会直接返回一个compilation对象,然后触发下一个事件流make。
make的来源在EntryOptionPlugin插件中,无论entry参数是单入口字符串、单入口数组、多入口对象还是动态函数,都会在引入对应的入口插件后,注入一个make事件。
这里先以最简单的单入口字符串为例,开始跑make事件流:
// SingleEntryPlugincompiler.plugin("make", (compilation, callback) => { ???// 生成一个类型为single entry的依赖类 ???// dep.loc = name ???const dep = SingleEntryPlugin.createDependency(this.entry, this.name); ???compilation.addEntry(this.context, dep, this.name, callback);});
Compilation.addEntry
这里回到了compilation类中,调用原型函数addEntry。
class Compilation extends Tapable { ???// ... ???// context => 默认为process.cwd() ???// entry => dep => SingleEntryDependency ???// name => 单入口默认为main ???// callback => 后面的流程 ???addEntry(context, entry, name, callback) { ???????const slot = { ???????????name: name, ???????????module: null ???????}; ???????// 初始为[] ???????this.preparedChunks.push(slot); ???????this._addModuleChain(context, entry, (module) => { /**/ }, (err, module) => { /**/ }); ???}}
Compilation._addModuleChain
没什么好讲的,直接进入_addModuleChain函数:
class Compilation extends Tapable { ???// ... ???_addModuleChain(context, dependency, onModule, callback) { ???????// profile => options.profile ????????// 不传则start为undefined ???????const start = this.profile && Date.now(); ???????// bail => options.bail ???????const errorAndCallback = this.bail ? (err) => { ???????????callback(err); ???????} : (err) => { ???????????err.dependencies = [dependency]; ???????????this.errors.push(err); ???????????callback(); ???????}; ???????if (typeof dependency !== "object" || dependency === null || !dependency.constructor) { ???????????throw new Error("Parameter ‘dependency‘ must be a Dependency"); ???????} ???????// dependencyFactories包含了所有的依赖集合 ???????const moduleFactory = this.dependencyFactories.get(dependency.constructor); ???????if (!moduleFactory) { ???????????throw new Error(`No dependency factory available for this dependency type: ${dependency.constructor.name}`); ???????} ???????this.semaphore.acquire(() => { /**/ }); ???}}
profile和bail参数大概不会有人传吧,所有直接忽视。
接下来就是尝试从dependencyFactories中获取依赖类对应的值,这个Map对象所有值的设置都在compilation事件流中,详情可见24节中的流程图,传送门:http://www.cnblogs.com/QH-Jimmy/p/8183840.html
在这里,依赖类来源于SingleEntryDependency,键值对设置地点同样来源于SingleEntryPlugin:
// SingleEntryPlugincompiler.plugin("compilation", (compilation, params) => { ???const normalModuleFactory = params.normalModuleFactory; ???// 这里 ???compilation.dependencyFactories.set(SingleEntryDependency, normalModuleFactory);});
所以很简单,这里调用get后取出来的是normalModuleFactory。
而这个normalModuleFactory,在18节中有简单介绍并分析了其中RuleSet对module.rules的处理,传送门:http://www.cnblogs.com/QH-Jimmy/p/8109903.html
semaphore
获取对应的moduleFactory后,调用的this.semaphore其中是生成一个新类:
this.semaphore = new Semaphore(options.parallelism || 100);
(类的名字英文翻译是信号机)
内容比较简单,过一下源码:
class Semaphore { ???// 一个数字 默认为100 ???constructor(available) { ???????this.available = available; ???????this.waiters = []; ???}; ???// 当available大于0时执行callback并减1 ???// 否则将callback弹入waiters ???acquire(callback) { ???????if (this.available > 0) { ???????????this.available--; ???????????callback(); ???????} else { ???????????this.waiters.push(callback); ???????} ???}; ???// 尝试取出最近弹入的callback并在事件流末尾执行 ???release() { ???????if (this.waiters.length > 0) { ???????????const callback = this.waiters.pop(); ???????????process.nextTick(callback); ???????} else { ???????????this.available++; ???????} ???}}
设计看起来确实像个信号机,构造函数中有一个初始的使用次数以及一个待执行callback数组。
每次调用acquire时会传入一个callback,如果次数为正就执行callback并将使用次数减1,如果次数用完了,就把这个callback弹入waiters数组中。
每次调用release时,为尝试取出最新的callback并尽快执行,如果不存在待执行的callback,就将使用次数加1。
NormalModuleFactory.create
也就是说,以下代码可以理解成简单的函数调用:
this.semaphore.acquire(() => { ???moduleFactory.create({ ???????contextInfo: { ???????????issuer: "", ???????????compiler: this.compiler.name ???????}, ???????context: context, ???????dependencies: [dependency] ???}, (err, module) => { /* fn... */ });});
这样,流程跑到了normalModuleFactory的原型方法create上。
class NormalModuleFactory extends Tapable { ???/* ???????data => ????????{ ???????????contextInfo:{ ???????????????issuer: ‘‘, ???????????????compiler: this.compiler.name // undefined ???????????}, ???????????context: context, // process.cwd() ???????????dependencies: [SingleEntryDependency] ???????} ???*/ ???create(data, callback) { ???????const dependencies = data.dependencies; ???????// 尝试取缓存 ???????const cacheEntry = dependencies[0].__NormalModuleFactoryCache; ???????if (cacheEntry) return callback(null, cacheEntry); ???????// 上下文 => process.cwd() ???????const context = data.context || this.context; ???????// 入口文件字符串 => ./input.js ???????const request = dependencies[0].request; ???????const contextInfo = data.contextInfo || {}; ???????this.applyPluginsAsyncWaterfall("before-resolve", { ???????????contextInfo, ???????????context, ???????????request, ???????????dependencies ???????}, (err, result) => { /**/ }); ???}}
这里将上下文、入口文件、入口模块依赖类整合,然后开始触发normalModuleFactory类上的事件流。
关于normalModuleFactory的事件流注入,全部都在24节中有介绍,再来一个传送门:http://www.cnblogs.com/QH-Jimmy/p/8183840.html
这里的事件流before-resolve是没有的,所以按照Tapable的中applyPluginsAsyncWaterfall的执行方式:
Tapable.prototype.applyPluginsAsyncWaterfall = function applyPluginsAsyncWaterfall(name, init, callback) { ???if (!this._plugins[name] || this._plugins[name].length === 0) return callback(null, init); ???// more...}
这里会直接调用callback,分别传入null与第二个参数,如下所示:
this.applyPluginsAsyncWaterfall("before-resolve", { ???????contextInfo, ???????context, ???????request, ???????dependencies ???}, ???// err => null ???// result => 上面的对象 ????(err, result) => { ???????if (err) return callback(err); ???????if (!result) return callback(); ???????// 触发factory事件流 ???????const factory = this.applyPluginsWaterfall0("factory", null); ???????// Ignored ???????if (!factory) return callback(); ???????factory(result, (err, module) => { /**/ }); ???});
这里会接着触发factory事件流,这个是在构造函数中直接plugin的。
class NormalModuleFactory extends Tapable { ???constructor(context, resolvers, options) { ???????super(); ???????// ...other property ???????this.plugin("factory", () => (result, callback) => { ???????????let resolver = this.applyPluginsWaterfall0("resolver", null); ???????????if (!resolver) return callback(); ???????????resolver(result, (err, data) => { /**/ }); ???????}); ???}}
这里又触发了resolver事件流,同样是构造函数中另外一个plugin的事件。
这节先到这里。
.26-浅析webpack源码之事件流make(1)
原文地址:https://www.cnblogs.com/QH-Jimmy/p/8250774.html