Introducing Webpacker

Official Rails gem for bundling JavaScript assets with Webpack

With the ever-changing JavaScript world, one important thing that has been lacking in Rails was support for proper bundling system for JavaScript assets, but from Rails 5.1 this is going to change with the introduction of new Webpacker gem.

Rails 5.1 ships with webpack and yarn via the –webpack option and out of the box integration with React, Angular, vue, elm and more coming soon.

Prerequisites

Setup

Before starting out make sure ruby, node and yarn is installed on your machine. See prerequisites section for more details.

Now, open up your terminal and install rails 5.1 gem and then create a new rails app like so,

// Latest version of rails 5.1+
gem install rails
rails new webpacker-example-app --webpack
// or this to setup react or angular or vue 
rails new webpacker-example-app --webpack=react
rails new webpacker-example-app --webpack=angular
rails new webpacker-example-app --webpack=vue

Notice the new nifty -webpack option, this will setup webpack with Yarn after creating a Rails 5.1 app. Once app is created and webpacker is installed we are all set to use webpack in our new Rails app. Voila! 🎉

If you have an existing Rails 4.2+ app you can install webpacker, by adding it to your Gemfile and install it like so,

rails webpacker:install
rails webpacker:install:[react, angular or vue] (optional)

Feel free to checkout the project readme for more details, https://github.com/rails/webpacker

Note: We can also setup React or Angular if we supply the relevant options.

You can see a list of commands webpacker ships with by typing any of the following from within your app directory,

bundle exec rails webpacker
bundle exec rails -T

Configuration

As with all Rails things, webpacker also comes with certain conventions by default. Lets take a look at them one by one:

1. Folder structure

Take a look at the new app/*javascript folder. This is the folder that will contain all of the JavaScript app code and webpack entry points (a.k.a packs). By default it’s app/javascript/packs

The convention here is that all webpack entry points should be placed in the app/*javascript/*packs folder and the modules can be placed inside app/*javascript folder in any way you like. So, lets say if we are building a new calendar app. We can structure it like so:

*Note: All options are customisable from config/webpack/paths.yml

File and folder convention

By default notice webpacker generates an application.js inside the packs directory file for demo purposes.

2. Webpack configuration

The generator adds webpack configurations for each environment into the *config/webpack. These configurations out of the box support many of the webpack features for various environments, like code-splitting, asset-fingerprinting, and linking static assets like image and stylesheets (including post-css).

*Note: All options are customisable from config/webpack/paths.yml

Live reloading

Webpacker provides a binstub for running webpack-dev-server that supports live code reloading in the development environment. You will need to install additional plugins for Webpack if you want features like HMR [Hot module replacement]. *Note: Dev server options are customisable from config/webpack/development.server.yml

You can checkout these links on this subject,

https://webpack.js.org/configuration/dev-server/#devserver-hothttps://webpack.js.org/guides/hmr-react/

Putting it into action

Now, lets create a small JavaScript module and put it all together to see how it works.

1. Setup

First, lets add foreman gem for managing multiple processes in development group of your Gemfile and run bundle install. Then, create two files called Procfile and Procfile.dev(for dev) in the root folder.

Procfile

web: bundle exec puma -p $PORT

Procfile.dev

web: bundle exec rails s
# watcher: ./bin/webpack-watcher
webpacker: ./bin/webpack-dev-server

Also, lets setup a small binstub that runs the Procfile.dev, create a file inside bin/* folder called server and paste following commands:

#!/bin/bash -i
bundle install
bundle exec foreman start -f Procfile.dev

You might also need to do chmod 777 bin/server incase you get permission denied when running this binstub. So, now we can do ./bin/server and it will run the Procfile.dev and run webpack and puma as intended.

2. Code

Now, lets add our new example counter module, first create a module folder called counter in the app/javascript folder then inside this folder create two files: index.js and counter.js with following code.

counter.js

index.js

Then, inside packs directory create an entry file called counter.js and fill it up with following code.

Pretty simple!

3. View

Lastly, for adding this counter to our view lets generate a controller:

bundle exec rails g controller pages index

Then inside the routes.rb file setup our root route to be this:

root ‘pages#index’

..and finally inside pages/index.html.erb paste the following HTML snippet:

<div class=”counter-wrapper”>
<h1>Counter</h1>
<form class=’counter’>
<button id=’increment’>Increment</button>
<input type=”number” name=”counter” id=’counter’ value=’0' />
<button id=’decrement’>Decrement</button>
</form>
</div>
<%= javascript_pack_tag ‘counter’ %>

Notice, the javascript_pack_tag helper, it will pull in the compiled counter module script and reference it in app like so:

<script src=”http://localhost:8080/counter.js"></script>

4. Running

Open up the current directory in Terminal and run:

./bin/server 
# or
bundle exec foreman start -f Procfile.dev

You will notice in Terminal that webpack compiles our counter module and displays relevant information like size, etc.

Now, go to http://localhost:5000/ in your browser and you will see the counter app running. Yay! 😄

5. Styling

Lets add some styling to our counter module using Sass. Create a new style.sass inside app/javascript/counter/style.sass with following code:

..and then finally add it to our counter/index.js and view:

<%= stylesheet_pack_tag ‘counter’ %>

Now, go back to the browser and notice the new changes are live-reloaded because of webpack dev server live reloading. Amazing! 👍

<link rel="stylesheet" media="screen" href="http://localhost:8080/counter.css" />

Deployment

Last but not least, lets take a look at deployment, particularly deploying this app to Heroku. Heroku installs yarn and node by default if you deploy a rails app with Webpacker. Also replace sqlite gem with pg gem in Gemfile, bundle, and commit the changes.

Now type git push heroku master from your app folder and it should be deployed to Heroku. Simple! 😀

You can find more examples on this repo: https://github.com/gauravtiwari/webpacker-example-app and https://github.com/gauravtiwari/webpacker-react-frontend

Resources