Webpack版本

分析版本为3.6.0

4.0为最近升级的版本,与之前版本变化较大,编译输出的文件与3.0版本会不一致,目前项目中使用的版本3.0版本,所以基于3.0版本进行分析学习。

Webpack构建流程

  • 初始化:启动构建,读取与合并配置参数,加载Plugin,实例化Complier
  • 编译:从Entry发出,针对每个Module串行调用对应的Loader去转换文件内容,再找到该Module依赖的Module,递归进行编译处理。
  • 输出:对编译后对Module组合成Chunk,把Chunk转换成文件,输出到文件系统。

输出文件分析

原输出文件结构:

简化后的文件结构:

(function(modules) {
// 模拟 require 语句
function __webpack_require__() {
}
// 执行存放所有模块数组中的第0个模块
__webpack_require__(0);
})([/*存放所有模块的数组*/])

分割代码时输出

当使用按需加载加载文件时,Webpack的输出文件会发生变化。

// 异步加载 show.js
import('./show').then((show) => {
// 执行 show 函数
show('Webpack');
});

重新构建后会输出两个文件,分别是执行入口文件bundle.js和异步加载文件0.bundle.js

异步加载文件默认输入的文件名为 [id].js,可以在Webpack配置文件的output项中配置输出文件名

其中0.bundle.js内容如下:

// 加载在本文件(0.bundle.js)中包含的模块
webpackJsonp(
// 在其它文件中存放着的模块的 ID
[0],
// 本文件所包含的模块
[
// show.js 所对应的模块
(function (module, exports) {
function show(content) {
window.document.getElementById('app').innerText = 'Hello,' + content;
} module.exports = show;
})
]
);

bundle.js内容如下:

(function (modules) {
/***
* webpackJsonp 用于从异步加载的文件中安装模块。
* 把 webpackJsonp 挂载到全局是为了方便在其它文件中调用。
*
* @param chunkIds 异步加载的文件中存放的需要安装的模块对应的 Chunk ID
* @param moreModules 异步加载的文件中存放的需要安装的模块列表
* @param executeModules 在异步加载的文件中存放的需要安装的模块都安装成功后,需要执行的模块对应的 index
*/
window["webpackJsonp"] = function webpackJsonpCallback(chunkIds, moreModules, executeModules) {
// 把 moreModules 添加到 modules 对象中
// 把所有 chunkIds 对应的模块都标记成已经加载成功
var moduleId, chunkId, i = 0, resolves = [], result;
for (; i < chunkIds.length; i++) {
chunkId = chunkIds[i];
if (installedChunks[chunkId]) {
resolves.push(installedChunks[chunkId][0]);
}
installedChunks[chunkId] = 0;
}
for (moduleId in moreModules) {
if (Object.prototype.hasOwnProperty.call(moreModules, moduleId)) {
modules[moduleId] = moreModules[moduleId];
}
}
while (resolves.length) {
resolves.shift()();
}
}; // 缓存已经安装的模块
var installedModules = {}; // 存储每个 Chunk 的加载状态;
// 键为 Chunk 的 ID,值为0代表已经加载成功
var installedChunks = {
1: 0
}; // 模拟 require 语句,和上面介绍的一致
function __webpack_require__(moduleId) {
// ... 省略和上面一样的内容
} /**
* 用于加载被分割出去的,需要异步加载的 Chunk 对应的文件
* @param chunkId 需要异步加载的 Chunk 对应的 ID
* @returns {Promise}
*/
__webpack_require__.e = function requireEnsure(chunkId) {
// 从上面定义的 installedChunks 中获取 chunkId 对应的 Chunk 的加载状态
var installedChunkData = installedChunks[chunkId];
// 如果加载状态为0表示该 Chunk 已经加载成功了,直接返回 resolve Promise
if (installedChunkData === 0) {
return new Promise(function (resolve) {
resolve();
});
} // installedChunkData 不为空且不为0表示该 Chunk 正在网络加载中
if (installedChunkData) {
// 返回存放在 installedChunkData 数组中的 Promise 对象
return installedChunkData[2];
} // installedChunkData 为空,表示该 Chunk 还没有加载过,去加载该 Chunk 对应的文件
var promise = new Promise(function (resolve, reject) {
installedChunkData = installedChunks[chunkId] = [resolve, reject];
});
installedChunkData[2] = promise; // 通过 DOM 操作,往 HTML head 中插入一个 script 标签去异步加载 Chunk 对应的 JavaScript 文件
var head = document.getElementsByTagName('head')[0];
var script = document.createElement('script');
script.type = 'text/javascript';
script.charset = 'utf-8';
script.async = true;
script.timeout = 120000; // 文件的路径为配置的 publicPath、chunkId 拼接而成
script.src = __webpack_require__.p + "" + chunkId + ".bundle.js"; // 设置异步加载的最长超时时间
var timeout = setTimeout(onScriptComplete, 120000);
script.onerror = script.onload = onScriptComplete; // 在 script 加载和执行完成时回调
function onScriptComplete() {
// 防止内存泄露
script.onerror = script.onload = null;
clearTimeout(timeout); // 去检查 chunkId 对应的 Chunk 是否安装成功,安装成功时才会存在于 installedChunks 中
var chunk = installedChunks[chunkId];
if (chunk !== 0) {
if (chunk) {
chunk[1](new Error('Loading chunk ' + chunkId + ' failed.'));
}
installedChunks[chunkId] = undefined;
}
};
head.appendChild(script); return promise;
}; // 加载并执行入口模块,和上面介绍的一致
return __webpack_require__(__webpack_require__.s = 0);
})
(
// 存放所有没有经过异步加载的,随着执行入口文件加载的模块
[
// main.js 对应的模块
(function (module, exports, __webpack_require__) {
// 通过 __webpack_require__.e 去异步加载 show.js 对应的 Chunk
__webpack_require__.e(0).then(__webpack_require__.bind(null, 1)).then((show) => {
// 执行 show 函数
show('Webpack');
});
})
]
);

