.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均视为一个事件流,特殊分支给给出说明。

.33-浅析webpack源码之doResolve事件流(5)的更多相关文章
- .30-浅析webpack源码之doResolve事件流(1)
这里所有的插件都对应着一个小功能,画个图整理下目前流程: 上节是从ParsePlugin中出来,对'./input.js'入口文件的路径做了处理,返回如下: ParsePlugin.prototype ...
- .30-浅析webpack源码之doResolve事件流(2)
这里所有的插件都对应着一个小功能,画个图整理下目前流程: 上节是从ParsePlugin中出来,对'./input.js'入口文件的路径做了处理,返回如下: ParsePlugin.prototype ...
- .29-浅析webpack源码之doResolve事件流(1)
在上一节中,最后返回了一个resolver,本质上就是一个Resolver对象: resolver = new Resolver(fileSystem); 这个对象的构造函数非常简单,只是简单的继承了 ...
- .31-浅析webpack源码之doResolve事件流(2)
放个流程图: 这里也放一下request对象内容,这节完事后如下(把vue-cli的package.json也复制过来了): /* { context: { issuer: '', compiler: ...
- .32-浅析webpack源码之doResolve事件流(4)
流程图如下: 重回DescriptionFilePlugin 上一节最后进入relative事件流,注入地点如下: // relative plugins.push(new DescriptionFi ...
- .34-浅析webpack源码之事件流make(3)
新年好呀~过个年光打游戏,function都写不顺溜了. 上一节的代码到这里了: // NormalModuleFactory的resolver事件流 this.plugin("resolv ...
- 浅析libuv源码-node事件轮询解析(3)
好像博客有观众,那每一篇都画个图吧! 本节简图如下. 上一篇其实啥也没讲,不过node本身就是这么复杂,走流程就要走全套.就像曾经看webpack源码,读了300行代码最后就为了取package.js ...
- .27-浅析webpack源码之事件流make(2)
上一节跑到了NormalModuleFactory模块,调用了原型方法create后,依次触发了before-rsolve.factory.resolver事件流,这节从resolver事件流开始讲. ...
- .17-浅析webpack源码之compile流程-入口函数run
本节流程如图: 现在正式进入打包流程,起步方法为run: Compiler.prototype.run = (callback) => { const startTime = Date.now( ...
随机推荐
- cudnn 安装步骤
上官网下载对应的cudnn https://developer.nvidia.com/cudnn 下载完cudnn后,命令行输入文件所在的文件夹 (ubuntu为本机用户名) cd home/ubun ...
- [C++基础]队列<queue>中的常用函数
在C++中只要#include<queue>即可使用队列类,其中在面试或笔试中常用的成员函数如下(按照最常用到不常用的顺序) 1. push 2. pop 3. size 4. empty ...
- Java虚拟机7:垃圾收集(GC)-2(并行和并发的区别)
1.并发编程下 这两个名词都是并发编程中的概念,在并发编程的模型下的定义: 并发:是在同一个cpu上同时(不是真正的同时,而是看来是同时,因为cpu要在多个程序间切换)运行多个程序. 并行:是多个或同 ...
- C++调用API获取当前时间
#include <string> #include<iostream> #include<windows.h> #include <sstream> ...
- 简单题(K-D Tree)
简单题不简单-- 我们把单点加操作改成插入一个权值为增加量的点,将问题转化成询问一个矩阵中所有点的和,用 \(K-D\ Tree\) 维护,时间复杂度 \(O(n\sqrt{n})\) \(Code\ ...
- elasticsearch插件一head插件安装详解
elasticsearch-head是一个用来浏览.与Elastic Search簇进行交互的web前端展示插件. elasticsearch-head插件主要用途: elasticsearch主要有 ...
- OS之内存管理 --- 虚拟内存管理(二)
关于虚拟内存管理之前的请看:OS之内存管理 - 虚拟内存管理(一) 帧分配 每个进程对的最小帧数是由操作系统的体系结构决定的,但是最大帧数是由可用物理内存的数量决定的.所以在这之间,对于进程的帧的分配 ...
- centos7 初始化脚本
#!/bin/bash # 时间: 2018-11-21 # 作者: HuYuan # 描述: CentOS 7 初始化脚本 # 加载配置文件 if [ -n "${1}" ];t ...
- 基于GTK+3 开发远程控制管理软件(C语言实现)系列二 Centos7下开发环境搭建
一.安装gcc gcc-c++ make等编译工具 yum install gcc gcc-c++ kernel-devel 这一步,其实可以不用做,你在安装Centos7的时候,如果选择开发模式安装 ...
- Java实现二叉树先序,中序,后序,层次遍历
一.以下是我要解析的一个二叉树的模型形状.本文实现了以下方式的遍历: 1.用递归的方法实现了前序.中序.后序的遍历: 2.利用队列的方法实现层次遍历: 3.用堆栈的方法实现前序.中序.后序的遍历. . ...