Skip to content

Commit 53d1b00

Browse files
nkzawaijjk
andauthored
fix the dynamic routing of middleware (#32601)
* fix the dynamic routing of middleware * add middleware to dynamicRoutes of routes-manifest * remove unused import * fix middleware routing with static paths * update manifest version test * prevent to match with api route using regex * use iterator instead of generator * do not use Iterator * fix type * fix type * remove unused import * apply the fix for support colons Co-authored-by: JJ Kasper <jj@jjsweb.site>
1 parent 5d1f33f commit 53d1b00

34 files changed

Lines changed: 922 additions & 261 deletions

File tree

packages/next/build/index.ts

Lines changed: 26 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -447,12 +447,18 @@ export default async function build(
447447
namedRegex?: string
448448
routeKeys?: { [key: string]: string }
449449
}>
450-
dynamicRoutes: Array<{
451-
page: string
452-
regex: string
453-
namedRegex?: string
454-
routeKeys?: { [key: string]: string }
455-
}>
450+
dynamicRoutes: Array<
451+
| {
452+
page: string
453+
regex: string
454+
namedRegex?: string
455+
routeKeys?: { [key: string]: string }
456+
}
457+
| {
458+
page: string
459+
isMiddleware: true
460+
}
461+
>
456462
dataRoutes: Array<{
457463
page: string
458464
routeKeys?: { [key: string]: string }
@@ -471,14 +477,14 @@ export default async function build(
471477
localeDetection?: false
472478
}
473479
} = nextBuildSpan.traceChild('generate-routes-manifest').traceFn(() => ({
474-
version: 3,
480+
version: 4,
475481
pages404: true,
476482
basePath: config.basePath,
477483
redirects: redirects.map((r: any) => buildCustomRoute(r, 'redirect')),
478484
headers: headers.map((r: any) => buildCustomRoute(r, 'header')),
479485
dynamicRoutes: getSortedRoutes(pageKeys)
480-
.filter((page) => isDynamicRoute(page) && !page.match(MIDDLEWARE_ROUTE))
481-
.map(pageToRoute),
486+
.filter((page) => isDynamicRoute(page))
487+
.map(pageToRouteOrMiddleware),
482488
staticRoutes: getSortedRoutes(pageKeys)
483489
.filter(
484490
(page) =>
@@ -2190,3 +2196,14 @@ function pageToRoute(page: string) {
21902196
namedRegex: routeRegex.namedRegex,
21912197
}
21922198
}
2199+
2200+
function pageToRouteOrMiddleware(page: string) {
2201+
if (page.match(MIDDLEWARE_ROUTE)) {
2202+
return {
2203+
page: page.replace(/\/_middleware$/, '') || '/',
2204+
isMiddleware: true as const,
2205+
}
2206+
}
2207+
2208+
return pageToRoute(page)
2209+
}

packages/next/server/base-server.ts

Lines changed: 48 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,9 @@ import {
2929
TEMPORARY_REDIRECT_STATUS,
3030
} from '../shared/lib/constants'
3131
import {
32-
getRouteMatcher,
33-
getRouteRegex,
34-
getSortedRoutes,
32+
getRoutingItems,
3533
isDynamicRoute,
34+
RoutingItem,
3635
} from '../shared/lib/router/utils'
3736
import {
3837
setLazyProp,
@@ -71,12 +70,6 @@ export type FindComponentsResult = {
7170
query: NextParsedUrlQuery
7271
}
7372

74-
interface RoutingItem {
75-
page: string
76-
match: ReturnType<typeof getRouteMatcher>
77-
ssr?: boolean
78-
}
79-
8073
export interface Options {
8174
/**
8275
* Object containing the configuration next.config.js
@@ -177,8 +170,8 @@ export default abstract class Server {
177170
protected dynamicRoutes?: DynamicRoutes
178171
protected customRoutes: CustomRoutes
179172
protected middlewareManifest?: MiddlewareManifest
180-
protected middleware?: RoutingItem[]
181173
protected serverComponentManifest?: any
174+
protected allRoutes?: RoutingItem[]
182175
public readonly hostname?: string
183176
public readonly port?: number
184177

@@ -190,7 +183,8 @@ export default abstract class Server {
190183
protected abstract generateImageRoutes(): Route[]
191184
protected abstract generateStaticRoutes(): Route[]
192185
protected abstract generateFsStaticRoutes(): Route[]
193-
protected abstract generateCatchAllMiddlewareRoute(): Route | undefined
186+
protected abstract generateCatchAllStaticMiddlewareRoute(): Route | undefined
187+
protected abstract generateCatchAllDynamicMiddlewareRoute(): Route | undefined
194188
protected abstract generateRewrites({
195189
restrictedRedirectPaths,
196190
}: {
@@ -201,14 +195,6 @@ export default abstract class Server {
201195
fallback: Route[]
202196
}
203197
protected abstract getFilesystemPaths(): Set<string>
204-
protected abstract getMiddleware(): {
205-
match: (pathname: string | null | undefined) =>
206-
| false
207-
| {
208-
[paramName: string]: string | string[]
209-
}
210-
page: string
211-
}[]
212198
protected abstract findPageComponents(
213199
pathname: string,
214200
query?: NextParsedUrlQuery,
@@ -654,9 +640,11 @@ export default abstract class Server {
654640
fallback: Route[]
655641
}
656642
fsRoutes: Route[]
643+
internalFsRoutes: Route[]
657644
redirects: Route[]
658645
catchAllRoute: Route
659-
catchAllMiddleware?: Route
646+
catchAllStaticMiddleware?: Route
647+
catchAllDynamicMiddleware?: Route
660648
pageChecker: PageChecker
661649
useFileSystemPublicRoutes: boolean
662650
dynamicRoutes: DynamicRoutes | undefined
@@ -666,7 +654,7 @@ export default abstract class Server {
666654
const imageRoutes = this.generateImageRoutes()
667655
const staticFilesRoutes = this.generateStaticRoutes()
668656

669-
const fsRoutes: Route[] = [
657+
const internalFsRoutes: Route[] = [
670658
...this.generateFsStaticRoutes(),
671659
{
672660
match: route('/_next/data/:path*'),
@@ -756,10 +744,10 @@ export default abstract class Server {
756744
}
757745
},
758746
},
759-
...publicRoutes,
760-
...staticFilesRoutes,
761747
]
762748

749+
const fsRoutes: Route[] = [...publicRoutes, ...staticFilesRoutes]
750+
763751
const restrictedRedirectPaths = this.nextConfig.basePath
764752
? [`${this.nextConfig.basePath}/_next`]
765753
: ['/_next']
@@ -778,7 +766,10 @@ export default abstract class Server {
778766
)
779767

780768
const rewrites = this.generateRewrites({ restrictedRedirectPaths })
781-
const catchAllMiddleware = this.generateCatchAllMiddlewareRoute()
769+
const catchAllStaticMiddleware =
770+
this.generateCatchAllStaticMiddlewareRoute()
771+
const catchAllDynamicMiddleware =
772+
this.generateCatchAllDynamicMiddlewareRoute()
782773

783774
const catchAllRoute: Route = {
784775
match: route('/:path*'),
@@ -813,7 +804,7 @@ export default abstract class Server {
813804
}
814805
}
815806

816-
if (pathname === '/api' || pathname.startsWith('/api/')) {
807+
if (isApiRoute(pathname)) {
817808
delete query._nextBubbleNoFallback
818809

819810
const handled = await this.handleApiRequest(req, res, pathname, query)
@@ -842,19 +833,19 @@ export default abstract class Server {
842833
const { useFileSystemPublicRoutes } = this.nextConfig
843834

844835
if (useFileSystemPublicRoutes) {
836+
this.allRoutes = this.getAllRoutes()
845837
this.dynamicRoutes = this.getDynamicRoutes()
846-
if (!this.minimalMode) {
847-
this.middleware = this.getMiddleware()
848-
}
849838
}
850839

851840
return {
852841
headers,
853842
fsRoutes,
843+
internalFsRoutes,
854844
rewrites,
855845
redirects,
856846
catchAllRoute,
857-
catchAllMiddleware,
847+
catchAllStaticMiddleware,
848+
catchAllDynamicMiddleware,
858849
useFileSystemPublicRoutes,
859850
dynamicRoutes: this.dynamicRoutes,
860851
basePath: this.nextConfig.basePath,
@@ -931,24 +922,34 @@ export default abstract class Server {
931922
return this.runApi(req, res, query, params, page, builtPagePath)
932923
}
933924

925+
protected getAllRoutes(): RoutingItem[] {
926+
const pages = Object.keys(this.pagesManifest!).map(
927+
(page) =>
928+
normalizeLocalePath(page, this.nextConfig.i18n?.locales).pathname
929+
)
930+
const middlewareMap = this.minimalMode
931+
? {}
932+
: this.middlewareManifest?.middleware || {}
933+
const middleware = Object.keys(middlewareMap).map((page) => ({
934+
page,
935+
ssr: !MIDDLEWARE_ROUTE.test(middlewareMap[page].name),
936+
}))
937+
return getRoutingItems(pages, middleware)
938+
}
939+
934940
protected getDynamicRoutes(): Array<RoutingItem> {
935941
const addedPages = new Set<string>()
936942

937-
return getSortedRoutes(
938-
Object.keys(this.pagesManifest!).map(
939-
(page) =>
940-
normalizeLocalePath(page, this.nextConfig.i18n?.locales).pathname
943+
return this.allRoutes!.filter((item) => {
944+
if (
945+
item.isMiddleware ||
946+
addedPages.has(item.page) ||
947+
!isDynamicRoute(item.page)
941948
)
942-
)
943-
.map((page) => {
944-
if (addedPages.has(page) || !isDynamicRoute(page)) return null
945-
addedPages.add(page)
946-
return {
947-
page,
948-
match: getRouteMatcher(getRouteRegex(page)),
949-
}
950-
})
951-
.filter((item): item is RoutingItem => Boolean(item))
949+
return false
950+
addedPages.add(item.page)
951+
return true
952+
})
952953
}
953954

954955
protected async run(
@@ -1926,6 +1927,10 @@ export function prepareServerlessUrl(
19261927

19271928
export { stringifyQuery } from './server-route-utils'
19281929

1930+
export function isApiRoute(pathname: string) {
1931+
return pathname === '/api' || pathname.startsWith('/api/')
1932+
}
1933+
19291934
class NoFallbackError extends Error {}
19301935

19311936
// Internal wrapper around build errors at development

0 commit comments

Comments
 (0)