“This is the 19th day of my participation in the Gwen Challenge in November. Check out the details: The Last Gwen Challenge in 2021”
This article/answer originally planned to be three or four hundred words, but finally wrote more and more, wrote a thousand words.
Due to the rise of the Bundless build tool, all modules are required to be in ESM modular format.
Currently, some modules in the community support both ESM and CommonJS, but there are still many modules that only support CommonJS/UMD, so converting CommonJS to ESM is a transitional stage for ESM of all modules.
ESM is different from CommonJS import/export
In the ESM, there are two import and export modes:
- Named export/import:
Named Import/Export
- Default export/import:
Default Import/Export
A code example is as follows:
// Named export/import
export { sum }
import { sum } from 'sum'
// Default export/import
export default sum
import sum from 'sum'
Copy the code
In CommonJS, there is only one way to import and export:
module.exports = sum
Copy the code
Exports is just a reference to Module. exports
// Exports in fact
exports = module.exports
// The following two are equivalent
exports.a = 3
module.exports.a = 3
Copy the code
Exports/module. Exports/module. Exports/console
// hello.js exports.a = 3 module.exports.b = 4 // index.js const hello = require('./hello') console.log(hello) Copy the code
One more question:
// hello.js exports.a = 3 module.exports = { b: 4 } // index.js const hello = require('./hello') console.log(hello) Copy the code
Because of the differences between the two, there are compatibility issues that need to be resolved when converting the two.
Exports of transformation
Exports {} export default {} export default {} export default {} export default {} export default {}
// Input: index.cjs
exports.a = 3
// Output: index.mjs
// Convert the default export to a named export!
export const a = 3
export default { a }
Copy the code
What happens if you just convert to a named export of export const a = 3 without converting export default {a}? Here’s an example:
// Input: CJS
exports.a = 3 // index.cjs
const o = require('. ') // foo.cjs
console.log(o.a) // foo.cjs
// Output: ESM
// This is an example of a problematic error conversion:
// here a should export default {a} again
export a = 3 // index.mjs
import o from '. ' // foo.mjs
console.log(o.a) // foo.mjs has a problem here, a problem here, a problem here
Copy the code
The transformation of the module. Exports
For module.exports, we can iterate over the key (via the AST), converting key to Named Export and module.exports to Named Export
// Input: index.cjs
module.exports = {
a: 3.b: 4
}
// Output: index.mjs
// Convert the default export to a named export!
export default {
a: 3.b: 4
}
export const a = 3
export const b = 4
Copy the code
What if module.exports exports functions, especially exports mixed with module.exports program logic?
Here is a correct conversion result:
// Input: index.cjs
module.exports = () = > {}
exports.a = 3
exports.b = 4
// Output: index.mjs
const sum = () = > {}
sum.a = 3
sum.b = 4
export const a = 3
export const b = 4
export default = sum
Copy the code
Module. exports and exports code usage functions can be wrapped in this way, without worrying about the logical details.
var esm$1 = {exports: {}};
(function (module.exports) {
module.exports = () = > {};
exports.a = 3;
exports.b = 4;
}(esm$1, esm$1.exports));
var esm = esm$1.exports;
export { esm as default };
Copy the code
Some complicated transformations
ESM and CommonJS are not only different in simple syntax, but also completely different in way of thinking. Therefore, there are some more complicated transformations, which will not be discussed in this article. If you are interested, you can find relevant articles on my blog.
- How to deal with
__dirname
- How to deal with
require(dynamicString)
- How to handle programming logic in CommonJS, as follows
The following code involves programming logic, since exports is a dynamic Javascript object that can naturally be used twice, how should it compile properly to ESM?
// input: index.cjs
exports.sum = 0
Promise.resolve().then(() = > {
exports.sum = 100
})
Copy the code
The following is a code conversion result that doesn’t go wrong
// output: index.mjs
const _default = { }
let sum = _default.sum = 0
Promise.resolve().then(() = > {
sum = _default.sum = 100
})
export default _default
export { sum }
Copy the code
CommonJS To ESM build tool
CommonJS conversion to ESM naturally involves build tools such as
- @rollup/plugin-commonjs
Some CommonJS libraries are even converted to ESM and placed in CDN so that we can use them directly without building tools
- cdn.skypack.dev/
- jspm.org/