Skip to content

Conversation

@birkskyum
Copy link
Member

@birkskyum birkskyum commented Oct 29, 2025

closes #5636

Summary by CodeRabbit

  • New Features

    • Added a transition-enabled /transition route demonstrating param updates, suspense-driven async rendering, and preserved UI during navigation.
    • Root route creation now supports a customizable notFoundComponent for 404 rendering.
  • Behavioral Changes

    • Navigation now batches route match updates inside framework transitions to avoid loading flashes and keep previous content visible during transitions.
  • Tests

    • Added e2e tests verifying no loading flash during transitions.
    • Updated tests to use explicit async waits and skipped a couple of flaky cases.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 29, 2025

Walkthrough

Adds a new file-based /transition/ route and E2E test; relocates match commit and lifecycle hook execution into a framework startTransition batch; changes Solid Transitioner to delegate to Solid.startTransition; adjusts Suspense selection and synchronizes multiple tests to routing transition behavior.

Changes

Cohort / File(s) Summary
Transition Route & Generated Tree
e2e/solid-router/basic-file-based/src/routes/transition/index.tsx, e2e/solid-router/basic-file-based/src/routeTree.gen.ts
New file-route createFileRoute('/transition/') with search validation n: number and components that increment n inside a transition and render a suspended doubled value; route tree and public types updated to expose TransitionIndexRoute.
Transition E2E Test
e2e/solid-router/basic-file-based/tests/transition.spec.ts
New Playwright test that navigates to /transition, samples body text during navigation to assert no "Loading..." fallback, clicks to change search params, and verifies old values persist during transition and new values render after resolution.
Router Core Transition Wrapping
packages/router-core/src/router.ts
Move exiting/entering/staying match computation, cachedMatches update, clearExpiredCache, and lifecycle hook invocations (onLeave/onEnter/onStay) inside the provided startTransition batch so they execute within the framework transition context.
Solid Router Transitioner
packages/solid-router/src/Transitioner.tsx
router.startTransition changed from an async wrapper to a non-async delegator that calls Solid.startTransition(fn) and uses try/finally to reset isTransitioning; onBeforeRouteMount now uses createComputed.
Match / Suspense Selection
packages/solid-router/src/Match.tsx
ResolvedSuspenseBoundary condition expanded to consider PendingComponent() in addition to prior checks, affecting when Suspense/pending UI is chosen.
Tests: Synchronization & Expectations
packages/solid-router/tests/..., packages/react-router/tests/...
Multiple tests adjusted: update-count expectations changed, assertions wrapped in waitFor to synchronize with async updates, one flaky test skipped; files include store-updates-during-navigation.test.tsx, link.test.tsx, optional-path-params.test.tsx, useNavigate.test.tsx, and related fixtures.
Router Tests: notFound handling
packages/solid-router/tests/router.test.tsx
createRootRoute usage in tests updated to accept a notFoundComponent option; test asserts a provided not-found component mounts for 404 paths.

Sequence Diagram(s)

sequenceDiagram
    participant User as User Action
    participant App as Route Component
    participant RouterCore as Router Core
    participant Transitioner as Solid Transitioner
    participant Solid as Solid Runtime
    participant Suspense as Manual Suspense

    User->>App: click -> updateSearchParams()
    App->>RouterCore: navigate/update
    RouterCore->>Transitioner: call startTransition(fn)
    Transitioner->>Solid: Solid.startTransition(fn)
    rect rgb(210,230,250)
        RouterCore->>RouterCore: compute exiting/entering/staying matches
        RouterCore->>RouterCore: update cachedMatches / clearExpiredCache
        RouterCore->>RouterCore: invoke onLeave/onEnter/onStay
    end
    Suspense->>Suspense: hold old UI (no fallback) during transition
    Suspense->>App: when resources resolve -> render new UI
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

  • Focus areas:
    • packages/router-core/src/router.ts — correctness of state mutations, ordering, and lifecycle semantics inside transition batch.
    • packages/solid-router/src/Transitioner.tsx — ensure isTransitioning lifecycle and error handling preserved after signature change.
    • packages/solid-router/src/Match.tsx — verify Suspense selection edge cases.
    • E2E and unit test adjustments — ensure stable assertions and timeouts.

Possibly related PRs

Suggested reviewers

  • brenelz
  • schiller-manuel

Poem

🐰
I hopped the route and held the view,
Kept old bits warm while new ones grew,
startTransition wrapped the race,
Suspense stayed calm, no Loading face,
Hooray—smooth hops and brighter queue! 🥕✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The pull request title "fix(solid-router): make navigation transitions work" clearly and concisely describes the primary objective of the changeset. The title is specific to the solid-router package and accurately reflects the main focus on enabling navigation transitions, which is confirmed by the PR objectives and the core changes in router-core and solid-router packages. The title is appropriately scoped and avoids vague terminology.
Linked Issues Check ✅ Passed The pull request directly addresses issue #5636, which requires manual Suspense boundaries to transition on navigation rather than immediately showing fallback content. The core changes implement the necessary functionality: router-core/src/router.ts wraps match computations inside a startTransition context, solid-router/src/Transitioner.tsx properly delegates to Solid.startTransition with isTransitioning state management, and solid-router/src/Match.tsx updates the ResolvedSuspenseBoundary condition to consider PendingComponent, allowing Suspense boundaries to participate in transitions. The new E2E test demonstrates the fix works correctly by verifying that loading fallbacks do not appear during navigation transitions.
Out of Scope Changes Check ✅ Passed The substantive changes are all directly related to the objective of making navigation transitions work: modifications to router-core and solid-router for transition wrapping, the Match.tsx fix for Suspense boundary participation, and new test files demonstrating the feature. Updates to existing test files (count expectations, async assertions with waitFor) are necessary adjustments resulting from the new transition behavior affecting state update timing and counts; these are not extraneous additions but rather corrections to make tests pass with the new implementation. All changes align with fixing issue #5636.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch solid-navigation-transition

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@nx-cloud
Copy link

nx-cloud bot commented Oct 29, 2025

🤖 Nx Cloud AI Fix Eligible

An automatically generated fix could have helped fix failing tasks for this run, but Self-healing CI is disabled for this workspace. Visit workspace settings to enable it and get automatic fixes in future runs.

To disable these notifications, a workspace admin can disable them in workspace settings.


View your CI Pipeline Execution ↗ for commit 6b0d3e7

