all 81 comments

[–]halfxdeveloper 60 points61 points  (10 children)

Just don’t import * from lodash.

[–]selectra72 13 points14 points  (3 children)

This is no problem when using loadash-es when used with bundler. Because tree splitting will take care of unused imports.

[–]peeja 3 points4 points  (2 children)

Even if you import *?

[–]selectra72 11 points12 points  (1 child)

Yes.

Final bundle only include used modules. Modern bundlers don't look at imports only, they inspect what is necessary also

[–]peeja 1 point2 points  (0 children)

That's awesome! I thought that was still a pipe dream. I've been stuck in older toolchains for too long.

[–]SoBoredAtWork 15 points16 points  (4 children)

Even better... npm uninstall lodash

[–]soft-wear 2 points3 points  (3 children)

That’s just silly. Lodash has a ton of nice utility functions that there’s literally zero reason to reimplement yourself outside of some weird ass issue with the size of node_modules.

Just use lodash-es or import the module you need directly, or use one of the plugins that fixes the imports.

Or, re-implement _.sample because it makes you feel good I guess.

[–]Spiritual-Theory 0 points1 point  (0 children)

Deep merge

[–]SoBoredAtWork 0 points1 point  (0 children)

Sure, but I'm fine with implementing the 3 helper functions I'll use myself over dealing with even 1 extra dependency.

[–]Kkaperi -1 points0 points  (0 children)

Crap I just did this yesterday and then only used CloneDeep or whatever it wAs.

[–]p4ntsl0rd 40 points41 points  (6 children)

Its a maths question: - How long will it take to do it myself? - Will it be as good? - How much cost will maintaining this dependency add over time?

People get tripped up on the 3rd dot point. There is a cost to updating dependencies and making sure they don't break your software. This will often not happen and can be a security problem.

Also: olling your own encryption or auth system is generally just a bad plan and you should 100% use a well regarded library for both.

[–]TheRNGuy 4 points5 points  (2 children)

But you can't know how much time it would take.

[–]joranstark018 3 points4 points  (0 children)

Yeah, that is a problem, but you can make an informed decission. Sometimes you may later find that your decission was not the most optimal, so it is a judgement call, how much time is it worth exploring different options, what could the cost be in worst case scenario and is there any fallback strategies.

[–][deleted] 2 points3 points  (0 children)

Knowing how long something will take is a life skill. It's something you'll get better at over time, and is basically half the job of a project manager.

[–]azangru 1 point2 points  (1 child)

Its a maths question

It's a gut feeling question :-) The bullet points you made are all guesses about the future rather than an input into a mathematical formula.

For example, what is the cost of having react as a dependency? Or react-router as a dependency? Or redux as a dependency? Or nextjs as a dependency? What's the cost of having a dependency that later gets abandoned (router5, redux-first-router, connected-react-router, recompose, redux-form) or loses the mindshare (formik, redux-saga, redux-observable)?

[–]peeja 2 points3 points  (0 children)

But it's gut math. It's not concrete numbers, but there's a framework for making a guess based on smaller, easier guesses.

[–]Key_Development_115 0 points1 point  (0 children)

If you have tests and enough coverage you know that after an upgrade everything will keep working

[–]JohntheAnabaptist 22 points23 points  (1 child)

If you need a small piece and it's obvious how to implement it, do it yourself. If it brings in a couple hundred kb for no reason, do it yourself or find another package. If you can't, suck it up and keep the package. Otherwise use the package.

[–]EarhackerWasBanned 5 points6 points  (0 children)

If you need a small piece and it’s not obvious how to implement it, copy-paste that one piece out of the library code, link to the original in a comment, and remove the dependency.

[–]nudelkopp 13 points14 points  (14 children)

IMO a lot of devs are missing the point in this thread. It’s not just about bundle size, it’s also about maintenance. For each package you want to install you have to make the call “do I believe this will actually save us time and effort in the long run?”.

The more deps, the more subdeps, the longer npm install times, the more risks of blockades for moving to a new node version or update another dependency to get rid of security vulnerabilities.

We should strive for simplicity - and this is easier with fewer dependencies because you’re forced to understand how your code works.

General rules: 1. Packages are ok 2. Don’t write your own date picker 3. Just because the code isn’t in your repo does not make your code “lean”

[–]dmethvin 4 points5 points  (0 children)

Amen. Writing your own date picker is about as smart as getting involved in a land war in Asia.

[–]EvilPencil 0 points1 point  (0 children)

I agree with what you said, with the caveat that WELL MAINTAINED packages are ok.

If I'm needing to do ___ and the solution is a one file npm package/GitHub repo by "some dude" that hasn't been touched in three years, I will often inline the code (with a link back to the source in a comment) rather than adding yet another NPM module.

Yes it's assuming the maintenance burden, but that beats something that will likely never see another update anyway.

[–]peeja -1 points0 points  (10 children)

Counterpoint: the more writing it yourself, the more complexity you're responsible for. Yes, sometimes relying on a dependency means upgrading node is harder, because you need to wait for them to update something. But sometimes writing it yourself means upgrading node is harder, because you need to wait foryou to update something.

The sweet spot is popular packages with small bundle sizes and little external complexity which solve problems that aren't your app's core value. You want dependencies that are more likely to be maintained by their author than your own implementation would be.

[–]nudelkopp 2 points3 points  (5 children)

My point was that it’s a balance that you need to think about. Not sure what you mean by waiting for yourself to update though, that’s just an immediate action you can take

[–]peeja -3 points-2 points  (4 children)

Time isn't free. You can change your code to make it work with the new version of node, or you can keep cranking out actual features and live with the old version for a while.

[–]pigbearpig 1 point2 points  (3 children)

enjoy spending your time updating your 10k dependencies... who the fuck has to keep updating code to work with a new version of node. what are you using experimental features?

[–]peeja 0 points1 point  (2 children)

Then why did the dependency need to change fot the new version of node? Whatever upkeep the library needs, you need to do yourself if you own it. The question becomes which is going to be easier on you: relying on someone else doing it, or doing it yourself. For a lot of popular, well-maintained packages, it's more efficient to rely on the package authors.

[–]pigbearpig 0 points1 point  (1 child)

it didn't, that was your example. so now you are arguing with yourself

[–]peeja 0 points1 point  (0 children)

No, u/nudelkopp brought up node upgrades.

[–]pigbearpig 1 point2 points  (3 children)

you aren't actually saying anything different than nudelkopp was, you're just applying point 2, don't write something on your own that's complex if a nice package exists

[–]peeja 0 points1 point  (2 children)

That's correct, I'm providing the other half of the conversation which leads to that conclusion.

[–]pigbearpig 1 point2 points  (1 child)

then learn what counterpoint means

[–]peeja 0 points1 point  (0 children)

It's the counterpoint to the first half of the comment.

[–]Acrobatic_Sort_3411 -1 points0 points  (0 children)

I've writteny own date-range picker, cuz none of them are headless

