Max Krebs

Rails <3 Yarn

Declaring My Biases

I don’t like JavaScript. Not very much anyway. Technically, it was the first real programming language that I learned (if you don’t count HTML as a programming language, which is both arguable and for another time) way back three or four years ago when I did some Code Academy front-end tutorials. I’ve written whole hybrid mobile applications in JavaScript. I had an entire course in University taught in Angular. But I thought it would be important to tell you here and up front that I don’t enjoy using or writing JavaScript.

I don’t have any particularly unique or interesting reasons behind this, just all the usual ones. I think server-side rendered HTML is still the best overall way to architect web apps. Plus the language itself is a pain, although I hear ES6 is going to make that all better (and this year is the year of Linux on the desktop).

In my own development work, I tend to stick to using JavaScript only when I think it makes sense: dynamic DOM edits, fancy form fields etc. I try to keep npm out of my Rails projects because that seems like way too much additional complexity. Instead, when I need to use a JavaScript package, I download the source and manually add into the /vendor path. This was a pain, but I was avoiding the problems of dependency hell, right?

Okay, Let’s Get Down to Business1

As part of my attempts at doing the [#100DaysOfCode] challenge, I am working on my podcast discovery site, in which users can add shows, hosts, and podcast networks to a database and browse and search to find related shows. Each model in the app has a description field of some kind and I wanted that description field to support Markdown text editing and rendering. The Markdown rendering is dead simple with the Redcarpet Gem, but I was struggling to find a good WYSIWYG text editor plugin that supported Markdown.

I really liked SimpleMDE, but it had a series of dependencies so it required a JavaScript package manger like npm or bower to install. I had never even tried to mix npm and Rails, although I thought it would be theoretically possible. Possible or not, I was dreaded having to figure it out. Then I remembered that Facebook recently released an interface for the npm package repository called yarn. It made quite a splash when it shipped, and I noticed that Rails was moving in a distinctly direction. I thought it would be worth a shot. If its good enough for DHH, then it is Damn Well Good Enough for me.

It’s a Tight Knit System2

I really only found one other guide for setting up yarn with rails. Its a post by Jiazhen Xie on sheerdevelopment.com. I followed along with that post and modified it a bit, but its still a good introduction (Its definitely got less rambling and puns than this post).

Installing yarn is about as easy as any other software tool. Mac users can run brew install yarn, Windows people have an installer that I can only assume will run an installation wizard, and Linux folks know what they are doing.

After this, I added the yarn directory to my path by putting

export PATH="$PATH:`yarn global bin`"

to the bottom of my .zshrc file.

If yarn --version returns successfully, then you are good to go.

That is it for setting up yarn on a global level. Next, cd into your Rails project (or create a new one) and run yarn init. This will give you some prompts for things like your email address, the project name, and version number. Don’t panic and starting randomly hitting keys like I did when I first came across this. Each option has a default value, so if you can’t think of an original project name, just hit enter until the execution finishes. This will create a package.json files in the root project directory.

Next, to be in alignment with the Rails defaults going forward, I added a node_modules into the vendor folder to hold packages.

% mkdir vendor/node_modules

And then add the new folder to the asset path so any modules installed there will be added to the asset pipeline by adding this line into config/initializers/assets.rb:

Rails.application.config.assets.paths << Rails.root.join('vendor', 'node_modules')

Now you are ready to install some packages. For me, I needed SimpleMDE for the description text fields so I ran

% yarn add simplemde --modules-folder ./vendor/node_modules

Even though yarn was never mentioned in the SimpleMDE readme or in the installation instructions anywhere, because the library is on npm, it installed flawlessly along with all of its dependencies.

Then require the codebase in your manifest file:

# app/assets/stylesheets/application.scss
*= require path/to/code
# or
@import 'path/to/code'

# app/assets/javascripts/application.js
//= path/to/code

In this example, all I needed to do after that is use the jQuery function that converts the text field to the Markdown editor, and that is that.

Aftermath

This was so much more straightforward than I anticipated it being. It was actually, dare I say, enjoyable. The biggest pain points for me was 1) not expecting my package manager to ask me questions and 2) making Rails play nice with yarn. And even then, it was a pretty easily fixed issue with the asset pipeline.

I couldn’t believe how quickly I could get this all implemented. It was some great instant gratification seeing the beautiful Markdown editor show up on my site. I can’t imagine how much of a pain it would have been without yarn.

Honestly, I am glad that Rails is moving to make yarn a default. I think the more you can make it easier for developers to include third-party packages, the less JavaScript people actually have to write. And that, I think, is a beautiful thing.


  1. to defeat the Huns [return]
  2. my partner is a knitter, I am so sorry [return]