Command Status Duration Result
nx affected --targets=test:eslint,test:unit,tes... ❌ Failed 8m 7s View ↗
nx run-many --target=build --exclude=examples/*... ✅ Succeeded 1m 24s View ↗

☁️ Nx Cloud last updated this comment at 2025-11-02 13:30:06 UTC

@pkg-pr-new
Copy link

pkg-pr-new bot commented Oct 29, 2025

More templates

@tanstack/arktype-adapter

npm i https://pkg.pr.new/TanStack/router/@tanstack/arktype-adapter@5691

@tanstack/directive-functions-plugin

npm i https://pkg.pr.new/TanStack/router/@tanstack/directive-functions-plugin@5691

@tanstack/eslint-plugin-router

npm i https://pkg.pr.new/TanStack/router/@tanstack/eslint-plugin-router@5691

@tanstack/history

npm i https://pkg.pr.new/TanStack/router/@tanstack/history@5691

@tanstack/nitro-v2-vite-plugin

npm i https://pkg.pr.new/TanStack/router/@tanstack/nitro-v2-vite-plugin@5691

@tanstack/react-router

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-router@5691

@tanstack/react-router-devtools

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-router-devtools@5691

@tanstack/react-router-ssr-query

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-router-ssr-query@5691

@tanstack/react-start

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-start@5691

@tanstack/react-start-client

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-start-client@5691

@tanstack/react-start-server

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-start-server@5691

@tanstack/router-cli

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-cli@5691

@tanstack/router-core

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-core@5691

@tanstack/router-devtools

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-devtools@5691

@tanstack/router-devtools-core

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-devtools-core@5691

@tanstack/router-generator

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-generator@5691

@tanstack/router-plugin

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-plugin@5691

@tanstack/router-ssr-query-core

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-ssr-query-core@5691

@tanstack/router-utils

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-utils@5691

@tanstack/router-vite-plugin

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-vite-plugin@5691

@tanstack/server-functions-plugin

npm i https://pkg.pr.new/TanStack/router/@tanstack/server-functions-plugin@5691

@tanstack/solid-router

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-router@5691

@tanstack/solid-router-devtools

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-router-devtools@5691

@tanstack/solid-router-ssr-query

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-router-ssr-query@5691

@tanstack/solid-start

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-start@5691

@tanstack/solid-start-client

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-start-client@5691

@tanstack/solid-start-server

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-start-server@5691

@tanstack/start-client-core

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-client-core@5691

@tanstack/start-plugin-core

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-plugin-core@5691

@tanstack/start-server-core

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-server-core@5691

@tanstack/start-static-server-functions

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-static-server-functions@5691

@tanstack/start-storage-context

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-storage-context@5691

@tanstack/valibot-adapter

npm i https://pkg.pr.new/TanStack/router/@tanstack/valibot-adapter@5691

@tanstack/virtual-file-routes

npm i https://pkg.pr.new/TanStack/router/@tanstack/virtual-file-routes@5691

@tanstack/zod-adapter

npm i https://pkg.pr.new/TanStack/router/@tanstack/zod-adapter@5691

commit: 6b0d3e7

@birkskyum birkskyum marked this pull request as ready for review October 29, 2025 20:48
@birkskyum birkskyum changed the title solid navigation transitions fix(solid-router): make navigation transitions work Oct 29, 2025
Copy link
Contributor

@coderabbitai coderabbitai bot left a 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

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1ec3881 and 73b4984.

📒 Files selected for processing (5)
  • e2e/solid-router/basic-file-based/src/routeTree.gen.ts (11 hunks)
  • e2e/solid-router/basic-file-based/src/routes/transition/index.tsx (1 hunks)
  • e2e/solid-router/basic-file-based/tests/transition.spec.ts (1 hunks)
  • packages/router-core/src/router.ts (2 hunks)
  • packages/solid-router/src/Transitioner.tsx (2 hunks)
🧰 Additional context used
📓 Path-based instructions (5)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Use TypeScript in strict mode with extensive type safety across the codebase

Files:

  • e2e/solid-router/basic-file-based/tests/transition.spec.ts
  • packages/router-core/src/router.ts
  • packages/solid-router/src/Transitioner.tsx
  • e2e/solid-router/basic-file-based/src/routeTree.gen.ts
  • e2e/solid-router/basic-file-based/src/routes/transition/index.tsx
e2e/**

📄 CodeRabbit inference engine (AGENTS.md)

Store end-to-end tests under the e2e/ directory

Files:

  • e2e/solid-router/basic-file-based/tests/transition.spec.ts
  • e2e/solid-router/basic-file-based/src/routeTree.gen.ts
  • e2e/solid-router/basic-file-based/src/routes/transition/index.tsx
packages/router-core/**

📄 CodeRabbit inference engine (AGENTS.md)

Keep framework-agnostic core router logic in packages/router-core/

Files:

  • packages/router-core/src/router.ts
packages/{react-router,solid-router}/**

📄 CodeRabbit inference engine (AGENTS.md)

Implement React and Solid bindings/components only in packages/react-router/ and packages/solid-router/

Files:

  • packages/solid-router/src/Transitioner.tsx
**/src/routes/**

📄 CodeRabbit inference engine (AGENTS.md)

Place file-based routes under src/routes/ directories

Files:

  • e2e/solid-router/basic-file-based/src/routes/transition/index.tsx
🧠 Learnings (8)
📓 Common learnings
Learnt from: CR
PR: TanStack/router#0
File: AGENTS.md:0-0
Timestamp: 2025-09-23T17:36:12.598Z
Learning: Applies to packages/{react-router,solid-router}/** : Implement React and Solid bindings/components only in packages/react-router/ and packages/solid-router/
📚 Learning: 2025-10-08T08:11:47.088Z
Learnt from: nlynzaad
PR: TanStack/router#5402
File: packages/router-generator/tests/generator/no-formatted-route-tree/routeTree.nonnested.snapshot.ts:19-21
Timestamp: 2025-10-08T08:11:47.088Z
Learning: Test snapshot files in the router-generator tests directory (e.g., files matching the pattern `packages/router-generator/tests/generator/**/routeTree*.snapshot.ts` or `routeTree*.snapshot.js`) should not be modified or have issues flagged, as they are fixtures used to verify the generator's output and are intentionally preserved as-is.

Applied to files:

  • e2e/solid-router/basic-file-based/tests/transition.spec.ts
  • e2e/solid-router/basic-file-based/src/routeTree.gen.ts
  • e2e/solid-router/basic-file-based/src/routes/transition/index.tsx
📚 Learning: 2025-09-23T17:36:12.598Z
Learnt from: CR
PR: TanStack/router#0
File: AGENTS.md:0-0
Timestamp: 2025-09-23T17:36:12.598Z
Learning: Applies to packages/router-core/** : Keep framework-agnostic core router logic in packages/router-core/

Applied to files:

  • packages/router-core/src/router.ts
📚 Learning: 2025-09-23T17:36:12.598Z
Learnt from: CR
PR: TanStack/router#0
File: AGENTS.md:0-0
Timestamp: 2025-09-23T17:36:12.598Z
Learning: Applies to packages/{react-router,solid-router}/** : Implement React and Solid bindings/components only in packages/react-router/ and packages/solid-router/

Applied to files:

  • packages/solid-router/src/Transitioner.tsx
  • e2e/solid-router/basic-file-based/src/routeTree.gen.ts
  • e2e/solid-router/basic-file-based/src/routes/transition/index.tsx
📚 Learning: 2025-10-01T18:31:35.420Z
Learnt from: schiller-manuel
PR: TanStack/router#5330
File: e2e/react-start/custom-basepath/src/routeTree.gen.ts:58-61
Timestamp: 2025-10-01T18:31:35.420Z
Learning: Do not review files named `routeTree.gen.ts` in TanStack Router repositories, as these are autogenerated files that should not be manually modified.

Applied to files:

  • e2e/solid-router/basic-file-based/src/routeTree.gen.ts
  • e2e/solid-router/basic-file-based/src/routes/transition/index.tsx
📚 Learning: 2025-09-28T21:41:45.233Z
Learnt from: nlynzaad
PR: TanStack/router#5284
File: e2e/react-start/basic/server.js:50-0
Timestamp: 2025-09-28T21:41:45.233Z
Learning: In Express v5, catch-all routes must use named wildcards. Use `/*splat` to match everything except root path, or `/{*splat}` (with braces) to match including root path. The old `*` syntax is not allowed and will cause "Missing parameter name" errors. This breaking change requires explicit naming of wildcard parameters.

Applied to files:

  • e2e/solid-router/basic-file-based/src/routeTree.gen.ts
📚 Learning: 2025-10-14T18:59:33.990Z
Learnt from: FatahChan
PR: TanStack/router#5475
File: e2e/react-start/basic-prerendering/src/routes/redirect/$target/via-beforeLoad.tsx:8-0
Timestamp: 2025-10-14T18:59:33.990Z
Learning: In TanStack Router e2e test files, when a route parameter is validated at the route level (e.g., using zod in validateSearch or param validation), switch statements on that parameter do not require a default case, as the validation ensures only expected values will reach the switch.

Applied to files:

  • e2e/solid-router/basic-file-based/src/routes/transition/index.tsx
📚 Learning: 2025-09-23T17:36:12.598Z
Learnt from: CR
PR: TanStack/router#0
File: AGENTS.md:0-0
Timestamp: 2025-09-23T17:36:12.598Z
Learning: Applies to **/src/routes/** : Place file-based routes under src/routes/ directories

Applied to files:

  • e2e/solid-router/basic-file-based/src/routes/transition/index.tsx
🧬 Code graph analysis (2)
packages/router-core/src/router.ts (1)
packages/router-core/src/Matches.ts (1)
  • AnyRouteMatch (240-240)
packages/solid-router/src/Transitioner.tsx (1)
packages/solid-router/src/link.tsx (1)
  • isTransitioning (581-583)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Test
🔇 Additional comments (4)
packages/router-core/src/router.ts (2)

941-946: LGTM: Clean framework-agnostic extension point.

The wrapBatch hook provides a well-designed extension point for framework-specific transition handling. The default no-op implementation ensures backward compatibility while allowing frameworks like Solid to opt into custom batching behavior.

Based on coding guidelines


2105-2141: LGTM: Correct integration of wrapBatch for transition-aware batching.

The refactoring correctly hoists the match array declarations outside wrapBatch so they can be accessed by the lifecycle hooks (lines 2143-2154). The batch operation and cache cleanup are properly wrapped, enabling framework-specific transition handling while preserving the existing state update logic.

packages/solid-router/src/Transitioner.tsx (2)

64-71: LGTM: Proper async lifecycle management.

The try/finally block correctly ensures that isTransitioning is always reset, even if the navigation fails. The separation of concerns between tracking the transition state here and wrapping batch updates in wrapBatch is well-designed and clearly documented.

Based on coding guidelines


38-60: No actionable concerns found.

The jsdom detection in wrapBatch (line 48) is part of a multi-layered guard strategy that works correctly. The approach has three safety checks: isRealBrowser && !router.isServer && isTransitioning(). The test suite validates this behavior in both jsdom (standard tests) and server environments (server mode tests), confirming the detection works as intended. The fallback behavior—directly executing the callback—is safe in all scenarios where startTransition is skipped.

Comment on lines 17 to 39
const pollInterval = setInterval(async () => {
const text = await page.locator('body').textContent().catch(() => '')
if (text) bodyTexts.push(text)
}, 50)

// Click the increase button to trigger navigation with new search params
await page.getByTestId('increase-button').click()

// Wait a bit to capture text during the transition
await page.waitForTimeout(200)

clearInterval(pollInterval)

// Eventually, new values should appear
await expect(page.getByTestId('n-value')).toContainText('n: 2', {
timeout: 2000,
})
await expect(page.getByTestId('double-value')).toContainText('double: 4', {
timeout: 2000,
})
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Guard against leaking the polling interval on failures.

If any assertion between starting the interval and calling clearInterval throws (for example, the click hangs), the timer keeps running against a disposed page. That leaves an active handle in the worker and can make later tests flaky or hang. Please ensure the interval is always cleared via try/finally.

Apply this diff:

-  const pollInterval = setInterval(async () => {
-    const text = await page.locator('body').textContent().catch(() => '')
-    if (text) bodyTexts.push(text)
-  }, 50)
-
-  // Click the increase button to trigger navigation with new search params
-  await page.getByTestId('increase-button').click()
-
-  // Wait a bit to capture text during the transition
-  await page.waitForTimeout(200)
-
-  clearInterval(pollInterval)
+  const pollInterval = setInterval(async () => {
+    const text = await page.locator('body').textContent().catch(() => '')
+    if (text) bodyTexts.push(text)
+  }, 50)
+
+  try {
+    // Click the increase button to trigger navigation with new search params
+    await page.getByTestId('increase-button').click()
+
+    // Wait a bit to capture text during the transition
+    await page.waitForTimeout(200)
+  } finally {
+    clearInterval(pollInterval)
+  }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const pollInterval = setInterval(async () => {
const text = await page.locator('body').textContent().catch(() => '')
if (text) bodyTexts.push(text)
}, 50)
// Click the increase button to trigger navigation with new search params
await page.getByTestId('increase-button').click()
// Wait a bit to capture text during the transition
await page.waitForTimeout(200)
clearInterval(pollInterval)
// Eventually, new values should appear
await expect(page.getByTestId('n-value')).toContainText('n: 2', {
timeout: 2000,
})
await expect(page.getByTestId('double-value')).toContainText('double: 4', {
timeout: 2000,
})
const pollInterval = setInterval(async () => {
const text = await page.locator('body').textContent().catch(() => '')
if (text) bodyTexts.push(text)
}, 50)
try {
// Click the increase button to trigger navigation with new search params
await page.getByTestId('increase-button').click()
// Wait a bit to capture text during the transition
await page.waitForTimeout(200)
} finally {
clearInterval(pollInterval)
}
// Eventually, new values should appear
await expect(page.getByTestId('n-value')).toContainText('n: 2', {
timeout: 2000,
})
await expect(page.getByTestId('double-value')).toContainText('double: 4', {
timeout: 2000,
})
🤖 Prompt for AI Agents
In e2e/solid-router/basic-file-based/tests/transition.spec.ts around lines 17 to
36, the polling interval started before the click is not guaranteed to be
cleared if an assertion or click throws; wrap the actions that depend on the
interval (the click, waitForTimeout, and the subsequent assertions) inside a try
block and call clearInterval(pollInterval) in a finally block so the timer is
always cleared even on failures; ensure the finally runs before making further
cleanup or test teardown.

Copy link
Contributor

@coderabbitai coderabbitai bot left a 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

🧹 Nitpick comments (1)
packages/solid-router/src/Transitioner.tsx (1)

38-52: Consider caching the isRealBrowser check for performance.

The isRealBrowser computation runs on every wrapBatch invocation, which could be frequent during navigation. Since the browser environment doesn't change during the component lifecycle, consider computing this once during mount and storing it in a variable.

Apply this diff to optimize:

  const [isTransitioning, setIsTransitioning] = Solid.createSignal(false)
+
+ const isRealBrowser =
+   typeof window !== 'undefined' &&
+   typeof window.navigator !== 'undefined' &&
+   typeof window.navigator.userAgent === 'string' &&
+   !window.navigator.userAgent.includes('jsdom')

  router.wrapBatch = (fn: () => void) => {
-   const isRealBrowser =
-     typeof window !== 'undefined' &&
-     typeof window.navigator !== 'undefined' &&
-     typeof window.navigator.userAgent === 'string' &&
-     !window.navigator.userAgent.includes('jsdom')
-
    if (isRealBrowser && isTransitioning()) {
      Solid.startTransition(() => {
        fn()
      })
    } else {
      fn()
    }
  }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 05672a2 and 16ab243.

📒 Files selected for processing (2)
  • packages/router-core/src/router.ts (2 hunks)
  • packages/solid-router/src/Transitioner.tsx (2 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Use TypeScript in strict mode with extensive type safety across the codebase

Files:

  • packages/solid-router/src/Transitioner.tsx
  • packages/router-core/src/router.ts
packages/{react-router,solid-router}/**

📄 CodeRabbit inference engine (AGENTS.md)

Implement React and Solid bindings/components only in packages/react-router/ and packages/solid-router/

Files:

  • packages/solid-router/src/Transitioner.tsx
packages/router-core/**

📄 CodeRabbit inference engine (AGENTS.md)

Keep framework-agnostic core router logic in packages/router-core/

Files:

  • packages/router-core/src/router.ts
🧠 Learnings (3)
📓 Common learnings
Learnt from: CR
PR: TanStack/router#0
File: AGENTS.md:0-0
Timestamp: 2025-09-23T17:36:12.598Z
Learning: Applies to packages/{react-router,solid-router}/** : Implement React and Solid bindings/components only in packages/react-router/ and packages/solid-router/
Learnt from: nlynzaad
PR: TanStack/router#5402
File: packages/router-generator/tests/generator/no-formatted-route-tree/routeTree.nonnested.snapshot.ts:19-21
Timestamp: 2025-10-08T08:11:47.088Z
Learning: Test snapshot files in the router-generator tests directory (e.g., files matching the pattern `packages/router-generator/tests/generator/**/routeTree*.snapshot.ts` or `routeTree*.snapshot.js`) should not be modified or have issues flagged, as they are fixtures used to verify the generator's output and are intentionally preserved as-is.
Learnt from: CR
PR: TanStack/router#0
File: AGENTS.md:0-0
Timestamp: 2025-09-23T17:36:12.598Z
Learning: Applies to packages/router-core/** : Keep framework-agnostic core router logic in packages/router-core/
📚 Learning: 2025-09-23T17:36:12.598Z
Learnt from: CR
PR: TanStack/router#0
File: AGENTS.md:0-0
Timestamp: 2025-09-23T17:36:12.598Z
Learning: Applies to packages/{react-router,solid-router}/** : Implement React and Solid bindings/components only in packages/react-router/ and packages/solid-router/

Applied to files:

  • packages/solid-router/src/Transitioner.tsx
📚 Learning: 2025-09-23T17:36:12.598Z
Learnt from: CR
PR: TanStack/router#0
File: AGENTS.md:0-0
Timestamp: 2025-09-23T17:36:12.598Z
Learning: Applies to packages/router-core/** : Keep framework-agnostic core router logic in packages/router-core/

Applied to files:

  • packages/router-core/src/router.ts
🧬 Code graph analysis (2)
packages/solid-router/src/Transitioner.tsx (1)
packages/solid-router/src/link.tsx (1)
  • isTransitioning (581-583)
packages/router-core/src/router.ts (1)
packages/router-core/src/Matches.ts (1)
  • AnyRouteMatch (240-240)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Preview
  • GitHub Check: Test
🔇 Additional comments (4)
packages/solid-router/src/Transitioner.tsx (2)

23-23: Minor formatting change.

The extra blank line improves readability.


54-61: Excellent error handling improvement.

The try/finally block ensures isTransitioning is always reset, even if the transition function throws. This prevents the router from getting stuck in a transitioning state.

packages/router-core/src/router.ts (2)

949-954: Well-designed framework extension point.

The wrapBatch method provides a clean hook for framework-specific transition handling while keeping the core router framework-agnostic. The default no-op implementation and clear documentation make this easy for framework adapters to override.


2105-2141: Refactoring correctly enables framework-specific transition wrapping.

The refactored logic wraps the batch operation in wrapBatch, allowing framework adapters like Solid to inject transition handling around state updates. The match computation moved inside the wrapped context is necessary for Solid's reactivity tracking to work correctly.

The closure correctly captures exitingMatches, enteringMatches, and stayingMatches for use in lifecycle hooks after the batch completes.

Copy link
Contributor

@coderabbitai coderabbitai bot left a 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

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 367f8bf and 6fc2d8b.

📒 Files selected for processing (2)
  • packages/solid-router/src/Transitioner.tsx (2 hunks)
  • packages/solid-start/src/useServerFn.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/solid-router/src/Transitioner.tsx
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Use TypeScript in strict mode with extensive type safety across the codebase

Files:

  • packages/solid-start/src/useServerFn.ts
packages/{*-start,start-*}/**

📄 CodeRabbit inference engine (AGENTS.md)

Name and place Start framework packages under packages/-start/ or packages/start-/

Files:

  • packages/solid-start/src/useServerFn.ts
🧠 Learnings (2)
📓 Common learnings
Learnt from: CR
PR: TanStack/router#0
File: AGENTS.md:0-0
Timestamp: 2025-09-23T17:36:12.598Z
Learning: Applies to packages/{react-router,solid-router}/** : Implement React and Solid bindings/components only in packages/react-router/ and packages/solid-router/
Learnt from: nlynzaad
PR: TanStack/router#5402
File: packages/router-generator/tests/generator/no-formatted-route-tree/routeTree.nonnested.snapshot.ts:19-21
Timestamp: 2025-10-08T08:11:47.088Z
Learning: Test snapshot files in the router-generator tests directory (e.g., files matching the pattern `packages/router-generator/tests/generator/**/routeTree*.snapshot.ts` or `routeTree*.snapshot.js`) should not be modified or have issues flagged, as they are fixtures used to verify the generator's output and are intentionally preserved as-is.
Learnt from: CR
PR: TanStack/router#0
File: AGENTS.md:0-0
Timestamp: 2025-09-23T17:36:12.598Z
Learning: Applies to packages/router-core/** : Keep framework-agnostic core router logic in packages/router-core/
📚 Learning: 2025-10-01T18:30:26.591Z
Learnt from: schiller-manuel
PR: TanStack/router#5330
File: packages/router-core/src/router.ts:2231-2245
Timestamp: 2025-10-01T18:30:26.591Z
Learning: In `packages/router-core/src/router.ts`, the `resolveRedirect` method intentionally strips the router's origin from redirect URLs when they match (e.g., `https://foo.com/bar` → `/bar` for same-origin redirects) while preserving the full URL for cross-origin redirects. This logic should not be removed or simplified to use `location.publicHref` directly.

Applied to files:

  • packages/solid-start/src/useServerFn.ts
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Test
🔇 Additional comments (1)
packages/solid-start/src/useServerFn.ts (1)

21-26: Race condition concern is technically valid but requires architectural evaluation.

Concurrent server function calls do occur in practice (confirmed via Promise.all patterns in e2e tests), and the shared _isServerFnRedirect flag can indeed be cleared prematurely by the first redirect's finally() block while other navigations are in progress.

However, this pattern appears intentional for Solid's architecture—the comment states the flag exists to "skip Solid transitions" during server function redirects. React-start omits this flag entirely, suggesting different architectural needs between frameworks.

The suggested fix (passing flag as navigation options) requires verifying whether the router's navigation API supports this parameter. Alternatively, consider whether the race condition's actual impact (skipping the "skip transitions" behavior for concurrent redirects) warrants mitigation given the Solid-specific requirements.

err.options._fromLocation = router.state.location
return router.navigate(router.resolveRedirect(err).options)
// Mark this as a server function redirect to skip Solid transitions
;(router as any)._isServerFnRedirect = true
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Type safety violation: avoid any type assertion in strict TypeScript.

Using (router as any) bypasses TypeScript's type checking and defeats the purpose of strict mode. This creates a maintenance risk as the router's API evolves.

