Guide to Rails 7 and the Asset Pipeline

Intro

Rails 7 brought with it an overhaul of the Asset Pipeline in the form of multiple new gems that either introduced a new way of handling assets (importmaps-rails), or broke down existing gems (propshaft, jsbundling-rails, cssbundling-rails) into smaller parts that make use of existing standalone tools and therefore support modern features that were previously unavailable.

While a few of these gems are still in pre-release status, their maintainers, contributors and early adopters have already deployed them to production. However, widespread adoption is currently being hampered by the lack of detailed documentation and some missing features that would allow them to support more use cases.

With the creation of the new Rails Discord channel for people interested in contributing to Rails, I think it’s a good time to coordinate with the community so we can pare down the rough edges. Therefore I’d like to start this thread so we can make a more visible demonstration that there are people working to improve things and provide central source of knowledge while all the related guides haven’t been updated.

If you want the TL:DR version of this guide, check “What will Rails recommend going forward?” further down.

This is a work in progress

Four approaches to the Asset Pipeline

  • Sprockets: The original asset pipeline gem, built for the HTTP/1 era and low javascript frontends. It handled the bundling and digesting of javascript, css and image files, without relying on node packages.

  • Webpacker/Shakapacker: Shipped with Rails 5.2, as a wrapper around the complexity of Webpack/Node/Yarn, this gem could completely replace Sprockets or simply take over javascript transpiling and bundling. It provided Rails “out of the box” support for SPA frameworks like React.

  • Import Maps: Shipped with Rails 7.0, it replaces Sprockets as the default asset pipeline gem. Although it eliminates the need for node/yarn and other complex tooling, it requires the application using it to be deployed in an environment that supports HTTP/2, otherwise it causes severe performance problems.

  • Bundling gems: Shipped with Rails 7.0, the multiple bundling gems provide a more traditional, if more modern, approach to the asset pipeline than import maps does. They basically break down the “all in one” approach of Sprockets into multiple smaller, specialized pieces. The main gems are propshaft, jsbundling and cssbundling.

Explanations and recommendations

I’m writing this not as maintainer of any of these gems, but as a regular contributor and someone who has deployed most of them in the monolithic production app that my own company relies on. Corrections and suggestions are welcome.

Sprockets

  • Status: Maintained

  • Notes: Several fixes and updates are only available in the edge version.

The original asset pipeline gem, Sprockets provides bundling and digesting for javascript, css and image files. Built before node was widely adopted, Sprocket’s “everything included” approach worked well for many years. However, as frontend programming became more complex, it started to fall behind dedicated tools like webpack. It was the only officially supported gem up to Rails 5.2, when Webpacker was introduced, and remained the default until Rails 7, when it was replaced by Import Maps.

If you are learning Rails: Don’t use it. Your time will be better spent learning one of the more modern approaches.

If you are starting a new app: Only if you absolutely do not want to deal with node/yarn and are not ready for import maps.

If you have an existing app with Sprockets: You can continue using it. Sprockets will receive maintenance updates at least until Propshaft reaches 1.0, and probably longer.

Webpacker

  • Status: Retired

  • Notes: All work done for the unreleased version 6 went to Shakapacker.

Rails has always had a complicated relationship with vanilla javascript, and to get around perceived limitations of the language, it adopted coffeescript as the default. Things changed with the arrival of ES6 and Babel for transpilation, but getting everything working so that you could use modern features of the language while remaining compatible with older browsers was difficult. Webpacker was created to solve that problem and for some time provided the bridge for developers interested in investing more heavily in the javascript ecosystem.

Five years later, all browsers oficially support ES6, so transpilation was no longer necessary and the extra complexity not worth for many developers. This lead to Webpacker being retired.

If you are learning Rails: Don’t use it. If your plan is to build your frontend entirely with Rails and Hotwired, then import maps is the preferred approach. However if your plan is to use a framework like React, then Shakapacker is the official sucessor and includes all the nice things that most javascript developers expect.

