photo credit cleaning: pixabay
Why would we want to more safely delete image assets?
rake assets:precompile
All of this time adds up, assets compilation on a large legacy Rails app still adds around 40 seconds to the build time, down from 1m30s in the past. While asset preparation and deployment before cleanup and optimization of that flow and files was adding over 3 minutes to our deploy time.
OK, hopefully now you would love to delete all the images in your app/assets/images
folder that you don’t use… What images are safe to delete or out of use? I have looked at a number of ideas for this.
unknown_asset_fallback
alone, doesn’t make you entirely safe…What I wanted was a way to delete a folder of images or a single image that I believed was no longer in use, but have the build fail if there was any reference to the image. I wanted Rails to fail in these cases:
Not surprisingly, other folks have wanted this and Sprockets has a built-in option config.assets.unknown_asset_fallback, which gets close to what I wanted. From the docs, this option claims to:
When set to a truthy value, a result will be returned even if the requested asset is not found in the asset pipeline. When set to a falsey value it will raise an error when no asset is found in the pipeline. Defaults to true.
So let’s set it to false: Rails.application.config.assets.unknown_asset_fallback = false
. Now if you have a deleted image referenced like below:
<%= image_tag("deleted_image.svg") %>
You will get an error when visiting the page or running tests:
bundle exec rake
...S.......E
Error:
HomeControllerTest#test_should_get_index:
ActionView::Template::Error: The asset "deleted_image.svg" is not present in the asset pipeline.
app/views/home/index.html.erb:6:in `_app_views_home_index_html_erb___957919561084124106_70092585694780'
test/controllers/home_controller_test.rb:5:in `block in <class:HomeControllerTest>'
This doesn’t make one entirely safe, as images that are referenced in your scss, css, or other styles would still not cause an error. They would silently lead to broken images.
Sadly, I couldn’t find any option or configuration that would cause compiling stylesheets to fail. I thought this would block my goal of being able to remove a ton of assets safely with confidence… Well, after lots of digging, I figured out how to patch sprockets-rails
so that it will blow up and fail when it references an unknown asset.
You can apply this patch in your: config/initializers/assets.rb
Now if you have a file in your styles, like app/assets/stylesheets/application.scss
reference an image, your asset pipeline will blow up when the image is missing.
.broken-image-demo {
background-image: image-url('deleted_image.svg');
}
Depending on how your tests run, they will fail when precompiling assets, or a failure will occur when you call rake assets:precompile
as shown below.
bundle exec rake assets:precompile
...
Done in 1.32s.
rake aborted!
Sprockets::Rails::Helper::AssetNotFound: path not resolved: deleted_image.svg
/Users/danmayer/projects/coverband_demo/config/initializers/assets.rb:56:in `rescue in compute_asset_path'
/Users/danmayer/projects/coverband_demo/config/initializers/assets.rb:51:in `compute_asset_path'
/Users/danmayer/.rvm/gems/ruby-2.6.2/gems/actionview-5.2.2.1/lib/action_view/helpers/asset_url_helper.rb:200:in `asset_path'
...
If you want to see this in action, feel free to clone coverband demo. Install gems and get the tests passing. Then read the comments and run tests or compile assets when uncommenting the example lines to trigger the expected errours. Key Files:
On an old legacy application we were able to delete over 50% of the total asset disk size, by clearing out old unused image assets. This made it easier to find and navigate our assets folder, and it significantly sped up both our test suite and deployment. While I wouldn’t expect most projects to have as much image cruft sitting around, especially with older applications, it is easy for these unused assets to really build up over time.
While the above, should make it easier to delete image assets and do housekeeping yourself, it still takes a bit of time. You need to go through a process:
This obviously looks like a process that can be automated to help you clean up all your image assets automatically. That is totally true, and I will cover how to do that in a future post. This post covers what is a prerequisite to being able to automate the cleanup, ensuring that your app will properly and very loudly fail when an image was removed which is still required.