-
-
Notifications
You must be signed in to change notification settings - Fork 1.5k
refactor(router-core): skip URL constructor in buildLocation #6447
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
refactor(router-core): skip URL constructor in buildLocation #6447
Conversation
📝 WalkthroughWalkthroughThe PR replaces propagated URL objects with a string-based Changes
Sequence Diagram(s)sequenceDiagram
autonumber
participant Client
participant LinkComponent
participant RouterCore
participant RouterHistory
participant BrowserHistory
Client->>LinkComponent: render / click <to>
LinkComponent->>RouterCore: call next() -> maskedLocation ?? next()
RouterCore->>RouterCore: derive publicHref, href, external
alt external === true
LinkComponent->>Client: return { href: publicHref, external: true }
else
LinkComponent->>RouterHistory: router.history.createHref(publicHref)
RouterHistory->>LinkComponent: created href (path)
LinkComponent->>BrowserHistory: navigation (push/replace href)
BrowserHistory->>RouterCore: commit location (payload uses publicHref)
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
Comment |
|
View your CI Pipeline Execution ↗ for commit 230a2ba
☁️ Nx Cloud last updated this comment at |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 4
🤖 Fix all issues with AI agents
In `@packages/react-router/src/link.tsx`:
- Around line 131-149: The code currently treats full publicHref values as
internal by returning { href: publicHref, external: false }; update the handler
in link.tsx (the block that computes publicHref and isFullUrl) to mark full-URL
publicHref values as external (set external: true) so the Link component does
not intercept clicks for cross-origin rewrites; keep href as publicHref for
those cases and leave the router.history.createHref branch unchanged for
origin-stripped paths.
In `@packages/router-core/src/router.ts`:
- Around line 2646-2649: getParsedLocationHref currently returns an
origin-stripped location.href which loses cross-origin rewrite targets; change
getParsedLocationHref (used by resolveRedirect) to prefer the full URL (e.g.,
location.publicHref or location.url.href) and only strip the origin when it
exactly matches this.origin so same-origin behavior is preserved while
cross-origin redirects retain their full href; update any callers (notably
resolveRedirect) to use the new logic to emit full cross-origin URLs and keep
the existing same-origin stripping behavior.
In `@packages/solid-router/src/link.tsx`:
- Around line 140-158: The code treats full publicHref values as internal;
change the branch that detects full URLs (the isFullUrl check using
publicHref.startsWith('http://')/('https://')) to mark them external by
returning { href: publicHref, external: true } so SPA interception is disabled
for cross-origin rewrites; keep the other branch using
router.history.createHref(publicHref) for non-full paths.
In `@packages/vue-router/src/link.tsx`:
- Around line 474-493: The computed publicHref can be an absolute URL even for
an internal options.to, which risks client-side navigation attempting a
cross-origin push; update the href resolution and click handling so that when
publicHref is detected as a full URL (the logic in the block using
nextLocation?.maskedLocation ?? nextLocation and const publicHref =
location?.publicHref), you treat it as external: return the full publicHref and
signal/mark it as external (or short-circuit handleClick) so that handleClick
(the component's click handler that currently calls
router.navigate/router.history.createHref) does not attempt router.navigate or a
client-side push for that link; concretely, keep the isFullUrl detection, ensure
the resolver returns the absolute URL and modify handleClick to check the same
isFullUrl condition (or an external flag set alongside createHref) and fall back
to native navigation instead of calling router.navigate.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In `@packages/router-core/src/router.ts`:
- Around line 1885-1912: The internal href must be derived from fullPath before
running executeRewriteOutput to avoid in-place mutation of the URL changing our
internal path; change the block where this.rewrite is handled so href = fullPath
(or otherwise capture the origin-stripped path) before calling
executeRewriteOutput(this.rewrite, url), then compute publicHref from
rewrittenUrl (using rewrittenUrl.href when origins differ, or
rewrittenUrl.pathname+search+hash when same) so publicHref reflects the rewrite
while href remains the original internal path used by isSameUrl and redirects.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
packages/router-core/src/router.ts (1)
2218-2226: Guard against cross‑origin rewrites during imperative navigation.
buildLocationnow marksexternalwhen rewrite output changes origin.navigate({ to })still proceeds with client-side commit and may hit apushStatecross-origin error. Consider forcingreloadDocumentwhenlocation.externaland usingpublicHref.🛠️ Suggested fix
navigate: NavigateFn = async ({ to, reloadDocument, href, publicHref, ...rest }) => { let hrefIsUrl = false if (href) { try { new URL(`${href}`) hrefIsUrl = true } catch {} } if (hrefIsUrl && !reloadDocument) { reloadDocument = true } + + let resolvedLocation: ParsedLocation | undefined + if (!reloadDocument && (to !== undefined || !href)) { + resolvedLocation = this.buildLocation({ to, ...rest } as any) + if (resolvedLocation.external) { + reloadDocument = true + href = href ?? resolvedLocation.publicHref + publicHref = publicHref ?? resolvedLocation.publicHref + } + } if (reloadDocument) { // When to is provided, always build a location to get the proper publicHref // (this handles redirects where href might be an internal path from resolveRedirect) // When only href is provided (no to), use it directly as it should already // be a complete path (possibly with basepath) if (to !== undefined || !href) { - const location = this.buildLocation({ to, ...rest } as any) + const location = resolvedLocation ?? this.buildLocation({ to, ...rest } as any) // Use publicHref which contains the path (origin-stripped is fine for reload) href = href ?? location.publicHref publicHref = publicHref ?? location.publicHref }
♻️ Duplicate comments (1)
packages/router-core/src/router.ts (1)
1886-1910: Keep internalhrefstable when rewrite output mutates the URL.
executeRewriteOutputcan mutateurlin-place; usingurl.hrefafter rewrite can turn the internalhrefinto the public path and breakisSameUrlcomparisons. Prefer the pre‑rewritefullPathforhref.🛠️ Suggested fix
if (this.rewrite) { // With rewrite, we need to construct URL to apply the rewrite const url = new URL(fullPath, this.origin) const rewrittenUrl = executeRewriteOutput(this.rewrite, url) - href = url.href.replace(url.origin, '') + // Keep internal href stable even if rewrite.output mutates `url` + href = fullPath // If rewrite changed the origin, publicHref needs full URL // Otherwise just use the path components if (rewrittenUrl.origin !== this.origin) { publicHref = rewrittenUrl.href external = trueAlso applies to: 1912-1921
Summary by CodeRabbit
Refactor
Tests
✏️ Tip: You can customize this high-level summary in your review settings.