细说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 this指针
Jul 30 Javascript
javascript document.execCommand() 常用解析
Dec 14 Javascript
浏览器解析js生成的html出现样式问题的解决方法
Apr 16 Javascript
jQuery实现美观的多级动画效果菜单代码
Sep 06 Javascript
javascript实现3D切换焦点图
Oct 16 Javascript
详解jQuery移动页面开发中的ui-grid网格布局使用
Dec 03 Javascript
JS获取地址栏参数的两种方法(简单实用)
Jun 14 Javascript
vue.js入门教程之绑定class和style样式
Sep 02 Javascript
vue mint-ui 实现省市区街道4级联动示例(仿淘宝京东收货地址4级联动)
Oct 16 Javascript
angular4+百分比进度显示插件用法示例
May 05 Javascript
详解element-ui中表单验证的三种方式
Sep 18 Javascript
vue select 获取value和lable操作
Aug 28 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
php adodb连接带密码access数据库实例,测试成功
2008/05/14 PHP
php堆排序实现原理与应用方法
2015/01/03 PHP
php编写的抽奖程序中奖概率算法
2015/05/14 PHP
PHP中spl_autoload_register()函数用法实例详解
2016/07/18 PHP
PHP的PDO预处理语句与存储过程
2019/01/27 PHP
Laravel框架实现的上传图片到七牛功能详解
2019/09/06 PHP
PHP const定义常量及global定义全局常量实例解析
2020/05/28 PHP
改版了网上的一个js操作userdata
2007/04/27 Javascript
用JavaScript调用WebService的示例
2008/04/07 Javascript
javascript multibox 全选
2009/03/22 Javascript
js 兼容多浏览器的回车和鼠标焦点事件代码(IE6/7/8,firefox,chrome)
2010/04/14 Javascript
cookie.js 加载顺序问题怎么才有效
2013/07/31 Javascript
BootStrap学习系列之布局组件(下拉,按钮组[toolbar],上拉)
2017/01/03 Javascript
jQuery is not defined 错误原因与解决方法小结
2017/03/19 Javascript
jquery-file-upload 文件上传带进度条效果
2017/11/21 jQuery
vue 点击按钮增加一行的方法
2018/09/07 Javascript
Vue 利用指令实现禁止反复发送请求的两种方法
2019/09/15 Javascript
python中使用mysql数据库详细介绍
2015/03/27 Python
Python中is与==判断的区别
2017/03/28 Python
python3实现名片管理系统
2020/11/29 Python
python实现udp聊天窗口
2020/03/31 Python
python网络编程:socketserver的基本使用方法实例分析
2020/04/09 Python
html5超简单的localStorage实现记住密码的功能实现
2017/09/07 HTML / CSS
天猫国际进口超市直营:官方直采,一站购齐
2017/12/11 全球购物
描述JSP和Servlet的区别、共同点、各自应用的范围
2012/10/02 面试题
大学生如何写自荐信
2014/01/08 职场文书
四川成都导游欢迎词
2014/01/18 职场文书
先进事迹报告会感言
2014/01/24 职场文书
求职信标题怎么写
2014/05/26 职场文书
远程培训的心得体会
2014/09/01 职场文书
小学竞选班长演讲稿
2014/09/09 职场文书
股份转让协议书范本
2015/01/27 职场文书
校园开放日新闻稿
2015/07/17 职场文书
2016年“我们的节日·端午节”活动总结
2016/04/01 职场文书
用python实现监控视频人数统计
2021/05/21 Python
Vue3中的Refs和Ref详情
2021/11/11 Vue.js