.31-浅析webpack源码之doResolve事件流(3)

  放个流程图:

  这里也放一下request对象内容,这节完事后如下(把vue-cli的package.json也复制过来了):

/*{ context: { issuer: '', compiler: undefined },path: 'd:\\workspace\\doc',request: './input.js',query: '',module: false,directory: false,file: false,descriptionFilePath: 'd:\\workspace\\doc\\package.json',descriptionFileData: *package.json内容*,descriptionFileRoot: 'd:\\workspace\\doc',relativePath: '.',__innerRequest_request: './input.js',__innerRequest_relativePath: '.',__innerRequest: './input.js' }
*/

  上一节看到这:

// 调用的是callback()
function innerCallback(err, result) {if (arguments.length > 0) {if (err) return callback(err);if (result) return callback(null, result);return callback();}runAfter();
}

  这里接下来会调用runAfter方法,之前有讲解过这个,简单讲就是触发after-type的事件流,这里的type为parsed-resolve,即触发after-parsed-resolve事件流。

  来源如下:

plugins.push(new NextPlugin("after-parsed-resolve", "described-resolve"));

  这个插件就非常简单了:

NextPlugin.prototype.apply = function(resolver) {var target = this.target;resolver.plugin(this.source, function(request, callback) {resolver.doResolve(target, request, null, callback);});
};

  直接调用doResolve方法触发下一个target的事件流,比起有描述文件的情况,这里的区别就是request少了几个参数,触发下一个事件流时没有message。

 

  刚发现事件流的名字代表着某阶段,此时代表描述文件解析完毕。

  接下来的事件流来源于以下几个插件:

// described-resolve
alias.forEach(function(item) {plugins.push(new AliasPlugin("described-resolve", item, "resolve"));
});
plugins.push(new ConcordModulesPlugin("described-resolve", {}, "resolve"));
aliasFields.forEach(function(item) {plugins.push(new AliasFieldPlugin("described-resolve", item, "resolve"));
});
plugins.push(new ModuleKindPlugin("after-described-resolve", "raw-module"));
plugins.push(new JoinRequestPlugin("after-described-resolve", "relative"));

 

AliasPlugin  

  先从第一个开始看,alias参数引用vue-cli的代码,这里的alias在上面的第二部分进行了转换(具体可参考28节)。

  数组的元素作为参数传入了AliasPlugin插件中,源码如下:

