1- import { cp , mkdir , readFile , rm , writeFile } from 'node:fs/promises'
2- import { dirname , join } from 'node:path'
1+ import { cp , mkdir , readdir , readFile , rm , writeFile } from 'node:fs/promises'
2+ import { dirname , join , parse as parsePath } from 'node:path'
33
44import type { Manifest , ManifestFunction } from '@netlify/edge-functions'
55import { glob } from 'fast-glob'
@@ -8,9 +8,21 @@ import { pathToRegexp } from 'path-to-regexp'
88
99import { EDGE_HANDLER_NAME , PluginContext } from '../plugin-context.js'
1010
11+ type ManifestFunctionWithGenerator = ManifestFunction & { generator ?: string }
12+
13+ const getEdgeManifestPath = ( ctx : PluginContext ) => join ( ctx . edgeFunctionsDir , 'manifest.json' )
14+
1115const writeEdgeManifest = async ( ctx : PluginContext , manifest : Manifest ) => {
1216 await mkdir ( ctx . edgeFunctionsDir , { recursive : true } )
13- await writeFile ( join ( ctx . edgeFunctionsDir , 'manifest.json' ) , JSON . stringify ( manifest , null , 2 ) )
17+ await writeFile ( getEdgeManifestPath ( ctx ) , JSON . stringify ( manifest , null , 2 ) )
18+ }
19+
20+ const readEdgeManifest = async ( ctx : PluginContext ) => {
21+ try {
22+ return JSON . parse ( await readFile ( getEdgeManifestPath ( ctx ) , 'utf-8' ) ) as Manifest
23+ } catch {
24+ return null
25+ }
1426}
1527
1628const copyRuntime = async ( ctx : PluginContext , handlerDirectory : string ) : Promise < void > => {
@@ -145,7 +157,7 @@ const getHandlerName = ({ name }: Pick<NextDefinition, 'name'>): string =>
145157const buildHandlerDefinition = (
146158 ctx : PluginContext ,
147159 { name, matchers, page } : NextDefinition ,
148- ) : Array < ManifestFunction > => {
160+ ) : Array < ManifestFunctionWithGenerator > => {
149161 const fun = getHandlerName ( { name } )
150162 const funName = name . endsWith ( 'middleware' )
151163 ? 'Next.js Middleware Handler'
@@ -162,8 +174,35 @@ const buildHandlerDefinition = (
162174 } ) )
163175}
164176
177+ const clearStaleEdgeHandlers = async ( ctx : PluginContext ) => {
178+ const previousManifest = await readEdgeManifest ( ctx )
179+ if ( ! previousManifest ) {
180+ return [ ]
181+ }
182+
183+ const uniqueNextRuntimeFunctions = new Set < string > ( )
184+ const nonNextRuntimeFunctions : ManifestFunctionWithGenerator [ ] = [ ]
185+
186+ for ( const fn of previousManifest . functions as ManifestFunctionWithGenerator [ ] ) {
187+ if ( fn ?. generator ?. startsWith ( ctx . pluginName ) ) {
188+ uniqueNextRuntimeFunctions . add ( fn . function )
189+ } else {
190+ nonNextRuntimeFunctions . push ( fn )
191+ }
192+ }
193+
194+ for ( const fileOrDir of await readdir ( ctx . edgeFunctionsDir , { withFileTypes : true } ) ) {
195+ const nameWithoutExtension = parsePath ( fileOrDir . name ) . name
196+
197+ if ( uniqueNextRuntimeFunctions . has ( nameWithoutExtension ) ) {
198+ await rm ( join ( ctx . edgeFunctionsDir , fileOrDir . name ) , { recursive : true , force : true } )
199+ }
200+ }
201+ return nonNextRuntimeFunctions
202+ }
203+
165204export const createEdgeHandlers = async ( ctx : PluginContext ) => {
166- await rm ( ctx . edgeFunctionsDir , { recursive : true , force : true } )
205+ const nonNextRuntimeFunctions = await clearStaleEdgeHandlers ( ctx )
167206
168207 const nextManifest = await ctx . getMiddlewareManifest ( )
169208 const nextDefinitions = [
@@ -175,7 +214,7 @@ export const createEdgeHandlers = async (ctx: PluginContext) => {
175214 const netlifyDefinitions = nextDefinitions . flatMap ( ( def ) => buildHandlerDefinition ( ctx , def ) )
176215 const netlifyManifest : Manifest = {
177216 version : 1 ,
178- functions : netlifyDefinitions ,
217+ functions : [ ... nonNextRuntimeFunctions , ... netlifyDefinitions ] ,
179218 }
180219 await writeEdgeManifest ( ctx , netlifyManifest )
181220}
0 commit comments