JavaScript in Rails 7

Frontend in Rails will be very different from Rails 6.

Written by Rico Sta. Cruz
(@rstacruz) · 20 June 2022

JavaScript in Rails 7 will be different: the Webpacker gem has been retired, and there are 2 new gems to manage frontend files.

In this article:
  1. Webpacker has been retired
  2. The importmap-rails gem
  3. The jsbundling-rails gem
  4. The Shakapacker gem
  5. Comparing them all
  6. Links

Webpacker has been retired

Webpacker was the gem that Rails used to integrate Webpack, and Webpacker 5 will be the last version. The Webpacker 6 release candidate is now going to be community-maintained under a new name. (source)

Webpacker has been retired as of 2022 according to the project's README.

What’s after Webpacker?

There are now 3 options that I know about:

  • importmap-rails — This gem is the new Rails 7 default. The importmap-rails gem allows using npm packages in the Rails asset pipeline.

  • jsbundling-rails — An alternative that unifies support for any Node.js-based bundler (Webpack, Rollup, esbuild) under one gem. However, it only supports a subset of features that Webpacker does.

  • shakapacker — A community-supported continuation of Webpacker maintained by Shakacode, now called Shakapacker.

The importmap-rails gem

The importmap-rails gem will come pre-loaded in Rails 7, and seems to be the answer to the question “how do I use npm packages in Rails?”.

importmap-rails is a new gem to integrate JavaScript in Rails without transpiling or bundling.

What is import-map?

Import-map is a lightweight tool to transform imports from npm module names (eg, “react”) into URL’s, useful for loading scripts from an external CDN.

example.js
// Transforms this:
import React from 'react';
// Into this:
import React from 'https://ga.jspm.io/npm:[email protected]/index.js';

Importing URL’s?

Yes, using import in the browser is natively supported by all modern browsers—no bundlers needed! Importing URL’s inside a script tag should work. (docs)

esm_example.html
<script type='module'>
import confetti from 'https://cdn.skypack.dev/canvas-confetti';
confetti();
</script>
Try this example at skypack.dev.

No compiling

There is no “build” or “compile” step in importmap-rails. There’s no Babel, PostCSS, or anything that transforms JavaScript code.

  • No npm/yarn required. It can be used with npm, but the recommended experience appears to be to use the jspm.org CDN. (article)

  • What about JavaScript modules (“esm”)? While Babel has often been used to convert ESM modules into common JavaScript code, Rails with importmap doesn’t do this. Instead, it relies on browsers’s built-in ability. (docs)

  • Limited React support. Because there is no compilation step, there is no support for build-time JSX compilation (it would have to be done on runtime using something like htm).

  • Limited legacy browser support. import-map relies on <script type="module"> which is not supported on IE11. (caniuse)

No bundling

It doesn’t combine many JavaScript files into one, unlike bundlers like Webpack. Rather than serving all files under one application.js, import-map will load all files individually(!).

https://example.com/assets/application-1a2b3c4d.js

Most applications would often serve a bundle of JavaScript like that above. However, import-map’s approach would be to not bundle the files, and serve them individually instead:

https://example.com/assets/application-1a2b3c4d.js
https://example.com/assets/components/button-1a2b3c4d.js
https://example.com/assets/components/radio-1a2b3c4d.js
https://example.com/assets/components/dialog-1a2b3c4d.js
https://example.com/assets/components/carousel-1a2b3c4d.js

Downsides

  • No tree-shaking. Since npm packages are loaded as-is (and often from a CDN), the benefits of removing unused code (“tree-shaking”) isn’t available when using importmap-rails.

  • HTTP2/SPDY is needed. Well, not required, but HTTP2 multiplexing will be needed to make loading hundreds of JS files a practical solution. (codavel.com: HTTP2 Multiplexing explained)

👋
Hey! I write articles about web development and productivity. If you'd like to support me, subscribe to the email list so you don't miss out on updates.

The jsbundling-rails gem

The jsbundling-rails gem appears born out of the desire to use Webpack alternatives in Rails.

jsbundling-rails readme on GitHub
jsbundling-rails enables support for esbuild, Rollup, Webpack and more.

Lighter than Webpacker

While Webpacker offered very tight integration with Webpack (even its configs are in Ruby and Yaml), jsbundling-rails is a more “lightweight” integration. The main source code is less than 20 lines: all it does is invoke “yarn install && yarn build” before asset precompilation.

Screenshot
Source code is only around 20 lines. Via: jsbundling-rails/build.rake at main · rails/jsbundling-rails (github.com)

esbuild, Rollup, and Webpack

Apart from Webpack, there are other bundlers supported. esbuild is a very fast alternative written in Go, and Rollup is a popular alternative often used with libraries.

Migration from webpacker

Seems straightforward. The goal is to set up Webpack as you would in a Node.js project (eg, work without Webpacker) and that’s it. The jsbundling-rails migration guide has more details.

Downsides

  • No code splitting support. Webpack’s ability to lazy-load certain parts of the bundle is not supported. (webpack.js.org: Code splitting)

  • No hot reloading. Be ready to press F5 a lot.

The Shakapacker gem

The work on Webpacker has been continued by ShakaCode and was named for their company. Shakapacker is based off of the unreleased Webpacker 6. (The last Webpacker version is 5.)

Comparing them all

import-mapjsbundlingshakapacker
npm modulesCDN only
Code splitting--
Hot module reloading--
React JSX support-
Delivery to the end userMultiple filesBundledBundled
Tree-shaking optimisation-

Written by Rico Sta. Cruz

I am a web developer helping make the world a better place through JavaScript, Ruby, and UI design. I write articles like these often. If you'd like to stay in touch, subscribe to my list.

Comments

More articles

← More articles