Skip to content

Commit ebb839d

Browse files
committed
more ntl serve compat + some routing adjustments
1 parent 268c79c commit ebb839d

File tree

3 files changed

+120
-80
lines changed

3 files changed

+120
-80
lines changed

src/adapter/build/routing.ts

Lines changed: 89 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ export function convertRedirectToRoutingRule(
143143
OnBuildCompleteContext['routes']['redirects'][number],
144144
'source' | 'destination' | 'priority'
145145
>,
146-
description?: string,
146+
description: string,
147147
): RoutingRuleRedirect {
148148
const { sourceRegexString, segments } = sourceToRegex(redirect.source)
149149

@@ -191,75 +191,79 @@ export async function generateRoutingRules(
191191
}
192192
}
193193

194-
const normalizeNextData: RoutingRuleRewrite[] = [
195-
{
196-
description: 'Normalize _next/data',
197-
match: {
198-
path: `^${nextAdapterContext.config.basePath}/_next/data/${await netlifyAdapterContext.getBuildId()}/(.*)\\.json`,
199-
has: [
200-
{
201-
type: 'header',
202-
key: 'x-nextjs-data',
194+
const normalizeNextData: RoutingRuleRewrite[] = shouldDenormalizeJsonDataForMiddleware
195+
? [
196+
{
197+
description: 'Normalize _next/data',
198+
match: {
199+
path: `^${nextAdapterContext.config.basePath}/_next/data/${await netlifyAdapterContext.getBuildId()}/(.*)\\.json`,
200+
has: [
201+
{
202+
type: 'header',
203+
key: 'x-nextjs-data',
204+
},
205+
],
203206
},
204-
],
205-
},
206-
apply: {
207-
type: 'rewrite',
208-
destination: `${nextAdapterContext.config.basePath}/$1${nextAdapterContext.config.trailingSlash ? '/' : ''}`,
209-
},
210-
},
211-
{
212-
description: 'Fix _next/data index normalization',
213-
match: {
214-
path: `^${nextAdapterContext.config.basePath}/index(?:/)?`,
215-
has: [
216-
{
217-
type: 'header',
218-
key: 'x-nextjs-data',
207+
apply: {
208+
type: 'rewrite',
209+
destination: `${nextAdapterContext.config.basePath}/$1${nextAdapterContext.config.trailingSlash ? '/' : ''}`,
219210
},
220-
],
221-
},
222-
apply: {
223-
type: 'rewrite',
224-
destination: `${nextAdapterContext.config.basePath}/`,
225-
},
226-
},
227-
]
228-
229-
const denormalizeNextData: RoutingRuleRewrite[] = [
230-
{
231-
description: 'Fix _next/data index denormalization',
232-
match: {
233-
path: `^${nextAdapterContext.config.basePath}/$`,
234-
has: [
235-
{
236-
type: 'header',
237-
key: 'x-nextjs-data',
211+
},
212+
{
213+
description: 'Fix _next/data index normalization',
214+
match: {
215+
path: `^${nextAdapterContext.config.basePath}/index(?:/)?`,
216+
has: [
217+
{
218+
type: 'header',
219+
key: 'x-nextjs-data',
220+
},
221+
],
238222
},
239-
],
240-
},
241-
apply: {
242-
type: 'rewrite',
243-
destination: `${nextAdapterContext.config.basePath}/index`,
244-
},
245-
},
246-
{
247-
description: 'Denormalize _next/data',
248-
match: {
249-
path: `^${nextAdapterContext.config.basePath}/((?!_next/)(?:.*[^/]|.*))/?$`,
250-
has: [
251-
{
252-
type: 'header',
253-
key: 'x-nextjs-data',
223+
apply: {
224+
type: 'rewrite',
225+
destination: `${nextAdapterContext.config.basePath}/`,
254226
},
255-
],
256-
},
257-
apply: {
258-
type: 'rewrite',
259-
destination: `${nextAdapterContext.config.basePath}/_next/data/${await netlifyAdapterContext.getBuildId()}/$1.json`,
260-
},
261-
},
262-
]
227+
},
228+
]
229+
: []
230+
231+
const denormalizeNextData: RoutingRuleRewrite[] = shouldDenormalizeJsonDataForMiddleware
232+
? [
233+
{
234+
description: 'Fix _next/data index denormalization',
235+
match: {
236+
path: `^${nextAdapterContext.config.basePath}/$`,
237+
has: [
238+
{
239+
type: 'header',
240+
key: 'x-nextjs-data',
241+
},
242+
],
243+
},
244+
apply: {
245+
type: 'rewrite',
246+
destination: `${nextAdapterContext.config.basePath}/index`,
247+
},
248+
},
249+
{
250+
description: 'Denormalize _next/data',
251+
match: {
252+
path: `^${nextAdapterContext.config.basePath}/((?!_next/)(?:.*[^/]|.*))/?$`,
253+
has: [
254+
{
255+
type: 'header',
256+
key: 'x-nextjs-data',
257+
},
258+
],
259+
},
260+
apply: {
261+
type: 'rewrite',
262+
destination: `${nextAdapterContext.config.basePath}/_next/data/${await netlifyAdapterContext.getBuildId()}/$1.json`,
263+
},
264+
},
265+
]
266+
: []
263267

264268
const routing: RoutingRule[] = [
265269
// order inherited from
@@ -278,7 +282,7 @@ export async function generateRoutingRules(
278282
// priority redirects includes trailing slash redirect
279283
...priorityRedirects, // originally: ...convertedPriorityRedirects,
280284

281-
...(hasPages ? normalizeNextData : []), // originally: // normalize _next/data if middleware + pages
285+
...normalizeNextData, // originally: // normalize _next/data if middleware + pages
282286

283287
// i18n prefixing routes
284288

@@ -288,7 +292,7 @@ export async function generateRoutingRules(
288292

289293
// server actions name meta routes
290294

291-
...(shouldDenormalizeJsonDataForMiddleware ? denormalizeNextData : []), // originally: // if skip middleware url normalize we denormalize _next/data if middleware + pages
295+
...denormalizeNextData, // originally: // if skip middleware url normalize we denormalize _next/data if middleware + pages
292296

293297
...(hasMiddleware
294298
? [
@@ -300,25 +304,32 @@ export async function generateRoutingRules(
300304
]
301305
: []),
302306

303-
...(shouldDenormalizeJsonDataForMiddleware ? normalizeNextData : []), // originally: // if skip middleware url normalize we normalize _next/data if middleware + pages
307+
...normalizeNextData, // originally: // if skip middleware url normalize we normalize _next/data if middleware + pages
304308

305309
// ...convertedRewrites.beforeFiles,
306310

307311
// add 404 handling if /404 or locale variants are requested literally
308312

309313
// add 500 handling if /500 or locale variants are requested literally
310314

311-
...(hasPages ? denormalizeNextData : []), // originally: // denormalize _next/data if middleware + pages
315+
...denormalizeNextData, // originally: // denormalize _next/data if middleware + pages
312316

313317
// segment prefetch request rewriting
314318

315319
// non-segment prefetch rsc request rewriting
316320

317321
// full rsc request rewriting
322+
{
323+
// originally: { handle: 'filesystem' },
324+
// this is no-op on its own, it's just marker to be able to run subset of routing rules
325+
description: "'filesystem' routing phase marker",
326+
routingPhase: 'filesystem',
327+
},
318328

319329
{
320330
// originally: { handle: 'filesystem' },
321-
description: 'Static assets or Functions',
331+
// this is to actual match on things 'filesystem' should match on
332+
description: 'Static assets or Functions (no dynamic paths for functions)',
322333
match: { type: 'static-asset-or-function' },
323334
},
324335

@@ -335,7 +346,7 @@ export async function generateRoutingRules(
335346
// ]
336347
// : []),
337348

338-
...(hasPages ? normalizeNextData : []), // originally: // normalize _next/data if middleware + pages
349+
...normalizeNextData, // originally: // normalize _next/data if middleware + pages
339350

340351
// normalize /index.rsc to just /
341352

@@ -363,7 +374,12 @@ export async function generateRoutingRules(
363374

364375
// rewrite segment prefetch to prefetch/rsc
365376

366-
// { handle: 'rewrite' },
377+
{
378+
// originally: { handle: 'rewrite' },
379+
// this is no-op on its own, it's just marker to be able to run subset of routing rules
380+
description: "'rewrite' routing phase marker",
381+
routingPhase: 'rewrite',
382+
},
367383

368384
// denormalize _next/data if middleware + pages
369385

src/adapter/run/routing.ts

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import process from 'node:process'
2+
13
import type { Context } from '@netlify/edge-functions'
24

35
import type { NetlifyAdapterContext } from '../build/types.js'
@@ -6,7 +8,7 @@ type RoutingRuleBase = {
68
/**
79
* Human readable description of the rule (for debugging purposes only)
810
*/
9-
description?: string
11+
description: string
1012
}
1113

1214
type Match = {
@@ -48,7 +50,17 @@ export type RoutingRuleMatchPrimitive = RoutingRuleBase & {
4850
}
4951
}
5052

51-
export type RoutingRule = RoutingRuleRedirect | RoutingRuleRewrite | RoutingRuleMatchPrimitive
53+
export type RoutingPhase = 'filesystem' | 'rewrite'
54+
55+
export type RoutingPhaseRule = RoutingRuleBase & {
56+
routingPhase: RoutingPhase
57+
}
58+
59+
export type RoutingRule =
60+
| RoutingRuleRedirect
61+
| RoutingRuleRewrite
62+
| RoutingPhaseRule
63+
| RoutingRuleMatchPrimitive
5264

5365
export function testRedirectRewriteRule(rule: RoutingRuleRedirect, request: Request) {
5466
const sourceRegexp = new RegExp(rule.match.path)
@@ -60,6 +72,8 @@ export function testRedirectRewriteRule(rule: RoutingRuleRedirect, request: Requ
6072
return { matched: false }
6173
}
6274

75+
let requestCounter = 0
76+
6377
export async function runNextRouting(
6478
request: Request,
6579
context: Context,
@@ -71,7 +85,12 @@ export async function runNextRouting(
7185
return
7286
}
7387

74-
const prefix = `[${Date.now()}]`
88+
const prefix = `[${
89+
request.headers.get('x-nf-request-id') ??
90+
// for ntl serve, we use a combination of timestamp and pid to have a unique id per request as we don't have x-nf-request-id header then
91+
// eslint-disable-next-line no-plusplus
92+
`${Date.now()} - #${process.pid}:${++requestCounter}`
93+
}]`
7594

7695
console.log(prefix, 'Incoming request for routing:', request.url)
7796

@@ -86,16 +105,19 @@ export async function runNextRouting(
86105
const { pathname } = currentURL
87106

88107
if ('type' in rule.match) {
108+
const pathnameToMatch = pathname === '/' ? '/index' : pathname
109+
89110
if (rule.match.type === 'static-asset-or-function') {
90111
let matchedType: 'static-asset' | 'function' | null = null
91-
if (outputs.staticAssets.includes(pathname)) {
112+
113+
if (outputs.staticAssets.includes(pathnameToMatch)) {
92114
matchedType = 'static-asset'
93-
} else if (outputs.endpoints.includes(pathname)) {
115+
} else if (outputs.endpoints.includes(pathnameToMatch)) {
94116
matchedType = 'function'
95117
}
96118

97119
if (matchedType) {
98-
console.log(prefix, 'Matched static asset:', pathname)
120+
console.log(prefix, `Matched static asset or function (${matchedType}):`)
99121
maybeResponse = await context.next(currentRequest)
100122
}
101123
} else if (rule.match.type === 'image-cdn' && pathname.startsWith('/.netlify/image/')) {
@@ -141,6 +163,8 @@ export async function runNextRouting(
141163
}
142164

143165
if (maybeResponse) {
166+
// for debugging add log prefixes to response headers to make it easy to find logs for a given request
167+
maybeResponse.headers.set('x-ntl-log-prefix', prefix)
144168
console.log(prefix, 'Serving response', maybeResponse.status)
145169
return maybeResponse
146170
}

src/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,6 @@ export const onEnd = async (options: NetlifyPluginOptions) => {
129129
}
130130

131131
await tracer.withActiveSpan('onEnd', async () => {
132-
await unpublishStaticDir(new PluginContext(options))
132+
// await unpublishStaticDir(new PluginContext(options))
133133
})
134134
}

0 commit comments

Comments
 (0)