reduxjs / redux-toolkit

The official, opinionated, batteries-included toolset for efficient Redux development
https://redux-toolkit.js.org
MIT License
10.7k stars 1.17k forks source link

NODE_ENV=development doesn't work in 2.x possible transpiliation issue or breaking change in 2.x? #4096

Closed jgraham909 closed 9 months ago

jgraham909 commented 9 months ago

I had updated my codebase to redux-toolkit 1.x last month and everything was working well. I saw that 2.x was released things have mostly updated smoothly to 2.0.1, but it doesn't seem to function if NODE_NEV=development. If NODE_ENV=production the build works okay and everything seems to be fine.

My existing project is running on next.js: not using typescript, using the pages functionality since it is a SPA. My app is also running a custom server.js with express to setup TLS, since to my knowledge that is not supported in next.js.

I tried scouring the 2.x notes, but it seemed to imply that other than changing how things are packaged there should be no breaking changes.

If I start with NODE_ENV=developement things work until a component with an RTK query endpoint eg useUserLoginMutation() is referenced. I get the following error: TypeError: react__WEBPACK_IMPORTED_MODULE_0__.useState is not a function originating from node_modules/@reduxjs/toolkit/dist/query/react/rtk-query-react.modern.mjs (376:44).

I added transpilePackages: ['@reduxjs'] to my next.config.js as I was receiving issues related to ts files prior on the 2.x branch. That got it to the point where the initial page load works.

Everything worked okay in 1.x, and everything works okay if NODE_ENV=production. I'm suspecting either I'm missing something with the new package setup and/or my next configuration or this may be an undocumented breaking change with the newer module release packaging in 2.x?

Any ideas or things to try in order to more successfully debug would be greatly appreciated.

markerikson commented 9 months ago

That seems extremely surprising - we tested 2.0 pretty thoroughly and have used it in both dev and prod builds.

Can you share a repo that shows this happening?

Can you also share the entire stack trace of the error? And is this happening on the client side, or in SSR?

jgraham909 commented 9 months ago

I can't share the repo in question. I'll try to reproduce on something smaller/generic.

I'm not sure, but this feels like it might be related to a webpack or other misconfig. It seems like there is an additional resource needed that isn't available.

I think this is happening client side, attached is the error from the browser I'm assuming this is the "entire stack trace" but if you meant something different let me know. callstack.txt

markerikson commented 9 months ago

Yeah, that definitely reads to me as a CJS/ESM mismatch. The correct RTK 2.0 build artifact has been loaded ( rtk-quer-react.modern.mjs ). It's being called from the right react-dom.development.js artifact. Webpack is supposed to be handling the interop between ESM and CJS here.

Out of curiosity, if you ensure you have import React from "react", and then do console.log(React) in this file, what does it log? My bet is that it's an object that looks like {default: {useState, useEffect, .........}} (in other words, the React default export nested inside of a field named default ).

Also, what version of Next are you using?

jgraham909 commented 9 months ago

Next.js is 14.0.4. I wasn't sure what you meant by "in this file":

React object Server side:

React object Client side:

markerikson commented 9 months ago

If you can provide a repro project I can take a look, but this feels like it's likely more of a CJS/ESM interop issue on the Next / Webpack side. It's still possible I might have screwed up something with the package exports definitions, but I'm fairly confident that the definitions are right.

jgraham909 commented 9 months ago

"this feels like it's likely more of a CJS/ESM interop issue on the Next / Webpack side"

Seems reasonable. I'm thinking this is quite possibly a misunderstanding of something on my part.

I'm a bit confused as redux-toolkit has stuff prebuilt in dist, and it clearly uses that from the stack trace, but if I remove transpilePackages: [ '@reduxjs'] from my next.config.js it throws typescript errors. Why does it need to transpile if it just loads rtk-query-react.modern.mjs?

markerikson commented 9 months ago

@jgraham909 if you've got some time, you might want to read through the post I have at https://blog.isquaredsoftware.com/2023/08/esm-modernization-lessons/ that talks about the work I had to do last year to modernize the Redux packages and improve our ESM artifact support.

I strongly suspect that the runtime symptom you're seeing is that there's some kind of CJS/ESM interop issue as Webpack is loading the RTKQ .mjs artifact, but trying to import React from its CJS artifact.

I also would not expect that you need to have transpilePackages at all here. What TS errors are you seeing?

jgraham909 commented 9 months ago

Thanks I'll read up on your resource.

Details on the painful experiences and hard-earned lessons I've learned migrating the Redux packages to ESM

I think that's right where I'm at. :laughing:

Without @reduxjs in transpile packages for next.js I get the following;

Failed to compile

