Skip to content

Conversation

@edmundhung
Copy link
Contributor

@edmundhung edmundhung commented Jan 5, 2026

Fix #6023

It seems like the Vite preview server currently strip out the base path from the request URL. This prepends it back to restore the actual URL that hits the preview server.

We are also enforcing trailing slash to the prerendering requests so we won't get a 404 response when base path has a trailing slash.

One thing I am not sure though is the log output. The prerendered pages is not actually saved in a test folder but the logs makes it looks like that when I verify it with the start-basic-static example.

Without base path With base path
Prerendered 36 pages: Prerendered 37 pages:
- / - /
- /test/
- /users - /test/route-a
- /posts - /test/posts
- /route-a - /test/users
- /users/1 - /test/route-b
- /users/4 - /test/posts/1
- /users/5 - /test/posts/5
- /users/2 - /test/posts/4
- /users/3 - /test/posts/2
- /users/7 - /test/posts/3
- /users/6 - /test/posts/6
- /users/9 - /test/posts/7
- /users/10 - /test/posts/8
- /users/8 - /test/posts/9
- /posts/1 - /test/posts/10
- /posts/2 - /test/users/1
- /posts/3 - /test/users/2
- /posts/4 - /test/users/3
- /posts/5 - /test/users/4
- /posts/6 - /test/users/5
- /posts/7 - /test/users/6
- /posts/8 - /test/users/7
- /posts/9 - /test/users/8
- /posts/10 - /test/users/9
- /route-b - /test/users/10
- /posts/1/deep - /test/posts/1/deep
- /posts/2/deep - /test/posts/5/deep
- /posts/3/deep - /test/posts/4/deep
- /posts/5/deep - /test/posts/2/deep
- /posts/4/deep - /test/posts/3/deep
- /posts/6/deep - /test/posts/6/deep
- /posts/7/deep - /test/posts/7/deep
- /posts/8/deep - /test/posts/8/deep
- /posts/9/deep - /test/posts/9/deep
- /posts/10/deep - /test/posts/10/deep
- /deferred - /test/deferred

Summary by CodeRabbit

Release Notes

  • New Features
    • Added support for deploying applications to a subpath (e.g., /test/), enabling better flexibility for hosting configurations and routing resolution across the application.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 5, 2026

📝 Walkthrough

Walkthrough

This change adds custom base path support to the TanStack Start prerender and preview server workflows. Configuration examples are updated with a /test/ base path, the prerender fetch URL is wrapped with a trailing slash to ensure proper resolution, and the preview server middleware prepends the configured base path to incoming request URLs.

Changes

Cohort / File(s) Summary
Example Configuration
examples/react/start-basic-static/src/router.tsx, examples/react/start-basic-static/vite.config.ts
Added basepath: '/test/' to router creation and base: '/test/' to Vite config to demonstrate custom base path setup in test example.
Prerender Base Path Handling
packages/start-plugin-core/src/prerender.ts
Imported withTrailingSlash from 'ufo' and wrapped the fetch URL construction to ensure trailing slash is applied after base path resolution.
Preview Server Middleware
packages/start-plugin-core/src/preview-server-plugin/plugin.ts
Imported joinURL from 'ufo' and prepended the configured server base path to incoming request URLs before constructing NodeRequest and invoking the server build.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested reviewers

  • birkskyum

Poem

🐰 A test path springs from / to /test/,
With trailing slashes binding manifest and zest,
The prerender hops with URLs now blessed,
Base paths joined where server knows its nest!

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 title accurately describes the main purpose of the PR: adding support for Vite preview base path handling, which is the core issue being addressed.
Linked Issues check ✅ Passed The PR addresses all key coding requirements from issue #6023: prepending base path to preview requests, handling trailing slashes in prerender requests, and updating the example configuration.
Out of Scope Changes check ✅ Passed All changes directly address the base path support issue: router basepath configuration, Vite base configuration, prerender URL handling, and preview server middleware modifications are all scoped to the linked issue.
✨ Finishing touches
  • 📝 Generate docstrings

📜 Recent review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2ea1abb and b6f260e.

📒 Files selected for processing (4)
  • examples/react/start-basic-static/src/router.tsx
  • examples/react/start-basic-static/vite.config.ts
  • packages/start-plugin-core/src/prerender.ts
  • packages/start-plugin-core/src/preview-server-plugin/plugin.ts
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Use TypeScript strict mode with extensive type safety for all code

