Skip to content

Commit

Permalink
fix the dynamic routing of middleware
Browse files Browse the repository at this point in the history
  • Loading branch information
nkzawa committed Jan 31, 2022
1 parent a410155 commit 9ffbf4a
Show file tree
Hide file tree
Showing 28 changed files with 626 additions and 92 deletions.
71 changes: 34 additions & 37 deletions packages/next/server/base-server.ts
Expand Up @@ -28,10 +28,9 @@ import {
TEMPORARY_REDIRECT_STATUS,
} from '../shared/lib/constants'
import {
getRouteMatcher,
getRouteRegex,
getSortedRoutes,
getRoutingItems,
isDynamicRoute,
RoutingItem,
} from '../shared/lib/router/utils'
import * as envConfig from '../shared/lib/runtime-config'
import { DecodeError, normalizeRepeatedSlashes } from '../shared/lib/utils'
Expand Down Expand Up @@ -64,12 +63,6 @@ export type FindComponentsResult = {
query: NextParsedUrlQuery
}

interface RoutingItem {
page: string
match: ReturnType<typeof getRouteMatcher>
ssr?: boolean
}

export interface Options {
/**
* Object containing the configuration next.config.js
Expand Down Expand Up @@ -165,7 +158,7 @@ export default abstract class Server {
protected dynamicRoutes?: DynamicRoutes
protected customRoutes: CustomRoutes
protected middlewareManifest?: MiddlewareManifest
protected middleware?: RoutingItem[]
protected allRoutes?: RoutingItem[]
public readonly hostname?: string
public readonly port?: number

Expand All @@ -188,14 +181,6 @@ export default abstract class Server {
fallback: Route[]
}
protected abstract getFilesystemPaths(): Set<string>
protected abstract getMiddleware(): {
match: (pathname: string | null | undefined) =>
| false
| {
[paramName: string]: string | string[]
}
page: string
}[]
protected abstract findPageComponents(
pathname: string,
query?: NextParsedUrlQuery,
Expand Down Expand Up @@ -542,7 +527,7 @@ export default abstract class Server {
if (url.locale?.path.detectedLocale) {
req.url = formatUrl(url)
addRequestMeta(req, '__nextStrippedLocale', true)
if (url.pathname === '/api' || url.pathname.startsWith('/api/')) {
if (isApiRoute(url.pathname)) {
return this.render404(req, res, parsedUrl)
}
}
Expand Down Expand Up @@ -792,7 +777,7 @@ export default abstract class Server {
}
}

if (pathname === '/api' || pathname.startsWith('/api/')) {
if (isApiRoute(pathname)) {
delete query._nextBubbleNoFallback

const handled = await this.handleApiRequest(req, res, pathname, query)
Expand Down Expand Up @@ -821,10 +806,8 @@ export default abstract class Server {
const { useFileSystemPublicRoutes } = this.nextConfig

if (useFileSystemPublicRoutes) {
this.allRoutes = this.getAllRoutes()
this.dynamicRoutes = this.getDynamicRoutes()
if (!this.minimalMode) {
this.middleware = this.getMiddleware()
}
}

return {
Expand Down Expand Up @@ -910,24 +893,34 @@ export default abstract class Server {
return this.runApi(req, res, query, params, page, builtPagePath)
}

protected getAllRoutes(): RoutingItem[] {
const pages = Object.keys(this.pagesManifest!).map(
(page) =>
normalizeLocalePath(page, this.nextConfig.i18n?.locales).pathname
)
const middlewareMap = this.minimalMode
? {}
: this.middlewareManifest?.middleware || {}
const middleware = Object.keys(middlewareMap).map((page) => ({
page,
ssr: !MIDDLEWARE_ROUTE.test(middlewareMap[page].name),
}))
return [...getRoutingItems(pages, middleware)]
}

protected getDynamicRoutes(): Array<RoutingItem> {
const addedPages = new Set<string>()

return getSortedRoutes(
Object.keys(this.pagesManifest!).map(
(page) =>
normalizeLocalePath(page, this.nextConfig.i18n?.locales).pathname
return this.allRoutes!.filter((item) => {
if (
item.isMiddleware ||
addedPages.has(item.page) ||
!isDynamicRoute(item.page)
)
)
.map((page) => {
if (addedPages.has(page) || !isDynamicRoute(page)) return null
addedPages.add(page)
return {
page,
match: getRouteMatcher(getRouteRegex(page)),
}
})
.filter((item): item is RoutingItem => Boolean(item))
return false
addedPages.add(item.page)
return true
})
}

protected async run(
Expand Down Expand Up @@ -1824,6 +1817,10 @@ export function prepareServerlessUrl(

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

export function isApiRoute(pathname: string) {
return pathname === '/api' || pathname.startsWith('/api/')
}

class NoFallbackError extends Error {}

// Internal wrapper around build errors at development
Expand Down
53 changes: 25 additions & 28 deletions packages/next/server/dev/next-dev-server.ts
Expand Up @@ -32,10 +32,9 @@ import {
DEV_MIDDLEWARE_MANIFEST,
} from '../../shared/lib/constants'
import {
getRouteMatcher,
getRouteRegex,
getSortedRoutes,
getRoutingItems,
isDynamicRoute,
RoutingItem,
} from '../../shared/lib/router/utils'
import Server, { WrappedBuildError } from '../next-server'
import { normalizePagePath } from '../normalize-page-path'
Expand All @@ -56,7 +55,6 @@ import {
} from 'next/dist/compiled/@next/react-dev-overlay/middleware'
import * as Log from '../../build/output/log'
import isError, { getProperError } from '../../lib/is-error'
import { getMiddlewareRegex } from '../../shared/lib/router/utils/get-middleware-regex'
import { isCustomErrorPage, isReservedPage } from '../../build/utils'
import {
BaseNextRequest,
Expand Down Expand Up @@ -94,6 +92,7 @@ export default class DevServer extends Server {
private isCustomServer: boolean
protected sortedRoutes?: string[]
private addedUpgradeListener = false
private middleware?: RoutingItem[]

protected staticPathsWorker?: { [key: string]: any } & {
loadStaticPaths: typeof import('./static-paths-worker').loadStaticPaths
Expand Down Expand Up @@ -262,7 +261,6 @@ export default class DevServer extends Server {
const routedMiddleware = []
const routedPages = []
const knownFiles = wp.getTimeInfoEntries()
const ssrMiddleware = new Set<string>()
const isWebServerRuntime =
this.nextConfig.experimental.concurrentFeatures
const hasServerComponents =
Expand All @@ -274,11 +272,13 @@ export default class DevServer extends Server {
}

if (regexMiddleware.test(fileName)) {
routedMiddleware.push(
`/${relative(pagesDir!, fileName).replace(/\\+/g, '/')}`
.replace(/^\/+/g, '/')
.replace(regexMiddleware, '/')
)
routedMiddleware.push({
page:
`/${relative(pagesDir!, fileName).replace(/\\+/g, '/')}`
.replace(/^\/+/g, '/')
.replace(regexMiddleware, '') || '/',
ssr: false,
})
continue
}

Expand All @@ -288,32 +288,27 @@ export default class DevServer extends Server {
pageName = pageName.replace(/\/index$/, '') || '/'

if (hasServerComponents && pageName.endsWith('.server')) {
routedMiddleware.push(pageName)
ssrMiddleware.add(pageName)
routedMiddleware.push({ page: pageName, ssr: true })
} else if (
isWebServerRuntime &&
!(isReservedPage(pageName) || isCustomErrorPage(pageName))
) {
routedMiddleware.push(pageName)
ssrMiddleware.add(pageName)
routedMiddleware.push({ page: pageName, ssr: true })
}

routedPages.push(pageName)
}

this.middleware = getSortedRoutes(routedMiddleware).map((page) => ({
match: getRouteMatcher(
getMiddlewareRegex(page, !ssrMiddleware.has(page))
),
page,
ssr: ssrMiddleware.has(page),
}))
this.allRoutes = [...getRoutingItems(routedPages, routedMiddleware)]
this.middleware = this.allRoutes.filter((r) => r.isMiddleware)

try {
// we serve a separate manifest with all pages for the client in
// dev mode so that we can match a page after a rewrite on the client
// before it has been built and is populated in the _buildManifest
const sortedRoutes = getSortedRoutes(routedPages)
const sortedRoutes = this.allRoutes
.filter((r) => !r.isMiddleware)
.map((r) => r.page)

if (
!this.sortedRoutes?.every((val, idx) => val === sortedRoutes[idx])
Expand All @@ -323,12 +318,9 @@ export default class DevServer extends Server {
}
this.sortedRoutes = sortedRoutes

this.dynamicRoutes = this.sortedRoutes
.filter(isDynamicRoute)
.map((page) => ({
page,
match: getRouteMatcher(getRouteRegex(page)),
}))
this.dynamicRoutes = this.allRoutes.filter(
(r) => !r.isMiddleware && isDynamicRoute(r.page)
)

this.router.setDynamicRoutes(this.dynamicRoutes)

Expand Down Expand Up @@ -528,6 +520,7 @@ export default class DevServer extends Server {
response: BaseNextResponse
parsedUrl: ParsedNextUrl
parsed: UrlWithParsedQuery
middleware: RoutingItem[]
}): Promise<FetchEventResult | null> {
try {
const result = await super.runMiddleware({
Expand Down Expand Up @@ -827,6 +820,10 @@ export default class DevServer extends Server {
return []
}

protected getAllRoutes(): RoutingItem[] {
return []
}

// In development dynamic routes cannot be known ahead of time
protected getDynamicRoutes(): never[] {
return []
Expand Down

0 comments on commit 9ffbf4a

Please sign in to comment.