天天看点

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

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'
           

结果

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

导入

先来看看打包后的文件导入规则与打包前有什么变化

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

可以看到。打包后,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

来实现模块的的导入

下面我们来看看是不是这样

导出

再来看看打包后的文件导出规则与打包前有什么变化

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

可以看到,打包前后的代码实际没有什么变化。并且,他如我们所想,这个匿名函数内部将我们需要导出的内容,挂载到了

module.exports

上,那么当这个匿名函数执行完成(模块加载完成)后,需要导出的变量自然就挂载到了我们传入的

module

对象中,从而实现模块的导出。至于这里为什么没有

__webpack_require__

形参是因为,这个模块并没有导入其他的模块,所以不需要这个方法。

总结

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

可以看到,导入导出最核心的方法其实就是

__webpack_require__

方法,我们通过向这个方法传递一个模块id,来找到对应模块id的模块执行函数。通过向模块执行函数传递一个

module对象

,让其内部导出的变量挂载到

module.exports

上来,并在

__webpack_require__

方法最后返回

module.exports

来实现模块的导出

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

以上内容仅供学习参考