Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Error Class extends value undefined is not a constructor or null occurs after the version upgrade from 0.49.2 to the latest version #1539

Closed
4 tasks done
JimLin94 opened this issue Feb 16, 2023 · 16 comments
Assignees
Labels
bug Something isn't working needs:triage Issues that have not been investigated yet. scope:browser Related to MSW running in a browser

Comments

@JimLin94
Copy link

Prerequisites

Environment check

  • I'm using the latest msw version
  • I'm using Node.js version 14 or higher

Browsers

Chromium (Chrome, Brave, etc.)

Reproduction repository

private code i am not allowed to share

Reproduction steps

I run into the error during the runtime after the MSW.js version upgrade.
It happens to the version between v0.49.3 to v1.0.1.

All the version 0.49.3 works fine before v0.49.3 for me.

image

AsyncEventEmitter.js:11 Uncaught TypeError: Class extends value undefined is not a constructor or null
    at __webpack_modules__../node_modules/@mswjs/interceptors/lib/utils/AsyncEventEmitter.js.__extends (AsyncEventEmitter.js:11:1)
    at AsyncEventEmitter.js:85:1
    at ./node_modules/@mswjs/interceptors/lib/utils/AsyncEventEmitter.js (AsyncEventEmitter.js:248:2)
    at __webpack_require__ (bootstrap:24:1)
    at fn (hot module replacement:62:1)
    at ./node_modules/@mswjs/interceptors/lib/Interceptor.js (Interceptor.js:16:27)
    at __webpack_require__ (bootstrap:24:1)
    at fn (hot module replacement:62:1)
    at ./node_modules/@mswjs/interceptors/lib/index.js (index.js:15:14)
    at __webpack_require__ (bootstrap:24:1)

Current behavior

package.json contains:
"msw": "1.0.1",

The entry point of the development mode. index.dev.tsx.

...
const worker = require('@mock-api/browser').default

worker.start().then(() => {
  renderApp()
})

The file handles the worker.

import { setupWorker } from 'msw'
import handlers from './handlers'

// This configures a Service Worker with the given request handlers.
const worker = setupWorker(...handlers())

export default worker

The file handles the handlers

...
import {
  rest,
  RestRequest,
  PathParams,
  ResponseResolver,
  ResponseComposition,
  RestContext,
} from 'msw'

export const handler = (responder = rest) => [
  responder.get(
    '....',
    withAuth((req, res, ctx) =>
      res(
        ctx.status(200),
        ctx.json({ ... })
      )
    )
  ),
...

Expected behavior

Working properly.

@JimLin94 JimLin94 added bug Something isn't working needs:triage Issues that have not been investigated yet. scope:browser Related to MSW running in a browser labels Feb 16, 2023
@JimLin94 JimLin94 changed the title Error Class extends value undefined is not a constructor or null occurs after the version upgrade from 0.49.2 Error Class extends value undefined is not a constructor or null occurs after the version upgrade from 0.49.2 to the latest version Feb 16, 2023
@DrZanuff
Copy link

Confirm the same problem. Just following this issue:
image

@azuline
Copy link

azuline commented Feb 21, 2023

I experienced this when transitively importing msw/node in a bundle that was loaded on the client. I resolved this by removing the msw/node import from the client bundle. I ended up with mocks.client.ts and mocks.server.ts, where only mocks.server.ts imported msw/node.

@mdbiscan
Copy link

I came across this same issue in Remix. I fixed it by doing this:

if (typeof process !== 'undefined' && process.env.NODE_ENV === 'development') {
  const { server } = require('./mocks/server');

  server.listen();
}

The typeof check is important. Otherwise, it'll try to run this in the browser and even though process is not available in the browser, it will still be truthy and attempt to execute.

@dustinmyers
Copy link

dustinmyers commented Mar 14, 2023

@JimLin94 I ran into this as well.

Going through the call stack, it looks like AsyncEventEmitter.js is an iife, and it's called with (strict_event_emitter_1.StrictEventEmitter)). However, with the latest dependency upgrades, strict-event-emitter@0.4.6 no longer has a module called StrictEventEmitter.

npm ls strict-event-emitter gives this:

npm ls strict-event-emitter             
portex-web-app@5.83.0 /Users/dustinmyers/Development/projects/portex/portex-web-app
└─┬ msw@1.1.0
  ├─┬ @mswjs/interceptors@0.17.9
  │ └── strict-event-emitter@0.2.8
  └── strict-event-emitter@0.4.6

Installing the older version - npm install strict-event-emitter@0.2.8 - get me past that error, but then I run into this error from SetupApi.ts due to the old version of strict-event-emitter not having the module Emitter any longer.

Screenshot 2023-03-14 at 11 02 57 AM

@oteoe
Copy link

oteoe commented Mar 17, 2023

I can confirm, same issue as @dustinmyers msw@1.1.0

@oteoe
Copy link

oteoe commented Mar 21, 2023

same issue in msw@1.1.1, downgrading to 49.2 fixes the problem but msw cant be updated to typescript 5.0

@Huespal
Copy link

Huespal commented Mar 28, 2023

Same happens here.
Upgrade from 0.49.2 to 1.2.1 and the error appears. Do not know what to do.
Using node version 18.15.0. Using Yarn v3.5.0 in pnp.
I was forced to add strict-event-emmiter to resolutions (v0.2.8 or v0.4.6)
With 0.2.8 -> TypeError: import_strict_event_emitter.Emitter is not a constructor error appears.
With 0.4.6 -> TypeError: Class extends value undefined is not a constructor or null error appears

A bit of a mess.

I will rollback to 0.49.2 and wait :)

