jQuery and Lodash could be considered "secondary stdlib" packages. Lodash for various data functions, and jQuery for dom manipulation functions. Now that other frameworks are more common and the basic stdlib is larger, many projects have migrated away from them to improve bundle size. (As an example, pulling in one lodash function tends to pull in lots of other functions from within lodash, unnecessarily inflating the amount of code sent to the browser.)
For the front end, ideally tree shaking is used, and even fancier build systems create code that doesn't pull down dependencies until they are actually needed at runtime.
I created a small Node+Express project, added a few dependencies to handle things like CORS, API Authentication, ORM, and data validation, and my node_modules folder has 300 packages already. Frontend wise, it's worse.
I only used a few libraries when I was doing Android, most of them utilities and vendor SDKs. And the contrast is even higher in another project I'm working on. The Java Code takes less than 10 minutes to build, while the frontend code turns the laptop into a jet.
The vast majority of node dependencies are for testing frameworks and other tools that are never shipped to the customer.
For example, if you install any tool that does pretty command line output, odds are it installs some console UI libraries as a dependency, and odds are they also install a lower level curses like library as a dependency.
(Also I've yet to meet a simple ORM system!)
Jest is another common offender, much like every other popular testing framework, it is large and complex, and due to the nature of Javascript, it is also more powerful than a lot of the other testing frameworks I have seen (e.g. Jest can do stuff at runtime that Java frameworks need to do at compile time).
Those Java frameworks that go in and mock classes are complicated, but they are all hidden behind a "single" dependency.
Regarding front end build times, if a frontend website is taking any amount of time to build, something else is wrong (e.g. TypeScript is rebuilding everything one very build). Typical frontend website dev stacks have hot reloading enabled that allows for the site to be refreshed and updated the instant a file is saved. Nicer setups live change the DOM and try to avoid reloading the page unless something touching state management has been altered.
(My experience is with React and Svelte alongside TS, Angular may be a different story, not sure!)
I'd take complicated and sane over the literal software illusions that many npm packages are.
> Regarding front end build times, if a frontend website is taking any amount of time to build, something else is wrong;
Not necessarily. Any production build should start from scratch (the dependencies may be cached).
oof... way to snatch defeat from the jaws of victory :(.
I generally prefer less magic over more magic.
So just to test I installed Django in a new virtualenv. I get a testing framework, and ORM, CORS, authentication, data validation, hot reloading and much more. It's three dependencies: django, asgiref and sqlparse.
Part of it is that Django just builds a ton of stuff on their own, but they also have the Python stdlib to build on.
As others mentioned you have things like Boost, the Go standard library, or even libc (of which there are multiple implementations). There's no reason why you couldn't have a JavaScript standard library, or multiple. They don't have to be shipped with the browsers, in fact I think that would be a bad idea. So when you start a new JavaScript project, you pull in your favorite standard library and when you ship your code, the bundler or whatever it's called could analyze your code pull out the relevant bits of the standard library and only include the bits you need.
That is kinda-sorta how things work, except JS devs like to split code up into smaller modules.
https://www.npmjs.com/package/jest?activeTab=dependencies has 4 dependencies, if you look at @jest/core a lot of its dependencies are in fact other parts of the same project.
The lack of batteries included means there is a lot more room for diversity, if someone wants to write a new server to compete with express (and plenty of people have) they can follow the same middleware API standard and you can swap our your existing web server for another one but your ORM will still work!
Also a minimum viable JS Rest endpoint is literally 4 or 5 lines of code. Getting cors working is 2 or 3 lines more (based on if you count the import statement as a LoC).
Adding schema validation to an endpoint is another 2 LoC.
The number of concepts needed to be understood to setup an endpoint in Node land is minimal, and you can then build out whatever tools you want on top.
If you want a batteries included framework, there are also plenty of those, from fullstack systems Sveltekit and Next.js to multiple starter templates for backend services that give you whatever tools you wanted.
People go "Python has Django" and there are huge advantages to having a single golden path, but Node has a richness in the ecosystem that lets people start off small with and choose what tooling is best as their projects grow.
And at the end of the day, an ORM is going to require N lines of code, it doesn't matter if it is bundled with a framework of it is an external dependency.
I wish more languages would invest in their stdlib.
With Go there is an owner at least.
But who is going to do it?
I guess it’s a tradeoff
Examples: are you likely to write unit tests for your GetFirstChar? A specialized open source library that built this function is far more likely to have unit tests and documentation. Those unit tests and documentation come in handy during edge cases and when your coworker decides to extend the function with an `options` parameter.
Also, general developers rarely understand the full breadth of character sets, for example. So if your function just grabs the 1st byte from a string and expects it to be a character, your end user might be angry when only the first byte of a multi byte character is returned. Similarly the difference between a character and a glyph and a rune, etc. are important and lesser understood.
What is the difference?
"rune" is Go's name for a unicode code point.
- The standard base class libraries with .NET are quite comprehensive; I end up rarely adding "utility" libraries
- For non-standard libraries, Microsoft is a first party publisher of many packages on nuget; many of their first party frameworks and tools are published this way
- For third-party libraries, generally speaking, I end up using maybe a dozen or so very well-known and well-vetted libraries which have low dependencies of their own (again, because of the rich standard libraries)
- You end up with far less surface area for dependency chain attacks
According to the 2020 State of the Octoverse report [0]: - Node projects had nearly an order of magnitude more transitive dependencies than the next highest (683 to 70 for PHP) (p.11)
- npm had the highest percentage of critical and high severity advisories (p.14)
- 72.8% of JavaScript repos had dependabot alerts (well above the weighted average of 59%) compared to 6.5% for .NET and 40.2% for Java
Some would say that Microsoft's stewardship of .NET and C# is a negative; it can never be truly OSS. The flip side of that is that there is a professional team of paid software engineers -- some of the best in the world -- maintaining, patching, and securing the platform. While the third party ecosystem doesn't have as many options for doing X, the few options for doing X on .NET tend to be more well-rounded by the tighter community focus on a few, well-known libraries.Maybe some variation of an Apache Foundation like approach to curating a set of OSS NPM libraries and some mechanism of establishing trust would be beneficial to the NPM ecosystem?
Just my take.
Things are better now, but for all its (many!) positives, .NET is not an example of how to create a good ecosystem.
Of course back then Microsoft considered an ecosystem to be 3rd party partners selling libraries, of which quite a few successful companies did.
.NET itself is only 2 decades old (first release in 2001).
The people in charge of each larger package can review contributions made to it and have the authority to reject code that includes attacks. If a larger package doesn't do a good job of preventing attacks, its reputation will decline and because there are fewer packages involved it is easy to remember these reputations.
I've had this debate before and, as far as dependencies go, sometimes you have to rip the bandaid off and audit your shit, and understand why exactly you outsourced something to a package.
I agree in the sense that smaller supply chain surface area is easier to secure/verify.
But it also makes the developers/maintainers of the few packages much brighter targets.
I’m more of a fan of standardizing how libraries can be rated, evaluated, trusted, marketed, etc. we need more efforts analogous to Consumer Reports / Underwriters Laboratories. So far there are a few for-profit companies in this space, including Google.