1 | (function(modules) { |
概述下上面打包后的代码,是一个立即执行函数,接受的参数是一个对象,对象的key为引入的模块路径,对应的value为导出的内容,不过babel会根据ejs or cjs来进行不同的适配导出。
iife函数内为:
- installedModules 闭包环境缓存模块对象
- webpack_require 变种的require方法
- webpack_require.d 适配commonjs的转换方法
- webpack_require.r 给babel转换的es6模块增加标志,也就是通过该方法来设置区分ejs 和 cjs的标志
- _webpack_require.n 根据 __esModule 导出
举例说明:
我们有以下几个文件,内容都很简单。
1 | // es6.js |
1 | // commonjs.js |
1 | // index.js |
通过webpack打包后的输出内容我们只取上面iife函数的参数部分,并去掉eval来提升可读性。
1 | // bundle.js |
一点点分析,从入口开始 => webpack_require(‘./index.js’)
首先会查看是否命中缓存,如果命中,那理所当然直接返回,否则进行新建 + 缓存的操作,边边角角直接略过,咱们看下面这个方法:
1 |
|
首先新建,并创建默认的导出对象,这也就说明了为什么文件没有导出,默认是{}的问题,然后,利用call传递函数执行上下文环境,并传入module, module.exports, webpack_require 参数,最后return了module中的exports的值。
来看关键的赋值这一步。
针对es6js,因为你是export default,所以babel会增加一个__esModule变量,进行ejs的标识,因为我们导出的时候,会根据ejs规范,导出得对象赋值到default上,如下
1 | // 赋值 __esModule |
当我们使用ejs规范import的时候,babel会进行default的读取,所以我们可以直接获取到我们想要的值,然后如果你使用require的话,babel会按照commonjs直接进行读取,所以会导致我们需要 .default 才能拿到我们真正想要的值,结果如下
针对cjs,由于使用cjs规范,所以我们的导出是不涉及default的,即
1 | module.exports = { type: 'commonjs' } |
其实我们直接导出即可,因为 webpack_require 的返回值就是 module.exports。
不过打包后的代码用 webpack_require.n 对commonjs的导出做了处理,判断是否为 es6 规范的导出,如果是那么导出default,不是直接导出module.exports,然后使用 getter 设置返回函数的a属性,获取a属性即返回cjs module的导出,猜测这是对es6 import的统一处理。
1 | // require |
结果如下:
简单总结
require 对 ejs 规范的导出不是很友好,换句话说,考虑的很单一,所以会有default的问题
import 适配的 ejs 和 cjs,会根据 __esModule 进行导出的判断,返回使用者真正想要的
不过进步一认证,发现如果是ejs的导出,会直接导出webpack_export[‘default’],也就是 module.export.defualt,看起来不需要处理 __esModule 的请求,暂时还不清楚到底是怎么回事。有缘窃听下回分解吧。
具体babel是怎么解析的,暂时不涉及,只分析结果,得出一点点结论。
小提示
类似这种的代码 (0, foo.bar)() 相当于 foo.bar.call(winodw|global|this) 改变执行时的上下文环境