前言
之前我一直不太明白webpack的模块引入机制。正好看到了bundle.js文件的解析才更加了解一些
首先要知道所有模块的内容都被整合到一个文件中了。 你可能会说这样做不就是违背了模块化的思想吗?
实际上并没有,因为内部模块化的实现是基于函数的,也就说不通模块内容被封锁在不同的函数中
这样每一个函数都是一个函数作用域,形成了一个私有的作用域。
另一方面,浏览器没有像Node.js那样对于模块化定义了Commonjs规范,所以需要在浏览器中模拟Node的模块加载机制
分析
先给出一个整体代码
(
function (modules) {
var installedModules = {};
function __webpack_require__(moduleId) {
if (installedModules[moduleId]) {
return installedModules[moduleId].exports;
}
var module = installedModules[moduleId] = {
i: moduleId,
l: false,
exports: {}
};
modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
module.l = true;
return module.exports;
}
__webpack_require__.p = "";
return __webpack_require__(__webpack_require__.s = 0);
})(
[
(function (module, exports, __webpack_require__) {
const show = __webpack_require__(1);
show('Webpack');
}),
(function (module, exports) {
function show(content) {
window.document.getElementById('app').innerText = 'Hello,' + content;
}
module.exports = show;
})
]
);
整体代码分三个部分 1.主体执行代码webpackBootstrap(webpack启动程序) 2.__webpack_require__函数 3.模块数组(作为参数传递进去)
__webpack_require__函数
这个函数可以说是核心函数,它的作用是什么?
function __webpack_require__(moduleId) {
if (installedModules[moduleId]) {
return installedModules[moduleId].exports;
}
var module = installedModules[moduleId] = {
i: moduleId,
l: false,
exports: {}
};
modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
module.l = true;
return module.exports;
}
传入的参数是一个moduleID,由于传入webpackBootstrap的参数是一个模块数组,模块数组的index就是moduleID
1.函数内第一个功能是分析这个模块有没有被加载过
判断依据是一个所有模块共同拥护的对象中是否存在
var installedModules = {};
如果存在就将对象中已经加载过的内容返回
2.如果没有加载过
自然是要为这个这个模块设置一些信息
比如说模块id,是否已经加载过,以及最为重要的模块加载需要暴露出的内容(这相当于一个进程执行前创建的PCB)
这里要注意一下模块加载是一次性执行的,export暴露的出的内容也是一个值拷贝
之后就是将这个模块的内容(对应就是一个函数)执行,而且是基于module
最终将这个模块返回回去
从一个模块开始的执行流程
首先是从模块数组序号为0的开始调用__webpack_require__()函数
如果这个函数内部又调用其他模块,那么采取同样的策略
执行完毕之后,可以在当前模块访问到其他模块暴露的内容
后面还有一个异步加载时的代码,放在另外一篇
|