<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Deepak Pai's blog]]></title><description><![CDATA[Blog about Web, Frontend, Performance, React and GraphQL]]></description><link>https://blog.debugpai.com</link><generator>RSS for Node</generator><lastBuildDate>Tue, 14 Apr 2026 01:19:44 GMT</lastBuildDate><atom:link href="https://blog.debugpai.com/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[How to Save on Taxes with Pension Accounts in the Netherlands]]></title><description><![CDATA[I want to share what I have learned about the Pension system in the Netherlands and how a lot of folks do not know about the tax benefits that exist around it.
Disclaimer: I’m not a financial advisor. This is not financial advice. I’m only sharing my...]]></description><link>https://blog.debugpai.com/how-to-save-on-taxes-with-pension-accounts-in-the-netherlands</link><guid isPermaLink="true">https://blog.debugpai.com/how-to-save-on-taxes-with-pension-accounts-in-the-netherlands</guid><category><![CDATA[pensioen]]></category><category><![CDATA[Netherlands]]></category><category><![CDATA[taxes]]></category><category><![CDATA[TaxFreeLiving]]></category><category><![CDATA[ pension]]></category><dc:creator><![CDATA[Deepak Pai]]></dc:creator><pubDate>Mon, 06 Oct 2025 13:51:11 GMT</pubDate><content:encoded><![CDATA[<p>I want to share what I have learned about the Pension system in the Netherlands and how a lot of folks do not know about the tax benefits that exist around it.</p>
<p>Disclaimer: I’m not a financial advisor. This is not financial advice. I’m only sharing my knowledge. No rights can be derived from the content of this article.</p>
<p>I will first explain the general Dutch pension system and then explain the tax benefits.<br />If you just want to see what the tax benefits are, you can skip the first section.</p>
<h1 id="heading-the-four-pillars-of-the-dutch-pension-system">The Four Pillars of the Dutch Pension System</h1>
<p>Netherlands uses the 4 pillars pension system to guarantee income for the elderly.</p>
<ol>
<li><p>State Pension</p>
</li>
<li><p>Workplace pension</p>
</li>
<li><p>Private pension</p>
</li>
<li><p>Personal wealth &amp; investments</p>
</li>
</ol>
<h2 id="heading-state-pension-aow"><strong>State Pension (AOW)</strong></h2>
<p>The Algemene Ouderdomswet (AOW) provides a basic state pension to all residents who have lived or worked in the Netherlands. The amount depends on the number of years you’ve contributed between the ages of 15 and <a target="_blank" href="https://www.svb.nl/en/aow-pension/aow-pension-age/your-aow-pension-age">retirement age</a>.</p>
<p>Typically, the AOW forms the foundation of retirement income.</p>
<h2 id="heading-workplace-pension-tweede-pijler"><strong>Workplace Pension (Tweede Pijler)</strong></h2>
<p>Many employers in the Netherlands offer occupational pensions (tweede pijler). Contributions are usually shared between employer and employee.</p>
<p>These pensions are generally collective schemes, managed by pension funds or insurers, and significantly supplement the AOW.</p>
<p>You can check how much pension you have accrued so far by going to <a target="_blank" href="http://mijnpensioenoverzicht.nl">mijnpensioenoverzicht.nl</a> and logging in with your DigiD.</p>
<h2 id="heading-private-pension-savings-derde-pijler"><strong>Private Pension Savings (Derde Pijler)</strong></h2>
<p>The third pillar is an individual, voluntary way of saving for retirement. This is especially relevant for self-employed professionals and employees without strong employer-provided schemes. Contributions to third-pillar products—such as lijfrente (annuity policies) or pensioenbeleggingsrekening (pension investment accounts)—can be made in a <strong>tax-advantaged way</strong>. This is the focus of the article.</p>
<h2 id="heading-personal-wealth-amp-investments-vierde-pijler"><strong>Personal Wealth &amp; Investments (Vierde Pijler)</strong></h2>
<p>This is all investments and savings that people do independently of pension products. This includes cash savings, equity, bonds, real estate (non-primary residence) and commodities (crypto, gold, etc).</p>
<p>While this pillar does not enjoy the same tax benefits as the third pillar, it provides more flexibility.</p>
<p>In the Dutch tax system, these assets generally fall under <strong>Box 3</strong> (wealth tax). In 2025 this is 2.2% of the principal of the amount on January 1 (on non cash assets) and is proposed to go up in the coming years.</p>
<p>Taxing on principal in this way really puts brakes on compounding your wealth, so it is more important to optimize this tax burden.</p>
<h1 id="heading-saving-taxes-with-private-pension">Saving taxes with Private pension</h1>
<p>Let us dive deeper into how you can use the third pillar to save taxes.</p>
<h2 id="heading-calculating-the-amount-of-private-pension-you-can-invest">Calculating the amount of private pension you can invest</h2>
<p>There is a limit set to how much you can invest in a private pension account. There are 2 main categories for the limits: Jaarruimte and Reserveringsruimte.</p>
<p>You can calculate both Jaarruimte and Reserveringsruimte limits using the <a target="_blank" href="https://www.belastingdienst.nl/wps/wcm/connect/nl/aftrek-en-kortingen/content/hulpmiddel-lijfrentepremie-2016-en-daarna">portal by belastingdienst</a>.</p>
<h3 id="heading-jaarruimte-annual-allowance">Jaarruimte (Annual allowance)</h3>
<p>The <strong>Jaarruimte</strong> (also called vrije ruimte) is the amount you are allowed to contribute to a third-pillar pension product on a tax-deductible basis each year. It depends on your income and your existing pension accrual through your employer.</p>
<p>If you already build up significant pension rights via your employer, your jaarruimte will be lower. Conversely, freelancers or those with minimal employer pensions typically have higher jaarruimte.</p>
<p>To calculate this for this year you would need your total taxable income in Box 1 and your Factor A of the previous year.</p>
<p>An easy way to find total taxable income in Box 1 for previous year is to go to login to the <a target="_blank" href="https://www.belastingdienst.nl">belastingdienst portal</a> with your DigiD and check your last year’s tax statement.</p>
<p>For Factor A, you can find it by logging in with DigiD to the pension account where your employer contributes and looking into the Uniform Pensioen Overzicht (UPO) document.</p>
<h3 id="heading-reserveringsruimte-catch-up-allowance">Reserveringsruimte (Catch-Up Allowance)</h3>
<p>If you did not fully use your jaarruimte in past years, you can carry it forward for up to 10 years. This is known as <strong>reserveringsruimte</strong>. It allows you to make larger pension contributions in later years and still benefit from tax deductions. There are annual maximums for reserveringsruimte contributions, but for people nearing retirement (ages 56–70), these maximums are higher to allow more aggressive catch-up savings.</p>
<p>Use the <a target="_blank" href="https://www.belastingdienst.nl/wps/wcm/connect/nl/aftrek-en-kortingen/content/hulpmiddel-lijfrentepremie-2016-en-daarna">portal by belastingdienst</a> to calculate these limits. A handy way to do this is to write down the taxable income and factor A for each year. Then calculate the Jaarruimte for each year separately and write it down. After this calculate the vrije ruimte for last year and fill in the reserveringsruimte for previous years to get the final number.</p>
<h3 id="heading-example-calculation">Example calculation</h3>
<div class="hn-table">
<table>
<thead>
<tr>
<td><strong>Year</strong></td><td><strong>Income</strong></td><td><strong>Factor A</strong></td><td><strong>Jaarruimte</strong></td></tr>
</thead>
<tbody>
<tr>
<td>2022</td><td>80,000</td><td>2,000</td><td>6,197</td></tr>
<tr>
<td>2023</td><td>90,000</td><td>2,500</td><td>6,063</td></tr>
<tr>
<td>2024</td><td>100,000</td><td>3,000</td><td>5,927</td></tr>
</tbody>
</table>
</div><p>For 2025 contribution then you can answer “Yes” to the question do you want to calculate reserveringsruimte and add the Jaarruimte of previous years you calculated.</p>
<h2 id="heading-tax-deduction-and-deferred-tax">Tax Deduction and Deferred Tax</h2>
<p><strong>Tax Deductible Contributions</strong>: When you contribute to a third-pillar pension product within your vrije ruimte or reserveringsruimte, you can deduct this contribution from your taxable income. This reduces your current income tax burden. If your income falls in the highest bracket, <strong>you can get 49.5% of the money you invested back</strong>.</p>
<p><strong>Deferred Tax</strong>: The money inside your pension grows tax-free (no wealth tax or capital gains tax). However, when you retire and start receiving payouts, those amounts are taxed as income. The advantage is that your tax rate is often lower in retirement compared to your working years.</p>
<h2 id="heading-liquidity-considerations"><strong>Liquidity considerations</strong></h2>
<p>Pension products within the third pillar are highly regulated and cannot be accessed freely before the official pension age. This illiquidity is both a protection mechanism and a restriction.</p>
<h3 id="heading-early-withdrawal-penalties">Early Withdrawal Penalties</h3>
<p>If you withdraw money before the designated pension age (typically the AOW age), it is considered a forbidden withdrawal. In such cases:</p>
<ol>
<li><p>The full withdrawal amount becomes <strong>fully taxable</strong> as income in Box 1 in the year of withdrawal.</p>
</li>
<li><p>An additional <a target="_blank" href="https://www.belastingdienst.nl/wps/wcm/connect/nl/werk-en-inkomen/content/hulpmiddel-revisierente-berekenen"><strong>20% penalty tax (revisierente)</strong></a> is applied by the Belastingdienst (Dutch Tax Authority). This 20% penalty however is counteracted with Box 3 tax savings if you stay invested for at least 11 years.</p>
</li>
</ol>
<h3 id="heading-withdrawal-at-60-vs-at-pension-age">Withdrawal at 60 vs. at Pension Age</h3>
<p>Some lijfrente products allow flexibility in starting payouts earlier—generally from <strong>age 60 onwards</strong>, depending on the product terms and tax regulations. The key rules include:</p>
<ul>
<li><p>You may start receiving lijfrente payments at <strong>age 60</strong> if the product contract permits and the minimum payout duration is met (typically 20 years for early retirement).</p>
</li>
<li><p>If you wait until your official <strong>AOW age</strong>, you may structure shorter payout periods, often between 5 and 20 years, depending on your total pension capital.</p>
</li>
<li><p>Starting payouts earlier reduces the total investment growth potential but can provide flexibility for those retiring early.</p>
</li>
</ul>
<h3 id="heading-how-withdrawals-work-lijfrente-uitkeringen">How Withdrawals Work (Lijfrente Uitkeringen)</h3>
<p>At retirement, your accumulated lijfrente capital must be converted into <strong>periodic annuity payments (uitkeringen)</strong>. This is done by purchasing a lijfrente uitkeringsproduct from an insurer or bank. You cannot take a lump sum withdrawal (except under strict conditions, such as very small balances).</p>
<p>Once payouts begin, the capital is gradually distributed and taxed, completing the cycle of tax deferral that began when you made your initial contributions.</p>
<h1 id="heading-pension-providers">Pension providers</h1>
<p>Here are some pension providers you can go with:</p>
<h3 id="heading-degiro-pension-account">Degiro Pension account</h3>
<p>You can use <a target="_blank" href="https://www.degiro.nl/pensioenrekening">Degiro Pension account</a> and invest in assets(stocks, ETFs, bonds) of your choice. This is what I personally use at the moment. The costs are a bit <a target="_blank" href="https://www.degiro.nl/pensioenrekening/lage-tarieven">higher than non pension account</a> though.</p>
<h3 id="heading-other-providers">Other providers</h3>
<p>These are some other providers that I don’t have personal experience with:</p>
<ul>
<li><p><a target="_blank" href="https://brightpensioen.nl/pensioen/fiscaal-vriendelijk-pensioen-opbouwen/">Bright pensioen</a></p>
</li>
<li><p><a target="_blank" href="https://www.meesman.nl/onze-rekeningen/pensioenrekening/">Meesman</a></p>
</li>
<li><p><a target="_blank" href="https://new.brandnewday.nl/pensioenrekening-beleggen/">Brand new day</a></p>
</li>
</ul>
<h1 id="heading-conclusion">Conclusion</h1>
<p>The Dutch pension system is a finely balanced framework that rewards long-term planning and disciplined saving. Its combination of state support, employer participation, and individual flexibility allows residents to build a reliable income stream for retirement. However, it also demands awareness—understanding how the pillars interact, how tax advantages work, and how restrictions like illiquidity can affect access to funds.</p>
<p>By strategically using the third pillar’s tax benefits, maintaining diversification through personal savings in the fourth pillar, and planning around life events and retirement goals, individuals can achieve both security and flexibility. In short, the Dutch system works best for those who actively engage with it—monitoring contributions, adjusting as life changes, and optimizing within the rules to ensure a comfortable and sustainable retirement.</p>
]]></content:encoded></item><item><title><![CDATA[Speed Matters: How Amazon.com Achieves Lightning-Fast Page Loads]]></title><description><![CDATA[In this article, I want to go over how amazon.com is optimizing their page load performance and how you can benefit from some of the strategies that they’re using.
Why amazon.com? As of writing this article, Amazon has a lighthouse score of 97 on per...]]></description><link>https://blog.debugpai.com/speed-matters-how-amazoncom-achieves-lightning-fast-page-loads</link><guid isPermaLink="true">https://blog.debugpai.com/speed-matters-how-amazoncom-achieves-lightning-fast-page-loads</guid><category><![CDATA[page load speed]]></category><category><![CDATA[Case Study]]></category><category><![CDATA[Core Web Vitals]]></category><category><![CDATA[SEO]]></category><category><![CDATA[conversion]]></category><category><![CDATA[sustainability]]></category><dc:creator><![CDATA[Deepak Pai]]></dc:creator><pubDate>Tue, 26 Aug 2025 11:19:52 GMT</pubDate><content:encoded><![CDATA[<p>In this article, I want to go over how <a target="_blank" href="http://amazon.com">amazon.com</a> is optimizing their page load performance and how you can benefit from some of the strategies that they’re using.</p>
<p>Why <a target="_blank" href="http://amazon.com">amazon.com</a>? As of writing this article, Amazon has a lighthouse score of 97 on performance. Also e-commerce websites are more sensitive to conversion and retention metrics so I thought this was a good example for other websites in the same domain.</p>
<p><strong>Disclaimer:</strong> I do not work at amazon and am not aware of their internals, this is the information I gathered by auditing their website.</p>
<h1 id="heading-why-is-performance-important">Why is performance important?</h1>
<ul>
<li><p><strong>Conversion and retention:</strong> <a target="_blank" href="https://nitropack.io/blog/post/web-performance-matters-case-studies">Multiple studies</a> have shown how bad page performance negatively affect conversion and retention rates. This is especially noticeable with users with older mobile phones.</p>
</li>
<li><p><strong>SEO:</strong> Google has started tracking <a target="_blank" href="https://developers.google.com/search/docs/appearance/core-web-vitals">Core web vitals</a> metrics and penalizing websites that score poorly</p>
</li>
<li><p><strong>Caring about your users:</strong> Having a page that loads fast shows that you care about the user experience.</p>
</li>
<li><p><strong>Brand value:</strong> A website with a smooth experience that loads fast creates a perception of quality</p>
</li>
<li><p><strong>Environment:</strong> A page that loads fast consumes less resources (low energy consumption, support for older hardware, less server cost).</p>
</li>
</ul>
<h1 id="heading-the-methodology">The methodology</h1>
<p>I use <a target="_blank" href="https://developer.chrome.com/docs/devtools#performance">Google Chrome dev tools</a> for everything I’m demonstrating in this article. I’ll go over techniques to optimize for the following metrics:</p>
<ul>
<li><p>Time to first byte (TTFB)</p>
</li>
<li><p>First contentful paint (FCP)</p>
</li>
<li><p>Largest contentful paint (LCP)</p>
</li>
<li><p>Cumulative Layout Shift (CLS)</p>
</li>
</ul>
<h1 id="heading-time-to-first-byte-ttfb">Time to first byte (TTFB)</h1>
<p>This is the time from when a user first requests a page (clicks on a link or types in the URL) to when the first byte of data returns to the browser from the server.</p>
<h2 id="heading-how-to-measure">How to measure?</h2>
<p>An easy way to do this is to go to the chrome network tab, click on the entry for the document (html) of the page and go to the timing tab.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756130632168/9c22890c-6d51-48d6-a116-9b320c47f21e.png" alt="Here you will see how much time was spent waiting for server response before the content started to download." class="image--center mx-auto" /></p>
<p>Here you will see how much time was spent waiting for server response before the content started to download.</p>
<p>There could be other entries here as well like DNS lookup, initial connection, SSL, etc.</p>
<h2 id="heading-strategies-to-reduce-ttfb">Strategies to reduce TTFB</h2>
<p>Reducing TTFB is mostly a matter of getting your server to return the HTML document as fast as possible.</p>
<ul>
<li><p><strong>Minimal amount of data calls</strong></p>
<p>  For your server rendered HTML, keep the backend data calls as few as possible. You can render a skeleton of your page and fetch the rest of the data on the client side. We will dive deeper into progressive loading later</p>
</li>
<li><p><strong>Compression</strong></p>
<p>  Use gzip or brotli for compressing your HTML so fewer bytes have to be transferred over the network. Your web server mostly supports this already, you would just have to enable this</p>
<p>  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756132771281/849ad489-7494-4a7c-bd36-bcb71034af3f.png" alt="the response header of html would have Content-Encoding: gzip when compression is enabled" /></p>
<p>  the response header of html would have Content-Encoding: gzip when compression is enabled</p>
</li>
<li><p><strong>Caching</strong></p>
<p>  This would not apply to websites where the content changes frequently or is personalized per user. If your content remains stable for at least 10 minutes then there might be value for you in enabling caching at HTML level.</p>
</li>
</ul>
<h1 id="heading-first-contentful-paint-fcp">First contentful paint (FCP)</h1>
<p>This is TTFB plus time taken until the first content (text, image, or non-white canvas or SVG) is rendered on the page. In this section we will focus on the time from TTFB until when the first content is rendered on the page.</p>
<p>Before we get into strategies on how to reduce FCP, it would help to familiarize ourselves on the <a target="_blank" href="https://web.dev/learn/performance/understanding-the-critical-path">critical rendering path</a>. On a high level keep the following in mind:</p>
<ul>
<li><p>HTML document is processed and rendered in a streaming fashion. The content received is immediately displayed</p>
</li>
<li><p>CSS and JS are render blocking resources (by default). When a browser encounters these, rendering is stopped until this resource is downloaded, parsed and executed.</p>
</li>
<li><p>JS is parser blocking (by default). When a browser encounters JS, it parses and executes it and is not able to parse any other resource at the same time. Render is also blocked during this phase.</p>
</li>
</ul>
<h2 id="heading-how-to-measure-1">How to measure?</h2>
<p>For this we would have to look at the Performance tab in chrome dev tools and manually look at the frames section.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756132863159/d820ef58-8c50-4337-aaf3-bbd5560b7c9d.png" alt="example of measuring FCP" /></p>
<ol>
<li><p>In performance tool hit the “Record and reload” button on top.</p>
</li>
<li><p>Make sure you enable screenshots</p>
</li>
<li><p>You can open the frames section and you can select the frame you consider to be the FCP for your users</p>
</li>
<li><p>In the summary section at the bottom you can see the frame and the time it took to show it (in Amazon’s case it is 583ms)</p>
</li>
</ol>
<h2 id="heading-strategies-to-reduce-fcp">Strategies to reduce FCP</h2>
<ul>
<li><p><strong>Resource hints</strong></p>
<p>  Add <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/Performance/Guides/dns-prefetch">dns-prefetch</a> for resources on cross domain resources (css, fonts, analytics api). You can also explore other resource hints like <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Attributes/rel/preconnect">preconnect</a>, <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Attributes/rel/preload">preload</a> and <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Attributes/rel/dns-prefetch">prefetch</a></p>
<p>  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756132905163/17069288-5181-4c30-9f24-558fe11abdc2.png" alt="dns-prefetch example" /></p>
<p>  you can see here that <code>dns-prefetch</code> is being used at the beginning of the document before loading resources from those domains</p>
</li>
<li><p><strong>Lean head tag</strong></p>
<p>  The content usually would live in the <code>&lt;body&gt;</code> section of the page. The <code>&lt;head&gt;</code> section should only contain metadata, critical CSS and JS. Keep this as lean as possible. If you have a lot of CSS and JS here then it would block the rendering before content in <code>&lt;body&gt;</code> can be displayed.</p>
</li>
<li><p><strong>Server side rendering</strong></p>
<p>  If you rely on content to be rendered only on client side then this the user will need to wait until the JS is downloaded, parsed and executed.</p>
</li>
<li><p><strong>Asset optimization</strong></p>
<p>  By assets here I primarily mean JS and CSS. But you could also apply some of these strategies for fonts and images as well. There are a bunch of strategies here. I would just mention them at a high level without going into too much detail.</p>
<ul>
<li><p>Leverage CDN for hosting</p>
</li>
<li><p>Caching your assets</p>
</li>
<li><p>Minification</p>
</li>
<li><p>Compression (gzip or brotli). In case of assets, do this at build time as opposed to runtime</p>
</li>
<li><p>Only loading the data you need (<a target="_blank" href="https://blog.debugpai.com/dead-code-elimination-in-javascript">dead code elimination</a>, remove unused css, etc)</p>
</li>
</ul>
</li>
</ul>
<p>    <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756132973024/ccf8cdcd-c9e4-41d1-9bdb-d28850236b48.png" alt="how amazon uses CDN, compression and caching for its assets" /></p>
<p>    How amazon uses CDN, compression and caching for its assets</p>
<ul>
<li><p><strong>Progressive loading</strong></p>
<p>  You can load a placeholder first and progressively load your page. Amazon first loads a skeleton of the page, then it progressively loads more frames.</p>
<p>  new</p>
<ul>
<li><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756133455726/9f2ae5ef-24e9-4ebd-8144-77197aed2404.gif" alt="we can see how amazon first loads a skeleton then proceeds to populate the contents of the page. (The video is taken from the frames section of the performance tab in dev tools.)" /></p>
<p>  we can see how amazon first loads a skeleton then proceeds to populate the contents of the page. (The video is taken from the frames section of the performance tab in dev tools.)</p>
</li>
</ul>
</li>
<li><p><strong>Async and Defer attributes</strong></p>
<p>  Use this to prevent non-critical javascript from blocking the rendering of the page. <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/script#async_and_defer">More details</a></p>
<p>  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756140403307/05e74139-ab12-433e-8286-076ec095cb7e.png" alt="demonstration of how amazon is using async/defer attributes" /></p>
</li>
</ul>
<h1 id="heading-largest-contentful-paint-lcp">Largest Contentful Paint (LCP)</h1>
<p>LCP measures when the largest content element in the viewport becomes visible to the user. This metric is important because it represents when the main content of a page is likely visible to users, directly affecting their perception of site speed.</p>
<h2 id="heading-how-to-measure-2">How to measure?</h2>
<p>You can measure LCP in Chrome DevTools by looking at the Performance tab. The LCP is marked in the experience section, typically showing the largest image or text block on your page.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756140462777/b1a322e8-4fbf-45a7-86db-4e466ff6208d.png" alt="you can see how LCP &lt; 0.58s here" /></p>
<p>you can see how LCP &lt; 0.58s here</p>
<h2 id="heading-strategies-to-reduce-lcp">Strategies to reduce LCP</h2>
<ul>
<li><p><strong>Prioritize above-the-fold content</strong></p>
<p>  Ensure the largest content element (often hero images) loads as quickly as possible by optimizing and prioritizing it.</p>
</li>
<li><p><strong>Image optimization</strong></p>
<p>  There are multiple strategies here:</p>
<ul>
<li><p>Image size matching: display the image at its original size (so the browser doesn’t have to resize)</p>
</li>
<li><p>Use <code>srcset</code> attribute to fetch different resolutions for different devices</p>
</li>
<li><p>Use <code>webp</code> images else <code>png</code> since they’re more optimized for web</p>
</li>
<li><p>Compression: Tools like <a target="_blank" href="https://squoosh.app/">Squoosh</a> and <a target="_blank" href="https://imageoptim.com/">ImageOptim</a> can help here</p>
</li>
</ul>
</li>
<li><p><strong>Lazy loading</strong></p>
<p>  Only load images that appear below the fold when the user scrolls down to them. Note that you should NOT lazy load LCP elements.</p>
</li>
</ul>
<h1 id="heading-cumulative-layout-shift-cls">Cumulative Layout Shift (CLS)</h1>
<p>This measures visual stability. It quantifies how much elements on a page unexpectedly shift during loading, which can lead to a frustrating user experience when content moves just as users try to interact with it.</p>
<h2 id="heading-how-to-measure-3">How to measure?</h2>
<p>CLS can be measured in Chrome DevTools under the Performance tab.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1756140509957/3595750d-cdd4-40ff-bf9e-e6438fc5f1fa.png" alt="CLS in performance tab" /></p>
<p>You can explore layout shifts in the experience section.</p>
<h2 id="heading-strategies-to-reduce-cls">Strategies to reduce CLS</h2>
<ul>
<li><p><strong>Reserve space for dynamic content</strong></p>
<p>  Amazon pre-allocates space for images, ads, and other dynamic elements to prevent layout shifts as these elements load.</p>
</li>
<li><p><strong>Use width and height attributes</strong></p>
<p>  Always specify dimensions for images, videos, and other media to help the browser allocate the correct amount of space before they load.</p>
</li>
<li><p><strong>Avoid inserting content above existing content</strong></p>
<p>  Place new elements at the bottom of the viewport instead of pushing existing content down, which creates disruptive layout shifts.</p>
</li>
</ul>
<h1 id="heading-final-thoughts">Final thoughts</h1>
<p>Help make web leaner and better. Using the above techniques, you should strive for these targets:</p>
<ul>
<li><p>TTFB &lt;0.8s</p>
</li>
<li><p>FCP &lt;1.8s</p>
</li>
<li><p>LCP &lt;2.5s</p>
</li>
<li><p>CLS &lt;0.1</p>
</li>
</ul>
<h3 id="heading-i-also-offer-a-performance-optimization-service-if-youre-interested-you-can-contact-me-herehttpswwwdebugpaicomcontact">I also offer a Performance Optimization service. If you’re interested you can <a target="_blank" href="https://www.debugpai.com/#contact">contact me here</a>.</h3>
]]></content:encoded></item><item><title><![CDATA[Understanding how Apollo Cache normalizes data]]></title><description><![CDATA[Apollo uses a cache layer for its queries. By default, before executing a query, first the cache is accessed and if its not present in the cache then it makes a network call. This is called the cache-first fetch policy. You can find other fetch polic...]]></description><link>https://blog.debugpai.com/learn-apollo-cache-normalization</link><guid isPermaLink="true">https://blog.debugpai.com/learn-apollo-cache-normalization</guid><category><![CDATA[Apollo GraphQL]]></category><category><![CDATA[GraphQL]]></category><category><![CDATA[data]]></category><dc:creator><![CDATA[Deepak Pai]]></dc:creator><pubDate>Sun, 06 Dec 2020 12:08:26 GMT</pubDate><content:encoded><![CDATA[<p>Apollo uses a cache layer for its queries. By default, before executing a query, first the cache is accessed and if its not present in the cache then it makes a network call. This is called the <code>cache-first</code> fetch policy. You can find other fetch policies <a target="_blank" href="https://www.apollographql.com/docs/react/data/queries/#setting-a-fetch-policy">here</a>. </p>
<p>Before storing the data in memory, Apollo <code>InMemoryCache</code> processes the data using a technique called normalization. In this article we would look at what normalization means and what it means in the context of Apollo and GraphQL.</p>
<h2 id="what-is-normalization-anyway">What is normalization anyway?</h2>
<p>Normalization is an approach of eliminating data redundancy. It is an approach to make sure that there is only 1 record of 1 data. It is a concept originally from databases and is being ported to frontend. <a target="_blank" href="https://github.com/paularmstrong/normalizr">normalizr</a> was the first library that popularized using normalization for data management in frontend. It was used mostly with <a target="_blank" href="https://redux.js.org/">redux</a>. Now it is also being used in Apollo with <code>InMemoryCache</code>.</p>
<p>Let us try looking at an example to understand what is normalization better. Consider a query <code>Product</code> in an e-commerce site that has the fields <code>name</code>, <code>seller</code> and <code>brand</code>.</p>
<p>This would look like this in a table </p>
<table>
<thead>
<tr>
<td>id</td><td>name</td><td>seller</td><td>brand</td></tr>
</thead>
<tbody>
<tr>
<td>1</td><td>iPhone 12</td><td>T-Mobile</td><td>Apple</td></tr>
<tr>
<td>2</td><td>Cheetos</td><td>SnackCompany</td><td>Lay's</td></tr>
<tr>
<td>3</td><td>Apple Watch 6</td><td>AccessoryBar</td><td>Apple</td></tr>
<tr>
<td>4</td><td>Galaxy S</td><td>T-Mobile</td><td>Samsung</td></tr>
</tbody>
</table>
<p>As we can see here that the seller <code>T-Mobile</code> and brand <code>Apple</code> are being repeated.</p>
<p>Having these duplicate instances of the same data can lead to the following problems:</p>
<ul>
<li>Suppose each seller has a verified status next to their account. And for products with verified sellers we show an icon next to it. If for example <code>T-Mobile</code> became a verified seller. Then we would need to update all the products with this information. This is also called Updation anomaly</li>
<li>By normalizing data and preventing redundancy, we save a lot of memory space. If your app is being server side rendered, this would also mean fewer bytes transferred over the network.</li>
</ul>
<p>We can prevent this duplication by having only a reference to the seller/brand. This would look like the following in a table. Instead of storing duplicates of the same data, we just store a reference to the data. In databases this concept is called foreign keys. </p>
<table>
<thead>
<tr>
<td>id</td><td>name</td><td>seller</td><td>brand</td></tr>
</thead>
<tbody>
<tr>
<td>1</td><td>iPhone 12</td><td>seller#17</td><td>brand#13</td></tr>
<tr>
<td>2</td><td>Cheetos</td><td>seller#21</td><td>brand#45</td></tr>
<tr>
<td>3</td><td>Apple Watch 6</td><td>seller#64</td><td>brand#13</td></tr>
<tr>
<td>4</td><td>Galaxy S</td><td>seller#17</td><td>brand#15</td></tr>
</tbody>
</table>
<h2 id="normalization-in-apollo">Normalization in apollo</h2>
<p>Let us now see how this looks like in apollo. If we want to fetch products we would have a query like this:</p>
<pre><code><span class="hljs-section">Product</span> {
    <span class="hljs-attribute">id</span>
    name
    seller {
        <span class="hljs-attribute">id</span>
        name
    }
    brand {
        <span class="hljs-attribute">id</span>
        name
    }
}
</code></pre><p>When we fetch this data, the contents of <code>InMemoryCache</code> looks like this: (Apollo DevTools: <a target="_blank" href="https://addons.mozilla.org/en-US/firefox/addon/apollo-developer-tools/">Firefox</a> | <a target="_blank" href="https://chrome.google.com/webstore/detail/apollo-client-developer-t/jdkknkkbebbapilgoeccciglkfbmbnfm">Chrome</a>)</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1606237755773/JKQmRbRQ5.png" alt="product-cache-overzicht" /></p>
<p>In the above image you can see how apollo cache stores the query data it receives internally. The cache has an entry for each <code>Product</code>. It also makes a separate entry for each <code>Seller</code> and <code>Brand</code>. </p>
<p>Note at the root level, it has a reference to all the products. Not the actual product itself.</p>
<p>This is how the <code>Product</code>, <code>Seller</code> and <code>Brand</code> look like</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1607254978519/RNtr0bmEZ.png" alt="Product" /> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1607254984178/Aa3eH5kZd.png" alt="Seller" /> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1607254988482/X7X4A93KS.png" alt="Brand" /></p>
<p>Note how the <code>Product</code> has a reference to <code>Seller</code> and <code>Brand</code>.</p>
<p>Now if any information about a <code>Seller</code> or <code>Brand</code> is updated; it is automatically available to all queries that are using it. This is the benefit of normalization since there are no duplicate references of the same data.</p>
<h2 id="caveat">Caveat</h2>
<p>This only works if you query for the <code>id</code> of <code>Seller</code> and <code>Brand</code>. Consider you query for the data like this without ids: </p>
<pre><code><span class="hljs-section">Product</span> {
    <span class="hljs-attribute">name</span>
    seller {
        <span class="hljs-attribute">name</span>
    }
    brand {
        <span class="hljs-attribute">name</span>
    }
}
</code></pre><p>For the above query notice how the data is not normalized. You can see how each there is only a <code>ROOT_QUERY</code> and all data are stored in a large JSON.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1607254215716/KBXd8nbWV.png" alt="not-normalized-cache" /></p>
<h3 id="what-to-do-if-id-is-not-present">What to do if id is not present?</h3>
<p>You should always try to query an id if it is available in the server. You can try enforcing it by using <a target="_blank" href="https://github.com/apollographql/eslint-plugin-graphql#required-fields-validation-rule">graphql/required-fields</a> eslint rule. </p>
<p>It can happen that your server doesn't send a unique id for a field or it sends it with a different name. In that case always try to first see if an id can be first sent from the server. If this is not possible, you can generate one on the client side by <a target="_blank" href="https://www.apollographql.com/docs/react/caching/cache-configuration/#customizing-identifier-generation-by-type">customizing identifier generation by type</a>. You can use a field with a different name than the default <code>id</code> or <code>_id</code>. You can also generate the identifiers using 1 or more fields. If you want to know how to do this at runtime check out my other article on <a target="_blank" href="https://debugpai.com/defining-type-policies-during-runtime-in-apollo">defining type policies during runtime in apollo</a></p>
<h2 id="conclusion">Conclusion</h2>
<p>I hope you got a better idea about how apollo cache works under the hood, what is normalization and why it is useful. You can use apollo dev tools to make sure that the data you are fetching in your application is normalized. If it is not, you only have to make sure that the fields have a unique <code>id</code> field. For more information check out the references below</p>
<h2 id="references">References</h2>
<ul>
<li><a target="_blank" href="https://www.apollographql.com/blog/demystifying-cache-normalization/">Demystifying Cache Normalization</a> by <a target="_blank" href="https://khalilstemmler.com/">Khalil Stemmler</a></li>
<li><a target="_blank" href="https://www.studytonight.com/dbms/database-normalization.php">How Data normalization works</a></li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Aliasing Preact correctly for Server Side Rendering]]></title><description><![CDATA[React has become the most modern front end library. However there is a pretty big disadvantage of using it. react and react-dom library together make up 38.6kB minified and gzipped (version 16.13.1). This is quite a significant cost to pay on mobile ...]]></description><link>https://blog.debugpai.com/aliasing-preact-correctly-for-server-side-rendering</link><guid isPermaLink="true">https://blog.debugpai.com/aliasing-preact-correctly-for-server-side-rendering</guid><category><![CDATA[React]]></category><category><![CDATA[Preact]]></category><category><![CDATA[Server side rendering]]></category><category><![CDATA[webpack]]></category><dc:creator><![CDATA[Deepak Pai]]></dc:creator><pubDate>Sun, 08 Nov 2020 13:50:16 GMT</pubDate><content:encoded><![CDATA[<p>React has become the most modern front end library. However there is a pretty big disadvantage of using it. <code>react</code> and <code>react-dom</code> library together make up 38.6kB minified and gzipped (version 16.13.1). This is quite a significant cost to pay on mobile devices on slow internet connections. <a target="_blank" href="https://v8.dev/blog/cost-of-javascript-2019">This article by Addy Osmani</a> does a good job in highlighting the cost of javascript. <a target="_blank" href="https://preactjs.com/">Preact</a> is a fast 3kB alternative to React with the same modern API. It makes sense to use Preact if you want to optimize for first load time. However if you have a heavy application with a lot of user interactions, then react is more optimized.</p>
<p>Preact is lighter mostly because it doesn't ship <a target="_blank" href="https://reactjs.org/docs/events.html">synthetic events</a> that are bundled into <code>react-dom</code>. It tries to be as close to browser features as possible. <a target="_blank" href="https://preactjs.com/guide/v10/differences-to-react">These are all the differences</a> between react and preact.</p>
<h2 id="aliasing">Aliasing</h2>
<p>Aliasing with <code>preact/compat</code> is a good way to migrate your react app to start using preact without changing the source code. All you have to do is add <a target="_blank" href="https://webpack.js.org/configuration/resolve/#resolvealias">a new alias</a> like this to your webpack config</p>
<pre><code><span class="hljs-comment">// webpack.config.js</span>

<span class="hljs-keyword">const</span> webpackConfig = { 
  ...
  <span class="hljs-string">"resolve"</span>: { 
    <span class="hljs-string">"alias"</span>: { 
      <span class="hljs-string">"react"</span>: <span class="hljs-string">"preact/compat"</span>,
      <span class="hljs-string">"react-dom/test-utils"</span>: <span class="hljs-string">"preact/test-utils"</span>,
      <span class="hljs-string">"react-dom"</span>: <span class="hljs-string">"preact/compat"</span>,
      <span class="hljs-comment">// Must be below test-utils</span>
    }
  }
}
</code></pre><p>During bundling, whenever webpack encounters a file with <code>import ... from 'react'</code>, it swaps react to <code>preact/compat</code>. So <code>import React from 'react'</code> becomes <code>import React from 'preact/compat'</code> in the generated bundles. Note that this substitution happens not only for your code but also for the libraries that you're using. So for instance if you're using <code>react-redux</code>, all <code>react</code> imports in the library are swapped to use <code>preact</code>.</p>
<p>If you're using another bundler you can check the official docs <a target="_blank" href="https://preactjs.com/guide/v10/getting-started#aliasing-react-to-preact">here</a></p>
<h3 id="server-side-rendering">Server side rendering</h3>
<p>The above mentioned technique works well with client but you might face some problems if you're using server side rendering. This is especially true if you have any kind of an <a target="_blank" href="https://webpack.js.org/configuration/externals/">externals</a> setup in your webpack config. Externals allows for specifying specific libraries that you don't want included in your generated bundles. Webpack assumes that these would be available at runtime. </p>
<p>Server side rendered applications usually have a different bundling flow for the server than for the client. Thus different bundle(s) is generated for the server than the client. With server side rendered applications, it is a common practice to use <a target="_blank" href="https://github.com/liady/webpack-node-externals">node externals</a> which tells webpack not to include bundles in node_modules for the server bundles.
These are replaced with <code>require</code> statements which are then resolved by node's module resolution system at runtime.</p>
<p>This brings us a problem if we're aliasing with <code>preact/compat</code>. While aliasing client side modules, we're able to swap <code>react</code> with <code>preact/compat</code> for all dependencies. But when these modules are externalized, webpack no longer go through the dependencies and thus doesn't alias <code>preact/compat</code>. Whenever it encounters a dependency, it says its not my responsibility, let node handle it.</p>
<p>And node has no idea that it needs to swap <code>react</code> with <code>preact/compat</code>. We need to tell it how to correctly resolve <code>react</code>.</p>
<h4 id="enter-module-alias">Enter <code>module-alias</code></h4>
<p><a target="_blank" href="https://github.com/ilearnio/module-alias">module-alias</a> is a handy package that allows us to tell node to use <code>preact/compat</code>. It hooks into node's module resolution system and changes it according to our needs. We need to add this code to our application</p>
<pre><code><span class="hljs-keyword">const</span> moduleAlias = <span class="hljs-keyword">require</span>(<span class="hljs-string">'module-alias'</span>);
moduleAlias.addAlias(<span class="hljs-string">'react'</span>, <span class="hljs-string">'preact/compat/dist/compat.js'</span>);
moduleAlias.addAlias(<span class="hljs-string">'react-dom'</span>, <span class="hljs-string">'preact/compat/dist/compat.js'</span>);
</code></pre><p>Note that <code>moduleAlias</code> has to be added with <code>require</code> statement and not an <code>import</code>. This is because <code>import</code>s are not resolved synchronously. 
And we want <code>moduleAlias</code> to be executed synchronously before the rest of the code that references the aliased modules.</p>
<p>Also note that this has to be at the very beginning of your server execution for it to work.</p>
]]></content:encoded></item><item><title><![CDATA[Defining type policies during runtime in Apollo]]></title><description><![CDATA[Apollo InMemoryCache type policies are used to define field policies for local state, to customize identifier generation by type or to define a custom merge function for the cache.
The standard way of doing this is by defining the type policies durin...]]></description><link>https://blog.debugpai.com/defining-type-policies-during-runtime-in-apollo</link><guid isPermaLink="true">https://blog.debugpai.com/defining-type-policies-during-runtime-in-apollo</guid><category><![CDATA[Apollo GraphQL]]></category><category><![CDATA[JavaScript]]></category><dc:creator><![CDATA[Deepak Pai]]></dc:creator><pubDate>Mon, 26 Oct 2020 08:25:17 GMT</pubDate><content:encoded><![CDATA[<p>Apollo InMemoryCache type policies are used to define <a target="_blank" href="https://www.apollographql.com/docs/react/local-state/managing-state-with-field-policies/#defining">field policies for local state</a>, to <a target="_blank" href="https://www.apollographql.com/docs/react/caching/cache-configuration/#customizing-identifier-generation-by-type">customize identifier generation by type</a> or to <a target="_blank" href="https://www.apollographql.com/docs/react/caching/cache-field-behavior/#merging-arrays">define a custom merge function for the cache</a>.</p>
<p>The standard way of doing this is by defining the type policies during initialization of apollo client like this:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> apolloClient = <span class="hljs-keyword">new</span> ApolloClient({
    ...
    cache: <span class="hljs-keyword">new</span> InMemoryCache({
        <span class="hljs-attr">typePolicies</span>: {
            <span class="hljs-comment">// defining field policy for local state</span>
            <span class="hljs-attr">Article</span>: {
             <span class="hljs-comment">// Field policy map for the Article type</span>
                <span class="hljs-attr">fields</span>: {
                    <span class="hljs-comment">// Field policy for the isBookmarked field</span>
                    <span class="hljs-attr">isBookmarked</span>: {
                        <span class="hljs-comment">// The read function for the isBookmarked field</span>
                        read(_, { variables }) {
                            <span class="hljs-keyword">return</span> <span class="hljs-built_in">localStorage</span>
                              .getItem(<span class="hljs-string">'BOOKMARKS'</span>)
                              .includes(
                                 variables.articleId
                              );
                        }
                    }
                }
            },

            <span class="hljs-comment">// customizing identifier generation</span>
            <span class="hljs-attr">Book</span>: {
                <span class="hljs-attr">keyFields</span>: [<span class="hljs-string">"isbn"</span>],
            }


            <span class="hljs-comment">// defining custom merge function</span>
            <span class="hljs-attr">SearchResults</span>: {
                <span class="hljs-attr">fields</span>: {
                    <span class="hljs-attr">results</span>: {
                        merge(existing = [], <span class="hljs-attr">incoming</span>: any[]) {
                            <span class="hljs-keyword">return</span> [...existing, ...incoming];
                        },
                    }
                }
            }
        },
    });
})
</code></pre>
<p>This might not always be possible. You might want to do this at runtime instead. Some of these scenarios:</p>
<ol>
<li>If you are loading different chunks at runtime based on user interaction</li>
<li>You have a microfrontends architecture (like in our case).</li>
</ol>
<p>To do this you can follow these steps:</p>
<h3 id="1-get-an-instance-of-the-cache">1. Get an instance of the cache</h3>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> { loading, error, data, client } = useQuery(QUERY);

