Importing ES 6 Modules from CommonJS
Tags: javascript, typescript, ecmascript, node
Published: 2023-03-21 18:45:50

---
title: Importing ES 6 Modules from CommonJS
published: true
description: Suppose you have an application using CommonJS, and now you need features from a ES6 module. Is it possible to import that ES6 module? Well, today it is! Here is how.
tags: javascript, typescript, ecmascript, nodejs
cover_image: https://upload.wikimedia.org/wikipedia/commons/thumb/5/56/Handing_a_package_over_for_delivery.jpg/1024px-Handing_a_package_over_for_delivery.jpg
# Use a ratio of 100:42 for best results.
# published_at: 2023-03-21 18:32 +0000
---
Here at Liferay, a few days ago, we needed to use the [p-map](https://www.npmjs.com/package/p-map) package. There was only one problem: our application still uses the [CommonJS](https://nodejs.org/docs/latest/api/modules.html) format, and p-map releases [ES6 modules](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules) only. Even some of the best references I found (e.g. [this post](https://reflectoring.io/nodejs-modules-imports/)) made it clear that it would not be possible to import ES6 modules from CommonJS.

The good news is that this is no longer true! Using [dynamic `import`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/import), we can load ES6 modules from CommonJS. Let’s look at an example.

In this [project](https://github.com/brandizzi/es6commonjs/), the [`importer.js`](https://github.com/brandizzi/es6commonjs/blob/d7c3e3a69ef7828e6dcf714a5e83e77892294490/importer.js) file tries to use `require()` to import an ES6 module:

```javascript
const pmap = require('p-map');

exports.importer = () => {
  console.log('Yes, I could import p-map:', pmap);
}
```

Of course, it didn’t work:

```
$ node index.js 
internal/modules/cjs/loader.js:1102
      throw new ERR\_REQUIRE\_ESM(filename, parentPath, packageJsonPath);
      ^

Error \[ERR\_REQUIRE\_ESM\]: Must use import to load ES Module: /home/adam/software/es6commonjs/node\_modules/p-map/index.js
require() of ES modules is not supported.
require() of /home/adam/software/es6commonjs/node\_modules/p-map/index.js from /home/adam/software/es6commonjs/importer.js is an ES module file as it is a .js file whose nearest parent package.json contains "type": "module" which defines all .js files in that package scope as ES modules.
Instead rename index.js to end in .cjs, change the requiring code to use import(), or remove "type": "module" from /home/adam/software/es6commonjs/node\_modules/p-map/package.json.

    at new NodeError (internal/errors.js:322:7)
    at Object.Module.\_extensions..js (internal/modules/cjs/loader.js:1102:13)
    at Module.load (internal/modules/cjs/loader.js:950:32)
    at Function.Module.\_load (internal/modules/cjs/loader.js:790:12)
    at Module.require (internal/modules/cjs/loader.js:974:19)
    at require (internal/modules/cjs/helpers.js:101:18)
    at Object.<anonymous> (/home/adam/software/es6commonjs/importer.js:1:14)
    at Module.\_compile (internal/modules/cjs/loader.js:1085:14)
    at Object.Module.\_extensions..js (internal/modules/cjs/loader.js:1114:10)
    at Module.load (internal/modules/cjs/loader.js:950:32) {
  code: 'ERR\_REQUIRE\_ESM'
}
```

The solution is to convert `require()` into a dynamic `import`, a syntax where we invoke the `import` command as if it was an asynchronous function. But there is one detail: import imports return `Promise`s. There are many ways to deal with this; the simplest one is probably to make our function asynchronous, like in [this version](https://github.com/brandizzi/es6commonjs/blob/be491a9/importer.js):

```javascript
exports.importer = async () => {
  const pmap = await import('p-map');
  console.log('Yes, I could import p-map:', pmap);
}
```

Now our little app works!

```
$ node index.js 
ok
Yes, I could import p-map: \[Module: null prototype\] {
  AbortError: \[class AbortError extends Error\],
  default: \[AsyncFunction: pMap\],
  pMapSkip: Symbol(skip)
}
```

Some other adjustments may be necessary. (I had to adjust the [eslint](https://stackoverflow.com/questions/47815775/dynamic-imports-for-code-splitting-cause-eslint-parsing-error-import) settings, for example.) The important thing is that this is possible. And it’s not a kludge: [Node’s own documentation recommends this approach](https://nodejs.org/api/esm.html#import-expressions).

So, don’t be scared by outdated information: you won’t need to rewrite your entire application as ES 6 modules, at least for now. For us, this was quite a relief!https://suspensao.blog.br/disbelief/importing-es-6-modules-from-commonjs/

_(Cover image from [Wikimedia Commons](https://w.wiki/6UPZ).)_
_(The post [Importing ES 6 Modules from CommonJS](https://suspensao.blog.br/disbelief/importing-es-6-modules-from-commonjs/) was first published in [Suspension of Disbelief](https://suspensao.blog.br/disbelief/).)_