👋 Goodbye Sprockets. Welcome Webpacker

A simple guide to switch from Sprockets to Webpacker

Alessandro Rodi
7 min readFeb 12, 2018

Update from 19.01.2022

PLEASE DO NOT FOLLOW THIS GUIDE ANYMORE.
DO NOT MIGRATE TO WEBPACKER ANYMORE.
RAILS 7 PROVIDES BETTER OPTIONS FOR JS BUNDLING NOWADAYS.

Updated on the 1st May 2020 for Webpacker 5.

Updated on the 30th August 2019 for Webpacker 4 and Rails 6.0 and adding custom fonts.

This guide will let you through the process of migrating your Rails Application from Sprockets to Webpacker. Even though Webpacker suggests to keep using Sprockets for CSS and images, I don’t really see why we should keep two bundlers at the same time when we can simply use Webpacker for everything.
We will then first move only the Javascript part of your code and then we’ll see also how to move CSS, images, fonts, etc…

The requirements

We’ll start this guide from a Rails application which uses Sprockets. You are probably migrating to Rails 6.0, or you did so already, and you are wondering how can you migrate also your Javascript to Webpacker in an easy way and never come back.

I suggest you to migrate your application to Rails 6.0 and then proceed with this guide, but that’s not mandatory: when developing software there are a lot of things that are not necessary but, from time to time, you should take the chance to do them 😉.

Adding the gems

The first thing to do is to add webpacker gem to our project’s Gemfile:

gem 'webpacker', '~> 5.0'

and install it, following the project’s README:

bundle
bundle exec rails webpacker:install

NOTE: In order to use Webpacker you need to have node.js installed.
The installation and configuration of node.js is not part of this guide, but I suggest you to use the latest stable version and write it in a .nvmrc file in the project root, that nvm can read.

Now we have Webpacker ready and we can already start using it! 🎉

I’ll not explain to you what Webpacker does and which files it generates: you don’t need to know this now. What you need now is to drop Sprockets. That’s our goal for today.

Test it

Is it really working? Let’s test it first.

Let’s meet our first generated folder: app/javascript. That’s the equivalent of our old, dear,app/assets/javascript folder and, as in the old one, you’ll create a packs/application.js file you can start from.

app/javascript:
└── packs:
└── application.js

# application.js
console.log('Hello World from Webpacker');

That file is the exact equivalent of app/assets/javascript/application.js: is the starting point where we’ll include all our JS resources.

Let’s add it to our template, as we did for the old one, using

= javascript_pack_tag 'application'

(you may want to add the option 'data-turbolinks-track': 'reload' if you are using Turbolinks.)

and we should see the “Hello World” message in the Chrome Developer Tools, which confirms that everything is working fine:

A reassuring “Hello World” message

Migrate Javascript

Now that we have Webpacker installed and everything is working fine we can proceed by moving our old Javascript files. Our application.js has a very simple structure:

//= require jquery
//= require jquery_ujs
//= require turbolinks
//= require bootstrap-sprockets
//= require formvalidation/formValidation
//= require formvalidation/bootstrap4.min
//= require_tree .

it basically requires some libraries (jquery, turbolinks, etc…) and then includes our custom Javascript files.
Let’s move the last ones first: the steps are easy:

  1. Remove //= require_tree . from your old app/assets/application.js
  2. Move all files and folders from app/assets/javascript to /app/javascript/src (except application.js)
  3. Import all your files in the new packs/application.js
import '../src/filename.js';

Migrate libraries

Now is time to move the libraries we are using. Since we are talking about a very simple Rails app, those are our libraries at the moment:

//= require jquery
//= require rails-ujs
//= require turbolinks
//= require bootstrap-sprockets

We need to download the equivalent npm package and require them.

Setup jquery

If you are using JQuery in your app, you probably don’t want to get rid of it now (also because Bootstrap still requires it…) so we can migrate it. Add the package:

yarn add jquery

Now we have to configure Webpacker to include it in all our environments. To do that we change the environment.js file.

# app/config/webpack/environment.jsconst {environment} = require('@rails/webpacker');

const webpack = require('webpack');
environment.plugins.append('Provide', new webpack.ProvidePlugin({
$: 'jquery',
jQuery: 'jquery'
}));

module.exports = environment;

so you can finally use it into your application.js file.

# app/javascript/packs/application.js$(function () {
console.log('Hello World from Webpacker');
});

Setup rails-ujs and turbolinks

Install the modules:

yarn add @rails/ujs turbolinks

and start them:

# app/javascript/packs/application.jsrequire("@rails/ujs").start()
require("turbolinks").start()

if you use ActiveStorage and ActionCable you can install and require them as well:

yarn add @rails/actioncable @rails/activestoragerequire("@rails/activestorage").start()
require("channels")

