We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
当ECMAScript module(简称es module) 的模块化语法import/export产生的时候,commonjs的require/module.exports已经在nodejs的环境中被广泛使用,特别是es module中的default语法,让es module和commonjs之间的转换变得复杂。本文结合自己在es module和commonjs两种模块化互相转换的实践,聊聊会遇到的问题以及如何解决。
es module中export default带来的问题 __esModule __esModule存在的问题
es module模块间的互相引用不会有任何的问题,随着nodejs环境和浏览器环境都陆续开始支持es module, 一些主流的npm包的最新版本,都会提供es module的源文件,一般通过指定package.json中的module或者exports字段来提供esm形式的源文件。但是,如果在es module中引用一个commonjs中的模块,就可能会出现引用问题。
出问题的本质就是esm中export default的语法,在commonjs中是无法对应的。
举例来说:
//commonjs模块 a.js module.exports.name = 'Jony' module.exports.hobby = 'Play'
//main.js引用a.js const person = require("./a.js") //这样引没用问题
//main.js引用a.js,用esm的形式引用commonjs import person from './a.js' person = ???
上述的例子中,如果我们需要以es module的形式来引用a.js。因为a.js是commonjs形式的,我们在a.js中找不到与export default相对应的属性。
在问题一中的两个例子,本质都说明了esm 中export default的语法,在commonjs中很难找到对应。babel首先在commonjs模块的文件中引入__esModule标识,如果__esModule为true,那么将commonjs转化为es module,export default导出的是module.exports.default。如果__esModule为false,那么commonjs转化为es module后,export default到处的是整个module.exports。
我们同样拿上述章节中的例子,来说明:
这里没用__esModule属性,默认__esModule为false
//main.js引用a.js const person_cjs = require("./a.js") //这样引没有问题 person_cjs = {name,hobby}
因为__esModule为false或者不存在,那么export default导出的是整个module.exports对象。
//main.js引用a.js,用esm的形式引用commonjs import person_esm from './a.js' person_esm = {name,hobby}
再来看一个例子,如果包含commonjs中包含了module.exports.default属性,以及__esModule位true。
//commonjs 模块a.js module.exports.default = "aa" module.exports.name = "Jony" module.exports.hobby = 'Play' module.exports.__esModule = true
这里__esModule为true,且存在module.exports.default属性,那么以es module的方式引用上述文件得到的结果为:
//main.js引用a.js,用esm的形式引用commonjs import person_esm from './a.js' person_esm = "aa"
__esModule首先由Babel提出,其他的构建工具或者系统在commonjs和es module的转换中都遵循了这个规则。但是在使用在转换和引用的过程中需要注意几个细节。
(1)如果commonjs的模块中存在__esModule为false,到处的是整个Module.exports对象,如果设置了__esModule=false,这个对象中可能会多一个属性__esModule.
因此如果__esModule为false,可以不设置。否则到处的对象会多一个__esModule属性。
//commonjs a.js module.exports.a = 2 module.exports.b = 3 module.exports.__esModule = false //main.js import x from './a.js' x = {a:2,b:3,__esModule:false}
(2)如果commonjs的模块中存在__esModule为true,但是不存在module.exports.default属性。
这种情况下,不同的构建工具或者系统可能有不同的表现,以esbuild的最新版本为例子,对于这种情况esbuild构建后认为default = undefined.
//commonjs a.js module.exports.a = 2 module.exports.b = 3 module.exports.__esModule = true //main.js import x from './a.js' x = undefined
此外,也有一些工具的处理,如果__esModule为true,但是不存在module.exports.default不存在,就把这种情况当成__esModule为false来处理。
(3)如果在.mjs文件中引用
//commonjs a.js module.exports.default = "aa" module.exports.a = 2 module.exports.b = 3 module.exports.__esModule = true //main.mjs import x from './a.js' x = { default:'aa', a:2, b:2, __esModule:true }
以.mjs后缀结尾的文件,是nodejs中支持了es module的形式,此时如果在.mjs后缀结尾的文件中引用commonjs,一般不会做特殊处理。需要__esModule的场景本身就是为了兼容nodejs环境中,无法直接运行es module。
因此这里__esModule不会生效,所有属性都被当成普通属性。
The text was updated successfully, but these errors were encountered:
Sorry, something went wrong.
No branches or pull requests
深入聊一聊__esModule
当ECMAScript module(简称es module) 的模块化语法import/export产生的时候,commonjs的require/module.exports已经在nodejs的环境中被广泛使用,特别是es module中的default语法,让es module和commonjs之间的转换变得复杂。本文结合自己在es module和commonjs两种模块化互相转换的实践,聊聊会遇到的问题以及如何解决。
一、es module中export default带来的问题
es module模块间的互相引用不会有任何的问题,随着nodejs环境和浏览器环境都陆续开始支持es module, 一些主流的npm包的最新版本,都会提供es module的源文件,一般通过指定package.json中的module或者exports字段来提供esm形式的源文件。但是,如果在es module中引用一个commonjs中的模块,就可能会出现引用问题。
出问题的本质就是esm中export default的语法,在commonjs中是无法对应的。
举例来说:
上述的例子中,如果我们需要以es module的形式来引用a.js。因为a.js是commonjs形式的,我们在a.js中找不到与export default相对应的属性。
二、__esModule
在问题一中的两个例子,本质都说明了esm 中export default的语法,在commonjs中很难找到对应。babel首先在commonjs模块的文件中引入__esModule标识,如果__esModule为true,那么将commonjs转化为es module,export default导出的是module.exports.default。如果__esModule为false,那么commonjs转化为es module后,export default到处的是整个module.exports。
我们同样拿上述章节中的例子,来说明:
这里没用__esModule属性,默认__esModule为false
因为__esModule为false或者不存在,那么export default导出的是整个module.exports对象。
再来看一个例子,如果包含commonjs中包含了module.exports.default属性,以及__esModule位true。
这里__esModule为true,且存在module.exports.default属性,那么以es module的方式引用上述文件得到的结果为:
三、__esModule存在的问题
__esModule首先由Babel提出,其他的构建工具或者系统在commonjs和es module的转换中都遵循了这个规则。但是在使用在转换和引用的过程中需要注意几个细节。
(1)如果commonjs的模块中存在__esModule为false,到处的是整个Module.exports对象,如果设置了__esModule=false,这个对象中可能会多一个属性__esModule.
因此如果__esModule为false,可以不设置。否则到处的对象会多一个__esModule属性。
(2)如果commonjs的模块中存在__esModule为true,但是不存在module.exports.default属性。
这种情况下,不同的构建工具或者系统可能有不同的表现,以esbuild的最新版本为例子,对于这种情况esbuild构建后认为default = undefined.
此外,也有一些工具的处理,如果__esModule为true,但是不存在module.exports.default不存在,就把这种情况当成__esModule为false来处理。
(3)如果在.mjs文件中引用
以.mjs后缀结尾的文件,是nodejs中支持了es module的形式,此时如果在.mjs后缀结尾的文件中引用commonjs,一般不会做特殊处理。需要__esModule的场景本身就是为了兼容nodejs环境中,无法直接运行es module。
因此这里__esModule不会生效,所有属性都被当成普通属性。
The text was updated successfully, but these errors were encountered: