Lately, I’ve been working with a couple early stage Ember + Rails apps. One of the pain points I’ve seen with traditional Rails apps in the past is the lack of good client-side package management. While some packages have well maintained gems, many are not kept current or don’t exist at all.

In a large app, you might have 10s or 100s of assets dropped into /vendor/assets with little to no idea what version they are, or what dependencies they have. This is bad.

My approach to this problem has been to combine Bundler with the excellent Bower package manager. Bower has excellent coverage of client-side libraries. In the future Rails Assets could be a solution to this problem, but only time will tell because it doesn’t exist yet. (Update, Rails Assets is released.)

Now for the nitty gritty:

First drop in a .bowerrc into the root of your project. This is used to declare the location of your bower assets:

{
  "directory": "vendor/assets/components"
}

Next, we need a bower.json file in the root. A minimal file looks like this:

{
  "name": "app",
  "dependencies": {
    "momentjs": "~2.1.0",
    "nprogress": "~0.1.2"
  }
}

Take a look at the Bower docs for more detail on this file. If you don’t want bower.json in your root, you can define a line in your .bowerrc with the location of this file:

{
  "directory": "vendor/assets/components",
  "json" : "vendor/assets/component.json"
}

After you’ve installed Bower via NPM and added some dependencies, run bower install to install missing components. You should also add vendor/assets/components/ to your .gitignore.

Next, we’ll leverage the asset pipeline to take care of these assets. In your /config/application.rb:

module App
  class Application < Rails::Application
    ...
    config.assets.paths << Rails.root.join('vendor', 'assets', 'components')
    ...
  end
end

And finally, we can include these assets in our project. In my /app/assets/javascripts/application.js, I easily add moment:

...
//= require jquery_ujs

// *** Bower ***
//= require momentjs/moment
...

For an example of how easy I can leverage moment, I can write a quick Handlebars help for displaying the time:

Ember.Handlebars.helper('from-now', function(string) {
  return moment(string).fromNow();
});

That’s it! Happy coding.