Skip to content

Commit 93d19ad

Browse files
fix: route HMR handling (#5710)
1 parent 6f744c2 commit 93d19ad

File tree

6 files changed

+100
-20
lines changed

6 files changed

+100
-20
lines changed

packages/router-core/src/route.ts

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1709,15 +1709,6 @@ export class BaseRoute<
17091709
this._to = fullPath as TrimPathRight<TFullPath>
17101710
}
17111711

1712-
clone = (other: typeof this) => {
1713-
this._path = other._path
1714-
this._id = other._id
1715-
this._fullPath = other._fullPath
1716-
this._to = other._to
1717-
this.options.getParentRoute = other.options.getParentRoute
1718-
this.children = other.children
1719-
}
1720-
17211712
addChildren: RouteAddChildrenFn<
17221713
TRegister,
17231714
TParentRoute,

packages/router-plugin/src/core/code-splitter/compilers.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,7 @@ export function compileCodeSplitReferenceRoute(
133133
let createRouteFn: string
134134

135135
let modified = false as boolean
136+
let hmrAdded = false as boolean
136137
babel.traverse(ast, {
137138
Program: {
138139
enter(programPath) {
@@ -182,9 +183,10 @@ export function compileCodeSplitReferenceRoute(
182183
}
183184
if (!splittableCreateRouteFns.includes(createRouteFn)) {
184185
// we can't split this route but we still add HMR handling if enabled
185-
if (opts.addHmr) {
186-
modified = true
186+
if (opts.addHmr && !hmrAdded) {
187187
programPath.pushContainer('body', routeHmrStatement)
188+
modified = true
189+
hmrAdded = true
188190
}
189191
// exit traversal so this route is not split
190192
return programPath.stop()
@@ -307,8 +309,10 @@ export function compileCodeSplitReferenceRoute(
307309
)()
308310

309311
// add HMR handling
310-
if (opts.addHmr) {
312+
if (opts.addHmr && !hmrAdded) {
311313
programPath.pushContainer('body', routeHmrStatement)
314+
modified = true
315+
hmrAdded = true
312316
}
313317
} else {
314318
// if (splitNodeMeta.splitStrategy === 'lazyFn') {
Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,44 @@
11
import * as template from '@babel/template'
2+
import type { AnyRoute } from '@tanstack/router-core'
3+
4+
type AnyRouteWithPrivateProps = AnyRoute & {
5+
_path: string
6+
_id: string
7+
_fullPath: string
8+
_to: string
9+
}
10+
11+
function handleRouteUpdate(
12+
oldRoute: AnyRouteWithPrivateProps,
13+
newRoute: AnyRouteWithPrivateProps,
14+
) {
15+
newRoute._path = oldRoute._path
16+
newRoute._id = oldRoute._id
17+
newRoute._fullPath = oldRoute._fullPath
18+
newRoute._to = oldRoute._to
19+
newRoute.children = oldRoute.children
20+
newRoute.parentRoute = oldRoute.parentRoute
21+
22+
const router = window.__TSR_ROUTER__!
23+
router.routesById[newRoute.id] = newRoute
24+
router.routesByPath[newRoute.fullPath] = newRoute
25+
const oldRouteIndex = router.flatRoutes.indexOf(oldRoute)
26+
if (oldRouteIndex > -1) {
27+
router.flatRoutes[oldRouteIndex] = newRoute
28+
}
29+
router.invalidate({ filter: (m) => m.routeId === oldRoute.id })
30+
}
231

332
export const routeHmrStatement = template.statement(
433
`
534
if (import.meta.hot) {
635
import.meta.hot.accept((newModule) => {
7-
if (newModule && newModule.Route && typeof newModule.Route.clone === 'function') {
8-
newModule.Route.clone(Route)
36+
if (Route && newModule && newModule.Route) {
37+
(${handleRouteUpdate.toString()})(Route, newModule.Route)
938
}
1039
})
1140
}
1241
`,
42+
// Disable placeholder parsing so identifiers like __TSR_ROUTER__ are treated as normal identifiers instead of template placeholders
43+
{ placeholderPattern: false },
1344
)()

packages/router-plugin/tests/add-hmr/snapshots/react/arrow-function@true.tsx

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,26 @@ export const Route = createFileRoute('/posts')({
99
});
1010
if (import.meta.hot) {
1111
import.meta.hot.accept(newModule => {
12-
if (newModule && newModule.Route && typeof newModule.Route.clone === 'function') {
13-
newModule.Route.clone(Route);
12+
if (Route && newModule && newModule.Route) {
13+
(function handleRouteUpdate(oldRoute, newRoute) {
14+
newRoute._path = oldRoute._path;
15+
newRoute._id = oldRoute._id;
16+
newRoute._fullPath = oldRoute._fullPath;
17+
newRoute._to = oldRoute._to;
18+
newRoute.children = oldRoute.children;
19+
newRoute.parentRoute = oldRoute.parentRoute;
20+
const router = window.__TSR_ROUTER__;
21+
router.routesById[newRoute.id] = newRoute;
22+
router.routesByPath[newRoute.fullPath] = newRoute;
23+
const oldRouteIndex = router.flatRoutes.indexOf(oldRoute);
24+
if (oldRouteIndex > -1) {
25+
router.flatRoutes[oldRouteIndex] = newRoute;
26+
}
27+
;
28+
router.invalidate({
29+
filter: m => m.routeId === oldRoute.id
30+
});
31+
})(Route, newModule.Route);
1432
}
1533
});
1634
}

packages/router-plugin/tests/add-hmr/snapshots/react/function-declaration@true.tsx

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,26 @@ export const Route = createFileRoute('/posts')({
99
});
1010
if (import.meta.hot) {
1111
import.meta.hot.accept(newModule => {
12-
if (newModule && newModule.Route && typeof newModule.Route.clone === 'function') {
13-
newModule.Route.clone(Route);
12+
if (Route && newModule && newModule.Route) {
13+
(function handleRouteUpdate(oldRoute, newRoute) {
14+
newRoute._path = oldRoute._path;
15+
newRoute._id = oldRoute._id;
16+
newRoute._fullPath = oldRoute._fullPath;
17+
newRoute._to = oldRoute._to;
18+
newRoute.children = oldRoute.children;
19+
newRoute.parentRoute = oldRoute.parentRoute;
20+
const router = window.__TSR_ROUTER__;
21+
router.routesById[newRoute.id] = newRoute;
22+
router.routesByPath[newRoute.fullPath] = newRoute;
23+
const oldRouteIndex = router.flatRoutes.indexOf(oldRoute);
24+
if (oldRouteIndex > -1) {
25+
router.flatRoutes[oldRouteIndex] = newRoute;
26+
}
27+
;
28+
router.invalidate({
29+
filter: m => m.routeId === oldRoute.id
30+
});
31+
})(Route, newModule.Route);
1432
}
1533
});
1634
}

packages/router-plugin/tests/add-hmr/snapshots/solid/arrow-function@true.tsx

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,26 @@ export const Route = createFileRoute('/posts')({
88
});
99
if (import.meta.hot) {
1010
import.meta.hot.accept(newModule => {
11-
if (newModule && newModule.Route && typeof newModule.Route.clone === 'function') {
12-
newModule.Route.clone(Route);
11+
if (Route && newModule && newModule.Route) {
12+
(function handleRouteUpdate(oldRoute, newRoute) {
13+
newRoute._path = oldRoute._path;
14+
newRoute._id = oldRoute._id;
15+
newRoute._fullPath = oldRoute._fullPath;
16+
newRoute._to = oldRoute._to;
17+
newRoute.children = oldRoute.children;
18+
newRoute.parentRoute = oldRoute.parentRoute;
19+
const router = window.__TSR_ROUTER__;
20+
router.routesById[newRoute.id] = newRoute;
21+
router.routesByPath[newRoute.fullPath] = newRoute;
22+
const oldRouteIndex = router.flatRoutes.indexOf(oldRoute);
23+
if (oldRouteIndex > -1) {
24+
router.flatRoutes[oldRouteIndex] = newRoute;
25+
}
26+
;
27+
router.invalidate({
28+
filter: m => m.routeId === oldRoute.id
29+
});
30+
})(Route, newModule.Route);
1331
}
1432
});
1533
}

0 commit comments

Comments
 (0)