The rationale, Hampton argued, was that the core maintainers of lib-sass, a project in which Hampton was not currently involved, had since switched preferences for the Dart compiler version, as it would be easier to support by the Node community in the future. It was too difficult to find a C++ developer to maintain the old dependencies.
The answer came down from atop the Rails team: A decided no.
Let’s back up.
|Rails 3/3.1/3.2||2011||none||Sprockets was built-into Rails|
|Rails 4.1||2014||jQuery||Sprockets was sass-rails dependency|
|Rails 4.2||2014||jQuery & CoffeeScript||Sprockets was sass-rails dependency|
|Rails 5.0||2015||jQuery, CoffeeScript, Turbolinks||Sprockets was sass-rails dependency|
|Rails 5.1||2017||jQuery, CoffeeScript, Turbolinks||Sprockets was sass-rails dependency|
|Rails 5.2||2017||CoffeeScript, Turbolinks||Sprockets via sass-rails dependency|
|Rails 6.0||2019||Webpacker, Turbolinks||via sass-rails dependency|
|Rails 6.1||2020||Webpacker, Turbolinks||Sprockets via sass-rails dependency|
|Rails 7||2021||Import Map, Turbo Rails, Stimulus||Gone!|
replaced with JSBundling
replaced with CSSBundling
|Sprockets as default.|
History of Sprockets aka The Asset Pipeline
Sprockets, also known as ‘the asset pipeline,’ was first introduced in 2011 as part of Rails 3.1.
Then, in 2014, Sprockets was extracted out of Rails into its own Gem with the release of Rails 4.0 (a gem called sprockets-rails). To be clear, you were still encouraged to use Sprockets, but Rails 4 now shipped with jQuery + CoffeeScript as the default and Sprockets as opt-in using the sprocket-rails gem. It did not come installed by default with a new Rails app.
Sprockets looks like this
Sprockets required us to define a manifest file for each part of our app.
Introduce “ES6” aka ECMAScript 2015
You would use jQuery to pick at the DOM via targeting. Things lived in global namespaces. Parts of the codebase had no separation, composability, or dependency management. Like I said, they were dark times.
Then, ES6 Modules become the de-facto way to write modern JS: Defining encapsulated functionality within a module, exporting it explicitly, and then importing the functionality in the places where you want to use it.
You can get a quick dive into ES Modules, once referred to as ES6 Modules, here.
This worked, to a point and in theory. In practice, many people just loaded huge asset pipeline files and didn’t notice how much JS they were loading into their browser.
Enter Webpack & Webpacker
A Ruby extension named webpacker provided the glue between Ruby and webpack.
Webpacker and webpack solved an important problem but introduced new ones. Like Sprockets, Webpack created bundles that used thumbprint digests to expire them.
The Overpacking Problem
As discussed in this excellent post many apps suffered (and still do today) from an overpack problem.
The Speed, or Lack Thereof
One of the significant hurdles for Rails developers adopting Webpack is how slow it is to make changes. A good tool called web-dev-server allows you to rebuild CSS quickly while developing, but still running this extra overhead seemed like another thing to have to worry about to the Rails core team.
Also, having webpack in the build pipelines turns out to be slow. There then becomes a lot of work to deal with this slowness in your pipeline.
When Internet Explorer still existed and before browsers widely supported HTTP2 and ImportMap, this was all necessary. However, now that IE is dead and the browser support HTTP2, the story has changed.
DHH’s explained his reasons for switching away from Babel and transpiling with Node in a blog post from Aug 12, 2021. As discussed above, digest-based manifest files required expiring the entire manifest file for every change, creating a slow development workflow.
Two key advancements in browser technology:
- The universal adoption of ES Modules across all modern browsers obviates the need for transpiling with bundler. Of course, if you still are targeting old browsers you would still need a bundler. But with support ES Modules in all browsers Babel transpiling is no longer needed.
This giant leap forward in browser technology is only because of very recent advancements.
They are supported natively in Chrome and Edge browsers and work via a shim for Firefox and Safari. Fortunately, the Rails core team has packed the shim into the importmap-rails gem which comes by default with new Rails 7 apps.
As well, 2022 saw the entry of a new player in CSS bundling options for Rails: cssbundling-rails. This is an augmentation to Sprockets and makes the following changes to your Rails app.
app/assets/builds is now where application.js and applicatoin.css files live
2. these hold your bundled output as artifacts that are not checked into source control
To install it, you have one of two options:
- Start your new Rails 7 project with
rails new MyGreatApp --css=bootstrap)
- Don’t start with
--css=bootstrapand instead Add
gem 'cssbundling-rails'to your Gemfile and then install it with
Or, you can install any of Tailwind, Bulma, PostCSS, or SASS either.
If you use the cssbundling-rails installer, the installer adds this directory to
.gitignore by default.
Goodbye Node & Node Packages
Will Rails ever bring Webpack back by default? Probably not. Do you need to listen to the Rails core team and eject Node yourself? Absolutely not.
For one thing, building a React frontend packaged inside of your Rails app — still a great deployment option — still will require transpiling for the time being. Be sure to read my guide Rails 7 : Do I need ImportMap-rails to understand if you need or want Importmap-Rails or JSBundling.
4 thoughts on “When Rails Ejected Node and the History of Compiled JS in Rails”
If you use the gem “cssbundling-rails”, you STILL need to have Nodejs!
See the “About” paragraph on https://github.com/rails/cssbundling-rails :
“Bundle and process CSS in Rails with Tailwind, PostCSS, and Sass *via Node.js*.”
Yup John that is correct. see also https://jasonfleetwoodboldt.com/courses/stepping-up-rails/rails-7-do-i-need-importmap-rails/ and https://jasonfleetwoodboldt.com/courses/stepping-up-rails/rails-7-new-app-with-js-bundling-css-bundling/ to help navigate
I think webpacker may have actually been introduced in Rails 5.1. It was listed as optional in the release notes then: https://guides.rubyonrails.org/5_1_release_notes.html
Yes thank you for this. the chart above show what was in the default Gemfile when creating a new Rails app. You are correct that some of the options (like webpacker) were available as opt-in before they became default.