The Rails asset ecosystem is at peak complexity as it transitions from Sprockets to Importmaps and Propshaft, by way of Webpacker. How does it affect people who build Rails apps? How should Rails plugin developers navigate the transition?
Rails has always prided itself on convention over configuration and as a result, the community favors having one way to solve a problem vs. a bunch of different ways where a choice has to be made. That's why the state of the asset pipeline is so surprising—there's a lot of different ways to do it and a lot of different decisions that have to be made.
Today in Rails 7
Here's an over-simplified menu of your choices for an asset pipeline when creating a new Rails 7 application today:
Basic Asset Pipeline
rails new as of Rails 7 will default to bundling the
This approach does require HTTP/2 to be performant. Why? Because HTTP/2 allows websites to serve up separate files over a single connection.
There are some popular Rails web hosts out there that don't support HTTP/2, so be sure to check with your host for support. Fly supports HTTP/2 out of the box, so no additional configuration is required to use import maps.
Complex Asset Pipeline
cssbundling-rails gems. Each of those gems brings in more complexity, which is only worth it if you absolutely need it.
But Wait, There's More!
If you're new to Rails, you should pick the Basic Asset Pipeline option and get back to shipping. Don't get caught up in analysis paralysis on the perfect asset pipeline because it doesn't exist.
But just for fun, and to prove a point about how confusing this can be, know that there's a few other options for deploying Rails that work for more specialized needs:
- Tailwind asset pipeline - The
tailwindcss-railsgem wraps the
tailwindcssCLI, and is a great option if you plan to use only Tailwind and know you won't need to compile or manage other CSS dependencies.
- Dart Sass asset pipeline - Like the Tailwind asset pipeline above, the
dartsass-railsgem wraps the
dart-sassbinary and is great if you're certain that's all your project needs.
- Webpacker asset pipeline - Rails 5.2 shipped with Webpacker, a wrapper for webpack, that made it possible for Rails apps to ship complex JS front-ends, like React, out of the box. While this gem will work in Rails 7, its been retired and is recommended to migrate to jsbundling-rails.
If you're coming into Rails 7 from an older Rails app, there are few pain points that you can expect to run into:
The documentation and tools for migrating pipelines isn't fully baked yet, though efforts are being made to make this clearer, as evident in a Rails forum post and Draft Github PR that updates the Asset Pipeline Guide. Improving documentation will help eliminate some of the confusion around the asset pipeline.
Another thing to think about: if you create a new Rails 7 app with the basic pipeline, then find out in the future that you need to switch to
jsbundling-rails, you'll have to manually move around your asset files and reconfigure a few things.
Running the Development Server
For a long time, the way to run a Rails development server was
bin/rails server . Some asset pipeline configurations require running development servers in a separate process from the Rails development server. There is a slight learning curve for Rails developers who have to switch from running
bin/rails server to
bin/dev and learn about
Difficulty Using Assets From Rails Plugins
Where you're probably running into issues today is how to get assets from Rails plugins, like
local_time, working in Rails. Why is that? Let's take a closer look starting with the Installation section of the project's README file:
The first direction for inclusion in the asset bundle is Sprockets syntax. Since Sprockets managed load paths, it knew that
//= require local-time should look in that project's
The second direction for inclusion makes life a little more difficult for Rails plugin developers. In addition to maintaining the Ruby gem, they also now have to maintain an npm package and version that separately from the gem.
The third direction is missing, which would instruct Rails 7 application developers on how to pin the local-time npm package via
This confusion exists today because of the different asset management systems that Rails currently has in play: sprockets, webpacker, jsbundling-rails, and importmaps. There's no One Way™ for third party gem developers to integrate their assets with Rails.
Fortunately work is being done by the Rails community to solve a few of these pain points.
In the future, Propshaft will serve as the interface between Rails applications and assets. It will replace all that Sprockets does and focus on these four things:
- Load paths - Propshaft will keep track of asset load paths from the app and Rails gem plugins. This should make installing Rails plugin gems much easier since they'll register with Propshaft, eliminating the guesswork needed to find assets.
- Digest stamping - Assets defined in the load paths will be digested and copied into the
./publicdirectory, along with a
manifest.jsonfile, so Rails can serve up assets with long cache expiries. This is a well known technique that makes web applications load faster.
- Development server - Propshaft will run a development server inside of Rails, which means it will be possible to run some development environments via
bin/rails serverwithout a Procfile. This is still under active development, so expect changes in the final implementation.
- Basic compilers - Propshaft will support basic compilation steps, like replacing
url(asset)strings in CSS files with
url(digested-asset). Complex compilations will be delegated out to tools better suited for that purpose.
rails new, but instead of including Sprockets, it will include Propshaft. Sprockets will probably continue being supported for a while, but it will be recommended to switch to Propshaft as the way to manage Rails assets.
You might be thinking, "how did the Rails asset pipeline get to be such a beast?". Like most questions that end with, "get to be such a beast", it's a long story.
The Time Before Asset Management
application.js file into the
./public/assets directory. No fingerprinting was necessary because there were so few moving parts.
There were third-party gems, like jammit, that were available for production websites that cared about asset efficiency, but for the most part it's something Rails devs didn't think about.
Hello, My Name Is Sprockets
Move Over Sprockets, Webpacker Is in Town
Remember, this was all before Turbo landed. The way to build a high budget compelling Rails app at the time was to deploy a front-end Framework like React, Vue, or Backbone.js.
At the same time it was realized that HTTP/2 could deliver a lot of small asset files without incurring the performance penalties imposed by HTTP/1, so importmaps was born.