88

I love Bundler, it's great at dependency management. I love npm, installing node packages is easy! I have a nodejs app and would love to be able to specify my apps dependencies and easily install / update them wherever I deploy my app. This isn't a library I'm releasing, it's a full fledged web-app.

I'm aware of the npm bundle command, but that just seems to simply override the directory where packages are installed.

I'm used to using bundler in this fashion:

# Gemfile
gem "rails", "3.0.3"

Installs rails v3.0.3 and any other required gems on the host machine only if it doesn't already exist

> bundle install

How can I achieve something similar with npm?

glebm
  • 20,282
  • 8
  • 51
  • 67
Daniel Beardsley
  • 19,907
  • 21
  • 66
  • 79

6 Answers6

148

As of npm 1.0 (which is now what you get by default if you follow the steps in the README file), "bundle" is no longer a segregated thing -- it's just "how it works".

So:

  1. Put a package.json file in the root of your project
  2. List your deps in that file

    { "name" : "my-project"
    , "version" : "1.0.0"
    , "dependencies" : { "express" : "1.0.0" } }
    
  3. npm install Since you're calling this with no args, and not in global mode, it'll just install all your deps locally.

  4. require("express") and be happy.
lngs
  • 690
  • 1
  • 8
  • 17
isaacs
  • 16,656
  • 6
  • 41
  • 31
  • 2
    When in production, I highly recommend changing the local `your_app/node_modules` directory to a symlink outside your app directory. You don't want to have to download, build, and install each dependency every time you deploy. – Daniel Beardsley Jun 22 '11 at 09:35
  • Ok. what if I forget to update my package.json? Is there any way to force NPM to look not for package.json but for packages I am using in my code? – Pono Sep 13 '11 at 14:55
  • 4
    This is not quite correct. NPM will install all the dependencies for the above `my-project` in `./node_modules/my-project/node_modules`. I'm not sure if there is a convenient way to have it install all the dependencies in `./node_modules` Anyone? – Daniel Beardsley Nov 28 '11 at 08:01
  • @DanielBeardsley I don't think that's how npm works. If you're seeing that behavior, and you can reproduce it, please post an issue on the npm github page. – isaacs Dec 13 '11 at 02:44
  • Oh, no \n in SO comments, I guess. For your other issue, I recommend checking your node_modules folder into git, and not using `npm install` as part of the deploy. `npm rebuild` can re-compile binary deps. @Pono - No, npm doesn't read your code, or your mind. It strictly does what you tell it in package.json, configs, and the cli commands. :) – isaacs Dec 13 '11 at 02:47
  • 2
    Agree with @DanielBeardsley. I suffer from that behavior even with npm 1.1.70 – graffic Jan 07 '13 at 21:30
10

Edit: This only applies to npm versions < 1.0


It was quite difficult to figure this out, but NPM makes this possible.

You need three components

  1. A subdirectory in your repository (i.e. deps/)
  2. A package.json file in the above directory that lists dependencies
  3. An index.js file in the above directory that requires your dependencies

Example

Imagine that express is your only dependency

deps/package.json

note: Increment the version # each time you modify the dependencies

{
  "name": "myapp_dependencies",
  "version": "0.0.1",
  "engines": {
    "node": "0.4.1"
  },
  "dependencies":{
    "express": "2.0.0beta2"
  }
}

deps/index.js

export.modules = {
  express: require('express')
  //add more
}

Now you should be able to install your dependencies using npm. You could even make this part of your deployment process

cd deps
npm install

Then within your app code you can get access to your specific version of express like this:

var express = require('myapp_dependencies').express;
Daniel Beardsley
  • 19,907
  • 21
  • 66
  • 79
  • Thanks, this is the best method I've seen so far. However, wouldn't the `require('express')` in deps/index.js just import the latest express version, and not necessarily the one we installed? I'm a nodeJS noob so please bear with me. – adamJLev Apr 09 '11 at 16:53
  • No, that's the magic of `npm install`, it adds symlinks within the directory of your installed package to the correct versions of dependent packages. When your dependencies package is required, the `require('express')` checks the local directory first and finds the symlink to the correct version of express. – Daniel Beardsley Jun 22 '11 at 09:25
