Having used both, Node's package system is horrific compared to PHP's Composer. Composer's built-in composer.lock system is something NPM sorely needs by default.
There's a third-party tool [2] that is supposed to solve many of the issues, but I haven't tried it.
Of course, if you do this, there's a decent chance that if you try installing it again in 6 months, your shrinkwrapped version of at least one of the dependencies won't be available any more...
[1]: https://docs.npmjs.com/cli/shrinkwrap [2]: https://github.com/uber/npm-shrinkwrap
Biggest wart I've encountered is I've got a package that installs fsevents (OSX-only) as one of its optional dependencies. When I shrinkwrap and attempt to install on a Linux server, that optional dependency is treated as a required one, and it can't install. I have to manually zap it from the JSON. :-/
I, literally, cannot rebuild my application from a year and a half ago that is standard node + npm. The deps are broken...the code won't build with node-gyp...i mean node-waf...i mean who knows? What a mess and a HUGE regret.
Welcome to the Cloud Future Web 3.0, where every library you use is maintained like some random guy's personal homepage, and his robots.txt prevents you from caching a stable copy.
Besides, there's no universal unwritten rule stating that you have to use the bleeding edge version of every dependency.
Keeping all dependencies up-to-date is mostly in the interest of widely used libraries not one-off applications.
I did find a few libraries that have been completely abandoned...like 2/3 of the libraries I used.
I then spent a few hours downgrading each version to isolate the issue...found a few libraries that were hard-deprecated (which was nice), found some breaking changes in the node version I'm using and then I just gave up.