In this module we're going to look at using React with Webpack inside Rails using the react_on_rails gem.
Why use the react_on_rails gem?
react_on_rails also doesn't depend on jQuery.
react_on_rails uses Webpack for ES6 compilation and then uses the Rails asset pipeline to simply include the bundled asset file that Webpack generates.
So it gives you a lot more power at the cost of installing and managing a few extra things.
And most of this power comes from using Webpack.
What is Webpack?
Webpack is a module bundler.
It's a tool for processing and bundling your assets in convenient chunks and serving them efficiently to the client.
It'll automatically find all the required dependencies, convert our JSX and ES6 code to ES5 and concatenate all our assets into bundles, making sure all the code is loaded in the correct order.
But because it's so powerful, it can be confusing when you're starting out. You can get lost trying to learn everything about Webpack.
We don't want to do that. So for the purpose of this lesson, we're simply going to see how the react_on_rails gem sets up Webpack for us. We can look at it in more detail later on.
The first thing we need to do in order to use the react_on_rails gem is to install Node.js.
You can download a Node installer from the official website nodejs.org.
You can also install it using brew on a Mac or through Node Version Manager (nvm), which is like rvm for Ruby.
Once you've installed node, you can check that it's installed correctly by running the following command in the terminal:
That'll show you the version of node on your machine.
Ok, so let's get started with a react_on_rails app.
I'm going to create a new app, let's call it calreact again to show you the default setup of the react_on_rails gem.
$ rails new calreact
Then let's add the react_on_rails gem to its Gemfile.
gem 'react_on_rails', '~> 6'
Important Note about react_on_rails gem version:
At the time of recording this lesson, the latest react_on_rails gem version was 6.4.2, which did not depend on the yarn package manager, and only used npm.
However, the latest version of the gem requires yarn. So you can either specify the exact version in your Gemfile like this:
gem 'react_on_rails', '6.4.2'
Or if you want to use the latest gem with yarn, you can install yarn first and then replace all npm install commands in the lesson with yarn. On Mac OS X, you can install yarn with brew:
brew install yarn
After adding the gem to the Gemfile, run bundle:
Next we need to run the gem's generator.
But before we can do that, the gem requires us to commit all our changes to git. So let's do that quickly by initialising a new repo, adding all changes and committing them.
$ git init
$ git add -A
$ git commit -m "New Rails 5 app with react_on_rails"
Now we can run the generator:
rails generate react_on_rails:install
This generator will create a bunch of files and directories and add some configuration to our app.
The big change it makes is it adds a client directory in our app's root directory.
It also creates an example React component called HelloWorld which we can test right away to check if React's working in our app.
Then it tells us what to do next. Run bundle && npm install. npm install is like bundle install.
So let's run that:
bundle && npm install
If you're running a more recent version of react_on_rails, you need to run yarn instead:
bundle && yarn
Now that we've installed all the gems and node packages, we can run the app using foreman.
Foreman is a gem for running apps when you have more than one process to run at once. We tell foreman what processes to run in a Procfile.
In our case, we need to run rails as well as webpack. The react_on_rails gem generated a file called Procfile.dev.
When you type in the input text field, it updates the state and shows the same field value above it.
Ok, so now that we've seen how to set up this gem, let's take a step back and go through all the steps that we took and see how it really works in detail.
We first ran the generator which created the client directory and files inside it, and some manifest files and a Procfile.
Then we installed the dependent gems and node packages. So let's look at how that works.
When we run npm install (or yarn), it first looks in the package.json file in our root directory:
This is like a Gemfile with some extra features, but this file doesn't do a lot. It mainly just has a postinstall script which does the bulk of the setup.
That says cd into the client directory and run npm install there.
The gem's generator also created a manifest file called package.json inside the client directory.
It lists a bunch of libraries our app needs as dependencies in production or development. These are ones you'd want both in production and development. and devDependencies are only for development. When we run npm install, all these packages get installed.
And they all go into a directory called node_modules. There's a lot of stuff in there but don't worry, we're not going to edit any of that.
The client/package.json file also has some scripts it can run, which we'll look at in a moment.
Our next step was to start the app by running foreman with Procfile.dev.
It has 2 processes. The web process will run rails on port 3000. And the client process will do a couple of things.
First it deletes all files under this app/assets/webpack directory because every time we restart our server, webpack recreates those files. Then it goes into the client directory and runs this script -
npm run build:development
And that's one of the scripts defined in package.json that we just saw.
It's going to run webpack with the config file webpack.config.js which is where we define all the settings for webpack to process and bundle our assets.
The main thing in this file is the config object, which has several parts:
entry is the entry point, where webpack starts reading all dependencies. you can have multiple entry points but the important one for us here is this file which it will use as a starting point for setting up the example HelloWorld component.
output defines where webpack is going to save the bundled output - in this case, app/assets/webpack in the root directory.
resolve tells webpack which filetypes we want to include, so we can require files without their extension - say require('file') instead of require('file.js').
plugins are used for customising the build process. we don't need that right now.
Then we have a couple of loaders, which preprocess files. We have one which adds some legacy ES5 functionality and the babel-loader which is going to convert our JSX into ES5.
test defines the pattern to match files for the loader to run on and loader is the name of the loader.
We can also exclude directories.
So that's briefly the default webpack setup that react_on_rails creates for us.
Based on this config, webpack creates a webpack-bundle file in the app assets webpack directory.
But how does that get included in our rails asset pipeline? The react_on_rails gem adds it to the application.js manifest file.
But notice it doesn't add the full path of the file. That's because it adds the path to the config/initialiser/assets.rb file. So the file can be required directly.
Ok, now let's look at the example React component that the gem created.
We can start by looking at the entry file defined in the webpack config inside the client directory - app/bundles/helloworld/startup/registration.jsx.
This is how react_on_rails is able to use a component from a Rails view.
Now let's look at the HelloWorld component.
First we need to import React and proptypes from React.
If you remember from the previous lessons, when we use the react-rails gems we didn't need to specifically import React. We were able to directly use React.createclass to make our components.
Now while that may seem more convenient, we're going to follow this ES6 modules format from now on because it makes us be very specific about what libraries, modules or components we're including in any bit of code we write, so that we only include the code we want.
We're defining our component as a subclass of React.Component, which we're already familiar with from our previous lessons.
In addition we're also exporting this class by default. And that's how we're able to import it by name in registration.jsx.
We have a constructor function that accepts props and _railsContext (which is a convenience helper for getting details about the request like the current path).
The constructor sets the state and then we have a function called updateName for handling state changes.
Finally the render function returns a div which displays a hello message with the name which it gets from the input form field.
Once the component is defined, the last piece of the puzzle is to use it in our Rails view. We do that in exactly the same way we did with the react-rails gem.
So let's look in the app/views/hello_world folder in index.html.erb:
We have the react_component view helper method which accepts the name of the component and some props. We can also set prerender to true if we want server side rendering.
So that's all for this lesson.
Next we're going to look at using the react_on_rails gem in our calendar appointments app.
This lesson was part of the The Complete React on Rails 5 Course.