<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Sourav Bhowmik</title>
    <description>The latest articles on DEV Community by Sourav Bhowmik (@sourav_bhowmik_73d35592ab).</description>
    <link>https://dev.to/sourav_bhowmik_73d35592ab</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3502057%2Ffb268607-5873-4091-b997-bb39e42c5d18.png</url>
      <title>DEV Community: Sourav Bhowmik</title>
      <link>https://dev.to/sourav_bhowmik_73d35592ab</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/sourav_bhowmik_73d35592ab"/>
    <language>en</language>
    <item>
      <title>How I Cut a React App's Initial Bundle by 89%</title>
      <dc:creator>Sourav Bhowmik</dc:creator>
      <pubDate>Wed, 30 Sep 2026 17:40:53 +0000</pubDate>
      <link>https://dev.to/sourav_bhowmik_73d35592ab/how-i-cut-a-react-apps-initial-bundle-by-89-58k2</link>
      <guid>https://dev.to/sourav_bhowmik_73d35592ab/how-i-cut-a-react-apps-initial-bundle-by-89-58k2</guid>
      <description>&lt;p&gt;Building and shipping applications is an integral part of a software developer's life. In this article I show you how I ran an experiment on the initial bundle size of a frontend web app build, specifically, which factors are responsible for bundle bloat, and how much of it can actually be reduced. My baseline build shipped a 634 KB (gzip) initial bundle. After running four optimization experiments, it dropped to 71 KB, a staggering 89% reduction!&lt;/p&gt;

&lt;h2&gt;
  
  
  Setup
&lt;/h2&gt;

&lt;p&gt;I built a minimal activity-dashboard app in React, with help from Claude AI. The baseline version deliberately includes a few heavy dependencies: &lt;code&gt;react-icons&lt;/code&gt;, &lt;code&gt;lodash&lt;/code&gt;, &lt;code&gt;recharts&lt;/code&gt;, and &lt;code&gt;moment&lt;/code&gt;; each picked for a reason that seemed sensible at the time, not out of carelessness.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;moment&lt;/strong&gt;, because it's one of the most popular date libraries in JS and handling relative timestamps correctly (pluralization, day boundaries) felt like something worth not hand-rolling.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;lodash&lt;/strong&gt;, because I needed &lt;code&gt;debounce&lt;/code&gt; for the search input and &lt;code&gt;groupBy&lt;/code&gt; to cluster activities by date; pulling in a well-known utility library felt like the obvious choice. &lt;em&gt;(There is a surprise bug for the lodash imports! Continue reading to find out&lt;/em&gt; 😉&lt;em&gt;)&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;recharts&lt;/strong&gt;, because the Dashboard page just needed one simple line chart, and it didn't seem worth reaching for something heavier like Chart.js.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The app has three pages: &lt;strong&gt;Feed&lt;/strong&gt; (the landing page, showing dummy activity items), &lt;strong&gt;Dashboard&lt;/strong&gt; (a line chart of weekly activity via recharts), and &lt;strong&gt;Settings&lt;/strong&gt; (empty, included only to demonstrate route-based code splitting).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fcaybys4dtxw8f3g4olkk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fcaybys4dtxw8f3g4olkk.png" alt="Feed page" width="800" height="536"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fidhoc9n1dddkhwdmkt7g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fidhoc9n1dddkhwdmkt7g.png" alt="Dashboard page" width="800" height="453"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For measuring bundle composition, I used &lt;code&gt;rollup-plugin-visualizer&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// vite.config.js&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;visualizer&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;rollup-plugin-visualizer&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nf"&gt;defineConfig&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="nf"&gt;react&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="nf"&gt;visualizer&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;filename&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dist/stats.html&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;gzipSize&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;}),&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This generates a &lt;code&gt;stats.html&lt;/code&gt; treemap after every build, showing exactly which libraries and functions are taking up space.&lt;/p&gt;

&lt;h2&gt;
  
  
  Experiments
&lt;/h2&gt;

&lt;p&gt;I ran four experiments from the baseline, each isolated on its own branch, to measure the individual impact of a single fix on initial bundle size. A final branch combines all four.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Fixing the icon import
&lt;/h3&gt;

&lt;p&gt;This was the single biggest win. The baseline imported the entire icon set:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;Icons&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react-icons/fa&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This looked necessary because the icon to render is resolved at runtime from a &lt;code&gt;category&lt;/code&gt; field in the data — so it seemed like there was no way to know in advance which icons I'd need. But the category set is actually small and known ahead of time, so named imports work fine:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;FaComment&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;FaUpload&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;FaAt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;FaHeart&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;FaUserPlus&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react-icons/fa&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;CATEGORY_TO_ICON&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;comment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;FaComment&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;upload&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;FaUpload&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;mention&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;FaAt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;like&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;FaHeart&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;join&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;FaUserPlus&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This single change cut the initial bundle by &lt;strong&gt;67%&lt;/strong&gt; — from 634 KB to 209 KB (gzip).&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Lazy-loading the Dashboard route
&lt;/h3&gt;

&lt;p&gt;The Dashboard page's line chart (&lt;code&gt;recharts&lt;/code&gt;) was being loaded on every page visit, even for users who never opened the Dashboard. Wrapping the route in &lt;code&gt;React.lazy&lt;/code&gt; + &lt;code&gt;Suspense&lt;/code&gt; defers that cost until someone actually navigates there:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Before&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Dashboard&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./pages/Dashboard&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="c1"&gt;// After&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Dashboard&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;lazy&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./pages/Dashboard&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Suspense&lt;/span&gt; &lt;span class="na"&gt;fallback&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Loading...&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Routes&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Route&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"/dashboard"&lt;/span&gt; &lt;span class="na"&gt;element&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Dashboard&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/* ...other routes */&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Routes&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Suspense&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This reduced the initial bundle by &lt;strong&gt;17%&lt;/strong&gt;, from 634 KB to 529 KB (gzip).&lt;/p&gt;

