Starting with Rails 6, Webpacker became the default asset compiler, replacing sprockets–better known as the asset pipeline. While the asset pipeline was a big step for its time in making it easy to package JS, CSS, and images, webpack has matured enough to do all of the above and more, due to modern JavaScript’s support for modular imports and exports.
Personally, the biggest benefit of webpacker is how it encourages me to think about structuring assets as components, so that they are theoretically portable and do not rely on hidden globals. And by using an extensible tool like webpack under the hood, you can take advantage of popular plugins and customizations to tune what you need – like deduplicating shared imports, in both JS and CSS. Finally, you’re not limited to just extending webpack: it’s much easier to tap into the huge ecosystem of npm packages.
Below is a breakdown of how to start moving from sprockets to webpacker.
In Rails projects that use the asset pipleine, we are accustomed to seeing the frontend assets organized like so:
app assets images javascripts stylesheets
With webpacker, the project will end up looking like:
app javascript images packs stylesheets
bundle add webpacker
bundle exec rails webpacker:install
bundle exec rails webpacker:install:react # To optionally add React support. See Webpacker documentation for other supported frontend frameworks
The JS entrypoint changes from app/assets/javascripts/application.js to app/javascript/packs/application.js.
These polyfills ensure that modern JS features (promises, async/await, arrow function expressions, and more) are available on the browsers you intend to support, which is indicated by the .browserslistrc file.
yarn add core-js regenerator-runtime # Yarn is a pre-requisite: https://yarnpkg.com/
Then at the top of your new entrypoint:
// app/javascript/packs/application.js
import "core-js/stable"
import "regenerator-runtime/runtime"
# E.g. app/views/layouts/application.html.erb
javascript_include_tag "application"
can be replaced by
javascript_pack_tag "application"
Stylesheets can move directories:
app/assets/stylesheets => app/javascript/stylesheets
To get Webpacker to handle your styles, you need your JS entry point to import your stylesheet:
// app/javascript/packs/application.js
/**
* Refers to app/javascript/stylesheets/application.scss (or application.css)
* Note that we don't need to preface this path with "app/javascript" due to the `source_path` config set in config/webpacker.yml. Magical!
* The file extension can be left off due to the `extensions` config in config/webpacker.yml.
*/
import "stylesheets/application"
# E.g. app/views/layouts/application.html.erb
stylesheet_link_tag "application"
can be replaced by
stylesheet_pack_tag "application"
Images can move directories:
app/assets/images => app/javascript/images
Uncomment the generated block to make your pack aware of everything in the images directory:
// app/javascript/packs/application.js
const images = require.context('../images', true)
const imagePath = (name) => images(name, true)
# E.g. app/views/layouts/application.html.erb
image_tag "foo/bar"
Can be replaced by:
image_pack_tag "foo/bar"
Update your CI and deployment processes to fetch npm dependencies. For an example, see the CircleCI config in the Carbon Five Rails template app: https://github.com/carbonfive/raygun-rails/blob/master/.circleci/config.yml
Webpack 4 has a new plugin to split chunks, which allows for shared dependencies to be broken into their own file (“chunk”). These dependencies can be more easily cached independently of your application code. To opt into using split chunks, enable the config and update your views:
// config/webpack/environment.js
const { environment } = require(‘@rails/webpacker’)
environment.splitChunks()
module.exports = environment
# E.g. app/views/layouts/application.html.erb
javascript_packs_with_chunks_tag "application" # Replaces javascript_pack_tag "application"
stylesheet_packs_with_chunks_tag "application" # Replaces stylesheet_pack_tag "application"
If you find it strange to nest stylesheets and images under a “javascript” folder, Webpacker allows you to rename this directory, with minimal configuration changes.
mv app/javascript app/frontend
// config/webpacker.yml
source_path: app/frontend
Frontend gems can be replaced by corresponding npm packages. For example, we removed these four from our Rails app template:
Remove the Sprockets railtie from config/application.rb. You may need to expand the default require statement (“rails/all”) and explicitly state which railties you want to use. For reference, see the list of ‘all’ railties for the version of rails you are using: https://github.com/rails/rails/blob/master/railties/lib/rails/all.rb
# E.g. config/application.rb
require "active_job/railtie"
require "active_record/railtie"
# require "sprockets/railtie"
Remove any configs still in the Rails.application.config.assets namespace.