web-server.js 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", {
  3. value: true
  4. });
  5. exports.default = void 0;
  6. var _baseServer = _interopRequireWildcard(require("./base-server"));
  7. var _web = require("./api-utils/web");
  8. var _etag = require("./lib/etag");
  9. var _requestMeta = require("./request-meta");
  10. var _web1 = _interopRequireDefault(require("./response-cache/web"));
  11. var _pathMatch = require("../shared/lib/router/utils/path-match");
  12. var _getRouteFromAssetPath = _interopRequireDefault(require("../shared/lib/router/utils/get-route-from-asset-path"));
  13. var _detectDomainLocale = require("../shared/lib/i18n/detect-domain-locale");
  14. var _normalizeLocalePath = require("../shared/lib/i18n/normalize-locale-path");
  15. var _removeTrailingSlash = require("../shared/lib/router/utils/remove-trailing-slash");
  16. class NextWebServer extends _baseServer.default {
  17. constructor(options){
  18. super(options);
  19. // Extend `renderOpts`.
  20. Object.assign(this.renderOpts, options.webServerConfig.extendRenderOpts);
  21. }
  22. handleCompression() {
  23. // For the web server layer, compression is automatically handled by the
  24. // upstream proxy (edge runtime or node server) and we can simply skip here.
  25. }
  26. getResponseCache() {
  27. return new _web1.default(this.minimalMode);
  28. }
  29. getCustomRoutes() {
  30. return {
  31. headers: [],
  32. rewrites: {
  33. fallback: [],
  34. afterFiles: [],
  35. beforeFiles: []
  36. },
  37. redirects: []
  38. };
  39. }
  40. async run(req, res, parsedUrl) {
  41. super.run(req, res, parsedUrl);
  42. }
  43. async hasPage(page) {
  44. return page === this.serverOptions.webServerConfig.page;
  45. }
  46. getPublicDir() {
  47. // Public files are not handled by the web server.
  48. return "";
  49. }
  50. getBuildId() {
  51. return this.serverOptions.webServerConfig.extendRenderOpts.buildId;
  52. }
  53. loadEnvConfig() {
  54. // The web server does not need to load the env config. This is done by the
  55. // runtime already.
  56. }
  57. getHasStaticDir() {
  58. return false;
  59. }
  60. async getFallback() {
  61. return "";
  62. }
  63. getFontManifest() {
  64. return undefined;
  65. }
  66. getPagesManifest() {
  67. return {
  68. [this.serverOptions.webServerConfig.page]: ""
  69. };
  70. }
  71. getAppPathsManifest() {
  72. return {
  73. [this.serverOptions.webServerConfig.page]: ""
  74. };
  75. }
  76. getFilesystemPaths() {
  77. return new Set();
  78. }
  79. attachRequestMeta(req, parsedUrl) {
  80. (0, _requestMeta).addRequestMeta(req, "__NEXT_INIT_QUERY", {
  81. ...parsedUrl.query
  82. });
  83. }
  84. getPrerenderManifest() {
  85. return {
  86. version: 3,
  87. routes: {},
  88. dynamicRoutes: {},
  89. notFoundRoutes: [],
  90. preview: {
  91. previewModeId: "",
  92. previewModeSigningKey: "",
  93. previewModeEncryptionKey: ""
  94. }
  95. };
  96. }
  97. getServerComponentManifest() {
  98. return this.serverOptions.webServerConfig.extendRenderOpts.serverComponentManifest;
  99. }
  100. getServerCSSManifest() {
  101. return this.serverOptions.webServerConfig.extendRenderOpts.serverCSSManifest;
  102. }
  103. generateRoutes() {
  104. const fsRoutes = [
  105. {
  106. match: (0, _pathMatch).getPathMatch("/_next/data/:path*"),
  107. type: "route",
  108. name: "_next/data catchall",
  109. check: true,
  110. fn: async (req, res, params, _parsedUrl)=>{
  111. // Make sure to 404 for /_next/data/ itself and
  112. // we also want to 404 if the buildId isn't correct
  113. if (!params.path || params.path[0] !== this.buildId) {
  114. await this.render404(req, res, _parsedUrl);
  115. return {
  116. finished: true
  117. };
  118. }
  119. // remove buildId from URL
  120. params.path.shift();
  121. const lastParam = params.path[params.path.length - 1];
  122. // show 404 if it doesn't end with .json
  123. if (typeof lastParam !== "string" || !lastParam.endsWith(".json")) {
  124. await this.render404(req, res, _parsedUrl);
  125. return {
  126. finished: true
  127. };
  128. }
  129. // re-create page's pathname
  130. let pathname = `/${params.path.join("/")}`;
  131. pathname = (0, _getRouteFromAssetPath).default(pathname, ".json");
  132. // ensure trailing slash is normalized per config
  133. if (this.router.catchAllMiddleware[0]) {
  134. if (this.nextConfig.trailingSlash && !pathname.endsWith("/")) {
  135. pathname += "/";
  136. }
  137. if (!this.nextConfig.trailingSlash && pathname.length > 1 && pathname.endsWith("/")) {
  138. pathname = pathname.substring(0, pathname.length - 1);
  139. }
  140. }
  141. if (this.nextConfig.i18n) {
  142. const { host } = (req == null ? void 0 : req.headers) || {};
  143. // remove port from host and remove port if present
  144. const hostname = host == null ? void 0 : host.split(":")[0].toLowerCase();
  145. const localePathResult = (0, _normalizeLocalePath).normalizeLocalePath(pathname, this.nextConfig.i18n.locales);
  146. const { defaultLocale } = (0, _detectDomainLocale).detectDomainLocale(this.nextConfig.i18n.domains, hostname) || {};
  147. let detectedLocale = "";
  148. if (localePathResult.detectedLocale) {
  149. pathname = localePathResult.pathname;
  150. detectedLocale = localePathResult.detectedLocale;
  151. }
  152. _parsedUrl.query.__nextLocale = detectedLocale;
  153. _parsedUrl.query.__nextDefaultLocale = defaultLocale || this.nextConfig.i18n.defaultLocale;
  154. if (!detectedLocale && !this.router.catchAllMiddleware[0]) {
  155. _parsedUrl.query.__nextLocale = _parsedUrl.query.__nextDefaultLocale;
  156. await this.render404(req, res, _parsedUrl);
  157. return {
  158. finished: true
  159. };
  160. }
  161. }
  162. return {
  163. pathname,
  164. query: {
  165. ..._parsedUrl.query,
  166. __nextDataReq: "1"
  167. },
  168. finished: false
  169. };
  170. }
  171. },
  172. {
  173. match: (0, _pathMatch).getPathMatch("/_next/:path*"),
  174. type: "route",
  175. name: "_next catchall",
  176. // This path is needed because `render()` does a check for `/_next` and the calls the routing again
  177. fn: async (req, res, _params, parsedUrl)=>{
  178. await this.render404(req, res, parsedUrl);
  179. return {
  180. finished: true
  181. };
  182. }
  183. },
  184. ];
  185. const catchAllRoute = {
  186. match: (0, _pathMatch).getPathMatch("/:path*"),
  187. type: "route",
  188. matchesLocale: true,
  189. name: "Catchall render",
  190. fn: async (req, res, _params, parsedUrl)=>{
  191. let { pathname , query } = parsedUrl;
  192. if (!pathname) {
  193. throw new Error("pathname is undefined");
  194. }
  195. // next.js core assumes page path without trailing slash
  196. pathname = (0, _removeTrailingSlash).removeTrailingSlash(pathname);
  197. if (this.nextConfig.i18n) {
  198. var ref;
  199. const localePathResult = (0, _normalizeLocalePath).normalizeLocalePath(pathname, (ref = this.nextConfig.i18n) == null ? void 0 : ref.locales);
  200. if (localePathResult.detectedLocale) {
  201. pathname = localePathResult.pathname;
  202. parsedUrl.query.__nextLocale = localePathResult.detectedLocale;
  203. }
  204. }
  205. const bubbleNoFallback = !!query._nextBubbleNoFallback;
  206. if (pathname === "/api" || pathname.startsWith("/api/")) {
  207. delete query._nextBubbleNoFallback;
  208. }
  209. try {
  210. await this.render(req, res, pathname, query, parsedUrl, true);
  211. return {
  212. finished: true
  213. };
  214. } catch (err) {
  215. if (err instanceof _baseServer.NoFallbackError && bubbleNoFallback) {
  216. return {
  217. finished: false
  218. };
  219. }
  220. throw err;
  221. }
  222. }
  223. };
  224. const { useFileSystemPublicRoutes } = this.nextConfig;
  225. if (useFileSystemPublicRoutes) {
  226. this.appPathRoutes = this.getAppPathRoutes();
  227. this.dynamicRoutes = this.getDynamicRoutes();
  228. }
  229. return {
  230. headers: [],
  231. fsRoutes,
  232. rewrites: {
  233. beforeFiles: [],
  234. afterFiles: [],
  235. fallback: []
  236. },
  237. redirects: [],
  238. catchAllRoute,
  239. catchAllMiddleware: [],
  240. useFileSystemPublicRoutes,
  241. dynamicRoutes: this.dynamicRoutes,
  242. pageChecker: this.hasPage.bind(this),
  243. nextConfig: this.nextConfig
  244. };
  245. }
  246. // Edge API requests are handled separately in minimal mode.
  247. async handleApiRequest() {
  248. return false;
  249. }
  250. async renderHTML(req, _res, pathname, query, renderOpts) {
  251. const { pagesRenderToHTML , appRenderToHTML } = this.serverOptions.webServerConfig;
  252. const curRenderToHTML = pagesRenderToHTML || appRenderToHTML;
  253. if (curRenderToHTML) {
  254. return await curRenderToHTML({
  255. url: req.url,
  256. cookies: req.cookies,
  257. headers: req.headers
  258. }, {}, pathname, query, Object.assign(renderOpts, {
  259. disableOptimizedLoading: true,
  260. runtime: "experimental-edge"
  261. }), !!pagesRenderToHTML);
  262. } else {
  263. throw new Error(`Invariant: curRenderToHTML is missing`);
  264. }
  265. }
  266. async sendRenderResult(_req, res, options) {
  267. res.setHeader("X-Edge-Runtime", "1");
  268. // Add necessary headers.
  269. // @TODO: Share the isomorphic logic with server/send-payload.ts.
  270. if (options.poweredByHeader && options.type === "html") {
  271. res.setHeader("X-Powered-By", "Next.js");
  272. }
  273. const resultContentType = options.result.contentType();
  274. if (!res.getHeader("Content-Type")) {
  275. res.setHeader("Content-Type", resultContentType ? resultContentType : options.type === "json" ? "application/json" : "text/html; charset=utf-8");
  276. }
  277. if (options.result.isDynamic()) {
  278. const writer = res.transformStream.writable.getWriter();
  279. options.result.pipe({
  280. write: (chunk)=>writer.write(chunk),
  281. end: ()=>writer.close(),
  282. destroy: (err)=>writer.abort(err),
  283. cork: ()=>{},
  284. uncork: ()=>{}
  285. });
  286. } else {
  287. const payload = await options.result.toUnchunkedString();
  288. res.setHeader("Content-Length", String((0, _web).byteLength(payload)));
  289. if (options.generateEtags) {
  290. res.setHeader("ETag", (0, _etag).generateETag(payload));
  291. }
  292. res.body(payload);
  293. }
  294. res.send();
  295. }
  296. async runApi() {
  297. // @TODO
  298. return true;
  299. }
  300. async findPageComponents({ pathname , query , params }) {
  301. const result = await this.serverOptions.webServerConfig.loadComponent(pathname);
  302. if (!result) return null;
  303. return {
  304. query: {
  305. ...query || {},
  306. ...params || {}
  307. },
  308. components: result
  309. };
  310. }
  311. }
  312. exports.default = NextWebServer;
  313. function _interopRequireDefault(obj) {
  314. return obj && obj.__esModule ? obj : {
  315. default: obj
  316. };
  317. }
  318. function _getRequireWildcardCache() {
  319. if (typeof WeakMap !== "function") return null;
  320. var cache = new WeakMap();
  321. _getRequireWildcardCache = function() {
  322. return cache;
  323. };
  324. return cache;
  325. }
  326. function _interopRequireWildcard(obj) {
  327. if (obj && obj.__esModule) {
  328. return obj;
  329. }
  330. if (obj === null || typeof obj !== "object" && typeof obj !== "function") {
  331. return {
  332. default: obj
  333. };
  334. }
  335. var cache = _getRequireWildcardCache();
  336. if (cache && cache.has(obj)) {
  337. return cache.get(obj);
  338. }
  339. var newObj = {};
  340. var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor;
  341. for(var key in obj){
  342. if (Object.prototype.hasOwnProperty.call(obj, key)) {
  343. var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null;
  344. if (desc && (desc.get || desc.set)) {
  345. Object.defineProperty(newObj, key, desc);
  346. } else {
  347. newObj[key] = obj[key];
  348. }
  349. }
  350. }
  351. newObj.default = obj;
  352. if (cache) {
  353. cache.set(obj, newObj);
  354. }
  355. return newObj;
  356. }
  357. //# sourceMappingURL=web-server.js.map