node.jses6-modulescommonjs

Why NodeJS is able to load esm modules without default export for some packages?


When you have an ESM module like this:

// greetings.js
export const hello = 'hello';
export const hi = 'hi';

and you try to import it using default export:

import greatings from './greetings.js';

You will get The requested module './greetings.js' does not provide an export named 'default' error, which is expected.

But for some packages, like yup, I noticed you can import it like this:

import yup from 'yup';

if you install Yup and check index.esm.js, you will notice, it also doesn't have any default export. so how we are able to import it using default?

If you want to say, Yup is shipped with a CommonJS module (index.js), I have to say yes, but some other packages like rotating-file-stream are also shipped with a CommonJS module, but we get the does not provide an export named 'default' error when we try to import it using default import.

I trid these:

import yup from 'yup';

console.log(yup);

and

import rfs from 'rotating-file-stream';

console.log(rfs);

first one works, but second one doesn't, why?!

P.S. I tested using latest versions of both yup (1.4.0) and rotating-file-stream (3.2.3).


Solution

  • The actual reason for this behavior is the fact that NodeJS ignores the module filed in the yup package. so it loads the CJS module.

    When NodeJS loads a CJS module, it puts everything in module.exports inside the default ESM export. so we can load yup like import yup from 'yup';.

    But in the other hand, rotating-file-stream has an exports field in the package.json file, which is supported by NodeJS, so NodeJS is able to load the actual ESM module because of it.

    When NodeJS loads the actual ESM module, It treats it as it is, and because the ESM module of rotating-file-stream has no default export, we see the error.

    See: https://nodejs.org/api/esm.html#interoperability-with-commonjs