Consider one of these approaches:

Option 1: Add the flag to navigation options (preferred)

-        // Mark this as a server function redirect to skip Solid transitions
-        ;(router as any)._isServerFnRedirect = true
-        const result = router.navigate(router.resolveRedirect(err).options)
-        // Clear the flag after navigation starts
-        result.finally(() => {
-          ;(router as any)._isServerFnRedirect = false
-        })
-        return result
+        // Mark this as a server function redirect to skip Solid transitions
+        const result = router.navigate({
+          ...router.resolveRedirect(err).options,
+          _isServerFnRedirect: true,
+        })
+        return result

Option 2: Properly type the router extension

interface RouterWithServerFnFlag {
  _isServerFnRedirect?: boolean
}

// Then use:
(router as RouterWithServerFnFlag)._isServerFnRedirect = true

Option 1 is cleaner as it avoids shared mutable state and eliminates the need for the finally block.

🤖 Prompt for AI Agents
In packages/solid-start/src/useServerFn.ts around line 21 you assign a flag
using an any cast which breaks strict TypeScript; instead add a typed navigation
option (e.g., extend the existing navigate/redirect options type to include an
optional _isServerFnRedirect boolean) and pass that flag through the navigation
call so you can remove the (router as any) cast and the shared mutable
state/finally block; if you must keep the router mutation, declare a small
interface for the router extension with _isServerFnRedirect?: boolean and cast
to that interface rather than any.

