细说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 相关文章推荐
JavaScript delete 属性的使用
Oct 08 Javascript
js压缩工具 yuicompressor 使用教程
Mar 31 Javascript
JavaScript中双叹号!!作用示例介绍
Sep 21 Javascript
jquery 根据name名获取元素的value值
Feb 27 Javascript
javascript实现粘贴qq截图功能(clipboardData)
May 29 Javascript
Javascript DOM事件操作小结(监听鼠标点击、释放,悬停、离开等)
Jan 20 Javascript
完美的js图片轮换效果
Feb 05 Javascript
bootstrap手风琴折叠示例代码分享
May 22 Javascript
JS实现遍历不规则多维数组的方法
Mar 21 Javascript
在AngularJs中设置请求头信息(headers)的方法及不同方法的比较
Sep 04 Javascript
Vue在页面数据渲染完成之后的调用方法
Sep 11 Javascript
vue的路由映射问题及解决方案
Oct 14 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
ThinkPHP中关联查询实例
2014/12/02 PHP
PHP简单实现冒泡排序的方法
2016/12/26 PHP
php把字符串指定字符分割成数组的方法
2018/03/12 PHP
div+css布局的图片连续滚动js实现代码
2010/05/04 Javascript
javascript的字符串按引用复制和传递,按值来比较介绍与应用
2012/12/28 Javascript
兼容IE和FF的图片上传前预览js代码
2013/05/28 Javascript
轻量级网页遮罩层jQuery插件用法实例
2015/07/31 Javascript
基于JS实现EOS隐藏错误提示层代码
2016/04/25 Javascript
jQuery日程管理插件fullcalendar使用详解
2017/01/07 Javascript
Avalonjs 实现简单购物车功能(实例代码)
2017/02/07 Javascript
jQuery为DOM动态追加事件的方法
2017/02/16 Javascript
Bootstrap表单控件学习使用
2017/03/07 Javascript
nodejs+mongodb+vue前后台配置ueditor的示例代码
2018/01/02 NodeJs
解决Layui 表单提交数据为空的问题
2018/08/15 Javascript
vue3.0 CLI - 2.2 - 组件 home.vue 的初步改造
2018/09/14 Javascript
layui使用label标签的方法
2019/09/14 Javascript
浅析vue中的provide / inject 有什么用处
2019/11/10 Javascript
javascript 易错知识点实例小结
2020/04/25 Javascript
JavaScript 类的封装操作示例详解
2020/05/16 Javascript
分享6个隐藏的python功能
2017/12/07 Python
python使用正则筛选信用卡
2019/01/27 Python
python实现在内存中读写str和二进制数据代码
2020/04/24 Python
使用Keras预训练好的模型进行目标类别预测详解
2020/06/27 Python
Python改变对象的字符串显示的方法
2020/08/01 Python
Django权限控制的使用
2021/01/07 Python
使用Python+Appuim 清理微信的方法
2021/01/26 Python
HTML5自定义属性的问题分析
2019/08/16 HTML / CSS
微软日本官方网站:Microsoft日本
2017/11/26 全球购物
TripAdvisor西班牙官方网站:全球领先的旅游网站
2018/01/10 全球购物
澳大利亚最大的网上油画销售画廊:Direct Art Australia
2018/04/15 全球购物
爱尔兰旅游网站:ebookers.ie
2020/01/24 全球购物
乡镇总工会学雷锋活动总结
2014/03/01 职场文书
爱岗敬业演讲稿
2014/05/05 职场文书
合作意向书
2014/07/30 职场文书
总经理助理岗位职责范本
2015/03/31 职场文书
门球健将观后感
2015/06/16 职场文书