This blog post explores how to write CommonJS modules so that their exports can be name-imported from ESM modules on Node.js.
This is what the Node.js documentation says about this topic:
When importing CommonJS modules, the module.exports object is provided as the default export. Named exports may be available, provided by static analysis as a convenience for better ecosystem compatibility.
In other words:
Consider the following ESM module:
// main.mjs
import {namedExport} from './lib.cjs'; // (A)
console.log(namedExport); // 'yes'
The import in line A works if the CommonJS module looks like this:
// lib.cjs
exports.namedExport = 'yes';
We can also assign to module.exports.namedExport
.
Assigning objects to module.exports
prevents named imports:
// lib.cjs
module.exports = {
namedExport: 'yes',
};
If we now run main.mjs
, we get an error:
SyntaxError: Named export 'namedExport' not found.
In contrast to normal named imports, named CommonJS imports are not live connections:
// main.mjs
import {namedExport, changeNamedExport} from './lib.cjs';
console.log(namedExport); // 'yes'
changeNamedExport();
console.log(namedExport); // 'yes'
// lib.cjs
exports.namedExport = 'yes';
exports.changeNamedExport = () => {
exports.namedExport = 'changed';
};
Section “ECMAScript modules” in “JavaScript for impatient programmers”
Section “Server side: CommonJS modules” in “JavaScript for impatient programmers”