ElMassimo / ElMassimo/vite_ruby

CSS-only entrypoint sometimes resolves to a `.js` file in the manifest under Vite 8 / Rolldown

Open
#615 0 comments 1 reaction 0 assignees View on GitHub
bug: pending triage
Dominant language
Ruby
Stars
1.6k
Forks
149
Avg merge
5h 13m
Merged PRs (30d)
2

Description

### 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) ``/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:

```ruby
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.

Contributor guide

Open the contributing guide

Research direction

Start at ViteRuby::Manifest#resolve_entries(entry_name, type: :stylesheet) and the production manifest path used by vite_stylesheet_tag. Reproduce with a CSS-only entrypoint under Vite 8/Rolldown, then verify that resolution consistently returns the actual stylesheet rather than a .js wrapper, including when the stylesheet appears in the manifest's css array.

Written by the indexing model from the issue text.

Assessment

Tech stack
rails, ruby, vite
Domain
build-system
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
68/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.