Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 7195b1a

Browse files
committed
fix: don't delete functions generated by other build plugins
1 parent 4345795 commit 7195b1a

File tree

2 files changed

+92
-9
lines changed

2 files changed

+92
-9
lines changed

‎src/build/functions/edge.ts

Lines changed: 49 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
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,parseasparsePath } from 'node:path'
33

44
import type { Manifest, ManifestFunction } from '@netlify/edge-functions'
55
import { glob } from 'fast-glob'
@@ -8,9 +8,21 @@ import { pathToRegexp } from 'path-to-regexp'
88

99
import { 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+
1115
const 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

1628
const copyRuntime = async (ctx: PluginContext, handlerDirectory: string): Promise<void> => {
@@ -145,7 +157,7 @@ const getHandlerName = ({ name }: Pick<NextDefinition, 'name'>): string =>
145157
const 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,39 @@ 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+
if (uniqueNextRuntimeFunctions.size === 0) {
195+
return nonNextRuntimeFunctions
196+
}
197+
198+
for (const fileOrDir of await readdir(ctx.edgeFunctionsDir, { withFileTypes: true })) {
199+
const nameWithoutExtension = parsePath(fileOrDir.name).name
200+
201+
if (uniqueNextRuntimeFunctions.has(nameWithoutExtension)) {
202+
await rm(join(ctx.edgeFunctionsDir, fileOrDir.name), { recursive: true, force: true })
203+
}
204+
}
205+
return nonNextRuntimeFunctions
206+
}
207+
165208
export const createEdgeHandlers = async (ctx: PluginContext) => {
166-
awaitrm(ctx.edgeFunctionsDir,{recursive: true,force: true})
209+
constnonNextRuntimeFunctions=awaitclearStaleEdgeHandlers(ctx)
167210

168211
const nextManifest = await ctx.getMiddlewareManifest()
169212
const nextDefinitions = [
@@ -175,7 +218,7 @@ export const createEdgeHandlers = async (ctx: PluginContext) => {
175218
const netlifyDefinitions = nextDefinitions.flatMap((def) => buildHandlerDefinition(ctx, def))
176219
const netlifyManifest: Manifest = {
177220
version: 1,
178-
functions: netlifyDefinitions,
221+
functions: [...nonNextRuntimeFunctions, ...netlifyDefinitions],
179222
}
180223
await writeEdgeManifest(ctx, netlifyManifest)
181224
}

‎src/build/functions/server.ts

Lines changed: 43 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import { cp, mkdir, readFile, rm, writeFile } from 'node:fs/promises'
2-
import { join, relative } from 'node:path'
1+
import { cp, mkdir, readdir,readFile, rm, writeFile } from 'node:fs/promises'
2+
import { join, parseasparsePath,relative } from 'node:path'
33
import { join as posixJoin } from 'node:path/posix'
44

55
import { trace } from '@opentelemetry/api'
@@ -127,12 +127,52 @@ const writeHandlerFile = async (ctx: PluginContext) => {
127127
await writeFile(join(ctx.serverHandlerRootDir, `${SERVER_HANDLER_NAME}.mjs`), handler)
128128
}
129129

130+
const clearStaleServerHandlers = async (ctx: PluginContext) => {
131+
const potentialServerlessFunctionConfigFiles = await glob('**/*.json', {
132+
deep: 2,
133+
cwd: ctx.serverFunctionsDir,
134+
})
135+
136+
const toRemove = new Set<string>()
137+
138+
for (const potentialServerlessFunctionConfigFile of potentialServerlessFunctionConfigFiles) {
139+
try {
140+
const functionConfig = JSON.parse(
141+
await readFile(
142+
join(ctx.serverFunctionsDir, potentialServerlessFunctionConfigFile),
143+
'utf-8',
144+
),
145+
)
146+
147+
if (functionConfig?.config?.generator?.startsWith(ctx.pluginName)) {
148+
const parsedPath = parsePath(potentialServerlessFunctionConfigFile)
149+
150+
toRemove.add(parsedPath.dir || parsedPath.name)
151+
}
152+
} catch {
153+
// this might be malformatted json or json that doesn't represent function configuration
154+
// so we just skip it in case of errors
155+
}
156+
}
157+
158+
if (toRemove.size === 0) {
159+
return
160+
}
161+
162+
for (const fileOrDir of await readdir(ctx.serverFunctionsDir, { withFileTypes: true })) {
163+
const nameWithoutExtension = parsePath(fileOrDir.name).name
164+
165+
if (toRemove.has(nameWithoutExtension)) {
166+
await rm(join(ctx.serverFunctionsDir, fileOrDir.name), { recursive: true, force: true })
167+
}
168+
}
169+
}
130170
/**
131171
* Create a Netlify function to run the Next.js server
132172
*/
133173
export const createServerHandler = async (ctx: PluginContext) => {
134174
await tracer.withActiveSpan('createServerHandler', async () => {
135-
await rm(ctx.serverFunctionsDir,{recursive: true,force: true})
175+
await clearStaleServerHandlers(ctx)
136176
await mkdir(join(ctx.serverHandlerDir, '.netlify'), { recursive: true })
137177

138178
await copyNextServerCode(ctx)

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /