Rewrite instant validation to use depth-based URL boundary discovery#90905
Rewrite instant validation to use depth-based URL boundary discovery#90905
Conversation
Failing test suitesCommit: 4660de3 | About building and testing Next.js |
Stats from current PR🟢 1 improvement
📊 All Metrics📖 Metrics GlossaryDev Server Metrics:
Build Metrics:
Change Thresholds:
⚡ Dev Server
⚡ Production Builds
📦 Production Builds (Webpack) (Legacy)📦 Production Builds (Webpack)
📦 Bundle SizesBundle Sizes⚡ TurbopackClient Main Bundles: **402 kB** → **401 kB** ✅ -30 B80 files with content-based hashes (individual files not comparable between builds) Server Middleware
Build DetailsBuild Manifests
🔄 Shared (bundler-independent)Runtimes
📝 Changed Files (4 files)Files with changes:
View diffsapp-page-exp..ntime.dev.jsapp-page-tur..ntime.dev.jsapp-page-tur..ntime.dev.jsapp-page.runtime.dev.js📎 Tarball URL |
packages/next/src/server/app-render/instant-validation/instant-validation.tsx
Outdated
Show resolved
Hide resolved
packages/next/src/server/app-render/instant-validation/instant-validation.tsx
Outdated
Show resolved
Hide resolved
| hasStaticSegments: boolean | ||
| hasRuntimeSegments: boolean |
There was a problem hiding this comment.
nit: i would prefer that we either mark the rest as readonly or move these mutable bits into a separate object. at first look ValidationContext seems like a bag of options that gets passed around, it feels confusing to mix mutable state (essentially out-params) into it, like usedSegmentKinds used to be
There was a problem hiding this comment.
made it a closure again
There was a problem hiding this comment.
wdym? this sounds like it's responding to a different comment
There was a problem hiding this comment.
i mean i got rid of Validationcontext. it only existed to extract these closures out into regular functions. but it's not performance critical and just makes the logic a little harder to follow
| const loaderTree = ctx.componentMod.routeModule.userland.loaderTree | ||
|
|
||
| // Only affects a debug environment name label, not functional behavior. | ||
| const hasRuntimePrefetch = true |
There was a problem hiding this comment.
We don't expect any new logs thus we don't need the environment name to actually be correct. We can't know globally the right environment anyway because it is actually based on where in the tree you are. I think we can even just get rid of the environment altogether for this re-render pass and have it just return Server or have it return "You shouldn't be seeing this"
There was a problem hiding this comment.
hm. i mean, it can end up in stacs that we send to the browser, can it not? like i think you might get SomeComponent [Prerender] in the owner stack
There was a problem hiding this comment.
won't it have the original environment name from the original render?
packages/next/src/server/app-render/instant-validation/instant-validation.tsx
Outdated
Show resolved
Hide resolved
|
|
||
| const consumesDepth = segmentConsumesURLDepth(segment) | ||
|
|
||
| if (consumesDepth && urlDepthConsumed === depth) { |
There was a problem hiding this comment.
i would like some comments explaining how/why this stop condition works, and maybe some examples. it's not obvious for me, i'm guessing i'm not the only one
(also it seems buggy in some cases, DM'd repro)
85e0d38 to
c5599ac
Compare
Instead of pre-planning validation tasks by walking the tree and accumulating `navigationParents`, the new implementation drives validation by URL depth. Starting from the deepest URL segment and working backwards, it builds a combined payload at each depth where the boundary between shared (already-mounted) and new (being-navigated-to) content is determined by counting URL-consuming segments. If the new subtree at that depth contains any `unstable_instant` configs, the payload is validated. If not, it moves to the next shallower depth. This approach has several advantages over the task-based model: - Route group layouts no longer create spurious navigation boundaries — they don\`t consume URL depth, so they naturally share the boundary of their parent URL segment - The \`requiresInstantUI\` requirement propagates correctly through the tree: a local \`false\` config opts the subtree out, a non-false config opts it in, and no config defers to the OR-union of children slots - Both the static-stage and runtime-retry payloads are built in a single tree walk, avoiding the separate retry pass - The \`<head>\` stage correctly uses Runtime when any segment in the new tree uses runtime prefetch The old task-based implementation (\`findNavigationsToValidate\`, \`validateInstantConfigs\`, etc.) is preserved but no longer called. It will be removed in a follow-up commit.
c5599ac to
4660de3
Compare
…90905) Instead of pre-planning validation tasks by walking the tree and accumulating `navigationParents`, the new implementation drives validation by URL depth. Starting from the deepest URL segment and working backwards, it builds a combined payload at each depth where the boundary between shared (already-mounted) and new (being-navigated-to) content is determined by counting URL-consuming segments. If the new subtree at that depth contains any `unstable_instant` configs, the payload is validated. If not, it moves to the next shallower depth. This approach has several advantages over the task-based model: - Route group layouts no longer create spurious navigation boundaries — they don\`t consume URL depth, so they naturally share the boundary of their parent URL segment - The `requiresInstantUI` requirement propagates correctly through the tree: a local `false` config opts the subtree out, a non-false config opts it in, and no config defers to the OR-union of children slots - Both the static-stage and runtime-retry payloads are built in a single tree walk, avoiding the separate retry pass - The `<head>` stage correctly uses Runtime when any segment in the new tree uses runtime prefetch
Instead of pre-planning validation tasks by walking the tree and accumulating
navigationParents, the new implementation drives validation by URL depth. Starting from the deepest URL segment and working backwards, it builds a combined payload at each depth where the boundary between shared (already-mounted) and new (being-navigated-to) content is determined by counting URL-consuming segments. If the new subtree at that depth contains anyunstable_instantconfigs, the payload is validated. If not, it moves to the next shallower depth.This approach has several advantages over the task-based model:
requiresInstantUIrequirement propagates correctly through the tree: a localfalseconfig opts the subtree out, a non-false config opts it in, and no config defers to the OR-union of children slots<head>stage correctly uses Runtime when any segment in the new tree uses runtime prefetch