@@ -202,27 +202,18 @@ const writeEdgeFunction = async ({
202
202
edgeFunctionDefinition,
203
203
edgeFunctionRoot,
204
204
netlifyConfig,
205
- pageRegexMap,
206
- appPathRoutesManifest = { } ,
207
- nextConfig,
208
- cache,
205
+ functionName,
206
+ matchers = [ ] ,
207
+ middleware = false ,
209
208
} : {
210
209
edgeFunctionDefinition : EdgeFunctionDefinition
211
210
edgeFunctionRoot : string
212
211
netlifyConfig : NetlifyConfig
213
- pageRegexMap ?: Map < string , string >
214
- appPathRoutesManifest ?: Record < string , string >
215
- nextConfig : NextConfig
216
- cache ?: 'manual'
217
- } ) : Promise <
218
- Array < {
219
- function : string
220
- name : string
221
- pattern : string
222
- } >
223
- > => {
224
- const name = sanitizeName ( edgeFunctionDefinition . name )
225
- const edgeFunctionDir = join ( edgeFunctionRoot , name )
212
+ functionName : string
213
+ matchers ?: Array < MiddlewareMatcher >
214
+ middleware ?: boolean
215
+ } ) => {
216
+ const edgeFunctionDir = join ( edgeFunctionRoot , functionName )
226
217
227
218
const bundle = await getMiddlewareBundle ( {
228
219
edgeFunctionDefinition,
@@ -234,43 +225,52 @@ const writeEdgeFunction = async ({
234
225
235
226
await copyEdgeSourceFile ( {
236
227
edgeFunctionDir,
237
- file : ' runtime.ts',
228
+ file : middleware ? 'middleware-runtime.ts' : 'function- runtime.ts',
238
229
target : 'index.ts' ,
239
230
} )
240
231
241
- const matchers : EdgeFunctionDefinitionV2 [ 'matchers' ] = [ ]
232
+ if ( middleware ) {
233
+ // Functions don't have complex matchers, so we can rely on the Netlify matcher
234
+ await writeJson ( join ( edgeFunctionDir , 'matchers.json' ) , matchers )
235
+ }
236
+ }
242
237
238
+ const generateEdgeFunctionMiddlewareMatchers = ( {
239
+ edgeFunctionDefinition,
240
+ nextConfig,
241
+ } : {
242
+ edgeFunctionDefinition : EdgeFunctionDefinition
243
+ edgeFunctionRoot : string
244
+ nextConfig : NextConfig
245
+ cache ?: 'manual'
246
+ } ) : Array < MiddlewareMatcher > => {
243
247
// The v1 middleware manifest has a single regexp, but the v2 has an array of matchers
244
248
if ( 'regexp' in edgeFunctionDefinition ) {
245
- matchers . push ( { regexp : edgeFunctionDefinition . regexp } )
246
- } else if ( nextConfig . i18n ) {
247
- matchers . push (
248
- ...edgeFunctionDefinition . matchers . map ( ( matcher ) => ( {
249
- ...matcher ,
250
- regexp : makeLocaleOptional ( matcher . regexp ) ,
251
- } ) ) ,
252
- )
253
- } else {
254
- matchers . push ( ...edgeFunctionDefinition . matchers )
249
+ return [ { regexp : edgeFunctionDefinition . regexp } ]
255
250
}
256
-
257
- // If the EF matches a page, it's an app dir page so needs a matcher too
258
- // The object will be empty if appDir isn't enabled in the Next config
259
- if ( pageRegexMap && edgeFunctionDefinition . page in appPathRoutesManifest ) {
260
- const regexp = pageRegexMap . get ( appPathRoutesManifest [ edgeFunctionDefinition . page ] )
261
- if ( regexp ) {
262
- matchers . push ( { regexp } )
263
- }
251
+ if ( nextConfig . i18n ) {
252
+ return edgeFunctionDefinition . matchers . map ( ( matcher ) => ( {
253
+ ...matcher ,
254
+ regexp : makeLocaleOptional ( matcher . regexp ) ,
255
+ } ) )
264
256
}
257
+ return edgeFunctionDefinition . matchers
258
+ }
265
259
266
- await writeJson ( join ( edgeFunctionDir , 'matchers.json' ) , matchers )
267
-
268
- // We add a defintion for each matching path
269
- return matchers . map ( ( matcher ) => {
270
- const pattern = transformCaptureGroups ( stripLookahead ( matcher . regexp ) )
271
- return { function : name , pattern, name : edgeFunctionDefinition . name , cache }
272
- } )
260
+ const middlewareMatcherToEdgeFunctionDefinition = (
261
+ matcher : MiddlewareMatcher ,
262
+ name : string ,
263
+ cache ?: 'manual' ,
264
+ ) : {
265
+ function : string
266
+ name ?: string
267
+ pattern : string
268
+ cache ?: 'manual'
269
+ } => {
270
+ const pattern = transformCaptureGroups ( stripLookahead ( matcher . regexp ) )
271
+ return { function : name , pattern, name, cache }
273
272
}
273
+
274
274
export const cleanupEdgeFunctions = ( {
275
275
INTERNAL_EDGE_FUNCTIONS_SRC = '.netlify/edge-functions' ,
276
276
} : NetlifyPluginConstants ) => emptyDir ( INTERNAL_EDGE_FUNCTIONS_SRC )
@@ -348,9 +348,28 @@ export const writeRscDataEdgeFunction = async ({
348
348
]
349
349
}
350
350
351
+ const getEdgeFunctionPatternForPage = ( {
352
+ edgeFunctionDefinition,
353
+ pageRegexMap,
354
+ appPathRoutesManifest,
355
+ } : {
356
+ edgeFunctionDefinition : EdgeFunctionDefinitionV2
357
+ pageRegexMap : Map < string , string >
358
+ appPathRoutesManifest ?: Record < string , string >
359
+ } ) : string => {
360
+ // We don't just use the matcher from the edge function definition, because it doesn't handle trailing slashes
361
+
362
+ // appDir functions have a name that _isn't_ the route name, but rather the route with `/page` appended
363
+ const regexp = pageRegexMap . get ( appPathRoutesManifest ?. [ edgeFunctionDefinition . page ] ?? edgeFunctionDefinition . page )
364
+ // If we need to fall back to the matcher, we need to add an optional trailing slash
365
+ return regexp ?? edgeFunctionDefinition . matchers [ 0 ] . regexp . replace ( / ( [ ^ / ] ) \$ $ / , '$1/?$' )
366
+ }
367
+
351
368
/**
352
369
* Writes Edge Functions for the Next middleware
353
370
*/
371
+
372
+ // eslint-disable-next-line max-lines-per-function
354
373
export const writeEdgeFunctions = async ( {
355
374
netlifyConfig,
356
375
routesManifest,
@@ -415,16 +434,25 @@ export const writeEdgeFunctions = async ({
415
434
for ( const middleware of middlewareManifest . sortedMiddleware ) {
416
435
usesEdge = true
417
436
const edgeFunctionDefinition = middlewareManifest . middleware [ middleware ]
418
- const functionDefinitions = await writeEdgeFunction ( {
437
+ const functionName = sanitizeName ( edgeFunctionDefinition . name )
438
+ const matchers = generateEdgeFunctionMiddlewareMatchers ( {
419
439
edgeFunctionDefinition,
420
440
edgeFunctionRoot,
421
- netlifyConfig,
422
441
nextConfig,
423
442
} )
424
- manifest . functions . push ( ...functionDefinitions )
443
+ await writeEdgeFunction ( {
444
+ edgeFunctionDefinition,
445
+ edgeFunctionRoot,
446
+ netlifyConfig,
447
+ functionName,
448
+ matchers,
449
+ middleware : true ,
450
+ } )
451
+
452
+ manifest . functions . push (
453
+ ...matchers . map ( ( matcher ) => middlewareMatcherToEdgeFunctionDefinition ( matcher , functionName ) ) ,
454
+ )
425
455
}
426
- // Older versions of the manifest format don't have the functions field
427
- // No, the version field was not incremented
428
456
if ( typeof middlewareManifest . functions === 'object' ) {
429
457
// When using the app dir, we also need to check if the EF matches a page
430
458
const appPathRoutesManifest = await loadAppPathRoutesManifest ( netlifyConfig )
@@ -438,17 +466,25 @@ export const writeEdgeFunctions = async ({
438
466
439
467
for ( const edgeFunctionDefinition of Object . values ( middlewareManifest . functions ) ) {
440
468
usesEdge = true
441
- const functionDefinitions = await writeEdgeFunction ( {
469
+ const functionName = sanitizeName ( edgeFunctionDefinition . name )
470
+ await writeEdgeFunction ( {
442
471
edgeFunctionDefinition,
443
472
edgeFunctionRoot,
444
473
netlifyConfig,
474
+ functionName,
475
+ } )
476
+ const pattern = getEdgeFunctionPatternForPage ( {
477
+ edgeFunctionDefinition,
445
478
pageRegexMap,
446
479
appPathRoutesManifest,
447
- nextConfig,
480
+ } )
481
+ manifest . functions . push ( {
482
+ function : functionName ,
483
+ name : edgeFunctionDefinition . name ,
484
+ pattern,
448
485
// cache: "manual" is currently experimental, so we restrict it to sites that use experimental appDir
449
486
cache : usesAppDir ? 'manual' : undefined ,
450
487
} )
451
- manifest . functions . push ( ...functionDefinitions )
452
488
}
453
489
}
454
490
if ( usesEdge ) {
0 commit comments