模块化打包原理
解析 CommonJS 原理
/src/js/format.js
function sayHello() {
console.log('hello');
}
// 使用 CommonJS 导出
module.exports = { sayHello }
入口文件:
const { sayHello } = require('./js/format.js')
sayHello();
根据入口文件进行打包后。
会创建一个 __webpack_modules__
对象:
var __webpack_modules__ = {
"./src/index.js":
function (
__unused_webpack_module,
__unused_webpack_exports,
__webpack_require__
) {
const { sayHello } = __webpack_require__("./src/js/format.js");
sayHello();
},
"./src/js/format.js":
function (module) {
function sayHello() {
console.log('hello');
}
module.exports = { sayHello };
}
};
- 对象的
key
是模块的路径 key
对应的value
是一个函数,内部存放的就是模块中的代码,相当于单独创建了一个函数作用域来保持该模块代码
实际上这个对象保存了我们项目中的所有存在在模块依赖图中的模块代码,以文件路径为 key
,内部代码为 value
。
这里从 ./src/index.js
模块中可以发现,我们开发环境下使用的 require
被替换为了 __webpack_require__
。
接着又创建了一个 __webpack_module_cache__
对象。
var __webpack_module_cache__ = {};
该对象用来缓存已加载过的模块 所导出的内容,在上面的例子中,我们在入口文件中导入了 ./src/js/format.js
模块,因为该模块已经在入口文件中导入时加载过一遍了,缓存就会保存该模块导出的内容:
var __webpack_module_cache__ = {
".src/js/format.js": { exports: { sayHello } }
};
如果此时我们在其他模块中也导入该模块,则会从 __webpack_module_cache__
缓冲中导入该模块所导出的内容。
上面模块的加载过程和缓存机制都是通过 __webpack_require__
函数实现的。
现在我们来看一下 __webpack_require__
的实现原理,在 webpack 中使用 commonJS
的 require
导入某个模块时,最终都会转换为使用该函数。
// moduleId 表示的是模块的路径
function __webpack_require__(moduleId) {
// 1. 先从缓存查找模块导出的内容
var cachedModule = __webpack_module_cache__[moduleId];
if (cachedModule !== undefined) {
return cachedModule.exports;
}
// 2. 缓存中没找到,则初始化缓存,向里面添加模块id
var module = __webpack_module_cache__[moduleId] = { exports: {} };
// 3. 执行 __webpack_modules__ 中的模块,将模块导出的内容保存到缓存中
__webpack_modules__[moduleId](module, module.exports, __webpack_require__);
// 4. 返回模块导出的内容
return module.exports;
}
最后还有一段代码,作用就是通过 __webpack_require__
执行入口模块:
var __webpack_exports__ = __webpack_require__("./src/index.js");