对于项目工程中非常多的模块,Webpack打包时是通过什么方式将其有序组织在一起的呢?
模块:
// getInfo.js
module.exports = {
getSum: function(num1, num2) {
return num1 + num2;
}
}
// index.js
const getInfo = require('./getInfo.js');
const sum = getInfo.getSum(2,3);
console.log(sum);
bundle.js打包后的结果文件代码:
// 立即执行匿名函数
(function() {
// 模块缓存
var installedModules = {};
// 实现require
function __webpack_require__(moduleId) {
...
}
// 执行入口模块的加载
return __webpack_require__(__webpack_require__.s = 0);
})({
// modules: 以key-value的形式储存所有被打包的模块
0: function(module, exports, __webpack_require__) {
// 打包入口
module.exports = __webpack_require__("3qiv");
},
"3qiv": function() {
// index.js内容
},
jkzz: function(module, exports) {
// getInfo.js的内容
}
})
- 1、
bundle
文件分为几个部分,最外层是立即执行的匿名函数,主要是用来包裹bundle,并构成自身的作用域。 - 2、
installedModules
对象,每个模块只在第一次被加载的时候执行,之后其导出值就被存储到这个对象里面,当再次被加载的时候直接从这里取值,而不会重新执行。 - 3、
__webpack_require__
函数,对模块加载的实现,在浏览器中可以通过调用__webpack_require__(moduleId)
来完成模块导入。 - 4、
modules
对象,工程中所有产生了依赖关系的模块都会key-value的形式放在这里,key也就是一个模块的id,由数字或者一个很短的hash字符串构成;value则是由一个匿名函数包裹的模块实体,匿名函数的参数则赋予了每个模块导入和导出的能力。
打包后的bundle文件在浏览器中的执行过程:
- 1)、在最外层的匿名函数会初始化浏览器执行环境,包括定义
installedModules
对象、__webpack_require__
函数等,为模块的加载和执行做一些准备工作。 - 2)、加载入口模块。每个bundle都会
有且只有
一个入口模块,在上面的示例中,index.js
是入口模块,在浏览器中会从它先开始执行。 - 3)、执行模块代码,如果执行到了
module.exports
则会记录下模块的导出值,如果中间遇到require函数,也就是__webpack_require__
函数,则会暂时交出执行权,进入__webpack_require__
函数体内进行加载其他模块的逻辑。 - 4)、在
__webpack_require__
函数中会判断即将加载的模块是否存在于installedModules
中,如果存在则直接取值,否则回到上一步,执行该模块的代码来获取导出值。 - 5)、所有依赖的模块都已执行完毕,最后执行权又回到入口模块,当入口模块的代码执行到结尾,则该bundle文件执行完毕了。
第三步和第四步是一个递归的过程,Webpack为每一个模块创造了一个可以导入和导出模块的环境,但是本质上没有修改代码的执行逻辑,因此代码的执行顺序与模块加载的顺序是完全一致的。
·
网友评论