上一节跑到了NormalModuleFactory模块,调用了原型方法create后,依次触发了before-rsolve、factory、resolver事件流,这节从resolver事件流开始讲。

  源码简化如下:

this.plugin("resolver", () => (data, callback) => {
// 来自于create方法
const contextInfo = data.contextInfo;
const context = data.context;
const request = data.request;
// 检测前后缀
// 正则比较简单就不解释了
const noAutoLoaders = /^-?!/.test(request);
const noPrePostAutoLoaders = /^!!/.test(request);
const noPostAutoLoaders = /^-!/.test(request);
let elements = request.replace(/^-?!+/, "").replace(/!!+/g, "!").split("!");
// 传路径的话这里会是['./input.js']
let resource = elements.pop();
// 这里是空数组
elements = elements.map(identToLoaderRequest); asyncLib.parallel([ /**/ ], (err, results) => { /**/ });
});

  第一次进来这个函数传入的是entry,在这里对字符串进行正则校验与切割,一般情况下只会传入口文件路径,官网文档示例也是正常的形式,所以这里暂时无视。

  这里看一下identToLoaderRequest的源码:

// 根据问号切割值与参数
/*
value?opt =>
{
loader: value,
options: opt
}
*/
function identToLoaderRequest(resultString) {
const idx = resultString.indexOf("?");
let options;
if (idx >= 0) {
options = resultString.substr(idx + 1);
resultString = resultString.substr(0, idx);
return {
loader: resultString,
options
};
} else {
return {
loader: resultString
};
}
}

  非常普通的一个参数切割函数。

async.parallel

  接下来的调用引入了nodejs的async模块里面的parallel方法,该方法官网解释如下:

/*
Run the tasks collection of functions in parallel,
without waiting until the previous function has completed.
If any of the functions pass an error to its callback,
the main callback is immediately called with the value of the error.
Once the tasks have completed, the results are passed to the final callback as an array.
*/
asyncLib.parallel([ /*fn1,fn2...*/ ], (err, results) => { /**/ });

  简单来说就是并行调用数组中的方法,将所有方法返回值包装成一个数组(results)传给回调函数,任何一个方法出错会立即执行回调函数并将错误信息作为参数(err)传入。

  这里简要的介绍一下parallel方法源码的核心实现:

/*
https://github.com/caolan/async/blob/master/lib/eachOf.js
*/
/*
coll => 方法数组
iteratee => 迭代器
callback => 回调函数
*/
function eachOfArrayLike(coll, iteratee, callback) {
// 将回调函数包装成只执行一次
// 具体实现可参考jquery源码的一次性事件绑定
callback = once(callback || noop);
var index = 0, // 数组索引
completed = 0, // 已完成函数数量
length = coll.length;
if (length === 0) {
callback(null);
} function iteratorCallback(err, value) {
// 当其中一个函数执行出错立即执行callback
if (err) {
callback(err);
}
// breakLoop为空 无视
// 当所有函数都执行完后调用callback
else if ((++completed === length) || value === breakLoop) {
callback(null);
}
}
// 遍历方法数组
for (; index < length; index++) {
iteratee(coll[index], index, onlyOnce(iteratorCallback));
}
}

  可以看出,callback永远只执行一次,仅当中途执行报错或所有函数都执行完毕。

  如果某一个函数正常执行,则必须调用callback(null,args),其中args就是当前函数的返回值,该值会作为最终回调函数的数组参数之一。

  

  依次直接看数组中的方法:

asyncLib.parallel([
//
callback => this.resolveRequestArray(contextInfo, context, elements, this.resolvers.loader, callback),
//
callback => { /**/ }
], /*callback*/ )

  第一个是调用的原型方法,传入了一溜参数,源码如下:

class NormalModuleFactory extends Tapable {
/*
contextInfo => { issuer: '', compiler:undefined }
context => process.cwd()
array => []
resolver => 来源于WebpackOptionsApply模块中最后compiler.resolvers的设置
callback => 并行执行完成后的回调函数
*/
resolveRequestArray(contextInfo, context, array, resolver, callback) {
// 由于array当前为空数组 所以直接返回
if (array.length === 0) return callback(null, []);
asyncLib.map(array, (item, callback) => { /**/ }, callback);
}
}

  这里会直接返回,返回值为空数组。

  接下来看第二个方法:

callback => {
// resource => './input.js'
if (resource === "" || resource[0] === "?")
return callback(null, {
resource
});
this.resolvers.normal.resolve(contextInfo, context, resource, (err, resource, resourceResolveData) => {
if (err) return callback(err);
callback(null, {
resourceResolveData,
resource
});
});
}

  跳过第一个if判断,继而调用了resolver.normal的resolve方法,传入了3个参数以及一个回调函数。

  下一节分析resolver三个方法的具体实现。

