UNPKG

next

Version:

The React Framework

254 lines (253 loc) • 12 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; var _requestMeta = require("./request-meta"); var _pathMatch = require("../shared/lib/router/utils/path-match"); var _removeTrailingSlash = require("../shared/lib/router/utils/remove-trailing-slash"); var _normalizeLocalePath = require("../shared/lib/i18n/normalize-locale-path"); var _prepareDestination = require("../shared/lib/router/utils/prepare-destination"); var _removePathPrefix = require("../shared/lib/router/utils/remove-path-prefix"); var _formatNextPathnameInfo = require("../shared/lib/router/utils/format-next-pathname-info"); var _getNextPathnameInfo = require("../shared/lib/router/utils/get-next-pathname-info"); class Router { constructor({ headers =[] , fsRoutes =[] , rewrites ={ beforeFiles: [], afterFiles: [], fallback: [] } , redirects =[] , catchAllRoute , catchAllMiddleware =[] , dynamicRoutes =[] , pageChecker , useFileSystemPublicRoutes , nextConfig }){ this.nextConfig = nextConfig; this.headers = headers; this.fsRoutes = fsRoutes; this.rewrites = rewrites; this.redirects = redirects; this.pageChecker = pageChecker; this.catchAllRoute = catchAllRoute; this.catchAllMiddleware = catchAllMiddleware; this.dynamicRoutes = dynamicRoutes; this.useFileSystemPublicRoutes = useFileSystemPublicRoutes; this.seenRequests = new Set(); } get locales() { var ref; return ((ref = this.nextConfig.i18n) == null ? void 0 : ref.locales) || []; } get basePath() { return this.nextConfig.basePath || ""; } setDynamicRoutes(routes = []) { this.dynamicRoutes = routes; } setCatchallMiddleware(route) { this.catchAllMiddleware = route || []; } addFsRoute(fsRoute) { this.fsRoutes.unshift(fsRoute); } async execute(req, res, parsedUrl, upgradeHead) { if (this.seenRequests.has(req)) { throw new Error(`Invariant: request has already been processed: ${req.url}, this is an internal error please open an issue.`); } this.seenRequests.add(req); try { // memoize page check calls so we don't duplicate checks for pages const pageChecks = {}; const memoizedPageChecker = async (p)=>{ p = (0, _normalizeLocalePath).normalizeLocalePath(p, this.locales).pathname; if (pageChecks[p] !== undefined) { return pageChecks[p]; } const result = this.pageChecker(p); pageChecks[p] = result; return result; }; let parsedUrlUpdated = parsedUrl; const applyCheckTrue = async (checkParsedUrl)=>{ const originalFsPathname = checkParsedUrl.pathname; const fsPathname = (0, _removePathPrefix).removePathPrefix(originalFsPathname, this.basePath); for (const fsRoute of this.fsRoutes){ const fsParams = fsRoute.match(fsPathname); if (fsParams) { checkParsedUrl.pathname = fsPathname; const fsResult = await fsRoute.fn(req, res, fsParams, checkParsedUrl); if (fsResult.finished) { return true; } checkParsedUrl.pathname = originalFsPathname; } } let matchedPage = await memoizedPageChecker(fsPathname); // If we didn't match a page check dynamic routes if (!matchedPage) { const normalizedFsPathname = (0, _normalizeLocalePath).normalizeLocalePath(fsPathname, this.locales).pathname; for (const dynamicRoute of this.dynamicRoutes){ if (dynamicRoute.match(normalizedFsPathname)) { matchedPage = true; } } } // Matched a page or dynamic route so render it using catchAllRoute if (matchedPage) { const pageParams = this.catchAllRoute.match(checkParsedUrl.pathname); checkParsedUrl.pathname = fsPathname; checkParsedUrl.query._nextBubbleNoFallback = "1"; const result = await this.catchAllRoute.fn(req, res, pageParams, checkParsedUrl); return result.finished; } }; /* Desired routes order - headers - redirects - Check filesystem (including pages), if nothing found continue - User rewrites (checking filesystem and pages each match) */ const [middlewareCatchAllRoute, edgeSSRCatchAllRoute] = this.catchAllMiddleware; const allRoutes = [ ...middlewareCatchAllRoute ? this.fsRoutes.filter((r)=>r.name === "_next/data catchall").map((r)=>{ return { ...r, check: false }; }) : [], ...this.headers, ...this.redirects, ...this.useFileSystemPublicRoutes && middlewareCatchAllRoute ? [ middlewareCatchAllRoute ] : [], ...this.rewrites.beforeFiles, ...this.fsRoutes, // We only check the catch-all route if public page routes hasn't been // disabled ...this.useFileSystemPublicRoutes ? [ ...edgeSSRCatchAllRoute ? [ edgeSSRCatchAllRoute ] : [], { type: "route", name: "page checker", match: (0, _pathMatch).getPathMatch("/:path*"), fn: async (checkerReq, checkerRes, params, parsedCheckerUrl)=>{ let { pathname } = parsedCheckerUrl; pathname = (0, _removeTrailingSlash).removeTrailingSlash(pathname || "/"); if (!pathname) { return { finished: false }; } if (await memoizedPageChecker(pathname)) { return this.catchAllRoute.fn(checkerReq, checkerRes, params, parsedCheckerUrl); } return { finished: false }; } }, ] : [], ...this.rewrites.afterFiles, ...this.rewrites.fallback.length ? [ { type: "route", name: "dynamic route/page check", match: (0, _pathMatch).getPathMatch("/:path*"), fn: async (_checkerReq, _checkerRes, _params, parsedCheckerUrl)=>{ return { finished: await applyCheckTrue(parsedCheckerUrl) }; } }, ...this.rewrites.fallback, ] : [], // We only check the catch-all route if public page routes hasn't been // disabled ...this.useFileSystemPublicRoutes ? [ ...edgeSSRCatchAllRoute ? [ edgeSSRCatchAllRoute ] : [], this.catchAllRoute, ] : [], ]; for (const testRoute of allRoutes){ var ref; // only process rewrites for upgrade request if (upgradeHead && testRoute.type !== "rewrite") { continue; } const originalPathname = parsedUrlUpdated.pathname; const pathnameInfo = (0, _getNextPathnameInfo).getNextPathnameInfo(originalPathname, { nextConfig: this.nextConfig, parseData: false }); if (pathnameInfo.locale && !testRoute.matchesLocaleAPIRoutes && pathnameInfo.pathname.match(/^\/api(?:\/|$)/)) { continue; } if ((0, _requestMeta).getRequestMeta(req, "_nextHadBasePath")) { pathnameInfo.basePath = this.basePath; } const basePath = pathnameInfo.basePath; if (!testRoute.matchesBasePath) { pathnameInfo.basePath = ""; } if (testRoute.matchesLocale && parsedUrl.query.__nextLocale && !pathnameInfo.locale) { pathnameInfo.locale = parsedUrl.query.__nextLocale; } if (!testRoute.matchesLocale && pathnameInfo.locale === ((ref = this.nextConfig.i18n) == null ? void 0 : ref.defaultLocale) && pathnameInfo.locale) { pathnameInfo.locale = undefined; } if (testRoute.matchesTrailingSlash && (0, _requestMeta).getRequestMeta(req, "__nextHadTrailingSlash")) { pathnameInfo.trailingSlash = true; } const matchPathname = (0, _formatNextPathnameInfo).formatNextPathnameInfo({ ignorePrefix: true, ...pathnameInfo }); let newParams = testRoute.match(matchPathname); if (testRoute.has && newParams) { const hasParams = (0, _prepareDestination).matchHas(req, testRoute.has, parsedUrlUpdated.query); if (hasParams) { Object.assign(newParams, hasParams); } else { newParams = false; } } /** * If it is a matcher that doesn't match the basePath (like the public * directory) but Next.js is configured to use a basePath that was * never there, we consider this an invalid match and keep routing. */ if (newParams && this.basePath && !testRoute.matchesBasePath && !(0, _requestMeta).getRequestMeta(req, "_nextDidRewrite") && !basePath) { continue; } if (newParams) { parsedUrlUpdated.pathname = matchPathname; const result = await testRoute.fn(req, res, newParams, parsedUrlUpdated, upgradeHead); if (result.finished) { return true; } // since the fs route didn't finish routing we need to re-add the // basePath to continue checking with the basePath present parsedUrlUpdated.pathname = originalPathname; if (result.pathname) { parsedUrlUpdated.pathname = result.pathname; } if (result.query) { parsedUrlUpdated.query = { ...(0, _requestMeta).getNextInternalQuery(parsedUrlUpdated.query), ...result.query }; } // check filesystem if (testRoute.check === true) { if (await applyCheckTrue(parsedUrlUpdated)) { return true; } } } } return false; } finally{ this.seenRequests.delete(req); } } } exports.default = Router; //# sourceMappingURL=router.js.map