meteor/meteor — pull request #1768 by rdickert (2014-01-18 04:30:13+00:00)
Title: #1761: Put `/node_modules` in package root on build

This relates to packages failing to build if both of the following conditions are met

1. They do not have a `/node_modules` directory.
2. There is a `/node_modules` directory present in the directories above the package.

See Issue #1761 for more background.

I traced the problem behavior to a call to `npm list` to compare current packages to requirements during the build process. Meteor calls npm via `child_process.execFile` (basically like a bash script using the CLI) and passes the package root as the cwd. However, npm does not always treat the cwd as the project root. I take it that the idea is for a programmer to be able to call `npm list` using the CLI anywhere in a project, and it will find the project root and display the correct results. To determine where the root is, it searches recursively up the directory tree for a directory containing a `/node_modules` subdirectory (in that sense, `/node_modules` may function a bit like a `Vagrantfile` does for Vagrant). If it doesn't find any ancestor directories that contain `/node_modules` (as is usually the case in Meteor), then it defaults to cwd, and everything works. But if it finds one, it will treat that as the project root, and the build will break. This applies equally to Meteor core modules on builds from checkout. It may occur even on previously working builds, as packages are thrown away when Meteor upgrades due to possible platform-specific dependencies that could change. In my case, I didn't even realize I had a `/node_modules` dir in my home directory – it was a mistaken `npm install` in the wrong place that had put it there.

The simplest way to solve this is to make sure that every package has a `/node_modules` directory. There is already a precedent to this in the solution to #927, which does much the same thing (see `_makeNewPackageNpmDir` in `tools/meteor_npm.js`). There is the possibility that this PR may make that code redundant, but that hasn't been tested.

In general, it might be preferable to call npm as a library rather than as a command line tool (there is a parameter `npm.localPefix` that looks like it would lock the directory), but I'm sure there's a reason we do it this way, and this is a quick way to solve the issue, which is a tough one to diagnose when it happens.