Files:

  • examples/react/start-basic-static/vite.config.ts
  • packages/start-plugin-core/src/prerender.ts
  • packages/start-plugin-core/src/preview-server-plugin/plugin.ts
  • examples/react/start-basic-static/src/router.tsx
**/*.{js,ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Implement ESLint rules for router best practices using the ESLint plugin router

Files:

  • examples/react/start-basic-static/vite.config.ts
  • packages/start-plugin-core/src/prerender.ts
  • packages/start-plugin-core/src/preview-server-plugin/plugin.ts
  • examples/react/start-basic-static/src/router.tsx
🧠 Learnings (7)
📓 Common learnings
Learnt from: nlynzaad
Repo: TanStack/router PR: 5182
File: e2e/react-router/basic-file-based/tests/non-nested-paths.spec.ts:167-172
Timestamp: 2025-09-22T00:56:53.426Z
Learning: In TanStack Router, underscores are intentionally stripped from route segments during path parsing, but preserved in base path segments. This is the expected behavior implemented in PR #5182.
Learnt from: nlynzaad
Repo: TanStack/router PR: 5182
File: e2e/react-router/basic-file-based/src/routes/non-nested/named/$baz_.bar.tsx:3-5
Timestamp: 2025-09-22T00:56:49.237Z
Learning: In TanStack Router, underscores are intentionally stripped from route segments (e.g., `$baz_` becomes `baz` in generated types) but should be preserved in base path segments. This is the correct behavior as of the fix in PR #5182.
📚 Learning: 2025-12-21T12:52:35.231Z
Learnt from: Sheraff
Repo: TanStack/router PR: 6171
File: packages/router-core/src/new-process-route-tree.ts:898-898
Timestamp: 2025-12-21T12:52:35.231Z
Learning: In `packages/router-core/src/new-process-route-tree.ts`, the matching logic intentionally allows paths without trailing slashes to match index routes with trailing slashes (e.g., `/a` can match `/a/` route), but not vice-versa (e.g., `/a/` cannot match `/a` layout route). This is implemented via the condition `!pathIsIndex || node.kind === SEGMENT_TYPE_INDEX` and is a deliberate design decision to provide better UX by being permissive with missing trailing slashes.

Applied to files:

  • packages/start-plugin-core/src/prerender.ts
  • examples/react/start-basic-static/src/router.tsx
📚 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/start-plugin-core/src/prerender.ts
  • examples/react/start-basic-static/src/router.tsx
📚 Learning: 2025-12-24T22:47:44.320Z
Learnt from: schiller-manuel
Repo: TanStack/router PR: 6211
File: e2e/react-start/i18n-paraglide/src/server.ts:6-6
Timestamp: 2025-12-24T22:47:44.320Z
Learning: In TanStack Router projects using `inlang/paraglide-js`, the callback passed to `paraglideMiddleware` should use `() => handler.fetch(req)` (referencing the outer `req`) instead of `({ request }) => handler.fetch(request)`. This is intentional because the router needs the untouched URL to perform its own rewrite logic with `deLocalizeUrl`/`localizeUrl`. The middleware's processed request would delocalize the URL and interfere with the router's rewrite handling.

Applied to files:

  • packages/start-plugin-core/src/prerender.ts
📚 Learning: 2025-12-17T02:17:55.086Z
Learnt from: schiller-manuel
Repo: TanStack/router PR: 6120
File: packages/router-generator/src/generator.ts:654-657
Timestamp: 2025-12-17T02:17:55.086Z
Learning: In `packages/router-generator/src/generator.ts`, pathless_layout routes must receive a `path` property when they have a `cleanedPath`, even though they are non-path routes. This is necessary because child routes inherit the path from their parent, and without this property, child routes would not have the correct full path at runtime.

Applied to files:

  • packages/start-plugin-core/src/prerender.ts
  • examples/react/start-basic-static/src/router.tsx
📚 Learning: 2025-12-06T15:03:07.223Z
Learnt from: CR
Repo: TanStack/router PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-06T15:03:07.223Z
Learning: Applies to **/*.{js,ts,tsx} : Implement ESLint rules for router best practices using the ESLint plugin router

Applied to files:

  • examples/react/start-basic-static/src/router.tsx
