Closed GGAlanSmithee closed 2 days ago
You want to be able to access the WebSocket server outside of a SOCKET route? There isn't currently anyway to do that I believe, but I'll look into it.
Thanks for your answer.
Yes, more specifically in a custom server.
I'm my case, I need to run some cronjobs at startup which needs to access the socket, but it could also be useful for the more general case where you want to use the connected event for whatever reason.
I haven't actually looked at this myself, but since (I guess) this package monkey patches nextjs with ws functionality, maybe the server sticker is already "there" at the time of startup?
I've tried a few methods but I'm able to make the WS server globally available. Do you have a Next.js custom server sort of template that I can use to test?
@apteryxxyz I will put up an repo right away.
interestingly, when actually testing this right now, it seems that next-ws is not compatible with next.js custom server at all atm.
Notice the different outcome in the image below when running next dev
vs node server.js
:
(which does make sense, since the server is not patched in the node server.js
case. But it would be very interesting to have an api to be able to path it yourself. Or maybe I can deduce it from looking through the code)
Here is a repo to test with, just run npm run dev
: https://github.com/GGAlanSmithee/nextjs-ws-custom-server
Yeah I get that error as well, it comes somewhere from app.prepare()
.
Next ws grabs the http server from the server options of the next server, aka the object you pass to the next
function. Even if you do pass the custom server to that, it doesn't exist on the server options next ws receives. I'm not too sure why.
Not being able to use with custom server is also preventing me from adopting this package as well
I've just published an experimental version of Next WS (next-ws@experimental
) that adds support for custom servers. It appears to work but it's not fully tested.
The way it works is by you assigning your own http server (and optionally ws server) to a global variable, which Next WS will check for when setting up the server. I'm not a fan of assigning to global, but I prefer this over having to patch more things in Next.js.
CustomHttpServer
, CustomWsServer
are two symbols that get exported from next-ws/server
and can be used to assign your custom http server to the global object.
This is the setup I used:
// server.js
const { Server } = require('http');
const { WebSocketServer } = require('ws');
const { parse } = require('url');
const next = require('next');
const { CustomHttpServer, CustomWsServer } = require('next-ws/server');
const dev = process.env.NODE_ENV !== 'production';
const hostname = 'localhost';
const port = 3000;
const httpServer = new Server();
global[CustomHttpServer] = httpServer;
const wsServer = new WebSocketServer({ noServer: true });
global[CustomWsServer] = wsServer;
const app = next({ dev, hostname, port });
const handle = app.getRequestHandler();
app.prepare().then(() => {
httpServer
.on('request', async (req, res) => {
const parsedUrl = parse(req.url, true);
await handle(req, res, parsedUrl);
})
.listen(port, () => {
console.log(` ▲ Ready on http://${hostname}:${port}`);
});
});
Let me know if you try it and how it goes, I'll do more testing when I have more time.
Thanks so much man, it seems to be working for me as well, even when creating https and wss servers. Some things I noticed:
pnpx next-ws-cli@latest patch
, even for custom servertype: "module"
in package.json, change to module export in next.config.js, and change all the require statements in server.js to import statements, then importing from next-ws/server fails.Otherwise, the changes look good to me and I will use like this. Thanks again for doing this! So sad nextjs doesn't natively support websockets and makes it so difficult to include.
you still must run
pnpx next-ws-cli@latest
patch, even for custom server
Yeah, there's a few reasons for this but the main is the Next WS needs access to the NodeNextServer
. And there is no reliable (as in has everything Next WS needs) way that I know of to get that in the server.js
file. There are a lot of "solutions" to the problems I encounter but they just cause more problems to arise, which is why I ended up going with using global
.
the servers must be attached at the global level
The WebSocket server is setup when app.prepare
is called, so the custom HTTP server needs to be defined before that.
package doesn't seem to have any esm exports
I've been meaning to replace compiling with TSC to tsup, I'll use that to add ESM exports. For the time being I could replace the CustomHttpServer
symbol with a plain string so you don't have to grab it from the package in order to define.
Edit: I just remembered that Next.js has a ESM directory in their dist that Next WS doesn't patch (only patches the CommonJS versions). I not sure in which case these are used, I added type: "module"
(and use next.config.mjs
) to my test apps package.json
and it still works. I'll have to look into that.
I'll just published a new next-ws@experimental
version (1.0.1-experimental.2
), that replaces the custom symbols with strings so you no longer have to grab the symbols from the next-ws
package.
This is my new server.js
file:
import { Server } from 'node:http';
import { parse } from 'node:url';
import next from 'next';
import { WebSocketServer } from 'ws';
const dev = process.env.NODE_ENV !== 'production';
const hostname = 'localhost';
const port = 3000;
const httpServer = new Server();
global['NextWS::CustomHttpServer'] = httpServer;
const wsServer = new WebSocketServer({ noServer: true });
global['NextWS::CustomWsServer'] = wsServer;
const app = next({ dev, hostname, port });
const handle = app.getRequestHandler();
app.prepare().then(() => {
httpServer
.on('request', async (req, res) => {
const parsedUrl = parse(req.url, true);
await handle(req, res, parsedUrl);
})
.listen(port, () => {
console.log(` ▲ Ready on http://${hostname}:${port}`);
});
});
Thanks so much for doing this @apteryxxyz. I haven't been able to test this just yet, because I got caught up in a lot of work but I intend to test it ASAP
I'm finding I have a somewhat similar use-case. I'm building an app that needs an external source to be able to send messages to the WebSocket server, but I'm hitting a wall in getting that working. I tried the above solution, and was able to get it working locally, but since my project is built in standalone
mode (for Docker) it wasn't super clear how to use the custom server alongside the server.js
that gets generated by Next. Also didn't really love losing TypeScript support to have a custom server.
Hi,
Is there an easy way to access the server socket when using a custom server?
Thanks for this awesome plugin and in advance for answering my question!