Skip to content

Commit e633fd9

Browse files
authored
Refactor to share handler logic in route-module (#79106)
This pulls the logic added in `templates/pages-api` that is needed to support the `handler` interface into the `route-module` interface so that it can shared with the other templates as the `handler` interface is added for them as well. Validated against deploy tests here: https://github.com/vercel/vercel/actions/runs/14982451661/job/42089544277?pr=13326
1 parent 59d8bce commit e633fd9

File tree

12 files changed

+214
-138
lines changed

12 files changed

+214
-138
lines changed

packages/next/src/build/templates/app-page.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,4 +48,5 @@ export const routeModule = new AppPageRouteModule({
4848
userland: {
4949
loaderTree: tree,
5050
},
51+
distDir: process.env.__NEXT_RELATIVE_DIST_DIR || '',
5152
})

packages/next/src/build/templates/app-route.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ const routeModule = new AppRouteRouteModule({
2424
filename: 'VAR_DEFINITION_FILENAME',
2525
bundlePath: 'VAR_DEFINITION_BUNDLE_PATH',
2626
},
27+
distDir: process.env.__NEXT_RELATIVE_DIST_DIR || '',
2728
resolvedPagePath: 'VAR_RESOLVED_PAGE_PATH',
2829
nextConfigOutput,
2930
userland,

packages/next/src/build/templates/pages-api.ts

Lines changed: 7 additions & 126 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,5 @@
11
import type { NextApiResponse } from '../../types'
22
import type { IncomingMessage, ServerResponse } from 'node:http'
3-
import type { PrerenderManifest } from '..'
4-
import type { DevRoutesManifest } from '../../server/lib/router-utils/setup-dev-bundler'
5-
import type { InstrumentationOnRequestError } from '../../server/instrumentation/types'
63

74
import { sendError } from '../../server/api-utils'
85
import { RouteKind } from '../../server/route-kind'
@@ -15,26 +12,6 @@ import { hoist } from './helpers'
1512
import * as userland from 'VAR_USERLAND'
1613
import { getTracer, SpanKind } from '../../server/lib/trace/tracer'
1714
import { BaseServerSpan } from '../../server/lib/trace/constants'
18-
import {
19-
ensureInstrumentationRegistered,
20-
instrumentationOnRequestError,
21-
} from '../../server/lib/router-utils/instrumentation-globals.external'
22-
import { getUtils } from '../../server/server-utils'
23-
import { PRERENDER_MANIFEST, ROUTES_MANIFEST } from '../../api/constants'
24-
import { isDynamicRoute } from '../../shared/lib/router/utils'
25-
import {
26-
RouterServerContextSymbol,
27-
routerServerGlobal,
28-
} from '../../server/lib/router-utils/router-server-context'
29-
import { removePathPrefix } from '../../shared/lib/router/utils/remove-path-prefix'
30-
import {
31-
normalizeLocalePath,
32-
type PathLocale,
33-
} from '../../shared/lib/i18n/normalize-locale-path'
34-
import { loadManifestFromRelativePath } from '../../server/load-manifest.external'
35-
import { getHostname } from '../../shared/lib/get-hostname'
36-
import { detectDomainLocale } from '../../shared/lib/i18n/detect-domain-locale'
37-
import { parseReqUrl } from '../../lib/url'
3815

3916
// Re-export the handler (should be the default export).
4017
export default hoist(userland, 'default')
@@ -53,6 +30,7 @@ const routeModule = new PagesAPIRouteModule({
5330
filename: '',
5431
},
5532
userland,
33+
distDir: process.env.__NEXT_RELATIVE_DIST_DIR || '',
5634
})
5735

5836
export async function handler(
@@ -62,23 +40,6 @@ export async function handler(
6240
waitUntil?: (prom: Promise<void>) => void
6341
}
6442
): Promise<void> {
65-
const projectDir =
66-
routerServerGlobal[RouterServerContextSymbol]?.dir || process.cwd()
67-
const distDir = process.env.__NEXT_RELATIVE_DIST_DIR || ''
68-
const isDev = process.env.NODE_ENV === 'development'
69-
70-
const [routesManifest, prerenderManifest] = await Promise.all([
71-
loadManifestFromRelativePath<DevRoutesManifest>(
72-
projectDir,
73-
distDir,
74-
ROUTES_MANIFEST
75-
),
76-
loadManifestFromRelativePath<PrerenderManifest>(
77-
projectDir,
78-
distDir,
79-
PRERENDER_MANIFEST
80-
),
81-
])
8243
let srcPage = 'VAR_DEFINITION_PAGE'
8344

8445
// turbopack doesn't normalize `/index` in the page name
@@ -87,95 +48,16 @@ export async function handler(
8748
srcPage = srcPage.replace(/\/index$/, '')
8849
}
8950

90-
// We need to parse dynamic route params
91-
// and do URL normalization here.
92-
// TODO: move this into server-utils for re-use
93-
const { basePath, i18n, rewrites } = routesManifest
94-
95-
if (basePath) {
96-
req.url = removePathPrefix(req.url || '/', basePath)
97-
}
98-
99-
let localeResult: PathLocale | undefined
100-
101-
if (i18n) {
102-
const urlParts = (req.url || '/').split('?')
103-
localeResult = normalizeLocalePath(urlParts[0] || '/', i18n.locales)
104-
105-
if (localeResult.detectedLocale) {
106-
req.url = `${localeResult.pathname}${
107-
urlParts[1] ? `?${urlParts[1]}` : ''
108-
}`
109-
}
110-
}
111-
112-
const parsedUrl = parseReqUrl(req.url || '/')
51+
const prepareResult = await routeModule.prepare(req, srcPage)
11352

114-
if (!parsedUrl) {
53+
if (!prepareResult) {
11554
res.statusCode = 400
11655
res.end('Bad Request')
11756
ctx.waitUntil?.(Promise.resolve())
11857
return
11958
}
12059

121-
const pageIsDynamic = isDynamicRoute(srcPage)
122-
123-
const serverUtils = getUtils({
124-
page: srcPage,
125-
i18n,
126-
basePath,
127-
rewrites,
128-
pageIsDynamic,
129-
trailingSlash: process.env.__NEXT_TRAILING_SLASH as any as boolean,
130-
caseSensitive: Boolean(routesManifest.caseSensitive),
131-
})
132-
133-
const domainLocale = detectDomainLocale(
134-
i18n?.domains,
135-
getHostname(parsedUrl, req.headers),
136-
localeResult?.detectedLocale
137-
)
138-
139-
const defaultLocale = domainLocale?.defaultLocale || i18n?.defaultLocale
140-
141-
// Ensure parsedUrl.pathname includes locale before processing
142-
// rewrites or they won't match correctly.
143-
if (defaultLocale && !localeResult?.detectedLocale) {
144-
parsedUrl.pathname = `/${defaultLocale}${parsedUrl.pathname}`
145-
}
146-
147-
const rewriteParamKeys = Object.keys(
148-
serverUtils.handleRewrites(req, parsedUrl)
149-
)
150-
serverUtils.normalizeCdnUrl(req, [
151-
...rewriteParamKeys,
152-
...Object.keys(serverUtils.defaultRouteRegex?.groups || {}),
153-
])
154-
155-
const params: Record<string, undefined | string | string[]> =
156-
serverUtils.dynamicRouteMatcher
157-
? serverUtils.dynamicRouteMatcher(
158-
localeResult?.pathname || parsedUrl.pathname || ''
159-
) || {}
160-
: {}
161-
162-
const query = {
163-
...parsedUrl.query,
164-
...params,
165-
}
166-
serverUtils.normalizeQueryParams(query)
167-
168-
if (pageIsDynamic) {
169-
const result = serverUtils.normalizeDynamicRouteParams(query, true)
170-
171-
if (result.hasValidParams) {
172-
Object.assign(query, result.params)
173-
}
174-
}
175-
176-
// ensure instrumentation is registered and pass
177-
// onRequestError below
178-
await ensureInstrumentationRegistered(projectDir, distDir)
60+
const { query, params, prerenderManifest } = prepareResult
17961

18062
try {
18163
const method = req.method || 'GET'
@@ -197,11 +79,10 @@ export async function handler(
19779
// doesn't need to load
19880
previewProps: prerenderManifest.preview,
19981
propagateError: false,
200-
dev: isDev,
82+
dev: routeModule.isDev,
20183
page: 'VAR_DEFINITION_PAGE',
20284

203-
onError: (...args: Parameters<InstrumentationOnRequestError>) =>
204-
instrumentationOnRequestError(projectDir, distDir, ...args),
85+
onError: routeModule.instrumentationOnRequestError.bind(routeModule),
20586
})
20687
.finally(() => {
20788
if (!span) return
@@ -266,7 +147,7 @@ export async function handler(
266147
}
267148
} catch (err) {
268149
// we re-throw in dev to show the error overlay
269-
if (isDev) {
150+
if (routeModule.isDev) {
270151
throw err
271152
}
272153
// this is technically an invariant as error handling

packages/next/src/build/templates/pages.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ export const routeModule = new PagesRouteModule({
5151
bundlePath: '',
5252
filename: '',
5353
},
54+
distDir: process.env.__NEXT_RELATIVE_DIST_DIR || '',
5455
components: {
5556
// default export might not exist when optimized for data only
5657
App: app.default,

packages/next/src/build/webpack/loaders/next-edge-ssr-loader/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,8 @@ function getRouteModuleOptions(page: string) {
5555
bundlePath: '',
5656
filename: '',
5757
},
58+
// edge runtime doesn't read from distDir
59+
distDir: '',
5860
}
5961

6062
return options

packages/next/src/server/base-server.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ import RenderResult from './render-result'
8484
import { removeTrailingSlash } from '../shared/lib/router/utils/remove-trailing-slash'
8585
import { denormalizePagePath } from '../shared/lib/page-path/denormalize-page-path'
8686
import * as Log from '../build/output/log'
87-
import { getPreviouslyRevalidatedTags, getUtils } from './server-utils'
87+
import { getPreviouslyRevalidatedTags, getServerUtils } from './server-utils'
8888
import isError, { getProperError } from '../lib/is-error'
8989
import {
9090
addRequestMeta,
@@ -1191,7 +1191,7 @@ export default abstract class Server<
11911191
matchedPath = localeAnalysisResult.pathname
11921192
}
11931193

1194-
const utils = getUtils({
1194+
const utils = getServerUtils({
11951195
pageIsDynamic,
11961196
page: srcPathname,
11971197
i18n: this.nextConfig.i18n,

packages/next/src/server/route-modules/app-route/module.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -215,10 +215,11 @@ export class AppRouteRouteModule extends RouteModule<
215215
constructor({
216216
userland,
217217
definition,
218+
distDir,
218219
resolvedPagePath,
219220
nextConfigOutput,
220221
}: AppRouteRouteModuleOptions) {
221-
super({ userland, definition })
222+
super({ userland, definition, distDir })
222223

223224
this.resolvedPagePath = resolvedPagePath
224225
this.nextConfigOutput = nextConfigOutput

packages/next/src/server/route-modules/pages/builtin/_error.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ export const routeModule = new PagesRouteModule({
1515
filename: '',
1616
bundlePath: '',
1717
},
18+
distDir: process.env.__NEXT_RELATIVE_DIST_DIR || '',
1819
components: {
1920
App,
2021
Document,

0 commit comments

Comments
 (0)