<span class="hljs-keyword">const</span> cache = client.cache
</code></pre>
<h3 id="2-add-policies-to-the-cache">2. Add policies to the cache</h3>
<p>To specify key fields for custom identifier generation</p>
<pre><code class="lang-js">cache.policies.addTypePolicies({
    <span class="hljs-comment">// customizing identifier generation</span>
    <span class="hljs-attr">Book</span>: {
        <span class="hljs-attr">keyFields</span>: [<span class="hljs-string">"isbn"</span>],
    }
})
</code></pre>
<p>Or to define field policy for local storage</p>
<pre><code class="lang-js">cache.policies.addTypePolicies({
    <span class="hljs-attr">Article</span>: {
        <span class="hljs-attr">fields</span>: { 
            <span class="hljs-attr">isBookmarked</span>: { 
                read(_, { variables }) { 
                    <span class="hljs-keyword">return</span> <span class="hljs-built_in">localStorage</span>
                      .getItem(<span class="hljs-string">'BOOKMARKS'</span>)
                      .includes(
                        variables.articleId
                      );
                }
            }
        }
    },
})
</code></pre>
<h2 id="caveat">Caveat</h2>
<p>The reason why it is recommended to configure these at build time is because that way apollo can ensure that the data is not accessed before the type policies are defined.
If you want to do this at runtime, you need to make sure that you call <code>addTypePolicies</code> before you call <code>useQuery</code> with the query that uses the type whose policy you are modifying</p>
]]></content:encoded></item><item><title><![CDATA[Dead Code Elimination in Javascript]]></title><description><![CDATA[Dead code elimination is a process wherein code that is not used is excluded from the code that is executed. In many compile time languages this is a much easier process since a compiler can easily determine the code that is used. However in javascri...]]></description><link>https://blog.debugpai.com/dead-code-elimination-in-javascript</link><guid isPermaLink="true">https://blog.debugpai.com/dead-code-elimination-in-javascript</guid><category><![CDATA[JavaScript]]></category><category><![CDATA[webpack]]></category><category><![CDATA[Developer]]></category><dc:creator><![CDATA[Deepak Pai]]></dc:creator><pubDate>Sat, 17 Oct 2020 14:59:20 GMT</pubDate><content:encoded><![CDATA[<p>Dead code elimination is a process wherein code that is not used is excluded from the code that is executed. In many compile time languages this is a much easier process since a compiler can easily determine the code that is used. However in javascript, this can be quite tricky since this clarity is not present.</p>
<p>There are several forms of dead code in javascript</p>
<ul>
<li>Unused source files</li>
<li>Environment specific code</li>
<li>Unused code in same file </li>
</ul>
<h2 id="unused-source-files">Unused source files</h2>
<p>In the early days of javascript this used to be a real problem since unused source files had to be manually cleaned up. But with modern bundlers this becomes a really easy process. If a file is not imported anywhere then it is automatically excluded from the resulting bundle. There are also some plugins like <a target="_blank" href="https://www.npmjs.com/package/unused-files-webpack-plugin">this one</a> which also help us to remove these from the codebase.</p>
<h2 id="environment-specific-code">Environment specific code</h2>
<p>In a real world app we have several environment specific code. These can be production, staging and development, mobile vs desktop or even domain specific logic. So when we build an app for production, we don't want to serve code to the user which is only used during development. </p>
<p>We can do this by using <a target="_blank" href="https://webpack.js.org/plugins/define-plugin/">define-plugin</a> in webpack or <a target="_blank" href="https://github.com/rollup/plugins/tree/master/packages/replace">plugin-replace</a> in rollup. </p>
<pre><code class="lang-js"><span class="hljs-comment">// webpack.config.js</span>
<span class="hljs-keyword">new</span> webpack.DefinePlugin({
  <span class="hljs-string">'process.env.NODE_ENV'</span>: <span class="hljs-built_in">JSON</span>.stringify(process.env.NODE_ENV)
});
</code></pre>
<p>(webpack 4 does this automatically. this is just for showing what happens under the hood)</p>
<pre><code class="lang-js"><span class="hljs-comment">// rollup.config.js</span>
<span class="hljs-attr">plugins</span>: [
  replace({ <span class="hljs-string">"process.env.NODE_ENV"</span>: <span class="hljs-built_in">JSON</span>.stringify(process.env.NODE_ENV) })
]
</code></pre>
<p>What this does is if you have code that looks like the following</p>
<pre><code class="lang-js"><span class="hljs-keyword">let</span> API_HOST;
<span class="hljs-keyword">if</span> (process.env.NODE_ENV === <span class="hljs-string">'production'</span>) {
    API_HOST = <span class="hljs-string">'production-host.mycompany.com'</span>;
} <span class="hljs-keyword">else</span> {
    API_HOST = <span class="hljs-string">'localhost:9000'</span>;
}
</code></pre>
<p>Given <code>NODE_ENV=production</code>, it converts it to the following</p>
<pre><code class="lang-js"><span class="hljs-keyword">if</span> (<span class="hljs-string">'production'</span> === <span class="hljs-string">'production'</span>) {
    API_HOST = <span class="hljs-string">'production-host.mycompany.com'</span>;
} <span class="hljs-keyword">else</span> {
    API_HOST = <span class="hljs-string">'localhost:9000'</span>;
}
</code></pre>
<p>Then the minifier removes the unreachable code, reducing it down to the following,</p>
<pre><code><span class="hljs-attr">API_HOST</span> = <span class="hljs-string">'production-host.mycompany.com'</span><span class="hljs-comment">;</span>
</code></pre><h3 id="caveat">Caveat</h3>
<p>This only works if you don't reassign the variable defined in the bundler config. In this case <code>process.env.NODE_ENV</code>.</p>
<p>So if we change the code like the following</p>
<pre><code class="lang-js"><span class="hljs-keyword">let</span> API_HOST;
<span class="hljs-keyword">const</span> IS_PROD = process.env.NODE_ENV === <span class="hljs-string">'production'</span>;
<span class="hljs-keyword">if</span> (IS_PROD) {
    API_HOST = <span class="hljs-string">'production-host.mycompany.com'</span>;
} <span class="hljs-keyword">else</span> {
    API_HOST = <span class="hljs-string">'localhost:9000'</span>;
}
</code></pre>
<p>Then the bundler will not be able to eliminate the dead code because it cannot know for sure the correct value of <code>IS_PROD</code> inside the if statement. Since the value could have changed after assignment of the variable and the if statement.</p>
<p>If you do want to use <code>IS_PROD</code> as a variable and have dead code elimination available then you can declare it in the plugin config like this:</p>
<pre><code class="lang-js"><span class="hljs-comment">// webpack.config.js</span>
<span class="hljs-keyword">new</span> webpack.DefinePlugin({
  <span class="hljs-string">'IS_PROD'</span>: process.env.NODE_ENV === <span class="hljs-string">'production'</span>
});
</code></pre>
<pre><code class="lang-js"><span class="hljs-comment">// rollup.config.js</span>
<span class="hljs-attr">plugins</span>: [
  replace({ <span class="hljs-string">'IS_PROD'</span>: process.env.NODE_ENV === <span class="hljs-string">'production'</span> })
]
</code></pre>
<h2 id="unused-code-in-same-file">Unused code in same file</h2>
<p>There are 2 kinds of unused code that can be part of the same file.</p>
<ul>
<li>Unused exports</li>
<li>Side effects</li>
</ul>
<p>This is the most difficult type of code to dead code eliminate because Javascript is not a compiled language. However modern bundlers are finding smart ways to do it. They use a technique called as <a target="_blank" href="https://webpack.js.org/guides/tree-shaking/">tree shaking</a> where they rely on static structure of ES Modules to achieve it.</p>
<h3 id="unused-exports">Unused Exports</h3>
<p>In modern web development, we use various libraries to get the job done. The problem however is that we don't need all the code that the library ships. </p>
<p>Consider a file like the following</p>
<pre><code class="lang-js"><span class="hljs-comment">// math.js</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">add</span> (<span class="hljs-params">x, y</span>) </span>{
    <span class="hljs-keyword">return</span> x + y;
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">subtract</span> (<span class="hljs-params">x, y</span>) </span>{
    <span class="hljs-keyword">return</span> x - y;
}
</code></pre>
<p>If we have another file where we import only one of the functions like</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> { subtract } <span class="hljs-keyword">from</span> <span class="hljs-string">'./math'</span>;

