Prerender static metadata under dynamic segments to canonical pathname#93873
Draft
timneutkens wants to merge 3 commits into
Draft
Prerender static metadata under dynamic segments to canonical pathname#93873timneutkens wants to merge 3 commits into
timneutkens wants to merge 3 commits into
Conversation
Contributor
Tests PassedCommit: b72963b |
Contributor
Stats from current PR✅ No significant changes detected📊 All Metrics📖 Metrics GlossaryDev Server Metrics:
Build Metrics:
Change Thresholds:
⚡ Dev Server
📦 Dev Server (Webpack) (Legacy)📦 Dev Server (Webpack)
⚡ Production Builds
📦 Production Builds (Webpack) (Legacy)📦 Production Builds (Webpack)
📦 Bundle SizesBundle Sizes⚡ TurbopackClient Main Bundles
Server Middleware
Build DetailsBuild Manifests
📦 WebpackClient Main Bundles
Polyfills
Pages
Server Edge SSR
Middleware
Build DetailsBuild Manifests
Build Cache
🔄 Shared (bundler-independent)Runtimes
📎 Tarball URLCommit: b72963b |
gnoff
approved these changes
May 15, 2026
Contributor
gnoff
left a comment
There was a problem hiding this comment.
This is a nice improvement.
To make sure we're aligned on where we can go from here it seems to me the ideal impl is
- static metadata files are persisted in /public or wherever we store other static assets
- this public path is used in place of
-param substitution when rendering these files as metadata - a redirect route matcher is used to take ad-hoc .../[slug]/... pathnames and map them to the single static instance of this image/icon/etc...
The critical component is there should not need to be a route handler to serve this static image nor should there be any ISR.
If we had to sacrifice 3 to simply I think that'd also be acceptable
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What?
Fixes an invariant failure (
failed to find source route /dynamic/[id]/apple-icon.png for prerender /dynamic/[id]/apple-icon.png) raised by the build adapter when an app contains static metadata files (apple-icon.png,icon.png,opengraph-image.png,twitter-image.png,sitemap.xml) under a dynamic segment.Why?
Static metadata files under a dynamic segment were treated as full dynamic prerenders: they ended up in
prerenderManifest.dynamicRouteswithfallbackRouteParams, but no.bodyfile was exported and they never received anappOutputMapentry. The adapter'sdynamicRoutesloop then askedgetParentOutputfor a source route that didn't exist and threw.These files are content-stable across params — the route handler returns the same bytes for every URL that matches the dynamic pattern — so they should prerender once under a canonical pathname rather than be treated like per-param dynamic routes.
How?
getStaticMetadataPrerenderPathnamehelper that maps/dynamic/[id]/apple-icon.pngto/dynamic/-/apple-icon.png. This is the canonical pathname already used byfillStaticMetadataSegmentfor HTML link emission.build/utils.ts, routeAPP_ROUTEentries that are static metadata files through a newbuildStaticMetadataStaticPaths(one prerender path, no fallback params) instead of the regularbuildAppStaticPaths.build/index.ts:--placeholder pathname before splitting into known/unknown buckets, so it lands inprerenderManifest.routeswith a.bodyfile.dynamicPrerenderedRoutesloop so they don't get a strayPRERENDERmanifest entry.prerenderManifest.dynamicRoutes.prerenderManifest.routesunder the canonical placeholder pathname (with locale prefix when applicable) and skip static metadata in thedynamicRoutesloop.get-metadata-route.test.tslock in the placeholder behavior for the tricky cases: catchall, optional catchall, multi-level dynamic, literals between dynamics, dynamic + catchall mix.Reproduction:
test/e2e/app-dir/metadata-static-file/metadata-static-file-dynamic-route.test.tsconfigured withadapterPathpreviously crashed athandleBuildComplete; all three cases in that file now pass.Runtime stays the same: arbitrary param URLs continue to be served by the dynamic route handler shipped with the app route; only the canonical
-URL is statically served.