Moving from Asset Pipeline and Sprockets to Webpacker in Rails

02 Feb 2021

In 2018 my Rails 4.x project was given the task of making React “work” inside one of its pages. An additional requirement was to use Webpacker as it had recently been announced as the coming default of Rails 5. We bolted it in to the application but nobody really understood how it worked, interacted with other JavaScript, or how to finish the job of moving to Webpacker.

It’s now 2021, we’ve upgraded Rails a few times, and a ticket to “finish the move to Webpacker” landed on my pair and I. After a lot of searching the internet, copious floundering and cursing, we completed the story in a manner of speaking. It was not easy. Hopefully, this post can help someone save a bit of time.

8 things to know about moving from Asset Pipeline (which uses Sprockets) to Webpacker in Rails:

First, Webpacker is a gem and Webpack is a whole system of bundling assets into modules for “modern JavaScript applications.” Webpacker, the gem, wraps Webpack and provides some methods for using it with Rails.

Second, Modern JavaScript is sometimes called ECMAScript. ECMAScript is the API standard that JavaScript happens to implement. Browsers support ES standards but developers write in a version of JavaScript that implements that version’s ECMAScript protocols. If you’ve stepped away from JavaScript for a bit, this (and everything else about ‘modern’ JS) can be confusing.

Third, Most modern JS development involves Node.js. React relies on Node. Node.js is an event-driven JavaScript runtime. Writing for an event based runtime in the style of a thread based runtime (old-style JS) can be made to work and will be an absolute maintenance, debugging, and upgrade nightmare. A good developer can easily write some very bad code if they don’t understand event-driven architecture patterns. The differences are comparable to the differences between object oriented and functional programming. Spend some time understanding Node.js and the event-driven model before attempting to write anything of consequence.

Fourth, You do not need to move from Asset Pipeline to Webpacker all at once. Nobody sensible moves a legacy Rails application from pre-Node JavaScript and Rails’ Asset Pipeline to modern JS and Webpack in one release because it is not trivial. Any custom pre-Node JavaScript in your application can be converted to Node compatible JS but there are new concepts to grok and gotchas abound.

Fifth, Asset Pipeline and Webpacker can live together as you make the transition. In Rails 4.x, 5.x, and 6.x a legacy Rails application will continue to use Asset Pipeline for the non-Node JavaScript and the assets (images/css) it needs while using Node’s Webpack to handle Node.js assets.

Sixth, You really don’t have to worry about browser compatibility when working with Node.js because of Babel. It translates JavaScript down to whatever version you wish to support. This is nice but means the JavaScript that runs on the browser will be different than the source. Luckily, JS source maps can work with browsers to bridge that bit of indirection.

Seventh, Node.js has serious opinions about scope. This means old-style JS that is used to everything being in the global space will not be able to talk with Node JS unless that code is explicitly exposed globally. Generally, it is considered better to re-write in Node style any old JS that needs to communicate with Node JS code.

Eighth, Ross Kaffenberger’s website is an amazing resource on this subject. He’s compiled his blog posts about Rails, Webpacker, and the Asset Pipeline at https://rossta.net/webpack-on-rails/ This deep dive into all the settings contained in webpacker.yml helped me solve a 2 year old problem in my codebase: https://rossta.net/blog/how-to-use-webpacker-yml.html

To sum up: Moving from old-style JS to Webpack and Node should be an iterative process. Find the seams (see Michael Feathers “Working Effectively with Legacy Code”) and move chunks one at a time to give your QA a chance at catching all the bugs you will create. Many stories make the labor, if not light, then perhaps less crushing.