<span class="hljs-built_in">console</span>.log(subtract(<span class="hljs-number">3</span>, <span class="hljs-number">2</span>));
</code></pre>
<p>Then in the final resulting bundle only the <code>subtract</code> function is included. Add is excluded.</p>
<p>We can also combine this with Environment specific code which was highlighted in the previous section.</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> { subtract } <span class="hljs-keyword">from</span> <span class="hljs-string">'./math'</span>;

<span class="hljs-keyword">if</span> (process.env.NODE_ENV === <span class="hljs-string">'production'</span>) {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'This is production'</span>);
} <span class="hljs-keyword">else</span> {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Subtraction in dev mode only '</span> + subtract(<span class="hljs-number">1</span>, <span class="hljs-number">3</span>));
}
</code></pre>
<p>Here we are calling <code>subtract</code> function only in development. In cases like this, <code>subtract</code> is bundled only in development mode. In production mode, neither <code>add</code> nor <code>subtract</code> functions are bundled.</p>
<p>This is possible because ES modules are static in nature as opposed to <code>commonjs</code> modules which due to their dynamic nature makes it impossible for the bundler to determine which modules to tree shake.</p>
<pre><code class="lang-js"><span class="hljs-keyword">if</span> (process.env.NODE_ENV === <span class="hljs-string">'production'</span>) {
    <span class="hljs-built_in">require</span>(<span class="hljs-string">'./math.js'</span>).add(<span class="hljs-number">1</span>, <span class="hljs-number">2</span>);
} <span class="hljs-keyword">else</span> {
    <span class="hljs-built_in">require</span>(<span class="hljs-string">'./math.js'</span>).subtract(<span class="hljs-number">2</span>, <span class="hljs-number">3</span>)
}
</code></pre>
<p>This is the main reason why <a target="_blank" href="https://lodash.com/">lodash</a> which was based on commonjs modules created a new package <a target="_blank" href="https://github.com/lodash/lodash/tree/es">lodash-es</a> which is based on ES modules. This means that if we use only 1 function from <code>lodash-es</code> only that function will be bundled into our main bundle.</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> { reverse } <span class="hljs-keyword">from</span> <span class="hljs-string">'lodash-es'</span>;

