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

TypeError: Cannot set property WebSocket of #<Object> which has only a getter (Next.js) #2339

Closed
4 tasks done
lasseklovstad opened this issue Oct 29, 2024 · 4 comments
Closed
4 tasks done
Assignees
Labels
bug Something isn't working needs:triage Issues that have not been investigated yet. scope:node Related to MSW running in Node

Comments

@lasseklovstad
Copy link

Prerequisites

Environment check

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

Node.js version

20

Reproduction repository

https://github.com/lasseklovstad/msw-websocker-bug-nextjs

Reproduction steps

Run npm i, npm run dev and open the nextjs app

Current behavior

node_modules\@mswjs\interceptors\lib\browser\interceptors\WebSocket\index.mjs (668:1) @ _WebSocketInterceptor.setup ⨯ TypeError: Cannot set property WebSocket of #<Object> which has only a getter

Expected behavior

Nextjs app should work as before.

@lasseklovstad lasseklovstad added bug Something isn't working needs:triage Issues that have not been investigated yet. scope:node Related to MSW running in Node labels Oct 29, 2024
@kettanaito
Copy link
Member

Hi, @lasseklovstad. Thanks for reporting this!

I will take a look at this once I have a moment, I think I know the root cause of this.

@kettanaito kettanaito self-assigned this Oct 29, 2024
@kettanaito kettanaito changed the title Nextjs Websocket error in version 2.6.0 TypeError: Cannot set property WebSocket of #<Object> which has only a getter (Next.js) Oct 29, 2024
@kettanaito
Copy link
Member

Root cause

The issue is caused by Next.js defining the global WebSocket class (as it's missing in Node.js v20) in a way that forbids overrides:

https://github.com/vercel/next.js/blob/de4f197e2fde19526ee019fbebb068e962b58fc0/packages/next/src/server/node-environment-baseline.ts#L11-L15

This property definition doesn't support setters and doesn't have configurable: true to re-define this property. This is an extremely restrictive way to re-define a global.

Solution

Ideally, open a PR to Next to define that property with configurable: true. They don't own the WebSocket class, but even if they did, defining a global this way is too restrictive. This is a similar issue to how they used to define fetch in a way that was not overridable.

@kettanaito
Copy link
Member

I've opened a pull request to Next.js to fix this issue: vercel/next.js#72079. Hope the team will have time to look into this. Meanwhile, closed. Not an MSW issue. Please follow the progress at the linked pull request.

@kettanaito
Copy link
Member

I still think MSW should have a better developer experience around non-configurable globals, so I'm adding an error and disabling the interceptor if that's the case: mswjs/interceptors#665. Will make it easier to debug for everyone.

gnoff pushed a commit to vercel/next.js that referenced this issue Oct 30, 2024
…operty (#72079)

## What

The way Next.js re-defines a global `WebSocket` property makes it
non-configurable. No other agents, such as API mocking libraries, are
able to re-defined it. This [causes
issues](mswjs/msw#2339) for Next.js users.

# Why

Because the way the `WebSocket` property descriptor is set in Next.js
doesn't allow that property to be configured anymore (and neither does
it have a setter):


https://github.com/vercel/next.js/blob/de4f197e2fde19526ee019fbebb068e962b58fc0/packages/next/src/server/node-environment-baseline.ts#L11-L15

## How

This can be solved by setting `configurable: true` on the object
descriptor.

Generally, I'd advise against such restrictive descriptors for globals
Next.js doesn't own, like fetch or WebSocket. Try adhering to how such
globals are defined in Node.js—configurable and often with setters:

```
> Object.getOwnPropertyDescriptor(global, 'WebSocket')
{
  get: [Function: get WebSocket],
  set: [Function: set WebSocket],
  enumerable: false,
  configurable: true
}
```
stipsan pushed a commit to sanity-io/next.js that referenced this issue Nov 6, 2024
…operty (vercel#72079)

## What

The way Next.js re-defines a global `WebSocket` property makes it
non-configurable. No other agents, such as API mocking libraries, are
able to re-defined it. This [causes
issues](mswjs/msw#2339) for Next.js users.

# Why

Because the way the `WebSocket` property descriptor is set in Next.js
doesn't allow that property to be configured anymore (and neither does
it have a setter):


https://github.com/vercel/next.js/blob/de4f197e2fde19526ee019fbebb068e962b58fc0/packages/next/src/server/node-environment-baseline.ts#L11-L15

## How

This can be solved by setting `configurable: true` on the object
descriptor.

Generally, I'd advise against such restrictive descriptors for globals
Next.js doesn't own, like fetch or WebSocket. Try adhering to how such
globals are defined in Node.js—configurable and often with setters:

```
> Object.getOwnPropertyDescriptor(global, 'WebSocket')
{
  get: [Function: get WebSocket],
  set: [Function: set WebSocket],
  enumerable: false,
  configurable: true
}
```
@github-actions github-actions bot locked and limited conversation to collaborators Nov 14, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
bug Something isn't working needs:triage Issues that have not been investigated yet. scope:node Related to MSW running in Node
Projects
None yet
Development

No branches or pull requests

2 participants