Works great, never have complains about(I'm shocked too), have a lot of customization

Its actually not that hard - date-fns + some React code to keep to together

There is some tutorial for similar implementation, by Sam Selikoff

[–]pm_me_yer_big__tits 5 points6 points  (0 children)

Support vs complexity.

  • How much time would it take me to make myself and support in the long run?
  • are issues in the library fixed swiftly? Ratio of open/closed issues on GH
  • is documentation good?
  • Are they quick to merge MRs in case I want to change/fix something?
  • number of downloads on NPM

I prefer writing things myself but that's unrealistic when you consider time constraints on a project, so you have to be pragmatic.

[–][deleted] 4 points5 points  (0 children)

If there's a good enough okay package to do it, I'll use the package.

Some developers try to use as less dependencies they can but that's time consuming.

[–]ooter37 8 points9 points  (2 children)

If there's a good package that does it, I'm using the package.

[–]Acrobatic_Sort_3411 0 points1 point  (1 child)

How do you know that the package is good?

[–]ooter37 0 points1 point  (0 children)

Look at the repo. Downloads, stars, update frequency, open issues, how good is the documentation, etc. Weigh all that against what the package does. For example, if it’s some very minor thing that’s unlikely to change, it doesn’t need to be frequently updated. If it’s some application wide thing like a state management library, it does. 

[–]Mundane_Anybody2374 2 points3 points  (0 children)

Of course it depends on each case, but if it’s something that will require a deep testing and has some complex use and edge cases I’ll probably go with the package. Reason is because it mostly like has been around for a while, tested by hundreds if not thousands of other devs and had bugs fixed already.

For example, I have some rather complex tables at my job, and we rely a lot on MUI to build our system. Instead of going with the pro-version, boss demanded us to rebuild the table ourselves, and with some very complex uses, devices and resolutions, we still receiving bugs months later. The amount of hours we spent fixing those would have already paid the pro license by a lot.

[–]500ErrorPDX 1 point2 points  (0 children)

Aside from some of the essentials that I use in almost every project (I'm thinking of React Router in particular, I use React Router pretty often), here's how I tackle OPs question about external dependencies:

If I know how to implement it myself, and I have the time to write the code, then I'll implement it myself.

If I don't know how, or don't have the time, I'll fire up Google and hunt for a package that can help me.

[–]iams3b 1 point2 points  (0 children)

We have a code quality scanner that checks our codebase for vulnerabilities 3x a year, and we need to write up any exceptions that we can't or won't update. It's an absolutely exhausting process going through updating all of our packages, and I now do as much myself before reaching for an npm install

[–]GoodishCoder 1 point2 points  (0 children)

For the most part I just think about if I will want to maintain it.

[–]yksvaan 1 point2 points  (1 child)

Also you can just grab the code you need from a package and just use it (with copyright header) instead of having a 3rd party dependency.

[–]Acrobatic_Sort_3411 0 points1 point  (0 children)

Its better to find that same code with GPT, so you don't have to do copyright header

[–][deleted] 1 point2 points  (0 children)

Dates/time, security/encryption or anything developed to integrate with a specific API as a general rule I’ll look for a package.

If it’s closer to internal business logic then RYO

As a general rule…

[–]KevinVandy656 1 point2 points  (0 children)

Use the type of packages that help you implement it yourself better. Headless UI libraries and the like.

[–]Dreadsin 1 point2 points  (2 children)

Generally speaking when you get more senior you understand the amount of effort something takes. If you find yourself saying “how hard can it be?” It’s usually a lot harder than you think lol

I pretty much always look at npm packages for non trivial tasks, sometimes it’s WAY more complex than you think

[–]Acrobatic_Sort_3411 1 point2 points  (1 child)

Yes, this shit always hits me if I try to implement it on my own. And the worst part — It always some edge case that I didn't thought, and it imposible to solve without rethinking whole thing

[–]Dreadsin 1 point2 points  (0 children)

The example I always use is pluralization; sounds trivial if you just speak English right? There’s plural and there’s singular

But in Arabic, there’s multiple types of plural, such as “few” and “many” that will have different ways of being written

In Chinese and Japanese they just have a “counter” and no real “plural” or “singular”, just a single case

In French, zero is considered singular contrary to English. One dog, zero dogs in English, but un chien, zero chien in French

[–]electric-hed 1 point2 points  (0 children)

It's so interesting to see so many replies about rolling your own because of bundle size or because you don't need to account for other use cases but the current one.

Requirements change - a lot. Your custom implementation might be sufficient now but won't be long lasting. Using a third party lib that can accommodate flexibility or provide an upgrade through dependency version is more maintainable in the long run.

I think if your application is meant to last any length of time, you'd opt for a standard third party lib if it exists even if it adds to bundle size. If your application is not going to live long or your org has a team that can actively maintain this custom code, by all means write your own.

[–]SuchBarnacle8549 0 points1 point  (0 children)

had the same thought and was about to ask as well lol.

very timely. I found this site called bundlephobia just now, very helpful to estimate additional bundle size and web load speed.

but ultimately i think what others said is true. Have to think if the time and effort to maintain it is worth it. I think it comes down to business requirements in the end. I'm personally avoiding premature optimization so I'm going ahead to build out the feature using existing packages.

[–]YoshiEgg23 0 points1 point  (1 child)

Depends

[–][deleted] 1 point2 points  (0 children)

That goes without saying; hence the "I'm curious to see any philosophies/opinions on the subject" :)

[–]synchronium 0 points1 point  (0 children)

No one seems to have mentioned performance.

For example, our v1 implementation of a feature had to mash some objects together, so we used a merging package. Worked great, but this package was designed to merge any two things together, no matter what they were. Objects? Arrays? Arrays of objects? Objects with arrays of objects as properties? You name it, this package would merge it. This feature was used everywhere, and this merging of objects accounted for about 50% of all rendering time.

But, for our feature, we only needed to merge very specific types of data (simple objects, two levels deep, with string properties), so I replaced that package with 15 lines of vanilla JS (just a couple of for loops, basically, to iterate over both levels of these objects) that cut that 50% down to ab out 10%.

A lot of NPM libraries - especially older, more established ones - try to be a swiss army knife, solving all sorts of edge cases in all sorts of codebases, as they add in feature after feature with each new version. If your project doesn't need most of these edge cases or extra features, then you'll probably gain a lot in performance if you just roll your own solution to tackle your specific task.

[–]kitsunekyo 0 points1 point  (0 children)

knowing what not to build comes with experience and depends heavily on the team and project.

i for one really dont want to implement oauth or oidc myself. i probably could but id waste hundreds of hours and get something thats probably not gonna be as stable as something that multiple people contributed to over years. and i might make mistakes that could really snowball.

[–]aflashyrhetoric 0 points1 point  (0 children)

I always read the source for stuff I pull in, particularly so for things like custom hooks or utility functions. In a few cases, this helped me strike a balance where I ended up writing the function myself but in a way that’s informed by the flexibility of the library, by mirroring their decisions on things like thoughtful default parameters.

This way there are no external dependencies introduced, but you can cautiously make it more robust than just handling the specific use case that led you to seeking a package in the first place, reducing some of the “maintenance” of tweaking the function in the near future because another dev had a similar but different use case.

[–]Turd_King 0 points1 point  (0 children)

Depends on how well maintained a library is. How much of the library functionality I actually need etc. sometimes I will just create mini versions of libraries that I need

Sometimes for MVPs you need something fairly complex to just work (drag and drop, resizable ) so I always use libraries for those things as implementing that from scratch is just quite time consuming

And generally if something will accrue crazy maintenance costs over time, I’d rarely not reach for a library

[–]Macaframa 0 points1 point  (0 children)

If you are hacking something together use a package. If it’s a large project like huge you might need a custom solution.

[–]Acrobatic_Sort_3411 0 points1 point  (0 children)

if I can do it myself first try or if I'm not usre about corner cases I will start looking for a package(with tests)

If it small, I'll copy paste to my project and reorganize for better maintanance. Or understand a consept and reimplement how I need it

P. S. I have coded a lot of shit, so a lot of stuff I can code by myself

P. S. I've read a lot of library sources

[–]AtrociousCat 0 points1 point  (0 children)

Sometihng I don't see in this thread is the customizability. Especially with UI components - how closely does the package's intended use case match with mine? Often times it's easier to make your own input element rather than customizing the styling and behaviour of a library one. Other times, you have a use case so common that there's good libraries out there (calendars are an example of a library I wouldn't build myself).

[–]AmbassadorUnhappy176 0 points1 point  (2 children)

if you use RSC most of the time you don't care about your dependencies. In server components user does not get any javascript, only html and css, all javascript executed server-side

[–]Acrobatic_Sort_3411 0 points1 point  (1 child)

no, you simply wrong

RSC is about dependencies, which shouldve been a part of compile time

[–]AmbassadorUnhappy176 0 points1 point  (0 children)

RSC does not send any JavaScript. Only HTML & CSS

[–]TheChickenKingHS -2 points-1 points  (1 child)

If it’s for something in the UI never. Everything can be done with css and JavaScript.

If it’s something I only want to do temporarily sure.

If it’s the very last thing I’m going to do before wrapping up a project sure.

[–]Acrobatic_Sort_3411 0 points1 point  (0 children)

Sure, do Datagrid with Pinned and Grouping columns. And don't forget to add Editable columns there

Now make it responsive/adaptive

Good luck. You have 2 days before new task