A Rant About Javascript Bloat ![rw-book-cover](https://img.youtube.com/vi/1t-k6-m50Fc/maxresdefault.jpg) ๐Ÿ”— **Source:** [A Rant About Javascript Bloat](https://www.youtube.com/watch?v=1t-k6-m50Fc) > [!note]+ Document Notes > tags: #javascript #npm #bloat #performance #dependency-management > author: Theo - t3.gg > source: YouTube > reference: https://www.youtube.com/watch?v=1t-k6-m50Fc > date created: 2025-01-02 10:30 > > # ๐Ÿท๏ธ Title: A rant about Javascript bloat > <!-- deep-read:sections start --> ## ๐Ÿงฐ Action Inbox - [H1] Audit dependency trees using E18 CLI analyze mode โ€” identify redundant packages #dependency-management - [H2] Install NIP tool to find unused code and dependencies โ€” reduce bundle size #performance - [H3] Support E18 Foundation financially โ€” critical ecosystem cleanup work #open-source ## ๐Ÿงญ Table of Contents - [[#๐Ÿ“ Summary]] - [[#๐Ÿ“– Main Content]] - [[#๐Ÿ—’๏ธ Notes]] - [[#๐Ÿ“š References]] - [[#๐Ÿ—ฃ๏ธ Paraphrase]] - [[#๐Ÿ“ฐ Newsletter]] - [[#โœ… Action Items]] - [[#๐Ÿงช Hypotheses]] - [[#๐Ÿ“Š Methodology]] - [[#โ“ Questions]] - [[#๐Ÿ”ฎ Future Research]] - [[#๐Ÿ’ก Implications]] - [[#๐Ÿง  Learning Styles Assessment]] - [[#๐Ÿ“Š Accessibility Assessment]] - [[#๐ŸŒ DEIB Assessment]] - [[#โœ… Logical Validity]] - [[#๐Ÿ›ก๏ธ DARVO Analysis]] - [[#๐ŸŽฏ Conclusion]] ### ๐Ÿ”— References - [Three Pillars of JavaScript Bloat](https://npmjs.dev) by James Garbet - [E18 Foundation](https://eslint.org/blog/2024/09/eslint-officially-becomes-open-collective/) - [Module Replacements Project](https://github.com/es-tooling/module-replacements) ## ๐Ÿ“ Summary - JavaScript ecosystem suffers from massive dependency bloat with millions of unnecessary downloads weekly - Three main causes: legacy runtime support, atomic architecture, and outdated polyfills/ponyfills - Most bloat exists to support tiny niche use cases while entire ecosystem pays the cost - Solutions include E18 Foundation cleanup initiative, NIP tool, and module replacement projects - Community needs to audit dependencies and financially support ecosystem maintenance ## ๐Ÿ“– Main Content JavaScript dependency bloat has reached crisis levels, with packages like `is-string` requiring extensive dependency trees and simple utilities being downloaded millions of times weekly. James Garbet's analysis identifies three primary causes: **Legacy Runtime Support**: Packages maintain compatibility with ancient engines like IE6-7 and Node 0.4, requiring complex polyfills and primordial protections. Companies like Hero Devs specialize in maintaining these legacy codebases, but their requirements shouldn't dictate mainstream package architecture. **Atomic Architecture**: The philosophy of breaking code into microscopic, reusable packages has created absurd situations like `shebang-regex` (2 lines, 133M weekly downloads) and `slash` (96M weekly downloads). These "building blocks" rarely get reused as intended and increase supply chain attack surface. **Outdated Ponyfills**: Packages continue shipping fallback implementations for features supported natively for over a decade, like `Array.prototype.indexOf` (supported since 2010) still getting 2.3M weekly downloads. The E18 Foundation leads cleanup efforts through tools like their CLI analyzer and the Module Replacements project, helping identify and migrate away from bloated dependencies. ## ๐Ÿ—’๏ธ Notes #### โฑ๏ธ [00:00](https://youtu.be/1t-k6-m50Fc?t=0) โ€” [H1] JavaScript bloat crisis introduction - Key idea: Most JavaScript shipped on web is unnecessary bloat costing entire ecosystem - Evidence: "Most of the JavaScript that's being shipped around the web is almost entirely unnecessary" #### โฑ๏ธ [02:14](https://youtu.be/1t-k6-m50Fc?t=134) โ€” [H2] Three pillars article by James Garbet - Key idea: Systematic breakdown of bloat types needed to identify and fix problems - Evidence: James works on "ecosystem performance things, just trying to make our JavaScript ecosystem better" #### โฑ๏ธ [04:23](https://youtu.be/1t-k6-m50Fc?t=263) โ€” [H1] Legacy runtime support pillar - Key idea: Complex dependency chains exist primarily for ancient engine compatibility - Evidence: `is-string` package requires extensive dependency tree just for type checking #### โฑ๏ธ [06:45](https://youtu.be/1t-k6-m50Fc?t=405) โ€” [H2] Hero Devs company example - Key idea: Specialized companies maintain legacy codebases requiring ancient compatibility - Evidence: "They have forks of things like NodeJS 0.8 that bring in security fixes" #### โฑ๏ธ [09:12](https://youtu.be/1t-k6-m50Fc?t=552) โ€” [H2] Node.js primordials protection - Key idea: Node rebinds globals at startup to prevent user code from breaking internals - Evidence: "Node keeps a reference to those original versions of things like map" #### โฑ๏ธ [11:30](https://youtu.be/1t-k6-m50Fc?t=690) โ€” [H3] Cross-realm value problem - Key idea: Values passed between iframes/realms require special instanceof-free checking - Evidence: "new Array in an iframe is not the same thing as Array class as parent page" #### โฑ๏ธ [15:45](https://youtu.be/1t-k6-m50Fc?t=945) โ€” [H1] Atomic architecture pillar - Key idea: Breaking packages into microscopic pieces creates absurd dependency bloat - Evidence: "shebang-regex" is 2 lines downloaded 133 million times weekly #### โฑ๏ธ [18:20](https://youtu.be/1t-k6-m50Fc?t=1100) โ€” [H2] Ridiculous package examples - Key idea: Simple utilities become separate packages with massive download numbers - Evidence: "slash" replaces backslashes, downloaded 96 million times weekly #### โฑ๏ธ [20:15](https://youtu.be/1t-k6-m50Fc?t=1215) โ€” [H2] Sindre Sorhus package statistics - Key idea: Single developer's packages downloaded nearly 10 billion times weekly - Evidence: "his packages are downloaded almost 10 billion times per week" #### โฑ๏ธ [22:30](https://youtu.be/1t-k6-m50Fc?t=1350) โ€” [H3] Single-use package problem - Key idea: Many atomic packages only used by one consumer, defeating reusability purpose - Evidence: "shebang-regex almost solely used by shebang-command by same maintainer" #### โฑ๏ธ [25:10](https://youtu.be/1t-k6-m50Fc?t=1510) โ€” [H1] Ponyfills pillar - Key idea: Polyfill alternatives that overstay welcome after native support widespread - Evidence: "global-this" package gets 49M downloads weekly despite 2019 native support #### โฑ๏ธ [28:45](https://youtu.be/1t-k6-m50Fc?t=1725) โ€” [H2] Solutions and tools - Key idea: E18 Foundation provides tools to identify and replace bloated dependencies - Evidence: CLI can "suggest native style text instead of colors library" #### โฑ๏ธ [30:00](https://youtu.be/1t-k6-m50Fc?t=1800) โ€” [H1] Financial support call - Key idea: Ecosystem cleanup work requires funding to be sustainable - Evidence: Theo donates $5,000 to E18 Foundation with $17,000 total balance ## ๐Ÿ“š References - [Three Pillars of JavaScript Bloat](https://npmjs.dev/blog/the-three-pillars-of-javascript-bloat) - [E18 Foundation](https://eslint.org/) - [NIP - Find unused dependencies](https://github.com/webpro/knip) - [Module Replacements Project](https://github.com/es-tooling/module-replacements) - [npmxs - Package explorer](https://npmjs.dev) ## ๐Ÿ—ฃ๏ธ Paraphrase - JavaScript ecosystem drowns in unnecessary dependencies created for niche compatibility requirements that affect entire community - Three main bloat sources: ancient browser support, over-atomized packages, and outdated polyfills that never got removed - Simple solutions exist through tools like E18 CLI and NIP, but require community effort to audit and migrate dependencies ## ๐Ÿ“ฐ Newsletter **JavaScript Dependency Bloat: Time for Spring Cleaning** The JavaScript ecosystem has a weight problem. Packages downloaded millions of times weekly often contain just 2 lines of code or support browsers from 2006. James Garbet's analysis reveals three main culprits: legacy compatibility, over-atomized architecture, and outdated polyfills. **What This Means for WordPress Developers:** Many WordPress tools and plugins inherit this bloat through their JavaScript dependencies. The E18 Foundation provides tools to audit your dependency trees and find modern replacements. **Action Steps:** - Use NIP tool to find unused dependencies in your projects - Check the Module Replacements project for better alternatives - Support ecosystem cleanup efforts financially when possible **Resources:** [E18 Foundation](https://eslint.org/), [NIP Tool](https://github.com/webpro/knip), [Module Replacements](https://github.com/es-tooling/module-replacements) ## โœ… Action Items #### Community - Contributors: Audit project dependencies using E18 CLI analyze mode - Maintainers: Remove ponyfills for features with widespread native support - Sponsors: Financial support for E18 Foundation ecosystem cleanup work #### WordPress - Core: Review JavaScript dependencies in wp-admin and block editor - Performance: Integrate dependency bloat analysis into performance budgets - Community: Education about dependency management best practices #### OSPO - Software Inventory: Include bloat analysis in SBOM generation - Developer Support: Training on dependency hygiene and modern alternatives - Policy & Governance: Guidelines for dependency selection and maintenance ## ๐Ÿงช Hypotheses - Dependency bloat primarily serves edge cases while imposing costs on mainstream users - Atomic package architecture increases security vulnerabilities without providing reusability benefits - Native browser features adoption could eliminate 80% of current polyfill downloads - Financial incentives could accelerate ecosystem cleanup efforts significantly ### ๐Ÿ“Š Methodology - Weekly download statistics analysis from npm registry - Dependency tree mapping using tools like npm-graph - Native feature support timeline correlation with package usage - Supply chain attack surface measurement by package count ### โ“ Questions - How can package managers better handle version resolution to reduce duplication? - What governance models would prevent niche requirements from becoming ecosystem defaults? - Could bundlers automatically detect and remove unnecessary polyfills based on target environments? ### ๐Ÿ”ฎ Future Research - Automated bloat detection and migration tooling development - Supply chain security impact measurement of atomic package architecture - Developer behavior analysis around dependency selection criteria ### ๐Ÿ’ก Implications - Practice: Regular dependency audits become essential development hygiene - Policy: Package registry governance needs mechanisms to prevent ecosystem-wide bloat - Security: Smaller dependency trees reduce attack surface and maintenance burden - Education: Developers need training on modern JavaScript features and alternatives - Funding: Ecosystem maintenance requires sustainable financial support models ### ๐Ÿง  Learning Styles Assessment Reading level estimate: 12th grade (technical content with clear explanations) #### ๐Ÿ‘€ Visual learners - Present: Dependency tree diagrams, download statistics charts - Improve: Bloat impact visualizations, before/after migration diagrams #### ๐Ÿ”Š Aural learners - Present: Video format with clear narration and examples - Improve: Podcast version focusing on key concepts #### ๐Ÿ—ฃ๏ธ Verbal learners - Present: Clear explanations of technical concepts, real-world analogies - Improve: Glossary of package management terms, comparison frameworks #### ๐Ÿงฉ Kinesthetic learners - Present: Tool demonstrations, CLI command examples - Improve: Hands-on dependency audit workshop, migration checklists #### ๐Ÿง  Logical learners - Present: Systematic categorization of bloat types, cause-effect analysis - Improve: Decision trees for package selection, ROI calculations #### ๐Ÿง‘โ€๐Ÿคโ€๐Ÿง‘ Social learners - Present: Community discussion, collaborative problem-solving - Improve: Dependency review peer groups, shared audit results #### ๐Ÿง˜โ€โ™€๏ธ Solitary learners - Present: Individual analysis tools, self-directed exploration - Improve: Personal dependency hygiene checklists, reflection prompts #### ๐ŸŒฟ Naturalistic learners - Present: Ecosystem health analogies, organic growth patterns - Improve: Environmental impact of code bloat, sustainability metrics ### ๐Ÿ“Š Accessibility Assessment #### Screen reader semantics - Present: Clear heading structure, descriptive text for statistics - Improve: Alt text for dependency diagrams, table headers for package data #### Keyboard navigation - Present: Standard video controls, linked resources accessible - Improve: Skip links for long technical sections, focus indicators #### Contrast and readability - Present: High contrast code examples, clear typography - Improve: Color alternatives for syntax highlighting, increased line spacing #### Text resizing and reflow - Present: Responsive design handles zoom appropriately - Improve: Ensure code blocks remain readable at 200% zoom #### Media and captions - Present: Audio content with clear speech - Improve: Captions for technical terminology, transcript with timestamps #### Forms and interactions - Present: Functional links and navigation - Improve: Clear button labels for tool interfaces ### ๐ŸŒ DEIB Assessment #### Cultural breadth - Present: Technical content accessible globally - Improve: Examples from diverse development contexts, non-US-centric references #### Inclusive language - Present: Gender-neutral technical discussion - Improve: Define technical jargon, avoid cultural idioms #### Neurodiversity support - Present: Clear section breaks, consistent structure - Improve: Executive summaries, visual content organization #### Representation - Present: Focus on technical merit over personalities - Improve: Acknowledge diverse contributor perspectives #### Psychological safety - Present: Constructive criticism of technical choices - Improve: Frame problems as systemic rather than individual blame ### โœ… Logical Validity #### Strong reasoning - Deductive strength: Clear categorization of bloat types with specific examples - Inductive strength: Pattern recognition across multiple package examples - Causal reasoning: Direct connection between niche requirements and ecosystem costs - Analogical strength: Effective comparisons to supply chain and environmental concepts #### Fallacies - Hasty generalization: Some broad claims about "most JavaScript" could use more statistical backing - Appeal to authority: Heavy reliance on single expert opinion, though well-credentialed #### Tone of voice - Overall tone: Passionate but constructive criticism with clear solution focus ### ๐Ÿ›ก๏ธ DARVO Analysis - Deny: No denial patterns present - Attack: No attacks on individuals, focus on systemic issues - Reverse victim/offender: No victim/offender dynamics - Emotional cues and rhetoric: Passionate advocacy for ecosystem health, constructive frustration ## ๐ŸŽฏ Conclusion JavaScript dependency bloat represents a tragedy of the commons where niche requirements impose costs on the entire ecosystem. The path forward requires systematic identification of unnecessary dependencies, migration to modern alternatives, and sustainable funding for maintenance work. The E18 Foundation's cleanup initiative demonstrates that coordinated community effort can address these systemic problems, but success depends on widespread adoption of better dependency hygiene practices and financial support for ecosystem stewardship. ## ๐Ÿงฑ Refactor Appendix ### ๐Ÿ“š Literature Split Pad ### [H1] Legacy compatibility creates ecosystem-wide dependency bloat > [!quote] [A rant about Javascript bloat](https://www.youtube.com/watch?v=1t-k6-m50Fc) by [[Theo - t3.gg]] via [[YouTube]]. Published 2025-01-02. Accessed 2025-01-02. > "The tiny group of people who actually need this stuff should be the ones seeking out special packages for it." Analysis of how Hero Devs and similar legacy maintainers force their requirements onto mainstream packages. [view highlight](https://youtu.be/1t-k6-m50Fc?t=945) #dependency-management #javascript ID:rw_001 ### [H2] Atomic package architecture defeats its own reusability purpose > [!quote] [A rant about Javascript bloat](https://www.youtube.com/watch?v=1t-k6-m50Fc) > "These are separate packages that have no reason to --- ## Full Transcript [00:00] I want to be clear about something.<br>[00:01] JavaScript is far from my favorite<br>[00:02] language. There's a lot of things I like<br>[00:04] about it, but there's a lot that I<br>[00:05] don't. That said, it is almost essential<br>[00:07] because it's one of the few languages<br>[00:08] that's supported everywhere. And I mean<br>[00:10] everywhere. There are some costs to that<br>[00:12] though, and those costs add up, and the<br>[00:15] result often ends up being a lot of<br>[00:17] bloat. Most of the JavaScript that's<br>[00:18] being shipped around the web is almost<br>[00:20] entirely unnecessary. We're talking<br>[00:22] about bloat that just doesn't need to be<br>[00:24] there at all. Some of it's cuz our tools<br>[00:26] are outdated. Some of us is because the<br>[00:27] devs are lazy, but some of it is because<br>[00:29] it made sense at the time and we just<br>[00:31] never took the time to fix it after. And<br>[00:33] the result is a web where most of the<br>[00:35] JavaScript being downloaded isn't<br>[00:37] necessary at all. And that sucks. I<br>[00:39] think it's important for us all to take<br>[00:41] a moment to reflect on this. Why is<br>[00:42] there so much useless JavaScript being<br>[00:44] passed around and what can we do to fix<br>[00:46] it? At the very least, we need to be<br>[00:48] able to identify it. My team just sent<br>[00:49] me a very exciting article from James<br>[00:51] Garbet. The three pillars of JavaScript<br>[00:54] bloat. This is a breakdown of all of the<br>[00:56] different types of bloat that exist in<br>[00:57] our code bases that make it so we end up<br>[01:00] with these giant bundles that are full<br>[01:01] of garbage that nobody needs. If we ever<br>[01:03] want to fix this problem, we need to be<br>[01:05] able to identify it and describe it. And<br>[01:07] there's a lot to dig into there.<br>[01:10] Thankfully, not everything on the web is<br>[01:12] bloat. And one of the things that isn't<br>[01:14] is today's sponsor. I think we all<br>[01:15] understand now that our agents get way<br>[01:17] smarter when they have access to the<br>[01:18] web. But what we usually mean when we<br>[01:19] say that is that they can go to sites<br>[01:21] and get information from them. But if<br>[01:23] you want to do more, if you want to<br>[01:24] actually interact with and navigate the<br>[01:25] web, you need a browser for your agents<br>[01:27] to use. Today's sponsor is Browserbase,<br>[01:28] and they're here to give you the best<br>[01:30] possible experience for building with<br>[01:31] agents and the web. A few days ago, Ben<br>[01:33] was mad at me and he was threatening to<br>[01:34] leave SF, so he built an app using<br>[01:36] Browserbase to give him the best flight<br>[01:38] deals for leaving to go to LA. But<br>[01:39] there's something very interesting here<br>[01:41] that is a new thing as of GPT 5.4. We<br>[01:44] have two versions of this project. We<br>[01:45] have the traditional browser use version<br>[01:47] where it uses browser use primitives to<br>[01:49] trigger clicks and keyboard presses and<br>[01:51] all of those things, but 5.4 was trained<br>[01:53] with a new capability, the ability to<br>[01:55] write JavaScript that is meant to<br>[01:57] execute on the page to fake these<br>[01:59] interactions. And it turns out it's way<br>[02:01] more accurate and way faster. I just<br>[02:02] launched the app and thanks to browser<br>[02:04] base, you can actually watch as the<br>[02:06] browser is used throughout the whole<br>[02:08] process. Here we see it going to the<br>[02:10] flight tracker. It is already<br>[02:11] interacting with the page and we can see<br>[02:12] in the logs in our app what's going on<br>[02:14] and what it is doing. And here we see<br>[02:16] the code that it is writing to execute<br>[02:18] on the page. Pretty cool that it finds<br>[02:20] the button, selects the right button<br>[02:22] from that list, waits for the timeout<br>[02:23] for the focus from the click, and then<br>[02:25] does the next steps. And it's wild to<br>[02:28] watch. For my experience, the JavaScript<br>[02:29] execution method has been so much more<br>[02:32] reliable that I personally went from,<br>[02:34] yeah, I guess this isn't really for me<br>[02:35] to, yeah, I want to start using browser<br>[02:38] use type stuff. These types of tasks<br>[02:39] used to take minutes and now they take<br>[02:41] seconds. If you want your agents to<br>[02:43] really use the web, look no further than<br>[02:44] soyb.link/browserbase.<br>[02:46] I'm actually really, really excited to<br>[02:47] go through this article with you guys.<br>[02:49] Shout out to James, the author. He works<br>[02:51] really hard on ecosystem performance<br>[02:53] things, just trying to make our<br>[02:54] JavaScript ecosystem better. That's why<br>[02:56] he's so involved with things like unjs<br>[02:58] and all these other cool projects, as<br>[02:59] well as npmxdev, which is a really cool<br>[03:01] new like npm registry viewer tool.<br>[03:03] Choked is essential for a shitload of<br>[03:05] stuff that I do. This is the package<br>[03:07] that is used for tracking what changes<br>[03:09] are happening on your file system in<br>[03:10] node for things like hot reloading and<br>[03:12] he's an active contributor to it. It is<br>[03:14] rare that one dev touches that many<br>[03:16] different things in the open source<br>[03:17] world. So very excited to see his<br>[03:19] thoughts here. He knows this [ย __ย ] better<br>[03:20] than almost anyone. Three pillars of JS<br>[03:22] bloat. Over the last couple years, we've<br>[03:24] seen a significant growth of the E18<br>[03:25] community and a rise in performance<br>[03:27] focused contributions because of it. A<br>[03:29] large part of this is the cleanup<br>[03:30] initiative where the community has been<br>[03:32] pruning packages which are redundant,<br>[03:34] outdated or unmaintained. One of the<br>[03:36] most common topics that comes up as part<br>[03:37] of this is dependency bloat. The idea<br>[03:39] that mpm dependency trees are getting<br>[03:41] larger over time, often with long since<br>[03:43] redundant code which the platforms now<br>[03:46] provide natively. In this post, James<br>[03:48] wants to briefly look at what he thinks<br>[03:50] are the three main types of bloat in our<br>[03:51] depth trees, why they exist, and how we<br>[03:53] can start to address them. I couldn't be<br>[03:55] more excited for this one. This is one<br>[03:56] of those few people that like really<br>[03:58] knows what they're doing here. Oh [ย __ย ]<br>[03:59] one of my chatters has actually just<br>[04:01] joined E18 today. That's really cool to<br>[04:04] see. First piece and this is important.<br>[04:05] Older runtime support with safety and<br>[04:08] realms. What the hell is a realm? We'll<br>[04:09] know in a moment. Here's an example<br>[04:11] graph they have. There's the is string<br>[04:13] package. Is string checks has to string<br>[04:16] tag which has a dependency on has<br>[04:18] symbols. It also has a dep on call bound<br>[04:21] which has get intrinsic which has a<br>[04:23] shitload of additional subpackages. A<br>[04:25] handful of which touch call bind apply<br>[04:27] helpers and those touch function bind<br>[04:30] and ES errors. So yeah, quite a<br>[04:32] dependency tree for is string. Graphs<br>[04:34] like this are a common site in many npm<br>[04:36] dependency trees. A small utility<br>[04:38] function for something which seems like<br>[04:39] it should be natively available followed<br>[04:41] by many similarly small deep<br>[04:43] dependencies. So why is this a thing?<br>[04:45] Why do we need is string instead of type<br>[04:47] of checks? Why do we need has own<br>[04:49] instead of object or object.prototype<br>[04:52] hashazone property? Well, there's three<br>[04:54] things. First, there is support for very<br>[04:55] old engines. Second, there's protection<br>[04:57] against global namespace mutation.<br>[04:59] Third, and most importantly, there's<br>[05:00] crossrem values. Oh boy. First, we have<br>[05:04] the support for old engines. Somewhere<br>[05:06] in the world, some people are apparently<br>[05:07] exist who need to support ES3, like<br>[05:10] Internet Explorer 6 and 7 or extremely<br>[05:12] early versions of Node. Fun fact about<br>[05:14] this. Curious what he links as a<br>[05:16] footnote here. He says that he believes<br>[05:18] there are people who need these old<br>[05:19] engines, but he would love to see<br>[05:20] examples. There's actually a company<br>[05:22] that does this. They're named Hero Devs.<br>[05:24] They have what I would consider some of<br>[05:26] the most thankless work in the industry.<br>[05:28] Their job is to come in as contractors<br>[05:31] at companies that have old ancient<br>[05:33] terribly maintained and structured code<br>[05:35] bases that none of the engineers at the<br>[05:37] company want to work on. If they even<br>[05:38] have engineers there, they maintain<br>[05:40] these old endof life projects as well as<br>[05:42] their dependencies. They have forks of<br>[05:45] things like NodeJS 0.8 that bring in<br>[05:48] security fixes while still having the<br>[05:50] weird [ย __ย ] that the company needs<br>[05:51] for the old version of Node. They also<br>[05:53] will often have to change packages and<br>[05:55] fork them and maintain them themselves<br>[05:57] in order to keep them compatible with<br>[05:58] old versions of node. This has even<br>[06:00] burned some people in the past where<br>[06:01] they took over a poorly maintained repo<br>[06:04] that had a dependency that was being<br>[06:05] used by spelt and when they modified it,<br>[06:08] they wanted it to work for these really<br>[06:10] old things. So they took a package that<br>[06:12] had no dependencies and they ended up<br>[06:14] adding different things that they had<br>[06:16] made in order to let it support old<br>[06:19] ancient unmaintained versions of node.<br>[06:21] But that resulted in a package that used<br>[06:22] to be a single small dependency in<br>[06:24] speltkit becoming like 20 subd<br>[06:26] dependencies. Rich Harris flipped a<br>[06:28] [ย __ย ] And that was the first time a lot<br>[06:29] of people saw the type of work that<br>[06:31] these devs have to do. I know a couple<br>[06:33] employees at this company, they live in<br>[06:35] the shadows. They like development, the<br>[06:37] science more than the ecosystem. My<br>[06:40] friend who told me when they were going<br>[06:41] to start working there that they were<br>[06:43] interested. I was like, "Oh, you're not<br>[06:44] even like you're joking, right? Like<br>[06:46] there's no way you'd actually want to do<br>[06:47] that type of work." And they were like,<br>[06:48] "No, I love this stuff. I love these<br>[06:50] hard, thankless problems that nobody<br>[06:52] thinks about. Kind of nuts. Yeah, these<br>[06:54] people do actually exist. And to James,<br>[06:56] who seems to not know any of them<br>[06:57] according to his footnote, they are the<br>[06:59] ones you need to talk to if you want<br>[07:00] examples of people using these really<br>[07:02] old things that have this crazy set of<br>[07:05] weird dependencies that aren't needed in<br>[07:08] most places. It's all them. There's a<br>[07:10] bunch of things that we take for granted<br>[07:11] in modern JavaScript that just don't<br>[07:13] exist in these old places. For example,<br>[07:15] for each on arrays or reduce on arrays<br>[07:18] or object.keys. keys, which I use all of<br>[07:20] the [ย __ย ] time, or object. I use some<br>[07:23] of the time. I do not know how I would<br>[07:24] write JS without these. These are all<br>[07:26] ES5 features, meaning they simply don't<br>[07:28] exist in ES3 engines. For those<br>[07:30] unfortunate souls who are still running<br>[07:32] old engines, they need to reimplement<br>[07:33] everything themselves or be provided<br>[07:35] with polyfills. Alternatively, it'd be<br>[07:36] really nice if they just upgraded.<br>[07:38] Totally agree there. Protection against<br>[07:40] global namespace mutation. The second<br>[07:42] reason for some of these packages is<br>[07:44] safety in quotes. Basically, inside of<br>[07:46] node itself, there's a concept of<br>[07:48] primordials. These are essentially just<br>[07:50] global objects wrapped at startup and<br>[07:52] imported by node from then on to avoid<br>[07:54] node itself being broken by someone<br>[07:56] mutating the global namespace. For<br>[07:58] example, if node itself uses map and we<br>[08:00] redefine what map is, we can break node.<br>[08:03] To avoid this, node keeps a reference to<br>[08:05] those original versions of things like<br>[08:06] map which it imports rather than<br>[08:08] accessing the global. They have a whole<br>[08:10] section about this in the repo. This is<br>[08:13] fascinating. I did not know about this<br>[08:14] that Node rebinds all of the default<br>[08:17] globals in a custom name space early so<br>[08:19] that they can use them without your<br>[08:21] [ย __ย ] overriding them. Fascinating.<br>[08:23] This also makes a ton of sense as an<br>[08:24] engine because it shouldn't break if<br>[08:26] somebody overrides some core [ย __ย ]<br>[08:28] Good stuff. As always, the Node project<br>[08:30] is underappreciated for the level of<br>[08:32] complexity that they're operating<br>[08:33] within. Like Node and V8 are two of the<br>[08:35] most crazy complex, generous gifts to<br>[08:38] the software development world that get<br>[08:40] treated like [ย __ย ] because people just<br>[08:41] hate on JavaScript. always has annoyed<br>[08:43] me, even back when I hated JS. Okay,<br>[08:45] last time I hated JS was like the last<br>[08:46] time I had to write JS to be fair, but<br>[08:48] you you get what I mean. Apparently,<br>[08:49] there are some maintainers that believe<br>[08:50] this is the correct way to build<br>[08:51] packages, too. That's why we have<br>[08:53] dependencies like math intrinsics in the<br>[08:55] graph above, which is just a reexport of<br>[08:57] the various math.star functions in order<br>[08:59] to avoid them being mutated. What? Yep,<br>[09:02] math intrinsics. All that package does<br>[09:04] is reexports the default so if they get<br>[09:06] overridden, you can still rely on them.<br>[09:07] That is obnoxious. And now we get into<br>[09:09] realms crossrem values. This is what<br>[09:12] happens when you want to pass things<br>[09:13] from web pages to iframes and stuff like<br>[09:16] that. In this situation, a new reax in<br>[09:18] an iframe is not the same thing as a<br>[09:20] reax class as one of the parent pages.<br>[09:23] So if you make a reax inside of a page<br>[09:25] and you make a different one inside of<br>[09:26] the iframe, they don't match. So if you<br>[09:29] do something like trying to compare the<br>[09:31] window.reax versus iframe window.reax,<br>[09:33] the values are different and that would<br>[09:35] end up being false if it came from the<br>[09:37] iframe. For example, he's a maintainer<br>[09:38] of chai and we have this exact issue. We<br>[09:41] need to support assertions happening<br>[09:42] across realms. This test runner may run<br>[09:44] tests in a VM or even in an iframe. So<br>[09:46] we can't rely on instance of checks. For<br>[09:48] that reason, we have to use<br>[09:49] object.prototype.2string.all<br>[09:52] val equals object reax to check if<br>[09:55] something's a reax, which works across<br>[09:56] realms. It doesn't rely on the<br>[09:58] constructor. Apparently, it's the same<br>[09:59] thing that is string does because if you<br>[10:01] pass a new string from one realm to<br>[10:03] another, you might not be able to check<br>[10:05] against the global like window string<br>[10:06] because it's a different type because it<br>[10:08] came from a different realm. God, I<br>[10:10] people don't appreciate how hardJS can<br>[10:11] be at these levels. I don't know about<br>[10:13] you guys, I've never had to deal with<br>[10:14] this myself. I've never had to worry<br>[10:16] about what happens if I pass a value in<br>[10:18] out of an iframe and I can't do instance<br>[10:20] of calls on it. That's very different<br>[10:21] from the world I live in personally. I<br>[10:23] like this call out here. All of this<br>[10:24] makes sense for a very small group of<br>[10:26] people. If you're stuck supporting very<br>[10:27] old engines, passing values across<br>[10:29] realms, or you want protection from<br>[10:30] someone mutating the environment, these<br>[10:32] packages are exactly what you need.<br>[10:34] Problem is that the vast majority of us<br>[10:36] don't need any of this. We're running<br>[10:37] modern versions of node that were and by<br>[10:39] modern I mean the last 10 years or we're<br>[10:41] using an evergreen browser that gets<br>[10:42] automatically updated. We don't need to<br>[10:44] support prees5 environments. We don't<br>[10:47] pass values across frames and we<br>[10:48] uninstall packages that break the<br>[10:50] environment. Yes, mostly again hero<br>[10:53] devs. Yeah, these layers of niche<br>[10:55] compatibility somehow made their way<br>[10:57] into the hot path of everyday packages.<br>[11:00] The tiny group of people who actually<br>[11:01] need the stuff should be the ones<br>[11:03] seeking out special packages for it.<br>[11:04] Instead, it is reversed and we all pay<br>[11:06] the cost. Exactly. Thank you to the<br>[11:09] chatters and begrudgingly, thank you to<br>[11:11] Grock for the help finding this example<br>[11:13] from way back. The AX object query<br>[11:16] package, which is used by a bunch of<br>[11:17] things for programmatic detection of<br>[11:20] accessibility issues. It originally had<br>[11:22] almost no dependencies and a different<br>[11:24] developer had just come in to take over<br>[11:26] the project because it wasn't being<br>[11:27] maintained by the original devs anymore.<br>[11:29] they agreed to let him take it over. And<br>[11:30] when he did, he immediately focused on<br>[11:32] backward compatibility maxing, which he<br>[11:35] did by fundamentally changing the<br>[11:37] structure of the dependencies. And here<br>[11:39] you can see they added a bunch of<br>[11:41] additional dependencies that largely<br>[11:43] came from that team in order to try and<br>[11:45] make back compat with really old<br>[11:47] versions of node possible. This change<br>[11:49] pissed off so many people and confused<br>[11:51] them so much they thought it was a<br>[11:52] supply chain attack. Most devs had just<br>[11:55] never seen this type of back<br>[11:57] compatibility being added to a project.<br>[11:59] And it looked like this too since the<br>[12:01] dev LJ Harb was the one who built most<br>[12:03] of the subd dependencies that were added<br>[12:05] because again remember it is his job to<br>[12:08] maintain these ancient code bases and<br>[12:10] build all of the key pieces that are<br>[12:12] needed for things to work in stuff like<br>[12:14] old node 0.4 projects. That said, Sam<br>[12:17] was entirely wrong here. This was not a<br>[12:20] supply chain attack under the guise of<br>[12:22] supporting node 0.4. for nobody would do<br>[12:24] a supply chain attack with something<br>[12:25] that's that obviously stupid. They would<br>[12:27] do it with something that seems more<br>[12:29] promising like performance improvements.<br>[12:31] Nobody would ever do anything under this<br>[12:33] cuz this is not something anyone would<br>[12:35] want to merge. This is something that<br>[12:36] they're doing because they have to<br>[12:38] maintain these old code bases and that's<br>[12:39] the easiest path they've had. My problem<br>[12:41] with her devs and I have told this to<br>[12:43] the people who I know there is that they<br>[12:45] treat these core dependencies as though<br>[12:48] they have to support everything. They<br>[12:50] treat these core dependencies as the<br>[12:52] path to get that legacy support into<br>[12:54] their things, not even through custom<br>[12:56] versions of the packages, but through<br>[12:58] forcing the main versions of these<br>[13:00] packages to continue to be compatible<br>[13:02] with these ancient versions of things.<br>[13:04] And the result is a bunch of unnecessary<br>[13:06] bloat. It's worth noting that of those<br>[13:08] 60 new direct dependencies that were<br>[13:10] added, one of them, which is deep equal,<br>[13:12] which is necessary when using ancient<br>[13:13] versions of node for comparisons of<br>[13:15] things, added 50 by itself. This nearly<br>[13:18] doubled the number of packages that were<br>[13:20] necessary to install SpeltKit. And the<br>[13:22] Spelt team was [ย __ย ] pissed, as they<br>[13:25] should be. It's kind of crazy that a<br>[13:27] minor version bump of something that<br>[13:28] you're already using can suddenly double<br>[13:30] the number of dependencies that you have<br>[13:32] in your codebase. Again, I want to<br>[13:34] emphasize just how thankless this work<br>[13:36] is, but also that I don't think it is<br>[13:38] appropriate for the Hero Devs team to<br>[13:40] effectively be forcing their unique<br>[13:43] needs onto the default path for other<br>[13:46] devs. These things are so uncommon that<br>[13:48] they probably need to be in either other<br>[13:50] custom branches or tags or ideally even<br>[13:52] a fork with a different name for<br>[13:54] maintaining these old versions of the<br>[13:55] packages. That was all just for the<br>[13:58] first pillar. By the way, we got two<br>[14:00] more other separate things that can<br>[14:02] cause bloat. Thankfully, these ones are<br>[14:04] a little bit simpler. The next is atomic<br>[14:06] architecture. Some folks believe that<br>[14:08] packages should be broken up to an<br>[14:10] almost atomic level creating a<br>[14:12] collection of small building blocks<br>[14:13] which later can be reused to build other<br>[14:15] higher level things. So you end up with<br>[14:17] graphs like this one where you have exec<br>[14:19] a which has a couple subdevs like<br>[14:21] cinders merge streams cross spawn which<br>[14:23] depends on which path key shebang<br>[14:24] command shebang reax etc because all of<br>[14:27] these are really simple things like<br>[14:29] shebang reax a very simple reax for<br>[14:31] checking if it's a shebang or not is exe<br>[14:34] what that does get stream has its own<br>[14:36] separate readable stream implementation<br>[14:37] it references as well as an is stream<br>[14:39] function instead of just having them<br>[14:40] inside you get the idea when there's a<br>[14:43] part that is reusable it is broken out<br>[14:44] to be reusable Although it's funny, I<br>[14:47] just referenced the shebang reax one and<br>[14:50] then that's the example the author gives<br>[14:52] too. This is a package that is a package<br>[14:54] that is downloaded 133 million times a<br>[14:57] week. Do you understand how absurd that<br>[14:59] is? Two lines of code that there are<br>[15:02] four versions of four majors that are<br>[15:04] downloaded 133 million times a week. Two<br>[15:08] lines of code. It's a reax. It's a reax<br>[15:10] and an export. You might start to be<br>[15:12] thinking we did this to ourselves. And<br>[15:14] you know what? I think we did. By<br>[15:17] splitting code up to this atomic level,<br>[15:19] the theory is that we can then create<br>[15:20] higher level packages simply by joining<br>[15:22] the dots. I get this. I am a big fan of<br>[15:25] the Unix philosophy myself. But uh Unix<br>[15:28] philosophy should not be at a line of<br>[15:29] code level. Here are some common<br>[15:31] examples and I'm going to check how<br>[15:32] popular these are in npmjs as we go<br>[15:35] through. We have rfi which converts a<br>[15:36] value to an array. If it's an array,<br>[15:38] then we return the array. If not, then<br>[15:40] we return it with an array wrapper. It's<br>[15:42] one line of code. And this package is<br>[15:44] downloaded<br>[15:46] 32 million times a week. Next, we have<br>[15:49] slash, which replaces backslashes and<br>[15:51] file system paths with traditional<br>[15:53] slashes. This package is downloaded,<br>[15:56] wait for it,<br>[15:58] 96 million times a week. We got CLI<br>[16:01] boxes, which is a JSON file containing<br>[16:03] the edges of a box 40 million times a<br>[16:06] week. It literally is just a JSON blob<br>[16:09] with top left character, top character,<br>[16:12] top right, right, bottom right, bottom,<br>[16:14] bottom left, left. 40 million times a<br>[16:16] week. It's a JSON file. I'm going to<br>[16:18] die. I knew it was bad. I did not know<br>[16:19] it was this bad. Oh, path key. I've used<br>[16:22] this one. I've used this one. Oh no. How<br>[16:26] popular is this?<br>[16:29] 158 million times a week. It's a 4<br>[16:32] kilobyte of JS file. It is literally<br>[16:35] just a file. Let's look at the JS for<br>[16:38] it. If platform is not wind32, return<br>[16:41] path. Otherwise, we have to go steal the<br>[16:43] path in Windows because Windows has a<br>[16:45] lowercase path.<br>[16:48] I can't believe the world we're in. We<br>[16:50] did this to ourselves.<br>[16:53] Today's sponsor is all about hiring. If<br>[16:55] you need great engineers, look no<br>[16:56] further than G2. That's not G2I. That's<br>[16:59] the AI engineer conference in Miami.<br>[17:02] Yeah, I kind of tricked you guys. G2I<br>[17:04] does a lot more than just hiring. They<br>[17:05] run some of my favorite tech events.<br>[17:07] I've been going to React Miami for three<br>[17:08] years now, and it's consistently my<br>[17:10] favorite tech conference every year.<br>[17:12] They are still doing React Miami. In<br>[17:13] fact, it's right afterwards. If you want<br>[17:14] to hang out with cool engineers like me,<br>[17:16] Prime, and all the other awesome folks<br>[17:17] who show up for this stuff, I highly<br>[17:18] recommend checking out the AI engineer<br>[17:20] World Fair in Miami as well as React<br>[17:22] Miami from April 20th to 24th. If you<br>[17:24] don't have the time for a conference,<br>[17:25] it's probably because you need to hire<br>[17:26] more. And if you do, I highly recommend<br>[17:28] hiring at soy.<br>[17:30] Chat made a good call out. The dev who<br>[17:33] wrote this article is also working on<br>[17:34] npmx, so I should definitely be using<br>[17:36] that for these searches. It's a lot<br>[17:37] quicker when I search one time, which<br>[17:39] ensures a function is only called once,<br>[17:41] which is 131 million downloads a week.<br>[17:46] And it's once again Cinder. Poor Cinder<br>[17:49] has had to write so much random [ย __ย ]<br>[17:51] that we all rely on. He wrote Kai, which<br>[17:53] is still my favorite fetch rapper, as<br>[17:55] well as a ton of these thankless small<br>[17:58] projects that are necessaryish when you<br>[18:00] want to reuse things and have them be<br>[18:02] simpler. Kind of h a lot of respect for<br>[18:05] the work he does. I rely on so much of<br>[18:06] his [ย __ย ] regularly, but some of these<br>[18:08] things it hurts that they exist. Oh,<br>[18:11] this is cool. String width. This is how<br>[18:13] long the string actually is, not just<br>[18:16] how long the binary is. Thankfully, this<br>[18:19] one's relatively small for what it is.<br>[18:21] And it's actually kind of annoying to do<br>[18:23] this, right? Because like is a character<br>[18:24] like this is one care, but it is<br>[18:27] actually longer when you print it. And<br>[18:29] if you put a bunch of these tags around<br>[18:31] it, it's still only two cares long. And<br>[18:33] string width handles it. That's actually<br>[18:35] a good example of a thing that's kind of<br>[18:36] annoying to calculate and do, right?<br>[18:38] Especially with emojis and [ย __ย ] Yeah.<br>[18:40] One of the cool things I didn't realize<br>[18:42] on the site is that npmx will show you<br>[18:44] the total downloads per week of<br>[18:45] someone's packages. and his packages are<br>[18:47] downloaded almost 10 billion times per<br>[18:49] week. That is insane. Oh god, how<br>[18:53] popular is Windows? Okay, it's only 27<br>[18:55] mil. It's not as bad as some of the<br>[18:57] others, but you get the idea. These are<br>[18:58] all very, very, very, very, very, very<br>[19:01] popular packages. Absurdly. So, you want<br>[19:04] to build a new CLI, for example, you can<br>[19:05] pull a few of these in and not worry<br>[19:07] about implementation. You don't need to<br>[19:09] do env path or envase<br>[19:12] path or cells. You can just pull a<br>[19:13] package for that. Great. I actually have<br>[19:15] a whole video about why I think<br>[19:16] libraries are kind of dying as a result<br>[19:17] of vibe coding. It's really cool that<br>[19:19] it's a lot easier to write this solution<br>[19:21] than it ever was before because AI will<br>[19:23] know this mistake or at the very least<br>[19:25] find the package and hopefully read the<br>[19:26] code and realize it shouldn't be using<br>[19:28] it. TBD, but you get the idea. So why is<br>[19:30] this a problem? In reality, most or all<br>[19:33] of these packages did not end up as the<br>[19:35] reusable building blocks they were meant<br>[19:36] to be. They're either largely duplicated<br>[19:38] across various versions in a wider tree<br>[19:40] or they're single-use packages which<br>[19:41] only one other package uses. For<br>[19:44] example, shebang reax it's almost solely<br>[19:46] used by shebang command which is by the<br>[19:48] same maintainer. CLI boxes is used<br>[19:50] almost solely by boxin and ink also both<br>[19:53] by the same maintainer. One time is used<br>[19:55] almost solely by restore cursor which is<br>[19:56] again the same maintainer. These are<br>[19:58] separate packages that have no reason to<br>[20:00] be separate packages. Each of these<br>[20:02] having only one consumer means they are<br>[20:04] equivalent of inline code but cost us<br>[20:06] more to acquire because of npm requests,<br>[20:08] tar extraction, bandwidth, etc. Yep. If<br>[20:11] three different things you used required<br>[20:12] shebang reax, having it as a single<br>[20:14] shared package could theoretically make<br>[20:16] sense. The fact that it's one line makes<br>[20:17] it less so, but hypothetically speaking,<br>[20:20] but that's not the case. This is just<br>[20:21] dumb. And then we have the duplication<br>[20:23] problem. Taking a look at the Nux<br>[20:24] dependency tree, we can see a few of<br>[20:26] these building blocks that are<br>[20:27] duplicated because they have two<br>[20:28] different versions of the same thing.<br>[20:30] Another fun problem. There's two<br>[20:32] versions of his Docker. There's two<br>[20:33] versions of his stream. There's two of<br>[20:35] is Windows Subsystem for Linux. There's<br>[20:36] two of his exe two of npm run path two<br>[20:39] of path key and two of path scurry<br>[20:41] that's because they have packages that<br>[20:42] they're relying on that both rely on is<br>[20:45] docker or is stream and they rely on<br>[20:46] different versions so you end up with<br>[20:48] two versions of the same thing<br>[20:51] inlining these does not mean we no<br>[20:52] longer duplicate the code but it does<br>[20:54] mean we don't pay the cost of things<br>[20:55] like version resolution conflicts cost<br>[20:57] of acquisition etcing makes duplication<br>[21:00] almost free while packaging makes it<br>[21:02] expensive yep entirely correct and one<br>[21:04] of the biggest issues especially<br>[21:06] recently is the larger supply chain<br>[21:08] surface area makes it easier to attack<br>[21:11] and hijack people's [ย __ย ] It's so common<br>[21:13] that people now speculate that when<br>[21:15] somebody is trying to make something<br>[21:16] work in older projects that it is a<br>[21:17] supply chain attack because we just<br>[21:19] expect this now. The more packages you<br>[21:21] have, the larger the supply chain<br>[21:22] surface area is. Every package is a<br>[21:24] potential point of failure for<br>[21:26] maintenance, security, and so on. For<br>[21:28] example, a maintainer of many of these<br>[21:29] packages was compromised last year. This<br>[21:31] meant that hundreds of tiny building<br>[21:33] blocks were compromised, which meant<br>[21:34] that the higher level packages we<br>[21:36] actually install were also compromised.<br>[21:38] Logic as simple as array.isarray<br>[21:40] probably doesn't need to be its own<br>[21:42] package. Security, maintenance, and so<br>[21:44] on. It can just be inlined and we can<br>[21:46] avoid the risk of it being compromised.<br>[21:48] Absolutely agree. Similar to the first<br>[21:50] pillar, which is the older runtime<br>[21:51] support, this ended up being a thing<br>[21:53] that made its way into the general hot<br>[21:56] path. So, the thing most people do<br>[21:58] happens to now involve this. Even though<br>[21:59] these are more conceptually good things<br>[22:01] that are useful in niche specific<br>[22:03] places, it became the thing we're all<br>[22:05] doing whenever we install [ย __ย ] And the<br>[22:07] result is that we all have to pay this<br>[22:09] cost without getting any benefit<br>[22:10] ourselves. I'm going to turn off the<br>[22:12] dark mode for a sec. So, uh, prepare<br>[22:14] your eyes. It just happened to break<br>[22:16] this particular view because canvases<br>[22:18] are hard. This is the pony fills<br>[22:20] section. Pony fills that overstayed<br>[22:22] their welcome. There's a lot of things<br>[22:23] in here that were really useful in 2010<br>[22:26] like is array that still gets 160<br>[22:28] million installs a week or object.keys<br>[22:31] or string prototype trim that are way<br>[22:32] too popular and these dates by the way<br>[22:34] are effectively when the native support<br>[22:36] occurred. So in 2010 all these things<br>[22:38] became common in JS package are still<br>[22:40] huge is nan got built in in 2013 package<br>[22:43] still gets millions of installs a week.<br>[22:44] array prototype fine, string prototype,<br>[22:46] repeat, object sign, you get the idea.<br>[22:48] All of these features that have been in<br>[22:49] JavaScript for 15 plus years for some of<br>[22:53] them still have packages being installed<br>[22:55] that are entirely unnecessary. If you<br>[22:57] were looking away because of the lack of<br>[22:58] dark mode, you can look back now. You're<br>[23:00] building an app, you might want to use<br>[23:01] some future features that your chosen<br>[23:02] engine doesn't support yet. In that<br>[23:04] situation, a polyfill can come in handy.<br>[23:06] For all of you guys who really wanted<br>[23:08] temporal, you've probably been using a<br>[23:09] polyfill for a while now. Polyfills<br>[23:11] provide fallback implementations where<br>[23:12] the feature should be so you can use it<br>[23:14] as if it was natively supported. Very<br>[23:16] very cool thing. Typescript used to even<br>[23:18] introduce certain polyfills for things<br>[23:20] themselves so that features that most<br>[23:22] people wanted especially TypeScript<br>[23:23] focused ones could be in early so you<br>[23:25] could have access to them. Generally, I<br>[23:27] think that's an okay to good pattern.<br>[23:29] For example, temporal polyfill will<br>[23:31] polyfill the new temporal API so you can<br>[23:33] use it regardless of if the engine<br>[23:34] supports it or not. I swear when I<br>[23:36] started doing JavaScript heavily back in<br>[23:38] 2018, we were still talking about how<br>[23:40] exciting temporal was. It's just<br>[23:41] starting to ship now 8 years later,<br>[23:42] which is kind of crazy. And here we are.<br>[23:44] You're building a library instead. What<br>[23:46] should you do? In general, no library<br>[23:49] should load a polyfill as that is a<br>[23:51] consumer's concern and the library<br>[23:52] should not be mutating the environment<br>[23:54] around it. Again, polyfills add things<br>[23:56] to like globals so they will work in<br>[23:59] your environment. If you are personally<br>[24:01] writing code in your project that's<br>[24:03] userfacing and you want temporal, go<br>[24:06] install the polyfill. That's totally<br>[24:07] kind. It's a top level depth that makes<br>[24:08] sense. Polyfills sneaking in through<br>[24:10] other things makes way less sense.<br>[24:13] Thankfully, there are very few projects<br>[24:14] that do that that bring in a polyfill<br>[24:16] that can [ย __ย ] up your environment.<br>[24:18] There's a lot of devs who wanted that<br>[24:19] and I can sympathize here. There's a lot<br>[24:21] of devs that are using features that<br>[24:22] might be kind of new in their packages<br>[24:24] and those features are probably causing<br>[24:25] bugs for a lot of their users. The users<br>[24:28] being developers implementing them. So<br>[24:30] if you made a package that uses temporal<br>[24:32] person installs that package and it<br>[24:34] breaks because they don't have temporal<br>[24:35] installed, you're probably tired of<br>[24:36] telling all of them, make sure you<br>[24:37] install the polyfill, make sure you<br>[24:39] install the polyfill. So the solution<br>[24:40] for this is called a pony fill. It's<br>[24:42] kind of like a polyfill, but it gives<br>[24:44] you a different import path. So instead<br>[24:45] of changing the runtime, instead of<br>[24:47] binding things to globals, it just lets<br>[24:48] you import a fake temporal that you can<br>[24:51] call directly instead. I can absolutely<br>[24:53] sympathize with this cuz I had a lot of<br>[24:54] weird problems when I was maintaining<br>[24:56] projects at Twitch. There's only an<br>[24:57] internal dashboard for managing reports<br>[24:59] when users report people on Twitch. And<br>[25:01] almost all of the safety ops people that<br>[25:02] actually went through those reports were<br>[25:04] using Chrome, as were the devs.<br>[25:06] Everything worked great in Chrome. If<br>[25:08] you ever wonder where my disdain for<br>[25:10] Firefox started, it was then, because we<br>[25:12] had one single person who really wanted<br>[25:15] to use Firefox, and the amount of random<br>[25:17] [ย __ย ] that broke was horrifying.<br>[25:20] Backwards reax just wasn't supported.<br>[25:23] And it didn't even give good errors when<br>[25:24] you tried. That meant I had to polyfill<br>[25:27] reax for Firefox. Yes, really.<br>[25:31] This is the world we live in. Pony fills<br>[25:33] are basically polyfills that you import<br>[25:35] rather than mutating the environment.<br>[25:37] This kind of works since it means a<br>[25:38] library can use future tech by importing<br>[25:40] an implementation and it can pass that<br>[25:42] around so it can use the native one if<br>[25:44] it needs to, if it exists. Otherwise,<br>[25:46] it'll use its pony fill otherwise. None<br>[25:48] of this mutates the environment, so it's<br>[25:49] safe. So, why is this a problem? It<br>[25:51] seems fine if they're not mutating the<br>[25:53] environment, right? Well, the code's<br>[25:54] still there. These pony fills did their<br>[25:56] job at the time. They allowed library<br>[25:57] authors to use future tech without<br>[25:58] mutating your environment and without<br>[26:00] forcing consumers to know what polyfills<br>[26:02] they have to install. Problem comes with<br>[26:03] the pony fills when they outstay their<br>[26:05] welcome. When the feature they fill in<br>[26:07] for is now supported by all major<br>[26:09] engines that we care about, the pony<br>[26:10] fill should be removed. However, this<br>[26:12] often doesn't happen and the pony fill<br>[26:14] remains in place long after it's needed.<br>[26:17] We're now left with many, many packages<br>[26:19] which rely on pony fills for features<br>[26:21] we've all had for a decade or more,<br>[26:23] including global this because global<br>[26:24] this didn't used to exist, but it's been<br>[26:26] widely supported since 2019. The<br>[26:28] globalist package still gets 49 million<br>[26:30] downloads a week. Or index of, are you<br>[26:32] kidding? That's been supported since<br>[26:34] 2010 and it still gets 2.3 million<br>[26:36] downloads a week. And then object<br>[26:38] entries, which has been supported since<br>[26:40] 2017, still getting 35 million downloads<br>[26:42] a week. Unless these packages are being<br>[26:44] kept alive because of pillar one, which<br>[26:46] is the support for the old things,<br>[26:48] they're usually still just used because<br>[26:50] nobody ever thought to remove them. When<br>[26:52] all long-term support versions of<br>[26:53] engines have a feature, the pony fill<br>[26:55] should definitely be removed. Absolutely<br>[26:57] agree. Oh boy, the index of package. The<br>[26:59] description is great. Lame index of<br>[27:01] thing. Thanks, Microsoft. This clearly<br>[27:03] was only built to support Internet<br>[27:05] Explorer at the time. We look at the<br>[27:07] code, the very complex code. If index of<br>[27:10] does exist in your runtime, which is<br>[27:11] checked with the empty array index of,<br>[27:13] if it exists, we just use the<br>[27:15] array.index of that you passed looking<br>[27:17] for the object. And if it doesn't, then<br>[27:18] we for loop across it to get you the<br>[27:20] index. This is 10 lines of code that are<br>[27:23] downloaded millions of times a week that<br>[27:25] aren't only stupid and easy to write,<br>[27:28] they're entirely unnecessary. The author<br>[27:30] of this package is TJ, who is the<br>[27:33] creator of Express, who left JavaScript<br>[27:35] a decade ago. Dogpaw and Steven are<br>[27:37] helping a ton here. Thank you both, by<br>[27:39] the way. Huge shout out to you guys for<br>[27:41] making sure I get all the fun facts in<br>[27:43] this one. So, now the most important<br>[27:45] part. What can we do about all of this?<br>[27:47] Much of this bloat is so deeply nested<br>[27:49] in dependency trees today that it's a<br>[27:50] fairly hefty task to unravel it all and<br>[27:53] get to a good place. It will take time<br>[27:54] and it will take a lot of effort for<br>[27:56] both maintainers and the consumers of<br>[27:57] these libraries. Having said that, I do<br>[27:59] think we can make significant progress<br>[28:01] on this front if we all work together.<br>[28:03] Start asking yourself, why do I have<br>[28:04] this package and do I really need it?<br>[28:06] This is especially important for<br>[28:08] maintainers. If you find something which<br>[28:10] seems redundant, raise an issue with the<br>[28:12] maintainer asking if it can be removed.<br>[28:13] You encounter a direct dependency which<br>[28:15] has many of these issues, have a look<br>[28:17] for an alternative which doesn't. A good<br>[28:19] start for this is the module<br>[28:20] replacements project which is also part<br>[28:22] of E18. I already liked these guys. I<br>[28:25] very quickly am realizing they are<br>[28:27] essential to this ecosystem. Another<br>[28:29] great recommendation is NIP. We use this<br>[28:30] in all of our projects now. It has been<br>[28:32] an incredibly helpful thing. NIP will<br>[28:35] find unused code and imports in your<br>[28:37] project and make it easy to get rid of<br>[28:39] them. It also helps with unused depths,<br>[28:40] dead code, and many other random things.<br>[28:43] Be a great tool to find and remove<br>[28:44] depths you no longer use. It doesn't<br>[28:46] solve all these problems necessarily,<br>[28:47] but it's a great starting point to help<br>[28:48] clean up depth trees before doing the<br>[28:50] more involved work. Oh, E18 has a CLI<br>[28:53] that is an analyze mode that can<br>[28:55] determine which depths are no longer<br>[28:56] needed or have community replacements<br>[28:58] that are recommended. Apparently, chalk<br>[28:59] can be replaced with native<br>[29:00] functionality. That's really cool. This<br>[29:02] is a great little package here. That's<br>[29:04] so cool. They even have a migration<br>[29:06] command that can migrate for a handful<br>[29:07] of these things that are automatable. In<br>[29:09] this case, it'll migrate from chalk to<br>[29:10] Pico colors, which is a much smaller<br>[29:12] package that provides the same<br>[29:13] functionality. CLI will even recommend<br>[29:15] based on your environment. For example,<br>[29:17] it can suggest the native style text<br>[29:18] instead of a colors library if you're<br>[29:20] running a new enough node. That's really<br>[29:21] cool. Also, npm graphs. This is really,<br>[29:24] really useful. Using npm graphs to<br>[29:26] figure out what the dependencies are of<br>[29:27] your [ย __ย ] That's really good.<br>[29:30] Yeah.<br>[29:31] Yeah, I had a feeling the T3 package has<br>[29:35] uh built up a little bit. We got some<br>[29:38] effect. We got the diffs library. We got<br>[29:41] open and websocket node pointer and the<br>[29:44] claw agent SDK package is so heavily<br>[29:46] offuscated that they're also using<br>[29:48] what's the package that versel has? NCC.<br>[29:51] That's what I'm thinking of. NCC is a<br>[29:53] package by Forcell that takes all your<br>[29:54] dependencies and bundles them into a<br>[29:56] single JS file. And I'm almost positive<br>[29:58] Anthropic is using that here because<br>[29:59] they don't want us to know anything<br>[30:00] about how the Asian SDK is implemented<br>[30:02] because they are kind of evil. So I<br>[30:03] would bet this has lots of other<br>[30:05] subdeps. We just can't see them.<br>[30:06] Apparently Pierre diffs library has a<br>[30:09] lot of subdeps. I did not realize that<br>[30:11] like half our dependency graph comes<br>[30:13] from the diffs library. Interesting. To<br>[30:16] be fair, there are some core depths in<br>[30:17] here that have to be a little complex<br>[30:18] like shiki for the syntax highlighting.<br>[30:20] Like that's just not a trivial thing.<br>[30:22] And then the has to util HTML that turns<br>[30:24] the syntax tree into HTML has a lot of<br>[30:28] these subp packages too. Interesting.<br>[30:30] You learn something every day. And I'm<br>[30:32] learning about my own dependency graph<br>[30:33] right here. See this is a really good<br>[30:35] example here too with ESLint where<br>[30:37] there's this find up package that is a<br>[30:40] bunch of sub things around six total.<br>[30:42] And if you can replace that package then<br>[30:44] you can trim out six packages from your<br>[30:46] npm install. That's a great thing.<br>[30:48] There's also the module replacements<br>[30:49] project which has a set of replacements<br>[30:52] that are modern, simpler, and more<br>[30:54] well-maintained than these old things<br>[30:56] that makes it really easy to identify<br>[30:58] and replace anything that could be<br>[31:00] replaced. This has been an awesome<br>[31:01] article. Huge shout out again to James.<br>[31:02] Let's read the closing thoughts and do<br>[31:04] one last important thing at the end<br>[31:05] here. We all pay the cost for an<br>[31:06] incredibly small group of people to have<br>[31:08] an unusual architecture that they like<br>[31:09] or a level of backwards compatibility<br>[31:11] that they specifically need. It's not a<br>[31:13] fault of the people who made the<br>[31:14] packages as each person should be able<br>[31:15] to build however they want. Many of them<br>[31:17] are an older generation of influential<br>[31:18] JS devs building packages in a darker<br>[31:20] time where many of the nice APIs and<br>[31:22] cross-co compatibility that we have<br>[31:23] today simply didn't exist. They built<br>[31:25] the way they did because it was possibly<br>[31:26] the best way at the time. The problem is<br>[31:28] that we never moved on from there. We<br>[31:30] still download all of this bloat today.<br>[31:32] Even though we've had these features for<br>[31:33] several years, I think we can solve this<br>[31:35] by reversing things. The small group<br>[31:37] should pay the cost. They should have<br>[31:39] their own special stack that pretty much<br>[31:40] only they use. Everyone else should get<br>[31:42] the modern, lightweight, widely<br>[31:44] supported code. Hopefully things like<br>[31:45] the E18 Foundation and npmX can help<br>[31:48] with that through documentation,<br>[31:49] tooling, etc. You can help by taking a<br>[31:51] closer look at your dependencies and<br>[31:52] asking why. Raise issues with your<br>[31:54] dependencies, asking them if and why<br>[31:55] they need these packages anymore. We can<br>[31:57] fix it. E18E is one of the most<br>[32:00] essential things happening in the JS<br>[32:01] world. I already thought highly of them,<br>[32:03] but now I am convinced that we need them<br>[32:04] in order for JS to survive. As such, I'm<br>[32:07] going to do the most important thing to<br>[32:08] support a project like this, money. I<br>[32:11] just contributed $5,000. I think this is<br>[32:14] important. I hope this helps prove just<br>[32:16] how important I think this is. And I<br>[32:18] hope many of y'all take the opportunity<br>[32:20] to do the same. These projects are no<br>[32:22] joke. These are the things that actually<br>[32:23] make the ecosystem survivable. These are<br>[32:25] the things that make the web better and<br>[32:27] keep things from getting worse. If we<br>[32:29] want the web to win, and I hope we all<br>[32:31] do, I hope you guys who have money, and<br>[32:32] I know many of you have money, take the<br>[32:34] opportunity to contribute, or at the<br>[32:36] very least tell your boss that it's<br>[32:38] probably worth including in your open<br>[32:39] source financial contributions.<br>[32:40] Obviously, not everybody needs to donate<br>[32:42] this much money, but if you have a<br>[32:43] couple bucks to throw their way, you'd<br>[32:45] be amazed how far it goes. The team<br>[32:46] doesn't actually need too much money to<br>[32:48] survive right now, and they're very,<br>[32:50] very, very lean. I would argue more so<br>[32:53] than they should be because these devs<br>[32:54] are doing some of the hardest work, and<br>[32:55] they are being paid like [ย __ย ] They<br>[32:57] currently have a total balance of<br>[32:59] $17,000, which in my opinion is enough<br>[33:02] to pay one dev like once. These devs<br>[33:04] should be paid very generously because<br>[33:06] this is very, very important work. The<br>[33:08] fact that an organization that is this<br>[33:09] important literally only has about<br>[33:12] $17,000 there is terrifying and I am<br>[33:15] thankful I just got to meaningfully<br>[33:16] increase that myself. I got nothing else<br>[33:18] to say. Just go support these guys.<br>[33:19] They're doing important work. And until<br>[33:21] next time, peace nerds. <!-- deep-read:sections end --> ๐Ÿ“„ **Full text:** ![[Full Document Contents/Articles/A Rant About Javascript Bloat|A Rant About Javascript Bloat, YouTube]] ## Highlights - at companies that have old ancient terribly maintained and structured code bases that none of the engineers at the company want to work on. If they even have engineers there, they maintain these old endof life projects as well as their dependencies. They have forks of things like NodeJS 0.8 that bring in security fixes while still having the weird [ย __ย ] that the company needs for the old version of Node. They also will often have to change packages and fork them and maintain them themselves in order to keep them compatible with old versions of node. This has even ([View Highlight](https://read.readwise.io/read/01kmzkqqcj1w7nq4sb6jjza8yr)) - Tags: ๐Ÿ‘ป ai highlighted - examples of people using these really old things that have this crazy set of weird dependencies that aren't needed in most places. It's all them. There's a bunch of things that we take for granted in modern JavaScript that just don't exist in these old places. For example, for each on arrays or reduce on arrays or object.keys. keys, which I use all of the [ย __ย ] time, or object. I use some of the time. I do not know how I would write JS without these. These are all ES5 features, meaning they simply don't exist in ES3 engines. For those ([View Highlight](https://read.readwise.io/read/01kmzkqqeztsajehps22rgethm)) - Tags: ๐Ÿ‘ป ai highlighted - unfortunate souls who are still running old engines, they need to reimplement everything themselves or be provided with polyfills. Alternatively, it'd be really nice if they just upgraded. Totally agree there. Protection against global namespace mutation. The second reason for some of these packages is safety in quotes. Basically, inside of node itself, there's a concept of primordials. These are essentially just global objects wrapped at startup and imported by node from then on to avoid node itself being broken by someone mutating the global namespace. For example, if node itself uses map and we ([View Highlight](https://read.readwise.io/read/01kmzkqqgpr1ez05y4vv9tdf66)) - Tags: ๐Ÿ‘ป ai highlighted - is underappreciated for the level of complexity that they're operating within. Like Node and V8 are two of the most crazy complex, generous gifts to the software development world that get treated like [ย __ย ] because people just hate on JavaScript. always has annoyed me, even back when I hated JS. Okay, last time I hated JS was like the last time I had to write JS to be fair, but you you get what I mean. Apparently, there are some maintainers that believe this is the correct way to build packages, too. That's why we have dependencies like math intrinsics in the graph above, which is just a reexport of the various math.star functions in order to avoid them being mutated. What? Yep, ([View Highlight](https://read.readwise.io/read/01kmzkqqjfh35emzrk2m0fnx5b)) - Tags: ๐Ÿ‘ป ai highlighted - of this package is TJ, who is the creator of Express, who left JavaScript a decade ago. Dogpaw and Steven are helping a ton here. Thank you both, by the way. Huge shout out to you guys for making sure I get all the fun facts in this one. So, now the most important part. What can we do about all of this? Much of this bloat is so deeply nested in dependency trees today that it's a fairly hefty task to unravel it all and get to a good place. It will take time and it will take a lot of effort for both maintainers and the consumers of these libraries. Having said that, I do think we can make significant progress ([View Highlight](https://read.readwise.io/read/01kmzkqqx3j7z7wzhvvshast20)) - Tags: ๐Ÿ‘ป ai highlighted - Even though we've had these features for several years, I think we can solve this by reversing things. The small group should pay the cost. They should have their own special stack that pretty much only they use. Everyone else should get the modern, lightweight, widely supported code. Hopefully things like the E18 Foundation and npmX can help with that through documentation, tooling, etc. You can help by taking a closer look at your dependencies and asking why. Raise issues with your dependencies, asking them if and why they need these packages anymore. We can fix it. E18E is one of the most ([View Highlight](https://read.readwise.io/read/01kmzkqr1m4410r924fe7761zv)) - Tags: ๐Ÿ‘ป ai highlighted