If you want the small stdlib with small module approach, you need a language and runtime system with some better static guarantees.
Doesn't npm manage transitive dependencies, just like Maven in Java-land? I sure thought it did. Are package maintainers just not getting their dependencies right? E.g. - "everybody" uses jQuery, it will just be there, I'm not going to list it.
I have only used Node/NPM a little bit at home. Most of my JS work has been some things embedded within larger Java web apps, and my coworkers don't really like JS (they are wanting to do static-OOP where dynamic-FP fits better).
It does - actually the pain that I'm expressing is the same pain I felt with Maven: somebody comes along and says, "Oh, you're doing OAuth? You should definitely use an OAuth library for that." So I pull in the OAuth library and let either mvn or npm pull in all of the transitive dependencies, half of which I've never heard of and the other half I know, but am not an expert in. Which is a problem when one of them reports an error message like "Unrecognized parameter in dozer mapping". What? What parameter? What mapping? WTF is 'dozer'? I google the error message and get a hundred hits, none of which have anything to do with my case. So now I'm going through a poorly documented transitive dependency trying to figure out a) what it does b) how it does it and c) why it broke my OAuth implementation (all with the boss standing behind me, checking his watch, tapping his foot impatiently, wondering why this is taking so long when I'm reusing something that's supposed to make this all magically work instantaneously). I'm suddenly loading somebody else's source code in a debugger, trying to figure out where it gets all its configuration data, thinking "would it _really_ take that much longer to write my own OAuth.... (or date picker or JSON parser or whatever else is misbehaving)"
There is a small problem and a big problem with this. The small problem, is that your build size will be unreasonably large. The big problem, is that this React library has internal state - you can't just initialise multiple copies of it, and expect them to share a single state.
Enter peer dependencies. Each library that needs React, demands that the root module, your application, specify a normal depency on React, that satisfies their version range requirements. Clearly, this quickly becomes impossible. So, version mismatch is treated as a warning, not an error, and you (the application developer) learn to basically ignore that warning.
I can think of lots of solutions to this problem, all of which have problems of their own.
- All libraries factor out their state, so that they are stateless. Now you can load multiple instances of a module, but if they have different major versions, then they are totally going to mess up that state that you are holding for them.
- Application developer: it is your responsibility to patch your dependencies, and their dependencies, so that they all accept an overlapping range of React versions. But who has time to test 30 modules for regressions?
- Just build more, smaller, simpler applications. This is where I am right now. I still get version warnings, but it is a little less risky to ignore them.
How do you handle this issue in the Java community?
* Small, sharp tools (sometimes) - things like Google Guava "collections" utilities, or the Ostermiller CSV file handling library, which have very small and stable scope.
* Big collections of things, such as Spring or Struts. Regardless of how you feel about these libraries, they do tend to come as a family of interrelated libraries (supplemental components) that get released in lock-step and play nice together.
I dislike the Java language, but I guess it is nice that most of the stuff on Maven Central does tend to be stable.
Javascript, a la Web 2.0, has really only been a serious development thing for about 10 years. It's due for its own settling in period soon, I would imagine.
This is not true in npm v3: it now flattens the dependency tree and only duplicate dependencies if there are incompatible versions required.[1] Granted, if those four packages all depended on jQuery locked to different specific versions, then you would end up with four nested versions of jQuery.
It seems odd to bring up Java here, but this is one of the problems solved (not without cost) by checked exceptions.
By making the types of exceptions explicit, each layer is encouraged to reframe (or wrap) the errors from its dependencies in a way which matches its own usage and level of abstraction.