fix(next): detect next/image in Next.js 15+ App Router projects#10214
fix(next): detect next/image in Next.js 15+ App Router projects#10214dxdc wants to merge 2 commits intofirebase:mainfrom
Conversation
Next.js 15+ App Router projects may not populate the export marker or the client-reference-manifest with next/image references, even when next/image is actively used. This adds a source-level fallback that scans .tsx/.ts/.jsx/.js files under the app directory for next/image import statements before falling back to the images-manifest.json check.
There was a problem hiding this comment.
Code Review
This pull request implements a fallback mechanism for Next.js 15+ to detect next/image usage by scanning project source files in the app or src/app directories when build manifests are incomplete. The review feedback suggests refactoring the detection logic to reduce nesting, improving the extensibility of directory checks, and switching to asynchronous globbing to avoid blocking the event loop during file scans.
Reduce nesting in isNextImageInProjectSource by iterating over candidate directories. Simplify the conditional assignment in isUsingImageOptimization. Switch from globSync to async glob to avoid blocking the event loop during file scanning.
|
Hi @dxdc, thanks for the detailed write-up and the PR. I tried reproducing this with an App Router-only project on Next.js 15.5.14 (latest safe 15.5.x) and 16.1.1, and both existing detection tiers work correctly. Here's the 15.5.x app I used to test for reference: https://github.com/monogramdesign/firebase-tools-test-apps/tree/main/nextjs/15.5.x. My findings:
The deploy correctly detects image optimization and require a Cloud Function for it. Could you share a minimal reproduction project where both tiers fail? I'd like to understand what's different about your setup. Separately, I have concerns about the source-scanning fallback approach:
|
|
Thanks for testing this! I can reproduce the issue - here's the exact trigger: The image reference disappears from all Your test app works because // src/app/layout.tsx
+"use client"
import Image from "next/image"
// ...
// src/app/page.tsx
+"use client"
import Image from "next/image"
// ...
// src/app/app-image-test/page.tsx
+"use client"
import Image from "next/image"
// ...Build → check manifests → Why: When a This is a common pattern - any page that uses Redux, Re: the source-scanning concerns - those are fair points. A tighter alternative: check |
|
Btw: After experimenting with it some more, another workaround is a 1x1 hidden |
|
Thanks for reporting this @dxdc — your investigation into the "use client" edge case was spot on. The client-reference-manifest only tracks RSC boundary crossings, so when every next/image import lives in a "use client" component, both existing detection tiers miss it. I've opened #10228 with a fix that stays within the .next build artifacts approach: it scans prerendered HTML for the data-nimg=" attribute that next/image renders on every Thanks again for the detailed write-up — it made tracking this down much easier. |
|
thanks @leoortizz !! |
Firebase Hosting with
frameworksBackenddoes not detectnext/imageusage in Next.js 15+ App Router-only projects. This causesfirebase deployto skip adding Sharp to the Cloud Function, breaking image optimization.Affected: Any Next.js 15+ project using App Router (no
pages/directory) deployed via Firebase HostingframeworksBackend.Root Cause
isUsingImageOptimization()insrc/frameworks/next/utils.tshas two detection tiers that both fail:Tier 1:
export-marker.json→isNextImageImportedNext.js sets
isNextImageImportedonly for Pages Router pages. Innext/src/build/index.ts:For App Router-only projects, the flag remains
falseinexport-marker.json.Tier 2: Client reference manifest scan
isUsingNextImageInAppDirectory()searches*client-reference-manifest.jsfiles for the substringnode_modules/next/dist/client/image.In Next.js 15.5.x, the image component is no longer listed as a separate entry in client-reference-manifest files. The
next/imagecomponent is bundled into page-level client chunks instead of being registered individually. Verified by building a Next.js 15.5.12 project and inspecting every manifest file - none contain the stringimage.Result
Both checks return
false→isUsingImageOptimization()returnsfalse→ Sharp is not added to the Cloud Function → image optimization is silently disabled.Proposed Fix
Add a third fallback tier: scan project source files for
next/imageimports. This only runs when both existing checks fail, so it's fully backward compatible.The source scan is the most defensible approach: targeted (no false positives), backward compatible (only runs when existing checks fail), and robust (
from 'next/image'is a stable API contract).Reproduction
pages/directory)next/imagein any componentfirebase deploy --only hostingwithframeworksBackend.next/export-marker.json-isNextImageImportedisfalseWorkaround
Until fixed, patch
export-marker.jsonafter build: