Migrating from react-rails to Webpacker
As an early React adopter, react-rails was the obvious choice for integrating it into Ruby on Rails, and despite countless Medium posts over the years about the need to switch to Webpack right this minute using some Rube Goldberg machine of a setup, the additional overhead and effort rarely felt warranted on existing projects. I also had little interest in fully discarding Sprockets, because it simply works incredibly well for most things.
This did present some challenges every now and then when trying to integrate external React components, as they tend to be written with the larger general JavaScript ecosystem in mind (Webpack, Browserify, etc…) and there wasn’t always a way to include them with react-rails without some rewrites.
With Rails 5.1 around the corner and the announcement that it will have native support for both Webpack and Yarn thanks to Webpacker, it finally makes sense to move things over and to also start using Webpack to manage JS dependencies without losing the benefits of Sprockets for any existing stuff.
Here’s a recap of what the steps are for this process:
Add the following gems to your Gemfile
and run bundle install
.
+gem 'webpacker', github: 'rails/webpacker'
+gem 'webpacker-react'
Run this Webpacker command to easily add React:
rails webpacker:install:react
In development mode, you will now need to have the Webpack watcher running in a separate process to recompile your JS/JSX on the fly.
./bin/webpack-watcher
Configure the .babelrc
file if needed (I added stage 0 support):
{
"presets": ["env", "react", "stage-0"]
}
Remove your react-rails related require
statements from app/assets/javascripts/application.js
and delete app/assets/javascripts/components.js
. While you’re at it, clean up your config/environments
files to remove the config settings for react-rails.
Move your React components to app/javascript/components/
.
I didn’t feel like renaming the .js.jsx
extension so I made sure that Webpack would still parse them by editing config/webpack/shared.js
:
...
resolve: {
extensions: ['.js', '.jsx', '.js.jsx', '.coffee'],
modules: [
path.resolve('app/javascript'),
path.resolve('node_modules')
]
}
...
Rewrite your components to include proper import
and export
declarations:
+import React from 'react'
class TextField extends React.Component {
// your component code
}
+export default TextField;
Keep in mind that you will have to import
child components that you’re using in any given component.
If you’re using the immutability helpers anywhere, be sure to add:
+import update from 'react-addons-update'
I would recommend reading Webpacker’s README at this point to familiarize yourself with the notion of packs and how to include them in Rails. You will have to add a line to include the appropriate root component in your layout view:
<%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
<%= javascript_include_tag 'vendor', 'data-turbolinks-track': 'reload' %>
<%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %>
+<%= javascript_pack_tag 'my_pack' %>
This is what my pack file looks like:
import RootComponent from 'components/test/root_component';
import WebpackerReact from 'webpacker-react';
WebpackerReact.setup({RootComponent});
Using Webpacker::React allows me to still have a react_component
view helper, although there’s no support for pre-rendering yet. At some point I may just move to using the regular DOM mounting and skip this helper altogether.
Production
Install Yarn:
curl https://dl.yarnpkg.com/rpm/yarn.repo -o /etc/yum.repos.d/yarn.repo
yum install -y yarn
I also had to add this at the top of my config/webpack/shared.js
:
'use strict';
Install your packages:
yarn install --production
Compile your packs (this will generate files with digests):
RAILS_ENV=production rails webpacker:compile
Update (April 29, 2017)
this was written before react-rails added support for Webpacker. You can decide to use this process to rely on Webpacker to handle everything but still keep react-rails for its react_component
view helper, saving you the need to use Webpacker::React.