Skip to content

Admin stylesheet 500s under astro dev + @astrojs/cloudflare (?direct CSS request fails, vite:oxc) #2572

Description

@bvjebin

Bug

The admin shell's stylesheet (node_modules/emdash/src/astro/routes/admin.astro) is imported as:

import adminStylesUrl from "@emdash-cms/admin/styles.css?url";

and rendered as <link rel="stylesheet" href={adminStylesUrl} />.

Under astro dev with the @astrojs/cloudflare adapter, the browser's subsequent request for that stylesheet 500s with:

Transform failed with 1 error:

[PARSE_ERROR] Unexpected token
 -  in node_modules/@emdash-cms/admin/dist/styles.css?direct at 73..83

  Plugin: vite:oxc

This breaks every /_emdash/admin/* route in local dev — the HTML shell itself returns 200, but it's completely unstyled since the stylesheet request fails.

Versions

  • astro 7.2.1
  • @astrojs/cloudflare 14.2.1
  • emdash 0.33.0
  • @emdash-cms/cloudflare 0.33.0
  • vite 8.2.1 (hoisted by astro/@astrojs/cloudflare)
  • Node v24.12.0

Reproduce

npm install --legacy-peer-deps
npm run dev

Then, in another terminal, request the stylesheet the way a browser <link> does (Accept: text/css):

curl -s -w "HTTP %{http_code}\n" \
  -H "Accept: text/css,*/*;q=0.1" \
  "http://127.0.0.1:4321/node_modules/@emdash-cms/admin/dist/styles.css"

Expect HTTP 500 with the [PARSE_ERROR] ... vite:oxc body above. Visiting /_emdash/admin/login in a real browser shows the same thing — the HTML loads, but the linked stylesheet 500s.

A minimal reproduction repo is available at: https://github.com/bvjebin/emdash-cf-css-issue

Root cause (as far as we've traced it)

Vite's ?url CSS import resolves in dev to the file's bare path. When the browser later requests that path as a <link> (Accept: text/css), Vite's dev middleware appends a ?direct query to mean "give me raw CSS, not a JS module" (isDirectCSSRequest/directRequestRE in vite/dist/node/chunks/node.js).

We traced this with DEBUG=vite:plugin-transform astro dev and found:

  • The ?url-imported JS module itself (styles.css?url) transforms fine (it's real JS — export default "/path/to/styles.css").
  • The ?direct raw-CSS request is what fails, and only under @astrojs/cloudflare's bundled/workerd Vite environment.
  • vite:css / vite:css-post (which explicitly return null for direct CSS requests, expecting the raw CSS to pass through untouched) run first without error, but the raw CSS text then ends up handed to a JS-oriented transform (reported as vite:oxc), which fails to parse @layer properties{@supports (...)} — valid CSS, invalid JS.
  • A project-level postcss.config.cjs had no effect on this — ruled out as a contributing factor.

This looks like an interaction between @cloudflare/vite-plugin's bundled/workerd dev environment (which substitutes a different, rolldown-based JS transform plugin for the normal one) and Vite's ?direct CSS-serving mechanism, which isn't being correctly excluded from that substitution. We haven't root-caused this inside @cloudflare/vite-plugin/Vite itself.

Workaround

Importing the stylesheet with ?raw instead of ?url, and rendering it as an inline <style set:html={...}> instead of a <link>, sidesteps the browser's follow-up ?direct request entirely:

-import adminStylesUrl from "@emdash-cms/admin/styles.css?url";
+import adminStylesRaw from "@emdash-cms/admin/styles.css?raw";
...
-<link rel="stylesheet" href={adminStylesUrl} />
+<style set:html={adminStylesRaw}></style>

Happy to open a PR with this change (guarded to keep the original ?url/<link> behavior for setups not on @astrojs/cloudflare, if that's preferred) — let me know if that approach is acceptable.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions