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).04 / LABELS
Labels from the report text only; not yet run
No supported category has been assigned.
Label rules and the text that matched
[]