base-server.js 58 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", {
  3. value: true
  4. });
  5. exports.prepareServerlessUrl = prepareServerlessUrl;
  6. exports.default = void 0;
  7. var _utils = require("../shared/lib/utils");
  8. var _querystring = require("querystring");
  9. var _url = require("url");
  10. var _redirectStatus = require("../lib/redirect-status");
  11. var _constants = require("../shared/lib/constants");
  12. var _utils1 = require("../shared/lib/router/utils");
  13. var _apiUtils = require("./api-utils");
  14. var envConfig = _interopRequireWildcard(require("../shared/lib/runtime-config"));
  15. var _router = _interopRequireDefault(require("./router"));
  16. var _revalidateHeaders = require("./send-payload/revalidate-headers");
  17. var _utils2 = require("./utils");
  18. var _isBot = require("../shared/lib/router/utils/is-bot");
  19. var _renderResult = _interopRequireDefault(require("./render-result"));
  20. var _removeTrailingSlash = require("../shared/lib/router/utils/remove-trailing-slash");
  21. var _denormalizePagePath = require("../shared/lib/page-path/denormalize-page-path");
  22. var _normalizeLocalePath = require("../shared/lib/i18n/normalize-locale-path");
  23. var Log = _interopRequireWildcard(require("../build/output/log"));
  24. var _detectDomainLocale = require("../shared/lib/i18n/detect-domain-locale");
  25. var _escapePathDelimiters = _interopRequireDefault(require("../shared/lib/router/utils/escape-path-delimiters"));
  26. var _utils3 = require("../build/webpack/loaders/next-serverless-loader/utils");
  27. var _isError = _interopRequireWildcard(require("../lib/is-error"));
  28. var _requestMeta = require("./request-meta");
  29. var _removePathPrefix = require("../shared/lib/router/utils/remove-path-prefix");
  30. var _appPaths = require("../shared/lib/router/utils/app-paths");
  31. var _routeMatcher = require("../shared/lib/router/utils/route-matcher");
  32. var _routeRegex = require("../shared/lib/router/utils/route-regex");
  33. var _getLocaleRedirect = require("../shared/lib/i18n/get-locale-redirect");
  34. var _getHostname = require("../shared/lib/get-hostname");
  35. var _parseUrl = require("../shared/lib/router/utils/parse-url");
  36. var _getNextPathnameInfo = require("../shared/lib/router/utils/get-next-pathname-info");
  37. class Server {
  38. constructor(options){
  39. var ref, ref1;
  40. const { dir ="." , quiet =false , conf , dev =false , minimalMode =false , customServer =true , hostname , port , } = options;
  41. this.serverOptions = options;
  42. this.dir = process.env.NEXT_RUNTIME === "edge" ? dir : require("path").resolve(dir);
  43. this.quiet = quiet;
  44. this.loadEnvConfig({
  45. dev
  46. });
  47. // TODO: should conf be normalized to prevent missing
  48. // values from causing issues as this can be user provided
  49. this.nextConfig = conf;
  50. this.hostname = hostname;
  51. this.port = port;
  52. this.distDir = process.env.NEXT_RUNTIME === "edge" ? this.nextConfig.distDir : require("path").join(this.dir, this.nextConfig.distDir);
  53. this.publicDir = this.getPublicDir();
  54. this.hasStaticDir = !minimalMode && this.getHasStaticDir();
  55. // Only serverRuntimeConfig needs the default
  56. // publicRuntimeConfig gets it's default in client/index.js
  57. const { serverRuntimeConfig ={} , publicRuntimeConfig , assetPrefix , generateEtags , } = this.nextConfig;
  58. this.buildId = this.getBuildId();
  59. this.minimalMode = minimalMode || !!process.env.NEXT_PRIVATE_MINIMAL_MODE;
  60. const serverComponents = this.nextConfig.experimental.serverComponents;
  61. this.serverComponentManifest = serverComponents ? this.getServerComponentManifest() : undefined;
  62. this.serverCSSManifest = serverComponents ? this.getServerCSSManifest() : undefined;
  63. this.renderOpts = {
  64. poweredByHeader: this.nextConfig.poweredByHeader,
  65. canonicalBase: this.nextConfig.amp.canonicalBase || "",
  66. buildId: this.buildId,
  67. generateEtags,
  68. previewProps: this.getPreviewProps(),
  69. customServer: customServer === true ? true : undefined,
  70. ampOptimizerConfig: (ref = this.nextConfig.experimental.amp) == null ? void 0 : ref.optimizer,
  71. basePath: this.nextConfig.basePath,
  72. images: this.nextConfig.images,
  73. optimizeFonts: this.nextConfig.optimizeFonts,
  74. fontManifest: this.nextConfig.optimizeFonts && !dev ? this.getFontManifest() : undefined,
  75. optimizeCss: this.nextConfig.experimental.optimizeCss,
  76. nextScriptWorkers: this.nextConfig.experimental.nextScriptWorkers,
  77. disableOptimizedLoading: this.nextConfig.experimental.runtime ? true : this.nextConfig.experimental.disableOptimizedLoading,
  78. domainLocales: (ref1 = this.nextConfig.i18n) == null ? void 0 : ref1.domains,
  79. distDir: this.distDir,
  80. runtime: this.nextConfig.experimental.runtime,
  81. serverComponents,
  82. crossOrigin: this.nextConfig.crossOrigin ? this.nextConfig.crossOrigin : undefined,
  83. largePageDataBytes: this.nextConfig.experimental.largePageDataBytes
  84. };
  85. // Only the `publicRuntimeConfig` key is exposed to the client side
  86. // It'll be rendered as part of __NEXT_DATA__ on the client side
  87. if (Object.keys(publicRuntimeConfig).length > 0) {
  88. this.renderOpts.runtimeConfig = publicRuntimeConfig;
  89. }
  90. // Initialize next/config with the environment configuration
  91. envConfig.setConfig({
  92. serverRuntimeConfig,
  93. publicRuntimeConfig
  94. });
  95. this.pagesManifest = this.getPagesManifest();
  96. this.appPathsManifest = this.getAppPathsManifest();
  97. this.customRoutes = this.getCustomRoutes();
  98. this.router = new _router.default(this.generateRoutes());
  99. this.setAssetPrefix(assetPrefix);
  100. this.responseCache = this.getResponseCache({
  101. dev
  102. });
  103. }
  104. logError(err) {
  105. if (this.quiet) return;
  106. console.error(err);
  107. }
  108. async handleRequest(req, res, parsedUrl) {
  109. try {
  110. var ref, ref2;
  111. // ensure cookies set in middleware are merged and
  112. // not overridden by API routes/getServerSideProps
  113. const _res = res.originalResponse || res;
  114. const origSetHeader = _res.setHeader.bind(_res);
  115. _res.setHeader = (name, val)=>{
  116. if (name.toLowerCase() === "set-cookie") {
  117. const middlewareValue = (0, _requestMeta).getRequestMeta(req, "_nextMiddlewareCookie");
  118. if (!middlewareValue || !Array.isArray(val) || !val.every((item, idx)=>item === middlewareValue[idx])) {
  119. val = [
  120. ...middlewareValue || [],
  121. ...typeof val === "string" ? [
  122. val
  123. ] : Array.isArray(val) ? val : [],
  124. ];
  125. }
  126. }
  127. return origSetHeader(name, val);
  128. };
  129. const urlParts = (req.url || "").split("?");
  130. const urlNoQuery = urlParts[0];
  131. // this normalizes repeated slashes in the path e.g. hello//world ->
  132. // hello/world or backslashes to forward slashes, this does not
  133. // handle trailing slash as that is handled the same as a next.config.js
  134. // redirect
  135. if (urlNoQuery == null ? void 0 : urlNoQuery.match(/(\\|\/\/)/)) {
  136. const cleanUrl = (0, _utils).normalizeRepeatedSlashes(req.url);
  137. res.redirect(cleanUrl, 308).body(cleanUrl).send();
  138. return;
  139. }
  140. (0, _apiUtils).setLazyProp({
  141. req: req
  142. }, "cookies", (0, _apiUtils).getCookieParser(req.headers));
  143. // Parse url if parsedUrl not provided
  144. if (!parsedUrl || typeof parsedUrl !== "object") {
  145. parsedUrl = (0, _url).parse(req.url, true);
  146. }
  147. // Parse the querystring ourselves if the user doesn't handle querystring parsing
  148. if (typeof parsedUrl.query === "string") {
  149. parsedUrl.query = (0, _querystring).parse(parsedUrl.query);
  150. }
  151. this.attachRequestMeta(req, parsedUrl);
  152. const domainLocale = (0, _detectDomainLocale).detectDomainLocale((ref = this.nextConfig.i18n) == null ? void 0 : ref.domains, (0, _getHostname).getHostname(parsedUrl, req.headers));
  153. const defaultLocale = (domainLocale == null ? void 0 : domainLocale.defaultLocale) || ((ref2 = this.nextConfig.i18n) == null ? void 0 : ref2.defaultLocale);
  154. const url = (0, _parseUrl).parseUrl(req.url.replace(/^\/+/, "/"));
  155. const pathnameInfo = (0, _getNextPathnameInfo).getNextPathnameInfo(url.pathname, {
  156. nextConfig: this.nextConfig
  157. });
  158. url.pathname = pathnameInfo.pathname;
  159. if (pathnameInfo.basePath) {
  160. req.url = (0, _removePathPrefix).removePathPrefix(req.url, this.nextConfig.basePath);
  161. (0, _requestMeta).addRequestMeta(req, "_nextHadBasePath", true);
  162. }
  163. if (this.minimalMode && typeof req.headers["x-matched-path"] === "string") {
  164. try {
  165. // x-matched-path is the source of truth, it tells what page
  166. // should be rendered because we don't process rewrites in minimalMode
  167. let matchedPath = new URL(req.headers["x-matched-path"], "http://localhost").pathname;
  168. let urlPathname = new URL(req.url, "http://localhost").pathname;
  169. // For ISR the URL is normalized to the prerenderPath so if
  170. // it's a data request the URL path will be the data URL,
  171. // basePath is already stripped by this point
  172. if (urlPathname.startsWith(`/_next/data/`)) {
  173. parsedUrl.query.__nextDataReq = "1";
  174. }
  175. const normalizedUrlPath = this.stripNextDataPath(urlPathname);
  176. matchedPath = this.stripNextDataPath(matchedPath, false);
  177. if (this.nextConfig.i18n) {
  178. const localeResult = (0, _normalizeLocalePath).normalizeLocalePath(matchedPath, this.nextConfig.i18n.locales);
  179. matchedPath = localeResult.pathname;
  180. if (localeResult.detectedLocale) {
  181. parsedUrl.query.__nextLocale = localeResult.detectedLocale;
  182. }
  183. }
  184. matchedPath = (0, _denormalizePagePath).denormalizePagePath(matchedPath);
  185. let srcPathname = matchedPath;
  186. if (!(0, _utils1).isDynamicRoute(srcPathname) && !await this.hasPage((0, _removeTrailingSlash).removeTrailingSlash(srcPathname))) {
  187. for (const dynamicRoute of this.dynamicRoutes || []){
  188. if (dynamicRoute.match(srcPathname)) {
  189. srcPathname = dynamicRoute.page;
  190. break;
  191. }
  192. }
  193. }
  194. const pageIsDynamic = (0, _utils1).isDynamicRoute(srcPathname);
  195. const utils = (0, _utils3).getUtils({
  196. pageIsDynamic,
  197. page: srcPathname,
  198. i18n: this.nextConfig.i18n,
  199. basePath: this.nextConfig.basePath,
  200. rewrites: this.customRoutes.rewrites
  201. });
  202. // ensure parsedUrl.pathname includes URL before processing
  203. // rewrites or they won't match correctly
  204. if (defaultLocale && !pathnameInfo.locale) {
  205. parsedUrl.pathname = `/${defaultLocale}${parsedUrl.pathname}`;
  206. }
  207. const pathnameBeforeRewrite = parsedUrl.pathname;
  208. const rewriteParams = utils.handleRewrites(req, parsedUrl);
  209. const rewriteParamKeys = Object.keys(rewriteParams);
  210. const didRewrite = pathnameBeforeRewrite !== parsedUrl.pathname;
  211. if (didRewrite) {
  212. (0, _requestMeta).addRequestMeta(req, "_nextRewroteUrl", parsedUrl.pathname);
  213. (0, _requestMeta).addRequestMeta(req, "_nextDidRewrite", true);
  214. }
  215. // interpolate dynamic params and normalize URL if needed
  216. if (pageIsDynamic) {
  217. let params = {};
  218. let paramsResult = utils.normalizeDynamicRouteParams(parsedUrl.query);
  219. // for prerendered ISR paths we attempt parsing the route
  220. // params from the URL directly as route-matches may not
  221. // contain the correct values due to the filesystem path
  222. // matching before the dynamic route has been matched
  223. if (!paramsResult.hasValidParams && pageIsDynamic && !(0, _utils1).isDynamicRoute(normalizedUrlPath)) {
  224. let matcherParams = utils.dynamicRouteMatcher == null ? void 0 : utils.dynamicRouteMatcher(normalizedUrlPath);
  225. if (matcherParams) {
  226. utils.normalizeDynamicRouteParams(matcherParams);
  227. Object.assign(paramsResult.params, matcherParams);
  228. paramsResult.hasValidParams = true;
  229. }
  230. }
  231. if (paramsResult.hasValidParams) {
  232. params = paramsResult.params;
  233. }
  234. if (req.headers["x-now-route-matches"] && (0, _utils1).isDynamicRoute(matchedPath) && !paramsResult.hasValidParams) {
  235. const opts = {};
  236. const routeParams = utils.getParamsFromRouteMatches(req, opts, parsedUrl.query.__nextLocale || "");
  237. if (opts.locale) {
  238. parsedUrl.query.__nextLocale = opts.locale;
  239. }
  240. paramsResult = utils.normalizeDynamicRouteParams(routeParams, true);
  241. if (paramsResult.hasValidParams) {
  242. params = paramsResult.params;
  243. }
  244. }
  245. // handle the actual dynamic route name being requested
  246. if (pageIsDynamic && utils.defaultRouteMatches && normalizedUrlPath === srcPathname && !paramsResult.hasValidParams && !utils.normalizeDynamicRouteParams({
  247. ...params
  248. }, true).hasValidParams) {
  249. params = utils.defaultRouteMatches;
  250. }
  251. if (params) {
  252. matchedPath = utils.interpolateDynamicPath(srcPathname, params);
  253. req.url = utils.interpolateDynamicPath(req.url, params);
  254. }
  255. Object.assign(parsedUrl.query, params);
  256. }
  257. if (pageIsDynamic || didRewrite) {
  258. var ref3;
  259. utils.normalizeVercelUrl(req, true, [
  260. ...rewriteParamKeys,
  261. ...Object.keys(((ref3 = utils.defaultRouteRegex) == null ? void 0 : ref3.groups) || {}),
  262. ]);
  263. }
  264. parsedUrl.pathname = `${this.nextConfig.basePath || ""}${matchedPath === "/" && this.nextConfig.basePath ? "" : matchedPath}`;
  265. url.pathname = parsedUrl.pathname;
  266. } catch (err) {
  267. if (err instanceof _utils.DecodeError || err instanceof _utils.NormalizeError) {
  268. res.statusCode = 400;
  269. return this.renderError(null, req, res, "/_error", {});
  270. }
  271. throw err;
  272. }
  273. }
  274. (0, _requestMeta).addRequestMeta(req, "__nextHadTrailingSlash", pathnameInfo.trailingSlash);
  275. (0, _requestMeta).addRequestMeta(req, "__nextIsLocaleDomain", Boolean(domainLocale));
  276. parsedUrl.query.__nextDefaultLocale = defaultLocale;
  277. if (pathnameInfo.locale) {
  278. req.url = (0, _url).format(url);
  279. (0, _requestMeta).addRequestMeta(req, "__nextStrippedLocale", true);
  280. }
  281. if (!this.minimalMode || !parsedUrl.query.__nextLocale) {
  282. if (pathnameInfo.locale || defaultLocale) {
  283. parsedUrl.query.__nextLocale = pathnameInfo.locale || defaultLocale;
  284. }
  285. }
  286. if (!this.minimalMode && defaultLocale) {
  287. const redirect = (0, _getLocaleRedirect).getLocaleRedirect({
  288. defaultLocale,
  289. domainLocale,
  290. headers: req.headers,
  291. nextConfig: this.nextConfig,
  292. pathLocale: pathnameInfo.locale,
  293. urlParsed: {
  294. ...url,
  295. pathname: pathnameInfo.locale ? `/${pathnameInfo.locale}${url.pathname}` : url.pathname
  296. }
  297. });
  298. if (redirect) {
  299. return res.redirect(redirect, _constants.TEMPORARY_REDIRECT_STATUS).body(redirect).send();
  300. }
  301. }
  302. res.statusCode = 200;
  303. return await this.run(req, res, parsedUrl);
  304. } catch (err) {
  305. if (err && typeof err === "object" && err.code === "ERR_INVALID_URL" || err instanceof _utils.DecodeError || err instanceof _utils.NormalizeError) {
  306. res.statusCode = 400;
  307. return this.renderError(null, req, res, "/_error", {});
  308. }
  309. if (this.minimalMode || this.renderOpts.dev) {
  310. throw err;
  311. }
  312. this.logError((0, _isError).getProperError(err));
  313. res.statusCode = 500;
  314. res.body("Internal Server Error").send();
  315. }
  316. }
  317. getRequestHandler() {
  318. return this.handleRequest.bind(this);
  319. }
  320. async handleUpgrade(_req, _socket, _head) {}
  321. setAssetPrefix(prefix) {
  322. this.renderOpts.assetPrefix = prefix ? prefix.replace(/\/$/, "") : "";
  323. }
  324. // Backwards compatibility
  325. async prepare() {}
  326. // Backwards compatibility
  327. async close() {}
  328. getPreviewProps() {
  329. return this.getPrerenderManifest().preview;
  330. }
  331. async _beforeCatchAllRender(_req, _res, _params, _parsedUrl) {
  332. return false;
  333. }
  334. getDynamicRoutes() {
  335. const addedPages = new Set();
  336. return (0, _utils1).getSortedRoutes([
  337. ...Object.keys(this.appPathRoutes || {}),
  338. ...Object.keys(this.pagesManifest),
  339. ].map((page)=>{
  340. var ref;
  341. return (0, _normalizeLocalePath).normalizeLocalePath(page, (ref = this.nextConfig.i18n) == null ? void 0 : ref.locales).pathname;
  342. })).map((page)=>{
  343. if (addedPages.has(page) || !(0, _utils1).isDynamicRoute(page)) return null;
  344. addedPages.add(page);
  345. return {
  346. page,
  347. match: (0, _routeMatcher).getRouteMatcher((0, _routeRegex).getRouteRegex(page))
  348. };
  349. }).filter((item)=>Boolean(item));
  350. }
  351. getAppPathRoutes() {
  352. const appPathRoutes = {};
  353. Object.keys(this.appPathsManifest || {}).forEach((entry)=>{
  354. const normalizedPath = (0, _appPaths).normalizeAppPath(entry) || "/";
  355. if (!appPathRoutes[normalizedPath]) {
  356. appPathRoutes[normalizedPath] = [];
  357. }
  358. appPathRoutes[normalizedPath].push(entry);
  359. });
  360. return appPathRoutes;
  361. }
  362. async run(req, res, parsedUrl) {
  363. this.handleCompression(req, res);
  364. try {
  365. const matched = await this.router.execute(req, res, parsedUrl);
  366. if (matched) {
  367. return;
  368. }
  369. } catch (err) {
  370. if (err instanceof _utils.DecodeError || err instanceof _utils.NormalizeError) {
  371. res.statusCode = 400;
  372. return this.renderError(null, req, res, "/_error", {});
  373. }
  374. throw err;
  375. }
  376. await this.render404(req, res, parsedUrl);
  377. }
  378. async pipe(fn, partialContext) {
  379. const isBotRequest = (0, _isBot).isBot(partialContext.req.headers["user-agent"] || "");
  380. const ctx = {
  381. ...partialContext,
  382. renderOpts: {
  383. ...this.renderOpts,
  384. supportsDynamicHTML: !isBotRequest
  385. }
  386. };
  387. const payload = await fn(ctx);
  388. if (payload === null) {
  389. return;
  390. }
  391. const { req , res } = ctx;
  392. const { body , type , revalidateOptions } = payload;
  393. if (!res.sent) {
  394. const { generateEtags , poweredByHeader , dev } = this.renderOpts;
  395. if (dev) {
  396. // In dev, we should not cache pages for any reason.
  397. res.setHeader("Cache-Control", "no-store, must-revalidate");
  398. }
  399. return this.sendRenderResult(req, res, {
  400. result: body,
  401. type,
  402. generateEtags,
  403. poweredByHeader,
  404. options: revalidateOptions
  405. });
  406. }
  407. }
  408. async getStaticHTML(fn, partialContext) {
  409. const payload = await fn({
  410. ...partialContext,
  411. renderOpts: {
  412. ...this.renderOpts,
  413. supportsDynamicHTML: false
  414. }
  415. });
  416. if (payload === null) {
  417. return null;
  418. }
  419. return payload.body.toUnchunkedString();
  420. }
  421. async render(req, res, pathname, query = {}, parsedUrl, internalRender = false) {
  422. var ref;
  423. if (!pathname.startsWith("/")) {
  424. console.warn(`Cannot render page with path "${pathname}", did you mean "/${pathname}"?. See more info here: https://nextjs.org/docs/messages/render-no-starting-slash`);
  425. }
  426. if (this.renderOpts.customServer && pathname === "/index" && !await this.hasPage("/index")) {
  427. // maintain backwards compatibility for custom server
  428. // (see custom-server integration tests)
  429. pathname = "/";
  430. }
  431. // we allow custom servers to call render for all URLs
  432. // so check if we need to serve a static _next file or not.
  433. // we don't modify the URL for _next/data request but still
  434. // call render so we special case this to prevent an infinite loop
  435. if (!internalRender && !this.minimalMode && !query.__nextDataReq && (((ref = req.url) == null ? void 0 : ref.match(/^\/_next\//)) || this.hasStaticDir && req.url.match(/^\/static\//))) {
  436. return this.handleRequest(req, res, parsedUrl);
  437. }
  438. // Custom server users can run `app.render()` which needs compression.
  439. if (this.renderOpts.customServer) {
  440. this.handleCompression(req, res);
  441. }
  442. if ((0, _utils2).isBlockedPage(pathname)) {
  443. return this.render404(req, res, parsedUrl);
  444. }
  445. return this.pipe((ctx)=>this.renderToResponse(ctx), {
  446. req,
  447. res,
  448. pathname,
  449. query
  450. });
  451. }
  452. async getStaticPaths({ pathname }) {
  453. var ref;
  454. // `staticPaths` is intentionally set to `undefined` as it should've
  455. // been caught when checking disk data.
  456. const staticPaths = undefined;
  457. // Read whether or not fallback should exist from the manifest.
  458. const fallbackField = (ref = this.getPrerenderManifest().dynamicRoutes[pathname]) == null ? void 0 : ref.fallback;
  459. return {
  460. staticPaths,
  461. fallbackMode: typeof fallbackField === "string" ? "static" : fallbackField === null ? "blocking" : fallbackField
  462. };
  463. }
  464. async renderToResponseWithComponents({ req , res , pathname , renderOpts: opts }, { components , query }) {
  465. var ref, ref4, ref5, ref6, ref7;
  466. const is404Page = pathname === "/404";
  467. const is500Page = pathname === "/500";
  468. const isAppPath = components.isAppPath;
  469. const isLikeServerless = typeof components.ComponentMod === "object" && typeof components.ComponentMod.renderReqToHTML === "function";
  470. const hasServerProps = !!components.getServerSideProps;
  471. let hasStaticPaths = !!components.getStaticPaths;
  472. const hasGetInitialProps = !!((ref = components.Component) == null ? void 0 : ref.getInitialProps);
  473. const isServerComponent = !!((ref4 = components.ComponentMod) == null ? void 0 : ref4.__next_rsc__);
  474. let isSSG = !!components.getStaticProps || // For static server component pages, we currently always consider them
  475. // as SSG since we also need to handle the next data (flight JSON).
  476. (isServerComponent && !hasServerProps && !hasGetInitialProps && process.env.NEXT_RUNTIME !== "edge");
  477. // Toggle whether or not this is a Data request
  478. const isDataReq = !!(query.__nextDataReq || req.headers["x-nextjs-data"] && this.serverOptions.webServerConfig) && (isSSG || hasServerProps || isServerComponent);
  479. delete query.__nextDataReq;
  480. // Compute the iSSG cache key. We use the rewroteUrl since
  481. // pages with fallback: false are allowed to be rewritten to
  482. // and we need to look up the path by the rewritten path
  483. let urlPathname = (0, _url).parse(req.url || "").pathname || "/";
  484. let resolvedUrlPathname = (0, _requestMeta).getRequestMeta(req, "_nextRewroteUrl") || urlPathname;
  485. let staticPaths;
  486. let fallbackMode;
  487. if (isAppPath) {
  488. const pathsResult = await this.getStaticPaths({
  489. pathname,
  490. originalAppPath: components.pathname
  491. });
  492. staticPaths = pathsResult.staticPaths;
  493. fallbackMode = pathsResult.fallbackMode;
  494. const hasFallback = typeof fallbackMode !== "undefined";
  495. if (hasFallback) {
  496. hasStaticPaths = true;
  497. }
  498. if (hasFallback || (staticPaths == null ? void 0 : staticPaths.includes(resolvedUrlPathname))) {
  499. isSSG = true;
  500. }
  501. }
  502. // normalize req.url for SSG paths as it is not exposed
  503. // to getStaticProps and the asPath should not expose /_next/data
  504. if (isSSG && this.minimalMode && req.headers["x-matched-path"] && req.url.startsWith("/_next/data")) {
  505. req.url = this.stripNextDataPath(req.url);
  506. }
  507. if (!isServerComponent && !!req.headers["x-nextjs-data"] && (!res.statusCode || res.statusCode === 200)) {
  508. res.setHeader("x-nextjs-matched-path", `${query.__nextLocale ? `/${query.__nextLocale}` : ""}${pathname}`);
  509. }
  510. // Don't delete query.__flight__ yet, it still needs to be used in renderToHTML later
  511. const isFlightRequest = Boolean(this.serverComponentManifest && query.__flight__);
  512. // we need to ensure the status code if /404 is visited directly
  513. if (is404Page && !isDataReq && !isFlightRequest) {
  514. res.statusCode = 404;
  515. }
  516. // ensure correct status is set when visiting a status page
  517. // directly e.g. /500
  518. if (_constants.STATIC_STATUS_PAGES.includes(pathname)) {
  519. res.statusCode = parseInt(pathname.slice(1), 10);
  520. }
  521. // static pages can only respond to GET/HEAD
  522. // requests so ensure we respond with 405 for
  523. // invalid requests
  524. if (!is404Page && !is500Page && pathname !== "/_error" && req.method !== "HEAD" && req.method !== "GET" && (typeof components.Component === "string" || isSSG)) {
  525. res.statusCode = 405;
  526. res.setHeader("Allow", [
  527. "GET",
  528. "HEAD"
  529. ]);
  530. await this.renderError(null, req, res, pathname);
  531. return null;
  532. }
  533. // handle static page
  534. if (typeof components.Component === "string") {
  535. return {
  536. type: "html",
  537. // TODO: Static pages should be serialized as RenderResult
  538. body: _renderResult.default.fromStatic(components.Component)
  539. };
  540. }
  541. if (!query.amp) {
  542. delete query.amp;
  543. }
  544. if (opts.supportsDynamicHTML === true) {
  545. var ref8;
  546. const isBotRequest = (0, _isBot).isBot(req.headers["user-agent"] || "");
  547. const isSupportedDocument = typeof ((ref8 = components.Document) == null ? void 0 : ref8.getInitialProps) !== "function" || // When concurrent features is enabled, the built-in `Document`
  548. // component also supports dynamic HTML.
  549. (!!process.env.__NEXT_REACT_ROOT && _constants.NEXT_BUILTIN_DOCUMENT in components.Document);
  550. // Disable dynamic HTML in cases that we know it won't be generated,
  551. // so that we can continue generating a cache key when possible.
  552. // TODO-APP: should the first render for a dynamic app path
  553. // be static so we can collect revalidate and populate the
  554. // cache if there are no dynamic data requirements
  555. opts.supportsDynamicHTML = !isSSG && !isLikeServerless && !isBotRequest && !query.amp && isSupportedDocument;
  556. }
  557. const defaultLocale = isSSG ? (ref5 = this.nextConfig.i18n) == null ? void 0 : ref5.defaultLocale : query.__nextDefaultLocale;
  558. const locale = query.__nextLocale;
  559. const locales = (ref6 = this.nextConfig.i18n) == null ? void 0 : ref6.locales;
  560. let previewData;
  561. let isPreviewMode = false;
  562. if (hasServerProps || isSSG) {
  563. // For the edge runtime, we don't support preview mode in SSG.
  564. if (process.env.NEXT_RUNTIME !== "edge") {
  565. const { tryGetPreviewData } = require("./api-utils/node");
  566. previewData = tryGetPreviewData(req, res, this.renderOpts.previewProps);
  567. isPreviewMode = previewData !== false;
  568. }
  569. }
  570. let isManualRevalidate = false;
  571. let revalidateOnlyGenerated = false;
  572. if (isSSG) {
  573. ({ isManualRevalidate , revalidateOnlyGenerated } = (0, _apiUtils).checkIsManualRevalidate(req, this.renderOpts.previewProps));
  574. }
  575. if (isSSG && this.minimalMode && req.headers["x-matched-path"]) {
  576. // the url value is already correct when the matched-path header is set
  577. resolvedUrlPathname = urlPathname;
  578. }
  579. urlPathname = (0, _removeTrailingSlash).removeTrailingSlash(urlPathname);
  580. resolvedUrlPathname = (0, _normalizeLocalePath).normalizeLocalePath((0, _removeTrailingSlash).removeTrailingSlash(resolvedUrlPathname), (ref7 = this.nextConfig.i18n) == null ? void 0 : ref7.locales).pathname;
  581. const handleRedirect = (pageData)=>{
  582. const redirect = {
  583. destination: pageData.pageProps.__N_REDIRECT,
  584. statusCode: pageData.pageProps.__N_REDIRECT_STATUS,
  585. basePath: pageData.pageProps.__N_REDIRECT_BASE_PATH
  586. };
  587. const statusCode = (0, _redirectStatus).getRedirectStatus(redirect);
  588. const { basePath } = this.nextConfig;
  589. if (basePath && redirect.basePath !== false && redirect.destination.startsWith("/")) {
  590. redirect.destination = `${basePath}${redirect.destination}`;
  591. }
  592. if (redirect.destination.startsWith("/")) {
  593. redirect.destination = (0, _utils).normalizeRepeatedSlashes(redirect.destination);
  594. }
  595. res.redirect(redirect.destination, statusCode).body(redirect.destination).send();
  596. };
  597. // remove /_next/data prefix from urlPathname so it matches
  598. // for direct page visit and /_next/data visit
  599. if (isDataReq) {
  600. resolvedUrlPathname = this.stripNextDataPath(resolvedUrlPathname);
  601. urlPathname = this.stripNextDataPath(urlPathname);
  602. }
  603. let ssgCacheKey = isPreviewMode || !isSSG || opts.supportsDynamicHTML || isFlightRequest ? null // Preview mode, manual revalidate, flight request can bypass the cache
  604. : `${locale ? `/${locale}` : ""}${(pathname === "/" || resolvedUrlPathname === "/") && locale ? "" : resolvedUrlPathname}${query.amp ? ".amp" : ""}`;
  605. if ((is404Page || is500Page) && isSSG) {
  606. ssgCacheKey = `${locale ? `/${locale}` : ""}${pathname}${query.amp ? ".amp" : ""}`;
  607. }
  608. if (ssgCacheKey) {
  609. // we only encode path delimiters for path segments from
  610. // getStaticPaths so we need to attempt decoding the URL
  611. // to match against and only escape the path delimiters
  612. // this allows non-ascii values to be handled e.g. Japanese characters
  613. // TODO: investigate adding this handling for non-SSG pages so
  614. // non-ascii names work there also
  615. ssgCacheKey = ssgCacheKey.split("/").map((seg)=>{
  616. try {
  617. seg = (0, _escapePathDelimiters).default(decodeURIComponent(seg), true);
  618. } catch (_) {
  619. // An improperly encoded URL was provided
  620. throw new _utils.DecodeError("failed to decode param");
  621. }
  622. return seg;
  623. }).join("/");
  624. // ensure /index and / is normalized to one key
  625. ssgCacheKey = ssgCacheKey === "/index" && pathname === "/" ? "/" : ssgCacheKey;
  626. }
  627. const doRender = async ()=>{
  628. let pageData;
  629. let body;
  630. let sprRevalidate;
  631. let isNotFound;
  632. let isRedirect;
  633. // handle serverless
  634. if (isLikeServerless) {
  635. const renderResult = await components.ComponentMod.renderReqToHTML(req, res, "passthrough", {
  636. locale,
  637. locales,
  638. defaultLocale,
  639. optimizeFonts: this.renderOpts.optimizeFonts,
  640. optimizeCss: this.renderOpts.optimizeCss,
  641. nextScriptWorkers: this.renderOpts.nextScriptWorkers,
  642. distDir: this.distDir,
  643. fontManifest: this.renderOpts.fontManifest,
  644. domainLocales: this.renderOpts.domainLocales
  645. });
  646. body = renderResult.html;
  647. pageData = renderResult.renderOpts.pageData;
  648. sprRevalidate = renderResult.renderOpts.revalidate;
  649. isNotFound = renderResult.renderOpts.isNotFound;
  650. isRedirect = renderResult.renderOpts.isRedirect;
  651. } else {
  652. const origQuery = (0, _url).parse(req.url || "", true).query;
  653. // clear any dynamic route params so they aren't in
  654. // the resolvedUrl
  655. if (opts.params) {
  656. Object.keys(opts.params).forEach((key)=>{
  657. delete origQuery[key];
  658. });
  659. }
  660. const hadTrailingSlash = urlPathname !== "/" && this.nextConfig.trailingSlash;
  661. const resolvedUrl = (0, _url).format({
  662. pathname: `${resolvedUrlPathname}${hadTrailingSlash ? "/" : ""}`,
  663. // make sure to only add query values from original URL
  664. query: origQuery
  665. });
  666. const renderOpts = {
  667. ...components,
  668. ...opts,
  669. isDataReq,
  670. resolvedUrl,
  671. locale,
  672. locales,
  673. defaultLocale,
  674. // For getServerSideProps and getInitialProps we need to ensure we use the original URL
  675. // and not the resolved URL to prevent a hydration mismatch on
  676. // asPath
  677. resolvedAsPath: hasServerProps || hasGetInitialProps ? (0, _url).format({
  678. // we use the original URL pathname less the _next/data prefix if
  679. // present
  680. pathname: `${urlPathname}${hadTrailingSlash ? "/" : ""}`,
  681. query: origQuery
  682. }) : resolvedUrl
  683. };
  684. if (isSSG || hasStaticPaths) {
  685. renderOpts.supportsDynamicHTML = false;
  686. }
  687. const renderResult = await this.renderHTML(req, res, pathname, query, renderOpts);
  688. body = renderResult;
  689. // TODO: change this to a different passing mechanism
  690. pageData = renderOpts.pageData;
  691. sprRevalidate = renderOpts.revalidate;
  692. isNotFound = renderOpts.isNotFound;
  693. isRedirect = renderOpts.isRedirect;
  694. }
  695. let value;
  696. if (isNotFound) {
  697. value = null;
  698. } else if (isRedirect) {
  699. value = {
  700. kind: "REDIRECT",
  701. props: pageData
  702. };
  703. } else {
  704. if (!body) {
  705. return null;
  706. }
  707. value = {
  708. kind: "PAGE",
  709. html: body,
  710. pageData
  711. };
  712. }
  713. return {
  714. revalidate: sprRevalidate,
  715. value
  716. };
  717. };
  718. const cacheEntry = await this.responseCache.get(ssgCacheKey, async (hasResolved, hadCache)=>{
  719. const isProduction = !this.renderOpts.dev;
  720. const isDynamicPathname = (0, _utils1).isDynamicRoute(pathname);
  721. const didRespond = hasResolved || res.sent;
  722. if (!staticPaths) {
  723. ({ staticPaths , fallbackMode } = hasStaticPaths ? await this.getStaticPaths({
  724. pathname
  725. }) : {
  726. staticPaths: undefined,
  727. fallbackMode: false
  728. });
  729. }
  730. if (fallbackMode === "static" && (0, _isBot).isBot(req.headers["user-agent"] || "")) {
  731. fallbackMode = "blocking";
  732. }
  733. // skip manual revalidate if cache is not present and
  734. // revalidate-if-generated is set
  735. if (isManualRevalidate && revalidateOnlyGenerated && !hadCache && !this.minimalMode) {
  736. await this.render404(req, res);
  737. return null;
  738. }
  739. // only allow manual revalidate for fallback: true/blocking
  740. // or for prerendered fallback: false paths
  741. if (isManualRevalidate && (fallbackMode !== false || hadCache)) {
  742. fallbackMode = "blocking";
  743. }
  744. // When we did not respond from cache, we need to choose to block on
  745. // rendering or return a skeleton.
  746. //
  747. // * Data requests always block.
  748. //
  749. // * Blocking mode fallback always blocks.
  750. //
  751. // * Preview mode toggles all pages to be resolved in a blocking manner.
  752. //
  753. // * Non-dynamic pages should block (though this is an impossible
  754. // case in production).
  755. //
  756. // * Dynamic pages should return their skeleton if not defined in
  757. // getStaticPaths, then finish the data request on the client-side.
  758. //
  759. if (this.minimalMode !== true && fallbackMode !== "blocking" && ssgCacheKey && !didRespond && !isPreviewMode && isDynamicPathname && // Development should trigger fallback when the path is not in
  760. // `getStaticPaths`
  761. (isProduction || !staticPaths || !staticPaths.includes(// we use ssgCacheKey here as it is normalized to match the
  762. // encoding from getStaticPaths along with including the locale
  763. query.amp ? ssgCacheKey.replace(/\.amp$/, "") : ssgCacheKey))) {
  764. if (// In development, fall through to render to handle missing
  765. // getStaticPaths.
  766. (isProduction || staticPaths) && // When fallback isn't present, abort this render so we 404
  767. fallbackMode !== "static") {
  768. throw new NoFallbackError();
  769. }
  770. if (!isDataReq) {
  771. // Production already emitted the fallback as static HTML.
  772. if (isProduction) {
  773. const html = await this.getFallback(locale ? `/${locale}${pathname}` : pathname);
  774. return {
  775. value: {
  776. kind: "PAGE",
  777. html: _renderResult.default.fromStatic(html),
  778. pageData: {}
  779. }
  780. };
  781. } else {
  782. query.__nextFallback = "true";
  783. if (isLikeServerless) {
  784. prepareServerlessUrl(req, query);
  785. }
  786. const result = await doRender();
  787. if (!result) {
  788. return null;
  789. }
  790. // Prevent caching this result
  791. delete result.revalidate;
  792. return result;
  793. }
  794. }
  795. }
  796. const result = await doRender();
  797. if (!result) {
  798. return null;
  799. }
  800. return {
  801. ...result,
  802. revalidate: result.revalidate !== undefined ? result.revalidate : /* default to minimum revalidate (this should be an invariant) */ 1
  803. };
  804. }, {
  805. isManualRevalidate,
  806. isPrefetch: req.headers.purpose === "prefetch"
  807. });
  808. if (!cacheEntry) {
  809. if (ssgCacheKey && !(isManualRevalidate && revalidateOnlyGenerated)) {
  810. // A cache entry might not be generated if a response is written
  811. // in `getInitialProps` or `getServerSideProps`, but those shouldn't
  812. // have a cache key. If we do have a cache key but we don't end up
  813. // with a cache entry, then either Next.js or the application has a
  814. // bug that needs fixing.
  815. throw new Error("invariant: cache entry required but not generated");
  816. }
  817. return null;
  818. }
  819. if (isSSG && !this.minimalMode) {
  820. // set x-nextjs-cache header to match the header
  821. // we set for the image-optimizer
  822. res.setHeader("x-nextjs-cache", isManualRevalidate ? "REVALIDATED" : cacheEntry.isMiss ? "MISS" : cacheEntry.isStale ? "STALE" : "HIT");
  823. }
  824. const { revalidate , value: cachedData } = cacheEntry;
  825. const revalidateOptions = typeof revalidate !== "undefined" && (!this.renderOpts.dev || hasServerProps && !isDataReq) ? {
  826. // When the page is 404 cache-control should not be added unless
  827. // we are rendering the 404 page for notFound: true which should
  828. // cache according to revalidate correctly
  829. private: isPreviewMode || is404Page && cachedData,
  830. stateful: !isSSG,
  831. revalidate
  832. } : undefined;
  833. if (!cachedData) {
  834. if (revalidateOptions) {
  835. (0, _revalidateHeaders).setRevalidateHeaders(res, revalidateOptions);
  836. }
  837. if (isDataReq) {
  838. res.statusCode = 404;
  839. res.body('{"notFound":true}').send();
  840. return null;
  841. } else {
  842. if (this.renderOpts.dev) {
  843. query.__nextNotFoundSrcPage = pathname;
  844. }
  845. await this.render404(req, res, {
  846. pathname,
  847. query
  848. }, false);
  849. return null;
  850. }
  851. } else if (cachedData.kind === "REDIRECT") {
  852. if (revalidateOptions) {
  853. (0, _revalidateHeaders).setRevalidateHeaders(res, revalidateOptions);
  854. }
  855. if (isDataReq) {
  856. return {
  857. type: "json",
  858. body: _renderResult.default.fromStatic(// @TODO: Handle flight data.
  859. JSON.stringify(cachedData.props)),
  860. revalidateOptions
  861. };
  862. } else {
  863. await handleRedirect(cachedData.props);
  864. return null;
  865. }
  866. } else if (cachedData.kind === "IMAGE") {
  867. throw new Error("invariant SSG should not return an image cache value");
  868. } else {
  869. return {
  870. type: isDataReq ? "json" : "html",
  871. body: isDataReq ? _renderResult.default.fromStatic(JSON.stringify(cachedData.pageData)) : cachedData.html,
  872. revalidateOptions
  873. };
  874. }
  875. }
  876. stripNextDataPath(path, stripLocale = true) {
  877. if (path.includes(this.buildId)) {
  878. const splitPath = path.substring(path.indexOf(this.buildId) + this.buildId.length);
  879. path = (0, _denormalizePagePath).denormalizePagePath(splitPath.replace(/\.json$/, ""));
  880. }
  881. if (this.nextConfig.i18n && stripLocale) {
  882. const { locales } = this.nextConfig.i18n;
  883. return (0, _normalizeLocalePath).normalizeLocalePath(path, locales).pathname;
  884. }
  885. return path;
  886. }
  887. // map the route to the actual bundle name
  888. getOriginalAppPaths(route) {
  889. if (this.nextConfig.experimental.appDir) {
  890. var ref;
  891. const originalAppPath = (ref = this.appPathRoutes) == null ? void 0 : ref[route];
  892. if (!originalAppPath) {
  893. return null;
  894. }
  895. return originalAppPath;
  896. }
  897. return null;
  898. }
  899. async renderPageComponent(ctx, bubbleNoFallback) {
  900. var ref;
  901. const { query , pathname } = ctx;
  902. const appPaths = this.getOriginalAppPaths(pathname);
  903. const isAppPath = Array.isArray(appPaths);
  904. let page = pathname;
  905. if (isAppPath) {
  906. // When it's an array, we need to pass all parallel routes to the loader.
  907. page = appPaths[0];
  908. }
  909. const result = await this.findPageComponents({
  910. pathname: page,
  911. query,
  912. params: ctx.renderOpts.params || {},
  913. isAppPath,
  914. appPaths,
  915. sriEnabled: !!((ref = this.nextConfig.experimental.sri) == null ? void 0 : ref.algorithm)
  916. });
  917. if (result) {
  918. try {
  919. return await this.renderToResponseWithComponents(ctx, result);
  920. } catch (err) {
  921. const isNoFallbackError = err instanceof NoFallbackError;
  922. if (!isNoFallbackError || isNoFallbackError && bubbleNoFallback) {
  923. throw err;
  924. }
  925. }
  926. }
  927. return false;
  928. }
  929. async renderToResponse(ctx) {
  930. const { res , query , pathname } = ctx;
  931. let page = pathname;
  932. const bubbleNoFallback = !!query._nextBubbleNoFallback;
  933. delete query._nextBubbleNoFallback;
  934. try {
  935. // Ensure a request to the URL /accounts/[id] will be treated as a dynamic
  936. // route correctly and not loaded immediately without parsing params.
  937. if (!(0, _utils1).isDynamicRoute(page)) {
  938. const result = await this.renderPageComponent(ctx, bubbleNoFallback);
  939. if (result !== false) return result;
  940. }
  941. if (this.dynamicRoutes) {
  942. for (const dynamicRoute of this.dynamicRoutes){
  943. const params = dynamicRoute.match(pathname);
  944. if (!params) {
  945. continue;
  946. }
  947. page = dynamicRoute.page;
  948. const result = await this.renderPageComponent({
  949. ...ctx,
  950. pathname: page,
  951. renderOpts: {
  952. ...ctx.renderOpts,
  953. params
  954. }
  955. }, bubbleNoFallback);
  956. if (result !== false) return result;
  957. }
  958. }
  959. // currently edge functions aren't receiving the x-matched-path
  960. // header so we need to fallback to matching the current page
  961. // when we weren't able to match via dynamic route to handle
  962. // the rewrite case
  963. // @ts-expect-error extended in child class web-server
  964. if (this.serverOptions.webServerConfig) {
  965. // @ts-expect-error extended in child class web-server
  966. ctx.pathname = this.serverOptions.webServerConfig.page;
  967. const result = await this.renderPageComponent(ctx, bubbleNoFallback);
  968. if (result !== false) return result;
  969. }
  970. } catch (error) {
  971. const err = (0, _isError).getProperError(error);
  972. if (error instanceof _utils.MissingStaticPage) {
  973. console.error("Invariant: failed to load static page", JSON.stringify({
  974. page,
  975. url: ctx.req.url,
  976. matchedPath: ctx.req.headers["x-matched-path"],
  977. initUrl: (0, _requestMeta).getRequestMeta(ctx.req, "__NEXT_INIT_URL"),
  978. didRewrite: (0, _requestMeta).getRequestMeta(ctx.req, "_nextDidRewrite"),
  979. rewroteUrl: (0, _requestMeta).getRequestMeta(ctx.req, "_nextRewroteUrl")
  980. }, null, 2));
  981. throw err;
  982. }
  983. if (err instanceof NoFallbackError && bubbleNoFallback) {
  984. throw err;
  985. }
  986. if (err instanceof _utils.DecodeError || err instanceof _utils.NormalizeError) {
  987. res.statusCode = 400;
  988. return await this.renderErrorToResponse(ctx, err);
  989. }
  990. res.statusCode = 500;
  991. // if pages/500 is present we still need to trigger
  992. // /_error `getInitialProps` to allow reporting error
  993. if (await this.hasPage("/500")) {
  994. ctx.query.__nextCustomErrorRender = "1";
  995. await this.renderErrorToResponse(ctx, err);
  996. delete ctx.query.__nextCustomErrorRender;
  997. }
  998. const isWrappedError = err instanceof WrappedBuildError;
  999. if (!isWrappedError) {
  1000. if (this.minimalMode && process.env.NEXT_RUNTIME !== "edge" || this.renderOpts.dev) {
  1001. if ((0, _isError).default(err)) err.page = page;
  1002. throw err;
  1003. }
  1004. this.logError((0, _isError).getProperError(err));
  1005. }
  1006. const response = await this.renderErrorToResponse(ctx, isWrappedError ? err.innerError : err);
  1007. return response;
  1008. }
  1009. if (this.router.catchAllMiddleware[0] && !!ctx.req.headers["x-nextjs-data"] && (!res.statusCode || res.statusCode === 200 || res.statusCode === 404)) {
  1010. res.setHeader("x-nextjs-matched-path", `${query.__nextLocale ? `/${query.__nextLocale}` : ""}${pathname}`);
  1011. res.statusCode = 200;
  1012. res.setHeader("content-type", "application/json");
  1013. res.body("{}");
  1014. res.send();
  1015. return null;
  1016. }
  1017. res.statusCode = 404;
  1018. return this.renderErrorToResponse(ctx, null);
  1019. }
  1020. async renderToHTML(req, res, pathname, query = {}) {
  1021. return this.getStaticHTML((ctx)=>this.renderToResponse(ctx), {
  1022. req,
  1023. res,
  1024. pathname,
  1025. query
  1026. });
  1027. }
  1028. async renderError(err, req, res, pathname, query = {}, setHeaders = true) {
  1029. if (setHeaders) {
  1030. res.setHeader("Cache-Control", "no-cache, no-store, max-age=0, must-revalidate");
  1031. }
  1032. return this.pipe(async (ctx)=>{
  1033. const response = await this.renderErrorToResponse(ctx, err);
  1034. if (this.minimalMode && res.statusCode === 500) {
  1035. throw err;
  1036. }
  1037. return response;
  1038. }, {
  1039. req,
  1040. res,
  1041. pathname,
  1042. query
  1043. });
  1044. }
  1045. customErrorNo404Warn = (0, _utils).execOnce(()=>{
  1046. Log.warn(`You have added a custom /_error page without a custom /404 page. This prevents the 404 page from being auto statically optimized.\nSee here for info: https://nextjs.org/docs/messages/custom-error-no-custom-404`);
  1047. });
  1048. async renderErrorToResponse(ctx, err) {
  1049. const { res , query } = ctx;
  1050. try {
  1051. let result = null;
  1052. const is404 = res.statusCode === 404;
  1053. let using404Page = false;
  1054. // use static 404 page if available and is 404 response
  1055. if (is404 && await this.hasPage("/404")) {
  1056. result = await this.findPageComponents({
  1057. pathname: "/404",
  1058. query,
  1059. params: {},
  1060. isAppPath: false
  1061. });
  1062. using404Page = result !== null;
  1063. }
  1064. let statusPage = `/${res.statusCode}`;
  1065. if (!ctx.query.__nextCustomErrorRender && !result && _constants.STATIC_STATUS_PAGES.includes(statusPage)) {
  1066. // skip ensuring /500 in dev mode as it isn't used and the
  1067. // dev overlay is used instead
  1068. if (statusPage !== "/500" || !this.renderOpts.dev) {
  1069. result = await this.findPageComponents({
  1070. pathname: statusPage,
  1071. query,
  1072. params: {},
  1073. isAppPath: false
  1074. });
  1075. }
  1076. }
  1077. if (!result) {
  1078. result = await this.findPageComponents({
  1079. pathname: "/_error",
  1080. query,
  1081. params: {},
  1082. isAppPath: false
  1083. });
  1084. statusPage = "/_error";
  1085. }
  1086. if (process.env.NODE_ENV !== "production" && !using404Page && await this.hasPage("/_error") && !await this.hasPage("/404")) {
  1087. this.customErrorNo404Warn();
  1088. }
  1089. try {
  1090. return await this.renderToResponseWithComponents({
  1091. ...ctx,
  1092. pathname: statusPage,
  1093. renderOpts: {
  1094. ...ctx.renderOpts,
  1095. err
  1096. }
  1097. }, result);
  1098. } catch (maybeFallbackError) {
  1099. if (maybeFallbackError instanceof NoFallbackError) {
  1100. throw new Error("invariant: failed to render error page");
  1101. }
  1102. throw maybeFallbackError;
  1103. }
  1104. } catch (error) {
  1105. const renderToHtmlError = (0, _isError).getProperError(error);
  1106. const isWrappedError = renderToHtmlError instanceof WrappedBuildError;
  1107. if (!isWrappedError) {
  1108. this.logError(renderToHtmlError);
  1109. }
  1110. res.statusCode = 500;
  1111. const fallbackComponents = await this.getFallbackErrorComponents();
  1112. if (fallbackComponents) {
  1113. return this.renderToResponseWithComponents({
  1114. ...ctx,
  1115. pathname: "/_error",
  1116. renderOpts: {
  1117. ...ctx.renderOpts,
  1118. // We render `renderToHtmlError` here because `err` is
  1119. // already captured in the stacktrace.
  1120. err: isWrappedError ? renderToHtmlError.innerError : renderToHtmlError
  1121. }
  1122. }, {
  1123. query,
  1124. components: fallbackComponents
  1125. });
  1126. }
  1127. return {
  1128. type: "html",
  1129. body: _renderResult.default.fromStatic("Internal Server Error")
  1130. };
  1131. }
  1132. }
  1133. async renderErrorToHTML(err, req, res, pathname, query = {}) {
  1134. return this.getStaticHTML((ctx)=>this.renderErrorToResponse(ctx, err), {
  1135. req,
  1136. res,
  1137. pathname,
  1138. query
  1139. });
  1140. }
  1141. async getFallbackErrorComponents() {
  1142. // The development server will provide an implementation for this
  1143. return null;
  1144. }
  1145. async render404(req, res, parsedUrl, setHeaders = true) {
  1146. const { pathname , query } = parsedUrl ? parsedUrl : (0, _url).parse(req.url, true);
  1147. if (this.nextConfig.i18n) {
  1148. query.__nextLocale = query.__nextLocale || this.nextConfig.i18n.defaultLocale;
  1149. query.__nextDefaultLocale = query.__nextDefaultLocale || this.nextConfig.i18n.defaultLocale;
  1150. }
  1151. res.statusCode = 404;
  1152. return this.renderError(null, req, res, pathname, query, setHeaders);
  1153. }
  1154. }
  1155. exports.default = Server;
  1156. function _interopRequireDefault(obj) {
  1157. return obj && obj.__esModule ? obj : {
  1158. default: obj
  1159. };
  1160. }
  1161. function _getRequireWildcardCache() {
  1162. if (typeof WeakMap !== "function") return null;
  1163. var cache = new WeakMap();
  1164. _getRequireWildcardCache = function() {
  1165. return cache;
  1166. };
  1167. return cache;
  1168. }
  1169. function _interopRequireWildcard(obj) {
  1170. if (obj && obj.__esModule) {
  1171. return obj;
  1172. }
  1173. if (obj === null || typeof obj !== "object" && typeof obj !== "function") {
  1174. return {
  1175. default: obj
  1176. };
  1177. }
  1178. var cache = _getRequireWildcardCache();
  1179. if (cache && cache.has(obj)) {
  1180. return cache.get(obj);
  1181. }
  1182. var newObj = {};
  1183. var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor;
  1184. for(var key in obj){
  1185. if (Object.prototype.hasOwnProperty.call(obj, key)) {
  1186. var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null;
  1187. if (desc && (desc.get || desc.set)) {
  1188. Object.defineProperty(newObj, key, desc);
  1189. } else {
  1190. newObj[key] = obj[key];
  1191. }
  1192. }
  1193. }
  1194. newObj.default = obj;
  1195. if (cache) {
  1196. cache.set(obj, newObj);
  1197. }
  1198. return newObj;
  1199. }
  1200. class NoFallbackError extends Error {
  1201. }
  1202. exports.NoFallbackError = NoFallbackError;
  1203. class WrappedBuildError extends Error {
  1204. constructor(innerError){
  1205. super();
  1206. this.innerError = innerError;
  1207. }
  1208. }
  1209. exports.WrappedBuildError = WrappedBuildError;
  1210. function prepareServerlessUrl(req, query) {
  1211. const curUrl = (0, _url).parse(req.url, true);
  1212. req.url = (0, _url).format({
  1213. ...curUrl,
  1214. search: undefined,
  1215. query: {
  1216. ...curUrl.query,
  1217. ...query
  1218. }
  1219. });
  1220. }
  1221. //# sourceMappingURL=base-server.js.map