~/ Require esm imports

See what I did there?

I recently encountered a project that used require for including external modules, and when upgrading the dependency's major version, I was met with this error:

Error [ERR_REQUIRE_ESM]: require() of ES Module .../node_modules/beeper/index.js from .../index.js not supported.
Instead change the require of index.js in .../index.js to a dynamic import() which is available in all CommonJS modules.
    at async Promise.all (index 0) {
  code: 'ERR_REQUIRE_ESM'
}

I'm curious about a couple of things here:

Steps to reproduce

in index.js:

const beeper = require('beeper');
beeper(3);

in package.json:

{
"dependencies": {
"beeper": "2.1.0"
}
}

Run node index.js. If I upgrade the dependency with npm install beeper@latest --save and rerun node index.js I see the ERR_REQUIRE_ESM.

What did beeper do between 2.1.0 and 3.0.0?

Looking at the 3.0.0 release I see:

This package is now pure ESM. Please read this.

There is a ton of useful information in here, but I wanted to see the beeper-specific change.

From https://github.com/sindresorhus/beeper/compare/v2.1.0...v3.0.0 I see a few useful things:

Reproduce the beeper package

The only things required to reproduce the ERR_REQUIRE_ESM are:

package/
├── index.js
└── package.json

where index.js is an empty file and package.json only has one property: "type": "module".

Neat! Now we know that the ERR_REQUIRE_ESM error is coming from the "type": "module" set in package.json.

From the documentation:

If the nearest parent package.json lacks a "type" field, or contains "type": "commonjs", .js files are treated as CommonJS. If the volume root is reached and no package.json is found, .js files are treated as CommonJS.

Oh that's interesting. NodeJS supports both CommonJS and ES Modules.

Is supporting both CJS and ES modules feasible?

Well, no; this looks pretty complex:

I now understand why the release notes linked to the Pure ESM Package note.


~/ Posted by Jesse Shawl on 2023-05-08