Static images, css, js, fonts, videos, text files, binaries, etc
CSS and JS files change often
Images change less often
Videos and fonts don't change much
Before Rails 3.1
Before 2011
All assets in public folder or through CDNs
Issues with this approach:
Caching and cache invalidation (passing a "?timestamp" query
string in the url)
Single large file vs multiple small files
No support for languages like CoffeeScript -2009- or SASS
(TypeScript didn't exist yet)
Unoptimized file size
Hard to use existing libraries
The Assets Pipeline
With Sprockets - Since 2011
Introduced in Rails 3.1 with the `sprockets` gem as a dependency
of Rails
For Rails 4.0, the integration between Sprockets and Rails was
extracted as a new Rails dependency called `sprockets-rails`
Assets in /public were still valid
Solving problems:
Cache invalidation: a digest/fingerprint of the file content is
appended to the file name
Bundling: replaces "require" directives with the actual code (a
big long single file with all the code)
Transpilation: supports CoffeeScript and SASS/SCSS by default
Clean up files: uses compressors and uglifiers/minifiers to
remove what a browser does not need and compress the file
Easy to incorporate assets from gems instead of copying them
into the project
The `jquery-rails` gem is included as a default
Turbolinks (2013)
Included by default in new apps starting with Rails 4.0
Aims to provide a "single-page-app-like" feeling for multiple page
applications
Basic functionality works fine, but many JavaScript packages where
not fully compatible out of the box
Before Rails 5.1
Before 2016
The JS world was changing, but Sprockets kept adding features to
be compatible with it
Support of importing assets from a node_modules folder (using
Yarn)
Support for many of the new ECMAScript features (thought through
some experimental flags)
Other solutions for the same problem appeared for other
ecosystems, and the JS world changed more and more
Eventually, Webpack (2012) was the winner
Webpacker
Webpack was introduced as an option through the `webpacker` gem
for new apps with the `--webpacker` flag in Rails 5.1
The `jquery-rails` dependency was removed in favor if the
`rails-ujs` package that was part of Rails
`rails-ujs` was written in CoffeeScript, so `coffee-rails` was
now a requirement to use that feature of Rails
The Dark Ages
2019 - 2021
The JS ecosystem was changing faster than what Sprockets could
handle (new standards, new patterns, new languages, etc)
Webpack was capable of doing everything that was needed to
support that, so it was made the default for JavaScript assets
in Rails 6.0
The rest of the assets were still handled by Sprockets-rails by
default
It was possible to configure Rails to handle all the assets
using Webpacker too
Webpack cannot read assets from gems
Now gems that wanted to include assets had to also provide an
NPM package (the gem for the Rails code and the NPM package for
Webpack)
You could have both assets from Sprockets and Webpack for any of
the asset types
Multiple ways of using a feature was confusing (for example,
rails-ujs is included in Rails so it works OOTB if handling JS
assets with Sprockets, but the `@rails/ujs` package is needed in
the package.json file if using Webpack)
Where are we now?
Since 2021 (Rails 7.0)
Webpacker was retired and not a default anymore
importmap-rails, the default since Rails 7.0 (with support for
Rails 6)
jsbundling-rails, allows using other popular bundlers and not
just Webpack: esbuild, rollup, and bun
cssbundling-rails, allows using other popular CSS bundlers
(tailwind, bulma, dart-sass, etc)
vite_rails, allows using Vite to handle assets (non-official)
Shakapacker, continuation of the Webpacker gem (non-official)
`sprockets-rails` is not a dependency of Rails anymore
`turbolinks` and `rails-ujs` are replaced for new apps in favor
of `turbo-rails`
With the new defaults, new Rails 7.0 apps don't need Node to
manage assets
The future
Propshaft to solve assets fingerprinting (default in Rails 8). It
does way fewer things than Sprockets
Sprockets still supported ("for a long time" according to
Propshaft's readme)