Adding ES6 / Stimulus to Rails 4.2 using Webpacker

We have been following Basecamp's Javascript framework extraction Stimulus since v1 was released, and decided it was a good time to start write about adding ES6+ and some new tools into the mix.

This tip is focused on the basics of getting ES6 and Stimulus working in a Rails 4.2 application, so let's keep it simple and just start from scratch.

We're going to be using webpacker to handle JS pre-processing, and you can read more about the webpacker gem here: https://github.com/rails/webpacker.

We're also only handling ES6 specific JS with webpacker, and will keep the asset pipeline intact for handling CSS/Images. We will cover replacing the asset pipeline completely in an upcoming post.

1. Setup a Rails 4.2 app:

Install rails 4.2:

$ gem install rails -v '4.2.10' --no-ri --no-rdoc

Move into your work directory and create a new app:

$ rails _4.2.10_ new rails-stimulus

While we're at it lets generate a home page:

$ rails g controller pages home

And set the root to our new view:

# config/routes.rb

root 'pages#home'

Now we have a simple and basic Rails 4 app that we all know and love.

2. Add and Configure Webpacker

The great thing about webpacker is that it's maintained by rails core team, and they have reduced the complexity of configuring and using webpack, babel & yarn, etc, and provided a relatively smooth path to becoming productive.

Add the webpacker gem to your Gemfile:

gem 'webpacker', '~> 3.5'

Bundle and run the installation task:

$ bundle
$ bundle exec rake webpacker:install

This will create all the files needed to for the defaults, add basic configuration, and install dependencies. You can optionally run yarn upgrade to resolve unmet peer dependency warnings.

3. Add Stimulus

We can add the stimulus package using yarn

$ yarn add stimulus

4. Create stimulus controller

You can read more about using stimulus in the docs, but for now let's assume you understand how the library works.

Set up stimulus in app/javascripts/packs/application.js:

// app/javascripts/packs/application.js
import { Application } from "stimulus"
import { definitionsFromContext } from "stimulus/webpack-helpers"

const application = Application.start()
const context = require.context("./controllers", true, /\.js$/)
application.load(definitionsFromContext(context))

Create hello_controller.js:

// app/javascripts/packs/controllers/hello_controller.js

import { Controller } from "stimulus"

export default class extends Controller {
  static targets = [ "name" ]

  greet() {
    const element = this.nameTarget
    const name = element.value
    console.log(`Hello new, ${name}!`)
  }
}

Replace the markup in app/views/pages/home.html.erb with this:

<div data-controller="hello">
  <input data-target="hello.name" type="text">
  <button data-action="click->hello#greet">Greet</button>
</div>

Add the application pack tag to the application layout:

<%= javascript_pack_tag 'application' %>

5. Setup foreman for local server

We need to run two separate processes locally, one for the rails server, and one for webpack-dev-server to serve the packs.

Add gem foreman to your Gemfile and bundle

Create a Procfile.dev with these contents:

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

Run foreman start -f Procfile.dev to start the server up and test the app.

If everything goes well you should see a web.1 process and a webpacker.1 process running successfully.

6. Open browser and test

Visit: localhost:3000 in your browser and test the greeting. You should see the input value logged in the browser console.

Source code:

We have also made the source code for this guide available here: https://github.com/devato/rails-stimulus

Wrapping up

There are many different ways to configure webpack/babel and this guide was just a intro to using webpacker's defaults. Take some time to read about the configuration choices, and the generated config files to understand how you might be able to customize the set to suit your needs.

As always, let us know if you have any feedback, suggestions or ideas.

Enjoy!