UNPKG

7.2 kBJavaScriptView Raw
1"use strict";exports.__esModule=true;exports.default=exports.route=void 0;var _pathMatch=_interopRequireDefault(require("../lib/router/utils/path-match"));var _normalizeTrailingSlash=require("../../client/normalize-trailing-slash");var _normalizeLocalePath=require("../lib/i18n/normalize-locale-path");var _prepareDestination=require("../lib/router/utils/prepare-destination");function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj};}const route=(0,_pathMatch.default)();exports.route=route;const customRouteTypes=new Set(['rewrite','redirect','header']);function replaceBasePath(basePath,pathname){// If replace ends up replacing the full url it'll be `undefined`, meaning we have to default it to `/`
2return pathname.replace(basePath,'')||'/';}class Router{constructor({basePath='',headers=[],fsRoutes=[],rewrites={beforeFiles:[],afterFiles:[],fallback:[]},redirects=[],catchAllRoute,dynamicRoutes=[],pageChecker,useFileSystemPublicRoutes,locales=[]}){this.basePath=void 0;this.headers=void 0;this.fsRoutes=void 0;this.redirects=void 0;this.rewrites=void 0;this.catchAllRoute=void 0;this.pageChecker=void 0;this.dynamicRoutes=void 0;this.useFileSystemPublicRoutes=void 0;this.locales=void 0;this.basePath=basePath;this.headers=headers;this.fsRoutes=fsRoutes;this.rewrites=rewrites;this.redirects=redirects;this.pageChecker=pageChecker;this.catchAllRoute=catchAllRoute;this.dynamicRoutes=dynamicRoutes;this.useFileSystemPublicRoutes=useFileSystemPublicRoutes;this.locales=locales;}setDynamicRoutes(routes=[]){this.dynamicRoutes=routes;}addFsRoute(fsRoute){this.fsRoutes.unshift(fsRoute);}async execute(req,res,parsedUrl){// memoize page check calls so we don't duplicate checks for pages
3const pageChecks={};const memoizedPageChecker=async p=>{p=(0,_normalizeLocalePath.normalizeLocalePath)(p,this.locales).pathname;if(pageChecks[p]){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=replaceBasePath(this.basePath,originalFsPathname);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
4if(!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
5if(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;}};/*
6 Desired routes order
7 - headers
8 - redirects
9 - Check filesystem (including pages), if nothing found continue
10 - User rewrites (checking filesystem and pages each match)
11 */const allRoutes=[...this.headers,...this.redirects,...this.rewrites.beforeFiles,...this.fsRoutes,// We only check the catch-all route if public page routes hasn't been
12// disabled
13...(this.useFileSystemPublicRoutes?[{type:'route',name:'page checker',requireBasePath:false,match:route('/:path*'),fn:async(checkerReq,checkerRes,params,parsedCheckerUrl)=>{let{pathname}=parsedCheckerUrl;pathname=(0,_normalizeTrailingSlash.removePathTrailingSlash)(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',requireBasePath:false,match:route('/: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
14// disabled
15...(this.useFileSystemPublicRoutes?[this.catchAllRoute]:[])];const originallyHadBasePath=!this.basePath||req._nextHadBasePath;for(const testRoute of allRoutes){// if basePath is being used, the basePath will still be included
16// in the pathname here to allow custom-routes to require containing
17// it or not, filesystem routes and pages must always include the basePath
18// if it is set
19let currentPathname=parsedUrlUpdated.pathname;const originalPathname=currentPathname;const requireBasePath=testRoute.requireBasePath!==false;const isCustomRoute=customRouteTypes.has(testRoute.type);const isPublicFolderCatchall=testRoute.name==='public folder catchall';const keepBasePath=isCustomRoute||isPublicFolderCatchall;const keepLocale=isCustomRoute;const currentPathnameNoBasePath=replaceBasePath(this.basePath,currentPathname);if(!keepBasePath){currentPathname=currentPathnameNoBasePath;}const localePathResult=(0,_normalizeLocalePath.normalizeLocalePath)(currentPathnameNoBasePath,this.locales);const activeBasePath=keepBasePath?this.basePath:'';if(keepLocale){if(!testRoute.internal&&parsedUrl.query.__nextLocale&&!localePathResult.detectedLocale){currentPathname=`${activeBasePath}/${parsedUrl.query.__nextLocale}${currentPathnameNoBasePath==='/'?'':currentPathnameNoBasePath}`;}if(req.__nextHadTrailingSlash&&!currentPathname.endsWith('/')){currentPathname+='/';}}else{currentPathname=`${req._nextHadBasePath?activeBasePath:''}${activeBasePath&&localePathResult.pathname==='/'?'':localePathResult.pathname}`;}let newParams=testRoute.match(currentPathname);if(testRoute.has&&newParams){const hasParams=(0,_prepareDestination.matchHas)(req,testRoute.has,parsedUrlUpdated.query);if(hasParams){Object.assign(newParams,hasParams);}else{newParams=false;}}// Check if the match function matched
20if(newParams){// since we require basePath be present for non-custom-routes we
21// 404 here when we matched an fs route
22if(!keepBasePath){if(!originallyHadBasePath&&!req._nextDidRewrite){if(requireBasePath){// consider this a non-match so the 404 renders
23return false;}// page checker occurs before rewrites so we need to continue
24// to check those since they don't always require basePath
25continue;}parsedUrlUpdated.pathname=currentPathname;}const result=await testRoute.fn(req,res,newParams,parsedUrlUpdated);// The response was handled
26if(result.finished){return true;}// since the fs route didn't match we need to re-add the basePath
27// to continue checking rewrites with the basePath present
28if(!keepBasePath){parsedUrlUpdated.pathname=originalPathname;}if(result.pathname){parsedUrlUpdated.pathname=result.pathname;}if(result.query){parsedUrlUpdated.query={...parsedUrlUpdated.query,...result.query};}// check filesystem
29if(testRoute.check===true){if(await applyCheckTrue(parsedUrlUpdated)){return true;}}}}return false;}}exports.default=Router;
30//# sourceMappingURL=router.js.map
\No newline at end of file