@rangojs/router 0.12.1 → 0.12.3
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/vite/index.js
CHANGED
|
@@ -3746,7 +3746,7 @@ import { resolve } from "node:path";
|
|
|
3746
3746
|
// package.json
|
|
3747
3747
|
var package_default = {
|
|
3748
3748
|
name: "@rangojs/router",
|
|
3749
|
-
version: "0.12.
|
|
3749
|
+
version: "0.12.3",
|
|
3750
3750
|
description: "Django-inspired RSC router with composable URL patterns",
|
|
3751
3751
|
keywords: [
|
|
3752
3752
|
"react",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rangojs/router",
|
|
3
|
-
"version": "0.12.
|
|
3
|
+
"version": "0.12.3",
|
|
4
4
|
"description": "Django-inspired RSC router with composable URL patterns",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"react",
|
|
@@ -206,8 +206,8 @@
|
|
|
206
206
|
"esbuild": "^0.28.1",
|
|
207
207
|
"happy-dom": "^20.10.1",
|
|
208
208
|
"jiti": "^2.7.0",
|
|
209
|
-
"react": "^19.
|
|
210
|
-
"react-dom": "^19.
|
|
209
|
+
"react": "^19.3.0",
|
|
210
|
+
"react-dom": "^19.3.0",
|
|
211
211
|
"vitest": "^4.1.9",
|
|
212
212
|
"@shared/e2e": "0.0.1"
|
|
213
213
|
},
|
package/skills/catalog.json
CHANGED
|
@@ -197,7 +197,7 @@
|
|
|
197
197
|
},
|
|
198
198
|
{
|
|
199
199
|
"name": "react-compiler",
|
|
200
|
-
"description": "Enable the React Compiler in a Rango app
|
|
200
|
+
"description": "Enable the React Compiler in a Rango app with @vitejs/plugin-react 6.1's native `compiler` option (oxc-transform-react) — one flag, client components only, no Babel. Use when a consumer wants to turn React Compiler on, hits the dead plugin-react v6 `react({ babel })` path, sees an unmet-peer / ERESOLVE on oxc-transform-react, or is unsure why server components aren't being compiled.",
|
|
201
201
|
"argumentHint": "",
|
|
202
202
|
"path": "skills/react-compiler/SKILL.md"
|
|
203
203
|
},
|
package/skills/rango/SKILL.md
CHANGED
|
@@ -289,7 +289,7 @@ Grouped by concern — read when you need to…
|
|
|
289
289
|
| `/view-transitions` | React View Transitions on layouts, routes, and parallel slots |
|
|
290
290
|
| `/defer-hydration` | Full body HTML in the PPR shell + hydration off the critical path (gated Suspense boundary, content-as-fallback) |
|
|
291
291
|
| `/breadcrumbs` | Built-in Breadcrumbs handle for breadcrumb navigation |
|
|
292
|
-
| `/react-compiler` | Enable React Compiler (opt-in)
|
|
292
|
+
| `/react-compiler` | Enable React Compiler (opt-in) via plugin-react's native `compiler` option; client-only scope |
|
|
293
293
|
|
|
294
294
|
**Observability & production health**:
|
|
295
295
|
|
|
@@ -1,45 +1,49 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: react-compiler
|
|
3
|
-
description: Enable the React Compiler in a Rango app
|
|
3
|
+
description: Enable the React Compiler in a Rango app with @vitejs/plugin-react 6.1's native `compiler` option (oxc-transform-react) — one flag, client components only, no Babel. Use when a consumer wants to turn React Compiler on, hits the dead plugin-react v6 `react({ babel })` path, sees an unmet-peer / ERESOLVE on oxc-transform-react, or is unsure why server components aren't being compiled.
|
|
4
4
|
argument-hint:
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
# React Compiler
|
|
8
8
|
|
|
9
|
-
React Compiler is **opt-in** in Rango
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
9
|
+
React Compiler is **opt-in** in Rango, and it is one option on the plugin you
|
|
10
|
+
already have: `@vitejs/plugin-react` 6.1 ships a native React Compiler behind
|
|
11
|
+
`react({ compiler: true })`, backed by
|
|
12
|
+
[`oxc-transform-react`](https://www.npmjs.com/package/oxc-transform-react),
|
|
13
|
+
Oxc's Rust port of the compiler. No Babel, no extra plugin, no ordering rules.
|
|
14
|
+
Upstream marks the option experimental; the previous Babel wiring still works
|
|
15
|
+
and is kept below as the [fallback](#babel-fallback).
|
|
15
16
|
|
|
16
17
|
## The shape (read first)
|
|
17
18
|
|
|
18
|
-
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
app that plugin is `rango()` itself; in a Cloudflare app it is
|
|
24
|
-
`@cloudflare/vite-plugin`.
|
|
25
|
-
- **It is client-only.** `reactCompilerPreset()` gates itself to the client
|
|
26
|
-
environment. Server/RSC components are not compiled, and that is the upstream
|
|
27
|
-
example's behavior — not a Rango limitation. See
|
|
19
|
+
- **One option:** `react({ compiler: true })`. Needs `@vitejs/plugin-react` 6.1+
|
|
20
|
+
and its optional peer `oxc-transform-react`.
|
|
21
|
+
- **It is client-only.** plugin-react runs the compiler only in environments
|
|
22
|
+
whose `consumer` is not `"server"`. Server/RSC components are not compiled,
|
|
23
|
+
and that is plugin-react's contract — not a Rango limitation. See
|
|
28
24
|
[What gets compiled](#what-gets-compiled-client-only).
|
|
29
|
-
- **
|
|
30
|
-
|
|
25
|
+
- **It owns JSX and Fast Refresh too.** With `compiler` on, plugin-react hands
|
|
26
|
+
TypeScript, JSX and Fast Refresh to the same native pass and disables Vite's
|
|
27
|
+
built-in refresh injection. Nothing to configure, and dev line numbers still
|
|
28
|
+
point at your source.
|
|
29
|
+
- **Rango's build-time prerender is unaffected.** See
|
|
30
|
+
[Prerender](#interaction-with-build-time-prerender).
|
|
31
31
|
|
|
32
32
|
## Step 1: Install
|
|
33
33
|
|
|
34
34
|
```bash
|
|
35
|
-
pnpm add -D
|
|
36
|
-
# TypeScript users also want the Babel core types:
|
|
37
|
-
pnpm add -D @types/babel__core
|
|
35
|
+
pnpm add -D oxc-transform-react@^0.145.0
|
|
38
36
|
```
|
|
39
37
|
|
|
38
|
+
Take the range from `@vitejs/plugin-react`'s `peerDependencies` (`^0.145.0` for
|
|
39
|
+
6.1.x) rather than npm's latest. `oxc-transform-react` cuts a new minor every
|
|
40
|
+
couple of weeks and plugin-react widens its range in its own releases, so a newer
|
|
41
|
+
binding shows up as an unmet-peer warning under pnpm and an `ERESOLVE` error
|
|
42
|
+
under npm (vitejs/vite-plugin-react#1437). Bump both together.
|
|
43
|
+
|
|
40
44
|
React 19 ships `react/compiler-runtime` in-tree, so there is **no** extra runtime
|
|
41
|
-
to install and **no** `target` option to set. Only pass `target: '17' | '18'`
|
|
42
|
-
|
|
45
|
+
to install and **no** `target` option to set. Only pass `target: '17' | '18'` if
|
|
46
|
+
you are on an older React.
|
|
43
47
|
|
|
44
48
|
## Step 2: Wire it in
|
|
45
49
|
|
|
@@ -48,16 +52,11 @@ to install and **no** `target` option to set. Only pass `target: '17' | '18'` to
|
|
|
48
52
|
```ts
|
|
49
53
|
// vite.config.ts
|
|
50
54
|
import { defineConfig } from "vite";
|
|
51
|
-
import react
|
|
52
|
-
import babel from "@rolldown/plugin-babel";
|
|
55
|
+
import react from "@vitejs/plugin-react";
|
|
53
56
|
import { rango } from "@rangojs/router/vite";
|
|
54
57
|
|
|
55
58
|
export default defineConfig({
|
|
56
|
-
plugins: [
|
|
57
|
-
react(),
|
|
58
|
-
babel({ presets: [reactCompilerPreset()] }),
|
|
59
|
-
rango(), // supplies @vitejs/plugin-rsc
|
|
60
|
-
],
|
|
59
|
+
plugins: [react({ compiler: true }), rango()],
|
|
61
60
|
});
|
|
62
61
|
```
|
|
63
62
|
|
|
@@ -66,29 +65,29 @@ export default defineConfig({
|
|
|
66
65
|
```ts
|
|
67
66
|
// vite.config.ts
|
|
68
67
|
import { cloudflare } from "@cloudflare/vite-plugin";
|
|
69
|
-
import react
|
|
70
|
-
import babel from "@rolldown/plugin-babel";
|
|
68
|
+
import react from "@vitejs/plugin-react";
|
|
71
69
|
import { defineConfig } from "vite";
|
|
72
70
|
import { rango } from "@rangojs/router/vite";
|
|
73
71
|
|
|
74
72
|
export default defineConfig({
|
|
75
73
|
plugins: [
|
|
76
|
-
react(),
|
|
77
|
-
babel({ presets: [reactCompilerPreset()] }),
|
|
74
|
+
react({ compiler: true }),
|
|
78
75
|
rango({ preset: "cloudflare" }),
|
|
79
76
|
cloudflare({
|
|
80
77
|
/* ... */
|
|
81
|
-
}),
|
|
78
|
+
}),
|
|
82
79
|
],
|
|
83
80
|
});
|
|
84
81
|
```
|
|
85
82
|
|
|
83
|
+
Both layouts keep `react()` ahead of `rango()` / `cloudflare()`, which is what
|
|
84
|
+
Rango's own e2e apps run.
|
|
85
|
+
|
|
86
86
|
## What gets compiled (client-only)
|
|
87
87
|
|
|
88
|
-
`
|
|
89
|
-
`
|
|
90
|
-
|
|
91
|
-
`client` environment**:
|
|
88
|
+
plugin-react's `vite:react-compiler` transform runs in every environment, but
|
|
89
|
+
passes `reactCompiler: false` whenever `environment.config.consumer === "server"`.
|
|
90
|
+
Server environments only get the TypeScript/JSX pass:
|
|
92
91
|
|
|
93
92
|
| Environment | `consumer` | Compiled? |
|
|
94
93
|
| ----------- | ---------- | --------- |
|
|
@@ -96,43 +95,53 @@ even though the babel plugin is top-level, the transform runs **only in the
|
|
|
96
95
|
| ssr | `server` | No |
|
|
97
96
|
| rsc | `server` | No |
|
|
98
97
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
`babel-plugin-react-compiler` yourself without the preset's
|
|
102
|
-
`applyToEnvironmentHook` — that is outside what the example does and is not
|
|
98
|
+
If you genuinely need to compile **server** components, the native option cannot
|
|
99
|
+
do it; you would have to run `babel-plugin-react-compiler` yourself. That is not
|
|
103
100
|
covered here.
|
|
104
101
|
|
|
105
102
|
## Options
|
|
106
103
|
|
|
107
|
-
`
|
|
104
|
+
`compiler` takes `true` or the React Compiler configuration plus one plugin-level
|
|
105
|
+
flag:
|
|
106
|
+
|
|
107
|
+
| Option | Effect |
|
|
108
|
+
| ------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
109
|
+
| `compilationMode: 'annotation'` | Compile only components marked with the `"use memo"` directive, not every eligible one |
|
|
110
|
+
| `target: '17' \| '18'` | Emit `react-compiler-runtime` calls for React < 19. Omit on React 19+. |
|
|
111
|
+
| `logDiagnostics: true` | Log recoverable compiler diagnostics (why a component was skipped) through Vite. Default `false`. Fatal diagnostics always fail the transform. |
|
|
108
112
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
+
`logDiagnostics` can only relay what the binding reports. `oxc-transform-react`
|
|
114
|
+
0.145.x, the range plugin-react 6.1 declares, reports bail-out reasons. 0.148.0
|
|
115
|
+
dropped them (oxc-project/oxc#26318), so the flag goes silent once plugin-react's
|
|
116
|
+
peer range moves past it; 0.146 and 0.147 still report but need a later
|
|
117
|
+
plugin-react. Callback-valued Babel
|
|
118
|
+
options (`logger`, function-valued `sources`) do not exist on the native path;
|
|
119
|
+
`sources` takes an array of filename substrings.
|
|
113
120
|
|
|
114
121
|
## Interaction with build-time prerender
|
|
115
122
|
|
|
116
123
|
Nothing to configure. Rango's discovery/prerender step runs a throwaway temp Vite
|
|
117
124
|
server (`createTempRscServer`) that forwards only your **resolution** plugins
|
|
118
|
-
(`resolveId` / `load`)
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
125
|
+
(`resolveId` / `load`) and denies every `vite:*` plugin, so `vite:react-compiler`
|
|
126
|
+
never runs there. That is correct: the temp runner only produces **data**
|
|
127
|
+
(serialized Flight payloads + the route manifest), not shipped code, and React
|
|
128
|
+
Compiler is a memoization-only transform that does not change rendered output.
|
|
129
|
+
Your shipped client bundle is compiled by the `react({ compiler: true })` in your
|
|
130
|
+
app's own plugin array.
|
|
124
131
|
|
|
125
132
|
## Step 3: Verify the compiler actually ran
|
|
126
133
|
|
|
127
|
-
|
|
134
|
+
The native compiler emits the same shape as `babel-plugin-react-compiler`. A
|
|
135
|
+
compiled module imports the cache allocator from `react/compiler-runtime` and
|
|
128
136
|
calls `_c(n)`. Those two appear in **every** compiled module, so they are the
|
|
129
|
-
reliable per-module signal in dev
|
|
137
|
+
reliable per-module signal in dev, and a compiled module also carries Fast
|
|
138
|
+
Refresh's `$RefreshReg$(...)` registration:
|
|
130
139
|
|
|
131
140
|
```bash
|
|
132
141
|
pnpm dev
|
|
133
142
|
# fetch any client component module straight from Vite and look for the markers:
|
|
134
143
|
curl -s "http://localhost:5173/src/components/SomeClientComponent.tsx" \
|
|
135
|
-
| grep -E "compiler-runtime|_c\("
|
|
144
|
+
| grep -E "compiler-runtime|_c\(|\\\$RefreshReg\\\$\("
|
|
136
145
|
```
|
|
137
146
|
|
|
138
147
|
For a production build, grep the built client bundle for the compiler's
|
|
@@ -150,19 +159,48 @@ also defines that symbol once with a single `=` assignment, so count comparisons
|
|
|
150
159
|
not the bare string.) Run the same grep over `dist/rsc` / `dist/ssr` and you
|
|
151
160
|
should find **none** — that is the client-only contract.
|
|
152
161
|
|
|
162
|
+
Output is not byte-identical to Babel's: the port tracks React's experimental
|
|
163
|
+
compiler channel, so a handful of components memoize a different number of
|
|
164
|
+
values, and comments inside a compiled function body are dropped. Neither changes
|
|
165
|
+
rendered output.
|
|
166
|
+
|
|
167
|
+
## Babel fallback
|
|
168
|
+
|
|
169
|
+
On `@vitejs/plugin-react` < 6.1, or if you need a Babel-only compiler option, the
|
|
170
|
+
previous wiring still works: a top-level
|
|
171
|
+
[`@rolldown/plugin-babel`](https://www.npmjs.com/package/@rolldown/plugin-babel)
|
|
172
|
+
running `reactCompilerPreset()` from `@vitejs/plugin-react`, placed **after
|
|
173
|
+
`react()`** and **before the plugin that supplies `@vitejs/plugin-rsc`**. The
|
|
174
|
+
preset gates itself to `consumer === "client"`, so the client-only contract is
|
|
175
|
+
the same. Do not combine it with `compiler: true`.
|
|
176
|
+
|
|
177
|
+
```bash
|
|
178
|
+
pnpm add -D @rolldown/plugin-babel @babel/core babel-plugin-react-compiler @types/babel__core
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
```ts
|
|
182
|
+
import react, { reactCompilerPreset } from "@vitejs/plugin-react";
|
|
183
|
+
import babel from "@rolldown/plugin-babel";
|
|
184
|
+
|
|
185
|
+
// plugins: [react(), babel({ presets: [reactCompilerPreset()] }), rango()]
|
|
186
|
+
```
|
|
187
|
+
|
|
153
188
|
## Troubleshooting
|
|
154
189
|
|
|
155
|
-
| Symptom
|
|
156
|
-
|
|
|
157
|
-
|
|
|
158
|
-
|
|
|
159
|
-
| `
|
|
160
|
-
|
|
|
161
|
-
|
|
|
190
|
+
| Symptom | Cause / fix |
|
|
191
|
+
| ----------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
192
|
+
| `React Compiler requires the optional oxc-transform-react package` on startup | Install it (Step 1). plugin-react checks in its `config` hook, so the error is immediate. |
|
|
193
|
+
| Nothing is compiled; no `compiler-runtime` import anywhere | You used `react({ babel: { plugins: [...] } })`. plugin-react v6 has no internal Babel — use `react({ compiler: true })`. |
|
|
194
|
+
| pnpm warns `unmet peer oxc-transform-react`, npm fails with `ERESOLVE` | The binding is newer than plugin-react's peer range. Pin the range plugin-react declares. |
|
|
195
|
+
| Client compiled, but server/RSC components are not | Expected. The option is client-only (see the table). Not a bug. |
|
|
196
|
+
| `logDiagnostics: true` prints nothing | You are on `oxc-transform-react` 0.148.0 or later, which dropped recoverable diagnostics. On plugin-react 6.1.x stay on 0.145.x; 0.146 and 0.147 also report, but need a later plugin-react peer range. |
|
|
197
|
+
| Build pulls in `react-compiler-runtime` | You set `target: '17'`/`'18'` on React 19. Drop `target` — React 19 ships `react/compiler-runtime` in-tree. |
|
|
198
|
+
| Output looks compiled but a component misbehaves | The component likely breaks the Rules of React. Fix the component, or scope the compiler with `compilationMode: 'annotation'` while you do. |
|
|
162
199
|
|
|
163
200
|
## Reference
|
|
164
201
|
|
|
165
202
|
A worked, tested wiring (dev + production e2e markers, incl. the client-only
|
|
166
|
-
contract) lives in the `@rangojs/router` repository —
|
|
167
|
-
package: `docs/react-compiler.md` and the
|
|
168
|
-
`e2e/e2e-basic`, `tests/cloudflare-basic`,
|
|
203
|
+
contract and the Fast Refresh check) lives in the `@rangojs/router` repository —
|
|
204
|
+
not shipped in this package: `docs/react-compiler.md` and the
|
|
205
|
+
`react-compiler.test.ts` files under `e2e/e2e-basic`, `tests/cloudflare-basic`,
|
|
206
|
+
and `tests/vite-rsc-demo`.
|
|
@@ -9,9 +9,9 @@ argument-hint: [layout|route|parallel|intercept]
|
|
|
9
9
|
`transition()` opts a route (or group of routes) into transition-driven navigation. It does two things, and you choose how far to go:
|
|
10
10
|
|
|
11
11
|
1. **`startTransition` (the foundation).** The navigation commit is driven through React's `startTransition`. That holds the previous content across a same-route navigation (stale-while-revalidate — no loading-skeleton flash) and is the **precondition** for any view-transition animation. Works on **all** React versions.
|
|
12
|
-
2. **`<ViewTransition>` (the animation, layered on top).** On experimental
|
|
12
|
+
2. **`<ViewTransition>` (the animation, layered on top).** On React 19.3+ (or an experimental build), rango also wraps the segment content in React's `<ViewTransition>` so the swap cross-fades/morphs. This is the only part that needs 19.3+; pass `viewTransition: false` to keep #1 without it (and place your own `<ViewTransition>` where you want it).
|
|
13
13
|
|
|
14
|
-
> The `<ViewTransition>` layer requires React
|
|
14
|
+
> The `<ViewTransition>` layer requires a React that exports `<ViewTransition>` / `addTransitionType`: stable 19.3+ or an experimental build. Rango feature-detects it; on React 19.2 that layer is a no-op — but the `startTransition` driving (content hold) still applies.
|
|
15
15
|
|
|
16
16
|
## Purpose: `startTransition` vs `<ViewTransition>`
|
|
17
17
|
|
|
@@ -24,11 +24,11 @@ These are two **independent** mechanisms. `startTransition` controls _fallbacks_
|
|
|
24
24
|
|
|
25
25
|
The bottom-left cell is the key constraint: a view transition cannot exist without a `startTransition`. So once you reach for `transition()`, the only real choice is _startTransition_ vs _startTransition + ViewTransition_:
|
|
26
26
|
|
|
27
|
-
| What you want | Config | Effect
|
|
28
|
-
| -------------------------------------- | --------------------------------------------------- |
|
|
29
|
-
| nothing (default nav) | no `transition()` | remount + skeleton on param change
|
|
30
|
-
| `startTransition` only | `transition({ viewTransition: false })` | hold content; place your own `<ViewTransition>` where you want it
|
|
31
|
-
| `startTransition` + `<ViewTransition>` | `transition({})` / `transition({ enter, exit, … })` | hold + router cross-fade (experimental
|
|
27
|
+
| What you want | Config | Effect |
|
|
28
|
+
| -------------------------------------- | --------------------------------------------------- | ------------------------------------------------------------------------------------------------------------- |
|
|
29
|
+
| nothing (default nav) | no `transition()` | remount + skeleton on param change |
|
|
30
|
+
| `startTransition` only | `transition({ viewTransition: false })` | hold content; place your own `<ViewTransition>` where you want it |
|
|
31
|
+
| `startTransition` + `<ViewTransition>` | `transition({})` / `transition({ enter, exit, … })` | hold + router cross-fade (React 19.3+ or experimental; on 19.2 it degrades to the `startTransition`-only row) |
|
|
32
32
|
|
|
33
33
|
`createRouter({ viewTransition: "auto" \| false })` sets the app-wide default for the third row; a per-segment `viewTransition` wins. See [Opting out of the router boundary](#opting-out-of-the-router-boundary-place-your-own-viewtransition) for the full opt-out story.
|
|
34
34
|
|
|
@@ -322,6 +322,24 @@ On stable React the "VT" column is always a no-op (there is no `<ViewTransition>
|
|
|
322
322
|
|
|
323
323
|
> On **stable** React there is no `<ViewTransition>` at all, so `viewTransition: false` is visually a no-op there — but the startTransition driving and content-hold still apply, identical to `transition({})`.
|
|
324
324
|
|
|
325
|
+
## Testing a transition() route
|
|
326
|
+
|
|
327
|
+
On React 19.3+ a transition commit briefly keeps the exiting `<ViewTransition>`
|
|
328
|
+
host in the DOM next to the entering one (hidden, carrying React's `vt-*`
|
|
329
|
+
attributes) for a few hundred milliseconds. A strict Playwright locator on a
|
|
330
|
+
test id that exists in both the old and the new view (same route, different
|
|
331
|
+
params; a hard load followed by a revalidation commit) resolves to two elements
|
|
332
|
+
during that window. Target the entering host, which is appended after the
|
|
333
|
+
exiting one:
|
|
334
|
+
|
|
335
|
+
```ts
|
|
336
|
+
const page$ = page.getByTestId("feature-page").last();
|
|
337
|
+
await expect(page$).toBeVisible();
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
Waiting for `toHaveCount(1)` first is not enough: the count passes through 1
|
|
341
|
+
before the second host is inserted.
|
|
342
|
+
|
|
325
343
|
## Recommendations
|
|
326
344
|
|
|
327
345
|
**Put `<ParallelOutlet />` in layouts, not routes.** A route-level `transition` wraps the route component itself, so a `<ParallelOutlet />` rendered directly inside that route component remains inside the route VT subtree — modal opens on a route with a parallel outlet _will_ trigger the route's VT walker. The narrowing fix only applies at layout boundaries. If you combine intercept modals with route-level transitions, mount the slot one level up in a layout.
|
package/src/segment-system.tsx
CHANGED
|
@@ -40,8 +40,9 @@ function segDebugLog(msg: string, details?: Record<string, unknown>): void {
|
|
|
40
40
|
console.log(prefix);
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
-
// ViewTransition
|
|
44
|
-
//
|
|
43
|
+
// ViewTransition ships in React 19.3+ (and experimental builds); older stable
|
|
44
|
+
// releases lack it. Feature-detect via the namespace import so the router
|
|
45
|
+
// compiles against any supported React and degrades to a no-op boundary.
|
|
45
46
|
const ReactViewTransition: any =
|
|
46
47
|
"ViewTransition" in React ? (React as any).ViewTransition : null;
|
|
47
48
|
|
|
@@ -435,7 +436,7 @@ export async function renderSegments(
|
|
|
435
436
|
nodeContent = registerLazyRef(resolvedComponent);
|
|
436
437
|
}
|
|
437
438
|
|
|
438
|
-
// Wrap with <ViewTransition> if transition config exists (React experimental
|
|
439
|
+
// Wrap with <ViewTransition> if transition config exists (React 19.3+ / experimental).
|
|
439
440
|
// An empty config ({}) creates a bare <ViewTransition> boundary that participates
|
|
440
441
|
// in transitions without adding custom animation classes. Named element-level
|
|
441
442
|
// <ViewTransition> components inside (with name/share props) morph independently
|