Rails provides a smooth
assets:precompile task to prepare application assets but keeps all required gems for assets generation as a standard part of the generated Gemfile. Let’s see if we can avoid these dependencies for runtime.
A new Rails application comes with various gems concerning assets compilation and minification:
We might see other gems in older versions of Rails, like
It makes sense since the Rails’s
assets:precompile tasks is usually run within the
PRODUCTION environment, where the CSS concerns are defined:
$ cat config/environment/production.rb ... # Compress CSS using a preprocessor. # config.assets.css_compressor = :sass # Do not fallback to assets pipeline if a precompiled asset is missed. config.assets.compile = false
# example of older applications config.assets.css_compressor = :sass config.assets.js_compressor = :uglifier
All of this works but includes extra gems and might have implications about system dependencies. For example, both
assets:precompile and possibly for starting the Rails server (Webpacker shouldn’t complain, but
But what if we want to handle assets outside the Rails application’s deployment, thus removing these dependencies? What if we’re going to build an optimized Docker container using the multi-stage build and not provide Node.js in the final image?
Well, we can do something we already do with development and test dependencies – omit these gems for production. We can move them into a new assets group in the Gemfile:
gem 'webpacker', '~> 5.0' group :assets do gem 'sass-rails', '>= 6' ... end # or group :assets do gem 'sass-rails', '>= 6' gem 'uglifier' ... end
We could be ommiting Webpacker for production only if we don’t depend on
Then we can rely on Bundler configuration to set the right groups for the task at hand:
$ export RAILS_ENV=production $ bundle config set --local without development:test $ rails assets:precompile $ bundle config set --local without development:test:assets $ rails s
without option won’t load these assets gems but will fail whenever you try to use them in the configuration directly. This shouldn’t be an issue for a brand new Rails 6.1 application with Webpacker, but if your
js_compressor is set to
:uglifier, then omitting the gem ends up not starting the Rails server:
That happens because
uglifier relies on
Gem.loaded_specs, we can check if we are loading a specific gem and not set these configuration options:
... if Gem.loaded_specs.has_key?('uglifier') config.assets.js_compressor = :uglifier end ...
uglifier is used only if we are loading it – and we only load it while running
With the assets group and possibly updating the
production.rb configuration, we could omit certain gems while running the Rails application server and leave out Node.js from the production server or a final container image.
← IT'S OUT NOW
I wrote a complete guide on web application deployment. Ruby with Puma, Python with Gunicorn, NGINX, PostgreSQL, Redis, networking, processes, systemd, backups, and all your usual suspects.