0. Foreword

Since Rails 4.3-something – when webpacker started looking like a more and more probable conventional solution for the future Rails releases – I spent some time trying to find out the most intuitive union between Rails and a plethora of upcoming frontend frameworks and libraries: Angular, Ember and Vue and React.

Let me say this outright: I hate having to manage Rails frontend technologies via gems and sprockets. I know adding jQuery and bootstrap gems is just so convenient, but I never accepted it as natural. To me this was always inviting a middleman between the backend and frontend, that has its own versions, dependencies and problems. Whenever it was up to me, I forced the application to use actual .js files, either placed in vendor directories or pulled from CDN repositories. Otherwise – in my mind – frontend and backend were not isolated.

When webpacker was introduced for good with Rails 5 and was here to stay, it really felt like the proper tool, but I still struggled finding my own setup. None of the guides, posts and articles really worked for me. I had to work on my own setup.

I admit: using React.js wasn’t my choice at this point, but I already knew I don’t want to deal with Ember anymore, and Angular never clicked with me.

1. Setting up

Unlike most guides – let’s not start with creating a new project using a --webpacker flag. You either have an existing project, or you know how to generate one in a blink of an eye. Let’s assume you have one.

Let’s also assume you have yarn installed, which is to managing javascript packages what rubygems is to Ruby’s environment.

What you need to do now is add this:

# Gemfile
gem "webpacker"

 

…run bundle install and after Bundler is done, depending on your Rails version, run either one:

  • Rails 5.0 and higher: bundle exec rails webpacker:install
  • Earlier versions: bundle exec rake webpacker:install

This will add .gitignore entries, new config option in environments/ and initial modules to package.json (which is Webpacker’s equivalent of Bundler’s Gemfile, without going too deep into it).

Those modules will include webpack-dev-server and @rails/webpacker which I guess is a hook between both worlds. It’s probably the last time you’ll hear about it and that’s good.

You’ll encounter a couple of dotfiles which you won’t have to touch at this level (and possibly much longer than that).

Most importantly you’ll get a new directory of app/javascript, which is where your Webpacker-served source code for the frontend will sit.

If for some reason you already had this directory and it was not empty (Rails generated hello-world-ish file doesn’t count), then you need to stop whatever you’re doing right now, as someone already had an application there.

Your Webpacker back-endpoint is already configured, but your Rails app is not making any use of it, because the application is not requested in any of the views. For now let’s edit the most obvious of all, app/views/layouts/application.html.erb:

<!DOCTYPE html>
<html>
  <head>
  <title>WebpackerTest</title>
  <%= csrf_meta_tags %>
  <%= csp_meta_tag %>

  <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
  <%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %>
  </head>

  <body>
  <%= yield %>
  </body>
</html>

 

javascript_include_tag, that you’ve probably been using for years, serves javascript from app/assets/, but we will want none of that.

To plug your webpacker-served javascript you simply replace that line with javascript_pack_tag, and as a parameter pass a file from app/javascript/packs. After installing webpacker with the corresponding rails / rake command you should have app/javascript/packs/application.js. This file contains nothing more than a console.log call.

You can refer to this file thusly:

<%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %>

…but ultimately this file is of little consequence, as it is going to be completely replaced soon.

You can double-check http://localhost:3000 and open your javascript console in the browser, to see that the file has indeed been interpreted.

1.1. Adding a route, controller and view

A newly created Rails app will of course have no views outside of the static public/index.html. Note: Rails 5 no longer puts an actual file in your location, (just serves Rails::WelcomeController#index straight from the rails gem). It will stop serving it when you have a root defined in config/routes.rb. Don’t forget that in older Rails versions you might also need to remove public/index.html file.

Let’s add something simple:

# config/routes.rb
Rails.application.routes.draw do

  resource :app, only: [:index]
  root to: "app#index"

end
# app/controllers/app_controller.rb
class AppController < ApplicationController
  def index; end
end

Do not forget about adding app/views/app/index.html.erb or you will have rendering errors. The file can be completely empty for now.

At this point I strongly suggest to commit your changes to whatever versioning software (*cough* git *cough*) you’re using.

2. Installing React via webpacker

The webpacker gem we recently installed comes with a very useful set of pre-defined commands, helping with quick, initial setup (a sort of a mini-environment) for some of the supported javascript frameworks and libraries. Luckily for us it supports React out-of-the-box (you might be forced to run yarn install beforehand):

bundle exec rake webpacker:install:react

If you pay close attention (or just look at the diff between previous commit and current stage) you’ll see that there’s – thankfully – very little that has been added:

  • added react, react-dom and prop-types libraries
  • added Babel support (in my case via babel-preset-react library)
  • created an app/javascript/packs/hello_react.jsx file
  • and added support of *.jsx files in webpacker.yml

After that the script automatically calls yarn install as well, for good measure.

The point of most interest right now, I reckon, is Babel, which is a trans-compiling engine allowing your webpacker to read JSX files and compile them to pure javascript. React relies heavily on using JSX files which you’ll find – I hope – to be little more than javascript files with added syntax (and a very welcome addition it is too).

You might suspect already that your layout file should now point to hello_react file:

<!DOCTYPE html>
<html>
  <head>
  <title>WebpackerTest</title>
  <%= csrf_meta_tags %>
  <%= csp_meta_tag %>

  <%= stylesheet_link_tag    'application', media: 'all', 'data-turbolinks-track': 'reload' %>
  <%= javascript_pack_tag 'hello_react', 'data-turbolinks-track': 'reload' %>
  </head>

  <body>
  <%= yield %>
  </body>
</html>

…and the app/javascript/packs/application.js can be safely removed.

Word of warning: I had mixed results with using the same filename for sprockets AND webpacker – that is to say I’ve had Rails ignore one or the other when both were named application. This doesn’t always seem to pose a problem, but I started intentionally naming my webpacker entry-file differently just to be safe.

In this example I’ll rename hello_react.jsx to simply react.jsx, so ultimately your layout file will cointain this:

<%= javascript_pack_tag 'react', 'data-turbolinks-track': 'reload' %>

Start / restart your local Rails server and go to http://localhost:3000.

The view should display Hello React!.