Ctrl K
ComunidadGuías…

dev-server.mjs

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
/**
 * Custom Next.js dev server with WebSocket proxy.
 *
 * Problem: Next.js rewrites only handle HTTP, not WebSocket upgrade.
 * In dev mode the frontend runs on :3001 while the Go backend listens on
 * :8080.  Browsers that reach the frontend via SSH tunnel, LAN IP, or
 * localhost all need WebSocket to work transparently on the *same* origin
 * as the page — otherwise the connection fails or gets blocked by origin
 * checks.
 *
 * This server wraps `next dev` and intercepts `upgrade` requests for `/ws`
 * to proxy them to the Go backend.  No extra npm dependencies required.
 */

import { createServer, request as httpRequest } from "node:http"
import next from "next"

const port = parseInt(process.env.PORT || process.argv[2] || "3001", 10)
const goPort = parseInt(process.env.NEXT_PUBLIC_GO_PORT || "8080", 10)
const hostname = "0.0.0.0"

const app = next({ dev: true, hostname, port })

await app.prepare()

const handle = app.getRequestHandler()
const handleUpgrade = app.getUpgradeHandler()

const server = createServer((req, res) => handle(req, res))

server.on("upgrade", (req, socket, head) => {
  // Only proxy the /ws path; delegate everything else (e.g. HMR at
  // /_next/webpack-hmr) to Next.js so Turbopack hot-reload keeps working.
  if (!req.url?.startsWith("/ws")) {
    handleUpgrade(req, socket, head)
    return
  }

  const proxyReq = httpRequest({
    hostname: "localhost",
    port: goPort,
    path: req.url,
    method: req.method,
    headers: {
      ...req.headers,
      // Forward the real client host so the backend can log it.
      "x-forwarded-host": req.headers.host,
    },
  })

  proxyReq.on("upgrade", (proxyRes, proxySocket, proxyHead) => {
    // Relay the 101 Switching Protocols response.
    const statusLine = `HTTP/1.1 101 Switching Protocols\r\n`
    const headers = Object.entries(proxyRes.headers)
      .map(([k, v]) => `${k}: ${v}`)
      .join("\r\n")
    socket.write(statusLine + headers + "\r\n\r\n")
    if (proxyHead.length) socket.write(proxyHead)

    proxySocket.pipe(socket)
    socket.pipe(proxySocket)

    proxySocket.on("error", () => socket.destroy())
    socket.on("error", () => proxySocket.destroy())
  })

  // If the backend responds with a normal HTTP error (e.g. 401) instead of
  // upgrading, forward that error and close the socket.
  proxyReq.on("response", (proxyRes) => {
    const statusLine = `HTTP/1.1 ${proxyRes.statusCode} ${proxyRes.statusMessage}\r\n`
    const headers = Object.entries(proxyRes.headers)
      .map(([k, v]) => `${k}: ${v}`)
      .join("\r\n")
    socket.write(statusLine + headers + "\r\n\r\n")
    proxyRes.pipe(socket)
  })

  proxyReq.on("error", () => {
    socket.destroy()
  })

  if (head.length) proxyReq.write(head)
  proxyReq.end()
})

server.listen(port, hostname, () => {
  console.log(`> Dev server ready on http://${hostname}:${port}`)
  console.log(`> WebSocket /ws proxied to Go backend on :${goPort}`)
})