mirror of
https://github.com/hanzoai/next.js.git
synced 2026-10-30 14:46:38 +00:00
## What? This addresses [#68217](https://github.com/vercel/next.js/issues/68217) where middleware, incorrectly, does not run for _next/image requests. We can confirm this is not correct behavior through the explanation of middleware matchers in [docs](https://nextjs.org/docs/app/building-your-application/routing/middleware#matcher) > The matcher config allows full regex so matching like negative lookaheads or character matching is supported. An example of a negative lookahead to match all except specific paths can be seen here: > ```typescript > export const config = { > matcher: [ > /* > * Match all request paths except for the ones starting with: > * - api (API routes) > * - _next/static (static files) > * - _next/image (image optimization files) <- This means middleware **should** run for _next/image > * - favicon.ico, sitemap.xml, robots.txt (metadata files) > */ > '/((?!api|_next/static|_next/image|favicon.ico|sitemap.xml|robots.txt).*)', > ], > } > ``` ### When did this regress The regression happened here https://github.com/vercel/next.js/pull/57161/files#diff-6f4291cc2bfc5073fdca12a014011769e840ee68583db1468acef075f037015aL1245 > The diff since github isn't inlining the diff > ```diff > - let finished = await this.handleNextDataRequest(req, res, parsedUrl) > + finished = await this.handle(req, res, parsedUrl) > ``` > Note, `handle` groups calls to `handleNextDataRequest` **and** `handleImageRequest` https://github.com/vercel/next.js/pull/57161/files#diff-6f4291cc2bfc5073fdca12a014011769e840ee68583db1468acef075f037015aR1316-R1328 ### Why was this a regression Inside of `handle`, there is a new call to `handleNextImageRequest` (this fn handles image optimization). This ends up causing image optimization to run before user middleware code runs. When the image optimization completes, the server behaves as if the entire middleware pipeline is complete, which is **before** user middleware code is ran https://github.com/vercel/next.js/blob/d2711d22fb719131d63cbce05a6306917f3626ea/packages/next/src/server/base-server.ts#L1528-L1540 Said plainly, image optimization now runs in middleware. And when image optimization completes, it blocks user middleware code from running. Im going to assume this was an incorrect refactor since there did not seem to be a motivation for the behavior change in https://github.com/vercel/next.js/pull/57375 ### Solution The solution proposed is to follow the same behavior as `handleNextDataRequest`, which early returns during middleware: https://github.com/vercel/next.js/blob/d2711d22fb719131d63cbce05a6306917f3626ea/packages/next/src/server/base-server.ts#L728-L745 > Note, `handleNextDataRequest` has an extra condition that it only skips middleware requests when its not on edge. I’m going to assume this is not what we want for image optimization, since there was never an edge check for image optimization- to hedge I don’t have any knowledge on what can run on edge in this context And for confirmation that the new ```handleNextImageRequest``` (added in the regression mentioned) is truly redundant, you can confirm the image optimization happens when `invokePath` is specified in the request meta or when `'x-matched-path'` header exists (as far as my understanding goes, and based on the behavior I observed from runtime checks, these 2 cases should be exhaustive) : https://github.com/vercel/next.js/blob/d2711d22fb719131d63cbce05a6306917f3626ea/packages/next/src/server/base-server.ts#L1470-L1526 https://github.com/vercel/next.js/blob/d2711d22fb719131d63cbce05a6306917f3626ea/packages/next/src/server/base-server.ts#L1078-L1378 > what's relevant in both above snippets > ```typescript > finished = await this.normalizeAndAttachMetadata(req, res, parsedUrl) > if (finished) return > ``` > Note: it's probably optimal to not call normalizeAndAttachMetadata in the if middleware branch at all since both handlers in the function now no-op if they are handling middleware (which is guaranteed in that branch). Im not applying that change here to avoid scope of the fix, but can make the refactor upon request https://github.com/vercel/next.js/blob/d2711d22fb719131d63cbce05a6306917f3626ea/packages/next/src/server/base-server.ts#L1633-L1646 ## TLDR The problem is that image optimization runs before user middleware code, and when it completes successfully, it skips running user middleware code- which means requests to _next/image will not have middleware run for them. The solution is to not run the image optimization in middleware that caused the skip Fixes #68217 --------- Co-authored-by: Joseph Chamochumbi <[email protected]>
11 lines
318 B
JavaScript
11 lines
318 B
JavaScript
import Image from 'next/image'
|
|
|
|
export async function middleware(request) {
|
|
// reference Image so it's not tree shaken / DCE
|
|
console.log(`Has image: ${Boolean(Image)}`)
|
|
|
|
if (request.nextUrl.pathname.startsWith('/_next/image')) {
|
|
console.log(`x-_next-image: ${request.nextUrl.searchParams.get('url')}`)
|
|
}
|
|
}
|