GOTO 0
GOTO 0

Reputation: 47614

When can a CommonJS named export be imported by an ES module?

I have an ES module that uses a named export from a CommonJS module that I authored.

es.mjs

import { MyNamedExport } from './commonjs.cjs';

console.log(MyNamedExport);

commonjs.cjs (good one)

exports.MyNamedExport = 'OK';

When I run the ES module in Node.js like this everything is fine.

> node ./es.mjs
OK

Anyway, if the export part in the CommonJS module is changed in some seemingly irrelevant way, i.e. by adding a pair of parentheses, the named export stops working.

commonjs.cjs (bad one)

(exports).MyNamedExport = 'OK';
> node ./es.mjs
file:///path/to/current/folder/es.mjs:1
import { MyNamedExport } from './commonjs.cjs';
         ^^^^^^^^^^^^^
SyntaxError: Named export 'MyNamedExport' not found. The requested module './commonjs.cjs' is a CommonJS module, which may not support all module.exports as named exports.
CommonJS modules can always be imported via the default export, for example using:

import pkg from './commonjs.cjs';
const { MyNamedExport } = pkg;

    at ModuleJob._instantiate (node:internal/modules/esm/module_job:104:21)
    at async ModuleJob.run (node:internal/modules/esm/module_job:149:5)
    at async Loader.import (node:internal/modules/esm/loader:166:24)
    at async Object.loadESM (node:internal/process/esm_loader:68:5)

Of course, when my CommonJS named export is imported by another CommonJS module, the parentheses make no difference.

Why is this happening?

What should I do when I write a CommonJS module to make sure that named exports can be imported by ES modules?

Upvotes: 13

Views: 13596

Answers (1)

Bergi
Bergi

Reputation: 664195

From the docs:

For better compatibility with existing usage in the JS ecosystem, Node.js in addition [to the default import] attempts to determine the CommonJS named exports of every imported CommonJS module to provide them as separate ES module exports using a static analysis process.

[…]

The detection of named exports is based on common syntax patterns but does not always correctly detect named exports. In these cases, using the default import form described above can be a better option.

Named exports detection covers many common export patterns, reexport patterns and build tool and transpiler outputs. See cjs-module-lexer for the exact semantics implemented.

Upvotes: 8

Related Questions