.27-浅析webpack源码之事件流make(2)的更多相关文章

  1. .34-浅析webpack源码之事件流make(3)

    新年好呀~过个年光打游戏,function都写不顺溜了. 上一节的代码到这里了: // NormalModuleFactory的resolver事件流 this.plugin("resolv ...

  2. .23-浅析webpack源码之事件流compilation(1)

    正式开始跑编译,依次解析,首先是: compiler.apply( new JsonpTemplatePlugin(options.output), // start new FunctionModu ...

  3. .21-浅析webpack源码之事件流this-compilation

    上一节生成Compilation实例后,添加了一些属性,随后触发this-compilation事件流,如下: Compiler.prototype.newCompilation = (params) ...

  4. .26-浅析webpack源码之事件流make(1)

    compilation事件流中,依然只是针对细节步骤做事件流注入,代码流程如图: // apply => this-compilation // apply => compilation ...

  5. .24-浅析webpack源码之事件流compilation(2)

    下一个compilation来源于以下代码: compiler.apply(new EntryOptionPlugin()); compiler.applyPluginsBailResult(&quo ...

  6. .22-浅析webpack源码之事件流compilation总览

    呃,终于到了这地方-- newCompilation(params) { // ... this.applyPlugins("this-compilation", compilat ...

  7. .25-浅析webpack源码之事件流compilation(3)

    这一节跑下一批plugin. compiler.apply( new EnsureChunkConditionsPlugin(), new RemoveParentModulesPlugin(), n ...

  8. .37-浅析webpack源码之事件流make(4)

    赶紧完结这个系列咯,webpack4都已经出正式版了. 之前的代码搜索到js文件的对应loader,并添加到了对象中返回,流程如下: this.plugin("factory", ...

  9. 浅析libuv源码-node事件轮询解析(3)

    好像博客有观众,那每一篇都画个图吧! 本节简图如下. 上一篇其实啥也没讲,不过node本身就是这么复杂,走流程就要走全套.就像曾经看webpack源码,读了300行代码最后就为了取package.js ...

随机推荐

  1. /sbin/nologin 和 /bin/false 的区别

    /bin/false是最严格的禁止login选项,一切服务都不能用,而/sbin/nologin只是不允许系统login,可以使用其他ftp等服务 如果想要用false在禁止login的同时允许ftp ...

  2. Java 向下转型

    1.Java 中父类直接向子类转型的不合法的,可以编译但运行时报错. Java中子类直接向父类转型 是合法的,但转型后,可以执行的方法仅限存在于父类中的,在执行时,先看子类的是否有定义,有就执行,没有 ...

  3. Redis在APP中的应用

    前言 redis 是内存型数据库,读取data速度远快于mysql和sqlserver,如果将APP中列表信息或者一些常被访问的信息转存至内存上,然后APP通过redis读取内存上的数据,那么APP的 ...

  4. Java订单功能模块设计与实现

    在商城项目中,之前我们介绍了购物车功能模块的实现,商品加入到购物车之后,就是到购物车结算,然后显示购物车的商品列表,点击去结算,然后到了未提交前的订单列表, 点击提交订单后,生成此订单,返回订单的订单 ...

  5. ADB 安卓开发配置环境

    下载完后将名称中含有adb的文件,和fastboot.exe复制到 c:/windows/system32目录 或c:/windows/system64目录(看自己电脑系统配置 如电脑64操作系统就写 ...

  6. Java语言的概述?-什么是Java? (附一张Java工程师的学习路线图)

    什么是Java? Java是一门面向对象编程语言,不仅吸收了C++语言的各种优点,还摒弃了C++里难以理解的多继承.指针等概念,因此Java语言具有功能强大和简单易用两个特征.Java语言作为静态面向 ...

  7. 利用USearch去除嵌合体(chimeras)

    嵌合体序列指在pcr过程中,两条不同的序列产生杂交扩增的序列,属于人工污染,在ITS和16S分析中,应该首先去除,USearch提供去除嵌合体的功能 usearch -uchime_ref reads ...

  8. Android动画(一)-视图动画与帧动画

    项目中好久没用过动画了,所以关于动画的知识都忘光了.知识总是不用则忘.正好最近的版本要添加比较炫酷的动画效果,所以也借着这个机会,写博客来整理和总结关于动画的一些知识.也方便自己今后的查阅. Andr ...

  9. 获取Windows系统中的所有可用和在用串口

    目的:获取Windows系统中的所有可用和在用串口 方法:注册表查询法 优点:简单.实用.快速.无遗漏,无多余结果. 说明:另外还有8种方法可以枚举串口,但都不如此法. 代码和详细注释如下: //-- ...

  10. 使用Python实现贪心算法

    题目: 圣诞节来临了,在城市A中,圣诞老人准备分发糖果.现在有多箱不同的糖果,每一种糖果都有自己的价值和重量.每箱糖果都可以拆分成任意散装组合带走.圣诞老人的驯鹿最多只能承受一定重量的糖果.请问圣诞老 ...