If you are starting a new app: Don’t use it. SPAs should go with Shakapacker, the official sucessor of Webpacker, which supports things like HMR. Hotwired/Tailwind based apps should go with importmaps-rails, or the bundling gems, which let you to choose your preferred bundling tool (esbuild, postcss, etc.).

If you have an existing app with Webpacker: Give some serious consideration to replacing it. If your app is a SPA, specially a React one, then Shakapacker is your friend, as it’s the official sucessor to Webpacker. If you are mostly using Hotwired and doing server side rendering, jsbundling-rails + webpack is an easy migration (and you can later migrate to the excellent esbuild).

Import maps

  • Status: Released, in active development

  • Notes: A shim is available to provide support for older browsers.

Rails 7 apps defaults to the importmaps-rails gem, which shares the same name as the import maps feature in browsers. This gem relies on the trifecta of HTTP2 (which eliminates the penalty of many small files), wide spread support for ES6 and the import map feature (which can the added to legacy browsers and Safari through a shim).

If you are learning Rails: This is the preferred approach, but only if you plan on building your frontends with Rails/Hotwired. If you want to use React/Vue/etc. then go with Shakapacker.

If you are starting a new app: Is it an SPA or your planned production environment only support HTTP1? This is not your friend, go with Shakapacker or the bundlings gems. However, if you are on the Hotwired team and have Cloudflare or Nginx in front of your Puma servers, then sure!

If you have an existing app: Stay where you are. This is a very different approach to handling javascript and css files and will require extensive work to migrate, specially if you have a lot of frontend code or rely on many node packages.

Propshaft

  • Status: Alpha, in active development

  • Notes: Already deployed to production in Basecamp (and by me, FWIW).

The sucessor to Sprockets, it has a much smaller scope than its predecessor: it’s only handles digesting, fixin references in css files so they use the digested filename, and moving everything to the public folder.

This means that any setup using propshaft will also be using one or more of the new bundlings gems, probably jsbundling-rails and cssbundling-rails.

If you are learning Rails: Don’t use it. It has no documentation, very few users and is still in alpha. You are already going to be spending a lot of effort learning other things, no need to make your life harder.

If you are starting a new app: Stick to import maps if you are going with Hotwired or shakapacker if you are going with React.

If you have an existing app: Maybe. It should be an easy migration for apps that are running Sprockets (CSS and digests) and Webpacker (javascript) and will also allow you to later webpack with the phenomenal esbuild. Just make sure you are comfortable running pre-release code with almost zero documentation in production. For what is worth, I’m using it in production and so is Basecamp.

jsbundling-rails

  • Status: Released, in active development

  • Notes: -

Provides javascript bundling features that were previously handled by Sprockets and Webpacker. Supports webpack, esbuild and rollup.

If you are learning Rails:

If you are starting a new app:

If you have an existing app:

cssbundling-rails

  • Status: Released, in active development

  • Notes:

Provides css bundling features that were previously handled by Sprockets and Webpacker. Supports Tailwind, Bootstrap, Bulma, PostCSS and Dart Sass.

If you are learning Rails:

If you are starting a new app:

If you have an existing app:

dartsass-rails

  • Status: Released, in active development

  • Notes:

Same as cssbundling-rails, but specific for dart. A wrapper around the platform specific versions of dart, instead of the yarn versions.

If you are learning Rails:

If you are starting a new app:

If you have an existing app:

What will Rails recommend going forward?

The default (no node/yarn):

  • Rails 7: Import Maps + Sprockets
  • Rails 8: Import Maps + Propshaft

The alternative way (with node/yarn and your choice of bundler):

  • Rails 7: Bundling Gems* + Sprockets
  • Rails 8: Bundling Gems* + Propshaft

* Bundling gems are cssbundling-rails, jsbundling-rails, etc.

Github Pages

Upgrade Guides

Relevant Information

Changelog

  • 2022-06-17: First version
  • 2022-06-18: Added the ‘Four approaches’ section. Rewrote some explanations
  • 2022-06-28: Added “What will Rails recommend”.
12 Likes

