.17-浅析webpack源码之compile流程-入口函数run
本节流程如图:
现在正式进入打包流程,起步方法为run:
Compiler.prototype.run = (callback) => {
const startTime = Date.now(); const onCompiled = (err, compilation) => { /**/ }; this.applyPluginsAsync("before-run", this, err => {
if (err) return callback(err); this.applyPluginsAsync("run", this, err => {
if (err) return callback(err); this.readRecords(err => {
if (err) return callback(err); this.compile(onCompiled);
});
});
});
}
为什么不介绍compiler对象?因为构造函数中并没有一个初始化的方法,只是普通的变量声明,没啥好讲的。
在run方法中,首先是调用了tapable的applyPluginsAsync执行了before-run事件流,该事件流的定义地点如下:
// NodeEnvironmentPlugin
compiler.plugin("before-run", (compiler, callback) => {
if (compiler.inputFileSystem === inputFileSystem)
inputFileSystem.purge();
callback();
});
在对compiler对象的文件系统方法的挂载插件中,注入了before-run这个事件流,这里首先看一下applyPluginsAsync(做了小幅度的修改以适应webpack源码):
// tapable
Tapable.prototype.applyPluginsAsync = (name, ...args, callback) => {
var plugins = this._plugins[name];
if (!plugins || plugins.length === 0) return callback();
var i = 0;
var _this = this;
// args为[args,next函数]
args.push(copyProperties(callback, function next(err) {
// 事件流出错或者全部执行完后调用回调函数
if (err) return callback(err);
i++;
if (i >= plugins.length) {
return callback();
}
// 执行下一个事件
plugins[i].apply(_this, args);
}));
// 执行第一个事件
plugins[0].apply(this, args);
};
当时在第八节没有讲这个系列的事件流触发方式,这里简单说下:
1、copyProperties用于对象属性的拷贝,类似于Object.assign,然而在这里传入的是两个函数,一点用都没有!!!!!(当时没写讲解就是因为一直卡在这个对象拷贝方法在这里有什么毛用)
2、在webpack中,args为一个this,指向compiler的上下文
3、注入该事件流的事件必须要执行callback方法(如上例),此时执行的并不是外部的callback,而是next函数
4、有两种情况下会执行外部callback,中途出错或者所有事件流执行完毕
这样就很明白了,注入before-run中的函数形参的意义如下:
// before-run
// compiler => this
// callback => next
(compiler, callback) => {
if (compiler.inputFileSystem === inputFileSystem)
inputFileSystem.purge();
callback();
}
由于before-run中只有一个事件,所以在调用内部callback的next方法后,会由于i大于事件长度而直接调用外部callback。
这里的purge方法之前见过,这里复习下内容:
// NodeEnvironmentPlugin
compiler.inputFileSystem = new CachedInputFileSystem(new NodeJsInputFileSystem(), 60000); // CachedInputFileSystem
CachedInputFileSystem.prototype.purge = function(what) {
this._statStorage.purge(what);
this._readdirStorage.purge(what);
this._readFileStorage.purge(what);
this._readlinkStorage.purge(what);
this._readJsonStorage.purge(what);
}; // CachedInputFileSystem => Storage
Storage.prototype.purge = function(what) {
if (!what) {
this.count = 0;
clearInterval(this.interval);
this.nextTick = null;
this.data.clear();
this.levels.forEach(function(level) {
level.clear();
});
} else if (typeof what === "string") { /**/ } else { /**/ }
};
一句话概括就是:清除所有打包中缓存的数据。
由于假设是第一次,所以这里并没有什么实际操作,接着调用外部callback,用同样的方式触发了run事件流。
run事件流也只有一个方法,来源于CachePlugin插件:
Compiler.plugin("run", (compiler, callback) => {
// 这个属性我暂时也不知道是啥 反正直接callback了
if (!compiler._lastCompilationFileDependencies) return callback();
const fs = compiler.inputFileSystem;
const fileTs = compiler.fileTimestamps = {};
asyncLib.forEach(compiler._lastCompilationFileDependencies, (file, callback) => {
// ...
}, err => {
// ...
});
});
在第一次触发run事件流时,那个属性是undefined,所以会直接跳过,因为我是边看源码边解析,所以也不知道是啥,哈哈。
接下来下一个callback是这个:
this.readRecords(err => {
if (err) return callback(err);
this.compile(onCompiled);
});
这是另一个原型方法,源码如下:
Compiler.prototype.readRecords = (callback) => {
// 这个属性也没有
if (!this.recordsInputPath) {
this.records = {};
return callback();
}
this.inputFileSystem.stat(this.recordsInputPath, err => {
// ...
});
}
这里第一次也会跳过并直接callback,看源码大概是传入一个路径并读取里面的文件信息缓存到records中。
这下连跳两步,直接进入原型方法compile中,预览一下这个函数:
Compiler.prototype.compile = (callback) => {
const params = this.newCompilationParams();
// 依次触发事件流
this.applyPluginsAsync("before-compile", params, err => {
if (err) return callback(err);
this.applyPlugins("compile", params);
const compilation = this.newCompilation(params);
this.applyPluginsParallel("make", compilation, err => {
if (err) return callback(err);
compilation.finish();
compilation.seal(err => {
if (err) return callback(err);
this.applyPluginsAsync("after-compile", compilation, err => {
if (err) return callback(err);
return callback(null, compilation);
});
});
});
});
}
编译打包的核心流程已经一览无遗,方法中依次触发了before-compile、compile、make、after-compile事件流,最后调用了回调函数。
从下一节开始详细讲解每一步的流程(不懂的地方肯定会跳过啦)。
.17-浅析webpack源码之compile流程-入口函数run的更多相关文章
- .20-浅析webpack源码之compile流程-Template模块
这里的编译前指的是开始触发主要的事件流this-compilaiton.compilation之前,由于还有一些准备代码,这一节全部弄出来. 模块基本上只走构造函数,具体的方法调用的时候再具体讲解. ...
- .18-浅析webpack源码之compile流程-rules参数处理(1)
Tips:写到这里,需要对当初的规则进行修改.在必要的地方,会在webpack.config.js中设置特殊的参数来跑源码,例如本例会使用module:{rules:[...]}来测试,基本上测试参数 ...
- .19-浅析webpack源码之compile流程-rules参数处理(2)
第一步处理rule为字符串,直接返回一个包装类,很简单看注释就好了. test/include/exclude 然后处理test.include.exclude,如下: if (rule.test | ...
- 51ak带你看MYSQL5.7源码1:main入口函数
从事DBA工作多年 MYSQL源码也是头一次接触 尝试记录下自己看MYSQL5.7源码的历程 目录: 51ak带你看MYSQL5.7源码1:main入口函数 51ak带你看MYSQL5.7源码2:编译 ...
- 从Webpack源码探究打包流程,萌新也能看懂~
简介 上一篇讲述了如何理解tapable这个钩子机制,因为这个是webpack程序的灵魂.虽然钩子机制很灵活,而然却变成了我们读懂webpack道路上的阻碍.每当webpack运行起来的时候,我的心态 ...
- async源码学习 - 控制流程waterfall函数
waterfall函数会连续执行数组中的函数,每次通过数组下一个函数的结果.然而,数组任务中的任意一个函数结果传递失败,那么该函数的下一个函数将不会执行,并且主回调函数立马把错误作为参数执行. 以上是 ...
- .34-浅析webpack源码之事件流make(3)
新年好呀~过个年光打游戏,function都写不顺溜了. 上一节的代码到这里了: // NormalModuleFactory的resolver事件流 this.plugin("resolv ...
- jQuery 2.0.3 源码分析Sizzle引擎 - 编译函数(大篇幅)
声明:本文为原创文章,如需转载,请注明来源并保留原文链接Aaron,谢谢! 从Sizzle1.8开始,这是Sizzle的分界线了,引入了编译函数机制 网上基本没有资料细说这个东东的,sizzle引入这 ...
- .29-浅析webpack源码之Resolver.prototype.resolve
在上一节中,最后返回了一个resolver,本质上就是一个Resolver对象: resolver = new Resolver(fileSystem); 这个对象的构造函数非常简单,只是简单的继承了 ...
随机推荐
- [杂谈] 一个关于 as 的小测试
代码如下: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 procedure TForm1.Button1Click(Sender: TObject); va ...
- Linux-用户及权限
1. 用户组 RHEL 7/CentOS 7系统中的用户组有如下3类: 超级用户,UID 0:系统的超级用户. 系统用户,UID 1-999:系统中系统服务由不同用户运行,更加安全,默认被限制不能登录 ...
- C#中解析JSON数据,并获取到其中的值
1.应需求创建一个Json字符串 string json = "[{'Name':'张三','age':'20','Data':{'ID':100,'heigh':'180','weight ...
- StriveEngine-TCP
文章中的StriveEngine.dll版本为V3.9.0.0,源码下载请到 https://download.csdn.net/download/hanghangz/10966335 先上代码,建立 ...
- Stm32ADC-内部温度传感器的使用
搞完了ADC的基本配置步骤,下面就是ADC配合一些外设的应用了,首先就是stm32f1内部的温度传感器通过adc采集获得温度; 内部温度传感器在ADC1的通道16上,所以只需要初始化以下ADC1就好了 ...
- 添加vscode自定义代码块
以vue为例 一.打开vscode>文件>首选项>用户代码片段>vue.json二.编写代码块 其中一行一句:$1是占位符,就是你可以输入的地方."http get& ...
- js怎么样根据select的name取到值
先看一下ASP.NET MVC的html: 在jQuery中,可以写:
- pycharm光标变成黑框,恢复成竖线
pycharm光标变成黑框,如下图所示 解决办法: 按外接键盘上的Insert键,即可恢复.
- PHP进行数据库操作时遇到的一个问题
PHP进行数据库操作时遇到的一个问题 昨天在进行数据库操作时,遇到了一个问题(用的是 wampserver 环境): <?php $link = @mysqli_connect('localho ...
- drf-视图的理解
1. 类视图 写视图的步骤: 1. 数据库查询, 2. 构建序列化器, 进行序列化操作, 返回数据 一. 两大基类 >1 APIView (以常规的方法实现get po ...