rybones
November 24, 2023, 3:00pm
#1
Hello,
I’m trying to setup the Mobx state management library inside my project, but not matter how much I try, it does not work correctly with the bundler.
Don’t matter how much I try I can’t get it to run with cocos. I’m trying a very basic example
TypeError: (intermediate value)(intermediate value)(intermediate value) is not a function
at new Todo (file:///D:/gamedev/cocos/projects/FlippyPlane/temp/programming/packer-driver/targets/editor/chunks/5c/file:/D:/gamedev/cocos/projects/FlippyPlane/assets/manager/scripts/state/StateManager.ts:9:9)
import { action, makeObservable, observable } from 'mobx';
export class Todo {
id = Math.random();
title = '';
finished = false;
constructor(title: string) {
makeObservable(this, {
title: observable,
finished: observable,
toggle: action,
});
this.title = title;
}
toggle() {
this.finished = !this.finished;
}
}
if I try to set it with mobx/dist/mobx.esm.js, I then get: [Scene] Error: Error: Unexpected export statement in CJS module.
rybones
November 24, 2023, 4:38pm
#2
Ok so I’ve spent a bit of time trying to understand the issue here and I might think this could be a bug for the engine/bundle process.
So basically I was able to setup Redux into my project, but the only reason was because the bundle was .mjs file. Currently, most modern exports for esm commons use the extension .ems.js instead of .mjs.
It works by renaming the extension from .ems.js to .mjs, puff.
So it seems that Cocos because of the name convention cannot resolve the module or is not including .ems.js extensions into the resolve path.
For a better solution I’ve found this neat trick
opened 10:37AM - 25 Jan 22 UTC
closed 01:29AM - 17 Apr 23 UTC
I have a bit of an unusual setup where I use redux-toolkit also in the backend o… f 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 redux-toolkit in an mjs module using `import { createSlice } from '@reduxjs/toolkit';`, I am receiving the following error:
```
SyntaxError: Named export 'createSlice' not found. The requested module '@reduxjs/toolkit' is a CommonJS module, which may not support all module.exports as named exports.
CommonJS modules can always be imported via the default export, for example using:
import pkg from '@reduxjs/toolkit';
const { createSlice } = pkg;
```
The workaround suggested in the error message does work for Node.js mjs files. The problem is that the code where I use redux-toolkit is shared by the backend (running on Node.js) and the frontend (compiled using webpack). With the workaround in place, webpack can now not compile the file anymore and gives the following error:
```
export 'default' (imported as 'toolkit') was not found in '@reduxjs/toolkit' (possible exports: MiddlewareArray, __DO_NOT_USE__ActionTypes, applyMiddleware, bindActionCreators, combineReducers, compose, configureStore, createAction, createAsyncThunk, createDraftSafeSelector, createEntityAdapter, createImmutableStateInvariantMiddleware, createNextState, createReducer, createSelector, createSerializableStateInvariantMiddleware, createSlice, createStore, current, findNonSerializableValue, freeze, getDefaultMiddleware, getType, isAllOf, isAnyOf, isAsyncThunkAction, isDraft, isFulfilled, isImmutableDefault, isPending, isPlain, isPlainObject, isRejected, isRejectedWithValue, miniSerializeError, nanoid, original, unwrapResult)
```
# Reason for the error
redux-toolkit 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/redux-toolkit.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 { createSlice } from '@reduxjs/toolkit/dist/redux-toolkit.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)).
Node.js does support importing CommonJS packages in most cases, but in the case of redux-toolkit for some reason it doesn’t work. I am not sure why, but none of my other dependencies had this problem.
# 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/redux-toolkit.esm.mjs",
"require": "./dist/index.js"
},
```
This solution does not solve the problem completely, as redux-toolkit uses immer, which has a similar problem. I have reported that as immerjs/immer#901.
# Workaround
Use the import like this:
```javascript
import * as toolkitRaw from '@reduxjs/toolkit';
const { createSlice } = toolkitRaw.default ?? toolkitRaw;
```
or in Typescript:
```typescript
import * as toolkitRaw from '@reduxjs/toolkit';
const { createSlice } = ((toolkitRaw as any).default ?? toolkitRaw) as typeof toolkitRaw;
```
rybones
November 24, 2023, 5:45pm
#3
In fact no luck after the build =T
rybones
November 24, 2023, 7:41pm
#4
Found one file for Mobx that works
import mobx from 'mobx/dist/mobx.cjs.development.js';
1 Like