vercel / next.js

The React Framework
https://nextjs.org
MIT License
126.86k stars 26.97k forks source link

NextJS 13.4 (App Routing System) Socket.IO Integration #51252

Open bahmanworld opened 1 year ago

bahmanworld commented 1 year ago

How to integrate Socket.IO into NextJS route.ts?

import {Server} from 'socket.io'

export const POST = (request: Request) => {
   // todo
}
codad5 commented 1 year ago

How to integrate Socket.IO into NextJS route.ts?

import {Server} from 'socket.io'

export const POST = (req: Request) => {
   // todo
}

Have you gotten a fix for it ?

bahmanworld commented 1 year ago

How to integrate Socket.IO into NextJS route.ts?

import {Server} from 'socket.io'

export const POST = (req: Request) => {
   // todo
}

Have you gotten a fix for it ?

Not yet, I'm still waiting for a dev from vercel.

dkajolroy commented 1 year ago

Same problem.

nitayStain commented 1 year ago

Did you find anything?

fullgream commented 1 year ago

I tried adding a new server to the instrumentation.ts, but getting error. Module not found “crypto”

fullgream commented 1 year ago

I tried adding a new server to the instrumentation.ts, but getting error. Module not found “crypto”

Upd. In my instrumentation.ts I added


export async function register() {
  if (process.env.NEXT_RUNTIME === "nodejs") {
    await import("./lib/server");
  }
}

In server.ts

import { App } from "uWebSockets.js";
import { Server, Socket } from "socket.io";

const app = App();
export const io = new Server<
  ClientToServerEvents,
  ServerToClientEvents,
  InterServerEvents,
  SocketData
>();
io.attachApp(app);
  app.listen(privateEnv.WS_PORT, (token) => {
    if (!token) {
      return console.warn("port already in use");
    }
    console.log(`Socket server listening to port ${privateEnv.WS_PORT}`);
  });

aaaand it working. image

But where is a problem. Then I tried to use server (for emit, for example) I'm getting error:

./node_modules/uWebSockets.js/uws_darwin_arm64_93.node
Module parse failed: Unexpected character '�' (1:0)
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
(Source code omitted for this binary file)

and then I stop using uWebSocket I'm getting error

./node_modules/engine.io-client/build/esm/transports/index.js
Attempted import error: 'WT' is not exported from './webtransport.js' (imported as 'WT').

Maybe I missed something? I suspect that once the server is up and running there is no access to it from other parts of the code and it is running in a separate environment somewhere. Or is it still accessible?

fullgream commented 1 year ago

Yes, after a few tests with the default socket.io servers I found that in case of instrumentation they are running somewhere in the background and cannot be accessed. After I accessed the io instance the server tried to restart instead of giving me back the already running version (I got an error that the port was already in use)

Maks-Yaremenko commented 4 months ago

Do you have any updates on this? I was able to integrate socket.io using pages, but due to app routes not having response property in request handlers I'm unable to migrate the solution to route.ts

/pages/api/socket.ts

type NextApiResponseWithSocket = NextApiResponse & {
  socket: {
    server: HttpServer & {
      io?: IOServer;
    };
  };
};

const ioHandler = (req: NextApiRequest, res: NextApiResponseWithSocket) => {
  if (!res.socket.server.io) {
    console.log("Starting Socket.IO server...");
    const io = new IOServer(res.socket.server, {
      path: "/api/socket",
    });
    res.socket.server.io = io;

    io.on("connection", (socket) => {
      console.log("New client connected");

      socket.on("message", (msg) => {
        console.log("Message received:", msg);
        socket.broadcast.emit("message", msg);
      });

      socket.on("disconnect", () => {
        console.log("Client disconnected");
      });
    });
  } else {
    console.log("Socket.IO server already running.");
  }
  res.end();
};

export default ioHandler;

The above file works as expected, at least in dev env.

/api/socket/route.ts

import { NextApiRequest, NextApiResponse } from "next";
import { Server as HttpServer } from "http";
import { Server as IOServer } from "socket.io";

type NextApiResponseWithSocket = NextApiResponse & {
  socket: {
    server: HttpServer & {
      io?: IOServer;
    };
  };
};

export async function GET(req: NextApiRequest, res: NextApiResponseWithSocket) {
  if (!res.socket.server.io) {
    console.log("Starting Socket.IO server...");
    const io = new IOServer(res.socket.server, {
      path: "/api/socket",
    });
    res.socket.server.io = io;

    io.on("connection", (socket) => {
      console.log("New client connected");

      socket.on("message", (msg) => {
        console.log("Message received:", msg);
        socket.broadcast.emit("message", msg);
      });

      socket.on("disconnect", () => {
        console.log("Client disconnected");
      });
    });
  } else {
    console.log("Socket.IO server already running.");
  }
  res.end();
}

TypeError: Cannot read properties of undefined (reading 'server')