
Rails 5.1 and Forward - Part 1: Yarn on Rails
Exploring Yarn integration in Rails 5.1, the JavaScript package manager that is fast, secure and reliable. Learn how Rails embraces the modern JavaScript ecosystem.
Just a week ago, the most recent version of Ruby on Rails was announced, one of my favorite web frameworks that I’ve used in many projects for more than three years. There are many amazing features and new changes, one of my favorites is the integration with Yarn, a great package management tool for JavaScript, which is fast, secure and reliable.
I’m preparing a series of posts to explain the main changes introduced in Rails 5.1. In this post, I’m going to address the new way of handling JavaScript using Yarn, and of course I’m going to write a bit about Yarn in general. So let’s get started.
Rails 5.1, the proof of ecosystem maturity
Rails 5.1 solves many of the “pending issues” of recent years. Above all, issues related to asset management that since version 4.0 were handled by Sprockets, a gem that allowed us to centralize the entire process of bundling, using and compiling all our assets using practical conventions.
Although Sprockets does a fantastic job for most developers, it posed some problems for others, especially when you needed to work with complex third-party JavaScript libraries, usually with many additional dependencies. For those cases, maintaining third-party libraries was also a problem to such an extent that you usually needed to install additional gems that encapsulated the entire integration process and made it easier to update to newer versions of the libraries.
On the other hand, many years ago a growing set of tools emerged from the JavaScript community to solve many of the problems that developers had to face every time they started a new JavaScript project, giving practical solutions to the question: How to manage packages and their dependencies quickly and efficiently? And that’s how many tools emerged (like NPM, Bower, Grunt, etc.). And sometimes the process of managing asset dependencies in Rails felt repetitive considering the notable advances in the JS ecosystem for this area.
It was no surprise that when Chris McCord launched Phoenix Framework two years ago, he decided to include Brunch as an asset build tool, adopting NPM as a package manager. But, the Rails community showing its willingness to adopt new ways of doing things if necessary, decided with the release of Rails 5.1 to include Yarn as a package and dependency manager for JS assets and optionally Webpack to handle module bundles and compilation. That’s a big step in the right direction toward where web development is heading.
In this post we’ll cover how the integration with Yarn works.
Introducing Yarn
Yarn is a package manager created by Facebook, and announced last year. According to Facebook, they were using NPM but as the size of their codebase and the number of engineers working on their projects grew, they encountered problems with consistency, security and performance. So they needed a tool that was fast and reliable.
And best of all, Yarn development is backed by other companies like Google and Tilde.
Installing Yarn
macOS
- Using Homebrew
brew install yarn
- Using MacPorts
sudo port install yarn
Windows
The easiest way is to use the installer, you can find it here.
You can also use Chocolatey
choco install yarn
And Scoop too
scoop install yarn
Ubuntu
First you need to configure the repository
curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add -
echo "deb https://dl.yarnpkg.com/debian/ stable main" | sudo tee /etc/apt/sources.list.d/yarn.list
And finally just:
sudo apt-get update && sudo apt-get install yarn
To verify that everything went well, just check the installed yarn version:
yarn --version
Using yarn
Now, and prior to introducing Yarn applied to the RoR context, let’s start using Yarn independently.
So, let’s start a new project using Yarn:
mkdir yarn_test
cd yarn_test
yarn init
Yarn will ask you for basic information about the project, such as project name, version, description, author, repository url, etc.
When initialization is finished, you’ll see a new file called package.json, which contains the data you provided before.
And now let’s proceed to add new dependencies. You have different ways to add a dependency: just using its name, or specifying its version or tag. In this case, I’m just going to add a react.js package without specifying the version, to get the latest one.
yarn add react
And that’s it. If you check the package.json file you’ll find the latest version of reactjs.
Optionally you can add different categories of dependencies, and update or remove them. To install all the dependencies of a project you just need to run
yarn
or
yarn install
You can check the entire dependency tree in a new file that is created after installing the first package, called yarn.lock
And, since I don’t want to leave this example incomplete, let’s create a hello world application with react, the easy way.
First let’s install the create-react-app package, but globally to use it from the terminal.
yarn global add create-react-app
And now, we can verify that create-react-app is working by asking for its version:
create-react-app --version
If everything is fine, let’s proceed to create our first react.js application:
create-react-app hello-world
Then, you’ll see output similar to the following:
Success! Created hello_world at /Users/gerardo/opensource/yarntest/hello_world
Inside that directory, you can run several commands:
yarn start
Starts the development server.
yarn run build
Bundles the app into static files for production.
yarn test
Starts the test runner.
yarn run eject
Removes this tool and copies build dependencies, configuration files
and scripts into the app directory. If you do this, you can't go back!
We suggest that you begin by typing:
cd hello_world
yarn start
Happy hacking!
Amazing! So, let’s test our newly created application:
cd hello_world
yarn start
/////
Compiled successfully!
The app is running at:
http://localhost:3000/
Note that the development build is not optimized.
To create a production build, use yarn run build.
So, if you go to http://localhost:3000/ you’ll see your application running.
Now, let’s take a look at the generated files:
ls -l
-rw-r--r-- 1 gerardo staff 80668 May 31 10:10 README.md
drwxr-xr-x 774 gerardo staff 26316 May 31 10:18 node_modules
-rw-r--r-- 1 gerardo staff 374 May 31 10:10 package.json
drwxr-xr-x 4 gerardo staff 136 May 31 10:10 public
drwxr-xr-x 8 gerardo staff 272 May 31 10:10 src
-rw-r--r-- 1 gerardo staff 188529 May 31 10:10 yarn.lock
cat package.json
{
"name": "hello_world",
"version": "0.1.0",
"private": true,
"dependencies": {
"react": "^15.5.4",
"react-dom": "^15.5.4"
},
"devDependencies": {
"react-scripts": "0.9.x"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test --env=jsdom",
"eject": "react-scripts eject"
}
}
If you’ve previously tried other package and dependency managers, you’ll appreciate how clean and easy it was to get to this point. I’m not going to delve deeper into reactjs, maybe in a future post I’ll address that using Yarn, but that was a sample of Yarn. I’m very happy they decided to integrate it into the Rails workflow, you can see the details in this pull request.
Yarn on Rails
Now let’s try to use Yarn within a new Rails 5.1 application.
rails new yarn_test
cd yarn_test
In addition to the normal files you see when a new rails project is generated, you’ll find a package.json file, and if you take a look at the assets initializer file, you’ll find the following line:
# Add additional assets to the asset load path.
# Rails.application.config.assets.paths << Emoji.images_path
# Add Yarn node_modules folder to the asset load path.
Rails.application.config.assets.paths << Rails.root.join('node_modules')
So, Rails automatically includes the node_modules directory in the asset pipeline, you just need to reference the new package you want to add, for example, let’s say we want to use the moment.js library. First we need to install the library using Yarn:
yarn install moment
We can see that package.json was updated
{
"name": "yarn_test",
"private": true,
"dependencies": {
"moment": "^2.18.1"
}
}
And finally we need to include the new package in application.js:
//= require moment/moment
That’s all for this first part, in the second part of this series I’m going to address Webpack and how to use it to compile and manage JavaScript bundles.
Share this post:

About Gerardo Ortega
Software craftsman with a focus on scaling, polyglot programmer, coffee enthusiast, and lifelong learner. Passionate about machine learning, data science, and building great products.