Skip to content

Commit 5306df8

Browse files
jridgewellijjk
andauthored
Implement middleware support for Turbopack (#46397)
This implements middleware support for Turbopack's route resolver. In vercel/turborepo#3930, I'm updating the data that we pass to include a new `MiddlewareConfig`, which includes the files needed for invoking the edge function and the matchers extracted from the middleware's static `export config = {}`. ~~This needs to wait for vercel/turborepo#3930 to land first~~ Merged. Fixes https://linear.app/vercel/issue/WEB-624 --------- Co-authored-by: JJ Kasper <[email protected]>
1 parent b0b5cd8 commit 5306df8

File tree

2 files changed

+65
-6
lines changed

2 files changed

+65
-6
lines changed

packages/next/src/build/analysis/get-page-static-info.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ async function tryToReadFile(filePath: string, shouldThrow: boolean) {
140140
}
141141
}
142142

143-
function getMiddlewareMatchers(
143+
export function getMiddlewareMatchers(
144144
matcherOrMatchers: unknown,
145145
nextConfig: NextConfig
146146
): MiddlewareMatcher[] {

packages/next/src/server/lib/route-resolver.ts

Lines changed: 64 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,14 @@ import { RouteKind } from '../future/route-kind'
55
import { DefaultRouteMatcherManager } from '../future/route-matcher-managers/default-route-matcher-manager'
66
import { RouteMatch } from '../future/route-matches/route-match'
77
import type { PageChecker, Route } from '../router'
8+
import { getMiddlewareMatchers } from '../../build/analysis/get-page-static-info'
9+
import { getMiddlewareRouteMatcher } from '../../shared/lib/router/utils/middleware-route-matcher'
10+
import { join } from 'path'
811

12+
type MiddlewareConfig = {
13+
matcher: string[]
14+
files: string[]
15+
}
916
type RouteResult =
1017
| {
1118
type: 'rewrite'
@@ -48,7 +55,11 @@ class DevRouteMatcherManager extends DefaultRouteMatcherManager {
4855
}
4956
}
5057

51-
export async function makeResolver(dir: string, nextConfig: NextConfig) {
58+
export async function makeResolver(
59+
dir: string,
60+
nextConfig: NextConfig,
61+
middleware: MiddlewareConfig
62+
) {
5263
const url = require('url') as typeof import('url')
5364
const { default: Router } = require('../router') as typeof import('../router')
5465
const { getPathMatch } =
@@ -65,14 +76,57 @@ export async function makeResolver(dir: string, nextConfig: NextConfig) {
6576
const devServer = new DevServer({
6677
dir,
6778
conf: nextConfig,
79+
hostname: 'localhost',
80+
port: 3000,
6881
})
82+
6983
await devServer.matchers.reload()
7084

71-
// @ts-expect-error
72-
devServer.customRoutes = await loadCustomRoutes(nextConfig)
85+
if (middleware.files?.length) {
86+
// @ts-expect-error
87+
devServer.customRoutes = await loadCustomRoutes(nextConfig)
88+
89+
const matchers = middleware.matcher
90+
? getMiddlewareMatchers(middleware.matcher, nextConfig)
91+
: [{ regexp: '.*' }]
92+
// @ts-expect-error
93+
devServer.middleware = {
94+
page: '/',
95+
match: getMiddlewareRouteMatcher(matchers),
96+
matchers,
97+
}
98+
99+
type GetEdgeFunctionInfo =
100+
typeof DevServer['prototype']['getEdgeFunctionInfo']
101+
const getEdgeFunctionInfo = (
102+
original: GetEdgeFunctionInfo
103+
): GetEdgeFunctionInfo => {
104+
return (params: { page: string; middleware: boolean }) => {
105+
if (params.middleware) {
106+
return {
107+
name: 'middleware',
108+
paths: middleware.files.map((file) => join(process.cwd(), file)),
109+
env: [],
110+
wasm: [],
111+
assets: [],
112+
}
113+
}
114+
return original(params)
115+
}
116+
}
117+
// @ts-expect-error protected
118+
devServer.getEdgeFunctionInfo = getEdgeFunctionInfo(
119+
// @ts-expect-error protected
120+
devServer.getEdgeFunctionInfo.bind(devServer)
121+
)
122+
// @ts-expect-error protected
123+
devServer.hasMiddleware = () => true
124+
}
73125

74126
const routeResults = new WeakMap<any, string>()
75-
const routes = devServer.generateRoutes.bind(devServer)()
127+
const routes = devServer.generateRoutes()
128+
// @ts-expect-error protected
129+
const catchAllMiddleware = devServer.generateCatchAllMiddlewareRoute(true)
76130

77131
routes.matchers = new DevRouteMatcherManager(
78132
// @ts-expect-error internal method
@@ -81,6 +135,7 @@ export async function makeResolver(dir: string, nextConfig: NextConfig) {
81135

82136
const router = new Router({
83137
...routes,
138+
catchAllMiddleware,
84139
catchAllRoute: {
85140
match: getPathMatch('/:path*'),
86141
name: 'catchall route',
@@ -112,6 +167,7 @@ export async function makeResolver(dir: string, nextConfig: NextConfig) {
112167
route.type === 'redirect' ||
113168
route.type === 'header' ||
114169
route.name === 'catchall route' ||
170+
route.name === 'middleware catchall' ||
115171
route.name?.includes('check')
116172
return matches
117173
})
@@ -122,9 +178,12 @@ export async function makeResolver(dir: string, nextConfig: NextConfig) {
122178
) {
123179
const req = new NodeNextRequest(_req)
124180
const res = new NodeNextResponse(_res)
181+
const parsedUrl = url.parse(req.url!, true)
182+
// @ts-expect-error protected
183+
devServer.attachRequestMeta(req, parsedUrl)
125184
;(req as any)._initUrl = req.url
126185

127-
await router.execute.bind(router)(req, res, url.parse(req.url!, true))
186+
await router.execute(req, res, parsedUrl)
128187

129188
if (!res.originalResponse.headersSent) {
130189
res.setHeader('x-nextjs-route-result', '1')

0 commit comments

Comments
 (0)