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:
How and where to handle assets is in a confusing state, 1 foot in asset pipeline and one foot in webpacker... If that is going to be a long last direction vs a transition we should make the best practices more clear in guides and how to ensure they play nicely together— Dan Mayer (@danmayer) May 8, 2020
Even @avdi just last week:
Will someone please explain to me why after all the foofaraw about Rails 6 going to webpack, I'm still having to unfuck Sprockets in my application.rb— Avdi Grimm (@avdi) May 3, 2020
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:
The similarities exist. Both Sprockets and webpack will:
- combine many source files into one or a few destination bundles for production
- transpile source files from one syntax to another
- minify and fingerprint assets when building for production
- rebuild modified source files in development incrementally
However, Sprockets and webpack solve asset bundling in very different ways.
So why would Rails include both?
@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?
There's a lot to unpack there.
rails assets:precompile will first build all the Sprockets assets into the
public/assets directory, then will build all the webpack assets into the
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.
import '../application.css' import myImageUrl from '../images/my-image.jpg'
This isn't just a "Rails opinion". Consider this recent tweet from a prominent voice in the React community, Ryan Florence:
import url from "./whatever.jpg"— Ryan Florence (@ryanflorence) May 9, 2020
import html from "./some.md"
import str from "raw!./some.js"
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:
- Upgrading my legacy Rails app to Webpacker would be too costly
- I don't need advanced tooling for local development
- It just works and I don't have time to ramp up on alternatives
- My Rails app relies on specific asset gems and I don't have NPM alternatives
Why not Sprockets?
- Sprockets is slowing down my local development experience
- I need more control over aspects of our asset compilation
- I'm concerned about long-term support
- I want to take advantage of the cutting edge features from ES6+, Babel, PostCSS
- I want intelligent code-splitting features such as dynamic imports and webpack's splitChunks optimization
- I want more flexibility with how my build system generates source maps
- I want advanced tooling for local development including hot module replacement
- I want to build Single Page Apps*
*You don't need to have a Single Page App to use webpack; it works quite well for "Multi Page Apps".
Why not Webpacker?
- I am not ready to invest time to understand webpack and Webpacker
- It seems too complicated
Why use both?
- I'm upgrading from Sprockets to Webpacker incrementally
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.
Which is right for you?