本节流程如图:

  现在正式进入打包流程,起步方法为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事件流,最后调用了回调函数。

  从下一节开始详细讲解每一步的流程(不懂的地方肯定会跳过啦)。

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

.17-浅析webpack源码之compile流程-入口函数run相关推荐

  1. 从 Element UI 源码的构建流程看前端 UI 库设计

    引言 由于业务需要,近期团队要搞一套自己的UI组件库,框架方面还是Vue.而业界已经有比较成熟的一些UI库了,比如ElementUI.AntDesign.Vant等. 结合框架Vue,我们选择在Ele ...

  2. webpack源码解析七(optimization)

    前言 前面我们写了几篇文章用来介绍webpack源码,跟着官网结合demo把整个webpack配置撸了一遍: webpack源码解析一 webpack源码解析二(html-webpack-plugin ...

  3. webpack 源码分析(四)——complier模块

    webpack 源码分析(四)--complier模块 上一篇我们看到,webpack-cli 通过 yargs 对命令行传入的参数和配置文件里的配置项做了转换包装,然后传递给 webpack 的 c ...

  4. webpack 源码分析系列 ——loader

    想要更好的格式阅读体验,请查看原文:webpack 源码分析系列 --loader 为什么需要 loader webpack是一个用于现代 JavaScript 应用程序的静态模块打包工具.内部通过构 ...

  5. webpack源码阅读——npm脚本运行webpack与命令行输入webpack的区别

    原文地址:webpack源码阅读--npm脚本执行webpack与命令行输入webpack执行的区别 如有错误,欢迎指正! webpack是目前被大家广为使用的模块打包器.从命令行输入webpack或 ...

  6. 渣渣菜鸡的 ElasticSearch 源码解析 —— 启动流程(上)

    关注我 转载请务必注明原创地址为:http://www.54tianzhisheng.cn/2018/08/11/es-code02/ 前提 上篇文章写了 ElasticSearch 源码解析 -- ...

  7. 【Android 启动过程】Activity 启动源码分析 ( ActivityThread 流程分析 二 )

    文章目录 前言 一.ActivityManagerService.attachApplicationLocked 二.ActivityStackSupervisor.attachApplication ...

  8. [系统安全] 六.逆向分析之条件语句和循环语句源码还原及流程控制

    您可能之前看到过我写的类似文章,为什么还要重复撰写呢?只是想更好地帮助初学者了解病毒逆向分析和系统安全,更加成体系且不破坏之前的系列.因此,我重新开设了这个专栏,准备系统整理和深入学习系统安全.逆向分 ...

  9. [安全攻防进阶篇] 四.逆向分析之条件语句和循环语句源码还原及流程控制逆向

    从2019年7月开始,我来到了一个陌生的专业--网络空间安全.初入安全领域,是非常痛苦和难受的,要学的东西太多.涉及面太广,但好在自己通过分享100篇"网络安全自学"系列文章,艰难 ...

最新文章

  1. js老生常谈之this,constructor ,prototype
  2. C语言程序练习-L1-030 一帮一 (15分)
  3. 姑娘,你为什么要编程?
  4. 遗传算法锦标赛选择java实现_java – 遗传算法锦标赛选择
  5. 园龄一年了,可还未动笔.
  6. 史上最强春节红包战:互联网竞争缩影下的百亿争斗
  7. DataGridView 设置行不可见时,与货币管理器的位置关联的行不能设置为不可见
  8. 子组件向父组件传值_vue父子组件传值
  9. POJ 2429 GCD LCM Inverse(Miller-Rabbin素性测试,Pollard rho质因子分解)
  10. “代理XP”组件已作为此服务器安全配置的一部分被关闭
  11. 叶三《我们唱》-野孩子(白银饭店)
  12. 汇编语言编译器 masm.exe and link.exe
  13. 安卓仿苹果音量调节_安卓不仿苹果静音键?千万别小瞧“静音键”, 功能强悍到无敌!...
  14. 【Python • 图片识别】pytesseract快速识别提取图片中的文字
  15. 摄像头视频推流python_python中用FFmpeg向rtmp服务器推流,实现摄像头直播
  16. ACM入门题:幼儿园买玩具-Go语言
  17. 通达信指标公式绘图函数简介——自定义指标颜色、线型等
  18. 我的世界html启动器资源,我的世界hmcl启动器mod
  19. iOS 动画 - 从不会到熟练应用
  20. C语言中的截断与整型提升

热门文章

  1. ultraMaskedEdit使用心得
  2. WPF以Clickonce方式发布后使用管理员身份运行
  3. nginx反向代理nexus私服
  4. HDOJ 1874 HDU 1874 畅通工程续 ACM 1874 IN HDU
  5. 手机app 有没有window.location.href_热议小程序使用场景越来越多,未来有没有可能替代手机APP?...
  6. 特征值与特征向量_矩阵的特征值和特征向量
  7. python有道自动翻译_Python 调用有道翻译接口实现翻译
  8. js vm报错_uni-app v3版本更新常见问题排查
  9. unity android本地推送,Unity安卓本地推送
  10. freebasic 编译linux,免费BASIC编译器下载