📚 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:

  • examples/react/start-basic-static/src/router.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
🔇 Additional comments (4)
examples/react/start-basic-static/vite.config.ts (1)

8-8: Verify whether example configuration changes should remain post-merge.

The addition of base: '/test/' effectively demonstrates the base path feature, but example applications typically use default configurations unless specifically showcasing a feature. Should this configuration be reverted before merging to keep the example in its default state, or is the intent to permanently demonstrate base path usage in this example?

packages/start-plugin-core/src/preview-server-plugin/plugin.ts (1)

47-48: Solid fix for Vite preview base path handling.

The implementation correctly restores the base path that Vite strips from incoming requests. joinURL from ufo safely handles edge cases like trailing slashes and ensures proper URL construction.

packages/start-plugin-core/src/prerender.ts (1)

167-167: Correct implementation of base path with trailing slash handling.

The nested use of withTrailingSlash(withBase(...)) properly constructs fetch URLs by:

  1. Applying the router base path via withBase
  2. Adding a trailing slash for directory-like paths while preserving file extensions (e.g., /page.html remains unchanged, but /about becomes /about/)

This aligns with the router's trailing slash matching behavior and fixes the issue where prerender was fetching from / instead of the configured base path.

examples/react/start-basic-static/src/router.tsx (1)

9-9: Router basepath aligns with Vite base configuration.

The basepath: '/test/' correctly matches the Vite base: '/test/' configuration in the config file, ensuring consistent routing. However, similar to the Vite config change, consider whether this example modification should be reverted before merge to maintain the example in its default state.


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 Jan 5, 2026

View your CI Pipeline Execution ↗ for commit b6f260e

Command Status Duration Result
nx affected --targets=test:eslint,test:unit,tes... ✅ Succeeded 17m 4s View ↗
nx run-many --target=build --exclude=examples/*... ✅ Succeeded 20s View ↗

☁️ Nx Cloud last updated this comment at 2026-01-06 20:12:34 UTC

@pkg-pr-new
Copy link

pkg-pr-new bot commented Jan 5, 2026

More templates

@tanstack/arktype-adapter

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

@tanstack/eslint-plugin-router

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

@tanstack/history

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

@tanstack/nitro-v2-vite-plugin

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

@tanstack/react-router

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

@tanstack/react-router-devtools

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

@tanstack/react-router-ssr-query

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

@tanstack/react-start

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

@tanstack/react-start-client

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

@tanstack/react-start-server

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

@tanstack/router-cli

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

@tanstack/router-core

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

@tanstack/router-devtools

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

@tanstack/router-devtools-core

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

@tanstack/router-generator

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

@tanstack/router-plugin

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

@tanstack/router-ssr-query-core

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

@tanstack/router-utils

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

@tanstack/router-vite-plugin

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

@tanstack/solid-router

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

@tanstack/solid-router-devtools

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

@tanstack/solid-router-ssr-query

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

@tanstack/solid-start

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

@tanstack/solid-start-client

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

@tanstack/solid-start-server

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

@tanstack/start-client-core

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

@tanstack/start-fn-stubs

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-fn-stubs@6304

@tanstack/start-plugin-core

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

@tanstack/start-server-core

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

@tanstack/start-static-server-functions

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

@tanstack/start-storage-context

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

@tanstack/valibot-adapter

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

@tanstack/virtual-file-routes

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

@tanstack/vue-router

npm i https://pkg.pr.new/TanStack/router/@tanstack/vue-router@6304

@tanstack/vue-router-devtools

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

@tanstack/vue-router-ssr-query

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

@tanstack/vue-start

npm i https://pkg.pr.new/TanStack/router/@tanstack/vue-start@6304

@tanstack/vue-start-client

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

@tanstack/vue-start-server

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

@tanstack/zod-adapter

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

commit: b6f260e

@nlynzaad
Copy link
Contributor

nlynzaad commented Jan 5, 2026

this looks good. I've resolved the prettier error on the import orders and merged main that includes updates for the failures on react-start-basic raw stream tests (these were flaky and was not due to any changes in this PR)

@nlynzaad nlynzaad merged commit 8e037ae into TanStack:main Jan 6, 2026
6 checks passed
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.

Prerender fails when using custom base path - attempts to fetch / instead of configured base path

2 participants