Resolve/load `url()` references in CSS
Description
vite-imagetools transforms images to more efficient file formats. This works great for images included via an import in the JS. However, Vite's url() references are only being half handled today. Vite's static asset handling does rename these assets to have a hash in their name. But the vite-imagetools plugin is never invoked, so we can't do think like change jpg/png images to webp.
Suggested solution
Invoke Vite plugins on asset URLs found in CSS just as is done for asset URLs found in JS
Alternative
No response
Additional context
This is one of the top feature requests in vite-imagetools: https://github.com/JonasKruckenberg/imagetools/issues/563
Validations
- [X] Follow our Code of Conduct
- [X] Read the Contributing Guidelines.
- [X] Read the docs.
- [X] Check that there isn't already an issue that request the same feature to avoid creating a duplicate.
I suppose this is related to https://github.com/vitejs/vite/pull/10555. There's a perf concern if we run all Vite plugins for CSS resolving.
Would be nice to solve this issue, to allow images optimization also in css
Ran into this issue as well. I found that I can run my resolveId function run for url() through resolve.alias.customResolvers, ~~but that breaks dev mode (/@vite/client can no longer be resolved)~~ (that was unrelated).
~~This issue is that it requires that the url start with either /, ./, or ../ - a plugin can't handle, for example, https URLs to process them at build-time. So it seems this really does require work in vite.~~
I was wrong about the above too, resolve.alias.customResolvers seems to be an adequate workaround so far.
@lilnasy Is this workaround applicable for plugins like vite-imagetools?
@lilnasy could you show a hint where to dig to implement the custom resolver?
Is this workaround applicable for plugins like vite-imagetools?
Yes, although the plugin currently depends on the "load" hook. Within CSS, I think only the "resolve" could logically work.
For example, it can resolve example.png by processing it into a temporary folder on disk and returning the file path to the optimized image. Then ,vite/rollup's default load behavior replaces background-image: url("example.png?format=webp") with background-image: url("/_static/example_sLK87DNS.webp").
imagetools uses the "load" hook to also add metadata like width and format, I don't think information other than the final image path has a place in CSS.
could you show a hint where to dig to implement the custom resolver?
I implemented a font loader for my project using this customResolver: plugin code, usage.
Plugin authors might find the internal rollup plugin's source code helpful: rollup/plugins alias().
To summarise, it matches urls used inside CSS against alias.find. If it's a match, it calls customResolver which can perform arbitrary I/O before returning the replacement path for the url.
I'm not sure why its "resolve" hook gets called but third party plugins' doesn't. I'm guessing one of the plugins in this plugin chain blocks it: vitejs/vite resolvePlugins()
Hi! I’d like to work on this issue. I’ll test how url() assets in CSS are currently handled and explore invoking Vite’s plugins for these URLs similarly to JS imports. Let me know if there are any guidelines I should follow.
Hi! I’m interested in taking this issue. I’ll reproduce the behavior with a minimal setup and investigate how we can run Vite’s asset plugins on CSS url() references without causing performance issues. Any pointers before I begin would be appreciated.