Allow returning node:http server as an alternative to express
jansedlon opened this issue · 5 comments
As mentioned in #4, I'd need a way to return a different server other than express app. That's because libraries like socket.io
can be attached to an existing server, but i think it must be the server from node:http
.
This is an example from my app
const createRequestHandler =
MODE === "production"
? Sentry.wrapExpressCreateRequestHandler(createRequestHandler_)
: createRequestHandler_;
const viteDevServer =
MODE === "production"
? undefined
: await import("vite").then((vite) =>
vite.createServer({ server: { middlewareMode: true } }),
);
// Create express app
const app = express();
// Setup middlewares
// ...
// Setup vite dev server
if (viteDevServer) {
app.use(viteDevServer.middlewares);
} else {
// Remix fingerprints its assets so we can cache forever.
app.use(
"/assets",
express.static("build/client/assets", {
immutable: true,
maxAge: "1y",
}),
);
// Everything else (like favicon.ico) is cached for an hour. You may want to be
// more aggressive with this caching.
app.use(express.static("build/client", { maxAge: "1h" }));
}
// More middlewares
// ...
// Create request handler
async function getBuild() {
const build = viteDevServer
? viteDevServer.ssrLoadModule("virtual:remix/server-build")
: // @ts-ignore this should exist before running the server
// but it may not exist just yet.
await import("../build/server/index.js");
return build as unknown as ServerBuild;
}
app.all(
"*",
createRequestHandler({
mode: MODE,
getLoadContext: (_, res) => ({
cspNonce: res.locals.cspNonce,
serverBuild: getBuild(),
io,
}),
build: getBuild,
}),
);
// Create new http server and pass express into it
const httpServer = createServer(app);
// Create socket.io server
export const io = new SocketIOServer(httpServer);
io.on('connection', () => {});
// Here i have to call `listen` on the httpServer, not express, otherwise socket.io doesn't work
const server = httpServer.listen(3000, async () => {
// More code...
})
The most important part is the last section. The function listen
is called on the httpServer
, not the express app.
From my understanding, socket.io
attached request handlers/whatever to the node:http
server, not the express, therefore if only express is used, socket.io doesn't work at all
const server = httpServer.listen(3000, async () => {
// More code...
})
So to clarify, this socket server needs to attach to the existing server (either the Vite dev server or the production server).
BTW: both servers are based on node:net.Server
(which is the base of node:http.Server, etc)
Anyway, I'll see what changes I need to make in order to get socket.io working.
Yeah so it's basically like this
import { createServer } from "node:http";
import express from "express";
// Initialize express app
const app = express();
// Create httpServer from `node:http` based on express server
const httpServer = createServer(app);
// **Attach** Socket.io to the httpServer
const io = new SocketIOServer(httpServer);
// Listen on `node:http` server
httpServer.listen();
Fixed in v0.2.5. See README for example on how to setup socket.io
Thank you for the heads up. I have to imports a few files in order to actually use the socket.io server. Many of the files use other files, etc.. and i use the tsconfigPaths plugin in order to use path aliased (eg. ~/...
). I can import it like that in vite file. I have tried native nodejs import aliases (imports
fields in package.json
) but to no avail. Can I even imports files like that? I mean import app dir files in vite config?
I think I solved it by using this
"dev": "NODE_OPTIONS='--import tsx/esm' vite",
"build": "NODE_OPTIONS='--import tsx/esm' remix vite:build"