@oteoe
Copy link

oteoe commented Mar 28, 2023

for me this seams like a different issue:
#1539 (comment)

@kettanaito
Copy link
Member

Thanks for the insights, everyone. The root cause seems to be for the @mswjs/interceptors code ending up in your bundle when using msw import. May be a matter of a broken import somewhere in the source. Need investigation.

@trivikr
Copy link

trivikr commented May 17, 2023

The issue is reproducible in v0.49.3, but not in v0.49.2

The only change in 0.49.3 was the switch to EventTarget-based event emitter in #1522
GitHub release: https://github.com/mswjs/msw/releases/tag/v0.49.3

@elisa-massafra
Copy link

HI, any updates regarding this? thank you!

@leword
Copy link

leword commented Jun 6, 2023

Just did a fresh install of msw and encountered this. The latest versions are broken this way out of the box, at least for some systems.

@oteoe
Copy link

oteoe commented Jun 6, 2023

is it possible to revert the changes from v0.49.3, it affects a lot of users, for us this is an update blocker for ts 5

@kettanaito
Copy link
Member

@dustinmyers is correct regarding this: there are conflicting versions of strict-event-emitter, with the one from @mswjs/interceptors@0.17.9 relying on the API that's present in strict-event-emitter@0.2 (Interceptors dependency) but gone in strict-event-emitter@0.4 (MSW dependency). This is odd and it suggests some tooling along the way treats 0.4.x version range as the one satisfying the 0.2.x version range, which is incorrect.

In any case, I think we should release yet another backport to Interceptors where we update strict-event-emitter to the same version that MSW uses and the issue should be gone.

@kettanaito
Copy link
Member

kettanaito commented Jun 13, 2023

How to solve this

I've opened a work-in-progress fix at mswjs/interceptors#382. It requires quite a lot of changes to adopt the old version of Interceptors (0.17.9) to the newer strict-event-emitter. To add insult to injury, I've already spent a lot of time migrating to those changes as a part of #1404.

I'm sorry to everyone blocked by this but I don't have the capacity to dive into a week of refactoring to support a backport version. MSW 1.x is stale as I wrote countless times on Twitter, and I highly encourage you to update to msw@next. I'm certain it has this issue fixed there, just as dozens of other issues. Please read #1464 to make your migration easier (there's a migration guideline inside).

I wish I had more time to handle these projects with proper care, providing backport fixes and such. I simply don't. I know it will make people sad but that's the reality. You can change it, instead of being sad, by Sponsoring MSW.

If you are blocked by this, this is the best time to migrate to msw@next. Or you can pick up mswjs/interceptors#382, look at what I did regarding Emitter in #1404 and push those changes to the backport. Thanks for understanding.

@githubjakob
Copy link

I'm writing this now mostly for learning purposes since I found the problem really interesting and want to understand more how dependency resolution in this case works - I hope that is ok!

To sum up first: As others already pointed out, the problem is that @mswjs/interceptors has it's own dependency on strict-event-emitter@0.2.8 while msw depends on strict-event-emitter@0.4.6. There is a breaking change between version 0.2.8 and 0.4.6 (which I understand according to Semantic Versioning is ok).

What puzzles me is that when I create a fresh project with CRA and install the latest version of msw my yarn.lock file and my node_modules looks exactly the same as in a project which crashes with Class extends value undefined is not a constructor or null.

The node_modules folder in the root of the project in both cases looks like this:

/strict-event-emitter                                  <- 0.4.6 in root of node_modules
/@mswjs/interceptors/node_modules/strict-event-emitter <- 0.2.8 another version inside @mswjs/interceptors

So in both cases it looks fine to me!

In the non-working app it seems now that node, when resolving the dependency in @mswjs/interceptors prioritizes the higher version of strict-event-emitter from the root node_modules folder, despite having the correct version of strict-event-emitter in the local node_modules folder.

I would expect that node searches for strict-event-emitter in all node_modules up the directory chain. But this is not the case. When I print module.paths, I can see that it only contains one node_modules (the root one):

[ '/Users/jakob/projects/not-working-app/node_modules' ]

As compared to in the working, fresh CRA app:

 [
        '/Users/jakob/projects/working-app/node_modules/@mswjs/interceptors/lib/utils/node_modules',
        '/Users/jakob/projects/working-app/node_modules/@mswjs/interceptors/lib/node_modules',
        '/Users/jakob/projects/working-app/node_modules/@mswjs/interceptors/node_modules',
        //...
        '/Users/jakob/node_modules',
        '/Users/node_modules',
        '/node_modules'
      ]

Consequently, when I change the line where strict-event-emitter is imported inside @mswjs/interceptors from

require('strict-event-emitter')

to the relative path

require('../../node_modules/strict-event-emitter')

it is importing the correct version and works as expected.

Does anybody understand why node (or any other involved tooling) is changing module.paths from one app to another? Or point me to any learning material that could help to further understand the problem?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working needs:triage Issues that have not been investigated yet. scope:browser Related to MSW running in a browser
Projects
None yet
Development

No branches or pull requests