socketio / socket.io

Realtime application framework (Node.JS server)
https://socket.io
MIT License
61.18k stars 10.11k forks source link

Does not work with Nuxt 3 in prod with latest packages #5208

Closed beermonsterdota closed 2 weeks ago

beermonsterdota commented 1 month ago

Method from guide worked fine until nuxt/nitro updated crossws version to 0.3.0, where peer.ctx is moved to peer._internal. Simple change from ctx to _internal will work only in dev mode, but _iternal are undefined in production mode.

Possible temp solution Downgrade crossws version from 0.3.x to 0.2.4 - seems like it was last version that works

Not really socket.io bug, but probably you'll want to update guide

beermonsterdota commented 1 month ago

Seems like i've spent too much time trying to figure out reason why it suddenly stopped working.

Solution for 0.3.x crossws versions:

nitroApp.router.use(
    '/socket.io/',
    defineEventHandler({
      handler(event) {
        // @ts-expect-error private method
        engine.handleRequest(event.node.req, event.node.res)
        event._handled = true
      },
      websocket: {
        open(peer) {
          // @ts-expect-error private method
          const internal = peer._internal
          const req = internal.request
          // @ts-expect-error private method
          engine.prepare(req)

          // @ts-expect-error
          const rawSocket = internal.request._req.socket
          const websocket = internal.ws

          // @ts-expect-error private method
          engine.onWebSocket(req, rawSocket, websocket)
        }
      }
    })
  )
mhfeizi commented 3 weeks ago

It doesn't work for me with https :

Seems like i've spent too much time trying to figure out reason why it suddenly stopped working.

Solution for 0.3.x crossws versions:

nitroApp.router.use(
    '/socket.io/',
    defineEventHandler({
      handler(event) {
        // @ts-expect-error private method
        engine.handleRequest(event.node.req, event.node.res)
        event._handled = true
      },
      websocket: {
        open(peer) {
          // @ts-expect-error private method
          const internal = peer._internal
          const req = internal.request
          // @ts-expect-error private method
          engine.prepare(req)

          // @ts-expect-error
          const rawSocket = internal.request._req.socket
          const websocket = internal.ws

          // @ts-expect-error private method
          engine.onWebSocket(req, rawSocket, websocket)
        }
      }
    })
  )

It works :

nitroApp.router.use(
    "/socket.io/",
    defineEventHandler({
      handler(event) {
        // @ts-expect-error private method
        engine.handleRequest(event.node.req, event.node.res);
        event._handled = true;
      },
      websocket: {
        open(peer) {
          // @ts-expect-error private method and property
          engine.prepare(peer._internal.nodeReq);
          // @ts-expect-error private method and property
          engine.onWebSocket(peer._internal.nodeReq, peer._internal.nodeReq.socket, peer.websocket);
        }
      }
    }));
MickL commented 3 weeks ago

This sound to me like an issue with either Nitro or unjs/crossws but not Nuxt and not Socket.io ?

darrachequesne commented 2 weeks ago

The guide has been updated to work with crossws@^0.3.0: https://socket.io/how-to/use-with-nuxt#hook-the-socketio-server

The example too: https://github.com/socketio/socket.io/tree/main/examples/nuxt-example

Thanks for the heads-up!

fmgrafikdesign commented 2 weeks ago

This issue seems to not be fixed, and the minimal example does not work because of the issue outlined above. It does work fine in dev but does not for production. I can observe the same behavior in my application after updating. Accessing nodeReq on peer._internal is not possible in production. It throws errors like this and prevents the connection to be established / upgraded properly.

[nitro] [unhandledRejection] TypeError: Cannot read properties of undefined (reading 'nodeReq')

fmgrafikdesign commented 1 week ago

The issue was resolved by the latest (3.14) nuxt release, which upgraded nitropack to the 2.10 version which also uses crossws >=0.3 🥳 I speculate that the issue stemmed from socket.io and nitropack (nuxt server layer) using different crossws version, leading to incompatibilities.

To resolve the issue, upgrade to the latest nuxt version (3.14).

If this is for any reason not possible for you, you could try to just try to update the nitropack dependency to >=2.10 (I have not tested this).