&lt;p&gt;Worth calling out: this fix doesn't make &lt;code&gt;recharts&lt;/code&gt; disappear; it rather moves it into a separate chunk that loads on demand. So while the &lt;em&gt;initial&lt;/em&gt; download shrinks by 17%, the &lt;em&gt;total&lt;/em&gt; JS the app ships (initial + Dashboard chunk combined) barely changes. That distinction, initial load vs. total weight, turned out to matter a lot for how I read all four results, and especially the combined one at the end.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Fixing the lodash import
&lt;/h3&gt;

&lt;p&gt;The baseline imported lodash like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;debounce&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;groupBy&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;lodash&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This &lt;em&gt;looks&lt;/em&gt; like a named import, but it isn't one; at least not in a way that helps. Lodash's main entry point is a CommonJS module, so the bundler can't statically determine which functions are actually used and ends up including the whole library anyway. It's effectively the same as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;_&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;lodash&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The fix is to import each function from its own subpath:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;debounce&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;lodash/debounce&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;groupBy&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;lodash/groupby&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This properly tree-shakes and cuts the bundle by &lt;strong&gt;5%&lt;/strong&gt;; a small number, but the mistake itself is the more useful finding: it's easy to write an import that looks tree-shaken and isn't.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;N.B.&lt;/strong&gt; There is a subtle and easy-to-miss bug in the second lodash import &lt;code&gt;lodash/groupby&lt;/code&gt;. Named imports are case-sensitive, so the correct import path should be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;groupBy&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;lodash/groupBy&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then how did this work on my machine? Because Windows and MacOS filesystems are not case-sensitive. So the import path worked on my Windows environment. But this would raise an error in a Linux environment.&lt;/p&gt;

&lt;p&gt;Switching to &lt;code&gt;lodash-es&lt;/code&gt; with named imports (&lt;code&gt;import { debounce, groupBy } from 'lodash-es'&lt;/code&gt;) will completely remove this bug and make things even easier. &lt;strong&gt;And since &lt;code&gt;lodash-es&lt;/code&gt; is a proper ES Module, tree shaking is embedded by default.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Replacing moment with date-fns
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;moment&lt;/code&gt; is a large, feature-complete library, and reaching for it as a first instinct for date handling is common since it's intuitive and well-documented. But most of that surface area goes unused in any single app, and unlike modern alternatives, moment isn't built to tree-shake. Swapping it for &lt;code&gt;date-fns&lt;/code&gt;, which ships as individual function modules:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Before&lt;/span&gt;
&lt;span class="nf"&gt;moment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;fromNow&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="c1"&gt;// After&lt;/span&gt;
&lt;span class="nf"&gt;formatDistanceToNow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;addSuffix&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This produced the smallest change of the four — a &lt;strong&gt;2%&lt;/strong&gt; reduction. But in an app with heavier date usage than this one, that gap would likely be much larger; this app only touches three moment methods, so there wasn't much bulk to remove in the first place.&lt;/p&gt;

&lt;h2&gt;
  
  
  Combined result
&lt;/h2&gt;

&lt;p&gt;Applying all four fixes together dropped the initial bundle from 634 KB to &lt;strong&gt;71 KB&lt;/strong&gt; (gzip) — an &lt;strong&gt;89%&lt;/strong&gt; reduction.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Before&lt;/th&gt;
&lt;th&gt;After&lt;/th&gt;
&lt;th&gt;Change&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;Initial download&lt;/strong&gt; (what a first-time visitor gets)&lt;/td&gt;
&lt;td&gt;634 KB&lt;/td&gt;
&lt;td&gt;71 KB&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;-89%&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;Total JS shipped&lt;/strong&gt; (initial + Dashboard chunk)&lt;/td&gt;
&lt;td&gt;634 KB&lt;/td&gt;
&lt;td&gt;168 KB&lt;/td&gt;
&lt;td&gt;-74%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The gap between those two rows is the point of lazy-loading: total app weight didn't shrink as much as the initial load did, because the chart code still exists; it just isn't downloaded until someone actually needs it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Takeaway
&lt;/h2&gt;

&lt;p&gt;The goal here was to find out which kinds of bundle bloat actually matter, not just to list generic advice. Of the four fixes, the wildcard icon import alone accounted for a 67% reduction — more than the other three combined. If you're short on time, auditing wildcard/dynamic imports is probably the highest-leverage place to start.&lt;/p&gt;

&lt;p&gt;It's also worth knowing that named imports aren't automatically tree-shaken. Instead, it depends on how the library itself is structured, and it's easy to get this wrong without realizing it, as the lodash example shows.&lt;/p&gt;

&lt;p&gt;The full project, including each experiment on its own branch and the combined final version, is on GitHub: &lt;em&gt;[&lt;a href="https://github.com/bhowmik94/bundle-experiment" rel="noopener noreferrer"&gt;https://github.com/bhowmik94/bundle-experiment&lt;/a&gt;]&lt;/em&gt;. The &lt;code&gt;experiments/&lt;/code&gt; folder has the bundle visualizer output for each build, showing the exact size breakdown per library and function, if you want to dig deeper. You are welcome to reproduce the same results and see for yourself. Just fork the project and have fun! Please feel free to leave any questions or comments below for further discussions and improvements. And if you are feeling generous, consider leaving a heart in this article.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>react</category>
      <category>performance</category>
    </item>
  </channel>
</rss>
