.33-浅析webpack源码之doResolve事件流(5)
file => FileExistsPlugin
这个事件流快接近尾声了,接下来是FileExistsPlugin,很奇怪的是在最后才来检验路径文件是否存在。
源码如下:
FileExistsPlugin.prototype.apply = function(resolver) { var target = this.target; resolver.plugin(this.source, function(request, callback) { var fs = this.fileSystem; // file => d:\workspace\doc\input.js var file = request.path; fs.stat(file, function(err, stat) { // stat => 文件信息 if (err || !stat) { if (callback.missing) callback.missing.push(file); if (callback.log) callback.log(file + " doesn't exist"); return callback(); } // 是否为文件 if (!stat.isFile()) { if (callback.missing) callback.missing.push(file); if (callback.log) callback.log(file + " is not a file"); return callback(); } // 只做信息提示 不对结果做处理 this.doResolve(target, request, "existing file: " + file, callback, true); }.bind(this)); }); };
这里只是简单的对路径文件进行状态获取,然后判断是否存在?是否是文件?最后调用一个有message的doResolve方法进入到下一个事件流。
existing-file => NextPlugin
这个插件没什么卵用,之前提到过,会直接跳到下一个事件流。
resolved => ResultPlugin
这是最后一个插件,在注入的时候只有一个参数,代表事件流的结尾。
ResultPlugin.prototype.apply = function(resolver) { resolver.plugin(this.source, function(request, callback) { var obj = Object.assign({}, request); // 调用resolver的事件流 resolver.applyPluginsAsyncSeries1("result", obj, function(err) { if (err) return callback(err); callback(null, obj); }); }); };
这里直接调用了resolver的result事件流,并没有通过doResolve方法。
经过测试,这个事件流并不存在,所以会直接调用无参callback,这个callback是什么呢???
找了很久很久,终于找到了,回到最开始的resolve方法中,有个函数:
function onResolve(err, result) { // 无错误情况下调用这个 if (!err && result) { return callback(null, result.path === false ? false : result.path + (result.query || ""), result); } localMissing = []; log = []; // 错误处理 return resolver.doResolve("resolve", obj, message, createInnerCallback(onError, { log: writeLog, missing: localMissing, stack: callback.stack })); }
这里因为成功执行完事件流,第一个参数为null,所以会进入第一个if分支,最后返回的是path与result。
这个callback就简单了,回到了resolve方法的调用地点:
asyncLib.parallel([ callback => this.resolveRequestArray(contextInfo, context, elements, this.resolvers.loader, callback), callback => { if (resource === "" || resource[0] === "?") return callback(null, { resource }); this.resolvers.normal.resolve(contextInfo, context, resource, (err, resource, resourceResolveData) => { // 从这里开始 if (err) return callback(err); /* resource => d:\workspace\doc\input.js resourceResolveData => { context: { issuer: '', compiler: undefined }, path: 'd:\\workspace\\doc\\input.js', request: undefined, query: '', module: false, file: false, descriptionFilePath: 'd:\\workspace\\doc\\package.json', descriptionFileData:{ *配置文件内容* }, descriptionFileRoot: 'd:\\workspace\\doc', relativePath: './input.js', __innerRequest_request: undefined, __innerRequest_relativePath: './input.js', __innerRequest: './input.js' } */ callback(null, { resourceResolveData, resource }); }); } ], (err, results) => { /**/ })
总结
这里对之前的resolve方法所做的流程做一个总结,画一个图。
剔除一些诸如NextPlugin这种垃圾插件以及重复加载的插件,插件加载按顺序,所有的type的before、after均视为一个事件流,特殊分支给给出说明。
老子要日穿V8引擎