webpack源码分析—CommonJS规范模块的导入与导出详解

webpack源码分析—模块的导入与导出详解

前言

上一章我们说了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'

结果
在这里插入图片描述

导入

先来看看打包后的文件导入规则与打包前有什么变化
在这里插入图片描述
可以看到。打包后,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;
}

我们可以总结一下:

  • __webpack_require__返回的值是module.exports,也就是说导入的模块实际就是module.exports的内容
  • __webpack_require__会找到模块路径定义对象中对应模块id的键值,一个包含模块执行逻辑的匿名函数(模块定义函数),并传递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来实现模块的导出
在这里插入图片描述


以上内容仅供学习参考

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值