问题引入:最近在 Babel 编译时遇到一个问题,对 ES6 Module 编译的问题,本文将对解决该问题过程中关于 ES6 Module 有关内容进行记录和介绍。
关于:CommonJS, AMD, CMD, UMD
- CommonJS: 用于服务端,模块同步加载,node.js 的模块系统就是基于 CommonJS 规范的实现
- AMD (Asynchronous Module Definition): 用于浏览器端,模块异步加载,目前,流行的 require.js 库就实现了 AMD 规范
- CMD (Common Module Definition): 是 SeaJS 在推广过程中对模块定义的规范化,和 AMD 有些类似,参考:与 RequireJS 的异同
- UMD (Universal Module Definition): 兼容了 AMD 和 CommonJS,同时还支持老式的“全局”变量规范,使得模块化代码可以在前端浏览器和后台服务端中运行
问题阐述及解决
在 test.js
文件中,有如下一行代码:
在 gulpfile.js
文件中,有如下任务对其进行编译:
执行 gulp babel
编译后,结果为:
那么使用过程中会遇到什么问题呢?
例如,我们在 node.js
文件中有如下代码:
执行 node node.js
后,输出的结果为:--- { default: 23 }
如果想要 a
即为 23,那么需要:
显然每次 require
使用的时候需要手动添加 default
比较麻烦,而且代码也不好看🙃。那么有什么方法解决这个问题么?
👇下面我们需要对 exports
和 module.exports
进行了解
在 Node.js modules 中,我们对 exports
都不陌生,我们可以通过 exports
暴露任何合法的 JavaScript 对象,包括:boolean, number, date, JSON, string, function, array 等等。
然后在其他文件中使用:
那么 module.exports
又是什么呢❓
The
module.exports
object is created by the Module system.
所以真实存在,且最终返回给调用者的是 module.exports
;而 exports
只是 module.exports
的 shortcut/alias 辅助别名。我们可以这么理解:
module.exports
初始值为一个空对象 {}
; exports
是指向的对象和 module.exports
执向的对象相同。
exports
的作用在于收集属性和方法,例如:
此时,exports
和 module.exports
都是指向同一对象:{ a: [Function], b: [Function] };
但是如果:
此时,exports
执向的对象和 指向的对象已经不同,此时 exports
执行的是一个函数,而 module.exports
却依然执向一个空对象 {}
,二者的引用不同。可以通过 exports = module.exports
让 exports
重新指向 module.exports
即可保持二者引用相同。
对上述问题的理解就涉及到 JS中是 pass by value 还是 pass by reference
通过以上的分析,我们推荐是使用 module.exports
而非 exports
。(Node.js文档中也是这么推荐的)
由此,我们可以通过添加 module.exports
来解决 require
时需要指定 default
的问题
如上这个过程可以通过 🚀babel-plugin-add-module-exports 插件,在 babel 过程中自动处理。
由于浏览器中缺少 module
exports
require
global
这四个 NodeJS 环境变量,所以不兼容 CommonJS,也就是说,浏览器中并不能使用上述的模块,那么为了解决如上问题,我们需要另一个插件 🚀ES2015 modules to UMD transform,将模块代码编译成 UMD 模式。
综上:下载插件,在 babel 过程中传入两个插件名即可
经过编译后,最终生成的代码如下:
参考链接
Misunderstanding ES6 Modules, Upgrading Babel, Tears, and a Solution