A Rant About Javascript Bloat ![rw-book-cover](https://img.youtube.com/vi/1t-k6-m50Fc/maxresdefault.jpg) I want to be clear about something.JavaScript is far from my favoritelanguage. There's a lot of things I likeabout it, but there's a lot that Idon't. That said, it is almost essentialbecause it's one of the few languagesthat's supported everywhere. And I meaneverywhere. There are some costs to thatthough, and those costs add up, and theresult often ends up being a lot ofbloat. Most of the JavaScript that'sbeing shipped around the web is almostentirely unnecessary. We're talkingabout bloat that just doesn't need to bethere at all. Some of it's cuz our toolsare outdated. Some of us is because thedevs are lazy, but some of it is becauseit made sense at the time and we justnever took the time to fix it after. Andthe result is a web where most of the JavaScript being downloaded isn'tnecessary at all. And that sucks. Ithink it's important for us all to takea moment to reflect on this. Why isthere so much useless JavaScript beingPassed around and what can we do to fixit? At the very least, we need to beable to identify it. My team just sentme a very exciting article from JamesGarbet. The three pillars of JavaScriptbloat. This is a breakdown of all of thedifferent types of bloat that exist inour code bases that make it so we end upwith these giant bundles that are fullof garbage that nobody needs. If we everwant to fix this problem, we need to beable to identify it and describe it. Andthere's a lot to dig into there. Thankfully, not everything on the web isbloat. And one of the things that isn'tis today's sponsor. I think we allunderstand now that our agents get waysmarter when they have access to theweb. But what we usually mean when wesay that is that they can go to sitesand get information from them. But ifyou want to do more, if you want toactually interact with and navigate theweb, you need a browser for your agentsto use. Today's sponsor is Browserbase,And they're here to give you the bestpossible experience for building withagents and the web. A few days ago, Benwas mad at me, and he was threatening toleave SF, so he built an app usingBrowserbase to give him the best flightdeals for leaving to go to LA. Butthere's something very interesting here,that is a new thing as of GPT 5.4. Wehave two versions of this project. Wehave the traditional browser use versionwhere it uses browser use primitives to trigger clicks and keyboard presses,and all of those things, but 5.4 was trainedwith a new capability—the ability towrite JavaScript that is meant toexecute on the page to fake theseinteractions. And it turns out, it's waymore accurate and way faster. I justlaunched the app, and thanks to Browserbase,you can actually watch as thebrowser is used throughout the wholeprocess. Here we see it going to theflight tracker. It is alreadyinteracting with the page, and we can seeIn the logs in our app, what's going onand what it is doing. And here we seethe code that it is writing to executeon the page. Pretty cool that it findsthe button, selects the right buttonfrom that list, waits for the timeoutfor the focus from the click, and thendoes the next steps. And it's wild towatch. For my experience, the JavaScriptexecution method has been so much morereliable that I personally went from,yeah, I guess this isn't really for meto, yeah, I want to start using browseruse type stuff. These types of tasksused to take minutes, and now they takeseconds. If you want your agents toreally use the web, look no further thansoyb.link/browserbase. I'm actually really, really excited togo through this article with you guys.Shout out to James, the author. He worksreally hard on ecosystem performancethings, just trying to make ourJavaScript ecosystem better. That's whyhe's so involved with things like unjs. And all these other cool projects, aswell as npmxdev, which is a really coolnew like npm registry viewer tool.Choked is essential for a shitload ofstuff that I do. This is the packagethat is used for tracking what changesare happening on your file system innode for things like hot reloading andhe's an active contributor to it. It israre that one dev touches that manydifferent things in the open sourceworld. So very excited to see histhoughts here. He knows this [ \_\_ ] betterthan almost anyone. Three pillars of JSbloat. Over the last couple years, we'veseen a significant growth of the E18community and a rise in performancefocused contributions because of it. Alarge part of this is the cleanupinitiative where the community has been pruning packages which are redundant,outdated or unmaintained. One of themost common topics that comes up as partof this is dependency bloat. The ideathat npm dependency trees are gettingLarger over time, often with long sinceredundant code which the platforms nowprovide natively. In this post, Jameswants to briefly look at what he thinksare the three main types of bloat in ourdepth trees, why they exist, and how wecan start to address them. I couldn't bemore excited for this one. This is oneof those few people that like reallyknows what they're doing here. Oh [ \_\_ ]one of my chatters has actually justjoined E18 today. That's really cool tosee. First piece, and this is important. Older runtime support with safety andrealms. What the hell is a realm? We'llknow in a moment. Here's an examplegraph they have. There's the is stringpackage. Is string checks has to stringtag which has a dependency on hassymbols. It also has a dep on call boundwhich has get intrinsic which has ashitload of additional subpackages. Ahandful of which touch call bind applyhelpers and those touch function bindand ES errors. So yeah, quite aDependency tree for is string. Graphslike this are a common site in many npmdependency trees. A small utilityfunction for something which seems likeit should be natively available followedby many similarly small deepdependencies. So why is this a thing? Why do we need is string instead of typeof checks? Why do we need has owninstead of object or object.prototypehashazone property? Well, there's threethings. First, there is support for veryold engines. Second, there's protectionagainst global namespace mutation.Third, and most importantly, there'scrossrem values. Oh boy. First, we havethe support for old engines. Somewherein the world, some people are apparentlyexist who need to support ES3, likeInternet Explorer 6 and 7 or extremelyearly versions of Node. Fun fact aboutthis. Curious what he links as afootnote here. He says that he believesthere are people who need these oldengines, but he would love to seeExamples. There's actually a companythat does this. They're named Hero Devs. They have what I would consider some ofthe most thankless work in the industry.Their job is to come in as contractorsat companies that have old, ancientterribly maintained and structured codebases that none of the engineers at thecompany want to work on. If they evenhave engineers there, they maintainthese old end-of-life projects as well astheir dependencies. They have forks ofthings like NodeJS 0.8 that bring insecurity fixes while still having theweird [ \_\_ ] that the company needsfor the old version of Node. They alsowill often have to change packages and fork them and maintain them themselvesin order to keep them compatible withold versions of Node. This has evenburned some people in the past wherethey took over a poorly maintained repothat had a dependency that was beingused by spelt and when they modified it,they wanted it to work for these reallyOld things. So they took a package thathad no dependencies and they ended upadding different things that they hadmade in order to let it support oldancient unmaintained versions of node. But that resulted in a package that usedto be a single small dependency inspeltkit, becoming like 20 subdependencies.Rich Harris flipped a[\_\_]. And that was the first time a lotof people saw the type of work thatthese devs have to do. I know a coupleemployees at this company, they live inthe shadows. They like development, thescience more than the ecosystem. Myfriend who told me when they were goingto start working there that they wereinterested. I was like, "Oh, you're noteven like you're joking, right? Likethere's no way you'd actually want to dothat type of work." And they were like,"No, I love this stuff. I love thesehard, thankless problems that nobodythinks about. Kind of nuts. Yeah, thesepeople do actually exist. And to James,Who seems to not know any of them,according to his footnote, they are the ones you need to talk to if you wantexamples of people using these reallyold things that have this crazy set ofweird dependencies that aren't needed inmost places. It's all them. There's abunch of things that we take for grantedin modern JavaScript that just don'texist in these old places. For example,for each on arrays or reduce on arrays,or object.keys, which I use all ofthe time, or object. I use someof the time. I do not know how I wouldwrite JS without these. These are allES5 features, meaning they simply don'texist in ES3 engines. For thoseunfortunate souls who are still running,old engines, they need to reimplementeverything themselves or be providedwith polyfills. Alternatively, it'd bereally nice if they just upgraded. Totally agree there. Protection againstglobal namespace mutation. The secondreason for some of these packages isSafety in quotes. Basically, inside ofnode itself, there's a concept ofprimordials. These are essentially justglobal objects wrapped at startup andimported by node from then on to avoidnode itself being broken by someonemutating the global namespace. Forexample, if node itself uses map and weredefine what map is, we can break node. To avoid this, node keeps a reference tothose original versions of things likemap which it imports rather thanaccessing the global. They have a wholesection about this in the repo. This isfascinating. I did not know about thisthat Node rebinds all of the defaultglobals in a custom namespace early sothat they can use them without your[ \_\_ ] overriding them. Fascinating.This also makes a ton of sense as anengine because it shouldn't break ifsomebody overrides some core [ \_\_ ]Good stuff. As always, the Node projectis underappreciated for the level ofcomplexity that they're operatingWithin. Like Node and V8 are two of themost crazy complex, generous gifts tothe software development world that gettreated like [ \_\_ ] because people justhate on JavaScript. Always has annoyedme, even back when I hated JS. Okay,last time I hated JS was like the lasttime I had to write JS. To be fair,but you get what I mean. Apparently, there are some maintainers that believethis is the correct way to buildpackages, too. That's why we havedependencies like math intrinsics in thegraph above, which is just a reexport ofthe various math.star functions in orderto avoid them being mutated. What? Yep,math intrinsics. All that package doesis reexports the default so if they getoverridden, you can still rely on them. That is obnoxious. And now we get intorealms crossrem values. This is whathappens when you want to pass thingsfrom web pages to iframes and stuff likethat. In this situation, a new reax inan iframe is not the same thing as aReax class as one of the parent pages. So if you make a reax inside of a pageand you make a different one inside ofthe iframe, they don't match. So if youdo something like trying to compare thewindow.reax versus iframe window.reax,the values are different and that wouldend up being false if it came from theiframe. For example, he's a maintainerof chai and we have this exact issue. Weneed to support assertions happeningacross realms. This test runner may runtests in a VM or even in an iframe. Sowe can't rely on instanceof checks. Forthat reason, we have to useObject.prototype.toString.callvalue to check ifsomething's a reax, which works acrossrealms. It doesn't rely on theconstructor. Apparently, it's the samething that is string does because if youpass a new string from one realm to another, you might not be able to checkagainst the global like window stringbecause it's a different type because itCame from a different realm. God, Ipeople don't appreciate how hard JS canbe at these levels. I don't know aboutyou guys, I've never had to deal withthis myself. I've never had to worryabout what happens if I pass a value inout of an iframe and I can't do instanceof calls on it. That's very differentfrom the world I live in personally. Ilike this call out here. All of thismakes sense for a very small group ofpeople. If you're stuck supporting veryold engines, passing values acrossrealms, or you want protection fromsomeone mutating the environment, thesepackages are exactly what you need. Problem is that the vast majority of usdon't need any of this. We're runningmodern versions of node that were and bymodern I mean the last 10 years or we'reusing an evergreen browser that getsautomatically updated. We don't need tosupport prees5 environments. We don'tpass values across frames and weuninstall packages that break theEnvironment. Yes, mostly again herodevs. Yeah, these layers of nichecompatibility somehow made their wayinto the hot path of everyday packages. The tiny group of people who actuallyneed the stuff should be the onesseeking out special packages for it.Instead, it is reversed and we all paythe cost. Exactly. Thank you to thechatters, and begrudgingly, thank you toGrock for the help finding this examplefrom way back. The AX object querypackage, which is used by a bunch ofthings for programmatic detection ofaccessibility issues. It originally hadalmost no dependencies, and a differentdeveloper had just come in to take overthe project because it wasn't beingmaintained by the original devs anymore. They agreed to let him take it over. Andwhen he did, he immediately focused onbackward compatibility maxing, which hedid by fundamentally changing thestructure of the dependencies. And hereyou can see they added a bunch ofAdditional dependencies that largelycame from that team in order to try andmake back compat with really oldversions of node possible. This changepissed off so many people and confusedthem so much they thought it was asupply chain attack. Most devs had justnever seen this type of backcompatibility being added to a project. And it looked like this too, since thedev LJ Harb was the one who built mostof the subdependencies that were added,because, again, remember it is his job tomaintain these ancient code bases andbuild all of the key pieces that areneeded for things to work in stuff likeold node 0.4 projects. That said, Samwas entirely wrong here. This was not asupply chain attack under the guise ofsupporting node 0.4. For nobody would doa supply chain attack with somethingthat's that obviously stupid. They woulddo it with something that seems morepromising, like performance improvements.Nobody would ever do anything under this. Cuz this is not something anyone wouldwant to merge. This is something thatthey're doing because they have tomaintain these old code bases, and that'sthe easiest path they've had. My problemwith her devs, and I have told this tothe people who I know, is that theytreat these core dependencies as thoughthey have to support everything. Theytreat these core dependencies as thepath to get that legacy support intotheir things, not even through customversions of the packages, but throughforcing the main versions of thesepackages to continue to be compatiblewith these ancient versions of things. And the result is a bunch of unnecessarybloat. It's worth noting that of those60 new direct dependencies that wereadded, one of them, which is deep equal,which is necessary when using ancientversions of node for comparisons ofthings, added 50 by itself. This nearlydoubled the number of packages that werenecessary to install SpeltKit. And theSpelt team was [ \_\_ ] pissed, as theyshould be. It's kind of crazy that aminor version bump of something thatyou're already using can suddenly doublethe number of dependencies that you havein your codebase. Again, I want toemphasize just how thankless this workis, but also that I don't think it isappropriate for the Hero Devs team to effectively be forcing their uniqueneeds onto the default path for otherdevs. These things are so uncommon thatthey probably need to be in either othercustom branches or tags or ideally evena fork with a different name formaintaining these old versions of thepackages. That was all just for thefirst pillar. By the way, we got twomore other separate things that cancause bloat. Thankfully, these ones area little bit simpler. The next is atomicarchitecture. Some folks believe thatpackages should be broken up to analmost atomic level creating acollection of small building blocks. which later can be reused to build otherhigher level things. So you end up withgraphs like this one where you have execa, which has a couple sub-devs likecinders, merge streams, cross spawn, whichdepends on which path, key, shebang,command, shebang, reax, etc., because all ofthese are really simple things likeshebang, reax, a very simple reax forchecking if it's a shebang or not is exe. What that does, get stream, has its ownseparate readable stream implementation.It references as well as an is streamfunction instead of just having them.You get the idea: when there's apart that is reusable, it is broken outto be reusable. Although, it's funny, Ijust referenced the shebang reax one,then that's the example the author givestoo. This is a package that is a packagethat is downloaded 133 million times aweek. Do you understand how absurd thatis? Two lines of code, and there arefour versions of four majors that aredownloaded 133 million times a week. Lines of code. It's a reax. It's a reaxand an export. You might start to bethinking we did this to ourselves. Andyou know what? I think we did. Bysplitting code up to this atomic level,the theory is that we can then createhigher level packages simply by joiningthe dots. I get this. I am a big fan ofthe Unix philosophy myself. But uh Unixphilosophy should not be at a line ofcode level. Here are some commonexamples and I'm going to check howpopular these are in npmjs as we gothrough. We have rfi which converts avalue to an array. If it's an array,then we return the array. If not, thenwe return it with an array wrapper. It'sone line of code. And this package isdownloaded 32 million times a week. Next, we haveslash, which replaces backslashes andfile system paths with traditionalslashes. This package is downloaded,wait for it,96 million times a week. We got CLIBoxes, which is a JSON file containingthe edges of a box 40 million times aweek. It literally is just a JSON blobwith top left character, top character,top right, right, bottom right, bottom,bottom left, left. 40 million times aweek. It's a JSON file. I'm going todie. I knew it was bad. I did not knowit was this bad. Oh, path key. I've usedthis one. I've used this one. Oh no. Howpopular is this? 158 million times a week. It's a 4kilobyte of JS file. It is literallyjust a file. Let's look at the JS forit. If platform is not wind32, returnpath. Otherwise, we have to go steal thepath in Windows because Windows has alowercase path. I can't believe the world we're in. Wedid this to ourselves.Today's sponsor is all about hiring. Ifyou need great engineers, look nofurther than G2. That's not G2I. That'sthe AI engineer conference in Miami.Yeah, I kind of tricked you guys. Does a lot more than just hiring. Theyrun some of my favorite tech events.I've been going to React Miami for threeyears now, and it's consistently myfavorite tech conference every year.They are still doing React Miami. Infact, it's right afterwards. If you wantto hang out with cool engineers like me,Prime, and all the other awesome folkswho show up for this stuff, I highlyrecommend checking out the AI engineerWorld Fair in Miami as well as ReactMiami from April 20th to 24th. If youdon't have the time for a conference,it's probably because you need to hiremore. And if you do, I highly recommendhiring at soy.Chat made a good call out. The dev whowrote this article is also working onnpmx, so I should definitely be usingthat for these searches. It's a lotquicker when I search one time, whichensures a function is only called once,which is 131 million downloads a week.And it's once again Cinder. Poor Cinder. Has had to write so much random [ \_\_ ]that we all rely on. He wrote Kai, whichis still my favorite fetch rapper, aswell as a ton of these thankless smallprojects that are necessaryish when youwant to reuse things and have them besimpler. Kind of, h a lot of respect forthe work he does. I rely on so much ofhis [ \_\_ ] regularly, but some of thesethings it hurts that they exist. Oh,this is cool. String width. This is howlong the string actually is, not justhow long the binary is. Thankfully, thisone's relatively small for what it is. And it's actually kind of annoying to dothis, right? Because, like, is a characterlike this is one care, but it isactually longer when you print it. Andif you put a bunch of these tags aroundit, it's still only two cares long. Andstring width handles it. That's actuallya good example of a thing that's kind ofannoying to calculate and do, right? Especially with emojis and [ \_\_ ] Yeah.One of the cool things I didn't realize. On the site is that npm's will show youthe total downloads per week ofsomeone's packages, and his packages aredownloaded almost 10 billion times perweek. That is insane. Oh god, howpopular is Windows? Okay, it's only 27million. It's not as bad as some of theothers, but you get the idea. These areall very, very, very, very, very, verypopular packages. Absurdly. So, you wantto build a new CLI; for example, you canpull a few of these in and not worryabout implementation. You don't need todo env path or envasepath or cells. You can just pull apackage for that. Great. I actually havea whole video about why I thinklibraries are kind of dying as a resultof vibe coding. It's really cool thatit's a lot easier to write this solutionthan it ever was before because AI willknow this mistake or at the very leastfind the package and hopefully read thecode and realize it shouldn't be usingit. TBD, but you get the idea. So why isThis a problem? In reality, most or allof these packages did not end up as thereusable building blocks they were meantto be. They're either largely duplicatedacross various versions in a wider tree,or they're single-use packages whichonly one other package uses. Forexample, shebang reax it's almost solelyused by shebang command, which is by the same maintainer. CLI boxes is usedalmost solely by boxin and ink, also bothby the same maintainer. One time is usedalmost solely by restore cursor, which isagain the same maintainer. These areseparate packages that have no reason tobe separate packages. Each of thesehaving only one consumer means they areequivalent of inline code but cost usmore to acquire because of npm requests,tar extraction, bandwidth, etc. Yep. Ifthree different things you used requiredshebang reax, having it as a singleshared package could theoretically makesense. The fact that it's one line makesit less so, but hypothetically speaking,But that's not the case. This is justdumb. And then we have the duplicationproblem. Taking a look at the Nuxdependency tree, we can see a few ofthese building blocks that areduplicated because they have twodifferent versions of the same thing. Another fun problem. There's twoversions of his Docker. There's twoversions of his stream. There's two ofhis Windows Subsystem for Linux. There'stwo of his exe, two of npm, run path, twoof path key and two of path scurry. That's because they have packages thatthey're relying on that both rely on isdocker or is stream and they rely ondifferent versions so you end up withtwo versions of the same thing. Inlining these does not mean we nolonger duplicate the code but it doesmean we don't pay the cost of thingslike version resolution conflicts, costof acquisition, etc. Making duplicationalmost free while packaging makes itexpensive. Yep, entirely correct and oneOf the biggest issues, especiallyrecently, is the larger supply chainsurface area, which makes it easier to attackand hijack people's [ \_\_ ]. It's so commonthat people now speculate that whensomebody is trying to make somethingwork in older projects, that it is asupply chain attack, because we justexpect this now. The more packages youhave, the larger the supply chainsurface area is. Every package is apotential point of failure formaintenance, security, and so on. Forexample, a maintainer of many of thesepackages was compromised last year. Thismeant that hundreds of tiny buildingblocks were compromised, which meantthat the higher level packages weactually install were also compromised. Logic as simple as array.isarrayprobably doesn't need to be its ownpackage. Security, maintenance, and soon. It can just be inlined, and we canavoid the risk of it being compromised.Absolutely agree. Similar to the firstPillar, which is the older runtime support, this ended up being a thingthat made its way into the general hotpath. So, the thing most people dohappens to now involve this. Even thoughthese are more conceptually good thingsthat are useful in niche-specificplaces, it became the thing we're alldoing whenever we install [\_\_]. Theresult is that we all have to pay thiscost without getting any benefitourselves. I'm going to turn off the dark mode for a sec. So, uh, prepareyour eyes. It just happened to breakthis particular view because canvasesare hard. This is the pony fillssection. Pony fills that overstayedtheir welcome. There's a lot of thingsin here that were really useful in 2010like is array that still gets 160million installs a week or object.keysor string.prototype.trim that are waytoo popular and these dates, by the way,are effectively when the native supportoccurred. So, in 2010, all these thingsBecame common in JS package are stillhuge is NaN got built in in 2013 packagestill gets millions of installs a week. Array prototype, string prototype,repeat, object sign, you get the idea.All of these features that have been inJavaScript for 15 plus years, for some ofthem, still have packages being installedthat are entirely unnecessary. If youwere looking away because of the lack ofdark mode, you can look back now. You'rebuilding an app, you might want to usesome future features that your chosenengine doesn't support yet. In thatsituation, a polyfill can come in handy. For all of you guys who really wantedtemporal, you've probably been using apolyfill for a while now. Polyfillsprovide fallback implementations wherethe feature should be so you can use itas if it was natively supported. Veryvery cool thing. Typescript used to evenintroduce certain polyfills for thingsthemselves so that features that mostFocused ones could be in early, so youcould have access to them. Generally, Ithink that's an okay to good pattern. For example, temporal polyfill willpolyfill the new temporal API so you canuse it regardless of if the enginesupports it or not. I swear when Istarted doing JavaScript heavily back in2018, we were still talking about howexciting temporal was. It's juststarting to ship now 8 years later,which is kind of crazy. And here we are. You're building a library instead. Whatshould you do? In general, no libraryshould load a polyfill, as that is aconsumer's concern, and the libraryshould not be mutating the environmentaround it. Again, polyfills add thingsto like globals, so they will work inyour environment. If you are personallywriting code in your project that'suser-facing, and you want temporal, goinstall the polyfill. That's totallykind. It's a top-level depth that makessense. Polyfills sneaking in throughOther things make way less sense. Thankfully, there are very few projectsthat do that, that bring in a polyfillthat can [ \_\_ ] up your environment.There are a lot of devs who wanted that,and I can sympathize here.There are a lot of devs that are using features thatmight be kind of new in their packages,and those features are probably causingbugs for a lot of their users. The users,being developers implementing them.So, if you made a package that uses temporal,person installs that package and itbreaks because they don't have temporalinstalled, you're probably tired oftelling all of them, make sure youinstall the polyfill, make sure youinstall the polyfill. So, the solutionfor this is called a pony fill.It's kind of like a polyfill, but it givesyou a different import path.So, instead of changing the runtime,instead of binding things to globals, it just letsyou import a fake temporal that you cancall directly instead. I can absolutelyI sympathize with this because I had a lot ofweird problems when I was maintainingprojects at Twitch. There's only aninternal dashboard for managing reportswhen users report people on Twitch. Andalmost all of the safety ops people thatactually went through those reports wereusing Chrome, as were the devs. Everything worked great in Chrome. Ifyou ever wonder where my disdain forFirefox started, it was then, because wehad one single person who really wantedto use Firefox, and the amount of random[ \_\_ ] that broke was horrifying.Backwards reax just wasn't supported.And it didn't even give good errors whenyou tried. That meant I had to polyfillreax for Firefox. Yes, really.This is the world we live in. Pony fillsare basically polyfills that you importrather than mutating the environment.This kind of works since it means alibrary can use future tech by importingan implementation and it can pass thataround so it can use the native one ifIt needs to, if it exists. Otherwise,it'll use its pony fill otherwise. None of this mutates the environment, so it'ssafe. So, why is this a problem? Itseems fine if they're not mutating theenvironment, right? Well, the code'sstill there. These pony fills did theirjob at the time. They allowed libraryauthors to use future tech withoutmutating your environment and withoutforcing consumers to know what polyfillsthey have to install. The problem comes withthe pony fills when they outstay theirwelcome. When the feature they fill infor is now supported by all majorengines that we care about, the ponyfill should be removed. However, thisoften doesn't happen and the pony fillremains in place long after it's needed. We're now left with many, many packageswhich rely on pony fills for featureswe've all had for a decade or more,including global this because globalthis didn't used to exist, but it's beenwidely supported since 2019. Globalist package still gets 49 milliondownloads a week. Or index of, are youkidding? That's been supported since2010, and it still gets 2.3 milliondownloads a week. And then objectentries, which has been supported since2017, is still getting 35 million downloadsa week. Unless these packages are beingkept alive because of pillar one, whichis the support for the old things. They're usually still just used becausenobody ever thought to remove them. Whenall long-term support versions ofengines have a feature, the pony fillshould definitely be removed. Absolutelyagree. Oh boy, the index of package. Thedescription is great. Lame index ofthing. Thanks, Microsoft. This clearlywas only built to support InternetExplorer at the time. We look at thecode, the very complex code. If index ofdoes exist in your runtime, which ischecked with the empty array index of,if it exists, we just use thearray.indexOf that you passed looking. For the object. And if it doesn't, thenwe for loop across it to get you theindex. This is 10 lines of code that aredownloaded millions of times a week thataren't only stupid and easy to write,they're entirely unnecessary. The authorof this package is TJ, who is thecreator of Express, who left JavaScripta decade ago. Dogpaw and Steven arehelping a ton here. Thank you both, bythe way. Huge shout-out to you guys formaking sure I get all the fun facts inthis one. So, now the most importantpart. What can we do about all of this? Much of this bloat is so deeply nestedin dependency trees today that it's afairly hefty task to unravel it all andget to a good place. It will take timeand it will take a lot of effort forboth maintainers and the consumers ofthese libraries. Having said that, I dothink we can make significant progresson this front if we all work together. Start asking yourself, why do I havethis package, and do I really need it? This is especially important formaintainers. If you find something whichseems redundant, raise an issue with themaintainer asking if it can be removed.You encounter a direct dependency whichhas many of these issues, have a lookfor an alternative which doesn't. A goodstart for this is the modulereplacements project which is also partof E18. I already liked these guys. Ivery quickly am realizing they areessential to this ecosystem. Anothergreat recommendation is NIP. We use thisin all of our projects now. It has beenan incredibly helpful thing. NIP willfind unused code and imports in yourproject and make it easy to get rid ofthem. It also helps with unused depths,dead code, and many other random things. Be a great tool to find and removedepths you no longer use. It doesn'tsolve all these problems necessarily,but it's a great starting point to helpclean up depth trees before doing themore involved work. Oh, E18 has a CLIThat is an analyze mode that can determine which depths are no longer needed or have community replacements that are recommended. Apparently, chalk can be replaced with native functionality.That's really cool.This is a great little package here.That's so cool.They even have a migration command that can migrate for a handful of these things that are automatable.In this case, it'll migrate from chalk to Pico colors, which is a much smaller package that provides the same functionality.CLI will even recommend based on your environment.For example, it can suggest the native style text instead of a colors library if you're running a new enough node.That's really cool. Also, npm graphs.This is really, really useful.Using npm graphs to figure out what the dependencies are of your [ \_\_ ] is really good.Yeah. Yeah, I had a feeling the T3 package has built up a little bit.We got some infrastructure there. Effect. We got the diffs library. We gotopen and websocket node pointer, and theclaw agent SDK package is so heavilyoffuscated that they're also usingwhat's the package that Vercel has? NCC.That's what I'm thinking of. NCC is apackage by Vercel that takes all yourdependencies and bundles them into asingle JS file. And I'm almost positiveAnthropic is using that here becausethey don't want us to know anythingabout how the API SDK is implemented,because they are kind of evil. So Iwould bet this has lots of othersubdependencies. We just can't see them. Apparently Pierre's diffs library has alot of subdependencies. I did not realize that,like half of our dependency graph comesfrom the diffs library. Interesting. To be fair, there are some core dependencies inhere that have to be a little complex,like Shiki for the syntax highlighting. Like, that's just not a trivial thing.And then the HTML util that turnsthe syntax tree into HTML has a lot ofThese subpackages too. Interesting. You learn something every day. And I'mlearning about my own dependency graphright here. See, this is a really goodexample here too with ESLint, wherethere's this find-up package that is abunch of sub things around six total.And if you can replace that package, thenyou can trim out six packages from yournpm install. That's a great thing. There's also the module replacementsproject, which has a set of replacementsthat are modern, simpler, and morewell-maintained than these old things.That makes it really easy to identifyand replace anything that could bereplaced. This has been an awesomearticle. Huge shout out again to James.Let's read the closing thoughts and doone last important thing at the endhere. We all pay the cost for anincredibly small group of people to havean unusual architecture that they likeor a level of backwards compatibilitythat they specifically need. Fault of the people who made thepackages, as each person should be ableto build however they want. Many of themare from an older generation of influentialJS devs building packages in a darkertime, where many of the nice APIs andcross-compatibility that we havetoday simply didn't exist. They builtthe way they did because it was possiblythe best way at the time. The problem is that we never moved on from there.We still download all of this bloat today.Even though we've had these features forseveral years, I think we can solve thisby reversing things. The small groupshould pay the cost. They should havetheir own special stack that pretty muchonly they use. Everyone else should getthe modern, lightweight, widelysupported code. Hopefully, things likethe E18 Foundation and npmX can helpwith that through documentation,tooling, etc. You can help by taking acloser look at your dependencies andasking why. Raise issues with yourDependencies, asking them if and whythey need these packages anymore. We canfix it. E18E is one of the mostessential things happening in the JSworld. I already thought highly of them,but now I am convinced that we need them in order for JS to survive. As such, I'mgoing to do the most important thing tosupport a project like this, money. Ijust contributed $5,000. I think this isimportant. I hope this helps prove justhow important I think this is. And Ihope many of y'all take the opportunityto do the same. These projects are nojoke. These are the things that actuallymake the ecosystem survivable. These arethe things that make the web better andkeep things from getting worse. If wewant the web to win, and I hope we alldo, I hope you guys who have money, andI know many of you have money, take theopportunity to contribute, or at thevery least tell your boss that it'sprobably worth including in your opensource financial contributions. Obviously, not everybody needs to donatethis much money, but if you have acouple of bucks to throw their way, you'dbe amazed how far it goes. The teamdoesn't actually need too much money tosurvive right now, and they're very,very, very lean. I would argue more sothan they should be because these devsare doing some of the hardest work, andthey are being paid like [ \_\_ ]. They currently have a total balance of$17,000, which, in my opinion, is enoughto pay one dev once. These devsshould be paid very generously becausethis is very, very important work. Thefact that an organization that is thisimportant literally only has about$17,000, is terrifying. I amthankful I just got to meaningfullyincrease that myself. I got nothing elseto say. Just go support these guys. They're doing important work. And untilnext time, peace nerds., A Rant About Javascript Bloat, YouTube, 01kmxp3ra7321mcxxhfkp18m4w.