TanStack / TanStack/router

[Bug] CSS `?url` import broken with experimental.bundledDev — Tailwind v4 `@import` not processed and URL resolution is unstable

Open
#7,488 1 comment 3 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

needs-upstream-fix
Dominant language
TypeScript
Stars
15.1k
Forks
1.9k
Avg merge
1d 20h
Merged PRs (30d)
143

Description

Which project does this relate to?

Start

Describe the bug

With experimental: { bundledDev: true } in Vite 8, the standard TanStack Start CSS pattern from the docs fails:

import appCss from '../styles.css?url'
// ...
links: [{ rel: 'stylesheet', href: appCss }]

The failure mode is not consistent — across reloads and version bumps I observed three distinct broken behaviors against the latest packages (react-start@1.168.13, start-plugin-core@1.171.6, start-server-core@1.169.4, react-router@1.170.8, vite@8.0.13, @tailwindcss/vite@4.3.0).

Mode A — hashed URL returns unprocessed source

?url resolves to /assets/styles-<hash>.css. The dev server returns 200 OK, but the body is essentially the raw source CSS — the Tailwind v4 plugin's transform never ran. Source src/styles.css is:

@import './fonts.css';
@import 'tailwindcss';
@import './transitions.css';

So the browser tries to fetch each of those at runtime:

URL Status Note
/assets/styles-crgemPDo.css 200 (9.3 kB) matches source file size, not the ~35 kB of expanded Tailwind
/<base>/fonts.css 404 unresolved CSS @import
/<base>/tailwindcss 404 Tailwind v4 bare-specifier resolution didn't run
/<base>/transitions.css 404 unresolved CSS @import

Mode B — relative URL

?url resolves to a bare relative string like "styles.css". The browser resolves it against the current page URL (e.g. /?search=foo) → /styles.css -> 404. The 16 kB body is Vite's HTML error page.

Mode C — source path

?url resolves to /src/styles.css (the path the unbundled-dev transform middleware would normally serve). In bundledDev that middleware is disabled, so → 404 with the same HTML error page body.

All three modes produce an unstyled page.

Complete minimal reproducer

https://github.com/nikilok/learn-tanstack-start/pull/127

The PR enables experimental.bundledDev: true and demonstrates the working ?inline workaround. To reproduce this bug, undo the ?inline workaround:

  1. In apps/web/src/routes/__root.tsx, change import appCss from '../styles.css?inline' back to import appCss from '../styles.css?url'.
  2. Remove the inline <style dangerouslySetInnerHTML={{ __html: appCss }} /> tag from <head>.
  3. Add { rel: 'stylesheet', href: appCss } back into the route's head.links array.
Steps to Reproduce the Bug
  1. Check out the PR and apply the diff above.
  2. bun install and bun dev.
  3. Load the app in a browser.
  4. Observe in the Network tab: a styles*.css 404 and/or 404s for tailwindcss, fonts.css, transitions.css — page renders unstyled.
Expected behavior

?url should resolve to a URL whose response is the fully processed CSS (Tailwind expanded, @imports inlined), the way it does in vite build and the way ?inline does in dev. The pattern in the docs should work in bundledDev mode.

Screenshots or Videos

Browser Network tab in Mode A (all three CSS-pipeline failures visible simultaneously):

styles.css                            404   stylesheet   15.6 kB
styles.css?routes=__root__%2C%2F      200   stylesheet    0.6 kB   (dev-styles middleware, OK)
styles-crgemPDo.css                   200   stylesheet    9.3 kB   (unprocessed source!)
fonts.css                             404   stylesheet   15.6 kB
tailwindcss                           404   stylesheet   15.6 kB
transitions.css                       404   stylesheet   15.6 kB
Image
Platform
  • @tanstack/react-start: 1.168.13
  • @tanstack/start-plugin-core: 1.171.6
  • @tanstack/start-server-core: 1.169.4
  • @tanstack/react-router: 1.170.8
  • @tailwindcss/vite: 4.3.0
  • OS: macOS 26.5
  • Browser: Chrome (latest)
  • Bundler: Vite 8.0.13 with experimental.bundledDev: true
  • Bun: 1.3.13
Additional context

Workaround: use ?inline instead of ?url:

import appCss from '../styles.css?inline'
// ...
<style dangerouslySetInnerHTML={{ __html: appCss }} />

?inline forces the full Vite transform pipeline to run on the CSS (Tailwind expansion, @import resolution), and the processed CSS string is embedded directly into the JS bundle. Works in bundledDev, unbundled dev, and prod. Trade-offs: loses the natural <link rel="stylesheet"> semantic, and the bundled client JS grows by the CSS size (~35 kB for this app).

It's not obvious whether this is best fixed in TanStack Start's plugin pipeline, in @tailwindcss/vite, or in Vite core's ?url handling for bundledDev mode. Filing here because the failure surfaces against the Start-recommended pattern and Start users will hit it as they try bundledDev.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the minimal reproducer in PR 127 and apps/web/src/routes/root.tsx, switching the import between ?url and ?inline as described. Run bun install and bun dev, then inspect the browser Network tab and the CSS pipeline for styles.css, fonts.css, transitions.css, and tailwindcss. Done means the ?url response contains fully processed CSS and the page loads without the reported 404s.

Written by the indexing model from the issue text.

Assessment

Tech stack
react, tailwindcss, typescript, vite
Domain
build-system, frontend, web-dev
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
55/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.