Environment
vite_ruby: 3.10.2
vite_rails: 3.11.0
- Vite: 8.x (using the Rolldown bundler)
Description
This only affects production-style builds that read from the manifest. In dev mode, Vite serves the raw source file directly and transforms it into CSS on request, and resolve_entries deliberately returns no stylesheets while the dev server is running (CSS is expected to arrive via the JS module graph's HMR client instead) — so a standalone CSS entrypoint like this one has to be rendered differently in dev vs. production anyway, and the bug below only shows up on the production/manifest path.
For a CSS-only entrypoint (e.g. assets/stylesheets/foo.scss), ViteRuby::Manifest#resolve_entries(entry_name, type: :stylesheet) is inconsistent about where the actual stylesheet ends up in the manifest, depending on the entrypoint:
- For some CSS-only entrypoints, the manifest's
file key for the entry is the real .css file, as expected.
- For others,
file is a .js wrapper (seemingly a Rolldown artifact), and the real stylesheet only shows up in the entry's css array.
Since vite_stylesheet_tag (and resolve_entries(..., type: :stylesheet)'s scripts result) only reads the file key, this means some CSS-only entrypoints are rendered as (broken) <script>/stylesheet tags pointing at a .js file instead of the actual CSS, unless the caller also inspects the css array and merges it in manually.
Current workaround
We're working around this in our own helper by manually reading both scripts and stylesheets from resolve_entries and merging them:
entries = ViteRuby.instance.manifest.resolve_entries(entry_name, type: :stylesheet)
own_file = entries.fetch(:scripts).first
stylesheets = entries.fetch(:stylesheets)
stylesheets = [own_file, *stylesheets] if own_file&.end_with?('.css')
stylesheet_link_tag(*stylesheets.uniq, media: 'all', rel: 'stylesheet')
This was added while upgrading to Vite 8 in our app. We'd like to drop it once the manifest resolution is fixed/normalized upstream so vite_stylesheet_tag can be used directly again.
Environment
vite_ruby: 3.10.2vite_rails: 3.11.0Description
This only affects production-style builds that read from the manifest. In dev mode, Vite serves the raw source file directly and transforms it into CSS on request, and
resolve_entriesdeliberately returns no stylesheets while the dev server is running (CSS is expected to arrive via the JS module graph's HMR client instead) — so a standalone CSS entrypoint like this one has to be rendered differently in dev vs. production anyway, and the bug below only shows up on the production/manifest path.For a CSS-only entrypoint (e.g.
assets/stylesheets/foo.scss),ViteRuby::Manifest#resolve_entries(entry_name, type: :stylesheet)is inconsistent about where the actual stylesheet ends up in the manifest, depending on the entrypoint:filekey for the entry is the real.cssfile, as expected.fileis a.jswrapper (seemingly a Rolldown artifact), and the real stylesheet only shows up in the entry'scssarray.Since
vite_stylesheet_tag(andresolve_entries(..., type: :stylesheet)'sscriptsresult) only reads thefilekey, this means some CSS-only entrypoints are rendered as (broken)<script>/stylesheet tags pointing at a.jsfile instead of the actual CSS, unless the caller also inspects thecssarray and merges it in manually.Current workaround
We're working around this in our own helper by manually reading both
scriptsandstylesheetsfromresolve_entriesand merging them:This was added while upgrading to Vite 8 in our app. We'd like to drop it once the manifest resolution is fixed/normalized upstream so
vite_stylesheet_tagcan be used directly again.