Skip to content

Commit 322da87

Browse files
committed
feat: make edge image opt in instead of opt out
1 parent 5b35a73 commit 322da87

File tree

2 files changed

+120
-95
lines changed

2 files changed

+120
-95
lines changed

packages/runtime/src/helpers/edge.ts

Lines changed: 104 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -358,121 +358,131 @@ export const writeEdgeFunctions = async ({
358358
await writeJSON(join(edgeFunctionRoot, 'edge-shared', 'nextConfig.json'), nextConfig)
359359
await copy(join(publish, 'prerender-manifest.json'), join(edgeFunctionRoot, 'edge-shared', 'prerender-manifest.json'))
360360

361-
if (
362-
!destr(process.env.NEXT_DISABLE_EDGE_IMAGES) &&
363-
!destr(process.env.NEXT_DISABLE_NETLIFY_EDGE) &&
364-
!destr(process.env.DISABLE_IPX)
365-
) {
366-
console.log(
367-
'Using Netlify Edge Functions for image format detection. Set env var "NEXT_DISABLE_EDGE_IMAGES=true" to disable.',
368-
)
369-
const edgeFunctionDir = join(edgeFunctionRoot, 'ipx')
370-
await ensureDir(edgeFunctionDir)
371-
await copyEdgeSourceFile({ edgeFunctionDir, file: 'ipx.ts', target: 'index.ts' })
372-
await copyFile(
373-
join('.netlify', 'functions-internal', '_ipx', 'imageconfig.json'),
374-
join(edgeFunctionDir, 'imageconfig.json'),
375-
)
376-
manifest.functions.push({
377-
function: 'ipx',
378-
name: 'next/image handler',
379-
path: '/_next/image*',
380-
})
361+
// early return if edge is disabled
362+
if (destr(process.env.NEXT_DISABLE_NETLIFY_EDGE)) {
363+
return
381364
}
382-
if (!destr(process.env.NEXT_DISABLE_NETLIFY_EDGE)) {
383-
const rscFunctions = await writeRscDataEdgeFunction({
384-
prerenderManifest: await loadPrerenderManifest(netlifyConfig),
385-
appPathRoutesManifest: await loadAppPathRoutesManifest(netlifyConfig),
386-
})
387365

388-
manifest.functions.push(...rscFunctions)
366+
const rscFunctions = await writeRscDataEdgeFunction({
367+
prerenderManifest: await loadPrerenderManifest(netlifyConfig),
368+
appPathRoutesManifest: await loadAppPathRoutesManifest(netlifyConfig),
369+
})
389370

390-
const middlewareManifest = await loadMiddlewareManifest(netlifyConfig)
391-
if (!middlewareManifest) {
392-
console.error("Couldn't find the middleware manifest")
393-
return
394-
}
371+
manifest.functions.push(...rscFunctions)
395372

396-
let usesEdge = false
373+
const middlewareManifest = await loadMiddlewareManifest(netlifyConfig)
374+
if (!middlewareManifest) {
375+
console.error("Couldn't find the middleware manifest")
376+
return
377+
}
378+
379+
let usesEdge = false
380+
381+
for (const middleware of middlewareManifest.sortedMiddleware) {
382+
usesEdge = true
383+
const edgeFunctionDefinition = middlewareManifest.middleware[middleware]
384+
const functionName = sanitizeName(edgeFunctionDefinition.name)
385+
const matchers = generateEdgeFunctionMiddlewareMatchers({
386+
edgeFunctionDefinition,
387+
edgeFunctionRoot,
388+
nextConfig,
389+
})
390+
await writeEdgeFunction({
391+
edgeFunctionDefinition,
392+
edgeFunctionRoot,
393+
netlifyConfig,
394+
functionName,
395+
matchers,
396+
middleware: true,
397+
})
397398

398-
for (const middleware of middlewareManifest.sortedMiddleware) {
399+
manifest.functions.push(
400+
...matchers.map((matcher) => middlewareMatcherToEdgeFunctionDefinition(matcher, functionName)),
401+
)
402+
}
403+
// Functions (i.e. not middleware, but edge SSR and API routes)
404+
if (typeof middlewareManifest.functions === 'object') {
405+
// When using the app dir, we also need to check if the EF matches a page
406+
const appPathRoutesManifest = await loadAppPathRoutesManifest(netlifyConfig)
407+
408+
// A map of all route pages to their page regex. This is used for pages dir and appDir.
409+
const pageRegexMap = new Map(
410+
[...(routesManifest.dynamicRoutes || []), ...(routesManifest.staticRoutes || [])].map((route) => [
411+
route.page,
412+
route.regex,
413+
]),
414+
)
415+
// Create a map of pages-dir routes to their data route regex (appDir uses the same route as the HTML)
416+
const dataRoutesMap = new Map(
417+
[...(routesManifest.dataRoutes || [])].map((route) => [route.page, route.dataRouteRegex]),
418+
)
419+
420+
for (const edgeFunctionDefinition of Object.values(middlewareManifest.functions)) {
399421
usesEdge = true
400-
const edgeFunctionDefinition = middlewareManifest.middleware[middleware]
401422
const functionName = sanitizeName(edgeFunctionDefinition.name)
402-
const matchers = generateEdgeFunctionMiddlewareMatchers({
403-
edgeFunctionDefinition,
404-
edgeFunctionRoot,
405-
nextConfig,
406-
})
407423
await writeEdgeFunction({
408424
edgeFunctionDefinition,
409425
edgeFunctionRoot,
410426
netlifyConfig,
411427
functionName,
412-
matchers,
413-
middleware: true,
414428
})
415-
416-
manifest.functions.push(
417-
...matchers.map((matcher) => middlewareMatcherToEdgeFunctionDefinition(matcher, functionName)),
418-
)
419-
}
420-
// Functions (i.e. not middleware, but edge SSR and API routes)
421-
if (typeof middlewareManifest.functions === 'object') {
422-
// When using the app dir, we also need to check if the EF matches a page
423-
const appPathRoutesManifest = await loadAppPathRoutesManifest(netlifyConfig)
424-
425-
// A map of all route pages to their page regex. This is used for pages dir and appDir.
426-
const pageRegexMap = new Map(
427-
[...(routesManifest.dynamicRoutes || []), ...(routesManifest.staticRoutes || [])].map((route) => [
428-
route.page,
429-
route.regex,
430-
]),
431-
)
432-
// Create a map of pages-dir routes to their data route regex (appDir uses the same route as the HTML)
433-
const dataRoutesMap = new Map(
434-
[...(routesManifest.dataRoutes || [])].map((route) => [route.page, route.dataRouteRegex]),
435-
)
436-
437-
for (const edgeFunctionDefinition of Object.values(middlewareManifest.functions)) {
438-
usesEdge = true
439-
const functionName = sanitizeName(edgeFunctionDefinition.name)
440-
await writeEdgeFunction({
441-
edgeFunctionDefinition,
442-
edgeFunctionRoot,
443-
netlifyConfig,
444-
functionName,
445-
})
446-
const pattern = getEdgeFunctionPatternForPage({
447-
edgeFunctionDefinition,
448-
pageRegexMap,
449-
appPathRoutesManifest,
450-
})
429+
const pattern = getEdgeFunctionPatternForPage({
430+
edgeFunctionDefinition,
431+
pageRegexMap,
432+
appPathRoutesManifest,
433+
})
434+
manifest.functions.push({
435+
function: functionName,
436+
name: edgeFunctionDefinition.name,
437+
pattern,
438+
// cache: "manual" is currently experimental, so we restrict it to sites that use experimental appDir
439+
cache: usesAppDir ? 'manual' : undefined,
440+
})
441+
// pages-dir page routes also have a data route. If there's a match, add an entry mapping that to the function too
442+
const dataRoute = dataRoutesMap.get(edgeFunctionDefinition.page)
443+
if (dataRoute) {
451444
manifest.functions.push({
452445
function: functionName,
453446
name: edgeFunctionDefinition.name,
454-
pattern,
455-
// cache: "manual" is currently experimental, so we restrict it to sites that use experimental appDir
447+
pattern: dataRoute,
456448
cache: usesAppDir ? 'manual' : undefined,
457449
})
458-
// pages-dir page routes also have a data route. If there's a match, add an entry mapping that to the function too
459-
const dataRoute = dataRoutesMap.get(edgeFunctionDefinition.page)
460-
if (dataRoute) {
461-
manifest.functions.push({
462-
function: functionName,
463-
name: edgeFunctionDefinition.name,
464-
pattern: dataRoute,
465-
cache: usesAppDir ? 'manual' : undefined,
466-
})
467-
}
468450
}
469451
}
470-
if (usesEdge) {
471-
console.log(outdent`
472-
✨ Deploying middleware and functions to ${greenBright`Netlify Edge Functions`}
473-
This feature is in beta. Please share your feedback here: https://ntl.fyi/next-netlify-edge
474-
`)
452+
}
453+
454+
455+
if (destr(process.env.NEXT_FORCE_EDGE_IMAGES)) {
456+
if (
457+
!destr(process.env.NEXT_DISABLE_EDGE_IMAGES) &&
458+
!destr(process.env.DISABLE_IPX)
459+
) {
460+
usesEdge = true
461+
console.log(
462+
'Using Netlify Edge Functions for image format detection. Set env var "NEXT_DISABLE_EDGE_IMAGES=true" to disable.',
463+
)
464+
const edgeFunctionDir = join(edgeFunctionRoot, 'ipx')
465+
await ensureDir(edgeFunctionDir)
466+
await copyEdgeSourceFile({ edgeFunctionDir, file: 'ipx.ts', target: 'index.ts' })
467+
await copyFile(
468+
join('.netlify', 'functions-internal', '_ipx', 'imageconfig.json'),
469+
join(edgeFunctionDir, 'imageconfig.json'),
470+
)
471+
manifest.functions.push({
472+
function: 'ipx',
473+
name: 'next/image handler',
474+
path: '/_next/image*',
475+
})
475476
}
476477
}
478+
479+
if (usesEdge) {
480+
console.log(outdent`
481+
✨ Deploying middleware and functions to ${greenBright`Netlify Edge Functions`}
482+
This feature is in beta. Please share your feedback here: https://ntl.fyi/next-netlify-edge
483+
`)
484+
}
485+
486+
477487
await writeJson(join(edgeFunctionRoot, 'manifest.json'), manifest)
478488
}

test/index.spec.js

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -684,12 +684,27 @@ describe('onBuild()', () => {
684684
})
685685
})
686686

687-
test('generates an ipx function by default', async () => {
687+
// Skipped while edge images are off by default
688+
test.skip('generates an edge ipx function by default', async () => {
688689
await moveNextDist()
689690
await nextRuntime.onBuild(defaultArgs)
690691
expect(existsSync(path.join('.netlify', 'functions-internal', '_ipx', '_ipx.js'))).toBeTruthy()
691692
})
692693

694+
// Enabled while edge images are off by default
695+
test('does not generate an ipx edge function by default', async () => {
696+
await moveNextDist()
697+
await nextRuntime.onBuild(defaultArgs)
698+
expect(existsSync(path.join('.netlify', 'edge-functions', 'ipx', 'index.ts'))).toBeFalsy()
699+
})
700+
701+
test('generates an ipx edge function if force is set', async () => {
702+
process.env.NEXT_FORCE_EDGE_IMAGES = '1'
703+
await moveNextDist()
704+
await nextRuntime.onBuild(defaultArgs)
705+
expect(existsSync(path.join('.netlify', 'edge-functions', 'ipx', 'index.ts'))).toBeTruthy()
706+
})
707+
693708
test('does not generate an ipx function when DISABLE_IPX is set', async () => {
694709
process.env.DISABLE_IPX = '1'
695710
await moveNextDist()

0 commit comments

Comments
 (0)