细说webpack源码之compile流程-入口函数run


Posted in Javascript onDecember 26, 2017

Webpack是目前基于React和Redux开发的应用的主要打包工具。我想使用Angular 2或其他框架开发的应用也有很多在使用Webpack。

本节流程如图:

细说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事件流,最后调用了回调函数。

总结

以上所述是小编给大家介绍的webpack源码之compile流程-入口函数run,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对三水点靠木网站的支持!

Javascript 相关文章推荐
制作高质量的JQuery Plugin 插件的方法
Apr 20 Javascript
JavaScript中把数字转换为字符串的程序代码
Jun 19 Javascript
JavaScript改变HTML元素的样式改变CSS及元素属性
Nov 12 Javascript
js判断文本框剩余可输入字数的方法
Feb 04 Javascript
用jQuery获取table中行id和td值的实现代码
May 19 Javascript
wap手机端解决返回上一页的js实例
Dec 08 Javascript
jQuery插件HighCharts绘制2D金字塔图效果示例【附demo源码下载】
Mar 09 Javascript
vue.js中created方法作用
Mar 30 Javascript
从0到1搭建Element的后台框架的方法步骤
Apr 10 Javascript
Vue在 Nuxt.js 中重定向 404 页面的方法
Apr 23 Javascript
vuex state中的数组变化监听实例
Nov 06 Javascript
在Vue 中实现循环渲染多个相同echarts图表
Jul 20 Javascript
Vue 进入/离开动画效果
Dec 26 #Javascript
node.js中路由,中间件,ge请求和post请求的参数详解
Dec 26 #Javascript
Angular实现可删除并计算总金额的购物车功能示例
Dec 26 #Javascript
浅谈React深度编程之受控组件与非受控组件
Dec 26 #Javascript
使用vue实现简单键盘的示例(支持移动端和pc端)
Dec 25 #Javascript
vue的一个分页组件的示例代码
Dec 25 #Javascript
jQuery图片查看插件Magnify开发详解
Dec 25 #jQuery
You might like
留言板翻页的实现详解
2006/10/09 PHP
oracle资料库函式库
2006/10/09 PHP
Discuz!5的PHP代码高亮显示插件(黑暗中的舞者更新)
2007/01/29 PHP
php的mkdir()函数创建文件夹比较安全的权限设置方法
2014/07/28 PHP
php提供实现反射的方法和实例代码
2019/09/17 PHP
基于jQuery的投票系统显示结果插件
2011/08/12 Javascript
javascript 使td内容不换行不撑开
2012/11/29 Javascript
jquery五角星评分插件示例分享
2014/02/21 Javascript
javascript鼠标滑动评分控件完整实例
2015/05/13 Javascript
javascript中的previousSibling和nextSibling的正确用法
2015/09/16 Javascript
JavaScript实现瀑布流布局
2020/06/28 Javascript
基于JQuery的$.ajax方法进行异步请求导致页面闪烁的解决办法
2016/05/10 Javascript
jQuery实现弹窗居中效果类似alert()
2017/02/27 Javascript
bootstrap Table的一些小操作
2017/11/01 Javascript
Vuex 在Vue 组件中获得Vuex 状态state的方法
2018/08/27 Javascript
谈谈我在vue-cli3中用预渲染遇到的坑
2020/04/22 Javascript
Python作用域用法实例详解
2016/03/15 Python
Python网络编程之TCP与UDP协议套接字用法示例
2018/02/02 Python
[原创]Python入门教程3. 列表基本操作【定义、运算、常用函数】
2018/10/30 Python
python字典的遍历3种方法详解
2019/08/10 Python
大家都说好用的Python命令行库click的使用
2019/11/07 Python
在django中自定义字段Field详解
2019/12/03 Python
详解字符串在Python内部是如何省内存的
2020/02/03 Python
spyder 在控制台(console)执行python文件,debug python程序方式
2020/04/20 Python
实例讲解Python 迭代器与生成器
2020/07/08 Python
css3学习之2D转换功能详解
2016/12/23 HTML / CSS
css3实现超炫风车特效
2014/11/12 HTML / CSS
海蓝之谜(LA MER)澳大利亚官方商城:全球高端奢华护肤品牌
2017/10/27 全球购物
读书心得体会
2013/12/28 职场文书
司机检讨书
2014/02/13 职场文书
丧事主持词大全
2014/04/02 职场文书
平安校园建设方案
2014/05/02 职场文书
责任书格式范文
2014/07/28 职场文书
2015年护士节活动策划方案
2015/05/04 职场文书
海洋天堂观后感
2015/06/05 职场文书
2019年怎样才能撰写出优秀的自荐信
2019/03/25 职场文书