Extremely slow Rails webpacker compile times with hundreds of thousands of assets - ruby-on-rails

I'm working on a project that includes pictures for a google maps overlay and consequently contains around 750k image assets. This project uses rails 6 and webpacker, and after copying in all the files to the correct directory the webpage load times increase to the point of hours. The assets are located in /app/assets/images/.
So far I've tried using rails assets:precompile, which after a night of compiling didn't finish.
An odd thing is this only happens after a server restart. If I copy in the files while the server is running then everything behaves and performs fine.
What can I do to fix this? Am I fundamentally misunderstanding where the images should go and how webpacker should fit in?
Thanks

Ultimately wound up not including the files in development. In production we use apache, and that serves the large number of files without any problem.

Related

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
and the files listed in the directory, showing the file clearly exists
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
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.

Rails 6 - Should I put my CSS & JS in rails asset pipeline or webpacker or through Amazon Cloudfront? Which is the most efficient?

I use to host my CSS files in the rails asset pipeline and JS on webpacker. I recently realize my webpage has been loading slower and slower.
I ran Chrome lighthouse on my site and found that my CSS and JS assets are "render-blocking resources" and causing my page to load slower.
I've already tried moving all of my CSS and JS over to webpacker (semantic-ui css is still being imported by the rails asset pipeline, had lots of problems trying to make this work but couldnt still)
I notice on Chrome lighthouse that my load time improved marginally, I guess its from the minification of CSS and JS by webpacker but it's no where near the improvements I was looking for.
So my question here is, what is the most efficient method to serve CSS and JS files for rails app?
My app is hosted on Heroku's Hobby Tier.. could this be a factor as well?
Both approaches should allow you to achieve similar results. I don't know rails asset pipeline, but if it's used similarly to webpack it just changes your files on the build time & it's up to you how much code the user gets to download.
First of all, you can check the output size - in webpack, you can check the build standard output, or directly check the files it creates.
One trap you could be failing into with webpack is to have it set up wrongly. It could anything, from not minimizing code when for production build to having loades set up in a way that makes your images included directly inside js as data URL.
One advantage of using webpack, is that allows you to set up more complicated loading logic - for example lazy loading. Here something more about lazy load:
https://dev.to/marcinwosinek/lazy-load-library-in-application-build-with-webpack-5757

Less compiler doesn't update css file after LESS code is updated

This is way beyond my knowledge..
I was migrating my rails 3 application from Bootstrap 2 to Bootstrap 3. I downloaded Bootstrap 3 and FontAwesome, put them into my assets folder. Then I tried to modify the font path. I change #FontAwesomePath in font-awesome/variables.less several times, however it still don't points to the correct path. (I put font files in ./app/assets/fonts/font-awesome/)
#FontAwesomePath: "fonts/font-awesome"
It's ok, cuz I saw the line below this one is a cdn path to font files:
//#FontAwesomePath: "//netdna.bootstrapcdn.com/font-awesome/3.2.1/font"; // for referencing Bootstrap CDN font files directly
I uncomment this line, everything seems fine. The compiled css file load the font from cdn and all icons are displaying.
Then I delete this line, try to point #FontAwesomePath back to local server again. STRANGE thing happened! No matter what I did, the compiled css file points it to the CDN path! I tried to clear browser cache, reboot rails server (I was using development mode of rails server), even to load the website from other computers, nothing changes. It insisting point #FontAwesomePath to the CDN path even no where in the whole application code exists the url! I can only image there is some kind of variable cache in less compiler. Can anybody tell me what's happened inside this? It's driven me crazy.
edit: I'm using less gem (v 2.3.2), which includes lesscss v 1.3.3.
I had issues with CSS updates, these where only solved by going to tmp > cache and deleting the assets folder then restarting the server. The CSS was then updated.
Hope this helps.
Steph

Rails with Twitter Bootstrap: still serving an old asset

Going nuts here. I'm developing a rails app, and I'm using the twitter-bootstrap-rails gem in order to include the Twitter Bootstrap styles in my app. This gem generates a file called 'bootstrap_and_overrides.css.less' in app/assets/stylesheets, which I have been using to modify some of the bootstrap variables and include my own CSS overrides.
Everything has been working fine until today. For some reason, the changes I am making to this file today are getting saved to the file, but Rails is still serving the old version of the file! I've searched and found no precompiled versions of the file anywhere (nothing in public/assets)...only the one in assets/stylesheets which I have been modifying. Everything looks fine as far as the directories within the app go, but then when I start the rails server, load the page, and use the element inspector to look at the stylesheets, it's using an old version of 'bootstrap_and_overrides.css.less' with rules that I have deleted. I've turned of the cache in my browser, and tried it in 4 different browsers too, so I'm pretty sure this isn't a result of browser caching.
The rails asset pipeline just seems to serving a version of the file that doesn't exist! Does anybody have any ideas why this might be happening?
Fixed it.
The asset pipeline was storing a cached version in tmp/cache.
I ran rake tmp:clear, which deleted all the files in there, and then rails served the version of *bootstrap_and_overrides.css.less* that I wanted.
Why the cached version suddenly stopped getting updated is beyond me. Arrghhhh!

Heroku Rails 3 all.css / all.js dynamic generation?

I'm currently wrestling with a lot of all.js / all.css missing hits on a rails 2 upgraded to 3 app on Heroku. I'd prefer not to have a dozen or so stylesheet links per request, and also don't want to statically bundle -> s3 the files as part of the deploy.
This seems like a familiar problem, preparing some content specific to a url and sending it back to the browser.
Rather than using an external bundling app as part of a deploy script etc, has anyone considered having rails generate these files on-the-fly and use varnish to cache them (since it's cleared on redeploy, which is when the css/js files would change)?
My question is whether this has been done already & I just failed to google it, or if it sounds like a dumb idea, why?
Even better: Rails 3.1 asset pipeline does exactly this, and Heroku handles precompilation and caching for you.

Resources