I understand that this is a hairy, messy problem they are solving, and that they traded off one aspect of the problem for another (Install order dependency! as a new "feature" in 2015!).<p>But I wish they had aimed higher. The better goal would be that the entire state of the node modules directory is a pure function of the contents of the package.json file plus the platform details (compiler used for native modules).<p>While they're at it, the ecosystem could be improved considerably if there was some sort of obvious "penalty" applied to any package that compiles native code, because such things cause considerable extra trouble for Windows users. A visible penalty, transitively carried up the dependency tree, would discourage use of such modules with native code; projects would use them (depend on them) only if absolutely necessary instead of accidentally, all over, all the time.
<i>"dependency resolution depends on install order"</i><p>Does this sound insane to anyone else?<p>EDIT: I understand not wanting to modify node's `require` semantics, but this is an unacceptable sacrifice of consistency for efficiency. Surely it would have been possible for an `npm install --save x` to put the `node_modules` directory in a state identical to `npm install --save x && rm -rf node_modules && npm install`. It might take a little longer to shuffle some directories around, but certainly not longer than a full `npm install`.
That's a great improvement over the old behavior, but I'm wondering why the team didn't go a different route.<p>Why not always store packages at the top level, and create a directory for each version that's required?<p>For example: directory "A" contains two subdirectories: "v0.1.0" and "v0.1.1"
So, assuming I have two libraries, A and B, that both require the same version of library C, do those libraries still get their own separate in-memory copies of C, or do they share a singleton?<p>It's terrible practice, but it's not unheard of for an NPM module to monkey patch its dependencies, since before this the library could assume it had sole ownership of its whole subtree.
Jspm solves this by installing the module in a directory appending the package version. There is no maximally flat tree, the tree is 100% flat. At most there are several versions of the same package side by side, but no nesting.<p>It even supports circular dependencies.
This is good news for client side bundlers like Webpack and Browserify -- where size really matters -- they don't have to end up with multiple copies of the same module.<p>I would also assume for very large apps it may improve startup time because you don't have to initialize and retain multiple copies of the same module.
as the person who wrote these docs-- if you have questions or things you'd like to see addressed, i'd really love if you filed issues on the repo. <a href="https://github.com/npm/docs/issues" rel="nofollow">https://github.com/npm/docs/issues</a>
If this works it might reduce the slug size of a built node app by a lot of a little.<p>Though, if there are problems, I wonder - can the flat dep resolution be disabled using some CLI flag? Or when installing deps, or in .npmrc, or during a shrinkwrap?
I just filed a bug: <a href="https://github.com/npm/npm/issues/10999" rel="nofollow">https://github.com/npm/npm/issues/10999</a><p>I guess I'm not sure what level of non-determinism they expect, but on this page: <a href="https://docs.npmjs.com/how-npm-works/npm3-nondet" rel="nofollow">https://docs.npmjs.com/how-npm-works/npm3-nondet</a> it appears to make the claim that the only effect is on tree structure, not the actual versions of packages that are picked up. And in fact in their example this IS the case. I think this is fine btw.<p>However, I have found edge cases where install order actually changes the versions of packages that are picked up, and in ways that make it very very difficult to work around (basically you will be forced to manually edit a shrink-wrap file -- so it is necessarily on the end user not the package writer).<p>Basically, if any package lists and absolute dependency (vs a semver range), it will affect ALL the packages alphabetically later than it and FORCE them to take the same dependency.
I do not understand why they just didn't have a two level directory structure:<p>node_modules/[module_name]/[version]<p>Then it would be flat and support multiple versions of the same module in a way that is completely deterministic and also fully deduplicated.<p>This new system is unnecessarily complex.
Sorry to be negative but one of the things that I hate more than anything in my software development work is typing "npm install blah" and almost always being hit with wave after wave of errors typically related to dependencies. I don't know why it happens and I don't care I just wish they'd fix it. So many, many errors.<p>Go on, try installing X packages at random using npm - did they install cleanly?<p>The baseline outcome for using a package installer should not be reams of errors, it should be a cleanly installed package. Installing packages works fine with other language ecosystems, why not with npm?
V2's deep nesting recently caused trouble for us at work. We had errors where our node_modules folder was too long for Windows, due to the deep folder structure. Updating to v3 resolved the problem. Hopefully other flaws being discussed here can be worked out as npm evolves.
I think they are trying to be too smart about it ... I rather waste several GB's of HDD space then having my production crash <i>once</i> because of dependencies.