Skip to content

Commit f000296

Browse files
jaysin586claude
andcommitted
fix(docs-layout): break the breadcrumb effect self-cycle in DocsLayoutV2
Svelte 5's `$state` proxy reads the existing value during a `set` to dedupe equal writes. Inside an `$effect`, that hidden read subscribes the effect to the property it's writing — so the breadcrumb assignment `breadcrumbContext.breadcrumbs = buildCrumbs(...)` made the effect observe its own writes and re-fire, blowing up as `effect_update_depth_exceeded` on every doc-page hydration. Wrap the write in `untrack`. Compute the next value outside `untrack` so the legitimate dependency on `page.url.pathname` still flows through. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 23451a3 commit f000296

1 file changed

Lines changed: 12 additions & 2 deletions

File tree

‎src/lib/components/DocsLayoutV2.svelte‎

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
<script lang="ts">
3030
import { afterNavigate } from '$app/navigation'
3131
import { page } from '$app/state'
32-
import type { Snippet } from 'svelte'
32+
import { untrack, type Snippet } from 'svelte'
3333
import { enhanceCodeBlocks } from '../actions/enhanceCodeBlocks.js'
3434
import type { DocsKitConfig } from '../config.js'
3535
import { getBreadcrumbContext, type Breadcrumb } from '../contexts/breadcrumb.js'
@@ -103,12 +103,22 @@
103103
// Top-level assignment populates the context during SSR so HeaderV2 and any
104104
// BreadcrumbJsonLd consumer see crumbs in the server HTML; the $effect catches
105105
// client-side navigation between sibling doc pages where the layout doesn't remount.
106+
//
107+
// The write inside the $effect is wrapped in `untrack` because Svelte 5's `$state`
108+
// proxy reads the existing value during a `set` to dedupe equal writes, and that
109+
// read would otherwise subscribe this effect to `.breadcrumbs` — i.e. the effect
110+
// would observe its own writes and re-fire, blowing up as
111+
// `effect_update_depth_exceeded`. We still need the dependency on
112+
// `page.url.pathname`, so that read stays outside `untrack`.
106113
if (breadcrumbContext) {
107114
breadcrumbContext.breadcrumbs = buildCrumbs(page.url.pathname)
108115
}
109116
$effect(() => {
110117
if (!breadcrumbContext) return
111-
breadcrumbContext.breadcrumbs = buildCrumbs(page.url.pathname)
118+
const next = buildCrumbs(page.url.pathname)
119+
untrack(() => {
120+
breadcrumbContext.breadcrumbs = next
121+
})
112122
})
113123
114124
/** Pretty slug for the brut strip: "/docs" → "index", "/docs/use-spring" → "use-spring".

0 commit comments

Comments
 (0)