← All tasks
javascriptimmerjs/immer #901Not a task: not reproduced

immer is not properly exported to be used in Node.js ESM modules

envgap__immerjs__immer-901

01 / FAILURE SIGNATURE

As reported upstream

# Error description
Not a benchmark task.
  • In a clean container the reported failure did not reproduce, or the known fix did not make the project run.

02 / ENVIRONMENT RECIPE

Base commit
53c2f9129781e6535c343adc7bf3681656df4920
Manifest
package.json
Reproduce
Awaiting issue-specific recipe
Run under trace
Awaiting a meaningful runtime command

03 / ORIGINAL ISSUE TEXT

immerjs/immer #901 · read the original issue
I am trying to use immer in the backend of a Node.js application. I am currently in the process of migrating my backend to [ESM modules](https://nodejs.org/api/esm.html), since some dependencies (in particular [node-fetch](https://github.com/node-fetch/node-fetch)) are starting to ship only ESM modules.



# Error description



When I try to import immer in an mjs module using `import produce from 'immer';`, `produce` will be an object instead of a function, with its `default` property being the produce function.



I can access the produce function by using `import { produce } from 'immer';` or by using `import immer from 'immer';` and then using `immer.produce()`. The problem is that the documentation uses `import produce from 'immer';`, so there are libraries using this whose code I am not in control of. This means that these libraries break when I migrate to ESM modules.



# Reason for the error



immer is bundled in several different formats, among them `cjs` and `esm`. The bundles are referenced in `package.json` in the following way (`index.js` being a wrapper that includes the `cjs` bundle):

```json

  "main": "dist/index.js",

  "module": "dist/immer.esm.js",

```



While the `module` property is probably supported by webpack and other bundlers, it does not seem to be supported by Node.js. Instead, Node.js uses the `exports` property to support different main files for different environments (see [here](https://nodejs.org/api/packages.html#nodejs-packagejson-field-definitions). Since that is not defined in this case, Node.js requires the file from the `main` property, which is a CommonJS bundle.



Even forcing Node.js to use the ESM bundle by doing `import produce from 'immer/dist/immer.esm.js';` does not solve the problem. The problem is that Node.js interprets files as CommonJS unless they have a `.jsm` file extension or `"type": "module"` is defined in `package.json` (which then applies to all files in the package) (see [here](https://nodejs.org/api/packages.html#determining-module-system)).



# Possible solution



Setting `"type": "module"` is probably not an option, since that will break the CommonJS files.



The only solution that I can think of is to ship the ESM bundle as an `.mjs` file, either by renaming the current one or by creating a copy. The file can then be referenced in `package.json` like this:

```json

  "exports": {

    "import": "./dist/immer.esm.mjs",

    "require": "./dist/index.js"

  },

```



# Workaround



If you are using immer yourself, use `import { produce } from 'immer';` rather than `import produce from 'immer';`.



I have not found a workaround for cases where dependencies whose code you don't control are using immer. A last resort is probably [yarn patch](https://yarnpkg.com/cli/patch).
Continue on GitHub ↗

04 / LABELS

Labels from the report text only; not yet run

No supported category has been assigned.

Label rules and the text that matched
[]