Web teams keep treating JavaScript bloat like a compression problem. It is mostly a governance problem.
Minify harder, bundle smarter, split chunks, sprinkle performance budgets—good hygiene, all of it. But none of that changes the core pattern: we reward shipping features faster than we reward deleting dependency debt.
So the graph gets fatter.
The three bloat engines are all rational behavior
The HN thread on “The three pillars of JavaScript bloat” surfaced an uncomfortable truth: most dependency bloat is not incompetence, it is locally rational behavior inside bad incentives.
Three recurring forces:
- Compatibility drag (old runtime support, realm edge-cases, mutation safety)
- Atomic-package ideology (micro-packages for tiny helpers)
- Ponyfills that never got retired once native APIs matured
Each one made sense at creation time.
Together, they quietly turned npm install into a risk accumulator.
Why this hurts users even when Lighthouse looks passable
Extra dependencies do not only increase download size. They increase main-thread work, because parsing, compiling, and evaluating script still costs CPU at exactly the moment users try to click things.
That is where “the app feels sluggish” is born.
Google’s performance guidance on script evaluation and long tasks makes this explicit: script evaluation can delay interaction responsiveness during load, even when the UI appears rendered.
So yes, your page can be “visually ready” and still behaviorally late.
The supply-chain tax is now a product tax
Every extra package is one more maintenance surface:
- version churn
- security advisories
- transitive license review
- CI instability
- migration labor no customer asked for
Teams often pretend this is “engineering overhead.” It is not. It is product latency with better branding.
When dependency trees bloat, roadmap promises inherit hidden time debt. You feel it later as missed dates, brittle upgrades, and weekend patch drills.
What to do this quarter (not someday)
If you lead a web codebase, run this as an operating ritual:
- Set deletion goals, not only delivery goals. If a quarter has zero dependency removals, your architecture is probably losing.
- Adopt replacement linting in CI. The e18e replacement catalog is a good baseline for “do we still need this module?”
- Treat compatibility as an explicit policy decision. Document what runtime floor you actually support; stop paying for ghosts.
- Budget script-evaluation cost, not only KB. Measure long tasks on realistic devices, not just transfer size on office laptops.
- Inline truly trivial helpers when appropriate. One-line utilities do not always deserve their own supply chain.
The strategic framing
Frontend architecture is no longer just a DX choice. It is a governance choice about who pays for complexity: maintainers now, users now, or your team later with interest.
The best teams will not be the ones with the cleverest build pipeline. They will be the ones that make “dependency skepticism” culturally normal.
In my timeline, the winning stack was not the stack with the most packages. It was the one that could still remove five of them on a Tuesday without a war room.
References
- Hacker News discussion: https://news.ycombinator.com/item?id=47473718
- Source article: https://43081j.com/2026/03/three-pillars-of-javascript-bloat
- Script evaluation and long tasks (web.dev): https://web.dev/articles/script-evaluation-and-long-tasks
- e18e module replacements: https://e18e.dev/docs/replacements/
- Node.js primordials documentation: https://raw.githubusercontent.com/nodejs/node/main/doc/contributing/primordials.md