5

You should read these two articles from Isaacs(author npm) blog. I think they are really good, and I believe tell you how to achieve your goal:

  1. http://blog.izs.me/post/1675072029/10-cool-things-you-probably-didnt-realize-npm-could-do
  2. http://foohack.com/2010/08/intro-to-npm/

I believe link #1(point #11) explains this:

11: Bundle all your dependencies into the package itself

When you use the npm bundle command, npm will put all your dependencies into the node_modules folder in your package. But it doesn’t stop there.

If you want to depend on something that’s not on the registry, you can do that. Just do this:

npm bundle install http://github.com/whoever/whatever/tarball/master This will install the contents of that tarball into the bundle, and then you can list it as a dependency, and it won’t try to install it when your package gets installed.

This also is handy if you have your own fork of something, and would prefer not to change the name.

In fact, you can run almost any npm command at the bundle. To see what’s inside, you can do npm bundle ls. To remove something, do npm bundle rm thing. And, of course, you can install multiple versions and activate the one you want.

Community
  • 1
  • 1
Alfred
  • 60,935
  • 33
  • 147
  • 186
  • This is useful, though it wasn't what I was looking for. Perhaps I need to add clarification. I'm looking for a way to automatically install or update (on the destination machine) the NPM packages my app depends on whenever I deploy it. It looks like `npm bundle` is used to collect all your dependencies into a specific directory other than the default. I'll probably come up with my own solution that performs similarly to `bundle install` (`bundler` for ruby) – Daniel Beardsley Feb 07 '11 at 08:45
  • 1
    Just a note, since `npm` version 1.0+, `npm bundle` has been removed. Instead, just use the `npm install` command with no package name, it'll read the package.json and pull down the required packages. – Arthur Maltson May 26 '11 at 01:39
2

As of Npm version 1.1.2 , there's a new command npm shrinkwrap which creates an npm-shrinkwrapped.json file, analogous to Gemfile.lock. It's important to make one, to prevent software rot (see Bundler's rationale). Particularly as Nodejs has such a fast moving community.

While bundle install creates a Gemfile.lock automatically, npm install won't create npm-shrinkwrapped.json (but will use it when it exists). Hence you need to remember to use npm shrinkwrap.

Read a full guide at http://blog.nodejs.org/2012/02/27/managing-node-js-dependencies-with-shrinkwrap/

Colonel Panic
  • 132,665
  • 89
  • 401
  • 465
2

It seems to me that the simplest solution is to use a package.json file with the private flag (added to npm just last month) set to true. That way, you can run npm install or npm bundle to grab your project's dependencies, but you prevent anyone from accidentally publishing your non-public project.

Here's an example package.json:

{
"name": "yourProject"
,"version": "1.0.0"
,"dependencies": { "express" : ">=2.1.0" }
,"private": true
}

Running npm install will install express on the local system if it doesn't already exist; running npm publish gives an error because of the "private": true.

You and your team can use the version tag internally to track dependency changes over time—each time you change a dependency, bump the version. To see which version you've installed, use npm ls installed.

Trevor Burnham
  • 76,828
  • 33
  • 160
  • 196
  • I think you shouldn't quote `true` and that it's only working because strings are truthy values (that is, `!!"false" === true`). – Camilo Martin Jul 20 '14 at 15:38
1

Publish your app with npm as well, and list its dependencies in your package.json file.

When someone uses npm to install your package, npm will take care of resolving its dependencies.

Packages spec: http://wiki.commonjs.org/wiki/Packages/1.0

Dan Grossman
  • 51,866
  • 10
  • 112
  • 101
  • Yeah, but this is a non-opensource web app. If you have an idea that doesn't involve publishing the app, please edit your answer or create another one. – Daniel Beardsley Feb 02 '11 at 07:57
  • 1
    Then publish a package like "myapp-dependencies" that your users can use `npm` to install prior to installing your app. I don't think there's any other `gem` equivalent for node.js. – Dan Grossman Feb 02 '11 at 07:58