Created
October 29, 2024 15:18
-
-
Save jamesdaniels/1c631886fb124b106c8ac48047b33f9b to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { createServer, IncomingMessage, ServerResponse } from "node:http"; | |
import { Socket } from "node:net"; | |
import NextServer from "next/dist/server/next-server.js"; | |
import next from "next"; | |
import RequiredServerFiles from "./.next/required-server-files.json" assert { type: "json" }; | |
process.setMaxListeners(1_000); | |
const hostname = process.env.HOSTNAME || "127.0.0.1"; | |
const port = parseInt(process.env.PORT, 10) || 3000; | |
const keepAliveTimeout = parseInt(process.env.KEEP_ALIVE_TIMEOUT, 10) || 10; | |
const nextConfig = RequiredServerFiles.config; | |
nextConfig.compress = false; // turn off compression for this demo | |
process.env.__NEXT_PRIVATE_STANDALONE_CONFIG = JSON.stringify(nextConfig); | |
process.env.__NEXT_PRIVATE_PREBUNDLED_REACT = 'experimental'; | |
const nextMinimalServer = new NextServer.default({ | |
conf: nextConfig, | |
customServer: false, | |
dev: false, | |
dir: process.cwd(), | |
hostname: "0.0.0.0", | |
port, | |
minimalMode: true, | |
keepAliveTimeout, | |
}); | |
const nextFullServer = next({ | |
conf: nextConfig, | |
dev: false, | |
dir: process.cwd(), | |
hostname: "0.0.0.0", | |
port, | |
keepAliveTimeout, | |
}); | |
async function write(stream, ...args) { | |
const ok = stream.write(...args); | |
if (!ok) { | |
await new Promise((resolve) => stream.once("drain", resolve)); | |
} | |
} | |
async function requestHandle(req, res) { | |
const { pathname } = new URL(`http://YOLO${req.url}`); | |
await nextMinimalServer.prepare(); | |
const minimalMatch = await nextMinimalServer.matchers.match(pathname, {}); | |
if (!minimalMatch) { | |
await nextFullServer.prepare(); | |
return nextFullServer.getRequestHandler()(req, res); | |
} | |
const prerenderedRoute = nextMinimalServer.getPrerenderManifest().routes[pathname]; | |
if (!prerenderedRoute) return nextMinimalServer.getRequestHandler()(req, res); | |
const kind = minimalMatch?.definition?.kind; | |
const isRoutePPREnabled = prerenderedRoute.experimentalPPR; | |
const incrementalCache = await nextMinimalServer.getIncrementalCache({ requestHeaders: req.headers, requestProtcol: req.protocol }); | |
const cacheEntry = await incrementalCache.get(pathname, { kind, isRoutePPREnabled }); | |
if (!cacheEntry) return nextMinimalServer.getRequestHandler()(req, res); | |
res.writeHead(res.status || 200, res.statusText, cacheEntry.value.headers); | |
await write(res, req.headers['rsc'] ? cacheEntry.value.rscData : cacheEntry.value.html || cacheEntry.value.body); | |
const postponed = !req.headers['next-router-prefetch'] && cacheEntry.value.postponed; | |
if (!postponed) return res.end(); | |
// Trigger the postponed response, this has to be to next minimal | |
// it's a POST to the magic /_next/postponed/resume path | |
const resumeReq = new IncomingMessage(new Socket()); | |
resumeReq.url = `/_next/postponed/resume${req.url}`; | |
resumeReq.method = "POST"; | |
resumeReq.protocol = "http"; | |
resumeReq.httpVersion = "1.1"; | |
resumeReq.httpVersionMajor = 1; | |
resumeReq.httpVersionMinor = 1; | |
Object.assign(resumeReq.headers, req.headers); | |
resumeReq.headers["x-matched-path"] = `/_next/postponed/resume${pathname}`; | |
resumeReq.push(postponed); | |
resumeReq.push(null); | |
const resumeRes = new ServerResponse(resumeReq); | |
// it's only the body we care about, don't get clever with pipes :P | |
res.on("drain", () => resumeRes.emit("drain")); | |
resumeRes.write = res.write.bind(res); | |
resumeRes.end = res.end.bind(res); | |
nextMinimalServer.getRequestHandler()(resumeReq, resumeRes); | |
}; | |
createServer({ keepAliveTimeout }, requestHandle).listen(port, hostname, () => { | |
console.log(`shield listening on http://${hostname}:${port}.`); | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment