DEV Community

Mario
Mario

Posted on • Originally published at mariokandut.com on

How to convert a CJS module to an ESM

This article is based on Node v16.14.0.

Since Node v14 , there are two kinds of modules, CommonJS Modules (CJS) and EcmaScript Modules (ESM). EcmaScript Modules (ESM) were introduced as part of ES6 (EcmaScript 2015). The main goal was for module includes to be statically analyzable, so browsers would be able to pre-parse out imports. This behaviour is similar to collecting all <script> tags as the web page loads.

It took more than three years for major browsers to implement this retrofitting of a static module system into a dynamic language. And even longer for ESM to be implemented in NodeJS, because of interoperability with the existing CJS module system, though there are still some issues.

The main difference between CJS and ESM is that CJS loads every module synchronously , and ESM loads every module asynchronously.

There are also two types of ESM: native ESM and "transpiled ESM". Transpiled ESM is ESM-like syntax that would be typically be transpiled with Babel. The syntax looks similar, but the behaviour can vary. "Transpiled ESM" compiles to CommonJS in Node and will be compiled in the browser using a bundled synchronous loader. This means, that "transpiled ESM" loads modules synchronously, native ESM loads modules asynchronously.A Node application (or module) can contain CJS and ESM files.

Let's convert the module created in How to create a CSJ module.

The CSJ module contains this code:

'use strict';

const toUpper = str => {
  if (typeof str === 'symbol') str = str.toString(); // convert to string if symbol is used as input
  str += '';
  return str.toUpperCase();
};

module.exports = { toUpper };
Enter fullscreen mode Exit fullscreen mode

To convert it to an ESM module, the only we have to do change the file extension from .js to .mjs. If you are on linux you can use the mv command.

mv format.js format.mjs
Enter fullscreen mode Exit fullscreen mode

CJS modules modify the module.exports object, in ESM its native syntax. Hence, to create a named export, we can just use the export keyword.

Let's update our module:

export const toUpper = str => {
  if (typeof str === 'symbol') str = str.toString(); // convert to string if symbol is used as input
  str += '';
  return str.toUpperCase();
};
Enter fullscreen mode Exit fullscreen mode

The 'use strict' pragma to enforce strict mode is also not needed anymore, since ESM executes in strict-mode.

That's it for converting CSJ to ESM. There is only one thing, try to run the node application with node index. You will see an error.

internal/modules/cjs/loader.js:948
    throw new ERR_REQUIRE_ESM(filename);
    ^
Enter fullscreen mode Exit fullscreen mode

This error occurs because the require function will not automatically resolve a filename without an extension ('./format') to an .mjs extension.

Ok, so let's fix this and try again.

node -p "require('./format.mjs')"
Enter fullscreen mode Exit fullscreen mode

We will get an error again.Error [ERR_REQUIRE_ESM]: Must use import to load ES Module.

The major difference between CSJ and ESM, is that CJS is synchronous. CJS cannot require ESM since that would break the synchronous constraint, but ESM can import CJS.

There is a way around this constraint with dynamic import. Have a look at this article How to dynamically load an ESM Module in CJS.

TL;DR

  • Since Node v14 , there are two kinds of modules, CommonJS Modules (CJS) and EcmaScript Modules (ESM).
  • The main difference between CJS and ESM is that CJS loads every module synchronously , and ESM loads every module asynchronously.
  • To convert a CSJ module to ESM, change the file ending to .mjs and use the export keyword instead of module.exports.
  • CJS cannot require ESM since that would break the synchronous constraint, but ESM can import CJS.
  • Use dynamic import for importing ESM in CSJ.

Thanks for reading and if you have any questions , use the comment function or send me a message @mariokandut.

If you want to know more about Node, have a look at these Node Tutorials.

References (and Big thanks):

NodeJS,JSNAD,CommonJS

Top comments (0)