@tanstack/router-plugin 1.167.22 → 1.167.24
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/core/code-splitter/compilers.cjs +8 -4
- package/dist/cjs/core/code-splitter/compilers.cjs.map +1 -1
- package/dist/cjs/core/code-splitter/plugins/framework-plugins.cjs +8 -5
- package/dist/cjs/core/code-splitter/plugins/framework-plugins.cjs.map +1 -1
- package/dist/cjs/core/code-splitter/plugins/framework-plugins.d.cts +2 -2
- package/dist/cjs/core/code-splitter/plugins/react-refresh-ignored-route-exports.cjs +5 -9
- package/dist/cjs/core/code-splitter/plugins/react-refresh-ignored-route-exports.cjs.map +1 -1
- package/dist/cjs/core/code-splitter/plugins/react-refresh-ignored-route-exports.d.cts +1 -3
- package/dist/cjs/core/code-splitter/plugins/react-stable-hmr-split-route-components.cjs +6 -4
- package/dist/cjs/core/code-splitter/plugins/react-stable-hmr-split-route-components.cjs.map +1 -1
- package/dist/cjs/core/code-splitter/plugins/react-stable-hmr-split-route-components.d.cts +3 -2
- package/dist/cjs/core/code-splitter/plugins.d.cts +3 -2
- package/dist/cjs/core/config.cjs +1 -1
- package/dist/cjs/core/config.cjs.map +1 -1
- package/dist/cjs/core/config.d.cts +26 -18
- package/dist/cjs/core/{route-hmr-statement.cjs → hmr/handle-route-update.cjs} +39 -25
- package/dist/cjs/core/hmr/handle-route-update.cjs.map +1 -0
- package/dist/cjs/core/hmr/handle-route-update.d.cts +1 -0
- package/dist/cjs/core/hmr/index.d.cts +5 -0
- package/dist/cjs/core/hmr/select-adapter.cjs +20 -0
- package/dist/cjs/core/hmr/select-adapter.cjs.map +1 -0
- package/dist/cjs/core/hmr/select-adapter.d.cts +13 -0
- package/dist/cjs/core/hmr/vite-adapter.cjs +36 -0
- package/dist/cjs/core/hmr/vite-adapter.cjs.map +1 -0
- package/dist/cjs/core/hmr/vite-adapter.d.cts +12 -0
- package/dist/cjs/core/hmr/webpack-adapter.cjs +64 -0
- package/dist/cjs/core/hmr/webpack-adapter.cjs.map +1 -0
- package/dist/cjs/core/hmr/webpack-adapter.d.cts +20 -0
- package/dist/cjs/core/router-code-splitter-plugin.cjs +5 -5
- package/dist/cjs/core/router-code-splitter-plugin.cjs.map +1 -1
- package/dist/cjs/core/router-composed-plugin.cjs +30 -2
- package/dist/cjs/core/router-composed-plugin.cjs.map +1 -1
- package/dist/cjs/core/router-composed-plugin.d.cts +1 -1
- package/dist/cjs/core/router-hmr-plugin.cjs +17 -11
- package/dist/cjs/core/router-hmr-plugin.cjs.map +1 -1
- package/dist/cjs/esbuild.d.cts +14 -14
- package/dist/cjs/rspack.cjs +22 -3
- package/dist/cjs/rspack.cjs.map +1 -1
- package/dist/cjs/rspack.d.cts +3 -3
- package/dist/cjs/vite.d.cts +14 -14
- package/dist/cjs/webpack.cjs +19 -3
- package/dist/cjs/webpack.cjs.map +1 -1
- package/dist/cjs/webpack.d.cts +3 -3
- package/dist/esm/core/code-splitter/compilers.js +7 -3
- package/dist/esm/core/code-splitter/compilers.js.map +1 -1
- package/dist/esm/core/code-splitter/plugins/framework-plugins.d.ts +2 -2
- package/dist/esm/core/code-splitter/plugins/framework-plugins.js +8 -5
- package/dist/esm/core/code-splitter/plugins/framework-plugins.js.map +1 -1
- package/dist/esm/core/code-splitter/plugins/react-refresh-ignored-route-exports.d.ts +1 -3
- package/dist/esm/core/code-splitter/plugins/react-refresh-ignored-route-exports.js +4 -8
- package/dist/esm/core/code-splitter/plugins/react-refresh-ignored-route-exports.js.map +1 -1
- package/dist/esm/core/code-splitter/plugins/react-stable-hmr-split-route-components.d.ts +3 -2
- package/dist/esm/core/code-splitter/plugins/react-stable-hmr-split-route-components.js +5 -3
- package/dist/esm/core/code-splitter/plugins/react-stable-hmr-split-route-components.js.map +1 -1
- package/dist/esm/core/code-splitter/plugins.d.ts +3 -2
- package/dist/esm/core/config.d.ts +26 -18
- package/dist/esm/core/config.js +1 -1
- package/dist/esm/core/config.js.map +1 -1
- package/dist/esm/core/hmr/handle-route-update.d.ts +1 -0
- package/dist/esm/core/{route-hmr-statement.js → hmr/handle-route-update.js} +39 -23
- package/dist/esm/core/hmr/handle-route-update.js.map +1 -0
- package/dist/esm/core/hmr/index.d.ts +5 -0
- package/dist/esm/core/hmr/select-adapter.d.ts +13 -0
- package/dist/esm/core/hmr/select-adapter.js +20 -0
- package/dist/esm/core/hmr/select-adapter.js.map +1 -0
- package/dist/esm/core/hmr/vite-adapter.d.ts +12 -0
- package/dist/esm/core/hmr/vite-adapter.js +34 -0
- package/dist/esm/core/hmr/vite-adapter.js.map +1 -0
- package/dist/esm/core/hmr/webpack-adapter.d.ts +20 -0
- package/dist/esm/core/hmr/webpack-adapter.js +62 -0
- package/dist/esm/core/hmr/webpack-adapter.js.map +1 -0
- package/dist/esm/core/router-code-splitter-plugin.js +5 -5
- package/dist/esm/core/router-code-splitter-plugin.js.map +1 -1
- package/dist/esm/core/router-composed-plugin.d.ts +1 -1
- package/dist/esm/core/router-composed-plugin.js +30 -2
- package/dist/esm/core/router-composed-plugin.js.map +1 -1
- package/dist/esm/core/router-hmr-plugin.js +17 -11
- package/dist/esm/core/router-hmr-plugin.js.map +1 -1
- package/dist/esm/esbuild.d.ts +14 -14
- package/dist/esm/rspack.d.ts +3 -3
- package/dist/esm/rspack.js +22 -3
- package/dist/esm/rspack.js.map +1 -1
- package/dist/esm/vite.d.ts +14 -14
- package/dist/esm/webpack.d.ts +3 -3
- package/dist/esm/webpack.js +19 -3
- package/dist/esm/webpack.js.map +1 -1
- package/package.json +6 -6
- package/src/core/code-splitter/compilers.ts +4 -2
- package/src/core/code-splitter/plugins/framework-plugins.ts +7 -8
- package/src/core/code-splitter/plugins/react-refresh-ignored-route-exports.ts +2 -8
- package/src/core/code-splitter/plugins/react-stable-hmr-split-route-components.ts +10 -6
- package/src/core/code-splitter/plugins.ts +3 -2
- package/src/core/config.ts +11 -2
- package/src/core/{route-hmr-statement.ts → hmr/handle-route-update.ts} +85 -39
- package/src/core/hmr/index.ts +5 -0
- package/src/core/hmr/select-adapter.ts +32 -0
- package/src/core/hmr/vite-adapter.ts +47 -0
- package/src/core/hmr/webpack-adapter.ts +110 -0
- package/src/core/router-code-splitter-plugin.ts +5 -7
- package/src/core/router-composed-plugin.ts +60 -5
- package/src/core/router-hmr-plugin.ts +12 -9
- package/src/rspack.ts +37 -9
- package/src/webpack.ts +22 -9
- package/dist/cjs/core/hmr-hot-expression.cjs +0 -27
- package/dist/cjs/core/hmr-hot-expression.cjs.map +0 -1
- package/dist/cjs/core/hmr-hot-expression.d.cts +0 -6
- package/dist/cjs/core/route-hmr-statement.cjs.map +0 -1
- package/dist/cjs/core/route-hmr-statement.d.cts +0 -4
- package/dist/esm/core/hmr-hot-expression.d.ts +0 -6
- package/dist/esm/core/hmr-hot-expression.js +0 -23
- package/dist/esm/core/hmr-hot-expression.js.map +0 -1
- package/dist/esm/core/route-hmr-statement.d.ts +0 -4
- package/dist/esm/core/route-hmr-statement.js.map +0 -1
- package/src/core/hmr-hot-expression.ts +0 -31
|
@@ -2,24 +2,23 @@ import { createReactRefreshIgnoredRouteExportsPlugin } from './react-refresh-ign
|
|
|
2
2
|
import { createReactRefreshRouteComponentsPlugin } from './react-refresh-route-components'
|
|
3
3
|
import { createReactStableHmrSplitRouteComponentsPlugin } from './react-stable-hmr-split-route-components'
|
|
4
4
|
import type { ReferenceRouteCompilerPlugin } from '../plugins'
|
|
5
|
-
import type { Config } from '../../config'
|
|
5
|
+
import type { Config, HmrStyle } from '../../config'
|
|
6
6
|
|
|
7
7
|
export function getReferenceRouteCompilerPlugins(opts: {
|
|
8
8
|
targetFramework: Config['target']
|
|
9
9
|
addHmr?: boolean
|
|
10
|
-
|
|
10
|
+
hmrStyle?: HmrStyle
|
|
11
11
|
}): Array<ReferenceRouteCompilerPlugin> | undefined {
|
|
12
12
|
switch (opts.targetFramework) {
|
|
13
13
|
case 'react': {
|
|
14
14
|
if (opts.addHmr) {
|
|
15
|
+
const hmrStyle = opts.hmrStyle ?? 'vite'
|
|
15
16
|
return [
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
17
|
+
...(hmrStyle === 'vite'
|
|
18
|
+
? [createReactRefreshIgnoredRouteExportsPlugin()]
|
|
19
|
+
: []),
|
|
19
20
|
createReactRefreshRouteComponentsPlugin(),
|
|
20
|
-
createReactStableHmrSplitRouteComponentsPlugin({
|
|
21
|
-
hotExpression: opts.hmrHotExpression,
|
|
22
|
-
}),
|
|
21
|
+
createReactStableHmrSplitRouteComponentsPlugin({ hmrStyle }),
|
|
23
22
|
]
|
|
24
23
|
}
|
|
25
24
|
return undefined
|
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
import * as template from '@babel/template'
|
|
2
2
|
import * as t from '@babel/types'
|
|
3
|
-
import { createHmrHotExpressionAst } from '../../hmr-hot-expression'
|
|
4
3
|
import { getUniqueProgramIdentifier } from '../../utils'
|
|
5
4
|
import type { ReferenceRouteCompilerPlugin } from '../plugins'
|
|
6
5
|
|
|
7
6
|
const buildReactRefreshIgnoredRouteExportsStatements = template.statements(
|
|
8
7
|
`
|
|
9
|
-
const hot =
|
|
8
|
+
const hot = import.meta.hot
|
|
10
9
|
if (hot && typeof window !== 'undefined') {
|
|
11
10
|
;(hot.data ??= {})
|
|
12
11
|
const tsrReactRefresh = window.__TSR_REACT_REFRESH__ ??= (() => {
|
|
@@ -41,9 +40,7 @@ const buildRefreshAnchorStatement = template.statement(
|
|
|
41
40
|
{ syntacticPlaceholders: true },
|
|
42
41
|
)
|
|
43
42
|
|
|
44
|
-
export function createReactRefreshIgnoredRouteExportsPlugin(
|
|
45
|
-
hotExpression?: string
|
|
46
|
-
}): ReferenceRouteCompilerPlugin {
|
|
43
|
+
export function createReactRefreshIgnoredRouteExportsPlugin(): ReferenceRouteCompilerPlugin {
|
|
47
44
|
return {
|
|
48
45
|
name: 'react-refresh-ignored-route-exports',
|
|
49
46
|
onAddHmr(ctx) {
|
|
@@ -55,9 +52,6 @@ export function createReactRefreshIgnoredRouteExportsPlugin(opts?: {
|
|
|
55
52
|
ctx.programPath.pushContainer(
|
|
56
53
|
'body',
|
|
57
54
|
buildReactRefreshIgnoredRouteExportsStatements({
|
|
58
|
-
hotExpression: createHmrHotExpressionAst(
|
|
59
|
-
opts?.hotExpression ?? ctx.opts.hmrHotExpression,
|
|
60
|
-
),
|
|
61
55
|
moduleId: t.stringLiteral(ctx.opts.id),
|
|
62
56
|
}),
|
|
63
57
|
)
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as template from '@babel/template'
|
|
2
2
|
import * as t from '@babel/types'
|
|
3
|
-
import { createHmrHotExpressionAst } from '../../hmr-hot-expression'
|
|
4
3
|
import { getUniqueProgramIdentifier } from '../../utils'
|
|
4
|
+
import type { HmrStyle } from '../../config'
|
|
5
5
|
import type { ReferenceRouteCompilerPlugin } from '../plugins'
|
|
6
6
|
|
|
7
7
|
function capitalizeIdentifier(str: string) {
|
|
@@ -28,8 +28,14 @@ const buildStableSplitComponentStatements = template.statements(
|
|
|
28
28
|
},
|
|
29
29
|
)
|
|
30
30
|
|
|
31
|
-
|
|
32
|
-
|
|
31
|
+
function hotExpressionAstFor(hmrStyle: HmrStyle): t.Expression {
|
|
32
|
+
return template.expression.ast(
|
|
33
|
+
hmrStyle === 'webpack' ? 'import.meta.webpackHot' : 'import.meta.hot',
|
|
34
|
+
)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export function createReactStableHmrSplitRouteComponentsPlugin(opts: {
|
|
38
|
+
hmrStyle: HmrStyle
|
|
33
39
|
}): ReferenceRouteCompilerPlugin {
|
|
34
40
|
return {
|
|
35
41
|
name: 'react-stable-hmr-split-route-components',
|
|
@@ -49,9 +55,7 @@ export function createReactStableHmrSplitRouteComponentsPlugin(opts?: {
|
|
|
49
55
|
buildStableSplitComponentStatements({
|
|
50
56
|
stableComponentIdent,
|
|
51
57
|
hotDataKey: t.stringLiteral(hotDataKey),
|
|
52
|
-
hotExpression:
|
|
53
|
-
opts?.hotExpression ?? ctx.opts.hmrHotExpression,
|
|
54
|
-
),
|
|
58
|
+
hotExpression: hotExpressionAstFor(opts.hmrStyle),
|
|
55
59
|
lazyRouteComponentIdent: t.identifier(ctx.lazyRouteComponentIdent),
|
|
56
60
|
localImporterIdent: t.identifier(
|
|
57
61
|
ctx.splitNodeMeta.localImporterIdent,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type babel from '@babel/core'
|
|
2
2
|
import type * as t from '@babel/types'
|
|
3
|
-
import type { Config, DeletableNodes } from '../config'
|
|
3
|
+
import type { Config, DeletableNodes, HmrStyle } from '../config'
|
|
4
4
|
import type { CodeSplitGroupings } from '../constants'
|
|
5
5
|
import type { SplitNodeMeta } from './types'
|
|
6
6
|
|
|
@@ -11,7 +11,8 @@ export type CompileCodeSplitReferenceRouteOptions = {
|
|
|
11
11
|
filename: string
|
|
12
12
|
id: string
|
|
13
13
|
addHmr?: boolean
|
|
14
|
-
|
|
14
|
+
hmrStyle?: HmrStyle
|
|
15
|
+
hmrRouteId?: string
|
|
15
16
|
sharedBindings?: Set<string>
|
|
16
17
|
}
|
|
17
18
|
|
package/src/core/config.ts
CHANGED
|
@@ -72,8 +72,17 @@ export type CodeSplittingOptions = {
|
|
|
72
72
|
addHmr?: boolean
|
|
73
73
|
}
|
|
74
74
|
|
|
75
|
+
export type HmrStyle = 'vite' | 'webpack'
|
|
76
|
+
|
|
75
77
|
export type HmrOptions = {
|
|
76
|
-
|
|
78
|
+
/**
|
|
79
|
+
* Selects the HMR runtime style to emit code for.
|
|
80
|
+
* - `'vite'` (default): ESM `import.meta.hot` with Vite accept-callback semantics.
|
|
81
|
+
* - `'webpack'`: `import.meta.webpackHot` with webpack / Rspack `module.hot` re-execution semantics.
|
|
82
|
+
*
|
|
83
|
+
* Bundler-specific plugin entries (e.g. `rspack.ts`, `webpack.ts`) set this explicitly.
|
|
84
|
+
*/
|
|
85
|
+
style?: HmrStyle
|
|
77
86
|
}
|
|
78
87
|
|
|
79
88
|
const codeSplittingOptionsSchema = z.object({
|
|
@@ -99,7 +108,7 @@ export const configSchema = generatorConfigSchema.extend({
|
|
|
99
108
|
.object({
|
|
100
109
|
hmr: z
|
|
101
110
|
.object({
|
|
102
|
-
|
|
111
|
+
style: z.enum(['vite', 'webpack']).optional(),
|
|
103
112
|
})
|
|
104
113
|
.optional(),
|
|
105
114
|
vite: z
|
|
@@ -1,6 +1,3 @@
|
|
|
1
|
-
import * as template from '@babel/template'
|
|
2
|
-
import { createHmrHotExpressionAst } from './hmr-hot-expression'
|
|
3
|
-
import type * as t from '@babel/types'
|
|
4
1
|
import type {
|
|
5
2
|
AnyRoute,
|
|
6
3
|
AnyRouteMatch,
|
|
@@ -25,18 +22,23 @@ type AnyRouterWithPrivateMaps = AnyRouter & {
|
|
|
25
22
|
stores: AnyRouter['stores'] & {
|
|
26
23
|
cachedMatchStores: Map<
|
|
27
24
|
string,
|
|
28
|
-
Pick<RouterWritableStore<AnyRouteMatch>, 'set'>
|
|
25
|
+
Pick<RouterWritableStore<AnyRouteMatch>, 'get' | 'set'>
|
|
29
26
|
>
|
|
30
27
|
pendingMatchStores: Map<
|
|
31
28
|
string,
|
|
32
|
-
Pick<RouterWritableStore<AnyRouteMatch>, 'set'>
|
|
29
|
+
Pick<RouterWritableStore<AnyRouteMatch>, 'get' | 'set'>
|
|
30
|
+
>
|
|
31
|
+
matchStores: Map<
|
|
32
|
+
string,
|
|
33
|
+
Pick<RouterWritableStore<AnyRouteMatch>, 'get' | 'set'>
|
|
33
34
|
>
|
|
34
|
-
matchStores: Map<string, Pick<RouterWritableStore<AnyRouteMatch>, 'set'>>
|
|
35
35
|
}
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
type AnyRouteMatchWithPrivateProps = AnyRouteMatch & {
|
|
39
39
|
__beforeLoadContext?: unknown
|
|
40
|
+
__routeContext?: Record<string, unknown>
|
|
41
|
+
context?: Record<string, unknown>
|
|
40
42
|
}
|
|
41
43
|
|
|
42
44
|
function handleRouteUpdate(
|
|
@@ -69,14 +71,21 @@ function handleRouteUpdate(
|
|
|
69
71
|
}
|
|
70
72
|
})
|
|
71
73
|
|
|
74
|
+
const oldHasShellComponent = 'shellComponent' in oldRoute.options
|
|
75
|
+
const newHasShellComponent = 'shellComponent' in newRoute.options
|
|
76
|
+
const preserveComponentIdentity =
|
|
77
|
+
oldHasShellComponent === newHasShellComponent
|
|
78
|
+
|
|
72
79
|
// Preserve component identity so React doesn't remount.
|
|
73
80
|
// React Fast Refresh patches the function bodies in-place.
|
|
74
81
|
const componentKeys = '__TSR_COMPONENT_TYPES__' as unknown as Array<string>
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
82
|
+
if (preserveComponentIdentity) {
|
|
83
|
+
componentKeys.forEach((key) => {
|
|
84
|
+
if (key in oldRoute.options && key in newRoute.options) {
|
|
85
|
+
newRoute.options[key] = oldRoute.options[key]
|
|
86
|
+
}
|
|
87
|
+
})
|
|
88
|
+
}
|
|
80
89
|
|
|
81
90
|
oldRoute.options = newRoute.options
|
|
82
91
|
oldRoute.update(newRoute.options)
|
|
@@ -127,6 +136,7 @@ function handleRouteUpdate(
|
|
|
127
136
|
}
|
|
128
137
|
if (removedKeys.has('beforeLoad')) {
|
|
129
138
|
next.__beforeLoadContext = undefined
|
|
139
|
+
next.context = rebuildMatchContextWithoutBeforeLoad(next)
|
|
130
140
|
}
|
|
131
141
|
|
|
132
142
|
return next
|
|
@@ -153,37 +163,73 @@ function handleRouteUpdate(
|
|
|
153
163
|
node.optional?.forEach((child) => walkReplaceSegmentTree(route, child))
|
|
154
164
|
node.wildcard?.forEach((child) => walkReplaceSegmentTree(route, child))
|
|
155
165
|
}
|
|
156
|
-
}
|
|
157
166
|
|
|
158
|
-
|
|
167
|
+
function getStoreMatch(matchId: string) {
|
|
168
|
+
return (
|
|
169
|
+
router.stores.pendingMatchStores.get(matchId)?.get() ||
|
|
170
|
+
router.stores.matchStores.get(matchId)?.get() ||
|
|
171
|
+
router.stores.cachedMatchStores.get(matchId)?.get()
|
|
172
|
+
)
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
function getMatchList(matchId: string) {
|
|
176
|
+
const pendingMatches = router.stores.pendingMatches.get()
|
|
177
|
+
if (pendingMatches.some((match) => match.id === matchId)) {
|
|
178
|
+
return pendingMatches
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
const activeMatches = router.stores.matches.get()
|
|
182
|
+
if (activeMatches.some((match) => match.id === matchId)) {
|
|
183
|
+
return activeMatches
|
|
184
|
+
}
|
|
159
185
|
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
186
|
+
const cachedMatches = router.stores.cachedMatches.get()
|
|
187
|
+
if (cachedMatches.some((match) => match.id === matchId)) {
|
|
188
|
+
return cachedMatches
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
return []
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
function getParentMatch(match: AnyRouteMatch) {
|
|
195
|
+
const matchList = getMatchList(match.id)
|
|
196
|
+
const matchIndex = matchList.findIndex((item) => item.id === match.id)
|
|
197
|
+
|
|
198
|
+
if (matchIndex <= 0) {
|
|
199
|
+
return undefined
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
const parentMatch = matchList[matchIndex - 1]!
|
|
203
|
+
return getStoreMatch(parentMatch.id) || parentMatch
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
function rebuildMatchContextWithoutBeforeLoad(
|
|
207
|
+
match: AnyRouteMatchWithPrivateProps,
|
|
208
|
+
) {
|
|
209
|
+
const parentMatch = getParentMatch(match)
|
|
210
|
+
const getParentContext = (
|
|
211
|
+
router as unknown as {
|
|
212
|
+
getParentContext?: (
|
|
213
|
+
parentMatch?: AnyRouteMatch,
|
|
214
|
+
) => Record<string, unknown> | undefined
|
|
174
215
|
}
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
216
|
+
).getParentContext
|
|
217
|
+
const parentContext = getParentContext
|
|
218
|
+
? getParentContext.call(router, parentMatch)
|
|
219
|
+
: (parentMatch?.context ?? router.options.context)
|
|
220
|
+
|
|
221
|
+
return {
|
|
222
|
+
...(parentContext ?? {}),
|
|
223
|
+
...(match.__routeContext ?? {}),
|
|
179
224
|
}
|
|
180
|
-
|
|
225
|
+
}
|
|
181
226
|
}
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
227
|
+
|
|
228
|
+
const handleRouteUpdateStr = handleRouteUpdate.toString()
|
|
229
|
+
|
|
230
|
+
export function getHandleRouteUpdateCode(stableRouteOptionKeys: Array<string>) {
|
|
231
|
+
return handleRouteUpdateStr.replace(
|
|
232
|
+
/['"]__TSR_COMPONENT_TYPES__['"]/,
|
|
233
|
+
JSON.stringify(stableRouteOptionKeys),
|
|
234
|
+
)
|
|
189
235
|
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { createRouteHmrStatement } from './select-adapter'
|
|
2
|
+
export type { CreateRouteHmrStatementOpts } from './select-adapter'
|
|
3
|
+
export { createViteHmrStatement } from './vite-adapter'
|
|
4
|
+
export { createWebpackHmrStatement } from './webpack-adapter'
|
|
5
|
+
export { getHandleRouteUpdateCode } from './handle-route-update'
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { createViteHmrStatement } from './vite-adapter'
|
|
2
|
+
import { createWebpackHmrStatement } from './webpack-adapter'
|
|
3
|
+
import type { Config, HmrStyle } from '../config'
|
|
4
|
+
import type * as t from '@babel/types'
|
|
5
|
+
|
|
6
|
+
export type CreateRouteHmrStatementOpts = {
|
|
7
|
+
hmrStyle: HmrStyle
|
|
8
|
+
targetFramework: Config['target']
|
|
9
|
+
routeId?: string
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Dispatches to the configured HMR adapter. `hmrStyle` is set explicitly by
|
|
14
|
+
* the bundler-specific plugin entry (e.g. `rspack.ts` → `'webpack'`), so there
|
|
15
|
+
* is no runtime inference based on config string shapes.
|
|
16
|
+
*/
|
|
17
|
+
export function createRouteHmrStatement(
|
|
18
|
+
stableRouteOptionKeys: Array<string>,
|
|
19
|
+
opts: CreateRouteHmrStatementOpts,
|
|
20
|
+
): Array<t.Statement> {
|
|
21
|
+
const routeId = opts.routeId === '/__root' ? '__root__' : opts.routeId
|
|
22
|
+
|
|
23
|
+
if (opts.hmrStyle === 'webpack') {
|
|
24
|
+
return createWebpackHmrStatement(stableRouteOptionKeys, {
|
|
25
|
+
targetFramework: opts.targetFramework,
|
|
26
|
+
routeId,
|
|
27
|
+
})
|
|
28
|
+
}
|
|
29
|
+
return createViteHmrStatement(stableRouteOptionKeys, {
|
|
30
|
+
routeId,
|
|
31
|
+
})
|
|
32
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import * as template from '@babel/template'
|
|
2
|
+
import { getHandleRouteUpdateCode } from './handle-route-update'
|
|
3
|
+
import type * as t from '@babel/types'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Emits HMR accept code for Vite / native ESM HMR: `import.meta.hot.accept`
|
|
7
|
+
* with a callback that receives the freshly re-imported module.
|
|
8
|
+
*
|
|
9
|
+
* `targetFramework` is currently unused — Vite's framework-specific fast-refresh
|
|
10
|
+
* plugins handle component body patching via their own accept boundaries — but
|
|
11
|
+
* we take it for API symmetry with `createWebpackHmrStatement`.
|
|
12
|
+
*/
|
|
13
|
+
export function createViteHmrStatement(
|
|
14
|
+
stableRouteOptionKeys: Array<string>,
|
|
15
|
+
opts: {
|
|
16
|
+
routeId?: string
|
|
17
|
+
} = {},
|
|
18
|
+
): Array<t.Statement> {
|
|
19
|
+
const handleRouteUpdateCode = getHandleRouteUpdateCode(stableRouteOptionKeys)
|
|
20
|
+
// The replacement Route object can be uninitialized; keep a generated id as
|
|
21
|
+
// fallback for the existing router route we need to patch.
|
|
22
|
+
const routeIdFallback =
|
|
23
|
+
typeof opts.routeId === 'string' ? JSON.stringify(opts.routeId) : 'Route.id'
|
|
24
|
+
|
|
25
|
+
return [
|
|
26
|
+
template.statement(
|
|
27
|
+
`
|
|
28
|
+
if (import.meta.hot) {
|
|
29
|
+
const hot = import.meta.hot
|
|
30
|
+
const hotData = hot.data ??= {}
|
|
31
|
+
hot.accept((newModule) => {
|
|
32
|
+
if (Route && newModule && newModule.Route) {
|
|
33
|
+
const routeId = hotData['tsr-route-id'] ?? ${routeIdFallback}
|
|
34
|
+
if (routeId) {
|
|
35
|
+
hotData['tsr-route-id'] = routeId
|
|
36
|
+
}
|
|
37
|
+
(${handleRouteUpdateCode})(routeId, newModule.Route)
|
|
38
|
+
}
|
|
39
|
+
})
|
|
40
|
+
}
|
|
41
|
+
`,
|
|
42
|
+
{
|
|
43
|
+
syntacticPlaceholders: true,
|
|
44
|
+
},
|
|
45
|
+
)(),
|
|
46
|
+
]
|
|
47
|
+
}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import * as template from '@babel/template'
|
|
2
|
+
import { getHandleRouteUpdateCode } from './handle-route-update'
|
|
3
|
+
import type { Config } from '../config'
|
|
4
|
+
import type * as t from '@babel/types'
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Emits HMR accept code for bundlers with webpack-compatible `module.hot`
|
|
8
|
+
* semantics (classic webpack via `import.meta.webpackHot`, and Rspack).
|
|
9
|
+
*
|
|
10
|
+
* Unlike Vite's `hot.accept((newModule) => {...})` — where the callback receives
|
|
11
|
+
* the freshly re-imported module — webpack re-executes the module factory on
|
|
12
|
+
* accept, so our HMR logic must live at module top level and read the previous
|
|
13
|
+
* `routeId` out of `hot.data`. `hot.dispose` stashes it for the next run, and
|
|
14
|
+
* `hot.accept()` (no callback) enrolls us as a self-accepting boundary.
|
|
15
|
+
*
|
|
16
|
+
* Returns an array of statements so that for React we can prepend an
|
|
17
|
+
* `import { performReactRefresh } from 'react-refresh/runtime'` hoisted to the
|
|
18
|
+
* top of the module.
|
|
19
|
+
*/
|
|
20
|
+
export function createWebpackHmrStatement(
|
|
21
|
+
stableRouteOptionKeys: Array<string>,
|
|
22
|
+
opts: {
|
|
23
|
+
targetFramework: Config['target']
|
|
24
|
+
routeId?: string
|
|
25
|
+
},
|
|
26
|
+
): Array<t.Statement> {
|
|
27
|
+
const handleRouteUpdateCode = getHandleRouteUpdateCode(stableRouteOptionKeys)
|
|
28
|
+
const staticRouteIdLiteral =
|
|
29
|
+
typeof opts.routeId === 'string'
|
|
30
|
+
? JSON.stringify(opts.routeId)
|
|
31
|
+
: 'undefined'
|
|
32
|
+
|
|
33
|
+
const statements: Array<t.Statement> = []
|
|
34
|
+
|
|
35
|
+
// React-only: route modules aren't React Refresh "boundaries" (they export
|
|
36
|
+
// a non-component `Route`), so the bundler's react-refresh runtime won't
|
|
37
|
+
// call `performReactRefresh` for us. We kick it manually after swapping
|
|
38
|
+
// route options so newly-registered component bodies get patched into live
|
|
39
|
+
// fibers.
|
|
40
|
+
//
|
|
41
|
+
// We import `performReactRefresh` directly from `react-refresh/runtime` —
|
|
42
|
+
// the canonical public API — rather than relying on the ProvidePlugin-
|
|
43
|
+
// injected `__react_refresh_utils__` global, whose name is an internal
|
|
44
|
+
// detail of `@rspack/plugin-react-refresh`. The rspack plugin aliases
|
|
45
|
+
// `react-refresh` → its bundled runtime (getRefreshRuntimeDirPath), so this
|
|
46
|
+
// resolves to the same singleton the plugin itself uses and shares the
|
|
47
|
+
// registry React was patched against.
|
|
48
|
+
//
|
|
49
|
+
// Use the same delayed refresh style as Rspack's React Refresh runtime.
|
|
50
|
+
// Route modules and their split component chunks can arrive in separate HMR
|
|
51
|
+
// steps under CI load; a microtask can run before the split chunk registers
|
|
52
|
+
// its new component family, causing the refresh to no-op or remount.
|
|
53
|
+
//
|
|
54
|
+
// For non-React frameworks we skip this entirely.
|
|
55
|
+
const reactRefreshCall =
|
|
56
|
+
opts.targetFramework === 'react'
|
|
57
|
+
? `
|
|
58
|
+
const tsrRefreshState = globalThis.__TSR_HMR__ ??= {}
|
|
59
|
+
try {
|
|
60
|
+
if (!tsrRefreshState.refreshScheduled) {
|
|
61
|
+
tsrRefreshState.refreshScheduled = true
|
|
62
|
+
setTimeout(() => {
|
|
63
|
+
tsrRefreshState.refreshScheduled = false
|
|
64
|
+
try { __tsr_performReactRefresh() } catch (_e) { /* noop */ }
|
|
65
|
+
}, 30)
|
|
66
|
+
}
|
|
67
|
+
} catch (_err) { /* noop */ }`
|
|
68
|
+
: ''
|
|
69
|
+
|
|
70
|
+
if (opts.targetFramework === 'react') {
|
|
71
|
+
statements.push(
|
|
72
|
+
template.statement(
|
|
73
|
+
`import { performReactRefresh as __tsr_performReactRefresh } from 'react-refresh/runtime'`,
|
|
74
|
+
)(),
|
|
75
|
+
)
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
statements.push(
|
|
79
|
+
template.statement(
|
|
80
|
+
`
|
|
81
|
+
if (import.meta.webpackHot) {
|
|
82
|
+
const hot = import.meta.webpackHot
|
|
83
|
+
const hotData = hot.data ??= {}
|
|
84
|
+
const routeId = hotData['tsr-route-id'] ?? Route.id ?? (Route.isRoot ? '__root__' : ${staticRouteIdLiteral})
|
|
85
|
+
if (routeId) {
|
|
86
|
+
hotData['tsr-route-id'] = routeId
|
|
87
|
+
}
|
|
88
|
+
const existingRoute =
|
|
89
|
+
typeof window !== 'undefined' && routeId
|
|
90
|
+
? window.__TSR_ROUTER__?.routesById?.[routeId]
|
|
91
|
+
: undefined
|
|
92
|
+
if (routeId && existingRoute && existingRoute !== Route) {
|
|
93
|
+
(${handleRouteUpdateCode})(routeId, Route)${reactRefreshCall}
|
|
94
|
+
}
|
|
95
|
+
hot.dispose((data) => {
|
|
96
|
+
if (routeId) {
|
|
97
|
+
data['tsr-route-id'] = routeId
|
|
98
|
+
}
|
|
99
|
+
})
|
|
100
|
+
hot.accept()
|
|
101
|
+
}
|
|
102
|
+
`,
|
|
103
|
+
{
|
|
104
|
+
syntacticPlaceholders: true,
|
|
105
|
+
},
|
|
106
|
+
)(),
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
return statements
|
|
110
|
+
}
|
|
@@ -6,7 +6,6 @@
|
|
|
6
6
|
import { fileURLToPath, pathToFileURL } from 'node:url'
|
|
7
7
|
import { logDiff } from '@tanstack/router-utils'
|
|
8
8
|
import { getConfig, splitGroupingsSchema } from './config'
|
|
9
|
-
import { resolveHmrHotExpression } from './hmr-hot-expression'
|
|
10
9
|
import {
|
|
11
10
|
compileCodeSplitReferenceRoute,
|
|
12
11
|
compileCodeSplitSharedRoute,
|
|
@@ -129,7 +128,7 @@ export const unpluginRouterCodeSplitterFactory: UnpluginFactory<
|
|
|
129
128
|
const userShouldSplitFn = getShouldSplitFn()
|
|
130
129
|
|
|
131
130
|
const pluginSplitBehavior = userShouldSplitFn?.({
|
|
132
|
-
routeId: generatorNodeInfo.
|
|
131
|
+
routeId: generatorNodeInfo.routeId,
|
|
133
132
|
}) as CodeSplitGroupings | undefined
|
|
134
133
|
|
|
135
134
|
if (pluginSplitBehavior) {
|
|
@@ -158,9 +157,7 @@ export const unpluginRouterCodeSplitterFactory: UnpluginFactory<
|
|
|
158
157
|
|
|
159
158
|
const addHmr =
|
|
160
159
|
(userConfig.codeSplittingOptions?.addHmr ?? true) && !isProduction
|
|
161
|
-
const
|
|
162
|
-
userConfig.plugin?.hmr?.hotExpression,
|
|
163
|
-
)
|
|
160
|
+
const hmrStyle = userConfig.plugin?.hmr?.style ?? 'vite'
|
|
164
161
|
|
|
165
162
|
const compiledReferenceRoute = compileCodeSplitReferenceRoute({
|
|
166
163
|
code,
|
|
@@ -172,12 +169,13 @@ export const unpluginRouterCodeSplitterFactory: UnpluginFactory<
|
|
|
172
169
|
? new Set(userConfig.codeSplittingOptions.deleteNodes)
|
|
173
170
|
: undefined,
|
|
174
171
|
addHmr,
|
|
175
|
-
|
|
172
|
+
hmrStyle,
|
|
173
|
+
hmrRouteId: generatorNodeInfo.routeId,
|
|
176
174
|
sharedBindings: sharedBindings.size > 0 ? sharedBindings : undefined,
|
|
177
175
|
compilerPlugins: getReferenceRouteCompilerPlugins({
|
|
178
176
|
targetFramework: userConfig.target,
|
|
179
177
|
addHmr,
|
|
180
|
-
|
|
178
|
+
hmrStyle,
|
|
181
179
|
}),
|
|
182
180
|
})
|
|
183
181
|
|
|
@@ -3,15 +3,42 @@ import { unpluginRouterGeneratorFactory } from './router-generator-plugin'
|
|
|
3
3
|
import { unpluginRouterCodeSplitterFactory } from './router-code-splitter-plugin'
|
|
4
4
|
import { unpluginRouterHmrFactory } from './router-hmr-plugin'
|
|
5
5
|
import type { Config } from './config'
|
|
6
|
-
import type {
|
|
6
|
+
import type {
|
|
7
|
+
RspackCompiler,
|
|
8
|
+
UnpluginFactory,
|
|
9
|
+
UnpluginOptions,
|
|
10
|
+
WebpackCompiler,
|
|
11
|
+
} from 'unplugin'
|
|
12
|
+
|
|
13
|
+
const INLINE_CSS_DEFAULT_DEFINES = {
|
|
14
|
+
'process.env.TSS_INLINE_CSS_ENABLED': JSON.stringify('false'),
|
|
15
|
+
'import.meta.env.TSS_INLINE_CSS_ENABLED': JSON.stringify('false'),
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
type EsbuildOptionsWithDefine = Parameters<
|
|
19
|
+
NonNullable<NonNullable<UnpluginOptions['esbuild']>['config']>
|
|
20
|
+
>[0]
|
|
21
|
+
|
|
22
|
+
function applyWebpackInlineCssDefaultDefinePlugin(compiler: WebpackCompiler) {
|
|
23
|
+
new compiler.webpack.DefinePlugin(INLINE_CSS_DEFAULT_DEFINES).apply(compiler)
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function applyRspackInlineCssDefaultDefinePlugin(compiler: RspackCompiler) {
|
|
27
|
+
new compiler.webpack.DefinePlugin(INLINE_CSS_DEFAULT_DEFINES).apply(compiler)
|
|
28
|
+
}
|
|
7
29
|
|
|
8
30
|
export const unpluginRouterComposedFactory: UnpluginFactory<
|
|
9
|
-
Partial<Config> | undefined
|
|
31
|
+
Partial<Config | (() => Config)> | undefined
|
|
10
32
|
> = (options = {}, meta) => {
|
|
11
33
|
const ROOT: string = process.cwd()
|
|
12
|
-
const userConfig = getConfig(
|
|
34
|
+
const userConfig = getConfig(
|
|
35
|
+
(typeof options === 'function' ? options() : options) as Partial<Config>,
|
|
36
|
+
ROOT,
|
|
37
|
+
)
|
|
13
38
|
|
|
14
|
-
const getPlugin = (
|
|
39
|
+
const getPlugin = (
|
|
40
|
+
pluginFactory: UnpluginFactory<Partial<Config | (() => Config)>>,
|
|
41
|
+
) => {
|
|
15
42
|
const plugin = pluginFactory(options, meta)
|
|
16
43
|
if (!Array.isArray(plugin)) {
|
|
17
44
|
return [plugin]
|
|
@@ -22,7 +49,35 @@ export const unpluginRouterComposedFactory: UnpluginFactory<
|
|
|
22
49
|
const routerGenerator = getPlugin(unpluginRouterGeneratorFactory)
|
|
23
50
|
const routerCodeSplitter = getPlugin(unpluginRouterCodeSplitterFactory)
|
|
24
51
|
|
|
25
|
-
const result = [
|
|
52
|
+
const result = [
|
|
53
|
+
{
|
|
54
|
+
name: 'tanstack:router-inline-css-defaults',
|
|
55
|
+
vite: {
|
|
56
|
+
config() {
|
|
57
|
+
return {
|
|
58
|
+
define: {
|
|
59
|
+
...INLINE_CSS_DEFAULT_DEFINES,
|
|
60
|
+
},
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
},
|
|
64
|
+
webpack(compiler: WebpackCompiler) {
|
|
65
|
+
applyWebpackInlineCssDefaultDefinePlugin(compiler)
|
|
66
|
+
},
|
|
67
|
+
rspack(compiler: RspackCompiler) {
|
|
68
|
+
applyRspackInlineCssDefaultDefinePlugin(compiler)
|
|
69
|
+
},
|
|
70
|
+
esbuild: {
|
|
71
|
+
config(options: EsbuildOptionsWithDefine) {
|
|
72
|
+
options.define = {
|
|
73
|
+
...INLINE_CSS_DEFAULT_DEFINES,
|
|
74
|
+
...options.define,
|
|
75
|
+
}
|
|
76
|
+
},
|
|
77
|
+
},
|
|
78
|
+
},
|
|
79
|
+
...routerGenerator,
|
|
80
|
+
]
|
|
26
81
|
if (userConfig.autoCodeSplitting) {
|
|
27
82
|
result.push(...routerCodeSplitter)
|
|
28
83
|
}
|