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].svgapp/assets/builds/[webpack-hash].svg-> sprockets -> public/assets/[webpack-hash]-[sprockets-hash].svgmy JS component is resolving the image as
assets/[webpack-hash].svgand can’t find it because onlyassets/[webpack-hash]-[sprockets-hash].svgis accessible.Same general problem, but with rails 7.0 + propshaft + jsbundling + esbuild, specifically with react-leaflet. Using
--loader:.png=file --public-path=/assetsand 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].digestedon 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-namesparameter:--loader:.png=file --public-path=/assets --asset-names=[name]-[hash].digestedSame problem here.
app/asset/buildsis an intermediate space for the output from webpack. Sprocket moves js and images topublic/assetsand 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.jsimportapp/javascript/logo.svg(or other places) in JS way. After webpack building, we haveapp/assets/builds/application-abc.jsandapp/assets/builds/logo-abc.svg. Then sprocket producespublic/assets/application-abc-123.jsandpublic/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.svgrather 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.jsonunder"scripts"and edit theesbuildscript to include--public-path=/assets. In the PR I suggested--public-path=assetsbut 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’snameoption 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].digestedI’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/resourcefiles 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.