diff --git a/packages/react-router/src/Transitioner.tsx b/packages/react-router/src/Transitioner.tsx index 04e140acfc..b2981d1a67 100644 --- a/packages/react-router/src/Transitioner.tsx +++ b/packages/react-router/src/Transitioner.tsx @@ -52,10 +52,20 @@ export function Transitioner() { _includeValidateSearch: true, }) - if ( - trimPathRight(router.latestLocation.href) !== - trimPathRight(nextLocation.href) - ) { + const latestPublicHref = trimPathRight(router.latestLocation.publicHref) + const nextPublicHref = trimPathRight(nextLocation.publicHref) + + if (latestPublicHref !== nextPublicHref) { + const latestOrigin = new URL(router.latestLocation.url).origin + const nextOrigin = new URL(nextLocation.url).origin + + if (latestOrigin !== nextOrigin) { + if (typeof window !== 'undefined') { + window.location.href = nextLocation.url + } + return + } + router.commitLocation({ ...nextLocation, replace: true }) } diff --git a/packages/react-router/tests/router.test.tsx b/packages/react-router/tests/router.test.tsx index 90be8b8db2..cfb512651a 100644 --- a/packages/react-router/tests/router.test.tsx +++ b/packages/react-router/tests/router.test.tsx @@ -2809,6 +2809,72 @@ describe('basepath', () => { expect(router.state.location.pathname).toBe('/test') }) + it('should handle basepath when accessing root path and maintain basepath in browser URL', async () => { + const rootRoute = createRootRoute({ + component: () => , + }) + + const indexRoute = createRoute({ + getParentRoute: () => rootRoute, + path: '/', + component: () =>
Home
, + }) + + const routeTree = rootRoute.addChildren([indexRoute]) + + const history = createMemoryHistory({ + initialEntries: ['/my-app/'], + }) + + const router = createRouter({ + routeTree, + history, + basepath: '/my-app', + }) + + render() + + await waitFor(() => { + expect(screen.getByTestId('home')).toBeInTheDocument() + }) + + expect(router.state.location.pathname).toBe('/') + expect(history.location.pathname).toBe('/my-app/') + }) + + it('should handle basepath option for backward compatibility', async () => { + const rootRoute = createRootRoute({ + component: () => , + }) + + const indexRoute = createRoute({ + getParentRoute: () => rootRoute, + path: '/', + component: () =>
Home
, + }) + + const routeTree = rootRoute.addChildren([indexRoute]) + + const history = createMemoryHistory({ + initialEntries: ['/my-app/'], + }) + + const router = createRouter({ + routeTree, + history, + basepath: '/my-app', + }) + + render() + + await waitFor(() => { + expect(screen.getByTestId('home')).toBeInTheDocument() + }) + + expect(router.state.location.pathname).toBe('/') + expect(history.location.pathname).toBe('/my-app/') + }) + it('should combine basepath with additional input rewrite logic', async () => { const rootRoute = createRootRoute({ component: () => , diff --git a/packages/router-core/src/router.ts b/packages/router-core/src/router.ts index 78b5e11608..a8aa38c34e 100644 --- a/packages/router-core/src/router.ts +++ b/packages/router-core/src/router.ts @@ -1804,8 +1804,12 @@ export class RouterCore< return isEqual } + const latestPublicHref = + this.latestLocation.publicHref ?? this.latestLocation.href + const nextPublicHref = next.publicHref ?? next.href + const isSameUrl = - trimPathRight(this.latestLocation.href) === trimPathRight(next.href) + trimPathRight(latestPublicHref) === trimPathRight(nextPublicHref) const previousCommitPromise = this.commitLocationPromise this.commitLocationPromise = createControlledPromise(() => { diff --git a/packages/solid-router/src/Transitioner.tsx b/packages/solid-router/src/Transitioner.tsx index 2d602a2022..6aa52ba6dd 100644 --- a/packages/solid-router/src/Transitioner.tsx +++ b/packages/solid-router/src/Transitioner.tsx @@ -50,10 +50,10 @@ export function Transitioner() { _includeValidateSearch: true, }) - if ( - trimPathRight(router.latestLocation.href) !== - trimPathRight(nextLocation.href) - ) { + const latestPublicHref = trimPathRight(router.latestLocation.publicHref) + const nextPublicHref = trimPathRight(nextLocation.publicHref) + + if (latestPublicHref !== nextPublicHref) { router.commitLocation({ ...nextLocation, replace: true }) }