Replacing the Rails 5.1 asset pipeline with webpacker 3
My last post was about using webpacker
v3 on Rails 5.1.
This time I want to explore how to replace the traditional sprockets
-based asset pipeline completely.
Our goal will be to add Bootstrap v4 and jQuery v3 to an app, handled entirely through webpacker
. We won’t even install the sprockets related gems.
We’ll also enable rails-ujs
, turbolinks
, and even images using webpacker.
First steps
Let’s start with a new app:
1rails new look_ma_no_sprockets --skip-spring --skip-sprockets --webpack
Notice that Gemfile
is rather sparse and leaves out all the sprockets related gems.
Next, create a controller, skipping the default assets that would be for sprockets:
1rails g controller home index --no-assets
2
3# We'll need these in a minute:
4mkdir -p app/javascript/stylesheets app/javascript/images
And make the new route the default in config/routes.rb
:
1Rails.application.routes.draw do
2 root 'home#index'
3end
Plumbing in webpacker
Now let’s adjust our layout file to use webpacker assets.
In app/views/layouts/application.html.erb
, replace the default stylesheet and javascript tags with their webpacker equivalents:
1<head>
2 <title>LookMaNoSprockets</title>
3 <%= csrf_meta_tags %>
4
5 <%= stylesheet_pack_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
6 <%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %>
7</head>
We’ll be creating all stylesheets in app/javascript/stylesheets/
. Yes, it’s a bit of an odd place, but it keeps everything for webpacker in app/javascript/
, which is especially helpful if you decide to use both sprockets and webpacker.
Create app/javascript/stylesheets/application.scss
:
1.webpacker-test {
2 color: blue;
3}
Add this line to the bottom of app/javascript/packs/application.js
:
1require.context('../stylesheets/', true, /^\.\/[^_].*\.(css|scss|sass)$/i)
FYI, the true
in the second argument is whether to search all subdirectories. We’ll leave it as true here, but know that you can restrict which directories are searched if you need to.
Let’s also replace app/views/home/index.html.erb
with a few things to help us check our progress:
1<h1>Home</h1>
2
3<div class="webpacker-test">
4 I will be blue if webpacker's CSS is working.
5</div>
6
7<div class="bootstrap-test text-success">
8 I will be green if bootstrap is working.
9</div>
10
11<div class="jquery-test">
12 jQuery is not yet working.
13</div>
14<script>
15 $(function(){
16 $(".jquery-test").html("jQuery is working.");
17 });
18</script>
Once this is in place, go ahead and fire up rails server
and check your work at http://localhost:3000/
. You should see the “blue” test pass, but not the other two (yet).
Your browser’s console log should also show “Hello World from Webpacker”. (If you don’t see it, make sure you’re showing all logs, not just errors.)
Adding jQuery and Bootstrap
Now let’s get Bootstrap going. Since Bootstrap depends on jQuery and popper.js, we’ll handle those too.
As of this writing, Bootstrap 4 is at beta 2. Once v4 is fully released, you can drop the @version
part off the end.
1yarn add jquery popper.js bootstrap@4.0.0-beta.2
2
3cp node_modules/bootstrap/scss/_variables.scss app/javascript/stylesheets/
4ruby -pi -e 'gsub(/ !default/, "")' app/javascript/stylesheets/_variables.scss
The last two lines above prepare a copy of Bootstrap’s variables for your app to customize. We won’t customize it here, but it’ll be ready for you later.
Next, add the following three lines to the top of app/javascript/stylesheets/application.scss
. These will instruct our app to use Bootstrap’s CSS.
1@import '~bootstrap/scss/functions';
2@import 'variables';
3@import '~bootstrap/scss/bootstrap';
We also need to import jquery
and bootstrap
in our app/javascript/packs/application.js
. Here’s the complete new file:
1import $ from 'jquery'
2global.$ = $
3global.jQuery = $
4
5import 'bootstrap'
6
7require.context('../stylesheets/', true, /^\.\/[^_].*\.(css|scss|sass)$/i)
Finally, we need to help jQuery and popper.js be seen by other .js files you’ll write. Replace config/webpack/environment.js
with the following:
1const { environment } = require('@rails/webpacker')
2
3const webpack = require('webpack')
4environment.plugins.set(
5 'Provide',
6 new webpack.ProvidePlugin({
7 $: 'jquery',
8 jQuery: 'jquery',
9 'window.jQuery': 'jquery',
10 Popper: ['popper.js', 'default'],
11 })
12)
13
14module.exports = environment
If you reload the page in your browser, you should now see some green text indicating Bootstrap’s CSS is working. The jQuery message should also have changed to show it is also working.
rails-ujs and turbolinks
If you want to use rails-ujs (and you probably do, since Rails 5.1 now encourages remote/ajax forms), we now install it via yarn too.
1yarn add rails-ujs
Then, to app/javascript/packs/application.js
, add:
1import Rails from 'rails-ujs'
2Rails.start()
Adding turbolinks is similar.
1yarn add turbolinks
In app/javascript/packs/application.js
, add:
1import Turbolinks from 'turbolinks'
2Turbolinks.start()
Images
Images work a bit like stylesheets, in that they’ll be placed in app/javascript/images/
.
Add this to app/javascript/packs/application.js
, right after to the stylesheets line:
1require.context('../images/', true, /\.(gif|jpg|png|svg)$/i)
Using images (or other similar assets) within Rails views looks a little bit different from before. Use asset_pack_path()
inside the main asset helper, like this:
1<%= image_tag(asset_pack_path('images/abc.svg')) %>
Wrapping it up
That should be about everything. If you find a better way to do some part of this, please add a comment below.
For that matter, I’d love to hear how it goes for you.
tags: rails, webpacker, bootstrap
To have the Rails object available generally, I think you need to add:
global.Rails = Rails;
to the application.js file.
Thanks for the nice article. Very helpful.
Yep, that should work great. Thanks for the helpful contribution!
Thank you very much for putting this together. It was extremely helpful and the go-to guide while I was clean-slate restarting my app with webpack(er) instead of the asset-pipeline.
You’re very welcome. Glad it helped!
You need to change set to prepend in the environment.js file for Rails 5.2
environment.plugins.prepend(
‘Provide’,
new webpack.ProvidePlugin({
$: ‘jquery’,
jQuery: ‘jquery’,
‘window.jQuery’: ‘jquery’,
Popper: [‘popper.js’, ‘default’],
})
)