ruby-on-railsesbuild

Specific Image Not Loading After Rails 7 ESBuilt Update


I have a very frustrating issue with a Rails 7 app after migrating to Ruby 3.2 with Esbuild.

Basically there is a few specific images that simply will not load, however, there are many others that load just fine that live in the same location, and are accessed the exact same way. It's driving me nuts.

I have cleared cached, restarted servers, cleared all the local build files, everything I can think of. This is also happening in both dev and production.

My Esbuild is running just fine, it is finding the files and compiling them with a finger print. The files all exist and are in the right location. (all sitting under app/assets/builds)

Accessing the file direcly in the browser, ie http://localhost:4000/assets/logo_white_trans-QEBURZJB.png

Fails with a 404, cannot find the image. This file however exists with the correct name in the app/assets/builds folder.

Accessing another image from the page ie http://localhost:4000/assets/leadstory-symbol-B5T7OIJB.png

Loads just fine.

It's almost like there is a static list of rails routes that match the images and it is not generating the route for some of these specific images, hence the 404, even though the file exists.

Some screenshots that highlight the odd behaviour

enter image description here

and the files listed in the directory, showing the file clearly exists

enter image description here

My package.json build step is

esbuild app/javascript/bundles/*.* --bundle --sourcemap --outdir=app/assets/builds --public-path=/assets --minify --log-limit=0 --loader:.js=jsx --loader:.png=file --loader:.svg=file

And a snip from the app of how its being loaded.

import LogoWhiteTrans from "../../assets/images/logo_white_trans.png";
<img src={LogoWhiteTrans} className="logo" alt="logo" />

Which looks to be working fine, the HTML outputs

<img src="/assets/logo_white_trans-QEBURZJB.png" class="logo" alt="logo">

The image can be loaded fine, from elsewhere in the app in a regular rails view using asset helpers (not from within the React app) ie <%= asset_path('logo_white_trans.png') %>

Something I have noticed is in the logs, I see

 ActionController::RoutingError (No route matches [GET] "/logo_white_trans-QEBURZJB.png"):

Notice there it does not say "/assets/logo_white_trans..."? I thought that was weird, as the URL in the image tag clearly has a /assets at the start. Trying either path does not work, with or without /assets directly in the browser. Just seems odd rails would see it that way

Im going nuts here, what am I missing. Its not a png specific issue, as other pngs are loading fine in the same way, nor is it an image issue the file exists and the naming is fine.

Is there some sort of manifest thats not being updated? An internal asset route list or something along those lines?

Im running Rails 7 Ruby 3.2 ESBuild


Solution

  • This isn't really an answer, but what I have ended up doing is moving all image assets out of the asset pipeline and into the public folder. I noticed that my assets were being duplicated by esbuilt and the rails asset precompile process, and basically the javascript build and rails eco system just do not work well together.

    For anyone else having issues like this, we've just moved all our static assets in the public/images folder and we refernce the path /images/blah.png the same way in both React and Ruby now.

    All image tags in either React or standard .erb views are just <img src="/images/blah.png/>. Its a lot cleaner.

    Yes, we have given up asset finger printing, but its a small loss, considering most images never change and It's dramatically simplified things and sped up our build process considerably as it does not have to touch each file during precompilation.

    Our views now also just have standard tags, instead of <asset_path> tags, which im sure is just quicker in general instead of ruby generating these asset strings all the time.

    So, not really and answer to the initial question but it is a solution, and one i think anyone who is fusing modern javascript, react, typescript etc into a Rails app.