Since you're reading this post, chances are you've heard Rails 6 installs both Webpacker and Sprockets and you're wondering WTF is going on. By the way, it's a whole May of WTFs for Rails.

Wait, don't Sprockets and Webpacker basically do the same thing?

If this is what you're thinking, you're not alone.

Curious about or need help with webpack? I may be able to help! I'm developing a course for webpack on Rails and I frequently write about it on this blog.

Subscribe to my newsletter to get updates.

The question keeps coming up, like in this Reddit post, or this StackOverflow question, or this other Reddit post.

Here's my colleague @danmayer:

Even @avdi just last week:

It's clear the Webpacker-Sprockets co-existence is catching many by surprise. There's good reason for that too.

You wouldn't be wrong to think Sprockets and webpack solve the same general problem:

Packaging assets (JavaScript, CSS, images, fonts) for the browser

The similarities exist. Both Sprockets and webpack will:

However, Sprockets and webpack solve asset bundling in very different ways.

Sprockets was introduced way back in 2007 (!), before Node.js, before the Cambrian explosion of JavaScript, before module specifications like CommonJS, AMD, and EcmaScript modules, before webpack, browserify and $ANY_MODULE_AWARE_ASSET_BUNDLER. Sprockets has not attempted to keep up with improvements in tooling, language features, and browser capabilities (save for source maps) as other projects in JavaScript community have.

Webpack, on the other hand, fully embraces the concept of JavaScript modules. It integrates with Babel, PostCSS, and just about any recent web framework. It supports a number of module syntaxes, including dynamic imports for code splitting. There are a wide variety of configurable source map options. Top to bottom, the webpack compilation process is extremely modular and customizable.

So why would Rails include both?

Here's the answer plain and simple straight from DHH back in 2016 when Webpack was first introduced as the recommended JavaScript compiler with Rails 5.1.

We will continue to use the asset pipeline for JavaScript sprinkles, CSS, images, and other static stuff. The two approaches coexist great.

To elaborate on this decision, there was a telling response from DHH on his GitHub pull request to make Webpacker the default JavaScript compiler in Rails 6:

DHH: Webpack’s support is awkward in my opinion and does not offer any benefits over Sprockets. Unlike in the realm of JavaScript compilation.

@dwightwatson Out of curiousity, what is the argument to continue using Sprockets for CSS/static assets when Webpacker supports them by default out of the box?

@dhh Webpack’s support is awkward in my opinion and does not offer any benefits over Sprockets. Unlike in the realm of JavaScript compilation.

There's a lot to unpack there.

When it comes to asset bundling, the "Rails way" is webpack for JavaScript and Sprockets for everything else. The default setup in a fresh Rail 6 install, similar to what Basecamp uses, still compiles CSS, images, and fonts with Sprockets.

This means, if you're a member of the Basecamp camp, all your webpack JavaScript source files would live in app/javascript and all your Sprockets CSS and images would remain in app/assets. Running rails assets:precompile will first build all the Sprockets assets into the public/assets directory, then will build all the webpack assets into the public/packs directory.

To be very clear, this does not mean you need to run both Sprockets and Webpacker to serve assets for the browser. The two processes for bundling assets are completely separate and they do not share dependencies. Different helpers, different implementations, different directories, different, different, different. They are built in such a way that they can cohabitate a Rails application.

On the other hand, you could use only Sprockets or only Webpacker to bundle all your assets.

Feeling, awkward?

DHH calls webpack's approach to handling non-JavaScript assets awkward. Now, I happen to like webpack a lot. But he's not wrong.

He says this because, to bundle CSS and images in webpack, you need to import CSS and images from your JavaScript files.

import '../application.css'

import myImageUrl from '../images/my-image.jpg'

The reason for this is that webpack wants to treat everything as a JavaScript module. I mean everything.

All JavaScript imports are treated as JavaScript modules. To use CSS with webpack, you import it as you would a JavaScript module. To use an image with webpack, you import it as you would a JavaScript module. Depending on your perspective, this may be unusual—perhaps especially for Rails developers coming from Sprockets.

This isn't just a "Rails opinion". Consider this recent tweet from a prominent voice in the React community, Ryan Florence:

Sounds a lot like discovering Sprockets in reverse? (I'm not surprised at that 50/50 split either).

While awkward to some, webpack's "Everything is a Module" mindset is also extremely powerful. There are some interesting possibilities when a tool goes all in with such a mental model. Think of what "Everything is an Object" has done for Ruby.

Choosing Webpacker or Sprockets (or both)

The good news is there's no need to stress about it. Rails defaults mirror the preferred approach of the Basecamp team, but that doesn't mean you have to agree or that it's the right way to do things for your application. You can use both, as Basecamp does, or choose one over the other.

To help you decide, I adapted this excellent guide from the react-rails project:

Why Sprockets?

Why not Sprockets?

Why Webpacker?

*You don't need to have a Single Page App to use webpack; it works quite well for "Multi Page Apps".

Why not Webpacker?

Why use both?

On a personal note

I want to leave Sprockets behind. Sprockets was a huge leap forward for asset management when it was first introduced but it hasn't taken advantage of newer possibilities. It languishes while webpack's key features, such as performance optimizations through code-splitting, are first class.

Webpack is more complex and does require some investment. For me, it's been worth it.

I think webpack is a great choice for any application with a significant amount of JavaScript.

Which is right for you?

Discuss it on Twitter · Published on May 9, 2020

Need help with webpack on Rails?

My name is Ross Kaffenberger.

Webpacker now ships by default in Rails 6 but there's no need to stress. I'm putting together a course to help you master webpack on Rails.

I teach full stack web developers about frontend tools and performance, especially at the intersection of JavaScript and Ruby on Rails.

Subscribe to stay in the loop.

    Powered By ConvertKit

    More posts

    The webpack plugin I can't live without

    In this post, we'll take a look at installing and using the webpack-bundle-analyzer, perhaps the most invaluable webpack plugin, to analyze and debug the output of the webpack build in a Rails project configured to use Webpacker.

    How to debug webpack on Rails

    Understanding your Rails webpack configuration and build output can be a little confusing, especially if you're new to either Rails or webpack. This post contains a few tips for debugging your Webpacker setup, some specific to Rails Webpacker, some generally applicable to webpack.

    How to customize webpack in Rails apps

    Configuring webpack is precisely the main job of Webpacker's NPM package, @rails/webpacker. This post provides an overview of how to customize its default settings for your Rails application.

    Julian ebert farmland unsplash
    Photo by Julian Ebert on Unsplash