./node_modules/@reduxjs/toolkit/src/dynamicMiddleware/react/index.ts
Module parse failed: Unexpected token (1:12)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders
> import type {
|   Action as ReduxAction,
|   UnknownAction,

This error occurred during the build process and can only be dismissed by fixing the error.
EskiMojo14 commented 9 months ago

do you have any @reduxjs/toolkit/dist/ or @reduxjs/toolkit/src/ imports? i'm kinda confused why it's looking at TS files at all

markerikson commented 9 months ago

Yeah, Next should not be reading that file whatsoever. That's part of our lib source, and Next should only be looking at the pre-built bundles in dist.

jgraham909 commented 9 months ago

do you have any @reduxjs/toolkit/dist/ or @reduxjs/toolkit/src/ imports? i'm kinda confused why it's looking at TS files at all

Here is the complete list of my @redux imports

redux/store.js:2:import { configureStore } from '@reduxjs/toolkit';
redux/store.js:3:import { setupListeners } from '@reduxjs/toolkit/query';
redux/services/APIDEFINITION.js:1:import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react';
redux/modules/reducer.js:1:import { combineReducers } from '@reduxjs/toolkit';
jgraham909 commented 9 months ago

Yeah, Next should not be reading that file whatsoever. That's part of our lib source, and Next should only be looking at the pre-built bundles in dist.

Should I open an issue with next.js?

markerikson commented 9 months ago

None of those look like they should be causing Next to read one of our source files.

That feels to me like it's the actual root issue here, but I don't know what would be causing it atm (and is another example of why we would really need a repro project to investigate).

Yeah, filing an issue with Next is probably the best option atm.

jgraham909 commented 9 months ago

and is another example of why we would really need a repro project to investigate

Working on it, and I'll follow up with next.js once I have one.

Thanks for your time @markerikson

jgraham909 commented 9 months ago

I'm closing this out. As this is not an issue with redux-toolkit. Thanks for the help!

The import trace and error behavior is still very weird to me, especially since it works fine when NODE_ENV=production posted for posterity since the import trace may be of interest as it incorrectly implicates redux-toolkit:

Module parse failed: Unexpected token (1:12)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders
> import type {
|   Action as ReduxAction,
|   UnknownAction,

Import trace for requested module:
./node_modules/@reduxjs/toolkit/src/dynamicMiddleware/react/index.ts
./node_modules/@reduxjs/toolkit/src/react/index.ts
./node_modules/@reduxjs/toolkit/dist/query/react/rtk-query-react.modern.mjs
./redux/services/myAPI.mjs
./redux/store.mjs

My local changes which I think resolved the issue

In case anyone experiences this behavior with a next.js app try making sure you don't have extra junk laying around and reference a clean npx create-next-app@latest to ensure you have current dependencies.

I'm not 100% of the issue but the only thing I think could be the culprits are included below. Extraneous dependencies from package.json were removed, specifically:

also added the following as devDependencies, these are also likely causes since the issue was only when NODE_ENV=development:

npx create-next-app@latest' also creates a file next-env.d.ts in the app root with the following contents even if you say "no" to typescript even though I'm not using typescript I've added the file:

/// <reference types="next" />
/// <reference types="next/image-types/global" />

// NOTE: This file should not be edited
// see https://nextjs.org/docs/basic-features/typescript for more information.

There was also an extraneous .env with the following contents:

NODE_PATH=./src
NODE_ENV=production
PORT=80

I've also removed some legacy pages 404.jsx and _error.jsx

markerikson commented 9 months ago

Huh. That is still really weird. Nothing about our build artifacts should be referencing the src folder. No idea what's happening there :( 🤷‍♂️

kerensternbriya commented 7 months ago

Updating that I am getting the same error in my repo, which doesn't use Next (using React and Webpack). It started happening when updating redux-toolkit from V1 to V2.

I upgraded React, react-redux, webpack and any other packages I thought might be relevant, but still no luck 😅 .

I'm importing only from '@reduxjs/toolkit/query' and '@reduxjs/toolkit/query/react'.

In the console I get the same error as above: Syntax error: Unexpected token, expected "from" (1:12) node_modules/@reduxjs/toolkit/src/dynamicMiddleware/react/index.ts

1 | import type { | ^ 2 | Action as ReduxAction, 3 | UnknownAction, 4 | Dispatch as ReduxDispatch,

I've copied the full stack trace below.

Also in my terminal I get errors about react imports when running yarn start:

e.g:

ERROR in ./node_modules/@reduxjs/toolkit/dist/query/react/rtk-query-react.modern.mjs 403:6-16
export 'useEffect' (imported as 'useEffect3') was not found in 'react' (possible exports: ReducerType, SHOULD_AUTOBATCH, TaskAbortError, Tuple, __DO_NOT_USE__ActionTypes, addListener, applyMiddleware, asyncThunkCreator, autoBatchEnhancer, bindActionCreators, buildCreateSlice, clearAllListeners, combineReducers, combineSlices, compose, configureStore, createAction, createActionCreatorInvariantMiddleware, createAsyncThunk, createDraftSafeSelector, createDraftSafeSelectorCreator, createDynamicMiddleware, createEntityAdapter, createImmutableStateInvariantMiddleware, createListenerMiddleware, createNextState, createReducer, createSelector, createSelectorCreator, createSerializableStateInvariantMiddleware, createSlice, createStore, current, findNonSerializableValue, formatProdErrorMessage, freeze, isAction, isActionCreator, isAllOf, isAnyOf, isAsyncThunkAction, isDraft, isFluxStandardAction, isFulfilled, isImmutableDefault, isPending, isPlain, isPlainObject, isRejected, isRejectedWithValue, legacy_createStore, lruMemoize, miniSerializeError, nanoid, original, prepareAutoBatched, removeListener, unwrapResult, weakMapMemoize)
Uncaught Error: Module build failed (from ./node_modules/babel-loader/lib/index.js):
SyntaxError: /<repo_root>/node_modules/@reduxjs/toolkit/src/dynamicMiddleware/react/index.ts: Unexpected token, expected "from" (1:12)

> 1 | import type {
    |             ^
  2 |   Action as ReduxAction,
  3 |   UnknownAction,
  4 |   Dispatch as ReduxDispatch,
    at instantiate (<repo_root>i/node_modules/@babel/parser/lib/index.js:67:32)
    at constructor (<repo_root>i/node_modules/@babel/parser/lib/index.js:364:12)
    at Parser.raise (<repo_root>i/node_modules/@babel/parser/lib/index.js:3363:19)
    at Parser.unexpected (<repo_root>i/node_modules/@babel/parser/lib/index.js:3396:16)
    at Parser.expectContextual (<repo_root>i/node_modules/@babel/parser/lib/index.js:3732:18)
    at Parser.parseImport (<repo_root>i/node_modules/@babel/parser/lib/index.js:14541:12)
    at Parser.parseStatementContent (<repo_root>i/node_modules/@babel/parser/lib/index.js:13079:27)
    at Parser.parseStatementLike (<repo_root>i/node_modules/@babel/parser/lib/index.js:12963:17)
    at Parser.parseModuleItem (<repo_root>i/node_modules/@babel/parser/lib/index.js:12944:17)
    at Parser.parseBlockOrModuleBlockBody (<repo_root>i/node_modules/@babel/parser/lib/index.js:13569:36)
    at Parser.parseBlockBody (<repo_root>i/node_modules/@babel/parser/lib/index.js:13561:10)
    at Parser.parseProgram (<repo_root>i/node_modules/@babel/parser/lib/index.js:12853:10)
    at Parser.parseTopLevel (<repo_root>i/node_modules/@babel/parser/lib/index.js:12843:25)
    at Parser.parse (<repo_root>i/node_modules/@babel/parser/lib/index.js:14751:10)
    at parse (<repo_root>i/node_modules/@babel/parser/lib/index.js:14793:38)
    at parser (<repo_root>i/node_modules/@babel/core/lib/parser/index.js:41:34)
    at parser.next (<anonymous>)
    at normalizeFile (<repo_root>i/node_modules/@babel/core/lib/transformation/normalize-file.js:65:38)
    at normalizeFile.next (<anonymous>)
    at run (<repo_root>i/node_modules/@babel/core/lib/transformation/index.js:21:50)
    at run.next (<anonymous>)
    at transform (<repo_root>i/node_modules/@babel/core/lib/transform.js:22:41)
    at transform.next (<anonymous>)
    at step (<repo_root>i/node_modules/gensync/index.js:261:32)
    at <repo_root>i/node_modules/gensync/index.js:273:13
    at async.call.result.err.err (<repo_root>i/node_modules/gensync/index.js:223:11)
    at <repo_root>i/node_modules/gensync/index.js:189:28
    at <repo_root>i/node_modules/@babel/core/lib/gensync-utils/async.js:68:7
    at <repo_root>i/node_modules/gensync/index.js:113:33
    at step (<repo_root>i/node_modules/gensync/index.js:287:14)
    at <repo_root>i/node_modules/gensync/index.js:273:13
    at async.call.result.err.err (<repo_root>i/node_modules/gensync/index.js:223:11)
    at <repo_root>i/node_modules/gensync/index.js:37:40
    at ./node_modules/@reduxjs/toolkit/src/dynamicMiddleware/react/index.ts (util.js:6:1)
    at options.factory (react refresh:6:1)
    at __webpack_require__ (bootstrap:22:1)
    at fn (hot module replacement:61:1)
    at ./node_modules/@reduxjs/toolkit/src/react/index.ts (util.js:6:1)
    at options.factory (react refresh:6:1)
    at __webpack_require__ (bootstrap:22:1)
    at fn (hot module replacement:61:1)
    at ./node_modules/@reduxjs/toolkit/dist/query/react/rtk-query-react.modern.mjs (index.js:7:1)
    at options.factory (react refresh:6:1)
markerikson commented 7 months ago

@kerensternbriya : it's the same general sort of issue. Somehow your build system is treating node_modules/@reduxjs/toolkit/src/react as the target of a "react" import in your application code. Not sure how that could be happening, but it is.

kerensternbriya commented 7 months ago

@markerikson thanks for the quick response.

Yeah it's very weird.

The file where it looks like the react import error is being thrown (which sets up the api param using createApi) is actually not importing or using React directly - I am only importing the following:

import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react'; import config from 'Config';

henrytranvn93 commented 4 months ago

any update on this, I got the same issue with my project after updating to 2.0:

[CLIENT] ERROR in ./node_modules/@reduxjs/toolkit/src/dynamicMiddleware/react/index.ts 1:12
[CLIENT] Module parse failed: Unexpected token (1:12)
[CLIENT] You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders
[CLIENT] > import type {
[CLIENT] |   Action as ReduxAction,
[CLIENT] |   UnknownAction,
[CLIENT]  @ ./node_modules/@reduxjs/toolkit/src/react/index.ts 6:0-68 6:0-68
[CLIENT]  @ consume shared module (default) react@^16.8 || ^17 || ^18 (singleton) (fallback: ./node_modules/@reduxjs/toolkit/src/react/index.ts)
[CLIENT]  @ ./node_modules/@reduxjs/toolkit/dist/query/react/rtk-query-react.modern.mjs 32:0-143 68:0-51 70:19-26 78:17-23 79:2-11 88:0-67 91:17-24 92:2-12 101:120-135 101:138-148 129:84-94 171:11-22 189:39-46 217:40-47 218:25-32 258:6-16 264:13-21 285:28-36 286:25-32 299:37-44 303:22-33 315:6-16 320:6-16 325:13-21 335:24-31 336:34-42 341:28-36 364:21-29 367:15-23 383:8-21 391:15-23 408:36-44 409:6-16 414:30-41 424:34-42 428:31-39 431:20-31 453:6-19 462:25-33 467:13-21 582:0-35 583:0-48 584:0-26 589:26-36 593:18-32 599:2-12 600:25-44
[CLIENT]  @ ./src/client/components/SystemTasks/index.tsx 8:0-57 22:87-96
[CLIENT]  @ ./src/client/entries/HubWidget/App.tsx 20:0-58 32:28-39
[CLIENT]  @ ./src/client/entries/HubWidget/index.tsx 28:0-47 40:32-58 44:32-58
[CLIENT]  @ container entry ./EndUserManagementHubWidget[0
markerikson commented 4 months ago

@henrytranvn93 your build setup should not be trying to import from our src folder. Please check your config for things like aliases - that's most likely the issue.

henrytranvn93 commented 4 months ago

@markerikson thanks for a quick response, we didn't import any from reduxjs toolkit src folder. Tracing back in our baseapi: this is what we import:


import { BaseQueryFn, FetchArgs, FetchBaseQueryError, createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react'; 

export const baseApi = createApi({
  reducerPath: 'baseApi',
  tagTypes: [...tags
  ],
  baseQuery: dynamicBaseQuery,
  endpoints: () => ({}),
});
``
markerikson commented 4 months ago

@henrytranvn93 yeah, my point is that your build setup is likely aliasing something wrong and causing that import to resolve to our src folder. Check your build config.

henrytranvn93 commented 4 months ago

@markerikson thanks, it's super weird that we didn't have this problem before with version 1.9.7. After changing my webpack base config from this to that, it works

  resolve: {
    extensions: ['.js', '.jsx', '.ts', '.tsx', '.json', '.css', '.scss'],
    modules: ['src', 'node_modules'],
    plugins: [new TsconfigPathsPlugin()],
  },

  //to

    resolve: {
    extensions: ['.js', '.jsx', '.ts', '.tsx', '.json', '.css', '.scss'],
    modules: [path.resolve(__dirname, 'src'), 'node_modules'],
    plugins: [new TsconfigPathsPlugin()],
  },