I’m looking for contributors to help with this guide so we can eventually turn it into an official Rails guide. If you’d like to contribute join us at the Rails Discord channel. If you have questions about the asset pipeline, post here.

3 Likes

Could this be turned into a draft PR? Would make it easier to share feedback inline.

Here it goes.

1 Like

I just need

1 Like

@brenogazzola thanks, will you put the rest of the text from your OP? I don’t see text e.g about jsbundling-rails, propshaft, etc.

Sprockets + jsbundling-rails + cssbundling-rails is my preferred setup and would recommend it for a new app if you need a front end that is too complex for import maps.

I migrated a large Rails app from Webpacker to that setup with Webpack and it is light years better in performance, maintainability, and reliability.

I would probably go use esbuild with the bundling gems in a new app.

Hi, great guide.

Maybe it would be good to specify that whatever you use, you need Sprockets or Propshaft, unless you use Wekpacker or Shakapacker.

As explained now, it is understood that you have to choose between Sprockets, Propshaft, importmaps or jsbundling and cssbundling.

If you use importmap, you must use Sprockets or Propshaft.

If you use jsbundling or cssbundling or both at the same time, you must also use Sprockets or Propshaft.

If you use Webpacker or Shakapacker, you do not use Sprockets or Propshaft.

Anyway, now I see no reason to continue with Webpacker or Shakapacker, having jsbundling and cssbundling.

In my opinion, I would not recommend the use of unofficial or unmaintained gems, such as Webpacker or Shakapacker.

What do you think?

2 Likes

Interesting guide. Re-reading what I’ve written, I am not responding to this guide, per se, but to the choices made by Rails over the past few years when it comes to handling “assets”. (If I knew how to do ironic finger quotes, I would do them.)

I tried using webpacker several times over the last several years - particularly with new projects, but compared to using webpack it was a combination of “configuration: too hard”, “availability of webpack options: not good enough” and “directory naming: poor choices”.

Instead I use a hybrid approach: webpack/minipack** (not webpacker) for my work, and I let gems do their own thing, which is generally sprockets.

Now reading this guide I keep seeing “webpack: too hard”. I look at the multitude of options offered and which you should use depending on your capabilities and your type of application and it looks too hard. The hardest parts of configuring webpack have been conforming to Rails expectations of where javascripts, css, and images should live.

Import Maps looks as though it is the way to go, but then…

This [Import Maps] is a very different approach to handling javascript and css files and will require extensive work to migrate, specially if you have a lot of frontend code or rely on many node packages. … so perhaps not recommended.

Propshaft is still in alpha

…will also allow you to later webpack with the phenomenal esbuild …

There is a word missing here - I assume its “replace”.

All in all, looking at this it seems as if webpack and its successors continue to be a better path than the changing, changing, and changing again options that Rails has been offering.

I don’t have a well thought-out suggestion to offer, but I think if Rails stood back from taking decisions about frontend frameworks and let users pick the most suitable (popular/elite/easy) approach for a project, it would be better in the long run.

Anita

** Minipack, with minimal configuration, provides Rails helpers to handle webpack manifests.

1 Like

I’ve had some time to talk to others, and was offered a simplified explanation of what you are expected to choose:

The default (without node/yarn)

  • Rails 7: Import Maps + Sprockets
  • Rails 8: Import Maps + Propshaft

The “choose your own bundler” (with node/yarn)

  • Rails 7: Bundling Gems + Sprockets
  • Rails 8: Bundling Gems + Propshaft

I’ll also admit that the way I’ve written this guide makes it look more complicated, because I was trying to explain all the gems and give advice for three different types of users.

3 Likes

I wish we had this same guide for folks who are on Rails 6.

1 Like

Thanks a lot for all of this work @brenogazzola.

Should Upgrading Ruby on Rails — Ruby on Rails Guides should include part of this guide with only the mention “If you have an existing app” ?

I am wondering if guide should give an example with a basic tailwind, some custom code JS and CSS code and Stimulus (even a basic tree view in text). Especially on code organization. I see for example file migration on shakapacker migration guide.