đ Goodbye Sprockets. Welcome Webpacker
A simple guide to switch from Sprockets to Webpacker
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:
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:
- Remove
//= require_tree .
from your oldapp/assets/application.js
- Move all files and folders from
app/assets/javascript
to/app/javascript/src
(exceptapplication.js
) - 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.