这里的 bundle.js 和上面所讲的 bundle.js 非常相似,区别在于:

  • 多了一个 webpack_require.e 用于加载被分割出去的,需要异步加载的 Chunk 对应的文件;
  • 多了一个 webpackJsonp 函数用于从异步加载的文件中安装模块。

参考

深入浅出WebPack

最新文章

  1. css浮动与绝对定位小记
  2. 63.Hbase 常用命令
  3. vim 清空
  4. IOS测试程序运行耗时
  5. 【转】java 访问.net webservice返回的数据集
  6. java 字符串函数
  7. VMware11安装Mac OS X10提示不可恢复错误解决
  8. JavaScript实现点击按钮弹出输入框,点确定后添加li组件到ul组件里
  9. Merge OUTPUT 高级用法综合写的一个MergeTab的存储过程
  10. es6编写reactjs事件处理函数绑定this三种方式
  11. php一些需要注意的点
  12. 《ECMAScript6入门》___阮一峰 笔记
  13. _C#发送邮箱
  14. linux 学习之路:mkdir命令使用
  15. Servlet 使用ServletContext共享数据,读取web.xml配置
  16. Celery 异步任务 , 定时任务 , 周期任务 的芹菜
  17. EOS的发币逻辑
  18. 简单实现MySQL数据库的日志审计
  19. python使用代理访问服务器
  20. HDU 1811(并查集+拓扑排序)题解

热门文章

  1. TeamCity : Build 版本控制系统配置
  2. css学习笔记(1)
  3. AngularJS 学习之路(1)
  4. OpenGIS 介绍
  5. iOS- iPhone App 如何运营?
  6. AtomicInteger
  7. task2
  8. chrome下的js调试
  9. 读取xml时,遇到xmlns的问题
  10. Python codes
  11. zoj 1109 zoj 1109 Language of FatMouse(字典树)
  12. Linux常见命令整理(一)
  13. [转]iOS Tutorial – Dumping the Application Memory Part 2
  14. php之str_replace具体解释
  15. 【netty这点事儿】ByteBuf 的使用模式
  16. java常用类————Date类
  17. mysql触发器trigger 实例详解
  18. PC平台在Unity3D中播放硬盘ogg,mp3,wav文件
  19. 【Loadrunner基础知识】web_get_int_proterty
  20. Three.js开发指南---创建,加载高级网格和几何体(第八章)