Commonjs require/module.exports is already widely used in nodeJS environments, while ECMAScript Module es module import/export is generated. In particular, the default syntax in ES Module complicates the conversion between ES Module and CommonJS. In this paper, I will discuss the problems and how to solve them based on my practice of mutual conversion between ES Module and CommonJS.

  • Problems caused by export default in ES Module
  • __esModule
  • Problems with __esModule

1. Problems caused by export default in ES Module

Es Module references are not a problem. With the nodeJS environment and browser environment starting to support ES Module, the latest versions of some major NPM packages will provide es Module source files. Source files in ESM form are typically provided by specifying the Module or exports field in package.json. However, if you reference a commonJS module in an ES Module, you may have reference problems.

The essence of the problem is the syntax of export default in ESM, which cannot be corresponding in CommonJS.

For example:

/ / commonjs module a. s
module.exports.name = 'Jony'
module.exports.hobby = 'Play'
Copy the code
//main.js references a const person = require("./a.js"Copy the code
Commonjs import person from './a.js' person =???Copy the code

In the above example, if we need to refer to A. js as an ES module. Because A. js is in the form of CommonJS, we can’t find the attribute corresponding to export default in A. js.

Second, the __esModule

The two examples in question 1 essentially illustrate the syntax of export default in ESM, which is hard to find in CommonJS. Babel first introduces an __esModule flag in the commonJS module file. If __esModule is true, it converts commonJS to esModule. Export default exports module.exports.default. If __esModule is false, export default is exported to the entire module.exports after commonJS is converted to esModule.

Let’s also use the example from the preceding chapter to illustrate:

/ / commonjs module a. s
module.exports.name = 'Jony'
module.exports.hobby = 'Play'
Copy the code

There is no __esModule attribute; the default __esModule is false

// person_cjs const person_cjs = require("./a.js") person_cjs = {name,hobby}Copy the code

Export Default exports the entire module.exports object because __esModule is false or does not exist.

Commonjs import person_esm from './a.js' person_esm = {name,hobby}Copy the code

For another example, if commonJS contains the module.exports.default attribute and the __esModule bit true.

/ / commonjs module a. s
module.exports.default = "aa"
module.exports.name = "Jony"
module.exports.hobby = 'Play'
module.exports.__esModule = true

Copy the code

If __esModule is true and the module.exports.default attribute is present, the es module is used as a reference to the above file.

//main.js references a.js and commonjs in esM form
import person_esm from './a.js' 
person_esm = "aa"

Copy the code

Problems with __esModule

__esModule was first introduced by Babel, and other build tools or systems follow this rule in commonJS and ES Module conversions. However, there are a few details that need to be paid attention to during the conversion and reference process.

(1) If the commonJS Module has an __esModule set to false, the entire module. exports object is everywhere. If __esModule=false, the object may have an additional __esModule attribute.

Therefore, if __esModule is false, you do not need to set it. Otherwise objects everywhere will have an extra __esModule attribute.

//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}
Copy the code

(2) If the commonJS module has an __esModule set to true, but does not have a module.exports.default attribute.

In this case, different build tools or systems may have different behaviors. Take the latest version of the esbuild as an example. In this case, after the esbuild is built, default = undefined is considered.

//commonjs a.js
module.exports.a = 2
module.exports.b = 3
module.exports.__esModule = true

//main.js

import x from './a.js'
x = undefined 
Copy the code

In addition, there are tools that treat __esModule as false if it is true but no module.exports.default does not exist.

(3) if it is referenced in.mjs file

//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
}
Copy the code

A file with an. MJS suffix supports es Module in nodejs. In this case, if you reference Commonjs in a file with an. MJS suffix, no special treatment will be taken. The __esModule scenario itself is required to be compatible with a NodeJS environment and cannot run esModule directly.

Therefore, __esModule does not take effect and all attributes are treated as normal.