@birkskyum birkskyum force-pushed the solid-navigation-transition branch from 6fc2d8b to 05672a2 Compare October 29, 2025 23:41
@birkskyum birkskyum requested review from brenelz and removed request for brenelz October 29, 2025 23:57
@birkskyum birkskyum force-pushed the solid-navigation-transition branch from 6b8192a to 29ffc5c Compare October 30, 2025 00:03
@birkskyum birkskyum added this to the catch up solid to react milestone Oct 30, 2025
@birkskyum birkskyum force-pushed the solid-navigation-transition branch 2 times, most recently from e1ef229 to 39dc575 Compare October 30, 2025 05:33
Copy link
Contributor

@coderabbitai coderabbitai bot left a 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

🧹 Nitpick comments (1)
packages/solid-router/tests/router.test.tsx (1)

1681-1685: Consider aligning this test with the similar loader test or clarifying the intent.

The root route now includes a notFoundComponent, but the similar test above (lines 1640-1676, "loader throws a notFound()") creates the root route without this option. Additionally, the specific route at lines 1700-1702 already defines its own notFoundComponent with identical content.

If this change is intentional to test fallback behavior or component precedence, consider adding a comment explaining the difference. Otherwise, for consistency and clarity, align both tests to use the same pattern.

</review_comment_end>

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 39dc575 and 2f53719.