/*
源配置alias: {'vue$': 'vue/dist/vue.esm.js','@': '../src'}
转换后为alias:[{name: 'vue',onlyModule: true,alias: 'vue/dist/vue.esm.js'},{name: '@',onlyModule: false,alias: '../src'           }]
*/
AliasPlugin.prototype.apply = function(resolver) {var target = this.target;var name = this.name;var alias = this.alias;var onlyModule = this.onlyModule;resolver.plugin(this.source, function(request, callback) {var innerRequest = request.request;if (!innerRequest) return callback();// 两个元素传进来并不满足if条件 跳过// startsWith可参考ES6的新方法http://es6.ruanyifeng.com/#docs/string#includes-startsWith-endsWithif (innerRequest === name || (!onlyModule && startsWith(innerRequest, name + "/"))) {if (innerRequest !== alias && !startsWith(innerRequest, alias + "/")) {var newRequestStr = alias + innerRequest.substr(name.length);var obj = Object.assign({}, request, {request: newRequestStr});return resolver.doResolve(target, obj, "aliased with mapping '" + name + "': '" + alias + "' to '" + newRequestStr + "'", createInnerCallback(function(err, result) {if (arguments.length > 0) return callback(err, result);// don't allow other aliasing or raw requestcallback(null, null);}, callback));}}return callback();});
};

  不太懂这里的处理是干什么,反正两个元素传进来都没有满足if条件,跳过。

 

ConcordModulesPlugin

  described-resolve事件流还没有完,所以callback执行后只是记数,下一个插件源码如下:

ConcordModulesPlugin.prototype.apply = function(resolver) {var target = this.target;resolver.plugin(this.source, function(request, callback) {// 获取的还是'./input.js'var innerRequest = getInnerRequest(resolver, request);if (!innerRequest) return callback();// request.descriptionFileData就是配置文件package.json中的内容var concordField = DescriptionFileUtils.getField(request.descriptionFileData, "concord");// 找不到该属性直接返回if (!concordField) return callback();// 下面的都不用跑了var data = concord.matchModule(request.context, concordField, innerRequest);if (data === innerRequest) return callback();if (data === undefined) return callback();if (data === false) {var ignoreObj = Object.assign({}, request, {path: false});return callback(null, ignoreObj);}var obj = Object.assign({}, request, {path: request.descriptionFileRoot,request: data});resolver.doResolve(target, obj, "aliased from description file " + request.descriptionFilePath + " with mapping '" + innerRequest + "' to '" + data + "'", createInnerCallback(function(err, result) {if (arguments.length > 0) return callback(err, result);// Don't allow other aliasing or raw requestcallback(null, null);}, callback));});
};

  这里有两个工具方法:getInnerRequest、getFiled,第一个获取request的inner属性,代码如下:

module.exports = function getInnerRequest(resolver, request) {// 第一次进来是没有这些属性的if (typeof request.__innerRequest === "string" &&request.__innerRequest_request === request.request &&request.__innerRequest_relativePath === request.relativePath)return request.__innerRequest;var innerRequest;// './input.js'if (request.request) {innerRequest = request.request;// 尝试获取relativePath属性进行拼接if (/^\.\.?\//.test(innerRequest) && request.relativePath) {innerRequest = resolver.join(request.relativePath, innerRequest);}} else {innerRequest = request.relativePath;}// 属性添加request.__innerRequest_request = request.request;request.__innerRequest_relativePath = request.relativePath;return request.__innerRequest = innerRequest;
};

  总的来说就是尝试获取__innerRequest属性,但是初次进来是没有的,所以会在后面进行添加,最后返回的仍然是'./input.js'。

  第二个方法就比较简单了,只是从之前读取的package.json对象查询对应的字段,代码如下:

// content为package.json配置对象
function getField(content, field) {if (!content) return undefined;// 数组及单key模式if (Array.isArray(field)) {var current = content;for (var j = 0; j < field.length; j++) {if (current === null || typeof current !== "object") {current = null;break;}current = current[field[j]];}if (typeof current === "object") {return current;}} else {if (typeof content[field] === "object") {return content[field];}}
}

  代码非常简单,这里就不讲了。

  常规情况下,没人会去设置concord属性吧,在vue-cli我也没看到,这里先跳过。

 

AliasFieldPlugin

  接下来是这个不知道干啥的插件,处理的是resolve.aliasFields参数,默认参数及插件源码如下:

// "aliasFields": ["browser"],
AliasFieldPlugin.prototype.apply = function(resolver) {var target = this.target;var field = this.field;resolver.plugin(this.source, function(request, callback) {if (!request.descriptionFileData) return callback();// 一样的var innerRequest = getInnerRequest(resolver, request);if (!innerRequest) return callback();// filed => browservar fieldData = DescriptionFileUtils.getField(request.descriptionFileData, field);if (typeof fieldData !== "object") {if (callback.log) callback.log("Field '" + field + "' doesn't contain a valid alias configuration");return callback();}var data1 = fieldData[innerRequest];var data2 = fieldData[innerRequest.replace(/^\.\//, "")];var data = typeof data1 !== "undefined" ? data1 : data2;if (data === innerRequest) return callback();if (data === undefined) return callback();if (data === false) {var ignoreObj = Object.assign({}, request, {path: false});return callback(null, ignoreObj);}var obj = Object.assign({}, request, {path: request.descriptionFileRoot,request: data});resolver.doResolve(target, obj, "aliased from description file " + request.descriptionFilePath + " with mapping '" + innerRequest + "' to '" + data + "'", createInnerCallback(function(err, result) {if (arguments.length > 0) return callback(err, result);// Don't allow other aliasing or raw requestcallback(null, null);}, callback));});
};

  开头跟之前那个是一样的,也是调用getField从package.json中获取对应的配置,但是这个默认的browser我在vue-cli也找不到,暂时跳过。

 

  正常处理完described-resolve事件流,继续执行runafter触发after-described-resolve事件流,来源如下:

plugins.push(new ModuleKindPlugin("after-described-resolve", "raw-module"));
plugins.push(new JoinRequestPlugin("after-described-resolve", "relative"));

 

ModuleKindPlugin

ModuleKindPlugin.prototype.apply = function(resolver) {var target = this.target;resolver.plugin(this.source, function(request, callback) {// 判断module属性if (!request.module) return callback();var obj = Object.assign({}, request);// 删除module属性delete obj.module;// 直接触发下一个事件流resolver.doResolve(target, obj, "resolve as module", createInnerCallback(function(err, result) {if (arguments.length > 0) return callback(err, result);// Don't allow other alternativescallback(null, null);}, callback));});
};

  这里的处理十分简单,判断request对象是否是module,是则直接触发下一个事件流。

  而在第一次时进来的是入口文件,module属性为false,所以这里会跳过,后面处理module再回来讲。

 

JoinRequestPlugin

JoinRequestPlugin.prototype.apply = function(resolver) {var target = this.target;resolver.plugin(this.source, function(request, callback) {var obj = Object.assign({}, request, {// request.path => d:\\workspace\\doc// request.request => ./input.js// 在join方法中会被拼接成d:\workspace\doc\.\input.js// 最后格式化返回d:\workspace\doc\input.js
            path: resolver.join(request.path, request.request),// undefinedrelativePath: request.relativePath && resolver.join(request.relativePath, request.request),request: undefined});resolver.doResolve(target, obj, null, callback);});
};

  这个地方终于把入口文件的路径拼起来了,接下来调用下一个事件流,这节先到这里。

 

  写完这节,总算对Resolver对象有所了解,总结如下:

1、该对象可以处理resolve参数、loader、module等等

2、插件的链式调用类似于if/else,比如说如果传进来的是一个module,插件会流向module事件流;如果是普通的文件,会流向本节所讲的方,每一种情况都有自己的结局。

3、一部分参数处理依赖于package.json的配置对象内容

转载于:https://www.cnblogs.com/QH-Jimmy/p/8340639.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/354187.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

c++ 虚函数,纯虚函数的本质区别

转载博客&#xff1a;https://mp.weixin.qq.com/s?__bizMzAxNzYzMTU0Ng&amp;mid2651289202&amp;idx1&amp;sn431ffd1fae4823366a50b68aed2838d4&amp;chksm80114627b766cf31f72018ef5f1fe29591e9f6f4bd72018e7aea849342ca6f0a271fb38465ae#rd 学习C的多态性&…

云通讯短信验证码实例

1.注册登录云通讯 http://www.yuntongxun.com/user/login 2.创建应用得到应用相关信息 3.下载对应相关的Demo示例  http://www.yuntongxun.com/doc/rest/sms/3_2_2_3.html 4.send.php文件添加代码方便后续操作 session_start(); //随机验证码 $code rand(100000,999999)…

java 数组 内存_图解Java数组的内存分配

1. Java数组是静态的Java是静态语言&#xff0c;所以Java的数组也是静态的&#xff0c;即&#xff1a;数组被初始化后&#xff0c;长度不可变静态初始化&#xff1a;显式指定每个数组元素的初始值&#xff0c;系统决定数组长度String[] books new String[]{"疯狂Java讲义…

libgdx和Kotlin –类[2D平台原型]

这篇文章是libgdx和Kotlin文章的后续文章。 我已经决定开发一个简单的2D平台程序的原型&#xff08;沿着我的早期文章中的Star Assault进行介绍&#xff09;&#xff0c;但是我一直在使用和学习Kotlin&#xff0c;而不是Java。 对于本教程&#xff0c;该项目应处于上一篇文章…

spring jmx_JMX和Spring –第2部分

spring jmx这篇文章从本教程的第1部分继续。 嗨&#xff0c;在我的上一篇文章中&#xff0c;我解释了如何通过Spring设置JMX服务器以及如何通过身份验证和授权保护对它的访问。 在本文中&#xff0c;我将展示如何实现一个简单的MBean&#xff0c;该MBean允许用户在运行时更改L…

LeetCode:位运算实现加法

LeetCode&#xff1a;位运算实现加法 写在前面 位运算符 实现加法的思路 两个加数&#xff0c;比如5(101)和6(110)&#xff0c;如何不用加法就能得出两者之和呢&#xff1f; 我们知道二进制计算中&#xff0c;如果使用异或将会产生无进位的两者之和&#xff0c;而两数相与将会产…

[机器学习] 模型评价参数,准确率,召回率,F1-score

很久很久以前&#xff0c;我还是有个建筑梦的大二少年&#xff0c;有一天&#xff0c;讲图的老师看了眼我的设计图&#xff0c;说&#xff1a;“我觉得你这个设计做得很紧张”&#xff0c;当时我就崩溃&#xff0c;对紧张不紧张这样的评价标准理解无能。多年后我终于明白老师当…

java记录登陆时间_Spring security如何实现记录用户登录时间功能

一、原理分析spring security提供了一个接口 AuthenticationSuccessHandler,该接口中只有一个方法&#xff0c;用来进行登录成功后的操作public interface AuthenticationSuccessHandler {/*** Called when a user has been successfully authenticated.** param request the r…

bzoj3680

$模拟退火$ $这种全局最优的问题用模拟退火$ $模拟退火就是每次向四周随机移动&#xff0c;移动的幅度和温度成正比&#xff0c;如果新的位置更优就接受&#xff0c;否则按一定概率接收&#xff0c;概率和温度成正比$ $最后稳定后再在最优解附近蹦跶几下看看有没有更好的$ $你问…

01背包(修订版)

由于时间比较充裕&#xff0c;重新修订一部分。 这次把一些补充的放进来&#xff0c;其他的基础说明见后半部分 这些一共说明&#xff1a;01背包、完全背包、多重背包 将会详细说明。 三种背包混合、二维背包、分组背包、依赖背包、泛化背包 将大致说明。 01背包 如上次说明一…

java 马踏棋盘优化_我所知道的十大常用算法之马踏棋盘算法(深度搜索、贪心思想优化 )...

前言需求今天我们学习的是马踏棋盘算法&#xff0c;我们还是从一个场景里引入看看马踏棋盘算法也被称为骑士周游问题将马随机放在国际象棋的66棋盘Board0&#xff5e;5的某个方格中提示&#xff1a;马按走棋规则(马走日字)进行移动要求&#xff1a;每个方格只进入一次&#xff…

app engine_App Engine中的Google Services身份验证,第2部分

app engine在本教程的第一部分中&#xff0c; 我介绍了如何使用OAuth进行Google API服务的访问/身份验证。 不幸的是&#xff0c;正如我稍后发现的那样&#xff0c;我使用的方法是OAuth 1.0&#xff0c;显然现在Google正式弃用了OAuth 1.0&#xff0c;改用OAuth 2.0版本。 显然…

Django知识总结(一)

壹 ● 有关http协议 一 ● 全称 超文本传输协议(HyperText Transfer Protocol) 二 ● 协议 双方遵循的规范 http协议是属于应用层的协议(还有ftp, smtp等), 即浏览器请求消息和服务器响应消息的一系列规则 三 ● http协议的特性 http是无状态、无连接的协议(stateless, connect…

mysql+if+x+mod+2_Windows 下 MantisBT 2.X + Apache 2.4 + PHP 7 + MySQL 5.7 的环境配置

Apache 2.4.25~ Visual C Redistributable for Visual Studio 2015PHP 7.1.3~ mod_fcgid-2.3.9Mantisbt-2.2.1MySQL Database 5.7.17~ NET Framework 3.5安装 Apache前期准备1.若计算机已安装了 Apache2.4 以前的版本&#xff0c;请自行卸载并删除安装目录。2.以管理员身份运行…

如何在Java中对文件进行模式匹配和显示相邻行

最近&#xff0c;我们在jOOλ0.9.9中发布了有关超棒的窗口函数支持的文章 &#xff0c;我相信这是对我们所做的库的最佳补充。 今天&#xff0c;我们将在一个用例中研究窗口函数的出色应用&#xff0c;该用例受到以下堆栈溢出问题Sean Nguyen的启发&#xff1a; 如何从Java 8…

64位内核第二讲,进程保护之对象钩子

64位内核第二讲,进程保护. 一丶什么是保护. 什么是保护. 比如我们安装了xxx杀毒软件.那么此时你用任务管理器关闭.是关闭不了的.原因是内核已经做了保护. 那么去掉保护的前提就是你要给自己的软件做保护. 比如我们给计算器做保护. 例如下图. 做保护.以前的病毒作者.都是想要退出…

jpql hql_无需部署即可测试JPQL / HQL

jpql hql您是否曾经想在不完全部署应用程序的情况下测试JPQL / HQL&#xff1f; 我们今天在这里看到的是适用于任何JPA实现的简单解决方案&#xff1a;Hibernate&#xff0c;OpenJPA&#xff0c;EclipseLink等。 这篇文章中找到的基本源代码来自本书&#xff1a;“ Pro JPA 2&a…

eclipse 代码上传github 笔记

第一步 先share project 如图所示 第二步 如果所示 第三步 点击 下面的create 然后点击完成 第四步提交 第五步&#xff1a; 第六步&#xff1a; 转载于:https://www.cnblogs.com/a8457013/p/8410471.html

Keycloak SSO集成到jBPM和Drools Workbench中

介绍 单一登录&#xff08;SSO&#xff09;和相关令牌交换机制正在成为Web上不同环境中进行身份验证和授权的最常见方案&#xff0c;尤其是在迁移到云中时。 本文讨论了Keycloak与jBPM或Drools应用程序的集成&#xff0c;以便使用Keycloak上提供的所有功能。 Keycloak是用于浏…

接口 java性能_接口测试性能测试

接口测试 接口测试是测试系统组件间接口的一种测试&#xff0c;主要用于检测外部系统与系统之间以及内部各个子系统之间的交互点。测试的重点是要检查数据的交换&#xff0c;传递和控制管理过程&#xff0c;以及系统间的相互逻辑依赖关系等。 原理 通过测试程序模拟客户端向服务…