Setup Bootstrap

The last piece missing is Bootstrap. JQuery is in place so we can simply install the package and require it.

yarn add bootstrap popper.js

add Popper to the environment configuration:

# app/config/webpack/environment.js...environment.plugins.append('Provide', new webpack.ProvidePlugin({
$: 'jquery',
jQuery: 'jquery',
Popper: ['popper.js', 'default']
}));

...

and import the plugins:

# app/javascript/packs/application.jsimport 'bootstrap/dist/js/bootstrap';

With Bootstrap, we have successfully moved all our Javascript resources to webpack. We can remove the old application.js file and remove the import of it from our template.

As you can see, is pretty easy to move javascript from Sprockets to Webpacker. Once you understand how files and modules are organised you’ll see that is easy as it was with Sprockets and you can remove some of the gems and import the correspondent npm package. In our case, for example, we could already remove sprockets-es6 , jquery-turbolinks and jquery-rails .

Webpacker is meant to manage javascript files, therefore we can stop here and keep using sprockets for images and CSS, but it can manage also those resources, so I think is worth to take a look on how to migrate them as well.

Migrate CSS

We can manage also stylesheets with Webpacker. Our application contains some custom SCSS files in our assets folder, bootstrap and font-awesome from a gem and a stylesheet in the vendor folder.

@import 'font-awesome';
@import 'shared/variables';
@import 'bootstrap';
@import 'transactions';
@import 'custom_buttons';
@import 'formValidation.min';

We’ll start by renaming the Webpacker folder, because it feels really wrong to place stylesheets into a javascript folder. Rename the app/javascript into app/webpacker and move all the javascript files from app/javascript/src to app/webpacker/src/javascripts. Don’t forget to change config/webpacker.yml:

source_path: app/webpacker

Create a app/webpacker/packs/stylesheets.scss file and move your CSS resources inside app/webpacker/src/stylesheets folder.
The file will look very similar to your original one:

#app/webpacker/packs/stylesheets.scss@import '../src/stylesheets/transactions';
@import '../src/stylesheets/custom_buttons';

enable CSS extraction in webpacker.yml by setting extract_css: true and include the following call in your template:

= stylesheet_pack_tag 'stylesheets'

Bootstrap

To have bootstrap working, and compiled from SCSS, you can simply include the following in our new stylesheets.scss

@import '~bootstrap/scss/bootstrap';

Since we customised our bootstrap, we can import the variables as we were doing before via

@import '../src/stylesheets/shared/variables';

before the import of bootstrap.

If you were using SCSS before, in the end, it doesn’t change that much.

We need, in the end, to import font-awesome from the npm package instead of the gem.

# fontawesome 4
yarn add font-awesome
# fontawesome 5
yarn add @fortawesome/fontawesome-free

and

# fontawesome 4
$fa-font-path: "~font-awesome/fonts";
@import '~font-awesome/scss/font-awesome'
;
# fontawesome 5
$fa-font-path: '~@fortawesome/fontawesome-free/webfonts';
@import '~@fortawesome/fontawesome-free/scss/fontawesome';
@import '~@fortawesome/fontawesome-free/scss/solid';

and you can remove the old link to the sprockets file

= stylesheet_link_tag 'application'

Images

To migrate your images is pretty easy. What we are going to do is to create a pack containing all the images and import them.

Create a folder app/webpacker/images and move all your images in that folder.

Now import them in your application.js file with

require.context('../images', true);

Now all your images are available through Webpacker. To use them you need to replace your old images using the asset_pack_path helper.

 - asset_path('icon.png')
+ image_pack_path('icon.png')

Since Sprockets helper are not available anymore you need to replace them in you SCSS files:

  .google-icon {
- background-image: image-url('btn_google_dark.svg');
+ background-image: url('../images/btn_google_dark.svg');
}

Fonts

Place your custom fonts into app/webpacker/fonts folder and import them in your stylesheets.scss with:

@font-face {
font-family: YourFontFamily;
src: url('../fonts/yourfile.ttf') format('truetype');
}

Conclusion

You have successfully replaced Sprockets with Webpacker and you can start taking advantage of all the benefits of it like Hot Module Reloading or Bundle analysis.

Does this mean you won’t use Sprockets anymore? From my point of view yes.
It simply doesn’t make sense to use a slower tool with less features when using Webpacker is so easy.

Using Webpacker you can add a frontend framework very quickly as soon as you’ll need it and it’s also much faster.

If I missed something or you have questions, leave a comment.
If you want to read about some of the cool features you can use now that you have Webpacker installed, read my articles about Hot Module Reloading for CSS and Hot Module Reloading for React.

--

--

Alessandro Rodi

Open Source Software Engineer at Renuo AG. Located in ZĂźrich. I do stuff. Sometimes.