webpack源码分析—模块的导入与导出详解
- 前言
- CommonJS规范的导入和导出
-
- 导入
- 导出
- 总结
前言
上一章我们说了webpack打包后代码的一个整体分析,这一章我们来详细说一下webpack打包后的代码是如何实现模块的导入和导出的,因为commonjs规范和esmodule规范两者有一定差异,且esmodule的差异更大,所以我们先分析CommonJS规范下的导入导出
CommonJS规范的导入和导出
示例代码
// 主模块入口
const data = require('./module.js')
const { param1, param2 } = require('./module.js')
console.log(data)
console.log(param1)
console.log(param2)
// module.js
module.exports = 'this is default export'
exports.param1 = 'export param1'
exports.param2 = 'export param2'
结果
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIyZuBnLzMTO4EDNxMjM1EzMwEjMwIzLc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)
导入
先来看看打包后的文件导入规则与打包前有什么变化
可以看到。打包后,webpack进行了如下处理:
- 将模块的内容通过匿名函数封装起来
- 将
方法替换成require
方法,并传递对应的模块路径__webpack_require__
- 将模块路径进行了处理,替换成相对于src目录下的相对路径
也就是说,导入模块内容的功能是由
__webpack_require__
方法实现的,那我们再看看
__webpack_require__
方法的逻辑是怎样的
// __webpack_require__
function __webpack_require__(moduleId) {
// installedModules 是一个模块缓存变量
// 先判断缓存内是否存在该模块
if (installedModules[moduleId]) {
// 存在,直接返回该模块的导出内容
return installedModules[moduleId].exports;
}
// 不存在,创建一个模块对象,定义一些初始值,并进行缓存
var module = installedModules[moduleId] = {
i: moduleId, // 模块id
l: false, // 加载标志
exports: {} // 导出内容
};
// modules是所有模块定义对象的集合,modules[moduleId]用于获取模块路径定义对象中对应模块id的键值,实际就是一个包含模块执行逻辑的匿名函数,最后执行该匿名函数并传递三个参数
// module, module.exports, __webpack_require__
// call方法只是用于改变this指向
modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
module.l = true;
// 返回模块的导出内容
return module.exports;
}
我们可以总结一下:
-
返回的值是module.exports,也就是说导入的模块实际就是module.exports的内容__webpack_require__
-
会找到模块路径定义对象中对应模块id的键值,一个包含模块执行逻辑的匿名函数(模块定义函数),并传递__webpack_require__
,module
,module.exports
三个参数执行__webpack_require__
我们可以猜测,
__webpack_require__
应该是通过执行模块定义函数,往传递的参数
module.exports
上挂载一些变量,并在
__webpack_require__
方法最后返回
module.exports
来实现模块的的导入
下面我们来看看是不是这样
导出
再来看看打包后的文件导出规则与打包前有什么变化
可以看到,打包前后的代码实际没有什么变化。并且,他如我们所想,这个匿名函数内部将我们需要导出的内容,挂载到了
module.exports
上,那么当这个匿名函数执行完成(模块加载完成)后,需要导出的变量自然就挂载到了我们传入的
module
对象中,从而实现模块的导出。至于这里为什么没有
__webpack_require__
形参是因为,这个模块并没有导入其他的模块,所以不需要这个方法。
总结
可以看到,导入导出最核心的方法其实就是
__webpack_require__
方法,我们通过向这个方法传递一个模块id,来找到对应模块id的模块执行函数。通过向模块执行函数传递一个
module对象
,让其内部导出的变量挂载到
module.exports
上来,并在
__webpack_require__
方法最后返回
module.exports
来实现模块的导出
以上内容仅供学习参考