📒 Files selected for processing (1)
  • packages/solid-router/tests/router.test.tsx (1 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Use TypeScript in strict mode with extensive type safety across the codebase

Files:

  • packages/solid-router/tests/router.test.tsx
packages/{react-router,solid-router}/**

📄 CodeRabbit inference engine (AGENTS.md)

Implement React and Solid bindings/components only in packages/react-router/ and packages/solid-router/

Files:

  • packages/solid-router/tests/router.test.tsx
🧠 Learnings (5)
📓 Common learnings
Learnt from: CR
PR: TanStack/router#0
File: AGENTS.md:0-0
Timestamp: 2025-09-23T17:36:12.598Z
Learning: Applies to packages/{react-router,solid-router}/** : Implement React and Solid bindings/components only in packages/react-router/ and packages/solid-router/
Learnt from: nlynzaad
PR: TanStack/router#5402
File: packages/router-generator/tests/generator/no-formatted-route-tree/routeTree.nonnested.snapshot.ts:19-21
Timestamp: 2025-10-08T08:11:47.088Z
Learning: Test snapshot files in the router-generator tests directory (e.g., files matching the pattern `packages/router-generator/tests/generator/**/routeTree*.snapshot.ts` or `routeTree*.snapshot.js`) should not be modified or have issues flagged, as they are fixtures used to verify the generator's output and are intentionally preserved as-is.
Learnt from: CR
PR: TanStack/router#0
File: AGENTS.md:0-0
Timestamp: 2025-09-23T17:36:12.598Z
Learning: Applies to packages/router-core/** : Keep framework-agnostic core router logic in packages/router-core/
📚 Learning: 2025-10-08T08:11:47.088Z
Learnt from: nlynzaad
PR: TanStack/router#5402
File: packages/router-generator/tests/generator/no-formatted-route-tree/routeTree.nonnested.snapshot.ts:19-21
Timestamp: 2025-10-08T08:11:47.088Z
Learning: Test snapshot files in the router-generator tests directory (e.g., files matching the pattern `packages/router-generator/tests/generator/**/routeTree*.snapshot.ts` or `routeTree*.snapshot.js`) should not be modified or have issues flagged, as they are fixtures used to verify the generator's output and are intentionally preserved as-is.

Applied to files:

  • packages/solid-router/tests/router.test.tsx
📚 Learning: 2025-09-23T17:36:12.598Z
Learnt from: CR
PR: TanStack/router#0
File: AGENTS.md:0-0
Timestamp: 2025-09-23T17:36:12.598Z
Learning: Applies to packages/{react-router,solid-router}/** : Implement React and Solid bindings/components only in packages/react-router/ and packages/solid-router/

Applied to files:

  • packages/solid-router/tests/router.test.tsx
📚 Learning: 2025-10-14T18:59:33.990Z
Learnt from: FatahChan
PR: TanStack/router#5475
File: e2e/react-start/basic-prerendering/src/routes/redirect/$target/via-beforeLoad.tsx:8-0
Timestamp: 2025-10-14T18:59:33.990Z
Learning: In TanStack Router e2e test files, when a route parameter is validated at the route level (e.g., using zod in validateSearch or param validation), switch statements on that parameter do not require a default case, as the validation ensures only expected values will reach the switch.

Applied to files:

  • packages/solid-router/tests/router.test.tsx
📚 Learning: 2025-10-01T18:30:26.591Z
Learnt from: schiller-manuel
PR: TanStack/router#5330
File: packages/router-core/src/router.ts:2231-2245
Timestamp: 2025-10-01T18:30:26.591Z
Learning: In `packages/router-core/src/router.ts`, the `resolveRedirect` method intentionally strips the router's origin from redirect URLs when they match (e.g., `https://foo.com/bar` → `/bar` for same-origin redirects) while preserving the full URL for cross-origin redirects. This logic should not be removed or simplified to use `location.publicHref` directly.

Applied to files:

  • packages/solid-router/tests/router.test.tsx
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Test

@birkskyum birkskyum force-pushed the solid-navigation-transition branch 2 times, most recently from 8087ee3 to 5c9998d Compare November 1, 2025 12:11
@birkskyum birkskyum force-pushed the solid-navigation-transition branch from 5c9998d to 6b0d3e7 Compare November 2, 2025 13:21
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

♻️ Duplicate comments (1)
e2e/solid-router/basic-file-based/tests/transition.spec.ts (1)

17-32: Always clear the polling interval.

If the click or wait throws, the interval keeps running against a torn-down page, leading to flaky tests. Wrap the interaction in try/finally and clear the interval in the finally block so it always tears down.

-  const pollInterval = setInterval(async () => {
-    const text = await page
-      .locator('body')
-      .textContent()
-      .catch(() => '')
-    if (text) bodyTexts.push(text)
-  }, 50)
-
-  // Click the increase button to trigger navigation with new search params
-  await page.getByTestId('increase-button').click()
-
-  // Wait a bit to capture text during the transition
-  await page.waitForTimeout(200)
-
-  clearInterval(pollInterval)
+  const pollInterval = setInterval(async () => {
+    const text = await page
+      .locator('body')
+      .textContent()
+      .catch(() => '')
+    if (text) bodyTexts.push(text)
+  }, 50)
+
+  try {
+    // Click the increase button to trigger navigation with new search params
+    await page.getByTestId('increase-button').click()
+
+    // Wait a bit to capture text during the transition
+    await page.waitForTimeout(200)
+  } finally {
+    clearInterval(pollInterval)
+  }
🧹 Nitpick comments (2)
packages/solid-router/tests/link.test.tsx (2)

785-793: Good synchronization for navigation side-effects.

The waitFor wrappers properly ensure that both the URL search parameters and DOM content have updated before assertions. This aligns with the PR's objective of handling navigation transitions correctly.

Consider consolidating the pathname assertion at line 788 into the first waitFor block for consistency:

     await waitFor(() => {
       expect(window.location.search).toBe('?page=2&filter=inactive')
+      expect(window.location.pathname).toBe('/posts')
     })
-    expect(window.location.pathname).toBe('/posts')

900-910: Navigation synchronization is correctly implemented.

The waitFor wrappers ensure navigation transitions complete before assertions, consistent with the fix for manual Suspense boundaries during navigation.

For consistency, consider consolidating the pathname assertion at line 903 into the first waitFor block:

     await waitFor(() => {
       expect(window.location.search).toBe('?page=2&filter=inactive')
+      expect(window.location.pathname).toBe('/Dashboard/posts')
     })
-    expect(window.location.pathname).toBe('/Dashboard/posts')
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5c9998d and 6b0d3e7.

📒 Files selected for processing (12)
  • e2e/solid-router/basic-file-based/src/routeTree.gen.ts (11 hunks)
  • e2e/solid-router/basic-file-based/src/routes/transition/index.tsx (1 hunks)
  • e2e/solid-router/basic-file-based/tests/transition.spec.ts (1 hunks)
  • packages/react-router/tests/store-updates-during-navigation.test.tsx (1 hunks)
  • packages/router-core/src/router.ts (1 hunks)
  • packages/solid-router/src/Match.tsx (1 hunks)
  • packages/solid-router/src/Transitioner.tsx (3 hunks)
  • packages/solid-router/tests/link.test.tsx (4 hunks)
  • packages/solid-router/tests/optional-path-params.test.tsx (1 hunks)
  • packages/solid-router/tests/router.test.tsx (1 hunks)
  • packages/solid-router/tests/store-updates-during-navigation.test.tsx (8 hunks)
  • packages/solid-router/tests/useNavigate.test.tsx (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (6)
  • packages/router-core/src/router.ts
  • e2e/solid-router/basic-file-based/src/routes/transition/index.tsx
  • packages/solid-router/tests/optional-path-params.test.tsx
  • packages/solid-router/tests/useNavigate.test.tsx
  • packages/react-router/tests/store-updates-during-navigation.test.tsx
  • packages/solid-router/src/Match.tsx
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Use TypeScript in strict mode with extensive type safety across the codebase

Files:

  • e2e/solid-router/basic-file-based/tests/transition.spec.ts
  • packages/solid-router/tests/store-updates-during-navigation.test.tsx
  • packages/solid-router/src/Transitioner.tsx
  • e2e/solid-router/basic-file-based/src/routeTree.gen.ts
  • packages/solid-router/tests/link.test.tsx
  • packages/solid-router/tests/router.test.tsx
e2e/**

📄 CodeRabbit inference engine (AGENTS.md)

Store end-to-end tests under the e2e/ directory

Files:

  • e2e/solid-router/basic-file-based/tests/transition.spec.ts
  • e2e/solid-router/basic-file-based/src/routeTree.gen.ts
packages/{react-router,solid-router}/**

📄 CodeRabbit inference engine (AGENTS.md)

Implement React and Solid bindings/components only in packages/react-router/ and packages/solid-router/

Files:

  • packages/solid-router/tests/store-updates-during-navigation.test.tsx
  • packages/solid-router/src/Transitioner.tsx
  • packages/solid-router/tests/link.test.tsx
  • packages/solid-router/tests/router.test.tsx
🧠 Learnings (9)
📓 Common learnings
Learnt from: CR
Repo: TanStack/router PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-09-23T17:36:12.598Z
Learning: Applies to packages/{react-router,solid-router}/** : Implement React and Solid bindings/components only in packages/react-router/ and packages/solid-router/
Learnt from: nlynzaad
Repo: TanStack/router PR: 5402
File: packages/router-generator/tests/generator/no-formatted-route-tree/routeTree.nonnested.snapshot.ts:19-21
Timestamp: 2025-10-08T08:11:47.088Z
Learning: Test snapshot files in the router-generator tests directory (e.g., files matching the pattern `packages/router-generator/tests/generator/**/routeTree*.snapshot.ts` or `routeTree*.snapshot.js`) should not be modified or have issues flagged, as they are fixtures used to verify the generator's output and are intentionally preserved as-is.
📚 Learning: 2025-10-08T08:11:47.088Z
Learnt from: nlynzaad
Repo: TanStack/router PR: 5402
File: packages/router-generator/tests/generator/no-formatted-route-tree/routeTree.nonnested.snapshot.ts:19-21
Timestamp: 2025-10-08T08:11:47.088Z
Learning: Test snapshot files in the router-generator tests directory (e.g., files matching the pattern `packages/router-generator/tests/generator/**/routeTree*.snapshot.ts` or `routeTree*.snapshot.js`) should not be modified or have issues flagged, as they are fixtures used to verify the generator's output and are intentionally preserved as-is.

Applied to files:

  • e2e/solid-router/basic-file-based/tests/transition.spec.ts
  • packages/solid-router/tests/store-updates-during-navigation.test.tsx
  • e2e/solid-router/basic-file-based/src/routeTree.gen.ts
  • packages/solid-router/tests/link.test.tsx
  • packages/solid-router/tests/router.test.tsx
📚 Learning: 2025-10-09T12:59:02.129Z
Learnt from: hokkyss
Repo: TanStack/router PR: 5418
File: e2e/react-start/custom-identifier-prefix/src/styles/app.css:19-21
Timestamp: 2025-10-09T12:59:02.129Z
Learning: In e2e test directories (paths containing `e2e/`), accessibility concerns like outline suppression patterns are less critical since the code is for testing purposes, not production use.

Applied to files:

  • e2e/solid-router/basic-file-based/tests/transition.spec.ts
📚 Learning: 2025-10-09T12:59:14.842Z
Learnt from: hokkyss
Repo: TanStack/router PR: 5418
File: e2e/react-start/custom-identifier-prefix/public/site.webmanifest:2-3
Timestamp: 2025-10-09T12:59:14.842Z
Learning: In e2e test fixtures (files under e2e directories), empty or placeholder values in configuration files like site.webmanifest are acceptable and should not be flagged unless the test specifically validates those fields.

Applied to files:

  • e2e/solid-router/basic-file-based/tests/transition.spec.ts
📚 Learning: 2025-09-23T17:36:12.598Z
Learnt from: CR
Repo: TanStack/router PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-09-23T17:36:12.598Z
Learning: Applies to packages/{react-router,solid-router}/** : Implement React and Solid bindings/components only in packages/react-router/ and packages/solid-router/

Applied to files:

  • packages/solid-router/tests/store-updates-during-navigation.test.tsx
  • packages/solid-router/src/Transitioner.tsx
  • e2e/solid-router/basic-file-based/src/routeTree.gen.ts
  • packages/solid-router/tests/link.test.tsx
  • packages/solid-router/tests/router.test.tsx
📚 Learning: 2025-10-01T18:31:35.420Z
Learnt from: schiller-manuel
Repo: TanStack/router PR: 5330
File: e2e/react-start/custom-basepath/src/routeTree.gen.ts:58-61
Timestamp: 2025-10-01T18:31:35.420Z
Learning: Do not review files named `routeTree.gen.ts` in TanStack Router repositories, as these are autogenerated files that should not be manually modified.

Applied to files:

  • e2e/solid-router/basic-file-based/src/routeTree.gen.ts
📚 Learning: 2025-09-28T21:41:45.233Z
Learnt from: nlynzaad
Repo: TanStack/router PR: 5284
File: e2e/react-start/basic/server.js:50-0
Timestamp: 2025-09-28T21:41:45.233Z
Learning: In Express v5, catch-all routes must use named wildcards. Use `/*splat` to match everything except root path, or `/{*splat}` (with braces) to match including root path. The old `*` syntax is not allowed and will cause "Missing parameter name" errors. This breaking change requires explicit naming of wildcard parameters.

Applied to files:

  • e2e/solid-router/basic-file-based/src/routeTree.gen.ts
📚 Learning: 2025-10-01T18:30:26.591Z
Learnt from: schiller-manuel
Repo: TanStack/router PR: 5330
File: packages/router-core/src/router.ts:2231-2245
Timestamp: 2025-10-01T18:30:26.591Z
Learning: In `packages/router-core/src/router.ts`, the `resolveRedirect` method intentionally strips the router's origin from redirect URLs when they match (e.g., `https://foo.com/bar` → `/bar` for same-origin redirects) while preserving the full URL for cross-origin redirects. This logic should not be removed or simplified to use `location.publicHref` directly.

Applied to files:

  • packages/solid-router/tests/router.test.tsx
📚 Learning: 2025-09-23T17:36:12.598Z
Learnt from: CR
Repo: TanStack/router PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-09-23T17:36:12.598Z
Learning: Applies to packages/router-core/** : Keep framework-agnostic core router logic in packages/router-core/

Applied to files:

  • packages/solid-router/tests/router.test.tsx
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Test
  • GitHub Check: Preview
🔇 Additional comments (1)
packages/solid-router/tests/link.test.tsx (1)

396-399: LGTM! Proper synchronization for navigation transition.

The addition of waitFor ensures the navigation has completed and the link has acquired the 'active' class before proceeding with subsequent assertions. This properly handles the asynchronous nature of navigation transitions.

Comment on lines +38 to 47
router.startTransition = (fn: () => void | Promise<void>) => {
setIsTransitioning(true)
await fn()
setIsTransitioning(false)
Solid.startTransition(async () => {
try {
await fn()
} finally {
setIsTransitioning(false)
}
})
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Don’t hand Solid.startTransition an async callback.

Solid’s startTransition expects a synchronous callback. Giving it an async function means the awaited part runs after Solid has already ended the transition, so updates escape the transition and errors become unhandled rejections. Run fn synchronously (capture its promise separately) and only await it outside the transition to keep semantics intact.

🤖 Prompt for AI Agents
In packages/solid-router/src/Transitioner.tsx around lines 38 to 47, the code
passes an async callback to Solid.startTransition which breaks transition
semantics; instead call Solid.startTransition with a synchronous function that
invokes fn() but does not await it, capture the returned promise in a local
variable, then await that promise outside the transition in a finally block that
resets setIsTransitioning(false) so the awaited work runs after Solid ends the
transition and any errors can be handled properly.

⚠️ Potential issue | 🔴 Critical

Maintain startTransition’s async contract.

router.startTransition used to resolve once the wrapped work finished. After this refactor it always returns void, so any callers still doing await router.startTransition(...) now resume immediately, which can break sequencing and let isTransitioning drop before the work finishes. Please restore the async return (e.g. by returning the Promise from Solid.startTransition).

🤖 Prompt for AI Agents
In packages/solid-router/src/Transitioner.tsx around lines 38 to 47,
router.startTransition currently returns void causing callers that await it to
resume immediately; restore the async contract by returning a Promise that
resolves when the wrapped work completes. Change the implementation to return
the Promise from Solid.startTransition (or wrap the async work in a new Promise)
so callers can await completion, ensure setIsTransitioning(true) is set before
starting and setIsTransitioning(false) in finally after the awaited work, and
propagate any errors to the returned Promise.

})

test('Router.preload="intent", pendingComponent renders during unresolved route loader', async () => {
test.skip('Router.preload="intent", pendingComponent renders during unresolved route loader', async () => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Clarify why this critical test is skipped.

This test validates that pendingComponent renders during an unresolved route loader, which is directly related to the PR's objective of fixing navigation transitions with Suspense boundaries. Skipping it without explanation is concerning.

Please explain why this test is being skipped:

  1. Does the new navigation transition behavior intentionally change how pendingComponent works?
  2. Is this a temporary skip while the implementation is in progress?
  3. Does the test need to be rewritten to match the new transition behavior?

If the behavior has changed intentionally, the test should be updated rather than skipped. If there's a regression, it should be fixed before merging.


🏁 Script executed:

#!/bin/bash
# Retrieve the test file content around line 4358
cat packages/solid-router/tests/link.test.tsx | sed -n '4340,4380p'

Length of output: 1096


🏁 Script executed:

#!/bin/bash
# Search for any context around the skipped test - look for comments explaining why
sed -n '4350,4370p' packages/solid-router/tests/link.test.tsx | cat -A

Length of output: 689


🏁 Script executed:

#!/bin/bash
# Search for TODO, FIXME, or skip-related comments in the test file
rg -n 'skip|TODO|FIXME' packages/solid-router/tests/link.test.tsx -A2 -B2 | head -50

Length of output: 217


🏁 Script executed:

#!/bin/bash
# Check if there are any recent changes or comments mentioning pendingComponent
rg -n 'pendingComponent' packages/solid-router/tests/link.test.tsx -B3 -A3

Length of output: 308


🏁 Script executed:

#!/bin/bash
# Get the full implementation of the skipped test
sed -n '4358,4420p' packages/solid-router/tests/link.test.tsx

Length of output: 1768


🏁 Script executed:

#!/bin/bash
# Search for other pendingComponent references in tests
rg -n 'pendingComponent' packages/solid-router/tests/ -B2 -A2

Length of output: 2016


🏁 Script executed:

#!/bin/bash
# Check source code for pendingComponent implementation
rg -n 'pendingComponent' packages/solid-router/src/ -B2 -A2

Length of output: 1594


🏁 Script executed:

#!/bin/bash
# Look for any related changes or comments about navigation transitions
rg -n 'preload.*intent' packages/solid-router/tests/link.test.tsx -B3 -A3

Length of output: 524


Remove test.skip() or add explanation for why this critical test is disabled.

This test validates that pendingComponent renders during navigation with preload="intent", which is core to the PR's objective. The test is complete and properly implemented, yet skipped without any comment explaining why.

If the behavior has intentionally changed, update the test expectations. If there's a known issue, document it with a TODO comment. If this is temporary, the test must be re-enabled before merging.

🤖 Prompt for AI Agents
In packages/solid-router/tests/link.test.tsx around line 4358, the test is
marked with test.skip which disables a critical test; either re-enable the test
by removing .skip, or if skipping is intentional, add a clear inline
comment/TODO explaining why (linking an issue or describing expected behavioral
change) and include a plan/date to restore it; if the behavior changed, update
the test expectations to match the new behavior instead of skipping.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

solid-router: manual suspense boundaries don't transition on navigation

3 participants