page-handler.js 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", {
  3. value: true
  4. });
  5. exports.getPageHandler = getPageHandler;
  6. var _url = require("url");
  7. var _utils = require("../../../../shared/lib/utils");
  8. var _sendPayload = require("../../../../server/send-payload");
  9. var _utils1 = require("./utils");
  10. var _render = require("../../../../server/render");
  11. var _node = require("../../../../server/api-utils/node");
  12. var _denormalizePagePath = require("../../../../shared/lib/page-path/denormalize-page-path");
  13. var _apiUtils = require("../../../../server/api-utils");
  14. var _redirectStatus = require("../../../../lib/redirect-status");
  15. var _getRouteFromAssetPath = _interopRequireDefault(require("../../../../shared/lib/router/utils/get-route-from-asset-path"));
  16. var _constants = require("../../../../shared/lib/constants");
  17. var _renderResult = _interopRequireDefault(require("../../../../server/render-result"));
  18. var _isError = _interopRequireDefault(require("../../../../lib/is-error"));
  19. function _interopRequireDefault(obj) {
  20. return obj && obj.__esModule ? obj : {
  21. default: obj
  22. };
  23. }
  24. function getPageHandler(ctx) {
  25. const { page , pageComponent , pageConfig , pageGetStaticProps , pageGetStaticPaths , pageGetServerSideProps , appModule , documentModule , errorModule , notFoundModule , encodedPreviewProps , pageIsDynamic , generateEtags , poweredByHeader , runtimeConfig , buildManifest , reactLoadableManifest , i18n , buildId , basePath , assetPrefix , canonicalBase , escapedBuildId , } = ctx;
  26. const { handleLocale , handleRewrites , handleBasePath , defaultRouteRegex , dynamicRouteMatcher , interpolateDynamicPath , getParamsFromRouteMatches , normalizeDynamicRouteParams , normalizeVercelUrl , } = (0, _utils1).getUtils(ctx);
  27. async function renderReqToHTML(req, res, renderMode, _renderOpts, _params) {
  28. let Component;
  29. let App;
  30. let config;
  31. let Document;
  32. let Error;
  33. let notFoundMod;
  34. let getStaticProps;
  35. let getStaticPaths;
  36. let getServerSideProps;
  37. [getStaticProps, getServerSideProps, getStaticPaths, Component, App, config, { default: Document }, { default: Error }, notFoundMod, ] = await Promise.all([
  38. pageGetStaticProps,
  39. pageGetServerSideProps,
  40. pageGetStaticPaths,
  41. pageComponent,
  42. appModule,
  43. pageConfig,
  44. documentModule,
  45. errorModule,
  46. notFoundModule,
  47. ]);
  48. const fromExport = renderMode === "export" || renderMode === true;
  49. const nextStartMode = renderMode === "passthrough";
  50. let hasValidParams = true;
  51. (0, _apiUtils).setLazyProp({
  52. req: req
  53. }, "cookies", (0, _apiUtils).getCookieParser(req.headers));
  54. const options = {
  55. App,
  56. Document,
  57. ComponentMod: {
  58. default: Component
  59. },
  60. buildManifest,
  61. getStaticProps,
  62. getServerSideProps,
  63. getStaticPaths,
  64. reactLoadableManifest,
  65. canonicalBase,
  66. buildId,
  67. assetPrefix,
  68. runtimeConfig: (runtimeConfig || {}).publicRuntimeConfig || {},
  69. previewProps: encodedPreviewProps,
  70. env: process.env,
  71. basePath,
  72. supportsDynamicHTML: false,
  73. ..._renderOpts
  74. };
  75. let _nextData = false;
  76. let defaultLocale = i18n == null ? void 0 : i18n.defaultLocale;
  77. let detectedLocale = i18n == null ? void 0 : i18n.defaultLocale;
  78. let parsedUrl;
  79. try {
  80. var ref;
  81. // We need to trust the dynamic route params from the proxy
  82. // to ensure we are using the correct values
  83. const trustQuery = !getStaticProps && req.headers[_utils1.vercelHeader];
  84. parsedUrl = (0, _url).parse(req.url, true);
  85. let routeNoAssetPath = parsedUrl.pathname;
  86. if (basePath) {
  87. routeNoAssetPath = routeNoAssetPath.replace(new RegExp(`^${basePath}`), "") || "/";
  88. }
  89. const origQuery = Object.assign({}, parsedUrl.query);
  90. handleRewrites(req, parsedUrl);
  91. handleBasePath(req, parsedUrl);
  92. // remove ?amp=1 from request URL if rendering for export
  93. if (fromExport && parsedUrl.query.amp) {
  94. const queryNoAmp = Object.assign({}, origQuery);
  95. delete queryNoAmp.amp;
  96. req.url = (0, _url).format({
  97. ...parsedUrl,
  98. search: undefined,
  99. query: queryNoAmp
  100. });
  101. }
  102. if (parsedUrl.pathname.match(/_next\/data/)) {
  103. _nextData = page !== "/_error";
  104. parsedUrl.pathname = (0, _getRouteFromAssetPath).default(parsedUrl.pathname.replace(new RegExp(`/_next/data/${escapedBuildId}/`), "/"), ".json");
  105. routeNoAssetPath = parsedUrl.pathname;
  106. }
  107. const localeResult = handleLocale(req, res, parsedUrl, routeNoAssetPath, fromExport || nextStartMode);
  108. defaultLocale = (localeResult == null ? void 0 : localeResult.defaultLocale) || defaultLocale;
  109. detectedLocale = (localeResult == null ? void 0 : localeResult.detectedLocale) || detectedLocale;
  110. routeNoAssetPath = (localeResult == null ? void 0 : localeResult.routeNoAssetPath) || routeNoAssetPath;
  111. if (parsedUrl.query.nextInternalLocale) {
  112. detectedLocale = parsedUrl.query.nextInternalLocale;
  113. delete parsedUrl.query.nextInternalLocale;
  114. }
  115. const renderOpts = Object.assign({
  116. Component,
  117. pageConfig: config,
  118. nextExport: fromExport,
  119. isDataReq: _nextData,
  120. locales: i18n == null ? void 0 : i18n.locales,
  121. locale: detectedLocale,
  122. defaultLocale,
  123. domainLocales: i18n == null ? void 0 : i18n.domains,
  124. optimizeCss: process.env.__NEXT_OPTIMIZE_CSS,
  125. nextScriptWorkers: process.env.__NEXT_SCRIPT_WORKERS,
  126. crossOrigin: process.env.__NEXT_CROSS_ORIGIN
  127. }, options);
  128. if (page === "/_error" && !res.statusCode) {
  129. res.statusCode = 404;
  130. }
  131. let params = {};
  132. if (!fromExport && pageIsDynamic) {
  133. const result = normalizeDynamicRouteParams(trustQuery ? parsedUrl.query : dynamicRouteMatcher(parsedUrl.pathname));
  134. hasValidParams = result.hasValidParams;
  135. params = result.params;
  136. }
  137. let nowParams = null;
  138. if (pageIsDynamic && !hasValidParams && ((ref = req.headers) == null ? void 0 : ref["x-now-route-matches"])) {
  139. nowParams = getParamsFromRouteMatches(req, renderOpts, detectedLocale);
  140. }
  141. // make sure to set renderOpts to the correct params e.g. _params
  142. // if provided from worker or params if we're parsing them here
  143. renderOpts.params = _params || params;
  144. normalizeVercelUrl(req, !!trustQuery);
  145. // normalize request URL/asPath for fallback/revalidate pages since the
  146. // proxy sets the request URL to the output's path for fallback pages
  147. if (pageIsDynamic && nowParams && defaultRouteRegex) {
  148. const _parsedUrl = (0, _url).parse(req.url);
  149. _parsedUrl.pathname = interpolateDynamicPath(_parsedUrl.pathname, nowParams);
  150. parsedUrl.pathname = _parsedUrl.pathname;
  151. req.url = (0, _url).format(_parsedUrl);
  152. }
  153. // make sure to normalize asPath for revalidate and _next/data requests
  154. // since the asPath should match what is shown on the client
  155. if (!fromExport && (getStaticProps || getServerSideProps)) {
  156. // don't include dynamic route params in query while normalizing
  157. // asPath
  158. if (pageIsDynamic && defaultRouteRegex) {
  159. delete parsedUrl.search;
  160. for (const param of Object.keys(defaultRouteRegex.groups)){
  161. delete origQuery[param];
  162. }
  163. }
  164. parsedUrl.pathname = (0, _denormalizePagePath).denormalizePagePath(parsedUrl.pathname);
  165. renderOpts.resolvedUrl = (0, _url).format({
  166. ...parsedUrl,
  167. query: origQuery
  168. });
  169. // For getServerSideProps we need to ensure we use the original URL
  170. // and not the resolved URL to prevent a hydration mismatch on asPath
  171. renderOpts.resolvedAsPath = getServerSideProps ? (0, _url).format({
  172. ...parsedUrl,
  173. pathname: routeNoAssetPath,
  174. query: origQuery
  175. }) : renderOpts.resolvedUrl;
  176. }
  177. const isFallback = parsedUrl.query.__nextFallback;
  178. const previewData = (0, _node).tryGetPreviewData(req, res, options.previewProps);
  179. const isPreviewMode = previewData !== false;
  180. if (process.env.__NEXT_OPTIMIZE_FONTS) {
  181. renderOpts.optimizeFonts = process.env.__NEXT_OPTIMIZE_FONTS;
  182. /**
  183. * __webpack_require__.__NEXT_FONT_MANIFEST__ is added by
  184. * font-stylesheet-gathering-plugin
  185. */ // @ts-ignore
  186. renderOpts.fontManifest = __webpack_require__.__NEXT_FONT_MANIFEST__;
  187. }
  188. let result = await (0, _render).renderToHTML(req, res, page, Object.assign({}, getStaticProps ? {
  189. ...parsedUrl.query.amp ? {
  190. amp: "1"
  191. } : {}
  192. } : parsedUrl.query, nowParams ? nowParams : params, _params, isFallback ? {
  193. __nextFallback: "true"
  194. } : {}), renderOpts);
  195. if (!renderMode) {
  196. if (_nextData || getStaticProps || getServerSideProps) {
  197. if (renderOpts.isNotFound) {
  198. res.statusCode = 404;
  199. if (_nextData) {
  200. res.end('{"notFound":true}');
  201. return null;
  202. }
  203. const NotFoundComponent = notFoundMod ? notFoundMod.default : Error;
  204. const errPathname = notFoundMod ? "/404" : "/_error";
  205. const result2 = await (0, _render).renderToHTML(req, res, errPathname, parsedUrl.query, Object.assign({}, options, {
  206. getStaticProps: notFoundMod ? notFoundMod.getStaticProps : undefined,
  207. getStaticPaths: undefined,
  208. getServerSideProps: undefined,
  209. Component: NotFoundComponent,
  210. err: undefined,
  211. locale: detectedLocale,
  212. locales: i18n == null ? void 0 : i18n.locales,
  213. defaultLocale: i18n == null ? void 0 : i18n.defaultLocale
  214. }));
  215. (0, _sendPayload).sendRenderResult({
  216. req,
  217. res,
  218. result: result2 != null ? result2 : _renderResult.default.empty,
  219. type: "html",
  220. generateEtags,
  221. poweredByHeader,
  222. options: {
  223. private: isPreviewMode || page === "/404",
  224. stateful: !!getServerSideProps,
  225. revalidate: renderOpts.revalidate
  226. }
  227. });
  228. return null;
  229. } else if (renderOpts.isRedirect && !_nextData) {
  230. const redirect = {
  231. destination: renderOpts.pageData.pageProps.__N_REDIRECT,
  232. statusCode: renderOpts.pageData.pageProps.__N_REDIRECT_STATUS,
  233. basePath: renderOpts.pageData.pageProps.__N_REDIRECT_BASE_PATH
  234. };
  235. const statusCode = (0, _redirectStatus).getRedirectStatus(redirect);
  236. if (basePath && redirect.basePath !== false && redirect.destination.startsWith("/")) {
  237. redirect.destination = `${basePath}${redirect.destination}`;
  238. }
  239. if (statusCode === _constants.PERMANENT_REDIRECT_STATUS) {
  240. res.setHeader("Refresh", `0;url=${redirect.destination}`);
  241. }
  242. res.statusCode = statusCode;
  243. res.setHeader("Location", redirect.destination);
  244. res.end(redirect.destination);
  245. return null;
  246. } else {
  247. (0, _sendPayload).sendRenderResult({
  248. req,
  249. res,
  250. result: _nextData ? _renderResult.default.fromStatic(JSON.stringify(renderOpts.pageData)) : result != null ? result : _renderResult.default.empty,
  251. type: _nextData ? "json" : "html",
  252. generateEtags,
  253. poweredByHeader,
  254. options: {
  255. private: isPreviewMode || renderOpts.is404Page,
  256. stateful: !!getServerSideProps,
  257. revalidate: renderOpts.revalidate
  258. }
  259. });
  260. return null;
  261. }
  262. }
  263. } else if (isPreviewMode) {
  264. res.setHeader("Cache-Control", "private, no-cache, no-store, max-age=0, must-revalidate");
  265. }
  266. if (renderMode) return {
  267. html: result,
  268. renderOpts
  269. };
  270. return result ? result.toUnchunkedString() : null;
  271. } catch (err) {
  272. if (!parsedUrl) {
  273. parsedUrl = (0, _url).parse(req.url, true);
  274. }
  275. if ((0, _isError).default(err) && err.code === "ENOENT") {
  276. res.statusCode = 404;
  277. } else if (err instanceof _utils.DecodeError) {
  278. res.statusCode = 400;
  279. } else {
  280. console.error("Unhandled error during request:", err);
  281. // Backwards compat (call getInitialProps in custom error):
  282. try {
  283. await (0, _render).renderToHTML(req, res, "/_error", parsedUrl.query, Object.assign({}, options, {
  284. getStaticProps: undefined,
  285. getStaticPaths: undefined,
  286. getServerSideProps: undefined,
  287. Component: Error,
  288. err: err,
  289. // Short-circuit rendering:
  290. isDataReq: true
  291. }));
  292. } catch (underErrorErr) {
  293. console.error("Failed call /_error subroutine, continuing to crash function:", underErrorErr);
  294. }
  295. // Throw the error to crash the serverless function
  296. if ((0, _utils).isResSent(res)) {
  297. console.error("!!! WARNING !!!");
  298. console.error("Your function crashed, but closed the response before allowing the function to exit.\\n" + "This may cause unexpected behavior for the next request.");
  299. console.error("!!! WARNING !!!");
  300. }
  301. throw err;
  302. }
  303. const result2 = await (0, _render).renderToHTML(req, res, "/_error", parsedUrl.query, Object.assign({}, options, {
  304. getStaticProps: undefined,
  305. getStaticPaths: undefined,
  306. getServerSideProps: undefined,
  307. Component: Error,
  308. err: res.statusCode === 404 ? undefined : err
  309. }));
  310. return result2 ? result2.toUnchunkedString() : null;
  311. }
  312. }
  313. return {
  314. renderReqToHTML,
  315. render: async function render(req, res) {
  316. try {
  317. const html = await renderReqToHTML(req, res);
  318. if (html) {
  319. (0, _sendPayload).sendRenderResult({
  320. req,
  321. res,
  322. result: _renderResult.default.fromStatic(html),
  323. type: "html",
  324. generateEtags,
  325. poweredByHeader
  326. });
  327. }
  328. } catch (err) {
  329. console.error(err);
  330. // Throw the error to crash the serverless function
  331. throw err;
  332. }
  333. }
  334. };
  335. }
  336. //# sourceMappingURL=page-handler.js.map