314 lines
13 KiB
JavaScript
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
|