At Lumos Labs (maker of Lumosity), we operate a Rails 4.2 backend (I know, it feels like it is always time to upgrade). One of the large pain points that we (and others) experience is an asset heavy application in development can REALLY chew up your time to serve sprockets generated js and css.

TLDR - Use file extensions when using Sprockets’ require directive.

One day, We decided to going to recall the parts of our CS education that don’t get regular exercise, and figure out why development was being such a pain in the butt (but only sometimes).

First step. Watch what’s really happening on the computer while it is serving pages and assets in development mode.

Start a rails process in dev

bundle exec rails s

watch what’s “really” happening behind all the magic using dtruss which is a wrapper around dtrace. (use the pid that matches your server process. In my case it was 16651)

1
sudo dtruss  -p 16651

We were able to see that we were searching a lot of places for a js file (and failing most of the lookups). For context, a stat64 is the equivalent of saying “is there a file here and what’s its status?” man page

1
2
3
4
5
6
7
utimes("/Users/joconnor/workspace/lumos_rails/tmp/cache/assets/sprockets/v3.0/wr/wrgQiXT4Hgtsyp7_4GmJhvwzwm_LsYH0pamGQt46png.cache\0", 0x0, 0x400)		 = 0 0
stat64("/Users/joconnor/workspace/lumos_rails/app/assets/audio/lumos/game_feedback_widget\0", 0x7FFF5ACAA490, 0x400)		 = -1 Err#2
stat64("/Users/joconnor/workspace/lumos_rails/app/assets/documents/lumos/game_feedback_widget\0", 0x7FFF5ACAA490, 0x400)		 = -1 Err#2
stat64("/Users/joconnor/workspace/lumos_rails/app/assets/flash/lumos/game_feedback_widget\0", 0x7FFF5ACAA490, 0x400)		 = -1 Err#2
stat64("/Users/joconnor/workspace/lumos_rails/app/assets/images/lumos/game_feedback_widget\0", 0x7FFF5ACAA490, 0x400)		 = -1 Err#2
stat64("/Users/joconnor/workspace/lumos_rails/app/assets/javascripts/lumos/game_feedback_widget\0", 0x7FFF5ACAA490, 0x400)		 = 0 0
open_nocancel("/Users/joconnor/workspace/lumos_rails/app/assets/javascripts/lumos/game_feedback_widget\0", 0x1100004, 0x506905)		 = 27 0

This file came from a line in a js file that was being processed via Sprockets using the require directive

1
//=require 'game_feedback_widget'

So… the system decided that if we’re including a file in a js file, the best place to look for it is audio, then documents, then flash, then… you know what, that’s just silly. The file is a JS file, called from a JS file. Why look everywhere else first?

We all know that Rails is magic* wrapped tightly around Ruby’s duck typing. In this case, Sprockets is duck typing (instead of respond_to?, it is asking exists?) on the the file system… and A LOT. Let’s see if we can fix this by being more precise.

1
//=require 'game_feedback_widget.js'

That fixes it. No more errant lookup chains for this file. Awesome. That was easy. We were hoping for a really long path to finding a way to make it more explicit using something cool like a Rust tool calling a Phoenix service that introspects my file system and stashes all the results in an Elasticsearch cluster that runs in Docker Moby… but this turned out to be much easier than all of that. (if all of that HAD to happen, the fix likely wouldn’t have been worth the time spent on it, anyways).

If you enjoyed reading this, reach out and let us know. We’re also hiring for a lot of roles, so come and join us in San Francisco.