A place to cache linked articles (think custom and personal wayback machine)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

index.md 14KB

8 months ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. title: JavaScript Bloat in 2024
  2. url: https://tonsky.me/blog/js-bloat/
  3. hash_url: ad911ebf7ba5523ef0be1bdd599f7623
  4. archive_date: 2024-03-03
  5. og_image: https://dynogee.com/gen?id=dhqv5e0x3kfz7dy&title=JavaScript Bloat in 2024
  6. description: What is the average size of JavaScript code downloaded per website? Fuck around and find out!
  7. favicon: https://tonsky.me/i/favicon.png
  8. language: en_US
  9. <p><em>Translations: <a href="https://habr.com/ru/companies/ruvds/articles/796595/" target="_blank">Russian</a></em></p>
  10. <p>I was a bit out of touch with modern front-end development. I also remembered articles about web bloat, how the average web page size was approaching several megabytes!</p>
  11. <p>So all this time I was living under impression that, for example, if the average web page size is 3 MB, then JavaScript bundle should be around 1 MB. Surely content should still take the majority, no?</p>
  12. <p>Well, the only way to find out is to fuck around. Let’s do a reality check!</p>
  13. <p>I’m writing this in 2024, so maybe do a sequel in a few years?</p>
  14. <h1 id="method">Method</h1>
  15. <ul>
  16. <li>Firefox on macOS (but should be the same in any browser)</li>
  17. <li>Not incognito (I want to see numbers <em>inside</em> the app, and there’s a better chance it will resemble actual everyday experience)</li>
  18. <li>All extensions disabled</li>
  19. <li>JavaScript only</li>
  20. <li>Uncompressed</li>
  21. <li>Service Workers enabled (again, more real-life)</li>
  22. <li>All caching disabled (cold load)</li>
  23. </ul>
  24. <p>Why only JavaScript? Content varies a lot from site to site (surely videos on YouTube are heavier than text messages on Slack), but JavaScript is a universal metric for “complexity of interactions”.</p>
  25. <p>The main goal is to evaluate how much work the browser has to do to parse and execute code.</p>
  26. <p>To set some baseline, let’s start with this blog:</p>
  27. <figure>
  28. <img src="https://tonsky.me/blog/js-bloat/tonsky@2x.webp?t=1709315366"> </figure>
  29. <p>The number here would be 0.004 MB. I also highlighted all the important bits you need to set if you decide to reproduce this at home.</p>
  30. <h1 id="landings">Landings</h1>
  31. <p>Okay, let’s start with something simple, like landing pages/non-interactive apps.</p>
  32. <p>A normal slightly interactive page looks like this — Wikipedia, 0.2 MB:</p>
  33. <figure>
  34. <img src="https://tonsky.me/blog/js-bloat/wikipedia@2x.webp?t=1709315366"> </figure>
  35. <p>Slightly bloated — like this — Linear, 3 MB:</p>
  36. <figure>
  37. <img src="https://tonsky.me/blog/js-bloat/linear@2x.webp?t=1709315366"> </figure>
  38. <p>Remember: that’s without images, or videos, or even styles! Just JS code.</p>
  39. <p>A bad landing page looks like this — Zoom, 6 MB:</p>
  40. <figure>
  41. <img src="https://tonsky.me/blog/js-bloat/zoom@2x.webp?t=1709315366"> </figure>
  42. <p>or like Vercel, 6 MB:</p>
  43. <figure>
  44. <img src="https://tonsky.me/blog/js-bloat/vercel@2x.webp?t=1709315366"> </figure>
  45. <p>Yes, this is just a landing page. No app, no functionality, no calls. 6 MB of JavaScript just for that.</p>
  46. <p>You can do a lot worse, though — Gitlab, 13 MB:</p>
  47. <figure>
  48. <img src="https://tonsky.me/blog/js-bloat/gitlab@2x.webp?t=1709315366"> </figure>
  49. <p>Still just the landing.</p>
  50. <h1 id="mostly-static-websites">Mostly static websites</h1>
  51. <p>Nothing simpler than showing a static wall of text. Medium needs 3 MB just to do that:</p>
  52. <figure>
  53. <img src="https://tonsky.me/blog/js-bloat/medium@2x.webp?t=1709315366"> </figure>
  54. <p>Substack needs 4 MB:</p>
  55. <figure>
  56. <img src="https://tonsky.me/blog/js-bloat/substack@2x.webp?t=1709315366"> </figure>
  57. <p>Progress?</p>
  58. <p>Quora, 4.5 MB:</p>
  59. <figure>
  60. <img src="https://tonsky.me/blog/js-bloat/quora@2x.webp?t=1709315366"> </figure>
  61. <p>Pinterest, 10 MB:</p>
  62. <figure>
  63. <img src="https://tonsky.me/blog/js-bloat/pinterest@2x.webp?t=1709315366"> </figure>
  64. <p>Patreon, 11 MB:</p>
  65. <figure>
  66. <img src="https://tonsky.me/blog/js-bloat/patreon@2x.webp?t=1709315366"> </figure>
  67. <p>And all this could’ve been a static page...</p>
  68. <h1 id="search">Search</h1>
  69. <p>When your app’s interactivity is limited to mostly search. Type the query — show the list of results. How heavy is that?</p>
  70. <p>StackOverflow, 3.5 MB:</p>
  71. <figure>
  72. <img src="https://tonsky.me/blog/js-bloat/stackoverflow@2x.webp?t=1709315366"> </figure>
  73. <p>NPM, 4 MB:</p>
  74. <figure>
  75. <img src="https://tonsky.me/blog/js-bloat/npmjs@2x.webp?t=1709315366"> </figure>
  76. <p>Airbnb, 7 MB:</p>
  77. <figure>
  78. <img src="https://tonsky.me/blog/js-bloat/airbnb@2x.webp?t=1709315366"> </figure>
  79. <p>Booking.com, 12 MB:</p>
  80. <figure>
  81. <img src="https://tonsky.me/blog/js-bloat/booking@2x.webp?t=1709315366"> </figure>
  82. <p>But Niki, booking is complicated! Look at all this UI! All these filters. All these popups about people near you stealing your vacation!</p>
  83. <p>Okay, okay. Something simpler then. Google. How about Google? One text field, list of links. Right?</p>
  84. <p>Well, it’ll cost you whooping 9 MB:</p>
  85. <figure>
  86. <img src="https://tonsky.me/blog/js-bloat/google@2x.webp?t=1709315366"> </figure>
  87. <p>Just to show a list of links.</p>
  88. <h1 id="simple-one-interaction-apps">Simple one-interaction apps</h1>
  89. <p>Google Translate is just two text boxes. For that, you need 2.5 MB:</p>
  90. <figure>
  91. <img src="https://tonsky.me/blog/js-bloat/google_translate@2x.webp?t=1709315366"> </figure>
  92. <p>ChatGPT is <em>one</em> text box. 7 MB:</p>
  93. <figure>
  94. <img src="https://tonsky.me/blog/js-bloat/openai@2x.webp?t=1709315366"> </figure>
  95. <p>I mean, surely, ChatGPT is complex. But on the server, not in the browser!</p>
  96. <h1 id="videos">Videos</h1>
  97. <p>Loom — 7 MB:</p>
  98. <figure>
  99. <img src="https://tonsky.me/blog/js-bloat/loom@2x.webp?t=1709315366"> </figure>
  100. <p>YouTube — 12 MB:</p>
  101. <figure>
  102. <img src="https://tonsky.me/blog/js-bloat/youtube@2x.webp?t=1709315366"> </figure>
  103. <p>Compare it to people who really care about performance — Pornhub, 1.4 MB:</p>
  104. <figure>
  105. <img src="https://tonsky.me/blog/js-bloat/pornhub@2x.webp?t=1709315366"> </figure>
  106. <h1 id="audio">Audio</h1>
  107. <p>I guess audio just requires 12 MB no matter what:</p>
  108. <p>SoundCloud:</p>
  109. <figure>
  110. <img src="https://tonsky.me/blog/js-bloat/soundcloud@2x.webp?t=1709315366"> </figure>
  111. <p>Spotify:</p>
  112. <figure>
  113. <img src="https://tonsky.me/blog/js-bloat/spotify@2x.webp?t=1709315366"> </figure>
  114. <h1 id="email">Email</h1>
  115. <p>Okay, video and audio are probably heavy stuff (even though we are not measuring content, just JS, remember!). Let’s move to simpler office tasks.</p>
  116. <p>Google Mail is just (just!) 20 MB:</p>
  117. <figure>
  118. <img src="https://tonsky.me/blog/js-bloat/gmail@2x.webp?t=1709315366"> </figure>
  119. <p>It’s a freaking mailbox!!! How on earth is it almost as big as Figma, who ships entire custom C++/OpenGL rendering for their app?</p>
  120. <figure>
  121. <img src="https://tonsky.me/blog/js-bloat/figma@2x.webp?t=1709315366"> </figure>
  122. <p>And if you are thinking: mail is complicated, too. Lots of UI, lots of interactivity. Maybe 20 MB is okay?</p>
  123. <p>No!</p>
  124. <p>Just no. See, FastMail, same deal, but only 2 MB. 10× less!</p>
  125. <figure>
  126. <img src="https://tonsky.me/blog/js-bloat/fastmail@2x.webp?t=1709315366"> </figure>
  127. <h1 id="productivity">Productivity</h1>
  128. <p>Okay, maybe e-mail is too complicated? How about something even simpler? Like a TODO list?</p>
  129. <p>Well, meet Todoist, 9 MB:</p>
  130. <figure>
  131. <img src="https://tonsky.me/blog/js-bloat/todoist@2x.webp?t=1709315366"> </figure>
  132. <p>Showing you a list of files in folders requires 10 MB in Dropbox:</p>
  133. <figure>
  134. <img src="https://tonsky.me/blog/js-bloat/dropbox@2x.webp?t=1709315366"> </figure>
  135. <p>List of passwords? That’ll be 13 MB on 1Password:</p>
  136. <figure>
  137. <img src="https://tonsky.me/blog/js-bloat/1password@2x.webp?t=1709315366"> </figure>
  138. <p>Cards? Add 0.5 MB more, up to 13.5 MB. Trello:</p>
  139. <figure>
  140. <img src="https://tonsky.me/blog/js-bloat/trello@2x.webp?t=1709315366"> </figure>
  141. <p>Okay, maybe TODO lists are too complex, too? How about chatting?</p>
  142. <p>Well, Discord needs 21 MB to do that:</p>
  143. <figure>
  144. <img src="https://tonsky.me/blog/js-bloat/discord@2x.webp?t=1709315366"> </figure>
  145. <h1 id="document-editing">Document editing</h1>
  146. <p>Okay, document editing is hard, right? You have to implement cursor movement, synchronization, etc.</p>
  147. <p>Google Docs, 13.5 MB:</p>
  148. <figure>
  149. <img src="https://tonsky.me/blog/js-bloat/google_docs@2x.webp?t=1709315366"> </figure>
  150. <p>Something simpler? Notion, 16 MB:</p>
  151. <figure>
  152. <img src="https://tonsky.me/blog/js-bloat/notion@2x.webp?t=1709315366"> </figure>
  153. <h1 id="social-networks">Social Networks</h1>
  154. <p>The typical size of code that social networks need for like buttons to go brrr is 12 MB.</p>
  155. <p>Twitter, 11 MB:</p>
  156. <figure>
  157. <img src="https://tonsky.me/blog/js-bloat/twitter@2x.webp?t=1709315366"> </figure>
  158. <p>Facebook, 12 MB:</p>
  159. <figure>
  160. <img src="https://tonsky.me/blog/js-bloat/facebook@2x.webp?t=1709315366"> </figure>
  161. <p>TikTok, 12.5 MB:</p>
  162. <figure>
  163. <img src="https://tonsky.me/blog/js-bloat/tiktok@2x.webp?t=1709315366"> </figure>
  164. <p>Instagram is somehow bigger than Facebook, despite having like 10× less functions. 16 MB:</p>
  165. <figure>
  166. <img src="https://tonsky.me/blog/js-bloat/instagram@2x.webp?t=1709315366"> </figure>
  167. <p>LinkedIn. Is it a blog? A platform? It has search, it has messaging, it has social functions. Anyways, that’ll be 31 MB:</p>
  168. <figure>
  169. <img src="https://tonsky.me/blog/js-bloat/linkedin@2x.webp?t=1709315366"> </figure>
  170. <p>By the way, I'd like to add you to my professional network on LinkedIn.</p>
  171. <h1 id="elephants--its-own-category">Elephants — its own category</h1>
  172. <p>Sometimes websites are so stupidly, absurdly large that they deserve their own category.</p>
  173. <p>Here, Jira, a task management software. Almost 50 MB!</p>
  174. <figure>
  175. <img src="https://tonsky.me/blog/js-bloat/jira@2x.webp?t=1709315366"> </figure>
  176. <p>Do they ship the entire Electron compiled WASM or what?</p>
  177. <p>But that’s not the limit! Slack adds 5 more MB, up to 55 MB:</p>
  178. <figure>
  179. <img src="https://tonsky.me/blog/js-bloat/slack@2x.webp?t=1709315366"> </figure>
  180. <p>Yes, it’s a chat. You know, list of users, messages, reactions. Stuff we did on raw HTML, even before JS was invented?</p>
  181. <p>That’s 55 MB in today’s world. It’s almost like they are trying to see how much more bullshit can they put in a browser before it breaks.</p>
  182. <p>Finally, this blew my mind. Somehow <a href="https://react.dev/blog/2023/03/16/introducing-react-dev" target="_blank">react.dev</a> starts with a modest 2 MB but as you scroll back and forth, it grows indefinitely. Just for fun, I got it to 100 MB (of JavaScript!), but you can go as far as you like:</p>
  183. <figure>
  184. <video autoplay="" muted="" loop="" preload="auto" playsinline="" controls="">
  185. <source src="https://tonsky.me/blog/js-bloat/react@2x.mp4?t=1708621056" type="video/mp4">
  186. </source></video>
  187. </figure>
  188. <p>What is going on there? Even if it unloads and downloads parts of that blog post, how is it growing so quickly? The text itself is probably only 50 KB (0.05 MB).</p>
  189. <p>UPD: It has been brought to my attention that this behavior is not, in fact, representative of normal user experience. Normally embedded code editors will be cached after first load and subsequent loads will be served from disk cache. So as you scroll, you will see no network traffic, but these 100 MB of JS will still be parsed, evaluated and initialized over and over as you scroll.</p>
  190. <h1 id="how-fast-are-we-degrading">How fast are we degrading?</h1>
  191. <p>Look how cute! In 2015 average web page size was approaching shareware version of Doom 1 (2.5 MB):</p>
  192. <figure>
  193. <img src="https://tonsky.me/blog/js-bloat/bloat_2015@2x.webp?t=1709315366"><figcaption><a href="https://twitter.com/xbs/status/626781529054834688" target="_blank">Source</a></figcaption> </figure>
  194. <p>Well, in 2024, Slack pulls up 55 MB, the size of the original Quake 1 with all the resources. But now it’s just in JavaScript alone.</p>
  195. <p>For a chat app!</p>
  196. <h1 id="how-big-is-10-mb-anyway">How big is 10 MB anyway?</h1>
  197. <p>To be honest, after typing all these numbers, 10 MB doesn’t even feel that big or special. Seems like shipping 10 MB of <em>code</em> is normal now.</p>
  198. <p>If we assume that the average code line is about 65 characters, that would mean we are shipping ~150,000 lines of code. With every website! Sometimes just to show static content!</p>
  199. <p>And that code is minified already. So it’s more like 300K+ LoC just for one website.</p>
  200. <p>But are modern websites really <em>that</em> complex? The poster child of SPAs, Google Maps, is quite modest by modern standards — is <em>still</em> just 4.5 MB:</p>
  201. <figure>
  202. <img src="https://tonsky.me/blog/js-bloat/google_maps@2x.webp?t=1709315366"> </figure>
  203. <p>Somebody at Google is seriously falling behind. Written with modern front-end technologies, it should be at least 20 MB.</p>
  204. <p>And if you, like me, thought that “Figma is a really complex front-end app, so it must have a huge javascript download size”, well, that’s correct, but then Gmail is about as complex as Figma, LinkedIn is 1.5× more complex and Slack is 2.5× more ¯\_(ツ)_/¯</p>
  205. <h1 id="conclusion">Conclusion</h1>
  206. <p>It’s not just about download sizes. I welcome high-speed internet as much as the next guy. But code — JavaScript — is something that your browser has to parse, keep in memory, execute. It’s not free. And these people talk about performance and battery life...</p>
  207. <p>Call me old-fashioned, but I firmly believe content should outweigh code size. If you are writing a blog post for 10K characters, you don’t need 1000× more JavaScript to render it.</p>
  208. <p>This site is doing it right:</p>
  209. <figure>
  210. <img src="https://tonsky.me/blog/js-bloat/jquery@2x.webp?t=1709315366"> </figure>
  211. <p>That’s 0.1 MB. And that’s enough!</p>
  212. <p>And yet, on the same internet, in the same timeline, Gitlab needs 13 MB of code, 500K+ LoC of JS, just to display a static landing page.</p>
  213. <p>Fuck me.</p>