jsbundling-rails: Can't load images in JavaScript files
Hi,
I’m trying to migrate my Rails + React application from Webpacker to Jsbundling + Esbuild following switch_from_webpacker guide to first replace webpacker for Jsbundling
Everything is bundled to “app/assets/builds” by webpack, images included.
application.js and application.css are working fine in application.html.erb but the images in jsx files aren’t loading.
My React component are trying to load “0bdd8103a525a17c3528e4f40d701b33.svg” the same as output in assets/builds folder but public/assets has the digested version of my svg “0bdd8103a525a17c3528e4f40d701b33-b8fb0ca2943e7724f64b3717f8a3e2b3ecb321adac1053107f2c89142efffd17.svg”
import React from "react";
import Logo from "Assets/logo-brand.svg";
export default function Img() {
return <img height="46px" src={Logo} />;
}
I’m not sure if the correct approach is to move all assets from assets/build to public/asssets with a rake or if it is possible to skip sprockets-rails digest for images and rely on webpack digested file or if there is another way to load imagens inside js files
Thanks for jsbundling effort!
About this issue
- Original URL
- State: closed
- Created 2 years ago
- Reactions: 2
- Comments: 19 (6 by maintainers)
@richardkmiller,
This is what is happening with my
file.svg
:file.svg
-> webpack build ->app/assets/builds/[webpack-hash].svg
app/assets/builds/[webpack-hash].svg
-> sprockets -> public/assets/[webpack-hash]-[sprockets-hash].svgmy JS component is resolving the image as
assets/[webpack-hash].svg
and can’t find it because onlyassets/[webpack-hash]-[sprockets-hash].svg
is accessible.Same general problem, but with rails 7.0 + propshaft + jsbundling + esbuild, specifically with react-leaflet. Using
--loader:.png=file --public-path=/assets
and am trying to override the paths as mentioned in https://github.com/PaulLeCam/react-leaflet/issues/453#issuecomment-731732137 and the file ends up asassets/builds/marker-icon-2V3QKKVC.png
, but rails can’t find this file without it’s own digest. I’ve also tried using--entry-names=[name]-[hash].digested
on esbuild, but this doesn’t appear to apply to the file loader.Edit: Digging a little deeper into the esbuild config, I got this to work by using the
asset-names
parameter:--loader:.png=file --public-path=/assets --asset-names=[name]-[hash].digested
Same problem here.
app/asset/builds
is an intermediate space for the output from webpack. Sprocket moves js and images topublic/assets
and add hash to the tail of filename. So even we remove hash added by webpack can’t solve the problem.For example,
app/javascript/application.js
importapp/javascript/logo.svg
(or other places) in JS way. After webpack building, we haveapp/assets/builds/application-abc.js
andapp/assets/builds/logo-abc.svg
. Then sprocket producespublic/assets/application-abc-123.js
andpublic/assets/logo-abc-123.svg
. We can resolve the application.js inside the public folder byjavascript_include_tag "application"
. But the image lost due to the image filename inside the JS islogo-abc.svg
rather thanlogo-abc-123.svg
.@jon-sully , It’s working with JSB-Rails + Webpack 5!
I’m using webpack with this config and now sprockets are not re-stamping the assets.
Also you need sprockets >4.0.3 -> https://github.com/rails/sprockets/blob/master/CHANGELOG.md
@cirdes PR #58 should be helpful to you. The short answer is to open
package.json
under"scripts"
and edit theesbuild
script to include--public-path=/assets
. In the PR I suggested--public-path=assets
but after further use, I found an issue that was resolved by using the leading slash:--public-path=/assets
. Let me know if that doesn’t work for you.I’m having a similar, but maybe slightly different problem. After upgrading from Rails 6 and switching from Webpack to esbuild, I can load images in development, but not after deploying to production (Heroku). In production, it looks like an additional fingerprint is added to the asset path.
My esbuild.config.js looks like this:
A note for people hitting the same problem as me: Your asset name must have a dash before the digest.
The default value for
file-loader
’sname
option is[contenthash].[ext]
, so I changed it to[contenthash].digested.[ext]
. However, sprockets uses a regex that looks for the hyphen.After changing the option to
[name]-[contenthash].digested.[ext]
orasset-[contenthash].digested.[ext]
, the extra digest is no longer appended.@richardkmiller, moving forward to JSB-Rails with Esbuild I had to point sprockets to https://github.com/rails/sprockets/pull/726 and use --public-path=/assets
Images assets were working but not using my CDN to serve the assets. So I came with this solution: “–public-path=$CDN_URL_FULL/assets”
esbuild app/javascript/*.* --bundle --outdir=app/assets/builds --loader:.png=file --public-path=$CDN_URL_FULL/assets --asset-names=[name]-[hash].digested
I’m not sure if esbuild should generate assets string with cdn domain or if sprockets should somehow be responsible to rewrite urls with CND.
any thoughts about that?
Wanted to comment back a solution to folks that are using JSB-Rails + Webpack 5 not ESBuild — specifically in my case how to setup Webpack to output the
asset/resource
files with the right name such that Propshaft doesn’t re-stamp them with a new digest. This should work for folks using Sprockets instead of Propshaft even without https://github.com/rails/sprockets/pull/726 merging (if I’m reading the diff correctly).That helped fix things for us.