👋 Goodbye Sprockets. Welcome Webpacker 3.0

A simple guide to switch from Sprockets to Webpacker 3.0

This guide will let you through the process of migrating your Rails Application from Sprockets to Webpacker 3.0. 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 only Webpacker. If you want I have a video available of this tutorial that explains how to migrate JS and CSS (but not images).

The requirements

We’ll start this guide from a Rails 5.1 application which uses Sprockets. In our case we used EcmaScript6 and therefore we have the sprockets-es6 gem in our Gemfile (we were not using Sprockets 4).

Why didn’t we use Webpacker right from the beginnning has a really easy answer: even if Rails ❤️ Javascript, in order to use Webpacker you needed to run an additional process and have a lot of additional configuration files. All of that changed with Webpacker 3.0 and that’s why, today, we’ll switch to it and never come back.

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

Adding the gems

First thing to do is to add webpacker-rails gem to our project’s Gemfile:

gem 'webpacker', '~> 3.0'

and install it, following the project’s README:

bundle
bundle exec rails webpacker:install

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

I’ll not explain you what does this do and which files it generates: you don’t need to know that now. What you need is to drop Sprockets and that’s our goal 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 find an application.js file you can start from.

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 example 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 and then include our js and es6 files. 
Let’s move the last ones first: the steps for that are easy:

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

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 Webpack modules 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.js
const {environment} = require('@rails/webpacker');

const webpack = require('webpack');
environment.plugins.set('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.js
import Rails from 'rails-ujs';
import Turbolinks from 'turbolinks';

Rails.start();
Turbolinks.start();

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@4.0.0 popper.js

add Popper to the environment configuration:

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

...

and import the plugins:

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

With Bootstrap, we have successfully moved all our Javascript resources to webpacker. 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 that were just including javascript 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 webpack 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/javascript.

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

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

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.

yarn add font-awesome

and

$fa-font-path: "~font-awesome/fonts";
@import '~font-awesome/scss/font-awesome'
;

and you can remove the old link to the sprockets file

= stylesheet_link_tag 'application'

Images

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

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

Then create an index.js file in that folder to reference all of them. The content will look like the following:

# app/webpack/images/index.js
import './btn_google_dark.svg'
import './renuo_logo.png'
import './goody.png'
import './icon.png'

Create a file app/webpack/packs/images.js and import the content of that folder:

# app/webpack/packs/images.js
import '../images'

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')
+ asset_pack_path('images/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');
}

Conclusion

You have successfully replaced Sprockets with Webpacker and you can start take advantage of all the benefits of it like Hot Live 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. I already started using the following options when creating a new application and I really don’t miss Sprockets.

rails new my_app --skip-sprockets --webpack

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.

Good luck with your migration!

One clap, two clap, three clap, forty?

By clapping more or less, you can signal to us which stories really stand out.