Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/sixty-rings-find.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@tanstack/vue-router': patch
---

Compute hash-sensitive Link active states and inherited or function-derived hash hrefs from the server's empty hash during hydration. Use the live hash after hydration and immediately for client-only mounts, without a hydration update for ordinary links.
24 changes: 23 additions & 1 deletion packages/vue-router/src/link.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -189,11 +189,31 @@ function useLinkPropsImpl(
})
}

// Vue assigns vnode.el before setup only when reusing server DOM. A fresh
// client mount must use the live hash immediately, even on an SSR router.
const hydrating = Vue.ref(Vue.getCurrentInstance()?.vnode.el != null)
if (hydrating.value) {
Vue.onMounted(() => {
hydrating.value = false
})
}

const next = Vue.computed(() => {
// Rebuild when inherited search/hash or the current route context changes.

const options = getOptions()
const opts = { _fromLocation: currentLocation.value, ...options }
const hash = options.hash
// Only hash-dependent destinations need the server's empty hash. Keep
// the source location identity so links share the route-match cache.
if (
!options.href &&
!options._fromLocation &&
(hash === true || typeof hash === 'function') &&
hydrating.value
) {
opts.hash = hash === true ? '' : hash('')
}
return router.buildLocation(opts)
})

Expand Down Expand Up @@ -234,6 +254,7 @@ function useLinkPropsImpl(
next.value,
options.activeOptions,
router,
options.activeOptions?.includeHash && hydrating.value,
)
})

Expand Down Expand Up @@ -663,6 +684,7 @@ function getIsActive(
},
activeOptions: LinkOptions['activeOptions'],
router: AnyRouter,
hydrating = false,
) {
const currentPath = removeTrailingSlash(loc.pathname, router.basepath)
const nextPath = removeTrailingSlash(nextLoc.pathname, router.basepath)
Expand Down Expand Up @@ -693,7 +715,7 @@ function getIsActive(
}

if (activeOptions?.includeHash) {
return loc.hash === nextLoc.hash
return (hydrating ? '' : loc.hash) === nextLoc.hash
}
return true
}
Expand Down
Loading
Loading