2024-02-24 00:37:31 +08:00

314 lines
13 KiB
JavaScript

"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "startServer", {
enumerable: true,
get: function() {
return startServer;
}
});
const _http = /*#__PURE__*/ _interop_require_default(require("http"));
const _net = require("net");
const _log = /*#__PURE__*/ _interop_require_wildcard(require("../../build/output/log"));
const _utils = require("../../shared/lib/utils");
const _env = require("@next/env");
const _utils1 = require("./utils");
function _interop_require_default(obj) {
return obj && obj.__esModule ? obj : {
default: obj
};
}
function _getRequireWildcardCache(nodeInterop) {
if (typeof WeakMap !== "function") return null;
var cacheBabelInterop = new WeakMap();
var cacheNodeInterop = new WeakMap();
return (_getRequireWildcardCache = function(nodeInterop) {
return nodeInterop ? cacheNodeInterop : cacheBabelInterop;
})(nodeInterop);
}
function _interop_require_wildcard(obj, nodeInterop) {
if (!nodeInterop && obj && obj.__esModule) {
return obj;
}
if (obj === null || typeof obj !== "object" && typeof obj !== "function") {
return {
default: obj
};
}
var cache = _getRequireWildcardCache(nodeInterop);
if (cache && cache.has(obj)) {
return cache.get(obj);
}
var newObj = {};
var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor;
for(var key in obj){
if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) {
var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null;
if (desc && (desc.get || desc.set)) {
Object.defineProperty(newObj, key, desc);
} else {
newObj[key] = obj[key];
}
}
}
newObj.default = obj;
if (cache) {
cache.set(obj, newObj);
}
return newObj;
}
async function startServer({ dir , prevDir , port , isDev , hostname , useWorkers , allowRetry , keepAliveTimeout , onStdout , onStderr }) {
var _process_env_NODE_OPTIONS, _process_env_NODE_OPTIONS1;
const sockets = new Set();
let worker;
let handlersReady = ()=>{};
let handlersError = ()=>{};
let isNodeDebugging = !!(process.execArgv.some((localArg)=>localArg.startsWith("--inspect")) || ((_process_env_NODE_OPTIONS = process.env.NODE_OPTIONS) == null ? void 0 : _process_env_NODE_OPTIONS.match == null ? void 0 : _process_env_NODE_OPTIONS.match(/--inspect(=\S+)?( |$)/)));
if (process.execArgv.some((localArg)=>localArg.startsWith("--inspect-brk")) || ((_process_env_NODE_OPTIONS1 = process.env.NODE_OPTIONS) == null ? void 0 : _process_env_NODE_OPTIONS1.match == null ? void 0 : _process_env_NODE_OPTIONS1.match(/--inspect-brk(=\S+)?( |$)/))) {
isNodeDebugging = "brk";
}
let handlersPromise = new Promise((resolve, reject)=>{
handlersReady = resolve;
handlersError = reject;
});
let requestHandler = async (_req, _res)=>{
if (handlersPromise) {
await handlersPromise;
return requestHandler(_req, _res);
}
throw new Error("Invariant request handler was not setup");
};
let upgradeHandler = async (_req, _socket, _head)=>{
if (handlersPromise) {
await handlersPromise;
return upgradeHandler(_req, _socket, _head);
}
throw new Error("Invariant upgrade handler was not setup");
};
// setup server listener as fast as possible
const server = _http.default.createServer(async (req, res)=>{
try {
if (handlersPromise) {
await handlersPromise;
handlersPromise = undefined;
}
sockets.add(res);
res.on("close", ()=>sockets.delete(res));
await requestHandler(req, res);
} catch (err) {
res.statusCode = 500;
res.end("Internal Server Error");
_log.error(`Failed to handle request for ${req.url}`);
console.error(err);
}
});
if (keepAliveTimeout) {
server.keepAliveTimeout = keepAliveTimeout;
}
server.on("upgrade", async (req, socket, head)=>{
try {
sockets.add(socket);
socket.on("close", ()=>sockets.delete(socket));
await upgradeHandler(req, socket, head);
} catch (err) {
socket.destroy();
_log.error(`Failed to handle request for ${req.url}`);
console.error(err);
}
});
let portRetryCount = 0;
server.on("error", (err)=>{
if (allowRetry && port && isDev && err.code === "EADDRINUSE" && portRetryCount < 10) {
_log.warn(`Port ${port} is in use, trying ${port + 1} instead.`);
port += 1;
portRetryCount += 1;
server.listen(port, hostname);
} else {
_log.error(`Failed to start server`);
console.error(err);
process.exit(1);
}
});
let targetHost = hostname;
await new Promise((resolve)=>{
server.on("listening", ()=>{
const addr = server.address();
port = typeof addr === "object" ? (addr == null ? void 0 : addr.port) || port : port;
let host = !hostname || hostname === "0.0.0.0" ? "localhost" : hostname;
let normalizedHostname = hostname || "0.0.0.0";
if ((0, _net.isIPv6)(hostname)) {
host = host === "::" ? "[::1]" : `[${host}]`;
normalizedHostname = `[${hostname}]`;
}
targetHost = host;
const appUrl = `http://${host}:${port}`;
if (isNodeDebugging) {
const debugPort = (0, _utils1.getDebugPort)();
_log.info(`the --inspect${isNodeDebugging === "brk" ? "-brk" : ""} option was detected, the Next.js proxy server should be inspected at port ${debugPort}.`);
}
_log.ready(`started server on ${normalizedHostname}${(port + "").startsWith(":") ? "" : ":"}${port}, url: ${appUrl}`);
resolve();
});
server.listen(port, hostname);
});
try {
if (useWorkers) {
var _routerWorker__workerPool;
const httpProxy = require("next/dist/compiled/http-proxy");
let renderServerPath = require.resolve("./render-server");
let jestWorkerPath = require.resolve("next/dist/compiled/jest-worker");
if (prevDir) {
jestWorkerPath = jestWorkerPath.replace(prevDir, dir);
renderServerPath = renderServerPath.replace(prevDir, dir);
}
const { Worker } = require(jestWorkerPath);
const routerWorker = new Worker(renderServerPath, {
numWorkers: 1,
// TODO: do we want to allow more than 10 OOM restarts?
maxRetries: 10,
forkOptions: {
execArgv: await (0, _utils1.genRouterWorkerExecArgv)(isNodeDebugging === undefined ? false : isNodeDebugging),
env: {
FORCE_COLOR: "1",
..._env.initialEnv || process.env,
PORT: port + "",
NODE_OPTIONS: (0, _utils1.getNodeOptionsWithoutInspect)(),
...process.env.NEXT_CPU_PROF ? {
__NEXT_PRIVATE_CPU_PROFILE: `CPU.router`
} : {},
WATCHPACK_WATCHER_LIMIT: "20"
}
},
exposedMethods: [
"initialize"
]
});
let didInitialize = false;
for (const _worker of ((_routerWorker__workerPool = routerWorker._workerPool) == null ? void 0 : _routerWorker__workerPool._workers) || []){
// eslint-disable-next-line no-loop-func
_worker._child.on("exit", (code, signal)=>{
// catch failed initializing without retry
if ((code || signal) && !didInitialize) {
routerWorker == null ? void 0 : routerWorker.end();
process.exit(1);
}
});
}
const workerStdout = routerWorker.getStdout();
const workerStderr = routerWorker.getStderr();
workerStdout.on("data", (data)=>{
if (typeof onStdout === "function") {
onStdout(data);
} else {
process.stdout.write(data);
}
});
workerStderr.on("data", (data)=>{
if (typeof onStderr === "function") {
onStderr(data);
} else {
process.stderr.write(data);
}
});
const { port: routerPort } = await routerWorker.initialize({
dir,
port,
hostname,
dev: !!isDev,
workerType: "router",
isNodeDebugging: !!isNodeDebugging,
keepAliveTimeout
});
didInitialize = true;
const getProxyServer = (pathname)=>{
const targetUrl = `http://${targetHost === "localhost" ? "127.0.0.1" : targetHost}:${routerPort}${pathname}`;
const proxyServer = httpProxy.createProxy({
target: targetUrl,
changeOrigin: false,
ignorePath: true,
xfwd: true,
ws: true,
followRedirects: false
});
proxyServer.on("error", (_err)=>{
// TODO?: enable verbose error logs with --debug flag?
});
return proxyServer;
};
// proxy to router worker
requestHandler = async (req, res)=>{
const urlParts = (req.url || "").split("?");
const urlNoQuery = urlParts[0];
// this normalizes repeated slashes in the path e.g. hello//world ->
// hello/world or backslashes to forward slashes, this does not
// handle trailing slash as that is handled the same as a next.config.js
// redirect
if (urlNoQuery == null ? void 0 : urlNoQuery.match(/(\\|\/\/)/)) {
const cleanUrl = (0, _utils.normalizeRepeatedSlashes)(req.url);
res.statusCode = 308;
res.setHeader("Location", cleanUrl);
res.end(cleanUrl);
return;
}
const proxyServer = getProxyServer(req.url || "/");
// http-proxy does not properly detect a client disconnect in newer
// versions of Node.js. This is caused because it only listens for the
// `aborted` event on the our request object, but it also fully reads
// and closes the request object. Node **will not** fire `aborted` when
// the request is already closed. Listening for `close` on our response
// object will detect the disconnect, and we can abort the proxy's
// connection.
proxyServer.on("proxyReq", (proxyReq)=>{
res.on("close", ()=>proxyReq.destroy());
});
proxyServer.on("proxyRes", (proxyRes)=>{
res.on("close", ()=>proxyRes.destroy());
});
proxyServer.web(req, res);
};
upgradeHandler = async (req, socket, head)=>{
const proxyServer = getProxyServer(req.url || "/");
proxyServer.ws(req, socket, head);
};
handlersReady();
} else {
// when not using a worker start next in main process
const next = require("../next");
const addr = server.address();
const app = next({
dir,
hostname,
dev: isDev,
isNodeDebugging,
httpServer: server,
customServer: false,
port: addr && typeof addr === "object" ? addr.port : port
});
// handle in process
requestHandler = app.getRequestHandler();
upgradeHandler = app.getUpgradeHandler();
await app.prepare();
handlersReady();
}
} catch (err) {
// fatal error if we can't setup
handlersError();
console.error(err);
process.exit(1);
}
// return teardown function for destroying the server
async function teardown() {
server.close();
sockets.forEach((socket)=>{
sockets.delete(socket);
socket.destroy();
});
if (worker) {
await worker.end();
}
}
return teardown;
}
//# sourceMappingURL=start-server.js.map