<span class="hljs-built_in">console</span>.log(reverse([<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>]));
</code></pre>
<p>In the above example only the <code>reverse</code> function will be bundled into the code.</p>
<h3 id="side-effects">Side Effects</h3>
<p>There is a caveat to tree shaking and that is side effects. Side effects in terms of tree shaking is any code that changes global state or environment in some way. Examples can be polyfills and code in which css files are added. </p>
<p>Consider a polyfill for fetch like this</p>
<pre><code class="lang-js"><span class="hljs-comment">// fetchPolyfill.js</span>

<span class="hljs-built_in">window</span>.fetch = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">...</span>) </span>{ ... }
</code></pre>
<p>In the above file, fetch is being added to window object but its not being exported or imported from anywhere. Hence the bundler cannot know that this is used.
For these files where side effects are present, we need to explicitly specify them in <code>package.json</code></p>
<pre><code class="lang-json"><span class="hljs-string">"sideEffects"</span>: [
    './fetchPolyfill.js'
]
</code></pre>
<p>It is then bundled in the application like this:</p>
<pre><code class="lang-js">__webpack_require__.r(__webpack_exports__),(<span class="hljs-built_in">window</span>.fetch = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) ... )</span>
</code></pre>
<h3 id="vendor-dependencies">Vendor dependencies</h3>
<p>Before using any open source library in your package, you can go to <a target="_blank" href="https://bundlephobia.com/">bundlephobia</a> to verify if the package you are using is side effect free and tree shakeable.</p>
<h2 id="references">References</h2>
<ul>
<li><a target="_blank" href="https://developers.google.com/web/fundamentals/performance/optimizing-javascript/tree-shaking">Google blog reduce js payload with tree shaking</a></li>
</ul>
]]></content:encoded></item></channel></rss>