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

【读书笔记】《深入浅出Webpack》的更多相关文章

  1. csapp读书笔记-并发编程

    这是基础,理解不能有偏差 如果线程/进程的逻辑控制流在时间上重叠,那么就是并发的.我们可以将并发看成是一种os内核用来运行多个应用程序的实例,但是并发不仅在内核,在应用程序中的角色也很重要. 在应用级 ...

  2. CSAPP 读书笔记 - 2.31练习题

    根据等式(2-14) 假如w = 4 数值范围在-8 ~ 7之间 2^w = 16 x = 5, y = 4的情况下面 x + y = 9 >=2 ^(w-1)  属于第一种情况 sum = x ...

  3. CSAPP读书笔记--第八章 异常控制流

    第八章 异常控制流 2017-11-14 概述 控制转移序列叫做控制流.目前为止,我们学过两种改变控制流的方式: 1)跳转和分支: 2)调用和返回. 但是上面的方法只能控制程序本身,发生以下系统状态的 ...

  4. CSAPP 并发编程读书笔记

    CSAPP 并发编程笔记 并发和并行 并发:Concurrency,只要时间上重叠就算并发,可以是单处理器交替处理 并行:Parallel,属于并发的一种特殊情况(真子集),多核/多 CPU 同时处理 ...

  5. 读书笔记汇总 - SQL必知必会(第4版)

    本系列记录并分享学习SQL的过程,主要内容为SQL的基础概念及练习过程. 书目信息 中文名:<SQL必知必会(第4版)> 英文名:<Sams Teach Yourself SQL i ...

  6. 读书笔记--SQL必知必会18--视图

    读书笔记--SQL必知必会18--视图 18.1 视图 视图是虚拟的表,只包含使用时动态检索数据的查询. 也就是说作为视图,它不包含任何列和数据,包含的是一个查询. 18.1.1 为什么使用视图 重用 ...

  7. 《C#本质论》读书笔记(18)多线程处理

    .NET Framework 4.0 看(本质论第3版) .NET Framework 4.5 看(本质论第4版) .NET 4.0为多线程引入了两组新API:TPL(Task Parallel Li ...

  8. C#温故知新:《C#图解教程》读书笔记系列

    一.此书到底何方神圣? 本书是广受赞誉C#图解教程的最新版本.作者在本书中创造了一种全新的可视化叙述方式,以图文并茂的形式.朴实简洁的文字,并辅之以大量表格和代码示例,全面.直观地阐述了C#语言的各种 ...

  9. C#刨根究底:《你必须知道的.NET》读书笔记系列

    一.此书到底何方神圣? <你必须知道的.NET>来自于微软MVP—王涛(网名:AnyTao,博客园大牛之一,其博客地址为:http://anytao.cnblogs.com/)的最新技术心 ...

  10. Web高级征程:《大型网站技术架构》读书笔记系列

    一.此书到底何方神圣? <大型网站技术架构:核心原理与案例分析>通过梳理大型网站技术发展历程,剖析大型网站技术架构模式,深入讲述大型互联网架构设计的核心原理,并通过一组典型网站技术架构设计 ...

随机推荐

  1. JavaScript之12306自动刷新车票[待完善]

    function refresh(){ var search_btn = document.getElementById("query_ticket"); var result_t ...

  2. Java 注解 (Annotation)你可以这样学

    注解语法 因为平常开发少见,相信有不少的人员会认为注解的地位不高.其实同 classs 和 interface 一样,注解也属于一种类型.它是在 Java SE 5.0 版本中开始引入的概念. 注解的 ...

  3. ROS中的CMakeLists.txt

    在ROS的编程过程中,如果CMakeLists.txt如果写不好,编译就很难成功.如果看不懂CMakeLists.txt那么很多错误你也不知道时什么回事.所以深入了解它是很有必要的.现在我们就来看看它 ...

  4. IDEA常用快捷键和常用插件集成,持续更新......

    用习惯了eclipse,不容易转过来,记一下! 快捷键 psvm: main 方法快捷键 sout :syso快捷键 CTRL+O: 重写父类方法 Ctrl+Alt+V :自动补全返回值 Ctrl+S ...

  5. CodeForces Contest #1137: Round #545 (Div. 1)

    比赛传送门:CF #1137. 比赛记录:点我. 每次都自闭的 div1 啊,什么时候才能上 IM 呢. [A]Skyscrapers 题意简述: 有一个 \(n\times m\) 的矩阵 \(a_ ...

  6. SpringBoot三种配置Dubbo的方式

    *必须首先导入dubbo-starter (1).使用SpringBoot配置文件(application.properties或application.yml) dubbo.application. ...

  7. js的正则表达式编程,悬赏解决下面的问题

    悬赏解决下面的问题 1.切分url 2.将时间日期 转化为 yyyy-MM-dd的模式和可逆性 3.数据的千分位和可逆性 4.用C#或者nodejs检索如下的模式 h1{ border:1px sol ...

  8. win10-Anaconda2-Theano-cuda7.5-VS2013

    两天的辗转反侧,终于灵光一现找到了错误. 首先,我在win10下配置好了gpu和cudnn版本的caffe.但是因为win平台的限制,caffe用的不够舒服.因为之前用过一阵子theano,虽然很慢, ...

  9. ES系列十七、logback+ELK日志搭建

    一.ELK应用场景 在复杂的企业应用服务群中,记录日志方式多种多样,并且不易归档以及提供日志监控的机制.无论是开发人员还是运维人员都无法准确的定位服务.服务器上面出现的种种问题,也没有高效搜索日志内容 ...

  10. iPhone 收藏网址[添加到书签] 和 [添加到主屏幕] 显示自定义图标,而不是网页截图

    iPhone 收藏网址[添加到书签] 和 [添加到主屏幕] 显示自定义图标,而不是网页截图: <!-- Safari浏览器[添加到书签] --> <link rel="sh ...