At DockYard, we have a lot of Ruby on Rails experts who have adopted Ember on the frontend. One of the early hurdles a Ruby developer faces when working on an Ember.js application is dependency management. A popular mechanism for managing a Ruby application’s dependencies is the Gemfile provided by Bundler. Including a library is as easy as declaring it in the Gemfile and running
gem 'rails', '~> 4.2.0'
Ember-CLI uses npm to manage internal dependencies. npm resembles RubyGems, in so far as it allows you to install and manage third-party libraries, which in this case, are Node.js programs.
Libraries for npm are referred to as “packages.” Each package has a
package.json file which lists the dependencies of the library itself. In this regard, the
package.json is analogous to a RubyGem’s
You can configure how node packages get installed via the
.npmrc file. You may have one
globally, per user (
~/.npmrc), or per project.
To install an npm package, run
npm install [package-name] from the
This will either install the library and it’s dependencies
into your current working directory or in one of its parent directories. Here’s how it works: if there is a
package.json in any directory above the current working directory, packages will be installed into that directory. Otherwise, calling
npm install [package-name] creates a
node_modules/ directory in your current working directory and installs the packages there.
This is a slightly different mental model for Rubyists who are not used to installing gems on a per project basis; gems are generally installed into version-specific Ruby directories with the more popular version managers like rbenv or RVM.
It’s also possible to install packages globally using the
--global flag when installing. This installs the package in your
usr/local/lib/ directory by default. These packages typically contain executable files and are used via the command line (such as Ember-CLI).
Your dependencies will likely have dependencies. These get installed within a
node_modules/ directory in the given package. It’s a little strange the first time you navigate into a
node_modules/package-name/ only to find another
node_modules/ directory, but that’s what that is. You’ll notice a
node_modules/ directory for dependencies of global packages as well if you look in the
usr/local/lib/ directory where global packages live.
One last thing to note regarding npm installations: npm caches the
libraries you pull down to prevent you from having to download
libraries that are already on your system. You’ll find that cache:
Bower itself is an npm package. Its libraries are referred to as “components” and the end user can configure their installations via a
.bowerrc file. This file specifies where dependent components will be installed, the URL where the component will be registered (its registry), and the JSON file used to define the component (
bower.json by default) among other things.
As we mentioned, components can be searched for via registries. The registry matches the name of a component with the endpoint at which it’s hosted. Bower.io/search closely resembles rubygems.org in this way.
When you install a Bower component via
bower install [component_name], the repository will be cached locally to expedite any future installations of the component. In case you’re curious, the bower cache location is:
Unlike npm, Bower components are installed “flat” as opposed to in a hierarchical manner; all of your project’s components (and their dependencies) will be installed into
bower_components/ directory, by default. For example, if one of your components is dependent on the
underscore.js library, both will sit side-by-side in the
bower_components/ directory (remember, with npm, dependencies of dependencies are continually nested in their parent’s directory within a
Here’s a quick wrap-up of the analogous files between Ruby and the JS package managers we discussed:
|JS (npm, server-side)
|JS (Bower, client-side)
|Term for external library
|End-user configuration file
|Per-library configuration file