<?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" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
    <channel>
        
        <title>
            <![CDATA[ web performance - freeCodeCamp.org ]]>
        </title>
        <description>
            <![CDATA[ Browse thousands of programming tutorials written by experts. Learn Web Development, Data Science, DevOps, Security, and get developer career advice. ]]>
        </description>
        <link>https://www.freecodecamp.org/news/</link>
        <image>
            <url>https://cdn.freecodecamp.org/universal/favicons/favicon.png</url>
            <title>
                <![CDATA[ web performance - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Tue, 14 Jul 2026 11:19:28 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/news/tag/web-performance/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ How to Turn Performance Audits into AI Fix Prompts with a DevTools Extension ]]>
                </title>
                <description>
                    <![CDATA[ Performance tools are good at showing you what's slow. They can tell you that your Largest Contentful Paint is 4.2 seconds, your JavaScript bundle is too large, or an image below the fold is loading t ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-turn-performance-audits-into-ai-fix-prompts-with-a-devtools-extension/</link>
                <guid isPermaLink="false">6a3966d66a52acabf1b616a4</guid>
                
                    <category>
                        <![CDATA[ devtools ]]>
                    </category>
                
                    <category>
                        <![CDATA[ chrome extension ]]>
                    </category>
                
                    <category>
                        <![CDATA[ web performance ]]>
                    </category>
                
                    <category>
                        <![CDATA[ AI ]]>
                    </category>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Olamilekan Lamidi ]]>
                </dc:creator>
                <pubDate>Mon, 22 Jun 2026 16:46:14 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/uploads/covers/5e1e335a7a1d3fcc59028c64/70dc4877-86de-43ec-bdf5-9a6dc34b7bf1.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Performance tools are good at showing you what's slow. They can tell you that your Largest Contentful Paint is 4.2 seconds, your JavaScript bundle is too large, or an image below the fold is loading too early.</p>
<p>But they usually don't tell you the next info you need as a developer: <strong>What should I ask my coding agent to change?</strong></p>
<p>AI coding agents can help you fix performance issues, but they need clear context. If you type "make this site faster", you'll often get broad advice. If you give the agent the metric, the affected resource, the likely cause, and the files to inspect first, you have a much better chance of getting a useful patch.</p>
<p>In this tutorial, you'll learn how to turn a browser performance finding into a structured AI fix prompt. You'll also see how to add a "Copy AI fix prompt" button to a Chrome DevTools extension.</p>
<p>I'll use PerfLens, a Chrome DevTools extension I built, as the example. But the same pattern works with any tool that can collect performance data.</p>
<h2 id="heading-what-you-will-build">What You Will Build</h2>
<p>You'll build a small pipeline that looks like this:</p>
<pre><code class="language-text">Performance finding
  -&gt; Structured issue object
  -&gt; AI fix prompt
  -&gt; Clipboard
  -&gt; Coding agent
  -&gt; Code change
  -&gt; Re-run audit
</code></pre>
<p>By the end, you will have:</p>
<ul>
<li><p>A <code>Finding</code> type for storing audit results</p>
</li>
<li><p>A prompt builder function</p>
</li>
<li><p>A copy-to-clipboard function</p>
</li>
<li><p>A DevTools panel button that copies the generated prompt</p>
</li>
<li><p>A simple way to verify whether the fix worked</p>
</li>
</ul>
<h2 id="heading-prerequisites">Prerequisites</h2>
<p>To follow along, you should understand:</p>
<ul>
<li><p>Basic JavaScript or TypeScript</p>
</li>
<li><p>Basic browser extension concepts</p>
</li>
<li><p>How Chrome DevTools panels work at a high level</p>
</li>
<li><p>How to use an AI coding agent such as Cursor, Claude Code, GitHub Copilot, or a similar tool</p>
</li>
</ul>
<p>You don't need to build a full performance auditing engine for this tutorial. The focus is the handoff between a performance tool and a coding agent.</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ul>
<li><p><a href="#heading-why-performance-reports-are-hard-to-turn-into-code-changes">Why Performance Reports Are Hard to Turn into Code Changes</a></p>
</li>
<li><p><a href="#heading-what-an-ai-fix-prompt-should-include">What an AI Fix Prompt Should Include</a></p>
</li>
<li><p><a href="#heading-how-to-store-a-performance-finding-as-structured-data">How to Store a Performance Finding as Structured Data</a></p>
</li>
<li><p><a href="#heading-how-to-choose-the-most-important-finding">How to Choose the Most Important Finding</a></p>
</li>
<li><p><a href="#heading-how-to-build-the-ai-fix-prompt">How to Build the AI Fix Prompt</a></p>
</li>
<li><p><a href="#heading-how-to-copy-the-prompt-to-the-clipboard">How to Copy the Prompt to the Clipboard</a></p>
</li>
<li><p><a href="#heading-how-to-add-the-button-to-a-devtools-panel">How to Add the Button to a DevTools Panel</a></p>
</li>
<li><p><a href="#heading-how-to-verify-the-fix">How to Verify the Fix</a></p>
</li>
<li><p><a href="#heading-how-this-fits-alongside-lighthouse">How This Fits Alongside Lighthouse</a></p>
</li>
<li><p><a href="#heading-conclusion">Conclusion</a></p>
</li>
</ul>
<h2 id="heading-why-performance-reports-are-hard-to-turn-into-code-changes">Why Performance Reports Are Hard to Turn into Code Changes</h2>
<p>A performance score is a symptom. For example, a report might say:</p>
<pre><code class="language-text">Largest Contentful Paint: 4.2 seconds
</code></pre>
<p>That number matters, but it doesn't tell you where the fix lives.</p>
<p>The cause might be:</p>
<ul>
<li><p>A large hero image</p>
</li>
<li><p>A render-blocking script</p>
</li>
<li><p>Too much JavaScript on the initial route</p>
</li>
<li><p>A slow API request</p>
</li>
<li><p>Missing image dimensions that cause layout shift</p>
</li>
</ul>
<p>As a developer, you usually have to translate the report into a code-level task.</p>
<p>That translation step takes time. It's also the step where a coding agent can help most, if you give it enough context.</p>
<p>Instead of asking your agent to "make the site faster", you can give it a focused brief:</p>
<pre><code class="language-text">The homepage has a 258.1 KB image affecting load performance.
Inspect the hero section and image component first.
Resize or compress the image without changing the layout.
Then explain how to verify the improvement.
</code></pre>
<p>This is easier for the agent to act on because it points to one specific problem.</p>
<h2 id="heading-what-an-ai-fix-prompt-should-include">What an AI Fix Prompt Should Include</h2>
<p>A good AI fix prompt should read like a short engineering brief.</p>
<p>It should include:</p>
<ul>
<li><p>The performance problem</p>
</li>
<li><p>The measured evidence</p>
</li>
<li><p>The affected page or resource</p>
</li>
<li><p>The likely cause</p>
</li>
<li><p>The files or patterns to inspect first</p>
</li>
<li><p>A recommended fix</p>
</li>
<li><p>Constraints for the change</p>
</li>
<li><p>Verification steps</p>
</li>
</ul>
<p>Here is an example prompt:</p>
<pre><code class="language-text">You are helping optimize a Next.js app in a production build.

Problem: Image is 258.1 KB and may be slowing down the page.
Evidence: Image size = 258.1 KB
Page: http://localhost:3000
Affected resource: http://localhost:3000/_next/image?url=%2Fhome%2Four_story.webp&amp;w=3840&amp;q=75

Likely cause:
The page is loading an image that is larger than needed for its rendered size.

Inspect first:
- app/page.tsx or pages/index.tsx
- components/**/*.{tsx,jsx}
- next.config.js
- the hero section or image component

Recommended fix:
Resize or compress the image, use an appropriate modern format, and keep explicit width and height values so the layout does not shift.

Constraints:
- Keep the change local to the route or component causing the issue.
- Do not add a new dependency unless there is no reasonable alternative.
- Explain the change before applying it.

After the change:
- Re-run the performance audit.
- Confirm the image transfer size is lower.
- Confirm the layout still looks correct.
</code></pre>
<p>This prompt is specific. It tells the agent what happened, where to look, what to change, and how to check the result.</p>
<p>That's the core idea behind an AI patch brief.</p>
<p>Here is what that looks like inside PerfLens. A single performance finding is rendered as an AI patch brief, with the measured value, the affected resource, and the generated prompt gathered in one place. The "Copy AI fix prompt" button then hands the whole brief off to your coding agent in one click.</p>
<img src="https://cdn.hashnode.com/uploads/covers/69daa79bc8e5007ddbe1b633/2f5fa3ec-f3c1-44d0-b53b-3ce37fac65e9.png" alt="PerfLens screenshot" style="display:block;margin:0 auto" width="2652" height="1024" loading="lazy">

<h2 id="heading-how-to-store-a-performance-finding-as-structured-data">How to Store a Performance Finding as Structured Data</h2>
<p>Before you can build a prompt, you need to store the performance issue as data.</p>
<p>Here is a simple TypeScript type:</p>
<pre><code class="language-typescript">type Finding = {
  id: string;
  title: string;
  metric: string;
  measured: string;
  budget?: string;
  resource?: string;
  likelyCause: string;
  recommendedFix: string;
  inspectFirst: string[];
  severity: "low" | "medium" | "high";
};
</code></pre>
<p>Each field has a job:</p>
<ul>
<li><p><code>id</code> identifies the type of issue.</p>
</li>
<li><p><code>title</code> gives the human-readable summary.</p>
</li>
<li><p><code>metric</code> names the measurement.</p>
</li>
<li><p><code>measured</code> stores the actual value.</p>
</li>
<li><p><code>budget</code> stores the target value, if you have one.</p>
</li>
<li><p><code>resource</code> stores the affected URL, file, or asset.</p>
</li>
<li><p><code>likelyCause</code> explains why the issue may be happening.</p>
</li>
<li><p><code>recommendedFix</code> gives the agent a direction.</p>
</li>
<li><p><code>inspectFirst</code> points the agent toward likely files.</p>
</li>
<li><p><code>severity</code> helps you decide what to show first.</p>
</li>
</ul>
<p>Here is an example finding for an oversized image:</p>
<pre><code class="language-typescript">const finding: Finding = {
  id: "image-weight",
  title: "Image is 258.1 KB and may be slowing down the page",
  metric: "Image size",
  measured: "258.1 KB",
  resource: "http://localhost:3000/_next/image?url=%2Fhome%2Four_story.webp&amp;w=3840&amp;q=75",
  likelyCause:
    "The page is loading an image that is larger than needed for its rendered size.",
  recommendedFix:
    "Resize or compress the image, use an appropriate modern format, and keep explicit width and height values.",
  inspectFirst: [
    "app/page.tsx or pages/index.tsx",
    "components/**/*.{tsx,jsx}",
    "next.config.js",
    "the hero section or image component",
  ],
  severity: "high",
};
</code></pre>
<p>At this stage, you aren't doing anything with AI yet. You're only turning a performance result into a clean object.</p>
<p>That object gives you something reliable to transform into a prompt later.</p>
<h2 id="heading-how-to-choose-the-most-important-finding">How to Choose the Most Important Finding</h2>
<p>You should avoid sending ten unrelated performance issues to an agent at once.</p>
<p>A large prompt with many issues can lead to a large patch. That makes the result harder to review.</p>
<p>A better approach is to generate one prompt per finding.</p>
<p>You can start with a simple severity score:</p>
<pre><code class="language-typescript">function scoreFinding(finding: Finding): number {
  const severityWeight = {
    low: 1,
    medium: 2,
    high: 3,
  };

  return severityWeight[finding.severity];
}
</code></pre>
<p>Then you can sort findings by score:</p>
<pre><code class="language-typescript">function sortFindings(findings: Finding[]): Finding[] {
  return [...findings].sort(
    (a, b) =&gt; scoreFinding(b) - scoreFinding(a)
  );
}
</code></pre>
<p>This is a simple version, but it's enough to get started.</p>
<p>Later, you can improve the score by considering:</p>
<ul>
<li><p>How far the metric is over budget</p>
</li>
<li><p>Whether the issue affects Largest Contentful Paint</p>
</li>
<li><p>Whether the issue affects layout shift or interaction delay</p>
</li>
<li><p>Whether the affected resource is part of the first page load</p>
</li>
<li><p>How confident you are in the recommended fix</p>
</li>
</ul>
<p>The goal isn't to create a perfect scoring system. The goal is to help you focus on one high-impact issue at a time.</p>
<h2 id="heading-how-to-build-the-ai-fix-prompt">How to Build the AI Fix Prompt</h2>
<p>Once you have a <code>Finding</code>, building the prompt becomes a string formatting task.</p>
<p>You also need a small amount of page context:</p>
<pre><code class="language-typescript">type PageContext = {
  framework: string;
  mode: string;
  pageUrl: string;
};
</code></pre>
<p>Page context is a few facts about the page the finding came from: the framework the app uses, whether it's a development or production build, and the URL being audited.</p>
<p>The finding tells the agent <em>what</em> is slow. The page context tells it <em>where</em> the fix will land and <em>how</em> the code is built. This matters because the same problem is fixed differently from one stack to the next. An oversized image is handled through <code>next/image</code> and <code>next.config.js</code> in Next.js, but through other files and conventions elsewhere. The <code>mode</code> field also hints whether production optimizations should already be in place.</p>
<p>Giving the agent this up front means it spends less effort guessing about your setup and more on the actual fix.</p>
<p>Then you can create a prompt builder:</p>
<pre><code class="language-typescript">function buildFixPrompt(finding: Finding, ctx: PageContext): string {
  const lines = [
    "You are helping optimize a " + ctx.framework + " app in a " + ctx.mode + " build.",
    "",
    "Problem: " + finding.title,
    "Evidence: " + finding.metric + " = " + finding.measured +
      (finding.budget ? " (budget: " + finding.budget + ")" : ""),
    "Page: " + ctx.pageUrl,
  ];

  if (finding.resource) {
    lines.push("Affected resource: " + finding.resource);
  }

  lines.push(
    "",
    "Likely cause:",
    finding.likelyCause,
    "",
    "Inspect first:",
    ...finding.inspectFirst.map((file) =&gt; "- " + file),
    "",
    "Recommended fix:",
    finding.recommendedFix,
    "",
    "Constraints:",
    "- Keep the change local to the route or component causing the measured cost.",
    "- Do not add new dependencies unless there is no reasonable alternative.",
    "- Explain the change before applying it.",
    "",
    "After the change:",
    "- Re-run the performance audit.",
    "- Confirm the measured issue improved.",
    "- Check that the UI still works correctly.",
  );

  return lines.join("\n");
}
</code></pre>
<p>You can call it like this:</p>
<pre><code class="language-typescript">const pageContext: PageContext = {
  framework: "Next.js",
  mode: "production",
  pageUrl: "http://localhost:3000",
};

const prompt = buildFixPrompt(finding, pageContext);
</code></pre>
<p>The output is a prompt you can paste into a coding agent.</p>
<p>The <code>framework</code> field is especially useful. If the agent knows the app uses Next.js, it can look for files such as <code>app/page.tsx</code>, <code>pages/index.tsx</code>, <code>next.config.js</code>, and image usage through <code>next/image</code>.</p>
<h2 id="heading-how-to-copy-the-prompt-to-the-clipboard">How to Copy the Prompt to the Clipboard</h2>
<p>The safest integration is clipboard-first.</p>
<p>Many coding agents and editors support different launch methods. Some support deep links. Some run in the terminal. Some live inside an editor. But every agent can accept pasted text.</p>
<p>Here's a small copy function:</p>
<pre><code class="language-typescript">async function copyPrompt(prompt: string): Promise&lt;void&gt; {
  await navigator.clipboard.writeText(prompt);
}
</code></pre>
<p>In a browser extension UI, call this from a user action such as a button click:</p>
<pre><code class="language-typescript">copyButton.addEventListener("click", async () =&gt; {
  const prompt = buildFixPrompt(finding, pageContext);

  await copyPrompt(prompt);

  copyButton.textContent = "Prompt copied";
});
</code></pre>
<p>You can also try to open an editor after copying the prompt:</p>
<pre><code class="language-typescript">type AgentTarget = "cursor" | "vscode" | "copy-only";

async function sendToAgent(
  prompt: string,
  target: AgentTarget
): Promise&lt;void&gt; {
  await navigator.clipboard.writeText(prompt);

  if (target === "cursor") {
    window.location.href = "cursor://";
    return;
  }

  if (target === "vscode") {
    window.location.href = "vscode://";
    return;
  }
}
</code></pre>
<p>This doesn't paste the prompt into the agent automatically. It only copies the prompt and tries to open the selected tool.</p>
<p>That is a useful limitation. It keeps the workflow predictable and lets you review the prompt before sending it.</p>
<h2 id="heading-how-to-add-the-button-to-a-devtools-panel">How to Add the Button to a DevTools Panel</h2>
<p>If you build this into a Chrome extension, you can expose it inside a DevTools panel.</p>
<p>First, register a DevTools page in your <code>manifest.json</code> file:</p>
<pre><code class="language-json">{
  "manifest_version": 3,
  "name": "PerfLens",
  "version": "1.0.0",
  "devtools_page": "devtools.html",
  "permissions": ["clipboardWrite", "activeTab", "scripting"]
}
</code></pre>
<p>Then create the panel from your DevTools script:</p>
<pre><code class="language-typescript">chrome.devtools.panels.create(
  "PerfLens",
  "icons/icon-32.png",
  "panel.html"
);
</code></pre>
<p>Inside the panel, render each finding with a button:</p>
<pre><code class="language-typescript">function renderFinding(
  finding: Finding,
  ctx: PageContext
): HTMLElement {
  const item = document.createElement("article");
  const title = document.createElement("h3");
  const button = document.createElement("button");

  title.textContent = finding.title;
  button.textContent = "Copy AI fix prompt";

  button.addEventListener("click", async () =&gt; {
    const prompt = buildFixPrompt(finding, ctx);

    await sendToAgent(prompt, "copy-only");

    button.textContent = "Prompt copied";
  });

  item.append(title, button);

  return item;
}
</code></pre>
<p>The important part is the button handler.</p>
<p>When you click the button, your extension:</p>
<ol>
<li><p>Builds a prompt from the performance finding.</p>
</li>
<li><p>Copies the prompt to the clipboard.</p>
</li>
<li><p>Shows feedback that the prompt was copied.</p>
</li>
</ol>
<p>You can then paste the prompt into your coding agent and review the suggested patch.</p>
<h2 id="heading-how-to-verify-the-fix">How to Verify the Fix</h2>
<p>An AI-generated patch is only useful if the metric improves.</p>
<p>After the agent suggests a change, you should:</p>
<ol>
<li><p>Review the code diff.</p>
</li>
<li><p>Run the app locally.</p>
</li>
<li><p>Reload the page.</p>
</li>
<li><p>Re-run the performance audit.</p>
</li>
<li><p>Compare the new measurement with the original one.</p>
</li>
</ol>
<p>For the image example, you would check:</p>
<ul>
<li><p>Did the image transfer size go down?</p>
</li>
<li><p>Does the image still look sharp enough?</p>
</li>
<li><p>Did the page layout stay stable?</p>
</li>
<li><p>Did Largest Contentful Paint improve?</p>
</li>
<li><p>Did the change affect any other route?</p>
</li>
</ul>
<p>This creates a simple loop:</p>
<pre><code class="language-text">Measure -&gt; Prompt -&gt; Patch -&gt; Measure again
</code></pre>
<p>You shouldn't treat the agent's answer as the final authority. The browser measurement is the final authority.</p>
<h2 id="heading-how-this-fits-alongside-lighthouse">How This Fits Alongside Lighthouse</h2>
<p>Lighthouse is still useful. It gives you a detailed lab audit and a consistent score. This workflow solves a different problem.</p>
<p>Lighthouse helps you answer:</p>
<pre><code class="language-text">How does this page perform under controlled conditions?
</code></pre>
<p>An AI patch brief helps you answer:</p>
<pre><code class="language-text">What should I ask my coding agent to fix right now?
</code></pre>
<p>You can use both.</p>
<p>Use Lighthouse for scoring, regression tracking, and deeper audits. Use an AI prompt workflow when you want to move from a specific finding to a code change faster.</p>
<h2 id="heading-a-note-on-privacy">A Note on Privacy</h2>
<p>AI fix prompts can include URLs, resource names, routes, filenames, and implementation details.</p>
<p>Before you paste a prompt into a cloud-based coding agent, check that it doesn't include:</p>
<ul>
<li><p>Access tokens</p>
</li>
<li><p>Private customer data</p>
</li>
<li><p>Internal URLs you can't share</p>
</li>
<li><p>Secrets from environment variables</p>
</li>
<li><p>Sensitive logs</p>
</li>
</ul>
<p>Keep the prompt focused on the performance issue. Give the agent enough context to help, but not more than it needs.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In this tutorial, you learned how to turn a performance audit finding into an AI fix prompt.</p>
<p>You created:</p>
<ul>
<li><p>A structured <code>Finding</code> type</p>
</li>
<li><p>A way to rank findings</p>
</li>
<li><p>A <code>buildFixPrompt</code> function</p>
</li>
<li><p>A clipboard-first agent handoff</p>
</li>
<li><p>A DevTools panel button</p>
</li>
<li><p>A verification loop for checking the result</p>
</li>
</ul>
<p>The main idea is simple: performance tools produce evidence, and coding agents need context. A good AI patch brief connects the two.</p>
<p>PerfLens is one example of this workflow. If you want to try the extension or inspect how it implements this flow, you can find it here:</p>
<ul>
<li><p>Chrome Web Store: <a href="https://chromewebstore.google.com/detail/perflens/gkogamlpcnneeficmcdcnnnhobnbebdc">PerfLens</a></p>
</li>
<li><p>Source code: <a href="http://github.com/oluwatosinolamilekan/PerfLens">GitHub</a></p>
</li>
</ul>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Building a Website in 2026: What Matters More Than Your Tech Stack ]]>
                </title>
                <description>
                    <![CDATA[ For years, developers have debated which technology stack was best for building websites. Some preferred React. Others chose Vue, Angular, Svelte, or server-side frameworks such as Laravel and Django. ]]>
                </description>
                <link>https://www.freecodecamp.org/news/building-a-website-what-matters-more-than-your-tech-stack/</link>
                <guid isPermaLink="false">6a2e0f54136fd4eb2c9cc925</guid>
                
                    <category>
                        <![CDATA[ Web Development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ web performance ]]>
                    </category>
                
                    <category>
                        <![CDATA[ infrastructure ]]>
                    </category>
                
                    <category>
                        <![CDATA[ AI ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Manish Shivanandhan ]]>
                </dc:creator>
                <pubDate>Sun, 14 Jun 2026 02:17:56 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/uploads/covers/5e1e335a7a1d3fcc59028c64/10d14873-8414-410e-8325-17e7df039608.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>For years, developers have debated which technology stack was best for building websites.</p>
<p>Some preferred React. Others chose Vue, Angular, Svelte, or server-side frameworks such as Laravel and Django.</p>
<p>Entire conferences, blogs, and social media discussions have been dedicated to comparing frameworks and programming languages.</p>
<p>In 2026, those debates matter less than many developers think.</p>
<p>A modern website can be built with almost any mature framework and still perform well. The bigger challenge is making sure people can actually find, trust, and use that website.</p>
<p>Discoverability, performance, infrastructure, structured data, and AI search visibility now have a greater impact on success than the choice between competing frontend libraries.</p>
<p>The websites that win today aren't necessarily built with the most fashionable technologies. They're built with a strong foundation that helps users and search systems understand, access, and trust their content.</p>
<p>In this article, we'll look at what really matters when building a website these days. We'll explore why performance, hosting, domain management, structured data, and content quality often have a bigger impact than the technology stack itself.</p>
<p>We'll also examine how AI-powered search is changing the way people find information online and what developers can do to improve their website's visibility.</p>
<h3 id="heading-what-well-cover">What We'll Cover:</h3>
<ul>
<li><p><a href="#heading-the-tech-stack-has-become-a-commodity">The Tech Stack Has Become a Commodity</a></p>
</li>
<li><p><a href="#heading-performance-is-still-a-competitive-advantage">Performance Is Still a Competitive Advantage</a></p>
</li>
<li><p><a href="#heading-domains-and-infrastructure-still-matter">Domains and Infrastructure Still Matter</a></p>
</li>
<li><p><a href="#heading-hosting-is-no-longer-just-about-servers">Hosting Is No Longer Just About Servers</a></p>
</li>
<li><p><a href="#heading-structured-data-has-become-essential">Structured Data Has Become Essential</a></p>
</li>
<li><p><a href="#heading-the-rise-of-ai-search-and-answer-engines">The Rise of AI Search and Answer Engines</a></p>
</li>
<li><p><a href="#heading-content-quality-is-more-important-than-ever">Content Quality Is More Important Than Ever</a></p>
</li>
<li><p><a href="#heading-user-experience-is-the-new-differentiator">User Experience Is the New Differentiator</a></p>
</li>
<li><p><a href="#heading-the-future-is-about-outcomes-not-frameworks">The Future Is About Outcomes, Not Frameworks</a></p>
</li>
</ul>
<h2 id="heading-the-tech-stack-has-become-a-commodity"><strong>The Tech Stack Has Become a Commodity</strong></h2>
<p>The web development ecosystem has matured significantly over the past decade. Most modern frameworks provide similar capabilities. They support <a href="https://www.freecodecamp.org/news/a-brief-introduction-to-web-components/">component-based development</a>, <a href="https://www.freecodecamp.org/news/rendering-patterns/">server-side rendering</a>, API integrations, authentication systems, and performance optimization.</p>
<p>As a result, the gap between frameworks has narrowed.</p>
<p>A poorly optimized website built with the latest framework will often perform worse than a well-optimized website built with older technology. Users rarely care whether a page was built with React, Vue, or another framework. They care whether it loads quickly, works on mobile devices, and provides useful information.</p>
<p>Businesses care even more about outcomes. They want traffic, conversions, customer engagement, and revenue growth. None of those metrics improve simply because a team adopted a trendy technology stack.</p>
<p>This shift has forced development teams to focus on factors that have a direct impact on visibility and user experience.</p>
<h2 id="heading-performance-is-still-a-competitive-advantage"><strong>Performance Is Still a Competitive Advantage</strong></h2>
<p>Despite advances in hosting and frontend tooling, <a href="https://www.freecodecamp.org/news/performance-testing-for-web-applications/">website performance</a> remains one of the strongest predictors of user satisfaction.</p>
<p>Research consistently shows that slower websites lead to higher <a href="https://www.semrush.com/blog/bounce-rate/">bounce rates</a> and lower conversion rates. Users expect pages to load almost instantly. Even a delay of a few seconds can cause visitors to abandon a website before interacting with its content.</p>
<p>Modern performance optimisation goes beyond minimising JavaScript bundles. Teams must consider image optimisation, edge caching, content delivery networks, lazy loading, and server response times.</p>
<p>For example, an e-commerce website might reduce page load times by serving product images in modern formats such as WebP, implementing lazy loading for below-the-fold content, and using a CDN to deliver assets from locations closer to shoppers. These improvements often produce a more noticeable impact than migrating to a new frontend framework.</p>
<p>Many websites spend months migrating between frameworks while ignoring performance bottlenecks that would have a much larger impact on user experience. In practice, improving page speed often delivers greater business value than rebuilding an application using a different frontend stack.</p>
<p>Performance has also become increasingly important for search visibility. Search engines reward websites that provide a fast and reliable user experience. A technically impressive website that loads slowly is unlikely to achieve its full potential.</p>
<h2 id="heading-domains-and-infrastructure-still-matter"><strong>Domains and Infrastructure Still Matter</strong></h2>
<p>Developers often focus on application code while overlooking the infrastructure that supports it.</p>
<p>A website's domain remains one of its most important digital assets. Domain management affects security, reliability, and long-term brand ownership. Choosing a reputable registrar and maintaining proper DNS configuration are critical responsibilities.</p>
<p>A simple example is setting up DNS failover and enabling registrar-level security features such as domain lock and two-factor authentication. These measures help prevent outages and unauthorised domain transfers that could take a website offline.</p>
<p>For many teams, services such as <a href="https://www.namecheap.com/">Namecheap</a> and GoDaddy provide a straightforward way to manage domain registration, DNS records, SSL certificates, and related infrastructure. While these tasks may seem mundane compared to application development, they directly influence website availability and security.</p>
<p><a href="https://www.freecodecamp.org/news/how-dns-works-the-internets-address-book/">DNS performance</a> has become particularly important as websites adopt distributed architectures. Modern applications frequently rely on multiple services, APIs, content delivery networks, and edge platforms. A poorly configured DNS setup can introduce unnecessary latency and create reliability issues.</p>
<p>Infrastructure decisions also influence scalability. As traffic grows, websites must continue delivering fast and consistent experiences without requiring major architectural changes.</p>
<p>The most successful development teams treat infrastructure as a strategic asset rather than an afterthought.</p>
<h2 id="heading-hosting-is-no-longer-just-about-servers"><strong>Hosting Is No Longer Just About Servers</strong></h2>
<p>In the past, hosting primarily involved renting a server and deploying application code.</p>
<p>Today, hosting platforms offer far more than compute resources. They provide global content delivery networks, automatic scaling, integrated security features, <a href="https://www.hostinger.com/in/tutorials/best-observability-tools?utm_source=google&amp;utm_medium=cpc&amp;utm_id=11181890096&amp;utm_campaign=Generic-Tutorials-DSA-t1%7CNT:Se%7CLang:EN%7CLO:IN&amp;utm_term=&amp;utm_content=798975275269&amp;gad_source=1&amp;gad_campaignid=11181890096&amp;gbraid=0AAAAADMy-hZNKr2zB2PoiZCDVXWmMXbaA&amp;gclid=Cj0KCQjwof_QBhCgARIsADaMzOdeTB4LogkEU5Tg4r1U90UwKS3_-I-_yR5rTyGUdjeBDBoOwXaiIVgaAh2zEALw_wcB">observability tools</a>, and deployment automation.</p>
<p>The rise of edge computing has changed how websites are delivered. Content can now be served from locations close to users, reducing latency and improving responsiveness.</p>
<p>A media website experiencing a sudden traffic spike after a story goes viral can benefit from automatic scaling and edge caching, maintaining fast load times without requiring engineers to provision additional infrastructure manually.</p>
<p>Modern hosting decisions affect everything from performance and reliability to search rankings and customer satisfaction.</p>
<p>This means developers should evaluate hosting providers based on outcomes rather than specifications. Raw server resources matter less than factors such as uptime, deployment speed, geographic distribution, and operational simplicity.</p>
<p>A website that remains available during traffic spikes creates a better user experience than one that struggles under load, regardless of the underlying technology stack.</p>
<h2 id="heading-structured-data-has-become-essential"><strong>Structured Data Has Become Essential</strong></h2>
<p>One of the most overlooked aspects of modern website development is structured data.</p>
<p>Search engines and AI systems increasingly rely on structured information to understand website content. Schema markup helps machines identify products, articles, organisations, events, reviews, and many other types of information.</p>
<p>For instance, an online store can use a Product schema to display pricing and availability information in search results. At the same time, a recipe website can implement a Recipe schema to surface cooking times, ratings, and ingredients directly within search experiences.</p>
<p>Without structured data, websites force search systems to infer meaning from unstructured text. This increases the likelihood of misinterpretation.</p>
<p>Structured data improves the chances that content will appear in rich search results, featured snippets, knowledge panels, and other enhanced search experiences.</p>
<p>More importantly, structured data provides context that helps emerging AI systems understand content accurately.</p>
<p>As search evolves beyond traditional blue links, machine-readable information becomes increasingly valuable.</p>
<p>Developers who ignore structured data risk making their websites less visible, even if the content itself is excellent.</p>
<h2 id="heading-the-rise-of-ai-search-and-answer-engines"><strong>The Rise of AI Search and Answer Engines</strong></h2>
<p>Perhaps the biggest shift in website visibility is the growth of AI-powered search experiences.</p>
<p>Users increasingly ask questions directly to AI assistants rather than typing keywords into traditional search engines. These systems generate answers by combining information from multiple sources and presenting results in a conversational format.</p>
<p>This change creates new challenges for website owners.</p>
<p>Ranking on Google is no longer the only goal. Websites must also be structured in ways that help AI systems understand, retrieve, and reference their content.</p>
<p>A software company publishing detailed comparison guides, implementation tutorials, and clearly structured FAQs is more likely to be cited in AI-generated responses than a competitor relying solely on promotional landing pages.</p>
<p>This is where <a href="https://www.semrush.com/blog/answer-engine-optimization">Answer Engine Optimisation (AEO)</a> is becoming important. Unlike traditional SEO, which focuses on improving rankings in search results, AEO focuses on increasing the likelihood that content will be selected, cited, or referenced within AI-generated responses.</p>
<p>AI-powered search systems evaluate content differently from traditional search engines. Rather than simply matching keywords, they attempt to identify sources that provide clear explanations, authoritative information, and direct answers to user questions. Content that is well structured, factually accurate, and easy to interpret tends to perform better in these environments.</p>
<p>Platforms such as <a href="https://www.dirjournal.com/">DirJournal</a>, an answer engine optimisation platform, help businesses understand how their content appears across AI-driven search environments. As teams adapt to changing search behaviour, they're increasingly monitoring not only search rankings but also the frequency with which AI systems reference their brands, products, and expertise.</p>
<p>The websites that succeed in this environment are often those that publish clear, authoritative content supported by strong technical foundations.</p>
<p>In many cases, the same practices that improve traditional SEO also support AI discoverability. Fast websites, structured data, authoritative content, and clear information architecture all contribute to better visibility.</p>
<h2 id="heading-content-quality-is-more-important-than-ever"><strong>Content Quality Is More Important Than Ever</strong></h2>
<p>Technology can improve delivery, but content remains the primary reason users visit a website.</p>
<p>AI systems are becoming increasingly effective at identifying expertise, authority, and relevance. Thin content designed solely for search rankings is becoming less effective.</p>
<p>Modern websites must provide genuine value. They need original insights, practical examples, clear explanations, and trustworthy information.</p>
<p>For example, a cybersecurity vendor might publish original research on emerging threats, while a healthcare provider could create evidence-based patient guides reviewed by medical professionals. Content grounded in expertise tends to earn greater trust and visibility.</p>
<p>Developers building content-driven websites should think beyond page views and rankings. The goal is to create resources that answer real questions and solve real problems.</p>
<p>Content that demonstrates expertise is more likely to earn links, generate engagement, and be referenced by both search engines and AI systems.</p>
<p>The websites that stand out now are those that prioritize usefulness over optimization tricks.</p>
<h2 id="heading-user-experience-is-the-new-differentiator"><strong>User Experience Is the New Differentiator</strong></h2>
<p>As technology becomes more accessible, user experience becomes a larger competitive advantage.</p>
<p>Visitors expect intuitive navigation, accessible interfaces, responsive layouts, and consistent performance across devices.</p>
<p>Simple improvements such as reducing the number of checkout steps, increasing button sizes on mobile devices, or ensuring keyboard navigation works correctly can significantly improve usability and conversion rates.</p>
<p>Poor user experiences create friction that drives users away regardless of how advanced the underlying technology may be.</p>
<p><a href="https://www.freecodecamp.org/news/the-web-accessibility-handbook/">Accessibility deserves particular attention</a>. Websites should be usable by people with diverse abilities and assistive technologies. Accessibility improvements often enhance usability for all visitors while supporting compliance requirements.</p>
<p>The best websites combine technical excellence with thoughtful design. They remove obstacles and help users accomplish their goals quickly and efficiently.</p>
<h2 id="heading-the-future-is-about-outcomes-not-frameworks"><strong>The Future Is About Outcomes, Not Frameworks</strong></h2>
<p>The web development industry has reached a point where most modern frameworks are capable of delivering excellent results.</p>
<p>The real challenge is no longer choosing the perfect technology stack.</p>
<p>Success depends on building websites that are fast, discoverable, reliable, secure, and understandable to both humans and machines. Performance optimization, domain management, hosting strategy, structured data, content quality, and AI search visibility now play a larger role in determining outcomes.</p>
<p>These days, the websites that succeed aren't necessarily built with the newest technologies. They're built with the strongest foundations.</p>
<p>Developers who focus on those foundations will create websites that continue to perform well regardless of how search engines, AI systems, or frontend frameworks evolve in the years ahead.</p>
<p>Hope you enjoyed this article. You can <a href="https://linkedin.com/in/manishmshiva">connect with me on LinkedIn</a>.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Scale Laravel Applications for High-Traffic Production Systems ]]>
                </title>
                <description>
                    <![CDATA[ Your first scaling problem rarely arrives with a bang. For a while, everything is fine: pages load fast, the database barely breaks a sweat, and the team ships features without thinking much about inf ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-scale-laravel-applications-for-high-traffic-production-systems/</link>
                <guid isPermaLink="false">6a2b48a3a381db4fd3f61555</guid>
                
                    <category>
                        <![CDATA[ Laravel ]]>
                    </category>
                
                    <category>
                        <![CDATA[ scaling ]]>
                    </category>
                
                    <category>
                        <![CDATA[ production ]]>
                    </category>
                
                    <category>
                        <![CDATA[ web performance ]]>
                    </category>
                
                    <category>
                        <![CDATA[ performance ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Olamilekan Lamidi ]]>
                </dc:creator>
                <pubDate>Thu, 11 Jun 2026 23:45:39 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/uploads/covers/5e1e335a7a1d3fcc59028c64/8882176c-0420-4fc9-8d72-129640aac231.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Your first scaling problem rarely arrives with a bang. For a while, everything is fine: pages load fast, the database barely breaks a sweat, and the team ships features without thinking much about infrastructure.</p>
<p>Then traffic climbs. A campaign over-performs. A marketplace onboards a popular seller. A SaaS product signs a couple of enterprise accounts.</p>
<p>Suddenly, <code>/dashboard</code> takes two seconds instead of 300 milliseconds. Queue jobs that used to clear in seconds sit waiting for minutes. You have database CPU spikes every afternoon.</p>
<p>So you add another app server, and response time barely moves because the real culprit was a slow query on a large table all along.</p>
<p>If you have run Laravel in production, you've probably lived some version of this. The good news is that scaling Laravel almost never means abandoning the framework. It means learning where pressure builds and making the application behave predictably under load.</p>
<p>In this guide, you'll learn how to find common bottlenecks, tune the database, use Redis effectively, move slow work onto queues, optimize APIs, and monitor a Laravel application in production.</p>
<p>None of this requires a single heroic rewrite. The biggest wins usually come from practical work: removing inefficient queries, pushing slow tasks onto queues, adding the right indexes, caching carefully chosen data, and measuring whether each change actually helped.</p>
<h2 id="heading-prerequisites">Prerequisites</h2>
<p>You'll get the most out of this guide if you're already comfortable with:</p>
<ul>
<li><p>Building applications with Laravel and PHP</p>
</li>
<li><p>Writing Eloquent queries and database migrations</p>
</li>
<li><p>Using queues, jobs, and scheduled commands</p>
</li>
<li><p>Reading a basic database query plan</p>
</li>
<li><p>Deploying Laravel to a production server or platform</p>
</li>
<li><p>Working with Redis and either MySQL or PostgreSQL in a production-like setup</p>
</li>
</ul>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ul>
<li><p><a href="#heading-what-happens-when-laravel-apps-start-growing">What Happens When Laravel Apps Start Growing</a></p>
</li>
<li><p><a href="#heading-common-laravel-bottlenecks">Common Laravel Bottlenecks</a></p>
</li>
<li><p><a href="#heading-how-to-optimize-the-database">How to Optimize the Database</a></p>
</li>
<li><p><a href="#heading-how-to-scale-with-redis">How to Scale with Redis</a></p>
</li>
<li><p><a href="#heading-how-to-use-queue-driven-architectures">How to Use Queue-Driven Architectures</a></p>
</li>
<li><p><a href="#heading-how-to-optimize-api-performance">How to Optimize API Performance</a></p>
</li>
<li><p><a href="#heading-how-to-monitor-laravel-in-production">How to Monitor Laravel in Production</a></p>
</li>
<li><p><a href="#heading-an-example-high-traffic-laravel-architecture">An Example High-Traffic Laravel Architecture</a></p>
</li>
<li><p><a href="#heading-lessons-learned-the-hard-way">Lessons Learned the Hard Way</a></p>
</li>
<li><p><a href="#heading-a-pre-launch-scaling-checklist">A Pre-Launch Scaling Checklist</a></p>
</li>
<li><p><a href="#heading-conclusion">Conclusion</a></p>
</li>
<li><p><a href="#heading-references">References</a></p>
</li>
</ul>
<h2 id="heading-what-happens-when-laravel-apps-start-growing">What Happens When Laravel Apps Start Growing</h2>
<p>Traffic changes a system's behavior because it turns small inefficiencies into permanent costs. A query that takes 80 milliseconds is harmless when it runs a few hundred times an hour. Run it 30 times per page view on a page that gets thousands of hits a minute, and that same query becomes a capacity problem.</p>
<p>The pressure tends to show up in predictable places. More requests mean more PHP workers, more database connections, more queue volume, and more Redis operations.</p>
<p>The database, whether MySQL or PostgreSQL, is usually the first thing to buckle. Queues back up when work is created faster than workers can drain it. Caches only help when hit rates stay high and misses stay controlled. And scaling everything horizontally can turn sloppy code into an expensive cloud bill.</p>
<p>That's why scaling work has to start with measurement, not guesswork. Before you change anything, you want to know what is actually saturated: request CPU, database I/O, lock contention, Redis latency, queue depth, an external API, or oversized payloads.</p>
<p>A typical request in a growing Laravel app travels through several layers. The user sends a request, a load balancer routes it to an app server, and Laravel checks Redis for a cached result. On a miss, it queries the database, stores the computed result back in Redis, and hands any slow follow-up work to a queue. A worker picks up that job later while Laravel returns the response right away.</p>
<p>Here's the important part: adding more app servers does nothing for a slow query, a missing index, or an overloaded queue. Horizontal scaling only pays off once the shared dependencies behind those servers can keep up.</p>
<h2 id="heading-common-laravel-bottlenecks">Common Laravel Bottlenecks</h2>
<p>Laravel itself causes very few scaling problems. Most issues come from how application code talks to the database, the network, and background workers.</p>
<h3 id="heading-n1-queries">N+1 Queries</h3>
<p>The classic offender is the N+1 query. You load a list of models, then lazily touch a relationship on each one:</p>
<pre><code class="language-php">use App\Models\Post;

$posts = Post::latest()-&gt;take(50)-&gt;get();

foreach (\(posts as \)post) {
    echo $post-&gt;author-&gt;name;
}
</code></pre>
<p>That's one query for the posts plus one query per author: 51 queries for a single page. Eager load the relationship instead:</p>
<pre><code class="language-php">use App\Models\Post;

$posts = Post::with('author')
    -&gt;latest()
    -&gt;take(50)
    -&gt;get();

foreach (\(posts as \)post) {
    echo $post-&gt;author-&gt;name;
}
</code></pre>
<p>In production, these are sneaky. They often hide inside API Resources, Blade components, and authorization checks, where the relationship access isn't obvious from the controller.</p>
<h3 id="heading-missing-indexes">Missing Indexes</h3>
<p>Adding an index is one of the highest-return fixes you can make. Take a query like this:</p>
<pre><code class="language-php">\(orders = Order::where('account_id', \)accountId)
    -&gt;where('status', 'paid')
    -&gt;whereBetween('created_at', [\(start, \)end])
    -&gt;latest()
    -&gt;paginate(50);
</code></pre>
<p>If <code>orders</code> has millions of rows and no useful compound index, the database scans far more rows than it needs to. Add an index that matches how you actually query:</p>
<pre><code class="language-php">use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration {
    public function up(): void
    {
        Schema::table('orders', function (Blueprint $table) {
            $table-&gt;index(['account_id', 'status', 'created_at']);
        });
    }

    public function down(): void
    {
        Schema::table('orders', function (Blueprint $table) {
            $table-&gt;dropIndex(['account_id', 'status', 'created_at']);
        });
    }
};
</code></pre>
<p>Indexes aren't free, though. They take up space and slow down writes. Add them for real, repeated query patterns, not for every column that ever appears in a <code>where</code> clause.</p>
<h3 id="heading-inefficient-eager-loading">Inefficient Eager Loading</h3>
<p>You can also swing too far the other way. Loading every relationship "just in case" burns memory and ships data the request never uses:</p>
<pre><code class="language-php">$users = User::with([
    'profile',
    'teams',
    'roles.permissions',
    'invoices.lineItems.product',
])-&gt;get();
</code></pre>
<p>That might be fine for an admin detail page showing one user. On a list page, it's a liability. Constrain the eager loads and select only the columns you need:</p>
<pre><code class="language-php">$users = User::query()
    -&gt;select(['id', 'name', 'email'])
    -&gt;with([
        'profile:id,user_id,avatar_url',
        'teams:id,name',
    ])
    -&gt;latest()
    -&gt;paginate(25);
</code></pre>
<p>One caveat: tightly scoped select lists can break later code that expects a column you didn't load. Keep this technique close to read-heavy endpoints where the payoff is obvious.</p>
<h3 id="heading-synchronous-processing">Synchronous Processing</h3>
<p>High-traffic apps need short web requests. Sending email, generating PDFs, calling third-party APIs, resizing images, and building exports usually belong outside the request cycle. This version can hurt you:</p>
<pre><code class="language-php">public function store(Request $request)
{
    \(order = Order::create(\)request-&gt;validated());

    Mail::to(\(order-&gt;user)-&gt;send(new OrderReceipt(\)order));

    return response()-&gt;json($order, 201);
}
</code></pre>
<p>Push the work onto a queue instead:</p>
<pre><code class="language-php">public function store(StoreOrderRequest $request)
{
    \(order = Order::create(\)request-&gt;validated());

    SendOrderReceipt::dispatch($order-&gt;id);

    return response()-&gt;json([
        'id' =&gt; $order-&gt;id,
        'status' =&gt; 'accepted',
    ], 202);
}
</code></pre>
<p>Now your response time no longer depends on your mail provider. If the provider has a slow afternoon, the queue absorbs it and your users don't have to wait.</p>
<h3 id="heading-large-payloads">Large Payloads</h3>
<p>Oversized JSON responses hurt everyone in the chain: the app server serializing them, the network carrying them, and the client parsing them. A frequent mistake is returning whole models when you meant to return a summary:</p>
<pre><code class="language-php">return User::with('orders', 'invoices', 'teams')-&gt;findOrFail($id);
</code></pre>
<p>Define an explicit API Resource instead:</p>
<pre><code class="language-php">use Illuminate\Http\Resources\Json\JsonResource;

class UserSummaryResource extends JsonResource
{
    public function toArray($request): array
    {
        return [
            'id' =&gt; $this-&gt;id,
            'name' =&gt; $this-&gt;name,
            'avatar_url' =&gt; $this-&gt;profile?-&gt;avatar_url,
            'plan' =&gt; $this-&gt;subscription_plan,
        ];
    }
}
</code></pre>
<p>A small, deliberate response contract keeps endpoint cost easy to reason about and prevents accidental coupling.</p>
<h3 id="heading-expensive-joins">Expensive Joins</h3>
<p>Joins are useful, but expensive joins across large tables can dominate your database time, especially when they sort or filter on columns that aren't indexed:</p>
<pre><code class="language-php">$rows = DB::table('orders')
    -&gt;join('users', 'users.id', '=', 'orders.user_id')
    -&gt;join('accounts', 'accounts.id', '=', 'users.account_id')
    -&gt;where('accounts.region', 'us-east')
    -&gt;where('orders.status', 'paid')
    -&gt;orderByDesc('orders.created_at')
    -&gt;limit(100)
    -&gt;get();
</code></pre>
<p>At scale, you may need to denormalize a small field, precompute a reporting table, or move analytics off the primary transactional database entirely. Do not treat denormalization as an admission of defeat. Copying a stable field like <code>account_id</code> onto <code>orders</code> can remove a costly join from a hot path. The price you pay is keeping that duplicated data consistent, which can be a worthwhile trade-off.</p>
<h2 id="heading-how-to-optimize-the-database">How to Optimize the Database</h2>
<p>When a Laravel app slows down, the database is usually the first place to look.</p>
<h3 id="heading-add-indexes-around-real-query-patterns">Add Indexes Around Real Query Patterns</h3>
<p>Start with your slow query log, database metrics, and traces rather than intuition. If the app constantly looks up active subscriptions by account, build a compound index that matches that access pattern:</p>
<pre><code class="language-php">Schema::table('subscriptions', function (Blueprint $table) {
    $table-&gt;index(['account_id', 'status', 'renews_at']);
});
</code></pre>
<p>Then write the query so it can actually use the index:</p>
<pre><code class="language-php">\(subscription = Subscription::where('account_id', \)accountId)
    -&gt;where('status', 'active')
    -&gt;where('renews_at', '&gt;=', now())
    -&gt;orderBy('renews_at')
    -&gt;first();
</code></pre>
<p>Get in the habit of running <code>EXPLAIN</code> after you add an index to confirm that the plan changed. An index the optimizer ignores is just write overhead.</p>
<h3 id="heading-use-eager-loading-deliberately">Use Eager Loading Deliberately</h3>
<p>Match eager loading to what the endpoint actually returns. For list endpoints, keep relationships shallow and constrained:</p>
<pre><code class="language-php">$projects = Project::query()
    -&gt;select(['id', 'account_id', 'name', 'updated_at'])
    -&gt;withCount('openTasks')
    -&gt;with([
        'owner:id,name',
    ])
    -&gt;where('account_id', $accountId)
    -&gt;latest('updated_at')
    -&gt;paginate(30);
</code></pre>
<p>When you only need a number, <code>withCount</code> beats loading a whole relationship to count it:</p>
<pre><code class="language-php">$teams = Team::query()
    -&gt;withCount([
        'members',
        'invitations as pending_invitations_count' =&gt; fn (\(query) =&gt; \)query-&gt;whereNull('accepted_at'),
    ])
    -&gt;paginate(25);
</code></pre>
<p>Your memory footprint stays flat, which matters much more on a list page than on a detail page.</p>
<h3 id="heading-optimize-queries-before-adding-hardware">Optimize Queries Before Adding Hardware</h3>
<p>A bigger database instance buys you time. It also hides the inefficient queries that put you there until the next traffic jump exposes them again. Before you reach for a larger machine, find your highest-cost queries. In local or staging environments, logging slow ones is easy:</p>
<pre><code class="language-php">use Illuminate\Database\Events\QueryExecuted;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;

DB::listen(function (QueryExecuted $query) {
    if ($query-&gt;time &gt; 100) {
        Log::warning('Slow query detected', [
            'sql' =&gt; $query-&gt;toRawSql(),
            'time_ms' =&gt; $query-&gt;time,
        ]);
    }
});
</code></pre>
<p>Be careful doing this in production. Bindings can contain sensitive data, and verbose logging at high volume can become its own performance problem.</p>
<h3 id="heading-process-large-tables-with-chunking">Process Large Tables with Chunking</h3>
<p>Never pull an entire large table into memory for a batch job:</p>
<pre><code class="language-php">User::where('is_active', true)
    -&gt;chunkById(1000, function ($users) {
        foreach (\(users as \)user) {
            RefreshUserSearchIndex::dispatch($user-&gt;id);
        }
    });
</code></pre>
<p><code>chunkById</code> is safer than offset-based chunking when rows can change while the job runs, because it tracks the last seen ID instead of a numeric offset. For very large exports, stream the records or write them out in batches.</p>
<h3 id="heading-use-cursor-pagination-for-high-volume-feeds">Use Cursor Pagination for High-Volume Feeds</h3>
<p>Offset pagination gets slower the deeper a user scrolls, because the database still has to skip every row it's not returning. For feeds, audit logs, messages, and timelines, cursor pagination is usually the better fit:</p>
<pre><code class="language-php">$events = AuditEvent::query()
    -&gt;where('account_id', $accountId)
    -&gt;orderByDesc('id')
    -&gt;cursorPaginate(50);

return AuditEventResource::collection($events);
</code></pre>
<p>It relies on a stable, indexed ordering column and uses next/previous cursors rather than arbitrary page numbers, which is what an infinite-scroll feed usually needs.</p>
<h3 id="heading-split-reads-with-read-replicas">Split Reads with Read Replicas</h3>
<p>As read traffic grows, replicas can take load off the primary:</p>
<pre><code class="language-php">'mysql' =&gt; [
    'driver' =&gt; 'mysql',
    'read' =&gt; [
        'host' =&gt; [
            env('DB_READ_HOST', '127.0.0.1'),
        ],
    ],
    'write' =&gt; [
        'host' =&gt; [
            env('DB_WRITE_HOST', '127.0.0.1'),
        ],
    ],
    'sticky' =&gt; true,
    'database' =&gt; env('DB_DATABASE', 'laravel'),
    'username' =&gt; env('DB_USERNAME', 'root'),
    'password' =&gt; env('DB_PASSWORD', ''),
],
</code></pre>
<p>The <code>sticky</code> option keeps reads on the write connection after a write within the same request, which helps avoid some read-after-write surprises.</p>
<p>Replicas come with replication lag, and that lag matters. Don't route payment confirmations, password changes, permission checks, or anything else consistency-sensitive to a replica that might be a few seconds stale unless the business flow can genuinely tolerate seeing old data.</p>
<h2 id="heading-how-to-scale-with-redis">How to Scale with Redis</h2>
<p>Redis often does a lot in a Laravel production stack: caching, sessions, rate limiting, queues, locks, and Horizon metrics. It's fast, but it still needs thought: sensible key design, expiration policies, memory monitoring, and a real plan for invalidation.</p>
<h3 id="heading-caching">Caching</h3>
<p>Cache expensive reads that get requested often and can tolerate being slightly out of date:</p>
<pre><code class="language-php">use Illuminate\Support\Facades\Cache;

$stats = Cache::remember(
    "accounts:{$account-&gt;id}:dashboard-stats",
    now()-&gt;addMinutes(5),
    fn () =&gt; DashboardStats::forAccount($account)-&gt;calculate()
);
</code></pre>
<p>Short time-to-live values go a surprisingly long way. A five-minute cache can wipe out thousands of duplicate queries while keeping the data fresh enough for most dashboards.</p>
<p>When the data changes after a known event, invalidate it explicitly:</p>
<pre><code class="language-php">Order::created(function (Order $order) {
    Cache::forget("accounts:{$order-&gt;account_id}:dashboard-stats");
});
</code></pre>
<p>Caching works best when your keys are predictable and your invalidation is tied to domain events rather than guesswork.</p>
<h3 id="heading-sessions">Sessions</h3>
<p>For horizontally scaled app servers, file-based sessions are a trap: the next request can land on a different server that has never seen the session. Store sessions in Redis or a database so any server can handle any request:</p>
<pre><code class="language-env">SESSION_DRIVER=redis
CACHE_STORE=redis
QUEUE_CONNECTION=redis
</code></pre>
<h3 id="heading-rate-limiting">Rate Limiting</h3>
<p>Rate limits protect you from abusive clients, runaway loops, and endpoints that get hammered:</p>
<pre><code class="language-php">use Illuminate\Cache\RateLimiting\Limit;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\RateLimiter;

RateLimiter::for('api', function (Request $request) {
    return Limit::perMinute(120)-&gt;by(
        optional(\(request-&gt;user())-&gt;id ?: \)request-&gt;ip()
    );
});
</code></pre>
<p>Expensive endpoints deserve stricter limits:</p>
<pre><code class="language-php">RateLimiter::for('exports', function (Request $request) {
    return Limit::perHour(10)-&gt;by($request-&gt;user()-&gt;id);
});
</code></pre>
<p>Let business cost drive the numbers. Login, search, export, and webhook endpoints rarely need the same limit.</p>
<h3 id="heading-queues">Queues</h3>
<p>Redis is a common queue backend because it's quick and Horizon supports it well:</p>
<pre><code class="language-env">QUEUE_CONNECTION=redis
</code></pre>
<p>Dispatch work onto named queues from the request:</p>
<pre><code class="language-php">GenerateInvoicePdf::dispatch($invoice-&gt;id)
    -&gt;onQueue('documents');
</code></pre>
<p>Split work by profile, such as <code>default</code>, <code>emails</code>, <code>webhooks</code>, <code>documents</code>, and <code>imports</code>, because each workload can need different worker counts and retry rules. Keep the names meaningful. During an incident, "the documents queue is 20 minutes behind" tells you far more than "default is slow."</p>
<h2 id="heading-how-to-use-queue-driven-architectures">How to Use Queue-Driven Architectures</h2>
<p>Queues are one of Laravel's best scaling tools. They let the app accept work quickly and process it asynchronously with controlled concurrency. They also make the system more resilient: when a third-party API goes down, jobs retry on their own instead of tying up your PHP-FPM request workers.</p>
<h3 id="heading-laravel-queues">Laravel Queues</h3>
<p>A good job is small, idempotent, and safe to retry:</p>
<pre><code class="language-php">use App\Mail\OrderReceiptMail;
use App\Models\Order;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Queue\Queueable;
use Illuminate\Support\Facades\Mail;

class SendOrderReceipt implements ShouldQueue
{
    use Queueable;

    public int $tries = 3;
    public int $backoff = 60;

    public function __construct(public int $orderId)
    {
    }

    public function handle(): void
    {
        \(order = Order::with('user')-&gt;findOrFail(\)this-&gt;orderId);

        Mail::to(\(order-&gt;user)-&gt;send(new OrderReceiptMail(\)order));
    }
}
</code></pre>
<p>Pass IDs into jobs rather than full Eloquent models. The model might change before the job runs, and serializing a whole model bloats the payload. For external APIs, add timeouts and guard against duplicate work:</p>
<pre><code class="language-php">use App\Models\Order;
use App\Services\CrmClient;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Queue\Queueable;

class SyncOrderToCrm implements ShouldQueue
{
    use Queueable;

    public int $tries = 3;
    public int $backoff = 60;

    public function __construct(public int $orderId)
    {
    }

    public function handle(CrmClient $crm): void
    {
        \(order = Order::findOrFail(\)this-&gt;orderId);

        if ($order-&gt;crm_synced_at) {
            return;
        }

        \(crm-&gt;upsertOrder(\)order-&gt;external_reference, [
            'total' =&gt; $order-&gt;total,
            'status' =&gt; $order-&gt;status,
        ]);

        $order-&gt;forceFill(['crm_synced_at' =&gt; now()])-&gt;save();
    }
}
</code></pre>
<p>The <code>crm_synced_at</code> check is the whole point. Jobs run more than once in real life, and idempotency is what keeps a retry from double-charging or double-syncing.</p>
<h3 id="heading-horizon">Horizon</h3>
<p>Horizon gives you visibility and control over Redis queues. A typical setup runs different supervisors for different workloads:</p>
<pre><code class="language-php">'production' =&gt; [
    'supervisor-default' =&gt; [
        'connection' =&gt; 'redis',
        'queue' =&gt; ['default', 'emails'],
        'balance' =&gt; 'auto',
        'maxProcesses' =&gt; 20,
        'tries' =&gt; 3,
    ],

    'supervisor-documents' =&gt; [
        'connection' =&gt; 'redis',
        'queue' =&gt; ['documents'],
        'balance' =&gt; 'simple',
        'maxProcesses' =&gt; 5,
        'tries' =&gt; 2,
        'timeout' =&gt; 300,
    ],
],
</code></pre>
<p>The separation matters: a long-running document job shouldn't starve a quick password-reset email.</p>
<h3 id="heading-failed-jobs-and-retries">Failed Jobs and Retries</h3>
<p>Retries only help when failures are temporary. Retrying a job that's permanently broken just burns capacity. For jobs with a business deadline, use <code>retryUntil</code>:</p>
<pre><code class="language-php">use DateTime;
use Throwable;

public function retryUntil(): DateTime
{
    return now()-&gt;addMinutes(30);
}

public function failed(Throwable $exception): void
{
    ImportBatch::whereKey($this-&gt;batchId)-&gt;update([
        'status' =&gt; 'failed',
        'failed_reason' =&gt; $exception-&gt;getMessage(),
    ]);
}
</code></pre>
<p>Use <code>failed</code> to flag the problem somewhere a human will see it. Whatever you do, don't set unlimited retries on jobs that hit a third-party service.</p>
<h3 id="heading-queue-monitoring">Queue Monitoring</h3>
<p>Track queue depth, wait time, failure rate, and processing time together. Depth alone can mislead you. When depth starts climbing, walk through it methodically: are workers keeping pace with incoming jobs? If the queue keeps growing, check how long individual jobs take. If the slow part is the database, fix the query or dial back worker concurrency. If it's an external API, add backoff or a circuit breaker. If the work is CPU-bound, scale workers or break the jobs into smaller pieces.</p>
<p>Be careful with the "scale workers" instinct, though. Adding more workers without checking the database first can make an incident worse. More workers mean more concurrent queries, more locks, and more pressure on the primary exactly when it's already struggling.</p>
<h2 id="heading-how-to-optimize-api-performance">How to Optimize API Performance</h2>
<p>APIs earn special attention because clients call them repeatedly and payloads tend to grow quietly over months.</p>
<h3 id="heading-api-resources">API Resources</h3>
<p>Resources keep your response shape intentional:</p>
<pre><code class="language-php">class OrderResource extends JsonResource
{
    public function toArray($request): array
    {
        return [
            'id' =&gt; $this-&gt;id,
            'status' =&gt; $this-&gt;status,
            'total' =&gt; $this-&gt;total,
            'placed_at' =&gt; $this-&gt;created_at-&gt;toIso8601String(),
            'customer' =&gt; new CustomerSummaryResource($this-&gt;whenLoaded('customer')),
        ];
    }
}
</code></pre>
<p><code>whenLoaded</code> is doing real work here. It stops the resource from quietly triggering a lazy query when the relationship wasn't eager loaded:</p>
<pre><code class="language-php">$orders = Order::query()
    -&gt;with('customer:id,name')
    -&gt;where('account_id', $accountId)
    -&gt;latest()
    -&gt;paginate(50);

return OrderResource::collection($orders);
</code></pre>
<h3 id="heading-pagination">Pagination</h3>
<p>Returning unbounded collections is an easy way to create an API performance problem you won't notice until a client has a lot of data:</p>
<pre><code class="language-php">$perPage = min((int) request('per_page', 50), 100);

\(orders = Order::where('account_id', \)accountId)
    -&gt;latest()
    -&gt;paginate($perPage);
</code></pre>
<p>Cap the page size. If a client genuinely needs every record for an export, make that an async job rather than a giant synchronous response.</p>
<h3 id="heading-response-optimization">Response Optimization</h3>
<p>Stop returning fields nobody reads. On read-heavy endpoints, selecting only the columns you need cuts both database I/O and serialization cost:</p>
<pre><code class="language-php">$products = Product::query()
    -&gt;select(['id', 'name', 'slug', 'price', 'thumbnail_url'])
    -&gt;where('is_visible', true)
    -&gt;orderBy('name')
    -&gt;paginate(40);
</code></pre>
<p>It's also worth turning on compression at the web server or load balancer. JSON compresses extremely well, and that's often a small config change with a real bandwidth payoff.</p>
<h3 id="heading-rate-limiting">Rate Limiting</h3>
<p>Design API rate limits around identity and endpoint cost:</p>
<pre><code class="language-php">Route::middleware(['auth:sanctum', 'throttle:api'])
    -&gt;group(function () {
        Route::get('/orders', [OrderController::class, 'index']);
        Route::post('/exports/orders', [OrderExportController::class, 'store'])
            -&gt;middleware('throttle:exports');
    });
</code></pre>
<p>This keeps casual browsing and expensive exports under separate policies, so one heavy user can't squeeze out everyone else.</p>
<h3 id="heading-caching-api-responses">Caching API Responses</h3>
<p>Cache responses that are expensive to compute and can tolerate being a little stale:</p>
<pre><code class="language-php">public function index(Request $request)
{
    \(accountId = \)request-&gt;user()-&gt;account_id;
    \(page = \)request-&gt;integer('page', 1);

    \(cacheKey = "api:accounts:{\)accountId}:orders:v1:page:{$page}";

    return Cache::remember(\(cacheKey, now()-&gt;addSeconds(60), function () use (\)accountId) {
        return OrderResource::collection(
            Order::with('customer:id,name')
                -&gt;where('account_id', $accountId)
                -&gt;latest()
                -&gt;paginate(50)
        )-&gt;response()-&gt;getData(true);
    });
}
</code></pre>
<p>Notice the <code>v1</code> in the key. Bumping that version number lets you invalidate an entire response format at once when the shape changes. Always scope the key to the tenant or user for anything that's not truly global.</p>
<h2 id="heading-how-to-monitor-laravel-in-production">How to Monitor Laravel in Production</h2>
<p>The teams that catch problems before customers do are the ones collecting signals from everywhere: Laravel, queues, the database, Redis, the infrastructure, and external services.</p>
<p>Laravel gives you several good starting points. Horizon shows queue throughput, failed jobs, wait times, and worker balancing. Telescope surfaces request details, queries, exceptions, jobs, mail, and cache events. Your logs capture slow operations, unexpected retries, and external failures. Your metrics track latency, error rate, queue depth, job runtime, database CPU, lock waits, cache hit ratio, and Redis memory. Your alerting ties all of it back to something a customer would actually feel.</p>
<p>That last part is where teams often make mistakes. The best alerts are about symptoms, not machines being busy: p95 API latency over 800ms for 10 minutes, checkout error rate above 1%, the emails queue waiting more than 5 minutes, database CPU over 85% with slow queries rising, Redis memory over 80%, or failed payment webhooks crossing a threshold.</p>
<p>A useful mental model is this: logs tell you what happened, metrics tell you whether the system is healthy, and traces tell you where the time went. In practice, wrapping your expensive business operations in a bit of instrumentation pays off quickly:</p>
<pre><code class="language-php">use Illuminate\Support\Facades\Log;

$startedAt = microtime(true);

\(report = \)builder-&gt;forAccount($account)-&gt;build();

Log::info('Billing report generated', [
    'account_id' =&gt; $account-&gt;id,
    'duration_ms' =&gt; (int) ((microtime(true) - $startedAt) * 1000),
    'invoice_count' =&gt; $report-&gt;invoiceCount(),
]);
</code></pre>
<p>When something is failing at 2am, a log line like that can tell you which account, import, or report is causing the pressure.</p>
<p>One more thing worth internalizing: monitor wait time, not just throughput. A queue can process thousands of jobs a minute and still be unhealthy if important jobs sit waiting too long before they start. Users feel the wait, not the throughput.</p>
<h2 id="heading-an-example-high-traffic-laravel-architecture">An Example High-Traffic Laravel Architecture</h2>
<p>A high-traffic Laravel setup generally separates four things: stateless web requests, shared cache and session storage, asynchronous workers, and database roles.</p>
<p>Users hit a load balancer, which spreads traffic across a fleet of stateless Laravel app servers. Those servers use Redis for cache, sessions, rate limits, queues, and Horizon data. Queue workers handle slow or unreliable work off to the side. A MySQL primary takes all writes and any consistency-sensitive reads, while a read replica absorbs read-heavy endpoints that can tolerate some replication lag.</p>
<p>The flow looks like this:</p>
<pre><code class="language-text">Users
  -&gt; Load balancer
  -&gt; Stateless Laravel app servers
  -&gt; Redis for cache, sessions, rate limits, queues, and Horizon data
  -&gt; Primary database for writes and consistency-sensitive reads
  -&gt; Read replica for safe read-heavy endpoints

Redis queue
  -&gt; Queue workers
  -&gt; Database, external APIs, mail providers, object storage, and other services
</code></pre>
<p>This isn't the only valid shape. PostgreSQL can stand in for MySQL, Amazon SQS can replace Redis queues, a CDN can serve static assets and cache public responses, and object storage should hold user uploads. The principle that matters is that each layer has one clear job and can be scaled or tuned on its own.</p>
<p>The flip side of stateless app servers is that anything a user needs after the request ends has to live in shared storage. Uploads, generated files, and session state shouldn't sit on a single server's local disk, or they may disappear from the user's point of view when the load balancer sends the next request somewhere else.</p>
<h2 id="heading-lessons-learned-the-hard-way">Lessons Learned the Hard Way</h2>
<h3 id="heading-1-premature-optimization">1. Premature Optimization</h3>
<p>This usually shows up as elaborate infrastructure built before the app has any real visibility into itself.</p>
<p>The practical path works better: measure, rank the bottlenecks, fix the biggest one, repeat. For most Laravel apps, the first round of scaling is mostly indexes, N+1 fixes, queue separation, and trimming payloads.</p>
<h3 id="heading-2-over-caching">2. Over-caching</h3>
<p>Caching can make a system faster and harder to reason about at the same time. One team cached an account-settings response for 30 minutes, then later folded role changes into that same response. The result was that users who had just lost access could still see features until the cache expired.</p>
<p>The fix was splitting stable account metadata away from permission-sensitive state. The lesson is to avoid caching authorization data unless you have thought carefully about invalidation.</p>
<h3 id="heading-3-missing-indexes">3. Missing Indexes</h3>
<p>These hide until a table crosses a size threshold. A query that scanned 20,000 rows in development can scan 20 million in production. Bake index review into feature work, and plan big index migrations carefully so they don't lock a hot table at the worst possible time.</p>
<h3 id="heading-4-queue-overload">4. Queue Overload</h3>
<p>Queues don't remove work, they move it. The classic failure is letting one noisy workload block everything else. A big CSV import floods the default queue, and password-reset emails get stuck behind it. Separate queues are cheap insurance against that entire class of incident.</p>
<h3 id="heading-5-large-transactions">5. Large Transactions</h3>
<p>Long transactions hold locks longer and make failures more expensive. Dispatching a job inside a transaction is especially risky because a worker can grab it before the transaction commits:</p>
<pre><code class="language-php">DB::transaction(function () use ($request) {
    $order = Order::create([...]);
    \(order-&gt;items()-&gt;createMany(\)request-&gt;items);

    GenerateInvoicePdf::dispatch($order-&gt;id);
    SyncOrderToCrm::dispatch($order-&gt;id);
});
</code></pre>
<p>Use after-commit dispatching for any job that depends on committed data:</p>
<pre><code class="language-php">GenerateInvoicePdf::dispatch($order-&gt;id)-&gt;afterCommit();
SyncOrderToCrm::dispatch($order-&gt;id)-&gt;afterCommit();
</code></pre>
<p>Keep transactions scoped to the data that genuinely has to change atomically, and nothing more.</p>
<h3 id="heading-6-treating-symptoms-as-causes">6. Treating Symptoms as Causes</h3>
<p>This is the expensive one. If latency is high because an endpoint runs 300 queries, adding app servers adds database pressure. If jobs are slow because an external API is rate-limiting you, adding workers multiplies the failures.</p>
<p>Good scaling work keeps asking the same questions: What resource is saturated? Which endpoint, job, tenant, or query is causing it? Is this work necessary during the request? Can I reduce it, defer it, cache it, or isolate it? How will I know whether the change helped?</p>
<h2 id="heading-a-pre-launch-scaling-checklist">A Pre-Launch Scaling Checklist</h2>
<p>Run through this before a big launch, a traffic campaign, or an enterprise rollout.</p>
<p><strong>Application and runtime:</strong> Cache config, routes, and views during deploy. Set <code>APP_DEBUG=false</code>. Turn on OPcache. Keep web requests short and move slow work to queues. Store uploads in object storage, not on app-server disk. Keep servers stateless. Set timeouts on every external HTTP call.</p>
<p><strong>Database:</strong> Review slow query logs first. Add indexes for your high-volume filters, joins, and ordering. Hunt for N+1 queries in controllers, resources, policies, and views. Paginate every list endpoint. Use <code>chunkById</code> or cursors for batch work. Avoid long transactions and external calls inside transactions. Confirm your backup and restore process works. Test stale-read behavior if you use replicas.</p>
<p><strong>Redis and cache:</strong> Use Redis for cache, sessions, rate limiting, and queues where it fits. Set TTLs unless you have a clear reason not to. Include tenant, user, locale, and version in keys when relevant. Watch memory and the eviction policy. Avoid caching permission-sensitive responses without careful invalidation. Guard against cache stampedes on expensive recomputation.</p>
<p><strong>Queues:</strong> Separate queues by workload. Configure Horizon supervisors per queue. Set timeouts, retries, and backoff on purpose. Make jobs idempotent where you can. Use <code>afterCommit</code> for jobs that depend on committed data. Monitor wait time, runtime, failures, and retries. Review failed jobs instead of ignoring them.</p>
<p><strong>APIs:</strong> Use Resources to control response shape. Cap <code>per_page</code>. Use cursor pagination for big feeds and logs. Cache expensive reads with safe, versioned keys and short TTLs. Apply rate limits by endpoint cost. Don't return raw Eloquent models. Compress responses at the edge.</p>
<p><strong>Observability:</strong> Track p50, p95, and p99 latency on the endpoints that matter. Track error rates by route and job class. Alert on queue wait time, not just size. Watch database CPU, connections, slow queries, and lock waits. Watch Redis memory, latency, and evictions. Log important business operations with durations and identifiers. Test your alerts before launch night because a silent alert is worse than no alert.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Laravel runs high-traffic production systems well when you design around the real costs of data, concurrency, and external dependencies. Just make sure you measure before you optimize, because guessing wastes time and tends to complicate the wrong layer.</p>
<p>Fix the database first: indexes, query shape, pagination, and eager loading usually deliver the biggest early wins. Lean on queues to keep requests fast and push slow work into controlled background workers. Cache deliberately, with clear keys, sane TTLs, and a plan for invalidation. Keep watching latency, errors, queue wait time, database health, Redis memory, and your external dependencies.</p>
<p>The best scaling work is practical and repeatable. You study the system you actually have, remove waste, isolate slow parts, and give yourself enough visibility to make the next change with confidence. Do that on a loop, and you rarely need the big rewrite.</p>
<h2 id="heading-references">References</h2>
<ul>
<li><p><a href="https://laravel.com/docs/eloquent-relationships">Laravel documentation: Eloquent relationships</a></p>
</li>
<li><p><a href="https://laravel.com/docs/queries">Laravel documentation: Database queries</a></p>
</li>
<li><p><a href="https://laravel.com/docs/cache">Laravel documentation: Cache</a></p>
</li>
<li><p><a href="https://laravel.com/docs/queues">Laravel documentation: Queues</a></p>
</li>
<li><p><a href="https://laravel.com/docs/redis">Laravel documentation: Redis</a></p>
</li>
<li><p><a href="https://laravel.com/docs/routing#rate-limiting">Laravel documentation: Rate limiting</a></p>
</li>
<li><p><a href="https://laravel.com/docs/eloquent-resources">Laravel documentation: Eloquent API resources</a></p>
</li>
<li><p><a href="https://laravel.com/docs/horizon">Laravel Horizon documentation</a></p>
</li>
<li><p><a href="https://laravel.com/docs/telescope">Laravel Telescope documentation</a></p>
</li>
<li><p><a href="https://dev.mysql.com/doc/refman/8.4/en/optimization.html">MySQL documentation: Optimization</a></p>
</li>
<li><p><a href="https://redis.io/docs/latest/">Redis documentation</a></p>
</li>
</ul>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Reduce Round Trip Time (RTT) with Next.js ]]>
                </title>
                <description>
                    <![CDATA[ Have you ever wondered why some websites load almost immediately and others leave you looking at a blank screen, even when your internet connection is fast? In some cases, your internet speed may not be the issue. It is usually because of Round Trip ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-reduce-round-trip-time-rtt-with-nextjs/</link>
                <guid isPermaLink="false">690c78446959d1f714d81d45</guid>
                
                    <category>
                        <![CDATA[ Next.js ]]>
                    </category>
                
                    <category>
                        <![CDATA[ web performance ]]>
                    </category>
                
                    <category>
                        <![CDATA[ optimization ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Chukwudi Nweze ]]>
                </dc:creator>
                <pubDate>Thu, 06 Nov 2025 10:28:20 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1762424304223/4d818ff7-0fe2-448d-8acd-3da092bc55a4.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Have you ever wondered why some websites load almost immediately and others leave you looking at a blank screen, even when your internet connection is fast? In some cases, your internet speed may not be the issue. It is usually because of Round Trip Time (RTT), which is how long it takes your browser to send a request to a server and get a response.</p>
<p>The internet depends on physical infrastructure: fiber-optic cables, satellites, and data centers often located thousands of kilometers away. Network requests travel at high speed, but they are still limited by the speed of light (around 300,000 km/s). For instance, a network request from Lagos, Nigeria to a server in San Francisco, USA travels more than 12,000 km, and takes about 150–200 milliseconds for a single round trip under ideal conditions. Multiply that by the 20–30 requests a typical web page makes (for HTML, CSS, images, APIs and more), and those milliseconds quickly add up to seconds of delay before a page fully loads.</p>
<p>In this article, we’ll explain in detail what Round Trip Time(RTT) is, why it is one of the most overlooked factors in web performance, and how you can use Next.js to minimize the number of RTTs to make your applications feel fast and responsive. You will learn how features like Server-Side Rendering (SSR), React Server Components (RSC), image optimization, and caching all work together to reduce Round Trip Time in a web page.</p>
<h2 id="heading-what-you-will-learn"><strong>What You will Learn</strong></h2>
<ul>
<li><p><a class="post-section-overview" href="#heading-what-you-will-learn">What You will Learn</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-what-is-round-trip-time-rtt">What is Round Trip Time (RTT)?</a></p>
<ul>
<li><a class="post-section-overview" href="#heading-how-distance-increases-round-trip-time">How Distance Increases Round Trip Time</a></li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-how-round-trip-time-affects-web-performance">How Round Trip Time Affects Web Performance</a></p>
<ul>
<li><a class="post-section-overview" href="#heading-why-client-side-rendering-feels-slower">Why Client-Side Rendering Feels Slower</a></li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-reduce-round-trip-time-with-nextjs">How to Reduce Round Trip Time with Next.js</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-server-side-rendering-ssr">Server-Side Rendering (SSR)</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-react-server-components-rsc">React Server Components (RSC)</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-image-optimization">Image Optimization</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-caching-and-static-rendering">Caching and Static Rendering</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-trade-offs-across-nextjs-rendering-methods">Trade-offs Across Next.js Rendering Methods</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-when-to-use-each-rendering-method">When to Use Each Rendering Method</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></p>
</li>
</ul>
<h2 id="heading-what-is-round-trip-time-rtt">What is Round Trip Time (RTT)?</h2>
<p>When you visit a website, the browser makes a network request to a server. The server processes the request and then sends a response back. The Round Trip Time is the complete duration of this journey in milliseconds, which includes:</p>
<ol>
<li><p><strong>Travel Time</strong>: The amount of time it took the network request to get to the server.</p>
</li>
<li><p><strong>Processing Time</strong>: The amount of time the server took to process the request.</p>
</li>
<li><p><strong>Return Time</strong>: The amount of time it took the response get back to the browser.</p>
</li>
</ol>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1761405949671/1ceaadf4-5576-41ae-9f25-e846f41b3e67.png" alt="An illustration showing round-trip time (RTT) communication between a client and a server, where the client request takes about 100 ms to reach the server, and the server response takes about 200 ms to return to the client" class="image--center mx-auto" width="990" height="286" loading="lazy"></p>
<h3 id="heading-how-distance-increases-round-trip-time">How Distance Increases Round Trip Time</h3>
<p>Round Trip Time depends heavily on the physical distance between the client and server. For example:</p>
<ul>
<li><p>A user in Lagos, Nigeria making a network request to a server in London that is about 5,000 km away might see a round trip time of 100–150 ms.</p>
</li>
<li><p>A server in San Francisco that is about 12,000 km could push the roundtrip time to 200–300 ms. The farther the server, the higher the round trip time.</p>
</li>
</ul>
<h2 id="heading-how-round-trip-time-affects-web-performance">How Round Trip Time Affects Web Performance</h2>
<p>Modern web pages make multiple network requests to load completely. Imagine loading an e-commerce product page that requires:</p>
<ul>
<li><p>1 network request for HTML (about 200 ms)</p>
</li>
<li><p>5 network requests for CSS/JavaScript (about 1,000 ms)</p>
</li>
<li><p>10 network requests for images (about 2,000 ms)</p>
</li>
<li><p>4 network requests for product data via API (about 800 ms)</p>
</li>
</ul>
<p>That shows that the product page will take 20 network requests to fully load, which is about 4 seconds of network delay.</p>
<p>The probability of bounce increases 32% as page load time goes from 1 second to 3 seconds (<a target="_blank" href="https://www.thinkwithgoogle.com/marketing-strategies/app-and-mobile/page-load-time-statistics/">Google/SOASTA Research, 2017</a>). That means about one-third of visitors leave before the page even loads.</p>
<h3 id="heading-why-client-side-rendering-feels-slower">Why Client-Side Rendering Feels Slower</h3>
<p>In client side rendering applications, each request adds a round trip time, and traditional client-side rendering (CSR) in React apps increases this:</p>
<ul>
<li><p>The browser downloads a minimal HTML shell and a large JavaScript bundle.</p>
</li>
<li><p>The JavaScript runs to fetch data and render the UI, requiring additional network requests.</p>
</li>
<li><p>Each API call adds another RTT, delaying the First Contentful Paint (FCP).</p>
</li>
</ul>
<p>First Contentful Paint (FCP) measures the time from when the user first navigated to the page to when any part of the page's content such as text, images,<code>&lt;svg&gt;</code> or <code>&lt;canvas&gt;</code> elements is rendered on the screen.</p>
<p>In CSR apps, FCP is delayed because the browser cannot display any meaningful content until JavaScript has finished loading, parsing, and executing the code needed to construct the UI. A regular CSR application may need 5 to 10 network round trips to get all the resources needed for the rendering of the UI, which can easily add several seconds of delay.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// pages/index.js (CSR)</span>
<span class="hljs-keyword">import</span> { useState, useEffect } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Home</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [products, setProducts] = useState([])

  useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-comment">// Fetch data after page loads</span>
    fetch(<span class="hljs-string">"https://api.example.com/products"</span>)
      .then(<span class="hljs-function">(<span class="hljs-params">res</span>) =&gt;</span> res.json())
      .then(<span class="hljs-function">(<span class="hljs-params">data</span>) =&gt;</span> setProducts(data))
  }, [])

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>Products<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
      {products.length ? (
        products.map((product) =&gt; <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{product.id}</span>&gt;</span>{product.name}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>)
      ) : (
        <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Loading...<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
      )}
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  )
}
</code></pre>
<p>In the code above, when the <code>Home</code> component mounts, it initializes the state as an empty array. The <code>useEffect</code> hook then runs once to make an API request. While the request is in progress, the “Loading...” message is displayed on the screen. Once the request completes successfully, React updates the state with the fetched data and re-renders the UI to display the products. This process introduces an extra round trip, which further delays the FCP.</p>
<h2 id="heading-how-to-reduce-round-trip-time-with-nextjs">How to Reduce Round Trip Time with Next.js</h2>
<p>You cannot eliminate round trip time completely. Data must still travel over the network. What Next.js does is to reduce how often those network requests happen and how much data each request carries. It does this through a number of techniques, such as <strong>Server-Side Rendering (SSR)</strong>, <strong>React Server Components (RSC)</strong>, <strong>image optimization</strong>, and <strong>caching or static rendering</strong>.</p>
<h3 id="heading-server-side-rendering-ssr">Server-Side Rendering (SSR)</h3>
<p>Unlike traditional React.js applications, where the browser handles the majority of the work, such as fetching static files, JavaScript, and data required to render a page, the server generates the whole HTML, fetches the data, renders the page, and sends it to the browser in a single round trip time.</p>
<p><strong>Advantages:</strong></p>
<ul>
<li><p><strong>Fewer Round Trips:</strong> Since data fetching and rendering take place on the server, the browser receives a ready-to-display page in one round trip time.</p>
</li>
<li><p><strong>Improved First Contentful Paint:</strong> Low round trip time means content displays on the page almost immediately.</p>
</li>
</ul>
<pre><code class="lang-javascript"><span class="hljs-comment">// pages/index.js (SSR)</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getServerSideProps</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-comment">// Fetch data on the server</span>
  <span class="hljs-keyword">const</span> res = <span class="hljs-keyword">await</span> fetch(<span class="hljs-string">'https://api.example.com/products'</span>);
  <span class="hljs-keyword">const</span> products = <span class="hljs-keyword">await</span> res.json();

  <span class="hljs-keyword">return</span> {
    <span class="hljs-attr">props</span>: { products }, <span class="hljs-comment">// Pass data to the page</span>
  };
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Home</span>(<span class="hljs-params">{ products }</span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>Products<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
      {products.map((product) =&gt; (
        <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{product.id}</span>&gt;</span>{product.name}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
      ))}
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}
</code></pre>
<p>In the code above, <code>getServerSideProps</code> runs entirely on the server. When a user visits or refreshes the page, <code>getServerSideProps()</code> is called to fetch product data from the external API. The fetched data is then pre-rendered on the server, meaning the list of products is included in the HTML before it is sent to the browser to display. This removes the additional round trip seen in CSR and improves the FCP, since users see meaningful content as soon as the page loads.</p>
<h3 id="heading-react-server-components-rsc">React Server Components (RSC)</h3>
<p>Server-Side Rendering is a technique where the whole page gets generated on the server. But imagine if only some portions of a page are to be rendered on the server while others are to be rendered on the client?  </p>
<p>React Server Components allow partition of rendering between the server and the client.  </p>
<p>For example, a <code>ProductList</code> component can be rendered on the server, while a <code>SearchInput</code> component renders on the client to manage user interactions.  </p>
<p><strong>Advantages:</strong><br>RSC reduces the overall round trip time (RTT) and also increases the page first contentful paint.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// app/ProductList.jsx (Server Component)</span>
<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">ProductList</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-comment">// Fetch data on the server</span>
  <span class="hljs-keyword">const</span> res = <span class="hljs-keyword">await</span> fetch(<span class="hljs-string">'https://api.example.com/products'</span>);
  <span class="hljs-keyword">const</span> products = <span class="hljs-keyword">await</span> res.json();

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>Products<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
      {products.map((product) =&gt; (
        <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{product.id}</span>&gt;</span>{product.name}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
      ))}
      <span class="hljs-tag">&lt;<span class="hljs-name">ClientSearch</span> /&gt;</span> {/* Client Component */}
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> ProductList;
</code></pre>
<p>In the code above, <code>ProductList</code> is a server component with a <code>ClientSeacrch</code> component as a child component. The <code>ClientSearch</code> renders in the browser while the rest of the <code>ProductList</code> renders on the server. When the page loads, the server runs <code>fetch()</code> to retrieve product data and renders the complete HTML for the product list on the server while <code>ClientSearch</code> renders on the client side to handle user interactions.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// components/ClientSearch.jsx (Client Component)</span>
<span class="hljs-string">'use client'</span>;

<span class="hljs-keyword">import</span> { useState } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">ClientSearch</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [query, setQuery] = useState(<span class="hljs-string">''</span>);

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">input</span>
      <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span>
      <span class="hljs-attr">value</span>=<span class="hljs-string">{query}</span>
      <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(e)</span> =&gt;</span> setQuery(e.target.value)}
      placeholder="Search products..."
    /&gt;</span>
  );
}
</code></pre>
<p>The <code>ClientSearch</code> component above handles user interactions, such as updating the search input with <code>useState</code>. It’s marked with <code>'use client'</code>, so it runs entirely in the client side.</p>
<h3 id="heading-image-optimization">Image Optimization</h3>
<p>Images negatively impact round-trip time RTT when they are unoptimized, as larger files take a longer time to transfer from the server to the browser.</p>
<p>Next.js Image component optimizes images automatically:</p>
<p><strong>Resizing</strong>: It adjusts image size based on the user’s device.</p>
<p><strong>Compression</strong>: It uses new formats like WebP to shrink the file size significantly.</p>
<p><strong>Lazy Loading</strong>: Loads images only when they enter the user’s viewport, which reduces the number of initial requests.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// pages/index.js</span>
<span class="hljs-keyword">import</span> Image <span class="hljs-keyword">from</span> <span class="hljs-string">'next/image'</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Home</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>Welcome to Our Store<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Image</span>
        <span class="hljs-attr">src</span>=<span class="hljs-string">"/product.jpg"</span>
        <span class="hljs-attr">alt</span>=<span class="hljs-string">"Product Image"</span>
        <span class="hljs-attr">width</span>=<span class="hljs-string">{500}</span>
        <span class="hljs-attr">height</span>=<span class="hljs-string">{300}</span>
      /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}
</code></pre>
<p>In the code above, the page uses Next.js built-in <code>Image</code> component to render an optimized image. When the page loads, Next.js optimizes the image resizing, lazy loading, and so on. This means the browser will only download the right image size for the device.</p>
<h3 id="heading-caching-and-static-rendering">Caching and Static Rendering</h3>
<p>With SSR and Server Component, round trip time can still remain high if the server has to process data on every request. Next.js solves this problem with Static Site Generation (SSG) and Incremental Static Regeneration (ISR).  </p>
<p>Here’s how it works:  </p>
<p><strong>Static Site Generation</strong>: Pages are pre-rendered during build time, cached and delivered as static HTML from a CDN.  </p>
<p><strong>Incremental Static Regeneration</strong>: Pages are pre-rendered but can be re-generated in the background after an interval, for example, every 60 seconds.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// app/page.jsx</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> revalidate = <span class="hljs-number">60</span>; <span class="hljs-comment">// Regenerate the page every 60 seconds</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Home</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-comment">// Fetch data on the server</span>
  <span class="hljs-keyword">const</span> res = <span class="hljs-keyword">await</span> fetch(<span class="hljs-string">"https://api.example.com/products"</span>, {
    <span class="hljs-attr">next</span>: { <span class="hljs-attr">revalidate</span>: <span class="hljs-number">60</span> }, 
  });
  <span class="hljs-keyword">const</span> products = <span class="hljs-keyword">await</span> res.json();

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>Products<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
      {products.map((product) =&gt; (
        <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">key</span>=<span class="hljs-string">{product.id}</span>&gt;</span>{product.name}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
      ))}
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}
</code></pre>
<p>In the code above, the page uses Incremental Static Regeneration (ISR). The <code>revalidate = 60</code> option is to regenerate the page every 60 seconds. When a user visits the page, the server serves the pre-rendered HTML instantly. The <code>next: { revalidate: 60 }</code> inside the <code>fetch()</code> means that data is cached for 60 seconds. After 60 seconds, the next request will trigger the server to regenerate a fresh data.</p>
<h2 id="heading-trade-offs-across-nextjs-rendering-methods">Trade-offs Across Next.js Rendering Methods</h2>
<p>With <strong>Server-Side Rendering (SSR)</strong>, the browser gets the complete rendered page in only one round round trip. On the other hand, this can also lead to increased server load and a high TTFB. The TTFB (Time to First Byte) is the duration it takes for a user to see the content displayed on their browser.</p>
<p>With <strong>Incremental Static Regeneration (ISR)</strong>, the page is pre-rendered and cached, thus getting an instantaneous response from the server. The page will be re-generated depending on a fixed period (such as every 60 seconds). The downside of this method is that users might see old content before it gets updated.</p>
<p>In <strong>Server Components</strong>, rendering takes place on the server, and only interactive parts are managed on the client. With this, server-side rendering are still maintained while still allowing client interactions. The only drawback is that developers need to be very particular while deciding what to run on the server and what to run on the client.</p>
<h2 id="heading-when-to-use-each-rendering-method">When to Use Each Rendering Method</h2>
<p><strong>Server-Side Rendering (SSR)</strong> should be applied to pages that updates frequently, such as dashboards, user profiles, and so on. SSR guarantee users to always see the latest data.  </p>
<p>As for <strong>Incremental Static Regeneration (ISR)</strong>, it should be applied to pages with infrequent changes, for instance, product listings, marketing pages, or blogs.  </p>
<p>Use <strong>Server Components</strong> when you want part of the page to render on the server while some sections run on the client. For instance, pages that need user interaction like search inputs or filters, while data fetching and rendering takes place on the server.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Round Trip Time (RTT) is one of the hidden factors behind slow page loads. Each network request adds a round trip, and these network delays build up as the browser fetches several resources like scripts, images, and data files. Next.js deals with this issue by minimizing the number of network requests that need to be done before the first content paint.</p>
<ul>
<li><p><strong>Server-Side Rendering (SSR)</strong> and <strong>React Server Components (RSC)</strong> shift data fetching and rendering to the server, which reduces client-side requests.</p>
</li>
<li><p><strong>Image optimization</strong> reduces image size and uses CDNs to deliver content faster from nearby servers.</p>
</li>
<li><p><strong>Caching and static rendering</strong> serve pre-generated pages instantly without further processing from the server.</p>
</li>
</ul>
<p>With these techniques, you can build web applications that load faster and feel more responsive, even for users who are far from your origin server or are on slower networks.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Optimize Next.js Web Apps for Better Performance ]]>
                </title>
                <description>
                    <![CDATA[ As engineers, we often get so carried away with other aspects of development that we overlook how users perceive and interact with our applications. This oversight can result in users leaving the app almost as soon as they arrive, leading to higher b... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/optimize-nextjs-web-apps-for-better-performance/</link>
                <guid isPermaLink="false">6776a323218b455d646035b2</guid>
                
                    <category>
                        <![CDATA[ Next.js ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Web Development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ web performance ]]>
                    </category>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                    <category>
                        <![CDATA[ web ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Performance Optimization ]]>
                    </category>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                    <category>
                        <![CDATA[ optimization ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Ayantunji Timilehin ]]>
                </dc:creator>
                <pubDate>Thu, 02 Jan 2025 14:30:59 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1735828217839/b65374be-d891-4f19-a359-f84f2ac8f3b9.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>As engineers, we often get so carried away with other aspects of development that we overlook how users perceive and interact with our applications. This oversight can result in users leaving the app almost as soon as they arrive, leading to higher bounce rates and minimal engagement.</p>
<p>At its core, every business thrives on delivering value to its users. When users are unable to access this value due to poor performance, it ultimately impacts the business's success. Slow load times, among other factors, frustrate users and drive them away before they even get a chance to engage.</p>
<p>Optimizing performance is more than just a technical detail – it’s also a critical part of creating a successful application. Without it, even the best features can go unnoticed if users don’t stick around long enough to see them.</p>
<p>In this article, we’ll explore key approaches to optimize your Next.js application, making it faster and more efficient.</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ul>
<li><p><a class="post-section-overview" href="#heading-building-a-performant-app">Building a Performant Application</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-optimize-your-applications">How to Optimize Your Applications</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-key-techniques-to-optimize-performance">Key Techniques To Optimize Performance</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-1-using-the-nextjs-image-component">Using The Next.js Image Component</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-2-optimizing-third-party-scripts-with-the-nextjs-script-component">Optimizing Third-Party Scripts with the Next.js Script Component</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-3-remove-unused-packagesdependencies">Remove Unused Packages/Dependencies</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-4-caching-and-incremental-static-regeneration-isr">Caching and Incremental Static Regeneration (ISR)</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-caching-frequently-used-content">Caching Frequently Used Content</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-5-font-optimization-with-nextfont">Font Optimization With next/font</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-6-lazy-loading-and-code-splitting">Lazy Loading And Code Splitting</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-lazy-loading-in-nextjs">Lazy Loading in Next.js</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-code-splitting">Code Splitting</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></p>
</li>
</ul>
<h2 id="heading-building-a-performant-application">Building a Performant Application</h2>
<p>Making your apps more performant means striking the right balance between speed, responsiveness, and efficient use of resources. You should strive to create an application that delivers value and keeps users satisfied.</p>
<p>Building a performant app is about making sure the app feels smooth and intuitive so that there are no frustrating lags when a user clicks buttons, scrolls, or navigates around. You’ll also want to make sure that data loads or updates without unnecessary delays.</p>
<h2 id="heading-how-to-optimize-your-applications">How to Optimize Your Applications</h2>
<p>The first step in optimizing your application is identifying problem areas. A number of tools and packages can help you analyze your application's performance effectively. Here's how you can use them:</p>
<h3 id="heading-using-npm-run-build">Using <code>npm run build</code></h3>
<p>When you run <code>npm run build</code>, Next.js creates a production-ready version of your application and gives a detailed breakdown of your pages. This includes:</p>
<ul>
<li><p><strong>Size</strong>: The size of the JavaScript files for each route. Highlighting any routes that are too large and could slow things down. Smaller page sizes generally result in faster load times while large pages might take longer to download, especially for users with slower network connections.</p>
</li>
<li><p><strong>First Load Js</strong>: This column provides information about the total amount of JavaScript the browser needs to download and execute to fully render the page for the first time. Large <strong>First Load JS</strong> values</p>
<p>  cause Slower Time-to-Interactive (TTI).</p>
</li>
</ul>
<p>Running this command produces an analysis like below:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1734639730677/cfd1f858-a9df-4e6c-af28-454857309156.png" alt="Example result of running npm run build" class="image--center mx-auto" width="984" height="300" loading="lazy"></p>
<h3 id="heading-using-nextbundle-analyzer">Using <code>@next/bundle-analyzer</code></h3>
<p>The <a target="_blank" href="https://www.npmjs.com/package/@next/bundle-analyzer">bundle analyzer</a> is a package provided by Next.js to analyze the size of JavaScript bundles by providing a visual representation of the application’s module and dependencies. Here’s how to use the package:</p>
<p>First, install the package by running this command:</p>
<pre><code class="lang-bash">npm install @next/bundle-analyzer
</code></pre>
<p>Or you can use yarn:</p>
<pre><code class="lang-bash">yarn add @next/bundle-analyzer
</code></pre>
<p>Then add the <code>@next/bundle-analyzer</code> configuration to your <code>next.config.js</code> file:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> withBundleAnalyzer = <span class="hljs-built_in">require</span>(<span class="hljs-string">'@next/bundle-analyzer'</span>)({
  <span class="hljs-attr">enabled</span>: process.env.ANALYZE === <span class="hljs-string">'true'</span>,
});

<span class="hljs-built_in">module</span>.exports = withBundleAnalyzer({
  <span class="hljs-comment">// other Next.js config options here</span>
});
</code></pre>
<p>To analyze your application bundles while generating a production build, run the following command:</p>
<pre><code class="lang-bash">ANALYZE=<span class="hljs-literal">true</span> npm run build
</code></pre>
<p>For a step-by-step guide on how to use the bundle analyzer effectively, check out this detailed <a target="_blank" href="https://www.youtube.com/watch?v=EIGmcxwbbZw">video tutorial</a></p>
<h3 id="heading-browser-tools">Browser tools</h3>
<p>Finally, modern browsers, including Google Chrome, Firefox, and Edge, offer powerful tools to analyze and improve your application's performance. Features like the Performance Tab help you record and visualize how your application runs, pinpointing issues like slow rendering or long tasks.</p>
<p>You can also use tools like Lighthouse (available in Chrome and Edge) to generate automated audits, highlighting problems such as large assets and unoptimized resources.</p>
<p>To access the <strong>Lighthouse</strong> and <strong>Performance</strong> tabs:</p>
<ol>
<li><p>Open your browser's developer tools by right-clicking anywhere on the browser and selecting the <strong>Inspect</strong> option or pressing <strong>Command + Option + I</strong> (on Mac) or <strong>Ctrl + Shift + I</strong> (on Windows).</p>
</li>
<li><p>Look at the top menu in the developer tools.</p>
</li>
<li><p>If you don’t see the <strong>Lighthouse</strong> or <strong>Performance</strong> tabs right away, click the <strong>double right arrow (&gt;&gt;)</strong> to reveal hidden tabs.</p>
</li>
<li><p>Select the desired tab to start analyzing performance or generating a Lighthouse report.</p>
</li>
</ol>
<p>Here is an example of a generated audit in the Performance tab on Chrome</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735616911745/e5f09934-df99-40fc-b194-a292a21a4517.png" alt="image of the performance tab on chrome browser" class="image--center mx-auto" width="1130" height="966" loading="lazy"></p>
<p>Here’s another image showing the generated audit by lighthouse</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1735617075187/dfde608b-eeb7-443d-81c6-56ff2a6dd92b.png" alt="dfde608b-eeb7-443d-81c6-56ff2a6dd92b" class="image--center mx-auto" width="1124" height="1522" loading="lazy"></p>
<h2 id="heading-key-techniques-to-optimize-performance">Key Techniques to Optimize Performance</h2>
<h3 id="heading-1-using-the-nextjs-image-component">1.) Using The Next.js <code>Image</code> Component</h3>
<p>Images often account for the largest portion of page weight, directly affecting load times and user experience. Large images slow down rendering and ultimately, increase bandwidth usage.</p>
<p>Next.js has a built-in <code>Image</code> component that automatically optimizes images, making it very useful for web performance. It takes care of resizing, lazy loading, and format optimization, so images are served in the most performant format (like .WebP) when the browser supports it.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> Image <span class="hljs-keyword">from</span> <span class="hljs-string">'next/image'</span>;

    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Image</span>
      <span class="hljs-attr">src</span>=<span class="hljs-string">"/house.jpg"</span>
      <span class="hljs-attr">alt</span>=<span class="hljs-string">"House Image"</span>
      <span class="hljs-attr">width</span>=<span class="hljs-string">{700}</span>
      <span class="hljs-attr">height</span>=<span class="hljs-string">{500}</span>
      <span class="hljs-attr">priority</span>=<span class="hljs-string">{false}</span> // <span class="hljs-attr">Lazy</span> <span class="hljs-attr">loads</span> <span class="hljs-attr">the</span> <span class="hljs-attr">image</span> <span class="hljs-attr">by</span> <span class="hljs-attr">default</span>
    /&gt;</span></span>
</code></pre>
<p>In the snippet above,</p>
<ul>
<li><p><code>src="/house.jpg"</code>: This points to the image file's location, which is in the <code>public</code> folder. Images in the <code>/public</code> directory are served statically, so you don’t need extra configuration.</p>
</li>
<li><p><code>alt="House Image"</code>: The <code>alt</code> text (just like in the native HTML <code>image</code> element) provides a description of the image, which is great for accessibility (like screen readers) and also helps with SEO.</p>
</li>
<li><p><code>width &amp; heigh</code>t: By explicitly setting the width and height, Next.js can calculate the space the image will occupy on the page before it loads. This prevents the page layout from shifting as the image loads, which improves user experience and boosts performance metrics like <a target="_blank" href="https://blog.hubspot.com/marketing/cumulative-layout-shift">Cumulative Layout Shift</a> (as shown in the image above).</p>
</li>
<li><p><code>priority={false}</code>: This ensures the image will only load when it's near the user's viewport conserving the bandwidth and improving page load times for non-critical images. However, for important images that should load immediately (like those visible as soon as the page opens), you can set <code>priority={true}</code> to bypass lazy loading and ensure the image loads as quickly as possible.</p>
</li>
</ul>
<p>One of the key advantages of the Next.js <code>Image</code> component is its built-in <strong>lazy loading</strong> feature. This means that images won’t be loaded until they are actually needed (when they enter the viewport). By only loading images that are about to be viewed, performance is improved and pages can load faster, even with many high-quality images.</p>
<h3 id="heading-2-optimizing-third-party-scripts-with-the-nextjs-script-component">2.) Optimizing Third-Party Scripts with the Next.js Script Component</h3>
<p>Third-party scripts, such as analytics tools or advertising networks, can heavily affect your application's performance if not properly managed. Next.js has a <strong>Script</strong> component that makes it easy to load scripts efficiently, giving you control over how and when they load.</p>
<p>The <code>Script</code> component allows you to define a <strong>loading strategy</strong> for scripts, determining when and how they are fetched and executed. By prioritizing or deferring scripts based on their importance, you can improve the overall performance and user experience of your application.</p>
<ul>
<li><p><code>beforeInteractive</code><strong>:</strong> Use this strategy for scripts that must load before the page becomes interactive, like essential analytics or monitoring tools.</p>
</li>
<li><p><code>afterInteractive</code>: When you use this strategy, the script loads after the page becomes interactive, which is the default behavior. This is ideal for scripts that add functionality but aren’t essential for initial rendering.</p>
</li>
<li><p><code>lazyOnload</code>: Defers loading the script until all other page resources have finished loading. This is perfect for non-essential scripts like ads or social media widgets.</p>
</li>
</ul>
<pre><code class="lang-javascript">&lt;Script src=<span class="hljs-string">"https://example.com/non-essential.js"</span> strategy=<span class="hljs-string">"lazyOnload"</span> /&gt; <span class="hljs-comment">//Pass the strategy as a prop to the component</span>
</code></pre>
<p>By leveraging the Next.js <code>Script</code> component, you can prevent scripts from blocking critical rendering, reducing load times and improve <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Glossary/Time_to_interactive">Time to Interactive</a> (TTI).</p>
<h3 id="heading-3-remove-unused-packagesdependencies">3.) Remove Unused Packages/Dependencies</h3>
<p>Over time, as you build and maintain your project, unused dependencies can pile up in your codebase. These unnecessary packages increase the size of your project, slow down installation times, and make the code harder to maintain. Cleaning up these unused dependencies is essential for optimizing your application's performance and keeping your codebase clean.</p>
<p>The <a target="_blank" href="https://www.npmjs.com/package/depcheck">depcheck</a> tool is a great way to identify and remove unused dependencies from your project. It analyzes your <code>package.json</code> and the project files to find unused dependencies, unused devDependencies, and missing dependencies.</p>
<p>You can run a <code>depcheck</code> like this:</p>
<pre><code class="lang-bash">npx depcheck
</code></pre>
<p>After identifying the unused dependencies, you can remove them by running:</p>
<pre><code class="lang-bash">npm uninstall &lt;package-name&gt;
</code></pre>
<p>or with yarn:</p>
<pre><code class="lang-bash">yarn remove &lt;package-name&gt;
</code></pre>
<p>Regularly running <code>depcheck</code> is a simple yet effective way to keep your project clean and efficient.</p>
<h3 id="heading-4-caching-and-incremental-static-regeneration-isr">4.) Caching and Incremental Static Regeneration (ISR)</h3>
<p>When you find yourself running the same calculations or database queries repeatedly, you should consider caching. It’s a simple yet powerful way to boost your web application's performance, especially for content that doesn’t change often. By storing frequently accessed data in a cache, you can avoid unnecessary processing and speed up load times.</p>
<p>In Next.js, you can take this a step further with Incremental Static Regeneration (ISR), which lets you serve static content instantly while keeping it fresh behind the scenes.</p>
<p><strong>Incremental Static Regeneration (ISR)</strong> in Next.js lets you update static pages without rebuilding the whole site. Here's how it works:</p>
<ol>
<li><p><strong>Build time generation</strong>: ISR generates pages when the site is built.</p>
</li>
<li><p><strong>Caching</strong>: It stores the pages so they load quickly when users visit.</p>
</li>
<li><p><strong>Background updates</strong>: When content changes, ISR updates the pages behind the scenes without affecting users.</p>
</li>
<li><p><strong>Dynamic updates</strong>: It combines the fast loading of static pages with the ability to update content regularly.</p>
</li>
</ol>
<pre><code class="lang-javascript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getStaticProps</span>(<span class="hljs-params"></span>) </span>{

  <span class="hljs-keyword">const</span> data = <span class="hljs-keyword">await</span> fetchData();

  <span class="hljs-keyword">return</span> {
    <span class="hljs-attr">props</span>: { data },
    <span class="hljs-comment">//regenerate the page every 20 seconds.</span>
    <span class="hljs-attr">revalidate</span>: <span class="hljs-number">20</span>,
  };
}

<span class="hljs-comment">//pre-render the page as static content</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">MyPage</span>(<span class="hljs-params">{ data }</span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>My Page<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>{data}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> MyPage;
</code></pre>
<h3 id="heading-caching-frequently-used-content">Caching Frequently Used Content</h3>
<p>For websites with pages that get a lot of visitors, like product listings or blog posts, it's important to keep the content fast and up-to-date.</p>
<p>Caching helps achieve this by saving a copy of the page so it doesn't need to be created from scratch each time someone visits. The browser or server will store this cached page for a set amount of time, which is controlled by caching headers. Meanwhile, ISR (Incremental Static Regeneration) ensures that the page can be updated in the background when necessary, without needing to rebuild the entire site.</p>
<p>In applications with lots of data, caching can also speed up the process by storing API responses. This way, when users request the same data again, they can get it quickly from the cache instead of waiting for it to be fetched anew. Tools like Vercel and Content Delivery Networks (CDNs) help by storing these cached pages in multiple locations around the world, so visitors can access them faster.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getStaticProps</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> data = <span class="hljs-keyword">await</span> fetchData();

  <span class="hljs-keyword">return</span> {
    <span class="hljs-attr">props</span>: { data },
    <span class="hljs-comment">// Regenerate page at most once every 30 seconds</span>
    <span class="hljs-attr">revalidate</span>: <span class="hljs-number">30</span>,
    <span class="hljs-comment">// Cache for 1 hour at the CDN level</span>
    <span class="hljs-attr">headers</span>: {
      <span class="hljs-string">'Cache-Control'</span>: <span class="hljs-string">'public, max-age=3600, must-revalidate'</span>,
    },
  };
}
</code></pre>
<p>Here, the page regenerates every 30 seconds and is cached at the CDN level for one hour. The <code>Cache-Control</code> header tells the CDN and browser to cache the page for 1 hour and revalidate it afterward.</p>
<p>For a deeper dive into caching and its role in web performance, check out this insightful <a target="_blank" href="https://www.freecodecamp.org/news/caching-vs-content-delivery-network/">freeCodeCamp article on Caching vs. Content Delivery Networks</a>.</p>
<h3 id="heading-5-font-optimization-with-nextfont">5.) Font Optimization With <code>next/font</code></h3>
<p>The <code>next/font</code> module in Next.js automatically handles font loading for improved performance, so you don’t need to manually configure or use extra libraries. It loads only the essential parts of the font, which results in faster page load times.</p>
<p>To further reduce the font file size, you can provide the <code>subsets</code> array which ensures fewer bytes are transferred and pages load quickly.</p>
<p>Here’s how it works:</p>
<ul>
<li><p><strong>Automatic font loading</strong>: The module optimizes font loading automatically, making sure fonts are served in the most efficient way, improving performance without extra effort.</p>
</li>
<li><p><strong>Subsetting fonts</strong>: You can specify the exact font characters needed for your app.</p>
</li>
<li><p><strong>Font display strategy</strong>: The font-display strategy determines how text is shown to the user while fonts are loading. Next.js typically uses the <code>swap</code> strategy by default, but you can manually configure it if necessary. The most common strategies are <code>swap</code> <code>fallback</code> <code>optional</code> and <code>block</code>.</p>
</li>
<li><pre><code class="lang-javascript">  <span class="hljs-keyword">import</span> { Inter } <span class="hljs-keyword">from</span> <span class="hljs-string">'next/font/google'</span>

  <span class="hljs-keyword">const</span> inter = Inter({
    <span class="hljs-attr">subsets</span>: [<span class="hljs-string">'latin'</span>, <span class="hljs-string">'latin-ext'</span>], <span class="hljs-comment">// Load only the Latin and extended Latin subsets</span>
    <span class="hljs-attr">weight</span>: <span class="hljs-string">'400'</span>, <span class="hljs-comment">// Choose the specific weight you need</span>
    <span class="hljs-attr">style</span>: <span class="hljs-string">'normal'</span>, <span class="hljs-comment">// Specify the style if needed</span>
  })

  <span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Page</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">return</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">{inter.className}</span>&gt;</span>Hello World<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  }
</code></pre>
</li>
</ul>
<p>The snippet above uses the Next.js built-in tool for Google Fonts. Instead of adding the font link in your HTML or using a third-party library, you can import it directly like this for ease and efficiency.s</p>
<ul>
<li><p><strong>subsets:</strong> Tells the app to load only the characters needed. Skipping other character sets like Cyrillic (used in Russian) or Greek, avoids downloading extra, unnecessary data, which keeps your app lightweight and faster to load.</p>
</li>
<li><p><strong>weight:</strong> Instead of loading all font weights (e.g., Bold, Light), you only bring in Regular (400). This reduces the overall size.</p>
</li>
<li><p><strong>style:</strong> Stick with the standard style (no fancy italics). This also trims down what’s downloaded.</p>
</li>
</ul>
<h3 id="heading-6-lazy-loading-and-code-splitting">6.) Lazy Loading and Code Splitting</h3>
<p>When building web apps, you want to make sure your users don’t wait too long for your pages to load. A big part of this involves reducing how much JavaScript is loaded when the page first opens. Two techniques that help with this are <strong>lazy loading</strong> and <strong>code splitting</strong>, both of which Next.js makes easy to use.</p>
<h4 id="heading-lazy-loading-in-nextjs">Lazy Loading in Next.js</h4>
<p>Think of lazy loading like waiting to download a movie only when you decide to watch it. Imagine you have a large component like a chart or a map that users only see after interacting with a page. Instead of loading it upfront, you can tell Next.js to load it only when it’s needed using <code>next/dynamic</code>.</p>
<h4 id="heading-code-splitting-in-nextjs">Code Splitting in Next.js</h4>
<p>Code splitting breaks your JavaScript into smaller pieces (called bundles), so users only load what’s necessary. For example, if a user visits your homepage, there’s no need to load JavaScript for other pages like "About Us" or "Dashboard". It typically happens during the build process or dynamically at runtime.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> dynamic <span class="hljs-keyword">from</span> <span class="hljs-string">'next/dynamic'</span>

<span class="hljs-comment">// Load HeavyComponent only when it’s rendered</span>
<span class="hljs-keyword">const</span> HeavyComponent = dynamic(<span class="hljs-function">() =&gt;</span> <span class="hljs-keyword">import</span>(<span class="hljs-string">'./HeavyComponent'</span>), { <span class="hljs-attr">ssr</span>: <span class="hljs-literal">false</span> })

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Home</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>Welcome Home!<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">HeavyComponent</span> /&gt;</span> {/* This loads only when rendered */}
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  )
}
</code></pre>
<p>In the above code, <code>dynamic</code> dynamically imports the component only when needed. <code>ssr: false</code> disables server-side rendering for the component, which can save resources if the component doesn’t need to be pre-rendered.</p>
<p>Next.js automatically splits code by page, meaning each page only loads the necessary JavaScript when accessed, improving load times. For more granular control, <code>next/dynamic</code> allows you to dynamically import specific components, ensuring they are loaded lazily only when needed. While Next.js handles page-level code splitting by default, using <code>next/dynamic</code> gives you the flexibility to apply component-level splitting, optimizing resource loading and enhancing performance.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Creating a high-performance application is a very important aspect of any business. A faster and more efficient application enhances user engagement, lowers bounce rates, and boosts SEO rankings, which all contribute to business growth and customer satisfaction.</p>
<p>By utilizing these techniques we discussed in this guide, you can provide a smooth user experience while maintaining optimal efficiency behind the scenes.</p>
<p>Remember, every second saved in load time translates to happier users and, ultimately, better business outcomes.</p>
<p>Thank you for reading!</p>
<p>Want to connect with me?</p>
<ul>
<li><p>Twitter / X: <a target="_blank" href="https://x.com/Timi471">@timi471</a></p>
</li>
<li><p>Linkedin: <a target="_blank" href="https://www.linkedin.com/in/timilehin-micheal/">Ayantunji Timilehin</a></p>
</li>
<li><p>Email: ayantunjitimilehin@gmail.com</p>
</li>
</ul>
<h3 id="heading-references">References</h3>
<ul>
<li><p><a target="_blank" href="https://nextjs.org/docs/pages/building-your-application/optimizing">Next.Js Documentation</a></p>
</li>
<li><p><a target="_blank" href="https://www.freecodecamp.org/news/caching-vs-content-delivery-network/">Caching-vs-content-delivery-network</a></p>
</li>
<li><p><a target="_blank" href="https://www.youtube.com/watch?v=EIGmcxwbbZw">Using next/bundle-analyzer</a></p>
</li>
<li><p><a target="_blank" href="https://blog.hubspot.com/marketing/cumulative-layout-shift">Cumulative layout shift</a></p>
</li>
</ul>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Boost Web Performance with Prefetching – Improve User Experience by Reducing Load Time ]]>
                </title>
                <description>
                    <![CDATA[ We've all encountered the frustration of waiting through long loading screens, only to find ourselves stuck with unresponsive pages. You see loading spinners everywhere, but nothing seems to move forward. Let me paint a clearer picture for you: This... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/boost-web-performance-with-prefetching/</link>
                <guid isPermaLink="false">66f18dbb04f1822b270db01b</guid>
                
                    <category>
                        <![CDATA[ web performance ]]>
                    </category>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Keyur Paralkar ]]>
                </dc:creator>
                <pubDate>Mon, 23 Sep 2024 15:48:11 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/-Vqn2WrfxTQ/upload/0657c02758973f4ea5701f2bd98469a7.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>We've all encountered the frustration of waiting through long loading screens, only to find ourselves stuck with unresponsive pages. You see loading spinners everywhere, but nothing seems to move forward. Let me paint a clearer picture for you:</p>
<p><a target="_blank" href="https://dribbble.com/shots/3358709-Skeleton-Loader#"><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1726397417280/bc56c517-c63f-433e-93c6-939c3b82c556.gif" alt="Multiple skeleton loader on a dashboard page" class="image--center mx-auto" width="800" height="600" loading="lazy"></a></p>
<p>This typically happens because the website is trying to fetch all the necessary data as soon as you land on the page. It could be that a API request is being processed, or multiple APIs are fetching data sequentially, causing delays in loading the page.</p>
<p>The result? A poor user experience. You might think, "How can such a large company not prioritize user experience? This is disappointing." Consequently, users often leave the site, affecting key metrics and potentially impacting revenue.</p>
<p>But what if you could fetch the data for these heavy pages ahead of time, so that by the time a user lands on the page, they can interact with it instantly?</p>
<p>This is where the concept of prefetching comes in, and that's exactly what we'll be diving into in this blog post. So without further ado, let's get started!</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ul>
<li><p><a class="post-section-overview" href="#heading-prefetching-as-a-solution">Prefetching as a Solution</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-prefetching-improves-user-experience">How Prefetching Improves User Experience</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-understanding-the-problem">Understanding The Problem</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-solution-1-prefetching-data-in-the-parent-component">Solution #1: Prefetching Data in the Parent Component</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-solution-2-prefetch-data-on-page-load">Solution #2: Prefetch Data on Page load</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-implement-prefetching-with-react">How to Implement Prefetching with React</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-implement-prefetching-with-react">Too much prefetching can also cause</a> <a class="post-section-overview" href="#heading-too-much-prefetching-can-also-cause-slowness">s</a><a class="post-section-overview" href="#heading-how-to-implement-prefetching-with-react">lowness</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-summary">Summary</a></p>
</li>
</ul>
<h2 id="heading-prefetching-as-a-solution">Prefetching as a Solution</h2>
<p>Here’s the revised version with just the grammar and spelling corrected:</p>
<p>For the problem above, what we want is to fetch the data for a given page before it's loaded onto the website so that the user doesn’t need to fetch the data on page load. This is called prefetching. From a technical perspective, its definition is as follows:</p>
<blockquote>
<p><em>It is a way to fetch the required data beforehand so that the main component doesn’t need to wait for the data, thus enhancing the experience.</em></p>
</blockquote>
<p>This can improve the user experience, boosting the customer’s confidence in your website.</p>
<p>Prefetching is a simple yet elegant solution that is more user-centric than a standard process. To implement prefetching, we need to understand the user’s behavior on the website. That is, the most visited pages, or which components fetch data on small interactions (such as hover).</p>
<p>After analyzing such scenarios, it makes sense to apply prefetching to them. However, as developers, we should be mindful of using this concept. Too much prefetching can also slow down your website since you're trying to fetch a lot of data for future scenarios, which might block the fetching of data for the main page.</p>
<h2 id="heading-how-prefetching-improves-user-experience">How Prefetching Improves User Experience</h2>
<p>Let us look at couple of scenarios where prefetching is beneficial:</p>
<ol>
<li><p>Loading data/page earlier for the most visited link from your landing page. For example, consider that you have a “contact us” link. Let’s assume that this is the link that users mostly check and it contains a lot of data when it loads. Rather than loading the data when the contact us page loads, you can simply fetch the data on the homepage so that you don’t have to wait at the Contact Us page for the data. You can read more about prefetching pages <a target="_blank" href="https://web.dev/articles/link-prefetch">here</a>.</p>
</li>
<li><p>Prefetching table data for later pages.</p>
</li>
<li><p>Fetching data from a parent component and loading it in the child component.</p>
</li>
<li><p>Prefetching data that needs to be displayed in a popover.</p>
</li>
</ol>
<p>These are some of the ways to achieve prefetching in your application and how it helps improve the user experience.</p>
<p>In this blog post we will be discussing about the last scenario: <em>“</em>prefetching data that needs to be displayed in the popover”. This is a classic example where prefetching can be beneficial and provides a smoother experience to the user.</p>
<h2 id="heading-understanding-the-problem">Understanding The Problem</h2>
<p>Let me define the problem here. Imagine the following scenario:</p>
<ol>
<li><p>You have a component that displays specific information.</p>
</li>
<li><p>There is an element inside this component that shows another popover/tooltip when you hover on it.</p>
</li>
<li><p>The popover fetches data when it loads.</p>
</li>
</ol>
<p>Now imagine that the user hovers on the element and needs to wait for the data to be fetched and displayed in the popover. During this wait, they see the skeleton loader.</p>
<p>The scenario will look like this:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1726395720567/6ec88fab-ffe2-4f20-b934-94342f9cf3c0.gif" alt="Example of fetching data when the popover component mounts" class="image--center mx-auto" width="600" height="268" loading="lazy"></p>
<p>It’s just frustrating how long the user has to wait whenever they hover on the image:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1726395733461/3598da70-e8af-4a1a-b3cf-5c3ed62fe9cc.gif" alt="User hovering images to load popover component that fetches data" class="image--center mx-auto" width="600" height="268" loading="lazy"></p>
<p>To solve this problem, there are two solutions that can help you get started and optimize the solution according to your needs.</p>
<h2 id="heading-solution-1-prefetching-data-in-the-parent-component">Solution #1: Prefetching Data in the Parent Component</h2>
<p>This solution is inspired from <a target="_blank" href="https://martinfowler.com/articles/data-fetch-spa.html?utm_source=cassidoo&amp;utm_medium=email&amp;utm_campaign=until-youre-ready-to-look-foolish-youll-never#prefetching">Martin Fowler’s blogpost</a>. It allows you to fetch the data before the popup appears, instead of fetching on component load.</p>
<p>The popup appears when you hover on it. We can fetch the data when the mouse enters the parent component. Before the actual component—the image—is hovered on, we’ll have the data for the popover and will pass it to the popover component.</p>
<p>This solution doesn’t remove the loading state all together but it helps to significantly lower the chances of seeing the loading state.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1726395771616/69b6c536-8b62-4124-837a-f26746f6f305.gif" alt="Improving the UX by fetching the data from the parent component" class="image--center mx-auto" width="600" height="296" loading="lazy"></p>
<h2 id="heading-solution-2-prefetch-data-on-page-load">Solution #2: Prefetch Data on Page load</h2>
<p>This solution is inspired by <a target="_blank" href="http://x.com">x.com</a> where, for the popover component, they fetch the data partially on the main page load and fetch the rest of the data when the component mounts.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1726395833198/c7f1fa64-986d-4bfc-83cb-f052cd560f3a.gif" alt="Twitter advertisement by XDevelopers. Text reads: &quot;Calling all #developers! Innovate with our real-time and historical data on the X API. Get started with Pro👇&quot;. Image shows a person in a white shirt with text &quot;Build what's next with our API @XDevelopers&quot; and &quot;Subscribe now!&quot; Used by permission. From twitter.com." class="image--center mx-auto" width="800" height="522" loading="lazy"></p>
<p>As you can see from the above video, the user’s profile details are viewed in the popover. If you look closely, the details related to followers are fetched later.</p>
<p>This technique is highly efficient when you have a lot of data to be displayed in the popover but fetching them can be costly on popover mount or on the main page load.</p>
<p>A better solution would be to partially load the required data on the main page and load the rest of the data when the component mounts.</p>
<p>In our example, we fetched the data for the popover when the cursor entered the image’s parent element. Now imagine that you need to fetch additional details once the popover data is loaded. So based on the above x.com’s method, we can fetch additional data on popover load. Here is the outcome of it:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1726395913909/b5f6f231-5a1e-4c44-a4eb-bd5ed863ce3b.gif" alt="GIF explaining how we prefetch data from parent and load additional data on component mount for popover " class="image--center mx-auto" width="1464" height="898" loading="lazy"></p>
<p>Here, we do the following things:</p>
<ul>
<li><p>We fetch the main data which is just necessary to render the popover when mouse enters the parent component of the image.</p>
</li>
<li><p>This gives us enough time to fetch the main data.</p>
</li>
<li><p>On popover load, we fetch another data, which is the album count. While the user reads data like name and email, we’ll have the next data ready to be seen.</p>
</li>
</ul>
<p>This way, we can make small and smart tweaks to minimize the blank staring of loaders on the screen 😊.</p>
<h2 id="heading-how-to-implement-prefetching-with-react">How to Implement Prefetching with React</h2>
<p>In this section we’ll briefly go through the how to implement the above prefetching example app.</p>
<h3 id="heading-project-setup">Project Setup</h3>
<p>To get started with creating the prefetching app, follow the process below:</p>
<p>You can use <a target="_blank" href="https://vitejs.dev/">vitejs</a> (this is what I used) or <a target="_blank" href="https://create-react-app.dev/">create-react-app</a> to create your app. Paste the command below in your terminal:</p>
<pre><code class="lang-bash">yarn create vite prefetch-example --template react-ts
</code></pre>
<p>Once the app has been created, you should have the following folder structure when you open the <strong>prefetch-example</strong> folder with VS Code.</p>
<ul>
<li><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1726764168271/2dc9bfa1-07d9-491e-96fd-e780c3623eeb.png" alt="Image of the folder structure once the vitejs app is created" class="image--center mx-auto" width="732" height="996" loading="lazy"></li>
</ul>
<p>Now let us dive into the components that we are going to be building for this app.</p>
<h3 id="heading-components">Components</h3>
<p>In this example we are going to be using 3 components:</p>
<ul>
<li><p><code>PopoverExample</code></p>
</li>
<li><p><code>UserProfile</code></p>
</li>
<li><p><code>UserProfileWithFetching</code></p>
</li>
</ul>
<h3 id="heading-popoverexample-component"><code>PopoverExample</code> Component</h3>
<p>Let us start with the first component which is the <code>PopoverExample</code>. This component displays an image avatar and some text to the right side of it. It should look like this:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1727002319443/bcc28972-fce0-42ba-899c-274513c4a7c6.png" alt="Image of the PopoverExample component that contains image to the left and lorem ipsum text to the right" class="image--center mx-auto" width="1376" height="656" loading="lazy"></p>
<p>The purpose of this component is to serve as an example similar to the real life scenarios. The image in this component loads a popover component when it is hovered on.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1727002429245/9af8f26e-f149-41f7-b124-3ec2a0f5c80a.png" alt="Image of popover element that contains user information when the image is hovered" class="image--center mx-auto" width="1480" height="950" loading="lazy"></p>
<p>Here’s the code for the component:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { useState } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> { useFloating, useHover, useInteractions } <span class="hljs-keyword">from</span> <span class="hljs-string">"@floating-ui/react"</span>;
<span class="hljs-keyword">import</span> ContentLoader <span class="hljs-keyword">from</span> <span class="hljs-string">"react-content-loader"</span>;
<span class="hljs-keyword">import</span> UserProfile <span class="hljs-keyword">from</span> <span class="hljs-string">"./UserProfile"</span>;
<span class="hljs-keyword">import</span> UserProfileWithFetching <span class="hljs-keyword">from</span> <span class="hljs-string">"./UserProfileWithFetching"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> MyLoader = <span class="hljs-function">() =&gt;</span> (
    &lt;ContentLoader
        speed={<span class="hljs-number">2</span>}
        width={<span class="hljs-number">340</span>}
        height={<span class="hljs-number">84</span>}
        viewBox=<span class="hljs-string">"0 0 340 84"</span>
        backgroundColor=<span class="hljs-string">"#d1d1d1"</span>
        foregroundColor=<span class="hljs-string">"#fafafa"</span>
    &gt;
        &lt;rect x=<span class="hljs-string">"0"</span> y=<span class="hljs-string">"0"</span> rx=<span class="hljs-string">"3"</span> ry=<span class="hljs-string">"3"</span> width=<span class="hljs-string">"67"</span> height=<span class="hljs-string">"11"</span> /&gt;
        &lt;rect x=<span class="hljs-string">"76"</span> y=<span class="hljs-string">"0"</span> rx=<span class="hljs-string">"3"</span> ry=<span class="hljs-string">"3"</span> width=<span class="hljs-string">"140"</span> height=<span class="hljs-string">"11"</span> /&gt;
        &lt;rect x=<span class="hljs-string">"127"</span> y=<span class="hljs-string">"48"</span> rx=<span class="hljs-string">"3"</span> ry=<span class="hljs-string">"3"</span> width=<span class="hljs-string">"53"</span> height=<span class="hljs-string">"11"</span> /&gt;
        &lt;rect x=<span class="hljs-string">"187"</span> y=<span class="hljs-string">"48"</span> rx=<span class="hljs-string">"3"</span> ry=<span class="hljs-string">"3"</span> width=<span class="hljs-string">"72"</span> height=<span class="hljs-string">"11"</span> /&gt;
        &lt;rect x=<span class="hljs-string">"18"</span> y=<span class="hljs-string">"48"</span> rx=<span class="hljs-string">"3"</span> ry=<span class="hljs-string">"3"</span> width=<span class="hljs-string">"100"</span> height=<span class="hljs-string">"11"</span> /&gt;
        &lt;rect x=<span class="hljs-string">"0"</span> y=<span class="hljs-string">"71"</span> rx=<span class="hljs-string">"3"</span> ry=<span class="hljs-string">"3"</span> width=<span class="hljs-string">"37"</span> height=<span class="hljs-string">"11"</span> /&gt;
        &lt;rect x=<span class="hljs-string">"18"</span> y=<span class="hljs-string">"23"</span> rx=<span class="hljs-string">"3"</span> ry=<span class="hljs-string">"3"</span> width=<span class="hljs-string">"140"</span> height=<span class="hljs-string">"11"</span> /&gt;
        &lt;rect x=<span class="hljs-string">"166"</span> y=<span class="hljs-string">"23"</span> rx=<span class="hljs-string">"3"</span> ry=<span class="hljs-string">"3"</span> width=<span class="hljs-string">"173"</span> height=<span class="hljs-string">"11"</span> /&gt;
    &lt;/ContentLoader&gt;
);
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">PopoverExample</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">const</span> [isOpen, setIsOpen] = useState(<span class="hljs-literal">false</span>);
    <span class="hljs-keyword">const</span> [isLoading, setIsLoading] = useState(<span class="hljs-literal">false</span>);
    <span class="hljs-keyword">const</span> [data, setData] = useState({});

    <span class="hljs-keyword">const</span> { refs, floatingStyles, context } = useFloating({
        open: isOpen,
        onOpenChange: setIsOpen,
        placement: <span class="hljs-string">"top"</span>,
    });

    <span class="hljs-keyword">const</span> hover = useHover(context);

    <span class="hljs-keyword">const</span> { getReferenceProps, getFloatingProps } = useInteractions([hover]);

    <span class="hljs-keyword">const</span> handleMouseEnter = <span class="hljs-function">() =&gt;</span> {
        <span class="hljs-keyword">if</span> (<span class="hljs-built_in">Object</span>.keys(data).length === <span class="hljs-number">0</span>) {
            setIsLoading(<span class="hljs-literal">true</span>);
            fetch(<span class="hljs-string">"https://jsonplaceholder.typicode.com/users/1"</span>)
                .then(<span class="hljs-function">(<span class="hljs-params">resp</span>) =&gt;</span> resp.json())
                .then(<span class="hljs-function">(<span class="hljs-params">data</span>) =&gt;</span> {
                    setData(data);
                    setIsLoading(<span class="hljs-literal">false</span>);
                });
        }
    };

    <span class="hljs-keyword">return</span> (
        &lt;div
            id=<span class="hljs-string">"hover-example"</span>
            style={{
                display: <span class="hljs-string">"flex"</span>,
                flexDirection: <span class="hljs-string">"row"</span>,
                alignItems: <span class="hljs-string">"center"</span>,
                textAlign: <span class="hljs-string">"left"</span>,
            }}
            onMouseEnter={handleMouseEnter}
        &gt;
            &lt;span
                style={{
                    padding: <span class="hljs-string">"1rem"</span>,
                }}
            &gt;
                &lt;img
                    ref={refs.setReference}
                    {...getReferenceProps()}
                    style={{
                        borderRadius: <span class="hljs-string">"50%"</span>,
                    }}
                    src=<span class="hljs-string">"https://cdn.jsdelivr.net/gh/alohe/avatars/png/vibrent_5.png"</span>
                /&gt;
            &lt;/span&gt;
            &lt;p&gt;
                Lorem Ipsum is simply dummy text <span class="hljs-keyword">of</span> the printing and typesetting
                industry. Lorem Ipsum has been the industry<span class="hljs-string">'s standard dummy text ever
                since the 1500s, when an unknown printer took a galley of type and
                scrambled it to make a type specimen book. It has survived not only five
                centuries, but also the leap into electronic typesetting, remaining
                essentially unchanged. It was popularised in the 1960s with the release
                of Letraset sheets containing Lorem Ipsum passages, and more recently
                with desktop publishing software like Aldus PageMaker including versions
                of Lorem Ipsum.
            &lt;/p&gt;
            {isOpen &amp;&amp; (
                &lt;div
                    className="floating"
                    ref={refs.setFloating}
                    style={{
                        ...floatingStyles,
                        backgroundColor: "white",
                        color: "black",
                        padding: "1rem",
                        fontSize: "1rem",
                    }}
                    {...getFloatingProps()}
                &gt;
                    {isLoading ? (
                        &lt;MyLoader /&gt;
                    ) : (
                        &lt;UserProfile hasAdditionalDetails {...data} /&gt;
                    )}
                    {/* &lt;UserProfileWithFetching /&gt; */}
                &lt;/div&gt;
            )}
        &lt;/div&gt;
    );
}</span>
</code></pre>
<p>There are couple of things happening here, let me explain them step-by-step:</p>
<ul>
<li><p>We have a parent <code>div</code> named <code>hover-example</code> that contains an image and some text.</p>
</li>
<li><p>Next, we conditionally rendered a <code>div</code> with class name of <code>floating</code>. This is the actual popover component that opens when you hover on the image.</p>
<ul>
<li>We made use of the <a target="_blank" href="https://floating-ui.com/"><code>floating-ui</code> library</a> and its <a target="_blank" href="https://floating-ui.com/docs/useHover">basic hover example</a> to achieve the hover effect for the popover.</li>
</ul>
</li>
<li><p>Inside the popover we conditionally loaded the <code>UserProfile</code> and the skeleton loader. This loader appears when we are fetching the data for the user’s profile. More on this later.</p>
</li>
<li><p>We made use of the <a target="_blank" href="https://github.com/danilowoz/react-content-loader">react-content-loader</a> library in the <code>MyLoader</code> component. This library also has a website that helps you to create loaders, you can check it out <a target="_blank" href="https://skeletonreact.com/">here</a>.</p>
</li>
</ul>
<h3 id="heading-userprofile-component"><code>UserProfile</code> Component</h3>
<p>Now that we have defined our <code>Popover</code> example, it is time for us to get into the details of the <code>UserProfile</code> component.</p>
<p>This component appears inside the popover component. The purpose of this component is to load the <code>name</code> <code>email</code> <code>phone</code> <code>website</code> details which are fetched from <a target="_blank" href="https://jsonplaceholder.typicode.com/users/1">JSON placeholder API</a>.</p>
<p>To demonstrate the prefetching example, we have to make sure that the <code>UserProfile</code> component only acts as a presentational component; that is, no explicit fetching logic is present inside of it.</p>
<p>The key thing to note about this component is that fetching the data happens from the parent component which is the <code>PopoverExample</code> component. In this component, we start fetching the data when the mouse enters this component (the <code>mouseenter</code> event). This is the solution #1 we discussed previously.</p>
<p>This gives you enough time for fetching the data until the user hovers on the image. Here’s the code:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { useEffect, useState } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> ContentLoader <span class="hljs-keyword">from</span> <span class="hljs-string">"react-content-loader"</span>;

<span class="hljs-keyword">const</span> MyLoader = <span class="hljs-function">() =&gt;</span> (
    &lt;ContentLoader
        speed={<span class="hljs-number">2</span>}
        viewBox=<span class="hljs-string">"0 0 476 124"</span>
        backgroundColor=<span class="hljs-string">"#d1d1d1"</span>
        foregroundColor=<span class="hljs-string">"#fafafa"</span>
    &gt;
        &lt;rect x=<span class="hljs-string">"4"</span> y=<span class="hljs-string">"43"</span> rx=<span class="hljs-string">"0"</span> ry=<span class="hljs-string">"0"</span> width=<span class="hljs-string">"98"</span> height=<span class="hljs-string">"30"</span> /&gt;
    &lt;/ContentLoader&gt;
);

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">UserProfile</span>(<span class="hljs-params">props: Record&lt;<span class="hljs-built_in">string</span>, <span class="hljs-built_in">string</span> | <span class="hljs-built_in">boolean</span>&gt;</span>) </span>{
    <span class="hljs-keyword">const</span> { name, email, phone, website, hasAdditionalDetails } = props;
    <span class="hljs-keyword">const</span> [isLoading, setIsLoading] = useState(<span class="hljs-literal">false</span>);
    <span class="hljs-keyword">const</span> [additionalData, setAdditionalData] = useState(<span class="hljs-number">0</span>);

    useEffect(<span class="hljs-function">() =&gt;</span> {
        <span class="hljs-keyword">if</span> (hasAdditionalDetails) {
            setIsLoading(<span class="hljs-literal">true</span>);
            fetch(<span class="hljs-string">"https://jsonplaceholder.typicode.com/albums"</span>)
                .then(<span class="hljs-function">(<span class="hljs-params">resp</span>) =&gt;</span> resp.json())
                .then(<span class="hljs-function">(<span class="hljs-params">data: <span class="hljs-built_in">Array</span>&lt;unknown&gt;</span>) =&gt;</span> {
                    <span class="hljs-keyword">const</span> albumCount = data.reduce(<span class="hljs-function">(<span class="hljs-params">acc, curr</span>) =&gt;</span> {
                        <span class="hljs-keyword">if</span> (curr.userId === <span class="hljs-number">1</span>) acc += <span class="hljs-number">1</span>;

                        <span class="hljs-keyword">return</span> acc;
                    }, <span class="hljs-number">0</span>);
                    setAdditionalData(albumCount);
                })
                .finally(<span class="hljs-function">() =&gt;</span> {
                    setIsLoading(<span class="hljs-literal">false</span>);
                });
        }
    }, [hasAdditionalDetails]);

    <span class="hljs-keyword">return</span> (
        &lt;div id=<span class="hljs-string">"user-profile"</span>&gt;
            &lt;div id=<span class="hljs-string">"user-name"</span>&gt;name: {name}&lt;/div&gt;
            &lt;div id=<span class="hljs-string">"user-email"</span>&gt;email: {email}&lt;/div&gt;
            &lt;div id=<span class="hljs-string">"user-phone"</span>&gt;phone: {phone}&lt;/div&gt;
            &lt;div id=<span class="hljs-string">"user-website"</span>&gt;website: {website}&lt;/div&gt;
            {hasAdditionalDetails &amp;&amp; (
                &lt;&gt;
                    {isLoading ? (
                        &lt;MyLoader /&gt;
                    ) : (
                        &lt;div id=<span class="hljs-string">"user-albums"</span>&gt;Album Count: {additionalData}&lt;/div&gt;
                    )}
                &lt;/&gt;
            )}
        &lt;/div&gt;
    );
}
</code></pre>
<p>This component makes use of the <code>hasAdditionalDetails</code> prop. The purpose of this <code>prop</code> is to load additional data when the component mounts. It illustrates the solution #2 mentioned above.</p>
<h3 id="heading-userprofilewithfetching-component"><code>UserProfileWithFetching</code> Component</h3>
<p>This component is pretty similar to that of the <code>UserProfile</code> component. It just contains the logic for fetching data when the component loads. The purpose of this component is to show what the general solution without the prefetching technique would look like.</p>
<p>So this component will always load the data when the component mounts, which displays the skeleton loader.</p>
<p>Here is the code:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { useEffect, useState } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> { MyLoader } <span class="hljs-keyword">from</span> <span class="hljs-string">"./PopoverExample"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">UserProfileWithFetching</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">const</span> [isLoading, setIsLoading] = useState(<span class="hljs-literal">false</span>);
    <span class="hljs-keyword">const</span> [data, setData] = useState&lt;Record&lt;<span class="hljs-built_in">string</span>, <span class="hljs-built_in">string</span>&gt;&gt;({});

    useEffect(<span class="hljs-function">() =&gt;</span> {
        setIsLoading(<span class="hljs-literal">true</span>);
        fetch(<span class="hljs-string">"https://jsonplaceholder.typicode.com/users/1"</span>)
            .then(<span class="hljs-function">(<span class="hljs-params">resp</span>) =&gt;</span> resp.json())
            .then(<span class="hljs-function">(<span class="hljs-params">data</span>) =&gt;</span> {
                setData(data);
                setIsLoading(<span class="hljs-literal">false</span>);
            });
    }, []);

    <span class="hljs-keyword">if</span> (isLoading) <span class="hljs-keyword">return</span> &lt;MyLoader /&gt;;

    <span class="hljs-keyword">return</span> (
        &lt;div id=<span class="hljs-string">"user-profile"</span>&gt;
            &lt;div id=<span class="hljs-string">"user-name"</span>&gt;name: {data.name}&lt;/div&gt;
            &lt;div id=<span class="hljs-string">"user-email"</span>&gt;email: {data.email}&lt;/div&gt;
            &lt;div id=<span class="hljs-string">"user-phone"</span>&gt;phone: {data.phone}&lt;/div&gt;
            &lt;div id=<span class="hljs-string">"user-website"</span>&gt;website: {data.website}&lt;/div&gt;
        &lt;/div&gt;
    );
}
</code></pre>
<p>The entire code for this app can be found <a target="_blank" href="https://github.com/keyurparalkar/prefetch-examples">here</a>.</p>
<h2 id="heading-too-much-prefetching-can-also-cause-slowness">Too much prefetching can also cause slowness</h2>
<p>A word of advice, too much prefetching is not good because:</p>
<ul>
<li><p>It might slow your app down.</p>
</li>
<li><p>It can degrade user experience if prefetching is not applied strategically.</p>
</li>
</ul>
<p>Prefetching needs to be applied when you know the behavior of the user. That is, you are able to predict the user movement by metrics and be able to tell if they visit a page often. In that case, prefetching is a good idea.</p>
<p>So remember to always apply prefetching strategically.</p>
<h2 id="heading-summary">Summary</h2>
<p>That’s all folks! Hope you like my blog post. In this blogpost, you learned that implementing prefetching can significantly enhance your web application’s speed and responsiveness, improving user satisfaction.</p>
<p>For further reading, please refer to the below articles:</p>
<ul>
<li><p><a target="_blank" href="https://www.patterns.dev/vanilla/prefetch/">Prefetching pages</a></p>
</li>
<li><p><a target="_blank" href="https://medium.com/reloading/preload-prefetch-and-priorities-in-chrome-776165961bbf">Preload, Prefetch And Priorities in Chrome</a></p>
</li>
<li><p><a target="_blank" href="https://addyosmani.com/blog/what-not-to-prefetch-prerender/">What not to prefetch</a></p>
</li>
</ul>
<p>For more content, you can follow me on <a target="_blank" href="https://twitter.com/keurplkar">Twitter</a>, <a target="_blank" href="http://github.com/keyurparalkar">GitHub</a>, and <a target="_blank" href="https://www.linkedin.com/in/keyur-paralkar-494415107/">LinkedIn</a>.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ What is Speedy Web Compiler? SWC Explained With Examples ]]>
                </title>
                <description>
                    <![CDATA[ In the evolving landscape of JavaScript development, the need for efficient and powerful tooling has become increasingly important. Developers rely on tools like compilers and bundlers to transform their code, optimize performance, and ensure compati... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/what-is-speedy-web-compiler/</link>
                <guid isPermaLink="false">66d90463e90270a49f64f4c6</guid>
                
                    <category>
                        <![CDATA[ Web Development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Rust ]]>
                    </category>
                
                    <category>
                        <![CDATA[ web performance ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Preston Mayieka ]]>
                </dc:creator>
                <pubDate>Thu, 05 Sep 2024 01:07:47 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1725290113209/260f00cb-5bfe-4260-8e45-0c61a1897cae.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>In the evolving landscape of JavaScript development, the need for efficient and powerful tooling has become increasingly important.</p>
<p>Developers rely on tools like <a target="_blank" href="https://en.wikipedia.org/wiki/Compiler"><strong>compilers</strong></a> and <a target="_blank" href="https://www.codejourney.net/what-is-a-javascript-bundler/"><strong>bundlers</strong></a> to transform their code, optimize performance, and ensure compatibility across different environments.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1725287352931/41e13dc3-100e-4f75-87df-98342df4beb2.png" alt="41e13dc3-100e-4f75-87df-98342df4beb2" class="image--center mx-auto" width="901" height="506" loading="lazy"></p>
<p>These tools are essential for modern JavaScript applications, enabling developers to write clean, maintainable code while leveraging the latest language features.</p>
<p>This article will help you understand what Speedy Web Compiler (SWC) is and how it helps optimize the performance of your web apps.</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ul>
<li><p><a class="post-section-overview" href="#heading-what-is-speedy-web-compiler">Introduction to Speedy Web Compiler</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-background-of-swc">Background of SWC</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-speedy-web-compiler-works">How Speedy Web Compiler Works</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-benefits-of-using-speedy-web-compiler">Benefits of Using Speedy Web Compiler</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-set-up-speedy-web-compiler">How to Set Up Speedy Web Compiler in Your Project</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-swc-integration-in-popular-frameworks">SWC Integration in Popular Frameworks</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></p>
</li>
</ul>
<h2 id="heading-what-is-speedy-web-compiler">What is Speedy Web Compiler?</h2>
<p>First, let me break it down.</p>
<p>SWC stands for Speedy Web Compiler, and when broken down:</p>
<p><strong>Speedy</strong> - This means it's fast! SWC processes and transforms JavaScript code, making it efficient to use in big projects.</p>
<p><strong>Web</strong> - It’s all about web development. It focuses on improving how JavaScript (the language of the web) handles it.</p>
<p><strong>Compiler</strong> - It takes code written in one form and transforms it into another form that can be better understood or used by computers.</p>
<h2 id="heading-background-of-swc">Background of SWC</h2>
<p><a target="_blank" href="https://github.com/kdy1">kdy1</a>, a South Korean developer and maintainer of <a target="_blank" href="https://nextjs.org/">Next.js</a>, created SWC as a faster tool for handling JavaScript code.</p>
<p>The motivation was the need for speed and efficiency, as web projects grow larger and more complex.</p>
<p>With numerous websites and apps depending on JavaScript, SWC helps developers save time and work more efficiently.</p>
<h2 id="heading-how-speedy-web-compiler-works">How Speedy Web Compiler Works</h2>
<p>SWC uses <a target="_blank" href="https://www.rust-lang.org/">Rust</a>, a programming language known for its speed and safety.</p>
<p>SWC works by taking your JavaScript or TypeScript code and transforming it into a version that can run efficiently in various environments.</p>
<p>Understanding how SWC achieves this involves examining its core steps: parsing, transforming, and generating code.</p>
<h3 id="heading-how-does-swc-parse-code">How Does SWC Parse Code?</h3>
<p>The first step in the compilation process is parsing.</p>
<p>Begins by <strong>reading</strong> and analyzing the code to understand its structure.</p>
<p>This is akin to taking a complex sentence and breaking it down into its grammatical components—subject, verb, object, etc.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1725287153049/b7ec431c-24db-4c7a-9fb0-ef3ce0d92921.png" alt="Illustration of Code parsing into forming abstract syntax tree" class="image--center mx-auto" width="891" height="499" loading="lazy"></p>
<p>In technical terms, SWC converts your code into an <a target="_blank" href="https://en.wikipedia.org/wiki/Abstract_syntax_tree"><strong>Abstract Syntax Tree (AST)</strong>.</a></p>
<p>The AST is a tree-like representation of the source code, where each node in the tree corresponds to a construct occurring in the code, such as expressions, statements, and functions.</p>
<p>This tree structure allows SWC to process and understand the code’s logic in a way that is both efficient and scalable.</p>
<h3 id="heading-how-does-swc-transform-code">How Does SWC Transform Code?</h3>
<p>After creating the AST, SWC moves on to the transformation phase.</p>
<p>This is where the magic happens—SWC applies various optimizations and changes to the code based on the target environment.</p>
<p>For instance, if you're targeting older browsers that don't support modern JavaScript features, SWC will transform your ES6+ code into a backward-compatible version.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1725287185279/371d2ac2-e919-4f25-8caf-01d4157fd290.png" alt="Yellow gear with two circular arrows surrounding it, accompanied by the text &quot;Transformation of AST&quot; on a dark background." class="image--center mx-auto" width="888" height="498" loading="lazy"></p>
<p>During this phase, SWC also handles TypeScript transformations. It strips away TypeScript-specific syntax, such as types and interfaces, converting the code into pure JavaScript that gets executed by any JavaScript engine.</p>
<p>SWC can apply custom transformations based on plugins or specific configurations, making it highly versatile.</p>
<h3 id="heading-how-does-swc-generate-optimized-code">How Does SWC Generate Optimized Code?</h3>
<p>After the transformations are complete, SWC proceeds to the final step: code generation.</p>
<p>In this step, SWC takes the transformed AST and converts it back into executable code.</p>
<p>In contrast, this process is not just a reversal of the parsing process.</p>
<p>SWC takes special care to generate code that is both functionally correct and optimized for performance.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1725287212996/af724e34-6473-4104-8244-e35c1be6a3c0.png" alt="Yellow line drawing of a coding window with a wrench and gear icon, above text that reads &quot;Generation of Optimized Code&quot; on a black background." class="image--center mx-auto" width="886" height="496" loading="lazy"></p>
<p>For instance, SWC might remove dead code (code that will never be executed) or inline certain functions to reduce overhead.</p>
<p>The goal is to produce code that is as clean and efficient as possible, ensuring that it runs quickly and reliably in production environments.</p>
<h2 id="heading-benefits-of-using-speedy-web-compiler">Benefits of Using Speedy Web Compiler</h2>
<h3 id="heading-performance">Performance</h3>
<p>One of the major benefits of using SWC is its outstanding speed. SWC achieves this exceptional speed by using Rust.</p>
<p>Developers can expect a significant performance improvement when compiling their code for large projects or codebases.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1725287254910/9c4827d9-81db-488d-bdb8-6b0806ddfd67.png" alt="Illustration of a stopwatch inside a web browser window, with motion lines indicating speed. The text below reads &quot;Faster Loading Times.&quot;" class="image--center mx-auto" width="893" height="498" loading="lazy"></p>
<p>This speed greatly reduces build times, enhancing the efficiency and responsiveness of the development process. It is so fast, you might think it’s late for a meeting!</p>
<h3 id="heading-optimized-output">Optimized Output</h3>
<p>SWC compiles your code and guarantees that the output is highly optimized for performance in production environment by removing dead code, in-lining functions, and reducing the size of the output.</p>
<p>This makes using SWC cost-effective, saving you from extra expenses during production.</p>
<p>The result is a leaner, faster, and more efficient code that can enhance loading times and performance in web applications.</p>
<h3 id="heading-compatibility">Compatibility</h3>
<p>SWC is fully compatible with modern JavaScript libraries and frameworks.</p>
<p>You do not have to worry about using ES6+ or TypeScript. This makes SWC a versatile choice for your projects.</p>
<h2 id="heading-how-to-set-up-speedy-web-compiler">How to Set Up Speedy Web Compiler</h2>
<h3 id="heading-installation">Installation</h3>
<p>To install SWC in your JavaScript or TypeScript project, follow these steps:</p>
<ol>
<li><strong>Initialize your project:</strong> If you haven't already, start by initializing a new project. In your terminal, run:</li>
</ol>
<pre><code class="lang-bash">npm init -y
</code></pre>
<ol start="2">
<li><strong>Install SWC with npm:</strong> Run the following command to download the pre-built binaries:</li>
</ol>
<pre><code class="lang-bash">npm install -D @swc/cli @swc/core
</code></pre>
<ol start="3">
<li><strong>Create a JavaScript file:</strong> Create a <code>src/index.js</code> file with some code:</li>
</ol>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> greet = <span class="hljs-function">(<span class="hljs-params">name</span>) =&gt;</span> {
  <span class="hljs-keyword">return</span> <span class="hljs-string">`Hello, <span class="hljs-subst">${name}</span>!`</span>;
};

<span class="hljs-built_in">console</span>.log(greet(<span class="hljs-string">"World"</span>));
</code></pre>
<ol start="4">
<li><strong>Compile with SWC:</strong> Run SWC from the command line to compile your JavaScript file:</li>
</ol>
<pre><code class="lang-bash">npx swc src/index.js -o dist/index.js
</code></pre>
<ol start="5">
<li><strong>Resulting Code:</strong> The resulting JavaScript code in <code>dist/index.js</code> will look like this:</li>
</ol>
<pre><code class="lang-javascript"><span class="hljs-meta">"use strict"</span>;
<span class="hljs-keyword">var</span> greet = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">name</span>) </span>{
    <span class="hljs-keyword">return</span> <span class="hljs-string">"Hello, "</span> + name + <span class="hljs-string">"!"</span>;
};
<span class="hljs-built_in">console</span>.log(greet(<span class="hljs-string">"World"</span>));
</code></pre>
<p>This is the transpiled ES5 code produced by SWC, suitable for environments that require backward compatibility with older JavaScript versions.</p>
<h2 id="heading-swc-integration-in-popular-frameworks">SWC Integration in Popular Frameworks</h2>
<p>If you are using Next.js, Deno, Vite, Remix, Parcel, or Turbopack, SWC is already integrated.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1725287305286/e0a1e681-4531-402c-ae41-1f8c5f1318c8.png" alt="Logos of various web development frameworks and tools on a black background, which include: Deno, Vite, Next.js, Remix, Turbopack, and an open cardboard box." class="image--center mx-auto" width="896" height="498" loading="lazy"></p>
<blockquote>
<p>Notable improvements were made on Next.js, a popular React framework, since version 12 (Source: <a target="_blank" href="https://nextjs.org/blog/next-12">Next.js 12: The SDK for the Web</a>)</p>
</blockquote>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In the constantly changing realm of JavaScript development, having the correct tools can make a significant difference.</p>
<p>SWC, the <a target="_blank" href="http://swc.rs">Speedy Web Compiler</a>, distinguishes itself as a strong solution for converting and optimizing JavaScript and TypeScript code.</p>
<p>Its impressive speed, owing to its Rust-based implementation, along with its efficient management of code transformations and optimizations, positions it as a powerful tool for modern web development.</p>
<p>If you would like to stay in touch:</p>
<p><a target="_blank" href="https://www.linkedin.com/in/preston-mayieka/">Connect with me on LinkedIn</a></p>
<p><a target="_blank" href="https://mobile.x.com/Preston_Mayieka">Follow me on X</a></p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Optimize Next.js App Performance With Lazy Loading ]]>
                </title>
                <description>
                    <![CDATA[ People don't like using slow applications. And the initial load time matters a lot for web applications and websites.  An application that takes more than 3 seconds to load is considered slow and may cause users to leave the application or website. N... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/next-js-performance-optimization/</link>
                <guid isPermaLink="false">66be00118c9c9099893ce790</guid>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Next.js ]]>
                    </category>
                
                    <category>
                        <![CDATA[ web performance ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Tapas Adhikary ]]>
                </dc:creator>
                <pubDate>Fri, 19 Jul 2024 22:31:12 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2024/07/lazyloading-next.js.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>People don't like using slow applications. And the initial load time matters a lot for web applications and websites. </p>
<p>An application that takes more than 3 seconds to load is considered slow and may cause users to leave the application or website.</p>
<p><code>Next.js</code> is a React-based framework you can use to build scalable, performant, and faster web applications and websites. With the inclusion of <a target="_blank" href="https://www.freecodecamp.org/news/how-to-use-react-server-components/">React Server Components</a> in the Next.js app router release, developers have a new mental model for "thinking in a server components" way. It solves the problem with SEO, helps create <code>zero bundle size</code> React components, and the end result is faster loading of UI components.</p>
<p>But your application may not be always about the server components. You may need to use client components as well. Also, you may want to load them either as part of the application's initial load or on demand (say at the click of a button).</p>
<p>Loading a client component on the browser includes downloading the component code into the browser, downloading all the libraries and other components you had imported into that client component, and a few additional things that React takes care of for you to make sure your components are working. </p>
<p>Based on the user's internet connection and other network factors, the entire loading of the client component may take a while, which may keep your users from using the application more quickly.</p>
<p>This is where <code>Lazy Loading</code> techniques can come in handy. They can help save you from a monolithic loading of your client components on the browser. </p>
<p>In this article, we will discuss a couple of lazy loading techniques in Next.js for client component loading optimization. We will also talk about a few edge cases you should know to handle.</p>
<p>If you like to learn from video content as well, this article is also available as a video tutorial here: 🙂</p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/gq9bBZru78Y" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
<p>Before we get started, a couple of things for you:</p>
<ul>
<li>We will write a bunch of code to build an app to demonstrate the lazy loading techniques. You can find all the source code from this GitHub repository: <a target="_blank" href="https://github.com/tapascript/nextjs-lazy-load">https://github.com/tapascript/nextjs-lazy-load</a>. But I strongly suggest that you write the code yourself as we proceed and use the repository only as a reference.</li>
<li>You can also access the app deployed publicly <a target="_blank" href="https://nextjs-lazy-load.netlify.app/">on Netlify here</a>.</li>
</ul>
<p>Let's start 🚀. Oh yes, if you are Tom &amp; Jerry cartoon lover, you are going to enjoy this even more!</p>
<h2 id="heading-table-of-contents"><strong>Table of Contents</strong></h2>
<ul>
<li><a class="post-section-overview" href="#heading-what-is-lazy-loading">What is Lazy Loading</a>?</li>
<li><a class="post-section-overview" href="#heading-lazy-loading-techniques-in-nextjs">Lazy Loading Techniques in Next.js</a></li>
<li><a class="post-section-overview" href="#heading-lazy-loading-with-dynamic-import-and-nextdynamic">Lazy Loading with dynamic import and next/dynamic</a></li>
<li><a class="post-section-overview" href="#heading-lazy-loading-with-reactlazy-and-suspense">Lazy Loading with React.lazy() and Suspense</a></li>
<li><a class="post-section-overview" href="#heading-how-to-lazy-load-the-named-exported-components">How to Lazy Load the Named Exported Components</a></li>
<li><a class="post-section-overview" href="#heading-lazy-loading-your-server-components-1">Lazy Loading Your Server Components</a></li>
<li><a class="post-section-overview" href="#heading-lazy-loading-your-server-components-1">Should We Lazy Load All Client Components in Next.js?</a></li>
<li><a class="post-section-overview" href="#heading-whats-next">What's Next?</a></li>
</ul>
<h2 id="heading-what-is-lazy-loading">What is Lazy Loading?</h2>
<p>In modern day web application development, we don't code all the logic in one JavaScript/TypeScript file, or all the styles into one mammoth CSS file. Rather, we split them at the source code level and create logical modules, business logic, presentational components, and style related files. This helps us organize our code better.</p>
<p>Then we use something called a bundler which kicks in at the build phase of the application development process. It creates bundles for our scripts and styles. Some of the famous bundlers are Webpack, Rollup, and Parcel, among others.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/07/image-43.png" alt="Image" width="600" height="400" loading="lazy">
<em>Bundler creating bundles from the source code</em></p>
<p>Now, as we have the bundles, if we try to load them on the browser all together, we will encounter some slowness. This is because the complete bundle needs to be loaded into the browser for the user interface to be functional. </p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/07/image-44.png" alt="Image" width="600" height="400" loading="lazy">
<em>Loading a huge bundle results in a poor loading experience</em></p>
<p>So, instead of waiting for the huge bundle to get loaded into the browser, modern web development libraries and tooling systems allow us to load the bundle in chunks. </p>
<p>We may want to load some of the chunks immediately, as users may need them sooner as the application loads. At the same time, we may want to wait to load certain parts of a web page until they're needed.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/07/image-45.png" alt="Image" width="600" height="400" loading="lazy">
<em>Breaking into chunks and loading what is needed</em></p>
<p>This mechanism of waiting to load part of the pages or application, and loading them only when they are absolutely necessary, is called <code>Lazy Loading</code>. The concept of lazy loading is not React or Next.js-specific. It is a performance optimization technique that you can implement with various libraries and frameworks.</p>
<h2 id="heading-lazy-loading-techniques-in-nextjs">Lazy Loading Techniques in Next.js</h2>
<p>Lazy loading techniques in Next.js is used to reduce the amount of JavaScript needed by a route. This helps the initial load performance of the application be faster. We can defer the load of the client components and imported libraries until they are needed.</p>
<p>There are two ways we can implement lazy loading techniques in Next.js:</p>
<ul>
<li>Using dynamic imports with the help of the <code>next/dynamic</code> package.</li>
<li>Using a combination of <code>React.lazy()</code> and <code>Suspense</code>.</li>
</ul>
<p>Let's understand each of these techniques with code examples.</p>
<h2 id="heading-lazy-loading-with-dynamic-import-and-nextdynamic">Lazy Loading With <code>dynamic import</code> and <code>next/dynamic</code></h2>
<p><code>next/dynamic</code> is a combination of React.lazy() and Suspense from ReactJS. Using a dynamic import with the next/dynamic package is a preferred approach to achieve lazy loading in Next.js.</p>
<p>To demonstrate it, let's first create a Next.js app using the following command:</p>
<pre><code class="lang-bash">npx create-next-app@latest
</code></pre>
<p>You can start the app locally using the following command:</p>
<pre><code class="lang-bash"><span class="hljs-comment">## Using npm</span>
npm run dev

<span class="hljs-comment">## Using yarn</span>
yarn dev

<span class="hljs-comment">## Or use pnpm, bun, whatever you wish!</span>
</code></pre>
<p>Now create a folder called <code>components</code> under the <code>app/</code> directory. We will create all our components under the component folder. Now, create a folder called <code>tom</code> under the <code>app/components/</code>. Finally, create a React component called <code>tom.jsx</code> under the <code>app/components/tom/</code> directory with the following code:</p>
<pre><code class="lang-js"><span class="hljs-comment">// tom.jsx</span>

<span class="hljs-keyword">const</span> LazyTom = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex flex-col"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h1</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-3xl my-2"</span>&gt;</span>The Lazy Tom<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-xl my-1"</span>&gt;</span>
        Tom, named <span class="hljs-symbol">&amp;quot;</span>Jasper<span class="hljs-symbol">&amp;quot;</span> in his debut appearance, is a gray and white
        domestic shorthair cat 🐈. <span class="hljs-symbol">&amp;quot;</span>Tom<span class="hljs-symbol">&amp;quot;</span> is a generic name for a male cat. He is
        usually but not always, portrayed as living a comfortable, or even
        pampered life. Tom is no match for Jerry<span class="hljs-symbol">&amp;apos;</span>s wits.
      <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-xl my-1"</span>&gt;</span>
        Although cats typically chase mice to eat them, it is quite rare for Tom
        to actually try to eat Jerry. He tries to hurt or compete with him just
        to taunt Jerry, even as revenge, or to obtain a reward from a human,
        including his owner(s)/master(s), for catching Jerry, or for generally
        doing his job well as a house cat. By the final <span class="hljs-symbol">&amp;quot;</span>fade-out<span class="hljs-symbol">&amp;quot;</span> of each
        cartoon, Jerry usually gets the best of Tom.
      <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> LazyTom;
</code></pre>
<p>To explain the above code:</p>
<ul>
<li>We have created a ReactJS component called <code>LazyTom</code>.</li>
<li>It is a simple presentational component which has a heading and a couple of paragraphs talking about the cat, Tom, from the famous <code>Tom &amp; Jerry</code> cartoon.</li>
<li>At the end, we have <code>default</code> exported the component to import it elsewhere.</li>
</ul>
<p>Now, create another file called <code>tom-story.jsx</code> under the <code>app/components/tom/</code> directory with the following code:</p>
<pre><code class="lang-js"><span class="hljs-comment">// tom-story.jsx</span>

<span class="hljs-string">"use client"</span>;

<span class="hljs-keyword">import</span> { useState } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> dynamic <span class="hljs-keyword">from</span> <span class="hljs-string">"next/dynamic"</span>;

<span class="hljs-keyword">const</span> LazyTom = dynamic(<span class="hljs-function">() =&gt;</span> <span class="hljs-keyword">import</span>(<span class="hljs-string">"./tom"</span>), {
    <span class="hljs-attr">loading</span>: <span class="hljs-function">() =&gt;</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>Loading Tom<span class="hljs-symbol">&amp;apos;</span>s Story...<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span></span>,
});

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">TomStory</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">const</span> [shown, setShown] = useState(<span class="hljs-literal">false</span>);

    <span class="hljs-keyword">return</span> (
        <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex flex-col m-8 w-[300px]"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">h2</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-xl my-1"</span>&gt;</span>Demonstrating <span class="hljs-tag">&lt;<span class="hljs-name">strong</span>&gt;</span>dynamic<span class="hljs-tag">&lt;/<span class="hljs-name">strong</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
                <span class="hljs-attr">className</span>=<span class="hljs-string">"bg-blue-600 text-white rounded p-1"</span>
                <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> setShown(!shown)}
            &gt;
                Load 🐈 Tom<span class="hljs-symbol">&amp;apos;</span>s Story
            <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>

            {shown &amp;&amp; <span class="hljs-tag">&lt;<span class="hljs-name">LazyTom</span> /&gt;</span>}
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
    );
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> TomStory;
</code></pre>
<p>The main magic of lazy loading with <code>dynamic</code> is happening in the above code:</p>
<ul>
<li>We have created a client component called <code>TomStory</code> using the <code>"use client"</code> directive.</li>
<li>First, we have imported the <code>useState</code> hook for managing a toggle state, and the <code>dynamic</code> function from the <code>next/dynamic</code> for the lazy loading of the component we created before.</li>
<li>The <code>dynamic</code> function takes a function as an argument that returns the imported component. You can also configure a custom loading message by providing an optional configuration object as argument to the dynamic function. </li>
<li>The <code>dynamic()</code> function returns the lazily loaded component instance – that is, <code>LazyTom</code> (could be any name). But this component is not loaded yet.</li>
<li>In the JSX, we have a toggle button that shows and hides the <code>LazyTom</code> component. Note that the component will be lazy loaded into the user browser at the first instance of a button click. After that, if you hide and show it again, the <code>LazyTom</code> component will not be reloaded until we hard refresh the browser or clear the browser cache.</li>
<li>Finally, we have default exported the <code>TomStory</code> component.</li>
</ul>
<p>Now we need to test it out. To do that, open the <code>page.js</code> file in the <code>app/</code> directory and replace the content with the following code:</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> TomStory <span class="hljs-keyword">from</span> <span class="hljs-string">"./components/tom/tom-story"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Home</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex flex-wrap justify-center "</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">TomStory</span> /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}
</code></pre>
<p>This is a simple ReactJS component that imports the <code>TomStory</code> component and uses it in its JSX. Now open your browser window. Open the browser's DevTools and open the <code>Network</code> tab. Make sure that the <code>All</code> filter is selected.</p>
<p>Now access the app on your browser using <code>http://localhost:3000</code>. You should see the button to load Tom's story. Also a bunch of resources will be listed on the <code>Network</code> tab. These are resources required in the initial load of the application and have been downloaded on your browser.</p>
<p>The <code>LazyTom</code> component from the <code>tom.jsx</code> has not been downloaded yet. This is because we haven't yet clicked on the <code>Load Tom's Story</code> button.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/07/Screenshot-2024-07-17-at-9.21.10-AM.png" alt="Image" width="600" height="400" loading="lazy">
<em>The button to lazy load Tom's story</em></p>
<p>Now, click on the button. You should see a loading message for a moment and then the component will be loaded with Tom's story. You can now see the <code>tom.jsx</code> component listed in the <code>Network</code> tab and also the component rendered on the page with the Tom's story.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/07/Screenshot-2024-07-17-at-9.27.55-AM.png" alt="Image" width="600" height="400" loading="lazy">
<em>Now Tom's story is lazily loaded</em></p>
<p>Now that you have experienced how the <code>dynamic</code> function from <code>next/dynamic</code> helps us load a component lazily, let's get started with the other technique using <code>React.lazy()</code> and <code>Suspense</code>.</p>
<h2 id="heading-lazy-loading-with-reactlazy-and-suspense">Lazy Loading with <code>React.lazy()</code> and <code>Suspense</code></h2>
<p>To demonstrate this technique, let's start with Jerry's story, my favourite character from the Tom &amp; Jerry cartoon. </p>
<p>First, we'll create a folder called <code>jerry</code> under the <code>app/components/</code> directory. Now, create a file called <code>jerry.jsx</code> under the <code>app/components/jerry/</code> with the following code:</p>
<pre><code class="lang-js"><span class="hljs-comment">// jerry.jsx</span>

<span class="hljs-keyword">const</span> LazyJerry = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex flex-col justify-center"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h1</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-3xl my-2"</span>&gt;</span>The Lazy Jerry<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-xl my-1"</span>&gt;</span>
        Jerry 🐀, whose name is not explicitly mentioned in his debut appearance,
        is a small, brown house mouse who always lives in close proximity to
        Tom. Despite being very energetic, determined and much larger, Tom is no
        match for Jerry<span class="hljs-symbol">&amp;apos;</span>s wits. Jerry possesses surprising strength for his
        size, approximately the equivalent of Tom<span class="hljs-symbol">&amp;apos;</span>s, lifting items such as
        anvils with relative ease and withstanding considerable impacts.
      <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-xl my-1"</span>&gt;</span>
        Although cats typically chase mice to eat them, it is quite rare for Tom
        to actually try to eat Jerry. He tries to hurt or compete with him just
        to taunt Jerry, even as revenge, or to obtain a reward from a human,
        including his owner(s)/master(s), for catching Jerry, or for generally
        doing his job well as a house cat. By the final <span class="hljs-symbol">&amp;quot;</span>fade-out<span class="hljs-symbol">&amp;quot;</span> of each
        cartoon, Jerry usually gets the best of Tom.
      <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> LazyJerry;
</code></pre>
<p>The content of <code>jerry.jsx</code> is structurally similar to <code>tom.jsx</code>. Here we have posted Jerry's story, instead of Tom's, and default exported the component.</p>
<p>Like the last time, let's create a <code>jerry-story.jsx</code> file to showcase the lazy loading of Jerry's story. Create the file under the <code>app/components/jerry/</code> directory with the following code:</p>
<pre><code class="lang-js"><span class="hljs-comment">// jerry-story.jsx</span>

<span class="hljs-string">"use client"</span>;

<span class="hljs-keyword">import</span> React, { useState, Suspense } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;

<span class="hljs-keyword">const</span> LazyJerry = React.lazy(<span class="hljs-function">() =&gt;</span> <span class="hljs-keyword">import</span>(<span class="hljs-string">'./jerry'</span>));

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">JerryStory</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">const</span> [shown, setShown] = useState(<span class="hljs-literal">false</span>);

    <span class="hljs-keyword">return</span> (
        <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex flex-col m-8 w-[300px]"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">h2</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-xl my-1"</span>&gt;</span> Demonstrating <span class="hljs-tag">&lt;<span class="hljs-name">strong</span>&gt;</span>React.lazy()<span class="hljs-tag">&lt;/<span class="hljs-name">strong</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
                <span class="hljs-attr">className</span>=<span class="hljs-string">"bg-pink-600 text-white rounded p-1"</span>
                <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> setShown(!shown)}
            &gt;
                Load 🐀 Jerry<span class="hljs-symbol">&amp;apos;</span>s Story
            <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>

            {shown &amp;&amp; <span class="hljs-tag">&lt;<span class="hljs-name">Suspense</span> <span class="hljs-attr">fallback</span>=<span class="hljs-string">{</span>&lt;<span class="hljs-attr">h1</span>&gt;</span>Loading Jerry<span class="hljs-symbol">&amp;apos;</span>s Story<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>}&gt;
                <span class="hljs-tag">&lt;<span class="hljs-name">LazyJerry</span> /&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">Suspense</span>&gt;</span>}
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
    );
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> JerryStory;
</code></pre>
<p>Here also we have a client component, and we will be using the <code>lazy()</code> method and <code>Suspense</code> from React, so we have imported them. Like the <code>dynamic()</code> function in the last technique, the <code>lazy()</code> function also takes a function as an argument that retrurns the lazily imported component. We have also provided the relative path to the component that we are trying to load.</p>
<p>Note that with <code>dynamic()</code> we had an opportunity to customize the loading message as part of the function itself. With <code>lazy()</code>, we will be doing that as part of the <code>Suspense</code> fallback. </p>
<p>Suspense uses a fallback when you wait for the data to load. If you would like to understand the Suspense and Error Boundary from ReactJS in-depth, you can <a target="_blank" href="https://www.youtube.com/watch?v=OpHbSHp8PcI">check out this video tutorial</a>. </p>
<p>Here, as our <code>LazyJerry</code> component is loading lazily, we have provided a fallback to show a loading message until the component code is download into the browser successfully and rendered.</p>
<pre><code class="lang-js">{shown &amp;&amp; 
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Suspense</span> <span class="hljs-attr">fallback</span>=<span class="hljs-string">{</span>&lt;<span class="hljs-attr">h1</span>&gt;</span>Loading Jerry<span class="hljs-symbol">&amp;apos;</span>s Story<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>}&gt;
                <span class="hljs-tag">&lt;<span class="hljs-name">LazyJerry</span> /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">Suspense</span>&gt;</span></span>
}
</code></pre>
<p>Also, as you can see, we are loading the component on the first button click. Here also, the component will not be reloaded every time we click on the button unless we refresh the browser or clear the browser cache.</p>
<p>Let's now test it by importing it into the <code>page.js</code> file and adding the component in its JSX.</p>
<pre><code class="lang-js"><span class="hljs-comment">// page.js</span>

<span class="hljs-keyword">import</span> TomStory <span class="hljs-keyword">from</span> <span class="hljs-string">"./components/tom/tom-story"</span>;
<span class="hljs-keyword">import</span> JerryStory <span class="hljs-keyword">from</span> <span class="hljs-string">"./components/jerry/jerry-story"</span>; 

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Home</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex flex-wrap justify-center "</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">TomStory</span> /&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">JerryStory</span> /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}
</code></pre>
<p>Now, you'll see another component appear on the user interface with a button to load Jerry's story. At this stage, you will not see the jerry.jsx component loaded into the browser.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/07/Screenshot-2024-07-17-at-9.33.36-AM.png" alt="Image" width="600" height="400" loading="lazy">
<em>The button to lazy load Jerry's story</em></p>
<p>Now, click on the button. You will see that the component is loaded, and you can see it on the Network tab list. You should be able to read Jerry's story rendered as part of the lazily loaded component.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/07/Screenshot-2024-07-17-at-9.37.30-AM.png" alt="Image" width="600" height="400" loading="lazy">
<em>Jerry's story is lazily loaded</em></p>
<h2 id="heading-how-to-lazy-load-the-named-exported-components">How to Lazy Load the Named Exported Components</h2>
<p>So far, with both the techniques we have imported a component that was exported with the <code>default export</code> and then lazy loaded it. In JavaScript (and so in React), you can export and import modules in two different ways:</p>
<ul>
<li>With the <code>default</code> keyword. In this case, the exported module can be imported with any name. You would use this if you wanted to export only one functionality from a module.</li>
<li>Without the <code>default</code> keyword, this is called a <code>named export</code>. In this case, you have to maintain the same module name for the export and import. You also need to enclose the module name in the curly brackets ({...}) while importing. You would use this if you wanted to export multiple functionalities from a module.</li>
</ul>
<p>If you want to get into JavaScript modules and how they work in greater detail, I would suggest going through <a target="_blank" href="https://www.youtube.com/watch?v=KeBxopnhizw">this crash course</a> published on freeCodeCamp's YouTube channel.</p>
<p>To demonstrate the lazy loading of a <code>named export</code> component, let's create another simple presentational React component. This time we will use the angry but cute dog named <code>Spike</code> from the Tom &amp; Jerry cartoon.</p>
<p>Create a folder called <code>spike</code> under the <code>app/components/</code> directory. Now, create a file called <code>spike.jsx</code> under the <code>app/components/spike/</code> directory with the following code:</p>
<pre><code class="lang-js"><span class="hljs-comment">// spike.jsx</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> LazySpike = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex flex-col"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h1</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-3xl my-2"</span>&gt;</span>The Lazy Spike<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-xl my-1"</span>&gt;</span>
        In his attempts to catch Jerry, Tom often has to deal with Spike 🦮, known
        as <span class="hljs-symbol">&amp;quot;</span>Killer<span class="hljs-symbol">&amp;quot;</span> and <span class="hljs-symbol">&amp;quot;</span>Butch<span class="hljs-symbol">&amp;quot;</span> in some shorts, an angry, vicious but easily
        duped bulldog who tries to attack Tom for bothering him or his son Tyke
        while trying to get Jerry. Originally, Spike was unnamed and mute, aside
        from howls and biting noises as well as attacking indiscriminately, not
        caring whether it was Tom or Jerry though usually attacking Tom.
      <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-xl my-1"</span>&gt;</span>
      In
        later cartoons, Spike spoke often, using a voice and expressions,
        performed by Billy Bletcher and later Daws Butler, modeled after
        comedian Jimmy Durante. Spike<span class="hljs-symbol">&amp;apos;</span>s coat has altered throughout the years
        between gray and creamy tan. The addition of Spike<span class="hljs-symbol">&amp;apos;</span>s son Tyke in the
        late 1940s led to both a slight softening of Spike<span class="hljs-symbol">&amp;apos;</span>s character and a
        short-lived spin-off theatrical series called Spike and Tyke.
      <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
};
</code></pre>
<p>Again, this component is structurally exactly same as the <code>tom.jsx</code> and <code>jerry.jsx</code> components we have seen before, but with two major differences:</p>
<ol>
<li>Here, we have exported the component without the default keyword, hence it is a <code>named export</code>.</li>
<li>We are talking about the dog, Spike.</li>
</ol>
<p>Now, we need to handle the lazy loading of a named exported component and it's going to be a bit different from the default exported component.</p>
<p>Create a file called <code>spike-story.jsx</code> under the <code>app/components/spike/</code> directory with the following code:</p>
<pre><code class="lang-js"><span class="hljs-comment">// spike-story.jsx</span>

<span class="hljs-string">"use client"</span>;

<span class="hljs-keyword">import</span> { useState } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> dynamic <span class="hljs-keyword">from</span> <span class="hljs-string">"next/dynamic"</span>;

<span class="hljs-keyword">const</span> LazySpike = dynamic(<span class="hljs-function">() =&gt;</span> <span class="hljs-keyword">import</span>(<span class="hljs-string">"./spike"</span>).then(<span class="hljs-function">(<span class="hljs-params">mod</span>) =&gt;</span> mod.LazySpike), {
    <span class="hljs-attr">loading</span>: <span class="hljs-function">() =&gt;</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>Loading Spike<span class="hljs-symbol">&amp;apos;</span>s Story...<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span></span>,
});

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">SpikeStory</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">const</span> [shown, setShown] = useState(<span class="hljs-literal">false</span>);

    <span class="hljs-keyword">return</span> (
        <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex flex-col m-8 w-[300px]"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">h2</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-xl my-1"</span>&gt;</span>Demonstrating <span class="hljs-tag">&lt;<span class="hljs-name">strong</span>&gt;</span>Named Export<span class="hljs-tag">&lt;/<span class="hljs-name">strong</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
                <span class="hljs-attr">className</span>=<span class="hljs-string">"bg-slate-600 text-white rounded p-1"</span>
                <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> setShown(!shown)}
            &gt;
                Load 🦮 Spike<span class="hljs-symbol">&amp;apos;</span>s Story
            <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>

            {shown &amp;&amp; <span class="hljs-tag">&lt;<span class="hljs-name">LazySpike</span> /&gt;</span>}
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
    );
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> SpikeStory;
</code></pre>
<p>Like <code>tom-story</code>, we are using the dynamic import with the next/dynamic. But let's zoom into the following block from the above code:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> LazySpike = dynamic(<span class="hljs-function">() =&gt;</span> <span class="hljs-keyword">import</span>(<span class="hljs-string">"./spike"</span>).then(<span class="hljs-function">(<span class="hljs-params">mod</span>) =&gt;</span> mod.LazySpike), {
    <span class="hljs-attr">loading</span>: <span class="hljs-function">() =&gt;</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>Loading Spike<span class="hljs-symbol">&amp;apos;</span>s Story...<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span></span>,
});
</code></pre>
<p>The changes you will notice here are that we are resolving the promise explicitly from the <code>import("./spike")</code> function using the the <code>.then()</code> handler function. We get the module first, and then pick the exported component by its actual name – that is <code>LazySpike</code> in this case. The rest of the things remain the same as before as in the <code>tom-story</code>.</p>
<p>Now to test it out, again import the component into the <code>page.js</code> file, and use it in the JSX  like the last two times.</p>
<pre><code class="lang-js"><span class="hljs-comment">// page.js</span>

<span class="hljs-keyword">import</span> TomStory <span class="hljs-keyword">from</span> <span class="hljs-string">"./components/tom/tom-story"</span>;
<span class="hljs-keyword">import</span> JerryStory <span class="hljs-keyword">from</span> <span class="hljs-string">"./components/jerry/jerry-story"</span>;
<span class="hljs-keyword">import</span> SpikeStory <span class="hljs-keyword">from</span> <span class="hljs-string">"./components/spike/spike-story"</span>; 

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Home</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex flex-wrap justify-center "</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">TomStory</span> /&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">JerryStory</span> /&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">SpikeStory</span> /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}
</code></pre>
<p>There you go – you should see the new component rendered on the browser with a button to load Spike's story from the <code>spike.jsx</code> file which is not loaded yet.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/07/Screenshot-2024-07-17-at-9.59.55-AM.png" alt="Image" width="600" height="400" loading="lazy">
<em>The button to lazy load Spike's story</em></p>
<p>Clicking on the button will load the file into the browser and render the component to show you Spike's story.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/07/Screenshot-2024-07-17-at-10.02.01-AM.png" alt="Image" width="600" height="400" loading="lazy">
<em>Spike's story is lazily loaded</em></p>
<p>Below you can see all three components demonstrating three different techniques and uses cases side-by-side. You can test them together. The image below is showcasing lazy loading of two components in parallel where another component was already lazily loaded.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/07/Screenshot-2024-07-17-at-10.14.21-AM.png" alt="Image" width="600" height="400" loading="lazy">
<em>Lazily loading multiple components in parallel</em></p>
<p>Here is another case where all three components were lazy loaded, on demand with the respective button clicks. </p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/07/Screenshot-2024-07-17-at-10.05.35-AM-1.png" alt="Image" width="600" height="400" loading="lazy">
<em>All the stories lazy loaded</em></p>
<h2 id="heading-lazy-loading-your-server-components">Lazy Loading Your Server Components</h2>
<p>We spoke about the lazy loading techniques of client components. Can we use the same on server components as well? Well, you can but you don't have to, as server components are already <code>code split</code> and the loading aspect is already been taken care of by Next.js. You are not going to get any kind of error if you are trying to do so, but it would be unnecessary. </p>
<p>In case, you are dynamically importing a server component that has one or more client components as children, those client components will be lazy loaded. But there won't be any impact on the (parent) server component itself.</p>
<p>Here is an example of a server component that has two client components as children:</p>
<pre><code class="lang-js"><span class="hljs-comment">// server-comp.jsx</span>

<span class="hljs-keyword">import</span> ComponentA <span class="hljs-keyword">from</span> <span class="hljs-string">"./a-client-comp"</span>;
<span class="hljs-keyword">import</span> ComponentB <span class="hljs-keyword">from</span> <span class="hljs-string">"./b-client-comp"</span>;

<span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>

<span class="hljs-keyword">const</span> AServerComp = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex flex-col m-8 w-[300px]"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">ComponentA</span> /&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">ComponentB</span> /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  )
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> AServerComp
</code></pre>
<p>Now, we are dynamically importing the server component into the <code>page.js</code> file and using it in its JSX. The child client components of the dynamically imported server component will be lazy loaded, but not the server component itself.</p>
<pre><code class="lang-js"><span class="hljs-comment">// page.js</span>

<span class="hljs-keyword">import</span> dynamic <span class="hljs-keyword">from</span> <span class="hljs-string">"next/dynamic"</span>;

<span class="hljs-keyword">import</span> TomStory <span class="hljs-keyword">from</span> <span class="hljs-string">"./components/tom/tom-story"</span>;
<span class="hljs-keyword">import</span> JerryStory <span class="hljs-keyword">from</span> <span class="hljs-string">"./components/jerry/jerry-story"</span>;
<span class="hljs-keyword">import</span> SpikeStory <span class="hljs-keyword">from</span> <span class="hljs-string">"./components/spike/spike-story"</span>;

<span class="hljs-keyword">const</span> AServerComp = dynamic(<span class="hljs-function">() =&gt;</span> <span class="hljs-keyword">import</span>(<span class="hljs-string">'./components/server-comps/server-comp'</span>), {
  <span class="hljs-attr">loading</span>: <span class="hljs-function">() =&gt;</span> <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>Loading Through Server Component...<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span></span>,
})


<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Home</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex flex-wrap justify-center "</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">TomStory</span> /&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">JerryStory</span> /&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">SpikeStory</span> /&gt;</span>

      <span class="hljs-tag">&lt;<span class="hljs-name">AServerComp</span> /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}
</code></pre>
<h2 id="heading-should-we-lazy-load-all-client-components-in-nextjs">Should We Lazy Load All Client Components in Next.js?</h2>
<p>I had this question when I first started learning about lazy loading. Now that I have gained more experience with this technique, here is my perspective:</p>
<p>You don't have to lazy load all client components. Optimzation is great, but over optimization can have adverse effects. You need to identify where these optimizations are required. </p>
<ul>
<li>Do you have client components that are really bulky? </li>
<li>Are you unnecessarily putting so many things into one component that you should break it down and refactor? </li>
<li>Do you import heavy libraries into your client components? </li>
<li>Have you opted for tree-shaking? </li>
<li>Can you mark bulky client components per route and is it fine not to load some or all of them at the initial load of the page for that route?</li>
</ul>
<p>As you see, these are a bunch of meaningful questions to ask before you step into optimizing things. Once you have answers, and decide you need lazy loading, then you can implement the techniques you learned from this article.</p>
<h2 id="heading-whats-next">What's Next?</h2>
<p>That's all for now. Did you enjoy reading this article and have you learned something new? If so, I would love to know if the content was helpful. I have my social handles provided below.</p>
<p>Up next, if you are willing to learn <code>Next.js</code> and its ecosystem like <code>Next-Auth(V5)</code> with both fundamental concepts and projects, I have a great news for you: you can <a target="_blank" href="https://www.youtube.com/watch?v=VSB2h7mVhPg&amp;list=PLIJrr73KDmRwz_7QUvQ9Az82aDM9I8L_8">check out this playlist on my YouTube</a> channel with 20+ video tutorials and 11+ hours of engaging content so far, for free. I hope you like them as well.</p>
<p>Let's connect.</p>
<ul>
<li>Subscribe to my <a target="_blank" href="https://www.youtube.com/tapasadhikary?sub_confirmation=1">YouTube Channel</a>.</li>
<li><a target="_blank" href="https://twitter.com/tapasadhikary">Follow me on X (Twitter</a>) or <a target="_blank" href="https://www.linkedin.com/in/tapasadhikary/">LinkedIn</a> if you don't want to miss the daily dose of up-skilling tips.</li>
<li>Check out and follow my Open Source work on <a target="_blank" href="https://github.com/atapas">GitHub</a>.</li>
<li>I regularly publish meaningful posts on my <a target="_blank" href="https://blog.greenroots.info/">GreenRoots Blog</a>, you may find them helpful, too.</li>
</ul>
<p>See you soon with my next article. Until then, please take care of yourself, and keep learning.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Caching vs Content Delivery Networks – What's the Difference? ]]>
                </title>
                <description>
                    <![CDATA[ By Anamika Ahmed In the world of network optimization, Content Delivery Networks (CDNs) and caching play a vital role in improving website performance and user experience.  And while both aim to speed up website loading times, they have distinct purp... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/caching-vs-content-delivery-network/</link>
                <guid isPermaLink="false">66d45d99680e33282da25e0c</guid>
                
                    <category>
                        <![CDATA[ caching ]]>
                    </category>
                
                    <category>
                        <![CDATA[ content delivery network  ]]>
                    </category>
                
                    <category>
                        <![CDATA[ web performance ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Fri, 01 Mar 2024 19:27:51 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2024/02/Conducting-Research-Projects-Educational-Presentation-in-Pink-and-Yellow-Colorful-Line-Style-1.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Anamika Ahmed</p>
<p>In the world of network optimization, Content Delivery Networks (CDNs) and caching play a vital role in improving website performance and user experience. </p>
<p>And while both aim to speed up website loading times, they have distinct purposes and mechanisms. </p>
<p>In this tutorial, we'll dive deep into the details of CDNs and caching to understand their similarities, differences, and how they contribute to enhancing online experiences.</p>
<h3 id="heading-heres-what-well-cover">Here's what we'll cover:</h3>
<ol>
<li><a class="post-section-overview" href="#heading-what-is-caching">What is Caching?</a></li>
<li><a class="post-section-overview" href="#heading-what-is-a-content-delivery-network-cdn">What is a Content Delivery Network (CDN)?</a></li>
<li><a class="post-section-overview" href="#heading-caching-vs-cdns-whats-the-difference">Caching vs CDNs – What's the Difference?</a></li>
<li><a class="post-section-overview" href="#heading-when-to-use-caching">When to Use Caching</a></li>
<li><a class="post-section-overview" href="#heading-when-to-use-cdns">When to use CDNs</a></li>
<li><a class="post-section-overview" href="#heading-combining-caching-and-cdns">Combining Caching and CDNs</a></li>
<li><a class="post-section-overview" href="#heading-wrapping-up">Wrapping Up</a></li>
</ol>
<h2 id="heading-what-is-caching">What is Caching?</h2>
<p>Imagine you’re a librarian managing a popular library. Every day, readers come in asking for the same set of books like “Think and Grow Rich” or “The Intelligent Investor.” </p>
<p>Initially, you fetch these books from the main shelves, which takes time and effort. But soon, you notice a pattern: the same set of books are requested repeatedly by different readers. So, what do you do?</p>
<p>You decide to create a special section near the entrance where you keep copies of these frequently requested books. Now, when readers come asking for them, you don’t have to run to the main shelves each time. Instead, you simply hand them the copies from the special section, saving time and making the process more efficient. </p>
<p>This special section represents the cache, storing frequently accessed books for quick retrieval.</p>
<p>Caching is a technique used to store copies of frequently accessed data temporarily. The cached data can be anything from web pages and images to database query results. When a user requests cached content, the server retrieves it from the cache instead of generating it anew, significantly reducing response times.</p>
<p>When a web server receives a request, it can follow different caching strategies to handle it efficiently. One prevalent strategy is known as read-through caching:</p>
<ol>
<li>Request Received: The web server gets a request from a client.</li>
<li>Check Cache: It first looks into the cache to see if the response to the request is already there.</li>
<li>Cache Hit: If the response is in the cache (hit), it sends the data back to the client right away.</li>
<li>Cache Miss: If the response isn’t in the cache (miss), the server queries the database to fetch the required data.</li>
<li>Store in Cache: Once it gets the data from the database, it stores the response in the cache for future requests.</li>
<li>Send Response: Finally, the server sends the data back to the client.</li>
</ol>
<h3 id="heading-what-to-consider-when-implementing-a-cache-system">What to Consider When Implementing a Cache System</h3>
<h4 id="heading-decide-when-to-use-a-cache">Decide When to Use a Cache:</h4>
<ul>
<li>A cache is best for frequently read but infrequently modified data.</li>
<li>Cache servers are not suitable for storing critical data as they use volatile memory.</li>
<li>Important data should be stored in persistent data stores to prevent loss in case of cache server restarts.</li>
</ul>
<h4 id="heading-set-an-expiration-policy">Set an Expiration Policy:</h4>
<ul>
<li>Implement an expiration policy to remove expired data from the cache.</li>
<li>Avoid setting expiration dates too short (to prevent frequent database reloads), and too long (to prevent stale data).</li>
</ul>
<h4 id="heading-maintain-synchronization-between-data-stores-and-cache">Maintain Synchronization Between Data Stores and Cache</h4>
<ul>
<li>Inconsistencies can arise due to separate operations on data storage and cache, especially in distributed environments.</li>
</ul>
<h4 id="heading-mitigate-failures">Mitigate Failures:</h4>
<ul>
<li>Use multiple cache servers across different data centers to avoid single points of failure.</li>
<li>Over-provision memory to accommodate increased usage and prevent performance issues.</li>
</ul>
<h4 id="heading-implement-an-eviction-policy">Implement an Eviction Policy:</h4>
<ul>
<li>When the cache is full, new items may cause existing ones to be removed (cache eviction).</li>
<li>A popular eviction policy is Least Recently Used (LRU), but other policies like Least Frequently Used (LFU) or First In, First Out (FIFO) can be chosen based on specific use cases.</li>
</ul>
<h3 id="heading-real-world-applications-of-caching">Real-World Applications of Caching</h3>
<p><strong>Social Media Platforms:</strong> Imagine scrolling through your Facebook feed. Thanks to caching, you see profile pictures, trending posts, and recently liked content instantly, even if millions of users are accessing the platform simultaneously. </p>
<p>Caching these frequently accessed elements on servers or your device minimizes delays and makes the experience smoother and more engaging.</p>
<p><strong>E-commerce Websites:</strong> When browsing Amazon for a new gadget, you expect a seamless shopping experience. Caching plays a crucial role here. Product images, descriptions, and pricing information are cached, enabling the website to display search results and product pages rapidly. </p>
<p>This is especially crucial during peak seasons like Black Friday or Cyber Monday, where caching helps handle surges in traffic and ensures customers can complete their purchases without encountering delays.</p>
<p><strong>Content Management Systems (CMS):</strong> Millions of websites rely on CMS platforms like WordPress. To ensure smooth performance for all these users, many CMS platforms integrate caching plugins. These plugins cache frequently accessed pages, reducing the load on the server and database. </p>
<p>This translates to faster page loading times, improved SEO ranking due to faster indexing by search engines, and a more responsive website overall, providing a better experience for visitors.</p>
<h2 id="heading-what-is-a-content-delivery-network-cdn">What is a Content Delivery Network (CDN)?</h2>
<p>Now, think of a CDN as a global network of book delivery trucks. Instead of storing all the books in one central library, you have local branches worldwide, each with copies of the most popular books. </p>
<p>When readers request a book, you don’t have to ship it from the main library. Instead, you direct them to the nearest branch, where they can quickly pick up a copy. This cuts down on travel time (data transfer time) and keeps everyone happy with fast access to their favorite books.</p>
<p>In technical terms, a CDN is a network of servers distributed across various locations globally. Its primary purpose is to deliver web content, such as images, videos, scripts, and stylesheets to users more efficiently by reducing the physical distance between the server and the user.</p>
<h3 id="heading-how-cdns-work">How CDNs Work:</h3>
<p>First, imagine that User A wants to see an image on a website. They click on a link provided by the CDN, like “<a target="_blank" href="https://mysite.cloudfront.net/logo.jpg">https://mywebsite.cloudfront.net/image.jpg</a>". This requests the image.</p>
<p>Then, if the image isn’t in the CDN’s storage (cache), the CDN fetches the image from the original source, like a web server or Amazon S3.</p>
<p>In response to that, the original source sends the image back to the CDN. It might include a Time-to-Live (TTL) header, indicating how long the image should stay cached.</p>
<p>Next, the the CDN stores the image and serves it to User A. It stays cached until the TTL expires.</p>
<p>Then let's say that user B requests the same image. At that point, the CDN checks if it’s still in the cache. If the image is still cached (TTL hasn’t expired), the CDN serves it from there (a hit). Otherwise (a miss), it fetches a fresh copy from the origin.</p>
<h3 id="heading-what-to-consider-when-implementing-a-cdn">What to Consider When Implementing a CDN</h3>
<ul>
<li><strong>Cost Management</strong>: CDNs charge for data transfers. It’s wise to cache frequently accessed content, but not everything.</li>
<li><strong>Cache Expiry</strong>: Set appropriate cache expiry times. Too long, and content might be stale. Too short, and it strains origin servers.</li>
<li><strong>CDN Fallback</strong>: Plan for CDN failures. Ensure your website can switch to fetching resources directly from the origin if needed.</li>
<li><strong>Invalidating Files</strong>: You can remove files from the CDN before they expire using various methods provided by CDN vendors.</li>
</ul>
<h3 id="heading-real-world-applications-of-a-cdn">Real-World Applications of a CDN</h3>
<p><strong>Video Streaming Services:</strong> Imagine you're in Sydney, Australia, craving to watch the latest season of your favorite show on Netflix. Without a CDN, the data would have to travel all the way from a server in, say, California, leading to buffering and frustrating delays. </p>
<p>But thanks to CDNs, Netflix caches popular content on edge servers closer to you, in Sydney or its surrounding region. This significantly reduces the distance the data needs to travel, ensuring smooth playback and an uninterrupted viewing experience, regardless of your location. </p>
<p>In fact, studies show that CDNs can <strong>reduce video startup time by up to 50%</strong>, making a significant difference in user satisfaction.</p>
<p><strong>Gaming Content Distribution:</strong> Gamers know the pain of waiting for massive game updates or DLC downloads. But companies like Steam and Epic Games leverage CDNs to make things faster. </p>
<p>These platforms cache game files, updates, and multiplayer assets on edge servers close to gaming communities. This means whether you're downloading a new game in New York or patching your favorite title in Tokyo, the data doesn't have to travel across continents. </p>
<p>Using CDNs can decrease download times quite a bit, leading to quicker access to the games you love and smoother multiplayer experiences with minimal lag.</p>
<p><strong>Global News Websites:</strong> Staying informed about global events shouldn't be hindered by slow loading times. Major news organizations like BBC News and The New York Times use CDNs to ensure their breaking news updates and multimedia content reach audiences worldwide instantly. </p>
<p>By caching critical information like articles, videos, and images on servers across different continents, CDNs enable news websites to deliver real-time updates quickly, keeping readers informed regardless of their location. </p>
<p>During major events or emergencies, this can be especially crucial, as evidenced by a case study where a news organization using a CDN reported a <strong>20% increase in website traffic without any performance issues</strong> during a breaking news event.</p>
<h2 id="heading-caching-vs-cdns-whats-the-difference">Caching vs CDNs – What's the Difference?</h2>
<h3 id="heading-similarities-between-caching-and-cdns">Similarities between caching and CDNs:</h3>
<p><strong>Improved Performance:</strong> Both CDNs and caching aim to enhance website performance by reducing latency and speeding up content delivery.</p>
<p><strong>Efficient Resource Utilization:</strong> By serving cached or replicated content, both approaches help optimize resource utilization and reduce server load.</p>
<p><strong>Enhanced User Experience:</strong> Faster load times lead to a better user experience, whether achieved through CDNs or caching.</p>
<h3 id="heading-differences-between-caching-and-cdns">Differences between Caching and CDNs</h3>
<h4 id="heading-scope">Scope:</h4>
<ul>
<li>CDNs: CDNs are a network of servers located in different geographic locations around the world.</li>
<li>Caching: Caching is a method of storing web content on a user’s local device or server.</li>
</ul>
<h4 id="heading-implementation">Implementation:</h4>
<ul>
<li>CDNs: CDNs require a separate infrastructure and configuration.</li>
<li>Caching: Caching can be implemented within a web application or server using caching rules and directives.</li>
</ul>
<h4 id="heading-geographic-coverage">Geographic Coverage:</h4>
<ul>
<li>CDNs: Designed to deliver web content to users across the world.</li>
<li>Caching: Typically used to improve performance for individual users or within a local network.</li>
</ul>
<h4 id="heading-network-architecture">Network Architecture:</h4>
<ul>
<li>CDNs: Use a distributed network of servers to cache and deliver content.</li>
<li>Caching: This can be implemented using various types of storage such as local disk, memory, or a server-side cache.</li>
</ul>
<h4 id="heading-performance-benefits">Performance Benefits:</h4>
<ul>
<li>CDNs: Provide faster and more reliable content delivery by caching content in multiple locations.</li>
<li>Caching: Improves performance by reducing the number of requests to the origin server and delivering content faster from a local cache.</li>
</ul>
<h4 id="heading-cost">Cost:</h4>
<ul>
<li>CDNs: Can be more expensive to implement and maintain due to the need for a separate infrastructure and ongoing costs for network maintenance.</li>
<li>Caching: Can be implemented using existing infrastructure and server resources, potentially reducing costs.</li>
</ul>
<h2 id="heading-when-to-use-caching">When to use Caching</h2>
<p>Caching is ideal for frequently accessed content that doesn't change frequently. This includes static assets like images, CSS files, and JavaScript libraries.</p>
<p>It's particularly effective for websites with a substantial user base accessing similar content, such as news websites, blogs, and e-commerce platforms.</p>
<p>Caching can also significantly reduce server load and improve response times for users, especially in scenarios where content delivery latency is a concern.</p>
<h2 id="heading-when-to-use-cdns">When to use CDNs</h2>
<p>CDNs are invaluable for delivering content to a global audience, especially when geographical distance between users and origin servers leads to latency issues.</p>
<p>They are well-suited for serving dynamic content, streaming media, and handling sudden spikes in traffic.</p>
<p>CDNs also excel in scenarios where content needs to be delivered reliably and consistently across diverse geographic regions, ensuring optimal user experience regardless of location.</p>
<h2 id="heading-combining-caching-and-cdns">Combining Caching and CDNs</h2>
<p>In many scenarios, employing both caching and CDNs together yields optimal results, particularly for dynamic websites and applications where a mix of static and dynamic content delivery is essential. Let's consider a popular news website as an example.</p>
<p>Imagine a bustling news website that regularly publishes breaking news articles, accompanied by images and videos. While the core news content is dynamic and frequently updated, the images and videos associated with older articles remain relatively static and are accessed repeatedly by users.</p>
<p>To address this, the website can implement a combined strategy:</p>
<ol>
<li><strong>Caching on the Origin Server:</strong> Frequently accessed elements like website templates, navigation menus, and static content are cached directly on the origin server. This caching reduces server load and enhances performance for initial page loads.</li>
<li><strong>CDN Caching:</strong> The website leverages a CDN to cache frequently accessed images and videos associated with news articles on edge servers located worldwide. This ensures that users, regardless of their geographic location, can swiftly access these elements with minimal latency.</li>
</ol>
<p>There are many benefits of the combined approach, such as:</p>
<ul>
<li><strong>Faster Loading Times:</strong> By serving cached content from both the origin server and CDN edge servers, users experience significantly faster loading times, leading to a more engaging browsing experience.</li>
<li><strong>Reduced Server Load:</strong> Caching alleviates pressure on the origin server, enabling it to efficiently process dynamic content updates while serving static elements from cache.</li>
<li><strong>Improved Global Reach:</strong> The CDN ensures that users worldwide can access the website and its content with minimal delays, irrespective of their proximity to the origin server.</li>
</ul>
<p>But there are also some factors to consider:</p>
<ul>
<li><strong>Cache Invalidation:</strong> Regularly updating cached content ensures users access the latest information. Most CDNs offer efficient cache invalidation mechanisms to facilitate this process.</li>
<li><strong>Cost Optimization:</strong> While combining caching and CDNs enhances performance, it's crucial to evaluate the cost-effectiveness of caching specific content. Analyzing user access patterns helps determine the optimal caching strategy.</li>
</ul>
<p>By strategically combining caching and CDNs, you and your team can create a robust content delivery infrastructure that delivers a superior user experience worldwide.</p>
<h2 id="heading-wrapping-up">Wrapping Up</h2>
<p>Both CDNs and caching play crucial roles in optimizing website performance and user experience by speeding up content delivery. </p>
<p>While caching stores frequently accessed data locally for quick retrieval, CDNs provide a geographically distributed network of servers to deliver content efficiently to users worldwide. </p>
<p>Understanding their similarities in performance improvement and resource utilization, as well as their key differences in scope, implementation, and cost is crucial for choosing the right approach for your specific needs.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Perform Performance Testing on Your Web Applications ]]>
                </title>
                <description>
                    <![CDATA[ Performance testing is an important yet underrated field of software development. And it’s a must-have skill that can help you prevent common software failures that occur in production applications.  Performance testing is a routine software practice... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/performance-testing-for-web-applications/</link>
                <guid isPermaLink="false">66bb58d1074d8d7b12eae39a</guid>
                
                    <category>
                        <![CDATA[ Testing ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Web Applications ]]>
                    </category>
                
                    <category>
                        <![CDATA[ web performance ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Oluwatobi ]]>
                </dc:creator>
                <pubDate>Mon, 26 Feb 2024 19:52:39 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2024/02/performance-test2.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Performance testing is an important yet underrated field of software development. And it’s a must-have skill that can help you prevent common software failures that occur in production applications. </p>
<p>Performance testing is a routine software practice which is carried out to determine the stability of a system in terms of scalability, reliability, and data management, among other parameters.</p>
<p>In this tutorial, I'll walk you through what performance testing entails, and the common tools used for backend testing. We'll also walk through a demo performance testing project together. </p>
<p>The tutorial is simplified and suitable for beginners, mid-level developers, and professional developers. Being proficient in performance testing is fundamental to growing as a backend developer, and this guide will serve as a good review even if you're more advanced in your career. With that said, let's dive in.</p>
<h3 id="heading-prerequisites">Prerequisites:</h3>
<ul>
<li>Intermediate knowledge of Node.js</li>
<li>Basic knowledge of JavaScript operations</li>
<li>Knowledge of API development\</li>
</ul>
<h2 id="heading-table-of-contents">Table of Contents:</h2>
<ol>
<li><a class="post-section-overview" href="#heading-what-is-performance-testing">What is Performance Testing?</a></li>
<li><a class="post-section-overview" href="#heading-examples-of-performance-testing-tools">Examples of Performance Testing Tools</a></li>
<li><a class="post-section-overview" href="#heading-demo-project">Demo Project</a></li>
<li><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></li>
</ol>
<h2 id="heading-what-is-performance-testing">What is Performance Testing?</h2>
<p>Performance testing serves quite a lot of purposes – one of the most important of which is to test system efficiency in performing and sustaining tasks. It also serves as a standard you can use to compare systems of varying efficiency and builds and enables you to choose the most effective one.</p>
<p>Performance testing also helps reveal vulnerabilities. State-of-the-art testing tools are well optimized to efficiently analyze the code to detect any errors. They're quick to highlight the areas where these errors occur.</p>
<p>The end goal of performance testing is dependent how you're using the application. It might be concurrency-oriented or transaction rate-oriented, depending on whether the app involves end users or not. </p>
<p>Performance testing could also involve load testing, which is usually carried out to evaluate the behavior of a web service under a specific expected load. Other types of testing you can do include integration testing, spike testing, soak testing, and stress testing.</p>
<h2 id="heading-examples-of-performance-testing-tools">Examples of Performance Testing Tools</h2>
<p>There are many tools commonly used to test the efficacy and latency of web applications. In this section, I'll discuss some of the popular tools used, and highlight their strengths and use cases.</p>
<h3 id="heading-jest">Jest</h3>
<p><a target="_blank" href="https://www.npmjs.com/package/jest">Jest</a> is a multi-platform testing tool used to assess the correctness of JavaScript-based applications. It's the one we'll be using in this demo. </p>
<p>Jest was initially created to test the efficiency of React applications, but has since been extended to test the efficiency of Node.js apps as well. It also offers a code coverage feature.</p>
<h3 id="heading-mocha">Mocha</h3>
<p><a target="_blank" href="https://www.npmjs.com/package/mocha">Mocha</a> is a concise asynchronous JavaScript-based testing tool for Node.js applications. It is also used with assertion libraries such as <code>[Chai]( https://www.npmjs.com/package/chai)</code> and <code>[should]( https://www.npmjs.com/package/should)</code>.</p>
<h3 id="heading-pythagora">Pythagora</h3>
<p><a target="_blank" href="https://github.com/Pythagora-io/pythagora">Pythagora</a> offers a unique integrating testing feature to help test how different part of the application works together. It also has a code coverage feature.</p>
<h3 id="heading-artillery">Artillery</h3>
<p><a target="_blank" href="https://artillery.io">Artillery</a> is a stack agnostic testing tool. This means it can be used for multiple web applications based on different programming languages and still produce an optimal test outcome. </p>
<p>This tool provides efficient load testing features which help to determine the optimal status of the application when exposed to a large load of traffic. It also checks the speed at which an app responds to a user request without crashing. </p>
<h3 id="heading-ava">Ava</h3>
<p><a target="_blank" href="https://www.npmjs.com/package/ava">Ava</a> is a JavaScript-based performance unit testing tool used to test the efficacy of Node.js applications. It works asynchronously, running multiple concurrent tests to determine the suitability of multiple code units.</p>
<h3 id="heading-loadtest">Loadtest</h3>
<p><a target="_blank" href="https://www.npmjs.com/package/loadtest">Loadtest</a> is a special Node package which is used to load test Node.js applications. It evaluates their ability to cope with requests of varying volumes and it evaluates for efficiency and concurrency.</p>
<h3 id="heading-apache-j-meter">Apache J-meter</h3>
<p><a target="_blank" href="https://jmeter.apache.org">Apache J-meter</a> offers load-testing features for web applications. It has an in-built IDE to enable interaction with the user. It is multithreaded, increasing its ability to mimic several users.</p>
<p>There are other testing tools which are also useful. But in this tutorial, we will be utilizing <code>Jest</code> to test our back-end application.</p>
<h2 id="heading-demo-project">Demo Project</h2>
<h3 id="heading-install-jest">Install Jest</h3>
<p>We'll now perform a unit test on our code using the <code>Jest</code> testing tool. To do this, you'll need to install the <code>Jest</code> package in your code folder. Type <code>npm install jest</code> in the command prompt. A success message will be displayed when the installation is completed.</p>
<h3 id="heading-configure-packagejson">Configure <code>package.json</code></h3>
<p>In this tutorial, we'll test the efficiency of some selected routes in our Node.js application. This will necessitate writing different unit tests for each route and evaluating its correctness. </p>
<p>Now let’s optimize our file structure to successfully unit test our application. Navigate to the <code>package.json</code> file and edit it to include the following code:</p>
<pre><code class="lang-javascript"><span class="hljs-string">"scripts"</span>: {
    <span class="hljs-string">"test"</span>: <span class="hljs-string">" jest"</span>,
    <span class="hljs-string">"start"</span>: <span class="hljs-string">"nodemon index.js"</span>
  },
</code></pre>
<p>Modifying the package.json file to include this code ensures that the Node.js server recognizes Jest as our default unit testing tool for the project. By so doing, any time we enter <code>npm test</code> in the command prompt, Jest gets activated.</p>
<h3 id="heading-set-up-the-test-environment">Set up the test environment</h3>
<p>Create a folder in the <code>root</code> directory named “tests”. This helps the Jest operator locate the specific files housing the routes to be tested. </p>
<p>Within the test folder, create a test file. The file can be named whatever you prefer, but the suffix <code>.test.js</code> should be added to enable <code>Jest</code> to recognize it and execute it.</p>
<p>After completing these steps, let’s get into the core details of unit testing in our project.</p>
<h3 id="heading-run-the-unit-tests">Run the unit tests</h3>
<p>The demo project we'll test in this tutorial is an eBook library application which contains some functions such as a <code>get all books</code> route, <code>Get a single book</code> route, <code>upload a book</code> route, and <code>delete a book</code> route.  We'll create unit tests for the <code>GetAllBooks</code> route in the example below, and then you can try to create your own for the other routes.</p>
<p>So firstly, we'll import the book database into the test.js file like this:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> Book = <span class="hljs-built_in">require</span>(<span class="hljs-string">'../models/Book'</span>)
</code></pre>
<p>The code above imports and initializes our default book MongoDB database model.</p>
<p>Then we'll import the functions that we'll test in each route:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> Book =  <span class="hljs-built_in">require</span>(<span class="hljs-string">"../models/Book"</span>)

<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">GetAllBooks</span> (<span class="hljs-params">req, res</span>)  </span>{
    <span class="hljs-keyword">try</span> {
<span class="hljs-keyword">const</span> allBooks =  <span class="hljs-keyword">await</span> Book.find();
res.status(<span class="hljs-number">200</span>)
res.send(allBooks)
    }
    <span class="hljs-keyword">catch</span> (err) {
res.status(<span class="hljs-number">500</span>)
res.send(err) 
    }
}
<span class="hljs-built_in">module</span>.exports = {GetAllBooks};
</code></pre>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> {GetAllBooks} = <span class="hljs-built_in">require</span>(<span class="hljs-string">"../controllers/Books"</span>);
</code></pre>
<p>The code above imports the getAllBooks function from a controller folder. </p>
<p>Having imported the function, let's now go ahead to setup our Jest unit test function.</p>
<pre><code class="lang-javascript">jest.mock(<span class="hljs-string">"../models/Book"</span>);

<span class="hljs-keyword">const</span> req = {};
<span class="hljs-keyword">const</span> res = {
  <span class="hljs-attr">status</span>: jest.fn(<span class="hljs-function">(<span class="hljs-params">x</span>) =&gt;</span> x),
  <span class="hljs-attr">send</span>: jest.fn(<span class="hljs-function">(<span class="hljs-params">x</span>) =&gt;</span> x),
};

it(<span class="hljs-string">"it should return all the books in the database"</span>, <span class="hljs-keyword">async</span> () =&gt; {

Book.find.mockImplementationOnce(<span class="hljs-function">() =&gt;</span> ({
    <span class="hljs-attr">Title</span>: <span class="hljs-string">"black is king"</span>,
    <span class="hljs-attr">Author</span>: <span class="hljs-string">"black"</span>,
    <span class="hljs-attr">price</span>: <span class="hljs-string">"$23"</span>,
    <span class="hljs-attr">Summary</span>: <span class="hljs-string">"Hello"</span>,
  }));

  <span class="hljs-keyword">await</span> GetAllBooks(req, res);


expect(res.status).toHaveBeenCalledWith(<span class="hljs-number">200</span>);

expect(res.send).toHaveBeenCalledTimes(<span class="hljs-number">1</span>);
});
</code></pre>
<p>First of all, Jest offers you the ability to create a fake database by copying the structure of the default database. This is known as mocking. This enables the unit test to operate faster and eliminate the lag that comes with getting responses from large databases. </p>
<p>Testing which involves the real database is referred to as end-to-end testing as opposed to unit testing.</p>
<p>Here's how you can do that in Jest:</p>
<pre><code class="lang-javascript">jest.mock(<span class="hljs-string">"../models/Book"</span>);
</code></pre>
<p>The code above illustrates database mocking. In order to get a faster unit test, we have to mock the existing Book database model we're using in our application.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> req = {};
<span class="hljs-keyword">const</span> res = {
  <span class="hljs-attr">status</span>: jest.fn(<span class="hljs-function">(<span class="hljs-params">x</span>) =&gt;</span> x),
  <span class="hljs-attr">send</span>: jest.fn(<span class="hljs-function">(<span class="hljs-params">x</span>) =&gt;</span> x),
};
</code></pre>
<p>The above code contains the default sample requests and response objects. The sample response object contains both the status and send functions, which return a defined output if executed successfully or not.</p>
<pre><code class="lang-javascript">it(<span class="hljs-string">"it should return all the books in the database"</span>, <span class="hljs-keyword">async</span> () =&gt; {
Book.find.mockImplementationOnce(<span class="hljs-function">() =&gt;</span> ({
    <span class="hljs-attr">Title</span>: <span class="hljs-string">"black is king"</span>,
    <span class="hljs-attr">Author</span>: <span class="hljs-string">"black"</span>,
    <span class="hljs-attr">price</span>: <span class="hljs-string">"$23"</span>,
    <span class="hljs-attr">Summary</span>: <span class="hljs-string">"Hello"</span>,
  }));
  <span class="hljs-keyword">await</span> GetAllBooks(req, res); 
expect(res.status).toHaveBeenCalledWith(<span class="hljs-number">200</span>);
expect(res.send).toHaveBeenCalledTimes(<span class="hljs-number">1</span>);
});
</code></pre>
<p>Now the <code>It</code> function contains a short description of what the test should be about. This is then coupled to an anonymous asynchronous function which contains a mock implementation of the database model with some dummy data.</p>
<p>After that, the getAllBooks request is triggered and executed with a null request passed to it and the format of the response object is included.</p>
<p>The <code>expect</code> statement returns <code>passed</code> if the function satisfies the requirements expected. For this code, the requirements are that the <code>response</code> object should return a status code of 200 and the <code>response.send</code> object should be called at least once with the response object included. If it fails, a failed status will be returned.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/02/test.JPG" alt="Image" width="600" height="400" loading="lazy">
<em>Tests passing</em></p>
<p>You now know the basics of how to unit test functions. You can also try to test the <code>delete book</code> route, <code>upload a book</code> route and <code>find a specific book</code> route.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In this tutorial, you've been able to harness the usefulness of testing tools in optimizing your web applications. </p>
<p>You've learned about various testing tools available and their use cases, and you also implemented a unit test in a web application.  </p>
<p>Following the steps highlighted in this tutorial, you will be able to perform unit tests on your coding projects.</p>
<p>I sincerely hope you learned something new and enjoyed this tutorial. Until next time, keep on coding.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Optimize Your CSS Code for Faster Web Pages ]]>
                </title>
                <description>
                    <![CDATA[ CSS is more than just a tool for styling. It also determines how web pages render in a browser. Well-optimized CSS means faster loading times and a smoother user experience. In today's digital landscape, the performance of a website is a key factor i... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-optimize-your-css-code-for-faster-web-pages/</link>
                <guid isPermaLink="false">66c5a33d5e24e23ff2251593</guid>
                
                    <category>
                        <![CDATA[ CSS ]]>
                    </category>
                
                    <category>
                        <![CDATA[ web performance ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Ophy Boamah ]]>
                </dc:creator>
                <pubDate>Fri, 26 Jan 2024 13:00:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2024/01/csstitle.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>CSS is more than just a tool for styling. It also determines how web pages render in a browser. Well-optimized CSS means faster loading times and a smoother user experience.</p>
<p>In today's digital landscape, the performance of a website is a key factor in its success. Writing efficient CSS code can greatly influence how quickly your web pages load, impacting everything from user experience to search engine rankings. </p>
<p>This guide delves into effective strategies to help you refine your CSS, ensuring that your website not only looks great but also loads swiftly and runs smoothly.</p>
<h2 id="heading-how-css-affects-web-performance">How CSS affects Web Performance</h2>
<p>When a user visits a webpage, the browser retrieves the site's structural HTML and its stylistic CSS. This is a set of detailed instructions on how each part of the webpage should look. </p>
<p>If the CSS is packed with too much information or is too complex, it's like giving the browser a puzzle that takes longer to solve. This can lead to longer waiting times for users, which can be annoying.</p>
<p>That's where the art of streamlining CSS comes into play. It's not just about tidying up the code, but also making sure the browser can get the webpage ready faster. </p>
<p>When CSS is made leaner and simpler, it's like giving the browser a clear, easy-to-follow map. This makes webpages load faster, making everything feel more responsive. </p>
<h2 id="heading-1-write-shorter-css">1. Write Shorter CSS</h2>
<p>When writing CSS, use the popular software development principle Don’t Repeat Yourself (DRY). This advocates for conciseness and clarity in your code. </p>
<p>This is important here, because in practice, CSS involves repeating properties across various selectors. The goal should be to identify and consolidate these repetitive properties. By doing so you eliminate redundancies, leading to cleaner and more manageable CSS.</p>
<p>For instance, in the code below, multiple elements (<code>h1</code>and <code>h2</code>) share the same font-size and color. </p>
<pre><code class="lang-css"><span class="hljs-selector-tag">h1</span> {
    <span class="hljs-attribute">font-size</span>: <span class="hljs-number">20px</span>;
    <span class="hljs-attribute">color</span>: <span class="hljs-number">#fff</span>;
}
<span class="hljs-selector-tag">h2</span> {
    <span class="hljs-attribute">font-size</span>: <span class="hljs-number">20px</span>;
    <span class="hljs-attribute">color</span>: <span class="hljs-number">#fff</span>;
}
</code></pre>
<p>So instead of declaring these properties separately for each selector, you can group them under a common class. This not only streamlines your stylesheet but also makes future updates easier and less error-prone.</p>
<p>You can rewrite the above code to look like this:</p>
<pre><code class="lang-css"><span class="hljs-selector-tag">h1</span>, <span class="hljs-selector-tag">h2</span> {
    <span class="hljs-attribute">font-size</span>: <span class="hljs-number">20px</span>;
    <span class="hljs-attribute">color</span>: <span class="hljs-number">#fff</span>;
}
</code></pre>
<p>Using shorthand properties is another effective strategy for minimizing the size of your CSS, making your code more efficient. It also allows you to set multiple related CSS properties with a single declaration. Here's how you can write effective shorthand CSS:</p>
<p>When all sides of an element have the same value, use that one value.</p>
<pre><code class="lang-css"><span class="hljs-comment">/* Before shorthand */</span>
<span class="hljs-selector-class">.same-sides</span> {
    <span class="hljs-attribute">padding-top</span>: <span class="hljs-number">15px</span>;
    <span class="hljs-attribute">padding-right</span>: <span class="hljs-number">15px</span>;
    <span class="hljs-attribute">padding-bottom</span>: <span class="hljs-number">15px</span>;
    <span class="hljs-attribute">padding-left</span>: <span class="hljs-number">15px</span>;
}

<span class="hljs-comment">/* After shorthand */</span>
<span class="hljs-selector-class">.same-sides</span> {
    <span class="hljs-attribute">padding</span>: <span class="hljs-number">15px</span>;
}
</code></pre>
<p>When all sides of an element have different values, use all four.</p>
<pre><code class="lang-css"><span class="hljs-comment">/* Before shorthand */</span>
<span class="hljs-selector-class">.different-sides</span> {
    <span class="hljs-attribute">padding-top</span>: <span class="hljs-number">10px</span>;
    <span class="hljs-attribute">padding-right</span>: <span class="hljs-number">20px</span>;
    <span class="hljs-attribute">padding-bottom</span>: <span class="hljs-number">15px</span>;
    <span class="hljs-attribute">padding-left</span>: <span class="hljs-number">25px</span>;
}

<span class="hljs-comment">/* After shorthand */</span>
<span class="hljs-selector-class">.different-sides</span> {
    <span class="hljs-attribute">padding</span>: <span class="hljs-number">10px</span> <span class="hljs-number">20px</span> <span class="hljs-number">15px</span> <span class="hljs-number">25px</span>;
}
</code></pre>
<p>When top/bottom and right/left have the same value, use two values.</p>
<pre><code class="lang-css"><span class="hljs-comment">/* Before shorthand */</span>
<span class="hljs-selector-class">.two-sides</span> {
    <span class="hljs-attribute">padding-top</span>: <span class="hljs-number">10px</span>;
    <span class="hljs-attribute">padding-right</span>: <span class="hljs-number">20px</span>;
    <span class="hljs-attribute">padding-bottom</span>: <span class="hljs-number">10px</span>;
    <span class="hljs-attribute">padding-left</span>: <span class="hljs-number">20px</span>;
}

<span class="hljs-comment">/* After shorthand */</span>
<span class="hljs-selector-class">.two-sides</span> {
    <span class="hljs-attribute">padding</span>: <span class="hljs-number">10px</span> <span class="hljs-number">20px</span>;
}
</code></pre>
<p>When only the right/left values are the same but the top and bottom aren't, use three values.</p>
<pre><code class="lang-css"><span class="hljs-comment">/* Before shorthand */</span>
<span class="hljs-selector-class">.three-sides</span> {
    <span class="hljs-attribute">padding-top</span>: <span class="hljs-number">10px</span>;
    <span class="hljs-attribute">padding-right</span>: <span class="hljs-number">20px</span>;
    <span class="hljs-attribute">padding-bottom</span>: <span class="hljs-number">15px</span>;
    <span class="hljs-attribute">padding-left</span>: <span class="hljs-number">20px</span>;
}

<span class="hljs-comment">/* After shorthand */</span>
<span class="hljs-selector-class">.three-sides</span> {
    <span class="hljs-attribute">padding</span>: <span class="hljs-number">10px</span> <span class="hljs-number">20px</span> <span class="hljs-number">15px</span>;
}
</code></pre>
<h2 id="heading-2-use-shallow-css-selectors">2. Use Shallow CSS Selectors</h2>
<p>Shallow CSS selectors are direct and concise selectors with fewer levels of nested elements that don't dig too deep into the HTML structure. </p>
<p>Simplifying your selectors can significantly speed up your webpage rendering because deeply nested selectors take longer for browsers to evaluate, which results in a slower page render.</p>
<p>Consider the example in the code below: to assign property values to a deeply nested selector like <code>header nav ul li a</code> is cumbersome and will cause rendering delays because the browser needs time to check each level (header, then nav, then ul, and so on) to find the right <strong><code>&lt;a&gt;</code></strong> tag to style). </p>
<p>Alternatively, giving it a direct class <code>.nav-link</code> is straightforward and quicker for browsers to interpret. Class selectors are generally more efficient than nested tags because the browser simply looks for elements with a class and applies the styles, without worrying about their position in the DOM tree.</p>
<pre><code class="lang-css"><span class="hljs-comment">/* Less efficient: Deeply nested selector */</span>
<span class="hljs-selector-tag">header</span> <span class="hljs-selector-tag">nav</span> <span class="hljs-selector-tag">ul</span> <span class="hljs-selector-tag">li</span> <span class="hljs-selector-tag">a</span> { 
   <span class="hljs-attribute">color</span>: <span class="hljs-number">#000</span>;
   <span class="hljs-attribute">font-size</span>: <span class="hljs-number">10px</span>;
 }

<span class="hljs-comment">/* More efficient: Class selector */</span>
<span class="hljs-selector-class">.nav-link</span> {
   <span class="hljs-attribute">color</span>: <span class="hljs-number">#000</span>;
   <span class="hljs-attribute">font-size</span>: <span class="hljs-number">10px</span>;
}
</code></pre>
<h2 id="heading-3-segment-css-code">3. Segment CSS Code</h2>
<p>Segmenting your CSS code into smaller, more focused segments like separate files for different website components and creating page-specific styles can greatly improve your website's performance. This approach not only makes it easier to find and edit specific styles but also ensures that webpages load only the CSS they need, avoiding unnecessary bulk.</p>
<p>Enhanced maintainability and faster page loading are the most obvious key benefits. Smaller CSS files are easier to manage, much like a well-organized toolbox where everything is easy to find. But also, by loading only the essential CSS for each page, the browser has less work to do hence improving the user experience.</p>
<h3 id="heading-original-css">Original CSS</h3>
<p>Suppose you have a CSS file that contains styles for various parts of your website:</p>
<pre><code class="lang-css"><span class="hljs-comment">/* Styles for the home page */</span>
<span class="hljs-selector-class">.homepage</span> {
    <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#f0f0f0</span>;
    <span class="hljs-attribute">padding</span>: <span class="hljs-number">10px</span>;
}

<span class="hljs-comment">/* Styles for the services page */</span>
<span class="hljs-selector-class">.services</span> {
    <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#333</span>;
    <span class="hljs-attribute">color</span>: white;
}

<span class="hljs-comment">/* Styles for the contact page */</span>
<span class="hljs-selector-class">.contact</span> {
    <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#222</span>;
    <span class="hljs-attribute">color</span>: white;
    <span class="hljs-attribute">padding</span>: <span class="hljs-number">20px</span>;
}
</code></pre>
<h3 id="heading-segmented-css">Segmented CSS</h3>
<p>Now, let's segment this CSS into different files based on their purpose:</p>
<ol>
<li><strong>Home page Styles (homepage.css):</strong></li>
</ol>
<pre><code class="lang-css"><span class="hljs-selector-class">.homepage</span> {
    <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#f0f0f0</span>;
    <span class="hljs-attribute">padding</span>: <span class="hljs-number">10px</span>;
}
</code></pre>
<ol start="2">
<li><strong>Services page Styles (services.css):</strong></li>
</ol>
<pre><code class="lang-css"><span class="hljs-selector-class">.services</span> {
    <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#333</span>;
    <span class="hljs-attribute">color</span>: white;
}
</code></pre>
<ol start="3">
<li><strong>Contact page Styles (contact.css):</strong></li>
</ol>
<pre><code class="lang-css"><span class="hljs-selector-class">.contact</span> {
    <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#222</span>;
    <span class="hljs-attribute">color</span>: white;
    <span class="hljs-attribute">padding</span>: <span class="hljs-number">20px</span>;
}
</code></pre>
<p>Each CSS file is focused on a specific part of the website. Now, when a user visits your website, each page loads only the CSS it requires hence enhancing the website's performance.</p>
<h2 id="heading-4-optimize-css-delivery">4. Optimize CSS Delivery</h2>
<p>You can make your CSS files lighter and faster to load by shrinking your CSS – that is, you can remove extra spaces and lines (this is called minifying). Then you can compress these files so they're smaller and quicker for users to download. </p>
<p>Also, make sure the most important styles of your website load first, so people see your page faster. The other styles can load in the background without slowing things down.</p>
<p>You can also make your website faster for people who visit more than once, by saving some of your CSS in their browser (this is known as caching). This means it doesn’t have to load again every time they visit. </p>
<p>Also, if you use a CDN or a network of servers, your CSS files can be stored in many places around the world to load faster no matter where your users are. </p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/01/minifycss.png" alt="Image" width="600" height="400" loading="lazy">
<em>Graphic comparing file size between an unminified CSS file at 167KB and a minified CSS file at 92KB</em></p>
<h3 id="heading-original-css-1">Original CSS</h3>
<pre><code class="lang-css"><span class="hljs-comment">/* Main Stylesheet */</span>
<span class="hljs-comment">/* Header Style */</span>
<span class="hljs-selector-tag">header</span> {
  <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#333</span>;
  <span class="hljs-attribute">color</span>: white;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">10px</span>;
}

<span class="hljs-comment">/* Navigation Style */</span>
<span class="hljs-selector-tag">nav</span> {
  <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#444</span>;
  <span class="hljs-attribute">margin-top</span>: <span class="hljs-number">10px</span>;
}
</code></pre>
<p>The above CSS code is readable and well-commented, but it contains extra spaces and comments that increase the file size.</p>
<h3 id="heading-minified-css">Minified CSS</h3>
<pre><code class="lang-css"><span class="hljs-selector-tag">header</span>{<span class="hljs-attribute">background-color</span>:<span class="hljs-number">#333</span>;<span class="hljs-attribute">color</span>:white;<span class="hljs-attribute">padding</span>:<span class="hljs-number">10px</span>}<span class="hljs-selector-tag">nav</span>{<span class="hljs-attribute">background-color</span>:<span class="hljs-number">#444</span>;<span class="hljs-attribute">margin-top</span>:<span class="hljs-number">10px</span>;}
</code></pre>
<p>The minified version combines all the rules into a single line, removing unnecessary spaces and comments, which reduces the file size for quicker loading.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Optimizing your CSS speeds up your website and consequently improves the overall user experience. </p>
<p>By implementing the practices outlined in this article, you can achieve more performant, efficient and maintainable CSS. The performance savings may not be significant from tweaking a few lines but over hundreds more across different stylesheets, the impact will begin to show. </p>
<p>Remember, web performance is an ongoing process. Regularly review and refine your CSS to keep up with best practices and emerging trends.</p>
<h3 id="heading-additional-resources">Additional Resources</h3>
<ul>
<li><a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/CSS">MDN Web Docs on CSS</a></li>
<li><a target="_blank" href="https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency">Google Web Fundamentals</a></li>
<li><a target="_blank" href="https://www.oreilly.com/library/view/web-performance-in/9781617293771/">Web Performance In Action</a></li>
</ul>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How Lazy Loading Works in Web Development ]]>
                </title>
                <description>
                    <![CDATA[ In the ever-evolving landscape of web development, performance optimization remains a top priority.  Among the plethora of strategies you can use to enhance web performance, lazy loading stands out for its efficiency and impact.  But what exactly is ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-lazy-loading-works-in-web-development/</link>
                <guid isPermaLink="false">66bae6b8db6fa5bf0acac927</guid>
                
                    <category>
                        <![CDATA[ performance ]]>
                    </category>
                
                    <category>
                        <![CDATA[ web performance ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Sudheer Kumar Reddy Gowrigari ]]>
                </dc:creator>
                <pubDate>Thu, 04 Jan 2024 01:08:30 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/12/A-simple-banner-image-depicting-the-concept-of-lazy-loading-images.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>In the ever-evolving landscape of web development, performance optimization remains a top priority. </p>
<p>Among the plethora of strategies you can use to enhance web performance, lazy loading stands out for its efficiency and impact. </p>
<p>But what exactly is lazy loading, and how does it revolutionize the way we handle web resources? That's what we'll cover in this article.</p>
<h2 id="heading-what-is-lazy-loading">What is Lazy Loading?</h2>
<p>Lazy loading is a web performance optimization strategy that plays a critical role in how resources are loaded on a webpage. </p>
<p>Traditionally, when you go to access a webpage, the browser attempts to load all resources (images, scripts, stylesheets) immediately. This can lead to longer load times, especially if the page contains many large files. </p>
<p>Lazy loading addresses this by marking certain resources as non-blocking or non-critical, loading them only when they are needed. This method is especially effective for elements that aren't immediately visible on the initial page load, such as images and videos that appear further down the page.</p>
<h3 id="heading-key-benefits-of-lazy-loading">Key benefits of lazy loading:</h3>
<ul>
<li><strong>Improved Performance</strong>: By loading only the necessary resources, the initial page load is faster, leading to a better user experience.</li>
<li><strong>Reduced Bandwidth Usage</strong>: Lazy loading minimizes the amount of data that needs to be transferred initially, saving bandwidth for both the user and the server.</li>
<li><strong>Enhanced User Engagement</strong>: Faster load times generally lead to lower bounce rates and higher engagement, as users are less likely to leave a slow-loading site.</li>
</ul>
<p>Lazy loading can be implemented in various ways, with the most common method being JavaScript-based. But modern web development practices have introduced native HTML ways to implement lazy loading, such as the loading attribute for images.</p>
<h2 id="heading-the-role-of-the-image-loading-attribute-in-lazy-loading">The Role of the Image Loading Attribute in Lazy Loading</h2>
<p>As we delve deeper into the practicalities of lazy loading, you'll see that the <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/img#loading">loading</a> attribute in the <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/img"><code>&lt;img&gt;</code></a> element is a game-changer. </p>
<p>This attribute, a relatively recent addition to the HTML specification, offers a simple yet powerful way to implement lazy loading natively, without the need for additional JavaScript. By leveraging the loading attribute, you can significantly enhance web performance and user experience, especially in content-heavy websites.</p>
<h3 id="heading-browser-level-lazy-loading">Browser-Level Lazy Loading</h3>
<p>Primarily, browsers like Chrome and Firefox support the loading attribute for <img width="600" height="400" alt="" loading="lazy"> and <div class="embed-wrapper"><iframe title="Embedded content" loading="lazy"> elements. Using loading="lazy", the browser defers the loading of images until they are near the viewport. </iframe></div></p>
<p>This method is efficient and enhances performance by loading images only when they are likely to be viewed by the user. But it's important to note that the lazy value for <div class="embed-wrapper"><iframe title="Embedded content" loading="lazy"> elements is not yet standardized and may undergo changes.</iframe></div></p>
<p>Let's look at some examples to see how this works.</p>
<h4 id="heading-basic-lazy-loading-of-a-single-image">Basic lazy loading of a single image</h4>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"image-1.jpg"</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">"A scenic landscape"</span> <span class="hljs-attr">loading</span>=<span class="hljs-string">"lazy"</span>&gt;</span>
</code></pre>
<p>In this example, the <code>loading="lazy"</code> attribute in the <code>&lt;img&gt;</code> tag tells the browser to defer loading this image until it's about to enter the viewport. This means the image won't load when the page initially loads, but only when the user scrolls near it.</p>
<h4 id="heading-lazy-loading-with-high-priority-images">Lazy loading with high-priority images</h4>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"logo.jpg"</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">"Company Logo"</span> <span class="hljs-attr">loading</span>=<span class="hljs-string">"eager"</span>&gt;</span> 
<span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"featured.jpg"</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">"Featured Product"</span> <span class="hljs-attr">loading</span>=<span class="hljs-string">"lazy"</span>&gt;</span>
</code></pre>
<p>Here, the first image (logo) uses <code>loading="eager"</code>, which is the default behavior to load the image immediately. It's useful for important images that need to be seen right away. The second image (featured product) uses <code>loading="lazy"</code>, ideal for images that are not critical to see immediately.</p>
<h4 id="heading-lazy-loading-in-a-gallery">Lazy loading in a gallery</h4>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"gallery-image-1.jpg"</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">"Gallery Image 1"</span> <span class="hljs-attr">loading</span>=<span class="hljs-string">"lazy"</span>&gt;</span> 
<span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"gallery-image-2.jpg"</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">"Gallery Image 2"</span> <span class="hljs-attr">loading</span>=<span class="hljs-string">"lazy"</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"gallery-image-3.jpg"</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">"Gallery Image 3"</span> <span class="hljs-attr">loading</span>=<span class="hljs-string">"lazy"</span>&gt;</span>
</code></pre>
<p>For image galleries, using <code>loading="lazy"</code> for each image ensures that images load as the user scrolls through the gallery, improving page load time and reducing bandwidth usage.</p>
<p><strong>Combining Lazy Loading with Art Direction</strong></p>
<p>Art direction in web design refers to the practice of adapting the presentation of content to suit different contexts, devices, or demographics. It often involves using different images or visual styles to convey a specific message or feeling that resonates with various audience segments or fits different screen sizes.</p>
<p>For instance, a website might display a detailed, large image on a desktop but a simpler, smaller image on a mobile device – both delivering the same message but optimized for their respective viewing contexts. </p>
<p>Here’s how you can implement this alongside lazy loading:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">picture</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">source</span> <span class="hljs-attr">media</span>=<span class="hljs-string">"(min-width: 800px)"</span> <span class="hljs-attr">srcset</span>=<span class="hljs-string">"large.jpg"</span> <span class="hljs-attr">loading</span>=<span class="hljs-string">"lazy"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">source</span> <span class="hljs-attr">media</span>=<span class="hljs-string">"(min-width: 400px)"</span> <span class="hljs-attr">srcset</span>=<span class="hljs-string">"medium.jpg"</span> <span class="hljs-attr">loading</span>=<span class="hljs-string">"lazy"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"small.jpg"</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">"Responsive Image"</span> <span class="hljs-attr">loading</span>=<span class="hljs-string">"lazy"</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">picture</span>&gt;</span>
</code></pre>
<p>In this code, the <code>&lt;picture&gt;</code> element contains multiple <code>&lt;source&gt;</code> elements, each with a different <code>srcset</code> attribute for different screen sizes, and a default <code>&lt;img&gt;</code> element. The <code>loading="lazy"</code> attribute is added to each source to enable lazy loading.</p>
<h3 id="heading-intersection-observer-for-polyfilling">Intersection Observer for Polyfilling</h3>
<p>The Intersection Observer API is a modern web API that provides a way to asynchronously observe changes in the intersection of a target element with an ancestor element or the viewport. Essentially, it allows you to execute code when an element enters or leaves the viewport, which is perfect for lazy loading images.</p>
<p>Polyfilling is a technique in web development where modern functionality is replicated in older browsers that do not support that functionality natively. A polyfill is a piece of code (usually JavaScript) that provides the technology that developers expect the browser to provide natively.</p>
<p>When it comes to lazy loading, if a browser does not support the <code>loading</code> attribute, we can use the Intersection Observer as a polyfill to achieve lazy loading behavior.</p>
<p>This JavaScript-based method involves observing <code>&lt;img&gt;</code> elements to determine their visibility within the viewport. When an image becomes visible, its <code>src</code> and <code>srcset</code> attributes are updated to load the actual image. </p>
<p>This method requires additional markup, including a class attribute for selection, a <code>src</code> attribute for a placeholder image, and <code>data-src</code> and <code>data-srcset</code> attributes for the actual image URLs</p>
<h4 id="heading-first-the-html-setup">First, the HTML setup:</h4>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"lazy"</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"placeholder.jpg"</span> <span class="hljs-attr">data-src</span>=<span class="hljs-string">"actual-image.jpg"</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">"Description"</span>&gt;</span>
</code></pre>
<ul>
<li><code>class="lazy"</code>: A class identifier for JavaScript selection.</li>
<li><code>src</code>: A placeholder image URL.</li>
<li><code>data-src</code>: The actual image URL to be loaded.</li>
</ul>
<h4 id="heading-then-the-javascript">Then, the JavaScript:</h4>
<pre><code class="lang-javascript"><span class="hljs-built_in">document</span>.addEventListener(<span class="hljs-string">"DOMContentLoaded"</span>, <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">var</span> lazyImages = [].slice.call(<span class="hljs-built_in">document</span>.querySelectorAll(<span class="hljs-string">"img.lazy"</span>));

  <span class="hljs-keyword">if</span> (<span class="hljs-string">"IntersectionObserver"</span> <span class="hljs-keyword">in</span> <span class="hljs-built_in">window</span>) {
    <span class="hljs-keyword">let</span> lazyImageObserver = <span class="hljs-keyword">new</span> IntersectionObserver(<span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">entries, observer</span>) </span>{
      entries.forEach(<span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">entry</span>) </span>{
        <span class="hljs-keyword">if</span> (entry.isIntersecting) {
          <span class="hljs-keyword">let</span> lazyImage = entry.target;
          lazyImage.src = lazyImage.dataset.src;
          lazyImage.classList.remove(<span class="hljs-string">"lazy"</span>);
          lazyImageObserver.unobserve(lazyImage);
        }
      });
    });

    lazyImages.forEach(<span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">lazyImage</span>) </span>{
      lazyImageObserver.observe(lazyImage);
    });
  } <span class="hljs-keyword">else</span> {
    <span class="hljs-comment">// Fallback for browsers without Intersection Observer support</span>
  }
});
</code></pre>
<p>This section of code demonstrates how you can use the Intersection Observer API to implement lazy loading. It checks if the Intersection Observer is supported in the browser and, if so, uses it to load images only when they enter the viewport.</p>
<h2 id="heading-wrapping-up">Wrapping Up</h2>
<p>Using lazy loading, particularly through the <strong>loading</strong> attribute in HTML, can significantly help you improve web performance. By selectively deferring the loading of images and iframes until they are needed, this technique not only enhances the speed and efficiency of web pages but also contributes to a more seamless and responsive user experience. </p>
<p>Whether you apply lazy loading to individual images, galleries, or complex responsive layouts, the versatility of the loading attribute allows you to cater to various web development scenarios, ensuring that resources are utilized effectively and efficiently. </p>
<p>As web technologies continue to evolve, adopting such performance-centric strategies will become increasingly vital in delivering content that meets the expectations of modern web users.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Set Up Message Queues for Async Tasks with RabbitMQ in Nest.js Apps ]]>
                </title>
                <description>
                    <![CDATA[ When you're developing programs, certain services can block or slow down the speed of your application. For example, CPU-intensive tasks like audio transcribing or file processing. So you might wonder – how do you make sure your application runs with... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/message-queues-with-rabbitmq-in-nest-js/</link>
                <guid isPermaLink="false">66bb51f80fc4910f8f7dfba8</guid>
                
                    <category>
                        <![CDATA[ nestjs ]]>
                    </category>
                
                    <category>
                        <![CDATA[ performance ]]>
                    </category>
                
                    <category>
                        <![CDATA[ queue ]]>
                    </category>
                
                    <category>
                        <![CDATA[ web performance ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Okoye Chukwuebuka Victor ]]>
                </dc:creator>
                <pubDate>Thu, 14 Dec 2023 01:20:25 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/12/articlePhoto.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>When you're developing programs, certain services can block or slow down the speed of your application. For example, CPU-intensive tasks like audio transcribing or file processing.</p>
<p>So you might wonder – how do you make sure your application runs without breaking? To handle this, you can send tasks to a queue outside your application's flow.</p>
<h2 id="heading-what-is-a-message-queue">What is a Message Queue?</h2>
<p>A message queue is a tool that facilitates the communication and transfer of data between services within a single application (or externally). It stores these data or messages using the First-In-First-Out (FIFO) principle. This means that older data that's passed into these queues gets processed before newer data.</p>
<p>Different components make up a message queue, such as:</p>
<ul>
<li><strong>Messages</strong>: These are the data that are sent to the queue. They are often referred to as jobs.</li>
<li><strong>Queues</strong>: These are the data structures used for storing messages.</li>
<li><strong>Producers</strong>: These are a service that sends messages or data into the queue system.</li>
<li><strong>Consumers</strong>: These are a service that listens to the queue and executes messages passed in it.</li>
</ul>
<h3 id="heading-message-queuing-tools">Message Queuing Tools</h3>
<p>Now, there are various message queuing tools you can use in asynchronous systems, like the following:</p>
<ul>
<li><strong>RabbitMQ</strong>: a reliable and flexible option for implementing message queues in applications.</li>
<li><strong>Apache</strong> <strong>Kafka</strong>: an efficient message queuing tool, also very good at event stream processing.</li>
<li><strong>Redis</strong>: an in-memory store used for message queuing, caching, and data processing.</li>
</ul>
<p>Note that some of these tools are not limited to message queuing but can be used for other purposes as well, like stream processing.</p>
<p>In this article, you will create a simple Nest.js project which will use RabbitMQ as the Message Queue Service Provider.</p>
<p>The tutorial will be divided into 3 parts:</p>
<ul>
<li><a class="post-section-overview" href="#heading-how-to-set-up-a-nestjs-project">How to Set Up a Nest.js Project for Basic User Registration Flow</a></li>
<li><a class="post-section-overview" href="#heading-how-to-set-up-an-email-service-for-user-registration">How to Set Up an Email Service for User Registration</a></li>
<li><a class="post-section-overview" href="#heading-how-to-integrate-a-queue-service-using-rabbitmq">How to Integrate a Queue Service using RabbitMQ</a></li>
</ul>
<h3 id="heading-prerequisites">Prerequisites</h3>
<ul>
<li>You'll need to have Node installed on your system. If you don't have it, here is its official site: <a target="_blank" href="https://nodejs.org/en">https://nodejs.org/en</a>.</li>
<li>You'll need to have Node Package Manager (NPM) installed, which you can download here if you don't have it: <a target="_blank" href="https://docs.npmjs.com/downloading-and-installing-node-js-and-npm">https://docs.npmjs.com/downloading-and-installing-node-js-and-npm</a>.</li>
<li>You'll need to have installed RabbitMQ. Here is where you can get it in case you haven't yet: <a target="_blank" href="https://www.rabbitmq.com/download.html">https://www.rabbitmq.com/download.html</a></li>
<li>You'll need to have a text editor. For this article, I'll use VSCode. You can download it here: <a target="_blank" href="https://code.visualstudio.com/download">https://code.visualstudio.com/download</a> or use the code editor of your choice.</li>
</ul>
<h2 id="heading-how-to-set-up-a-nestjs-project">How to Set Up a Nest.js Project</h2>
<p>Spinning up a Nest.js application is fast and simple if you use the Nest CLI. Open up your terminal and enter this command below to install the CLI:</p>
<pre><code class="lang-bash"> $ npm install -g @nestjs/cli
</code></pre>
<p>This installs the Nest.js CLI globally on your system, meaning you can call the CLI commands regardless of the directory you are currently in.</p>
<p>Moving forward, to create a simple REST API project, you will enter the command below:</p>
<pre><code class="lang-bash">nest new simple-queue
</code></pre>
<p>Simple-queue here is the directory name that will be created. Inputting this command gives you a prompt to select a package manager.</p>
<p>When that's done, navigate to the created directory and open it in your text editor by entering this command:</p>
<pre><code class="lang-bash"><span class="hljs-built_in">cd</span> simple-queue &amp;&amp; code .
</code></pre>
<p>This opens up your text editor. We want to work on a project that will best show how a message queue can be used in a real-world scenario – so let's set up a basic user registration form. On successful data entry it sends an email to the user, but you'll handle the email service separately by passing it into a queue to improve performance.</p>
<p>For this, we'll be using an SQLite database, TypeOrm, class-validators, and the dotenv package so you can secure your config variables. Go ahead to install them by typing this command in your terminal:</p>
<pre><code class="lang-bash">npm install --save @nestjs/typeorm typeorm sqlite3 class-validator dotenv
</code></pre>
<p>When the installation is complete, go to your root app module, and then include the TypeOrm configuration for your database. </p>
<p>SQLite is a lightweight SQL database which allows us to quickly spin up and test data. It's optimal for this use case – and now we'll configure it.</p>
<h3 id="heading-configuring-the-sqlite-database">Configuring the SQLite Database</h3>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { Module } <span class="hljs-keyword">from</span> <span class="hljs-string">"@nestjs/common"</span>;
<span class="hljs-keyword">import</span> { TypeOrmModule } <span class="hljs-keyword">from</span> <span class="hljs-string">"@nestjs/typeorm"</span>;
<span class="hljs-keyword">import</span> { AppController } <span class="hljs-keyword">from</span> <span class="hljs-string">"./app.controller"</span>;
<span class="hljs-keyword">import</span> { AppService } <span class="hljs-keyword">from</span> <span class="hljs-string">"./app.service"</span>;

<span class="hljs-meta">@Module</span>({
  imports: [
    TypeOrmModule.forRoot({
      <span class="hljs-keyword">type</span>:<span class="hljs-string">'sqlite'</span>,
      database: <span class="hljs-string">'mini-db.sqlite'</span>,
      entities: [__dirname + <span class="hljs-string">'/**/*.entity{.ts,.js}'</span>],
      synchronize: <span class="hljs-literal">true</span>,  
  })],
  controllers: [AppController],
  providers: [AppService],
})
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> AppModule {}
</code></pre>
<p>Congrats! You have successfully connected a DB to your project. Now it's time to create the services that will handle the user registration. </p>
<p>In order to do this, you will have to go back to your dear friend the Nest CLI. There, you'll be inputting a different command to help generate a resource folder for the User, which will contain the entity, service, dto, and the controller.</p>
<p>To do this, open your terminal and enter in this command:</p>
<pre><code class="lang-bash">nest generate resource users
</code></pre>
<p>A prompt to select your transport layer will be shown. Select the first one which is the <code>REST API</code>. Then, another prompt will ask if you would like to generate CRUD endpoints – you can type Yes. Then you can make modifications according to your requirements.</p>
<p>To proceed, you first have to define what information each user should have. First, create a User entity. You can do this by navigating to the user entity file in the created entity subfolder in the user folder. Then define the user data like this:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { Entity, PrimaryGeneratedColumn, Column } <span class="hljs-keyword">from</span> <span class="hljs-string">"typeorm"</span>;

<span class="hljs-meta">@Entity</span>(<span class="hljs-string">'users'</span>)
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> User {
  <span class="hljs-meta">@PrimaryGeneratedColumn</span>(<span class="hljs-string">'uuid'</span>)
  id: <span class="hljs-built_in">string</span>;

  <span class="hljs-meta">@Column</span>({ length: <span class="hljs-number">100</span>, unique: <span class="hljs-literal">true</span> })
  username: <span class="hljs-built_in">string</span>;

  <span class="hljs-meta">@Column</span>({ length: <span class="hljs-number">100</span>, unique: <span class="hljs-literal">true</span> })
  email: <span class="hljs-built_in">string</span>;
}
</code></pre>
<p>For this mini-project, you'll use basic user data to make the process faster. The username and email field have been set to be unique, meaning that there won't be a duplicate of the data instance passed in for this user table.</p>
<p>Now having done this, modify the create user dto file that was generated like this:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { IsNotEmpty, IsString, IsEmail } <span class="hljs-keyword">from</span> <span class="hljs-string">"class-validator"</span>;

<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> CreateUserDto {
    <span class="hljs-meta">@IsNotEmpty</span>()
    <span class="hljs-meta">@IsString</span>()
    username: <span class="hljs-built_in">string</span>;

    <span class="hljs-meta">@IsNotEmpty</span>()
    <span class="hljs-meta">@IsString</span>()
    <span class="hljs-meta">@IsEmail</span>()
    email: <span class="hljs-built_in">string</span>;
  }
</code></pre>
<p>This was created to validate the payload that will be sent in your request by using the class-validator package.</p>
<p>Now, modify the <code>create</code> method in the user service file.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { Injectable } <span class="hljs-keyword">from</span> <span class="hljs-string">"@nestjs/common"</span>;
<span class="hljs-keyword">import</span> { InjectRepository } <span class="hljs-keyword">from</span> <span class="hljs-string">"@nestjs/typeorm"</span>;
<span class="hljs-keyword">import</span> { Repository } <span class="hljs-keyword">from</span> <span class="hljs-string">"typeorm"</span>;
<span class="hljs-keyword">import</span> { CreateUserDto } <span class="hljs-keyword">from</span> <span class="hljs-string">"./dto/create-user.dto"</span>;
<span class="hljs-keyword">import</span> { User } <span class="hljs-keyword">from</span> <span class="hljs-string">"./entities/user.entity"</span>;

<span class="hljs-meta">@Injectable</span>()
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> UsersService {
  <span class="hljs-keyword">constructor</span>(<span class="hljs-params">
    <span class="hljs-meta">@InjectRepository</span>(User)
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> userRepository: Repository&lt;User&gt;
  </span>) {}
  <span class="hljs-keyword">async</span> create(createUserDto: CreateUserDto): <span class="hljs-built_in">Promise</span>&lt;User&gt; {
    <span class="hljs-keyword">const</span> newUser = <span class="hljs-built_in">this</span>.userRepository.create(createUserDto);
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.userRepository.save(newUser);
  }
}
</code></pre>
<p>Next you'll modify the controller file. You've already defined the <code>create</code> endpoint, so you'll just have to clean up the other endpoints that are not needed.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { Controller, Post, Body } <span class="hljs-keyword">from</span> <span class="hljs-string">"@nestjs/common"</span>;
<span class="hljs-keyword">import</span> { CreateUserDto } <span class="hljs-keyword">from</span> <span class="hljs-string">"./dto/create-user.dto"</span>;
<span class="hljs-keyword">import</span> { UsersService } <span class="hljs-keyword">from</span> <span class="hljs-string">"./users.service"</span>;

<span class="hljs-meta">@Controller</span>(<span class="hljs-string">'users'</span>)
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> UsersController {
 <span class="hljs-keyword">constructor</span>(<span class="hljs-params"><span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> usersService: UsersService</span>) {}
  <span class="hljs-meta">@Post</span>()
  create(<span class="hljs-meta">@Body</span>() createUserDto: CreateUserDto) {
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.usersService.create(createUserDto);
  }
}
</code></pre>
<p>Open up the user module file and make some adjustments by adding the import field to the Module decorator and using the TypeOrmModule property.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { Module } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/common'</span>;
<span class="hljs-keyword">import</span> { UsersService } <span class="hljs-keyword">from</span> <span class="hljs-string">'./users.service'</span>;
<span class="hljs-keyword">import</span> { UsersController } <span class="hljs-keyword">from</span> <span class="hljs-string">'./users.controller'</span>;
<span class="hljs-keyword">import</span> { TypeOrmModule } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/typeorm'</span>;
<span class="hljs-keyword">import</span> { User } <span class="hljs-keyword">from</span> <span class="hljs-string">'./entities/user.entity'</span>;

<span class="hljs-meta">@Module</span>({
  imports: [TypeOrmModule.forFeature([User])],
  controllers: [UsersController],
  providers: [UsersService],
})
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> UsersModule {}
</code></pre>
<p>Next, start up your server by entering this command on your terminal: <code>npm run start:dev</code>. Once the server is up and running, open up your API client of choice. For this article, we'll use Postman. Then make a POST request to the endpoint, which will be <code>localhost:3000/users</code>, providing the payload data required.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1696695190655/b8b3b246-0961-4655-aaee-081b9ecff35e.png" alt="Image" width="898" height="409" loading="lazy">
<em>A request was made and a user instance was created.</em></p>
<p>Next up is adding an email service to your project which will help notify new users who are registering.</p>
<h2 id="heading-how-to-set-up-an-email-service-for-user-registration">How to Set Up an Email Service for User Registration</h2>
<p>For this, you'll use some packages which are required to create an email service. Open up your terminal and input the command below to install these packages:</p>
<pre><code class="lang-bash">npm install --save @nestjs-modules/mailer nodemailer
</code></pre>
<p>When these packages are installed, you can now implement the mail service. Using the Nest CLI, create a mailer module and service by entering this command in your terminal:</p>
<pre><code class="lang-bash">nest generate module email &amp;&amp; nest generate service email
</code></pre>
<p>When it's done, open up the newly created module file in the mail folder. You'll use the MailerModule property of the <code>@nestjs-modules/mailer</code> package to configure your mail service here. It requires an SMTP client whose keys you'll need to configure this MailerModule. </p>
<p>For that you can use <a target="_blank" href="https://app.elasticemail.com/api/">https://app.elasticemail.com</a> to get these SMTP keys. Sign up and connect to the SMTP API. You'll then be given keys for your private use.</p>
<p>Note that this free mode of the SMTP client has limitations and it cannot send to all emails – so you should use a test email service.</p>
<h3 id="heading-how-to-configure-the-mailer-module">How to Configure the Mailer Module</h3>
<p>Once you have gotten that set up, go back to your application and create a <strong>.env</strong> file. Set your secrets for the SMTP keys. Then configure your MailerModule like this:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { Global, Module } <span class="hljs-keyword">from</span> <span class="hljs-string">"@nestjs/common"</span>;
<span class="hljs-keyword">import</span> { EmailService } <span class="hljs-keyword">from</span> <span class="hljs-string">"./email.service"</span>;
<span class="hljs-keyword">import</span> { MailerModule } <span class="hljs-keyword">from</span> <span class="hljs-string">"@nestjs-modules/mailer"</span>;

<span class="hljs-built_in">require</span>(<span class="hljs-string">'dotenv'</span>).config();
<span class="hljs-meta">@Global</span>()
<span class="hljs-meta">@Module</span>({
  imports: [
    MailerModule.forRoot({
      transport: {
        service: <span class="hljs-string">'QueueTest'</span>,
        host: process.env.SMTP_HOST,
        port: process.env.SMTP_PORT,
        auth: {
          user: process.env.SMTP_USER,
          pass: process.env.SMTP_PASSWORD,
        },
      },
      defaults: {
        <span class="hljs-keyword">from</span>: process.env.FROM_EMAIL,
      },
    }),
  ],
  providers: [EmailService]
})
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> EmailModule {}
</code></pre>
<p>The global decorator was set in order to make sure the MailModule can be called anywhere in your application. Make sure your secrets are properly loaded and thaqt you have a valid Email set in the <strong>from: process.env.FROM_EMAIL.</strong></p>
<p>Check to make sure that the EmailModule is also imported in the root App Module the same way your UsersModule was imported in the Imports Array of the App Module.</p>
<p>Next, open your email service file – you'll need to make some modifications to the EmailService class. Add a constructor and call the MailService property from the <code>@nestjs-modules/mailer</code> package. Then go ahead and create a function that will handle sending the emails.</p>
<p>Below is a class and method that does this:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { MailerService } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs-modules/mailer'</span>;
<span class="hljs-keyword">import</span> { HttpException, HttpStatus, Injectable } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/common'</span>;

<span class="hljs-meta">@Injectable</span>()
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> EmailService {
  <span class="hljs-keyword">constructor</span>(<span class="hljs-params"><span class="hljs-keyword">private</span> mailerService: MailerService</span>) {}
  <span class="hljs-keyword">async</span> sendEmail(options: { email: <span class="hljs-built_in">string</span>; subject: <span class="hljs-built_in">string</span>; html: <span class="hljs-built_in">string</span>;
  }) {
    <span class="hljs-keyword">try</span> {
      <span class="hljs-keyword">const</span> message = {
        to: options.email,
        subject: options.subject,
        html: options.html
      };
      <span class="hljs-keyword">const</span> emailSend = <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.mailerService.sendMail({
        ...message,
      });
      <span class="hljs-keyword">return</span> emailSend;
    } <span class="hljs-keyword">catch</span> (error) {
      <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> HttpException(<span class="hljs-string">'Error'</span>, HttpStatus.INTERNAL_SERVER_ERROR);
    }
  }
}
</code></pre>
<p>Now you've defined the method to send an email. You've also put an exception handler in place for better error handling.</p>
<p>Now it's time to add this newly created service to your user registration flow.</p>
<p>Navigate to your user service file, and add the mail service to your constructor as a provider. Then call the service in your <code>create user</code> method like this:</p>
<pre><code class="lang-typescript"><span class="hljs-meta">@Injectable</span>()
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> UsersService {
  <span class="hljs-keyword">constructor</span>(<span class="hljs-params">
    <span class="hljs-meta">@InjectRepository</span>(User)
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> userRepository: Repository&lt;User&gt;,
    <span class="hljs-keyword">private</span> emailService: EmailService
  </span>) {}
  <span class="hljs-keyword">async</span> create(createUserDto: CreateUserDto): <span class="hljs-built_in">Promise</span>&lt;User&gt; {
    <span class="hljs-keyword">const</span> newUser = <span class="hljs-built_in">this</span>.userRepository.create(createUserDto);
    <span class="hljs-keyword">const</span> user =  <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.userRepository.save(newUser);
      <span class="hljs-keyword">const</span> emailData = {
        email: user.email,
        subject: <span class="hljs-string">'Welcome to Our Community'</span>,
        html: <span class="hljs-string">`&lt;p&gt;Hello <span class="hljs-subst">${user.username}</span>,&lt;/p&gt;
        &lt;p&gt;Welcome to our community! Your account is now active.&lt;/p&gt;
        &lt;p&gt;Enjoy your time with us!&lt;/p&gt;`</span>,
      };
      <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.emailService.sendEmail(emailData)
    <span class="hljs-keyword">return</span> user
  }
}
</code></pre>
<p>Make sure to modify your modules in order to correct any dependency injection errors. In your email module file, add the EmailService to the exports array:</p>
<pre><code class="lang-typescript"> providers: [EmailService],
 <span class="hljs-built_in">exports</span>: [EmailService]
</code></pre>
<p>Add it below your providers to export the Email Service so it can be accessed in other modules. Then import the EmailModule to your User module file and add it to your import array like this:</p>
<pre><code class="lang-typescript"><span class="hljs-meta">@Module</span>({
  imports: [TypeOrmModule.forFeature([User]), EmailModule],
  controllers: [UsersController],
  providers: [UsersService],
})
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> UsersModule {}
</code></pre>
<p>Now it's time to test it. Get a free account from any online email testing platform and open Postman. Make a request to the <code>create user</code> endpoint with your valid email. You should get an email response like this:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1696695108644/25aa9e76-da00-436b-9e43-f0c978f87c6f.png" alt="Image" width="712" height="272" loading="lazy">
<em>Email response you should get</em></p>
<h2 id="heading-how-to-integrate-a-queue-service-using-rabbitmq">How to Integrate a Queue Service using RabbitMQ</h2>
<p>To get started with this, you'll have to install some packages that let you implement queues using RabbitMQ. Enter the command below to install these packages:</p>
<pre><code class="lang-bash">npm install --save amqplib @types/amqplib amqp-connection-manager
</code></pre>
<h3 id="heading-configure-the-producer-service">Configure the Producer Service</h3>
<p>Once installation is complete, it's time to configure RabbitMQ. You'll create a new folder in your src directory and name it queues. Then create the queue producer file. Import these packages and set them up like this:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { HttpException, HttpStatus, Injectable, Logger } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/common'</span>;
<span class="hljs-keyword">import</span> amqp, { ChannelWrapper } <span class="hljs-keyword">from</span> <span class="hljs-string">'amqp-connection-manager'</span>;
<span class="hljs-keyword">import</span> { Channel } <span class="hljs-keyword">from</span> <span class="hljs-string">'amqplib'</span>;

<span class="hljs-meta">@Injectable</span>()
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> ProducerService {
  <span class="hljs-keyword">private</span> channelWrapper: ChannelWrapper;
  <span class="hljs-keyword">constructor</span>(<span class="hljs-params"></span>) {
    <span class="hljs-keyword">const</span> connection = amqp.connect([<span class="hljs-string">'amqp://localhost'</span>]);
    <span class="hljs-built_in">this</span>.channelWrapper = connection.createChannel({
      setup: <span class="hljs-function">(<span class="hljs-params">channel: Channel</span>) =&gt;</span> {
        <span class="hljs-keyword">return</span> channel.assertQueue(<span class="hljs-string">'emailQueue'</span>, { durable: <span class="hljs-literal">true</span> });
      },
    });
  }

  <span class="hljs-keyword">async</span> addToEmailQueue(mail: <span class="hljs-built_in">any</span>) {
    <span class="hljs-keyword">try</span> {
      <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.channelWrapper.sendToQueue(
        <span class="hljs-string">'emailQueue'</span>,
        Buffer.from(<span class="hljs-built_in">JSON</span>.stringify(mail)),
        {
          persistent: <span class="hljs-literal">true</span>,
        },
      );
      Logger.log(<span class="hljs-string">'Sent To Queue'</span>);
    } <span class="hljs-keyword">catch</span> (error) {
      <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> HttpException(
        <span class="hljs-string">'Error adding mail to queue'</span>,
        HttpStatus.INTERNAL_SERVER_ERROR,
      );
    }
  }
}
</code></pre>
<p>The AMQP connection was set and is running on localhost with the default RabittMQ port which is 5432. You also established a channel on that connection with an option input which is executed anytime a new channel is created. This helps if you have any configuration for that channel. </p>
<p>You also created an <code>emailQueue</code> with the assertQueue property which checks that a queue with that name does not already exist. If it does exist, it has no effect so it's idempotent. </p>
<p>Then you created an option <code>durable: true</code> to make sure that the queue will survive a server restart.</p>
<p>Next, you defined the method to add the email data to a queue. This calls the <code>sendToQueue</code> property of the channelWrapper, passing in the queue name you want to send the data to. Ideally, it should be the same name as the one you defined with the assertQueue property.</p>
<p>The second argument is the mail data, but firstly you converted it to a JSON string then to a Buffer. You do this because messages in RabbitMQ are mostly transmitted as binary data.</p>
<p>You can then set an option <code>persistent: true</code> to ensure that the data being sent to the queue won't be lost if the server crashes. Then with some error handling and the method to send messages to the queue, it's good to go.</p>
<h3 id="heading-set-up-the-consumer-service">Set Up the Consumer Service</h3>
<p>Now that you've configured the producer service, it's time to set up the consumer service. </p>
<p>Create another file in the queue sub-folder. It's quite similar, but in this case, you will be consuming the data from the queue. Below is the configuration for the consumer service:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { Injectable, OnModuleInit, Logger } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/common'</span>;
<span class="hljs-keyword">import</span> amqp, { ChannelWrapper } <span class="hljs-keyword">from</span> <span class="hljs-string">'amqp-connection-manager'</span>;
<span class="hljs-keyword">import</span> { ConfirmChannel } <span class="hljs-keyword">from</span> <span class="hljs-string">'amqplib'</span>;
<span class="hljs-keyword">import</span> { EmailService } <span class="hljs-keyword">from</span> <span class="hljs-string">'src/email/email.service'</span>;

<span class="hljs-meta">@Injectable</span>()
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> ConsumerService <span class="hljs-keyword">implements</span> OnModuleInit {
  <span class="hljs-keyword">private</span> channelWrapper: ChannelWrapper;
  <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> logger = <span class="hljs-keyword">new</span> Logger(ConsumerService.name);
  <span class="hljs-keyword">constructor</span>(<span class="hljs-params"><span class="hljs-keyword">private</span> emailService: EmailService</span>) {
    <span class="hljs-keyword">const</span> connection = amqp.connect([<span class="hljs-string">'amqp://localhost'</span>]);
    <span class="hljs-built_in">this</span>.channelWrapper = connection.createChannel();
  }

  <span class="hljs-keyword">public</span> <span class="hljs-keyword">async</span> onModuleInit() {
    <span class="hljs-keyword">try</span> {
      <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.channelWrapper.addSetup(<span class="hljs-keyword">async</span> (channel: ConfirmChannel) =&gt; {
        <span class="hljs-keyword">await</span> channel.assertQueue(<span class="hljs-string">'emailQueue'</span>, { durable: <span class="hljs-literal">true</span> });
        <span class="hljs-keyword">await</span> channel.consume(<span class="hljs-string">'emailQueue'</span>, <span class="hljs-keyword">async</span> (message) =&gt; {
          <span class="hljs-keyword">if</span> (message) {
            <span class="hljs-keyword">const</span> content = <span class="hljs-built_in">JSON</span>.parse(message.content.toString());
            <span class="hljs-built_in">this</span>.logger.log(<span class="hljs-string">'Received message:'</span>, content);
            <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.emailService.sendEmail(content);
            channel.ack(message);
          }
        });
      });
      <span class="hljs-built_in">this</span>.logger.log(<span class="hljs-string">'Consumer service started and listening for messages.'</span>);
    } <span class="hljs-keyword">catch</span> (err) {
      <span class="hljs-built_in">this</span>.logger.error(<span class="hljs-string">'Error starting the consumer:'</span>, err);
    }
  }
}
</code></pre>
<p>First, you defined your consumer class. For this, it implements the <code>onModuleInit</code> interface which is provided by <code>@nestJs/common</code>. This specifies that the defined class should have a method named <code>onModuleInit()</code>. </p>
<p>Like the name says, the method will be called automatically during the module initialization which is when the module containing this class is loaded. </p>
<p>In the class constructor, you added the <code>emailService</code> because you'll be using the <code>sendEmail</code> method of that class.</p>
<p>In the <code>onModuleInit()</code> method, you defined a channel. This is necessary because you need a channel to consume messages from a queue.</p>
<p>From this, the channel is then used to assert a queue which should be similar in name and options to what you have on your producer service. If it's not, you won't be able to listen to the queue created on the producer service. </p>
<p>Then you used the consume method of channel to listen and execute the message coming from the queue you have registered.</p>
<p>Recall that before, you had to convert the message to Buffer in order to send it into a queue. Now, you have to convert it to a JavaScript object. Then call the emailService method to send an email and pass in the converted JavaScript object as the argument of that method.</p>
<p>Finally, you called the <code>ack</code> method which is used to inform the queue that the message has been received and processed successfully in order for it to be removed from the queue.</p>
<p>Now that you've defined these services, create a module file and set them in the providers array. Then export the producer service because you will be calling it in another module.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { Module } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/common'</span>;
<span class="hljs-keyword">import</span> { ConsumerService } <span class="hljs-keyword">from</span> <span class="hljs-string">'./consumer.file'</span>;
<span class="hljs-keyword">import</span> { ProducerService } <span class="hljs-keyword">from</span> <span class="hljs-string">'./producer.file'</span>;

<span class="hljs-meta">@Module</span>({
  providers: [ProducerService, ConsumerService],
  <span class="hljs-built_in">exports</span>: [ProducerService],
})
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> QueueModule {}
</code></pre>
<p>Next up is to add the emails being sent on user registration to the queue service that you just created. </p>
<p>Navigate back to your user service file and make some modifications: replace the email service with the producer service as a provider in the constructor, and then call the service and the method to add to the email queue as shown below:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { Injectable } <span class="hljs-keyword">from</span> <span class="hljs-string">"@nestjs/common"</span>;
<span class="hljs-keyword">import</span> { InjectRepository } <span class="hljs-keyword">from</span> <span class="hljs-string">"@nestjs/typeorm"</span>;
<span class="hljs-keyword">import</span> { Repository } <span class="hljs-keyword">from</span> <span class="hljs-string">"typeorm"</span>;
<span class="hljs-keyword">import</span> { CreateUserDto } <span class="hljs-keyword">from</span> <span class="hljs-string">"./dto/create-user.dto"</span>;
<span class="hljs-keyword">import</span> { User } <span class="hljs-keyword">from</span> <span class="hljs-string">"./entities/user.entity"</span>;
<span class="hljs-keyword">import</span> { ProducerService } <span class="hljs-keyword">from</span> <span class="hljs-string">"src/queues/producer.file"</span>;

<span class="hljs-meta">@Injectable</span>()
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> UsersService {
  <span class="hljs-keyword">constructor</span>(<span class="hljs-params">
    <span class="hljs-meta">@InjectRepository</span>(User)
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> userRepository: Repository&lt;User&gt;,
    <span class="hljs-keyword">private</span> producerService: ProducerService,
  </span>) {}
  <span class="hljs-keyword">async</span> create(createUserDto: CreateUserDto): <span class="hljs-built_in">Promise</span>&lt;User&gt; {
    <span class="hljs-keyword">const</span> newUser = <span class="hljs-built_in">this</span>.userRepository.create(createUserDto);
    <span class="hljs-keyword">const</span> user = <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.userRepository.save(newUser);
    <span class="hljs-keyword">const</span> emailData = {
      email: user.email,
      subject: <span class="hljs-string">'Welcome to Our Community'</span>,
      html: <span class="hljs-string">`&lt;p&gt;Hello <span class="hljs-subst">${user.username}</span>,&lt;/p&gt;
        &lt;p&gt;Welcome to our community! Your account is now active.&lt;/p&gt;
        &lt;p&gt;Enjoy your time with us!&lt;/p&gt;`</span>,
    };
    <span class="hljs-keyword">await</span> <span class="hljs-built_in">this</span>.producerService.addToEmailQueue(emailData);
    <span class="hljs-keyword">return</span> user;
  }
}
</code></pre>
<p>Also in the user module file, replace the EmailModule with that of the QueueModule to avoid dependency injection errors when you start up your server.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { Module } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/common'</span>;
<span class="hljs-keyword">import</span> { UsersService } <span class="hljs-keyword">from</span> <span class="hljs-string">'./users.service'</span>;
<span class="hljs-keyword">import</span> { UsersController } <span class="hljs-keyword">from</span> <span class="hljs-string">'./users.controller'</span>;
<span class="hljs-keyword">import</span> { TypeOrmModule } <span class="hljs-keyword">from</span> <span class="hljs-string">'@nestjs/typeorm'</span>;
<span class="hljs-keyword">import</span> { User } <span class="hljs-keyword">from</span> <span class="hljs-string">'./entities/user.entity'</span>;
<span class="hljs-keyword">import</span> { QueueModule } <span class="hljs-keyword">from</span> <span class="hljs-string">'src/queues/queue.module'</span>;

<span class="hljs-meta">@Module</span>({
  imports: [TypeOrmModule.forFeature([User]), QueueModule],
  controllers: [UsersController],
  providers: [UsersService],
})
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> UsersModule {}
</code></pre>
<p>Now finally, it's time to test the user registration flow again. So navigate back to Postman and then type in a valid email and username and hit enter. On the terminal of your server running, you will see logs that were set in order to track the way the message got sent and how it was received and executed.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1696982914939/7f28f0e3-22e3-462c-8956-0bd2156d4c10.png" alt="Image" width="800" height="153" loading="lazy">
<em>Logs that help you track the message</em></p>
<p>You can also open up the RabbitMQ dashboard to view queue activity on <a target="_blank" href="http://localhost:15672/">http://localhost:15672</a>, By default the user is "guest", so enter in <code>guest</code> for the username and password.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1702377899227/4158d8b2-2b9b-424e-bd0b-a4203648eb50.png" alt="Image" width="906" height="523" loading="lazy">
<em>RabbitMQ Queues and Streams</em></p>
<p>Here's the link to the <a target="_blank" href="https://github.com/ChuloWay/article-nestjs-queue">GitHub repository</a>. Feel free to check it out whenever you're stuck.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In this article you learned what a message queue is along with some major components of how they work. You also built a mini Nest.js project and implemented an email service in it. Finally, you integrated the queue service into your project, showing how it works in a real-life scenario.</p>
<p>Understanding message queue behaviors and patterns is an essential skill when developing scalable applications. This helps reduce lag and improves the speed and efficiency of your applications. </p>
<p>I hope you enjoyed reading this article. You can follow me on <a target="_blank" href="https://twitter.com/OkoyeVictorr">Twitter</a>.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Bundle a Simple React Application Using esbuild ]]>
                </title>
                <description>
                    <![CDATA[ Bundling is an important phase in the web development process, particularly when dealing with JavaScript frameworks like React. It entails combining all the various JavaScript files and dependencies into a single file for faster browser loading and e... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/bundle-a-basic-react-application-using-esbuild/</link>
                <guid isPermaLink="false">66ba6102bca875d7790d6aa6</guid>
                
                    <category>
                        <![CDATA[ Bundler ]]>
                    </category>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                    <category>
                        <![CDATA[ web performance ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ valentine Gatwiri ]]>
                </dc:creator>
                <pubDate>Tue, 22 Aug 2023 20:56:13 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/08/Screenshot-from-2023-08-21-16-04-04.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Bundling is an important phase in the web development process, particularly when dealing with JavaScript frameworks like React. It entails combining all the various JavaScript files and dependencies into a single file for faster browser loading and execution. </p>
<p>esbuild is a lightweight and efficient bundler for React apps. Here's an overview of how to use esbuild to bundle a basic React application.</p>
<h2 id="heading-how-to-install-esbuild-globally">How to Install esbuild Globally</h2>
<p>We'll start by installing esbuild globally in your system by running <code>npm install -g esbuild</code> in the command line. This will install the latest version of esbuild globally on your system. </p>
<p>After installation, you can access esbuild from the command line by typing <code>esbuild</code>.</p>
<h2 id="heading-how-to-create-a-new-directory-for-your-react-application">How to Create a New Directory for Your React Application</h2>
<p>To create a new directory for your React application, open the terminal and navigate to the directory where you want to create the new directory. Then run the following command:</p>
<pre><code class="lang-bash">mkdir my-react-app
</code></pre>
<p>This will create a new directory named <code>my-react-app</code>. You can replace it with whatever name you want to give your React application directory.</p>
<p>After creating the directory, navigate into it by running:</p>
<pre><code class="lang-bash"><span class="hljs-built_in">cd</span> my-react-app
</code></pre>
<p>Initialize a new <code>npm</code> project by running the following command and following the prompts:</p>
<pre><code class="lang-bash">npm init -y
</code></pre>
<p>Install React and React DOM by running <code>npm install react react-dom</code> in the terminal. This will install the latest versions of React and React DOM in your project, along with any required dependencies.</p>
<h2 id="heading-how-to-create-the-necessary-files-and-folders">How to Create the Necessary Files and Folders</h2>
<p>Let's create the necessary files and folders. Here's a basic structure:</p>
<pre><code>my-react-app
├── src
|   |
│   |── index.js
├── |--- index.html
│  
└── package.json
</code></pre><p>Add the code shown below in your app, following the above structure:</p>
<p><strong>index.html</strong>:</p>
<pre><code class="lang-html"><span class="hljs-meta">&lt;!DOCTYPE <span class="hljs-meta-keyword">html</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">html</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">charset</span>=<span class="hljs-string">"UTF-8"</span> /&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"viewport"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"width=device-width, initial-scale=1, shrink-to-fit=no"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>Hello, esbuild!<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"root"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"Bundle.js"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>

<span class="hljs-tag">&lt;/<span class="hljs-name">html</span></span>
</code></pre>
<p>The above code outlines the fundamental structure of an HTML5 web page. It starts with a declaration indicating the use of HTML5. The main structure consists of an <code>&lt;html&gt;</code> root element containing a <code>&lt;head&gt;</code> section for metadata, including character encoding and viewport settings for responsiveness.</p>
<p> The <code>&lt;title&gt;</code> element defines the browser tab's title, while the actual content resides in the <code>&lt;body&gt;</code> element. Within the <code>&lt;body&gt;</code>, a <code>&lt;div&gt;</code> element with the id "root" serves as a placeholder for potential dynamic content. </p>
<p>Additionally, there's a <code>&lt;script&gt;</code> tag pointing to an external JavaScript file named "Bundle.js," generated by esbuild, to be executed by the browser. </p>
<p>This structure sets the foundation for building a web page with HTML5, CSS, and JavaScript functionality.</p>
<p><strong>index.js</strong></p>
<pre><code class="lang-jsx"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> ReactDOM <span class="hljs-keyword">from</span> <span class="hljs-string">"react-dom"</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>Hello, esbuild! <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}

ReactDOM.render(<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">App</span> /&gt;</span></span>, <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">"root"</span>));
</code></pre>
<p>Our React code sets up a simple React application with a single component App. It renders a <code>&lt;div&gt;</code> element with the text <code>Hello, esbuild!</code> and mounts it into the DOM, specifically into the element with the <code>id</code> of <code>root</code>.</p>
<h2 id="heading-how-to-create-the-build-function">How to Create the Build Function</h2>
<p>Let's add the following build script using the <code>esbuild</code> bundler in our <code>package.json</code> file:</p>
<pre><code class="lang-json"><span class="hljs-string">"scripts"</span>: {
        <span class="hljs-attr">"build"</span>: <span class="hljs-string">"esbuild src/index.js --bundle --outfile=Bundle.js --loader:.js=jsx --format=cjs"</span>
},
</code></pre>
<p>This build script starts with the entry point <code>src/index.js</code> and proceeds to bundle all the dependencies. The resulting bundled code is saved as <code>Bundle.js</code>. </p>
<p>The script also specifies that files with the <code>.js</code> extension should be treated as <code>jsx</code> files, indicating the usage of JSX syntax.</p>
<p>Finally, the output format is set to <code>CommonJS (cjs)</code> which is the module system utilized by Node.js. </p>
<p>By executing this build script, the <code>esbuild</code> bundler will process the files, apply the necessary transformations, and generate a single bundled JavaScript file ready for deployment or further usage.</p>
<h3 id="heading-overview-of-the-build-function-and-its-purpose">Overview of the Build Function and its Purpose</h3>
<p>The build script using esbuild is JavaScript code that bundles your JavaScript code into a single file. This is useful for optimizing your code for production environments, reducing the number of HTTP requests needed to load your application, and improving load times.</p>
<p>The build method takes an <code>options</code> object as its argument, which allows you to configure how your code is bundled. The options object specifies properties such as <code>entryPoints</code>, <code>outfile</code>, <code>format</code>, <code>bundle</code>, and <code>loader</code>.</p>
<p>Once the build method is configured with the desired options, the build function is called, which triggers the build process. This will output a single bundled file containing all of your JavaScript code.</p>
<p>Finally, the build script is run by executing the script using Node.js. You can do this by updating the <code>package.json</code> file to include a script that runs the build script, as shown above.</p>
<p>Build the React app using the following command:</p>
<pre><code class="lang-bash">npm run build
</code></pre>
<p>Then run the app using this command:</p>
<pre><code class="lang-bash">npx http-server
</code></pre>
<h2 id="heading-conclusion">Conclusion</h2>
<p>By following these steps, you can bundle your basic React application using esbuild and have it ready for deployment or further usage. Here is the <a target="_blank" href="https://github.com/gatwirival/esbuild-bundling-demo.git">demo.</a></p>
<p>Happy coding!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Avoid the N+1 Query Problem in GraphQL and REST APIs [with Benchmarks] ]]>
                </title>
                <description>
                    <![CDATA[ By Mohamed Mayallo The N+1 query problem is a performance issue you might face while building APIs, regardless of whether they're GraphQL or REST APIs. In fact, this problem occurs when your application needs to return a set of data that includes rel... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/n-plus-one-query-problem/</link>
                <guid isPermaLink="false">66d46013a326133d12440a21</guid>
                
                    <category>
                        <![CDATA[ api ]]>
                    </category>
                
                    <category>
                        <![CDATA[ GraphQL ]]>
                    </category>
                
                    <category>
                        <![CDATA[ performance ]]>
                    </category>
                
                    <category>
                        <![CDATA[ REST API ]]>
                    </category>
                
                    <category>
                        <![CDATA[ web performance ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Fri, 07 Jul 2023 17:59:59 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/07/N-1-Query-Problem.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Mohamed Mayallo</p>
<p>The N+1 query problem is a performance issue you might face while building APIs, regardless of whether they're GraphQL or REST APIs.</p>
<p>In fact, this problem occurs when your application needs to return a set of data that includes related nested data – for example, a post that includes comments.</p>
<p>But how can you fix this problem? To avoid this issue, you should understand what is it and how it occurs.</p>
<p>So in this tutorial, you'll learn what the N+1 query problem is, why it is easy to fall into it, and how you can avoid it.</p>
<p>Before starting, it is good to know:</p>
<ul>
<li>The examples in this article are just for the sake of simplicity.</li>
<li><code>SELECT *</code> is very bad, and you should avoid it.</li>
<li>You should care about pagination if you’re working with large data sets.</li>
</ul>
<p>You can find the examples in this article in this <a target="_blank" href="https://github.com/Mohamed-Mayallo/n_plus_one_problem_benchmarks">repo</a>. Let's dive in.</p>
<h2 id="heading-understanding-the-n1-query-problem">Understanding the N+1 Query Problem</h2>
<p>The N+1 problem occurs when your application needs to return a set of data that includes related data that exists in:</p>
<ul>
<li>Another table.</li>
<li>Another database (in the case of microservices, for example)</li>
<li>Or even another third-party service.</li>
</ul>
<p>In other words, you need to execute extra database queries or external requests to return the nested data.</p>
<p>If you are wondering about what the name means (N+1), follow the below example, which uses a single database:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/07/related-data.drawio.png" alt="Post and Comment tables | By Author" width="600" height="400" loading="lazy">
<em>Illustration of N+1 problem</em></p>
<p>As you can see, the relationship between <code>Post</code> and <code>Comment</code> is one-to-many, respectively.</p>
<p>So, if your application needs to return a list of posts and their related comments, you might end up with this code:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> posts = <span class="hljs-keyword">await</span> rawSql(<span class="hljs-string">'SELECT * FROM "Post"'</span>); <span class="hljs-comment">// Get all posts (1 database query)</span>
<span class="hljs-keyword">for</span> (<span class="hljs-keyword">const</span> post <span class="hljs-keyword">in</span> posts) {
    <span class="hljs-comment">// For sure, you can replace the following query with an external request if you need to retrieve the post's comments from another service</span>
    <span class="hljs-keyword">const</span> comments = <span class="hljs-keyword">await</span> rawSql(<span class="hljs-string">`SELECT * FROM "Comment" WHERE "post_id" = <span class="hljs-subst">${post.id}</span>`</span>); <span class="hljs-comment">// Get all comments for every post (n database query for n posts)</span>
    post.comments = comments;
}
</code></pre>
<p>So, you have executed <strong>N</strong> queries to retrieve every post’s comments and <strong>1</strong> query to retrieve all posts <strong>(N comments queries + 1 posts query).</strong></p>
<p>But, why you should be aware of this problem?</p>
<h2 id="heading-why-is-the-n1-query-problem-a-serious-issue">Why Is the N+1 Query Problem a Serious Issue?</h2>
<p>Here are some reasons why the N+1 query problem can cause serious performance issues in your application:</p>
<ol>
<li>Your application makes a lot of database queries or external requests to retrieve a list of data like posts.</li>
<li>The more data your application retrieves, the slower your request is going to be and the more resources your application is going to consume.</li>
<li>A large data set might end up with notable network latency.</li>
<li>It is going to be challenging to scale the application to handle larger data sets.</li>
</ol>
<p>On top of that, you are going to see the performance impact in numbers in the benchmarks section later in this article.</p>
<p>Now that you understand the N+1 query problem and its impact on your application, let’s introduce some effective ways you can avoid this problem.</p>
<h2 id="heading-strategies-to-avoid-the-n1-query-problem">Strategies to Avoid the N+1 Query Problem</h2>
<p>Fortunately, there are a few simple strategies you can follow to avoid the N+1 query problem.</p>
<p>Let’s apply them to our previous example.</p>
<h3 id="heading-1-eager-loading-using-sql-joins-for-example">1) Eager Loading (Using SQL Joins, for example)</h3>
<p>In this strategy, instead of returning the post’s comments separately for every post, you can use <strong>SQL Joins</strong>.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> postsAndComments = <span class="hljs-keyword">await</span> rawSql(<span class="hljs-string">`
    SELECT * 
    FROM "Post"
    JOIN "Comment"
    ON "Comment"."post_id" = "Post"."post_id"
`</span>);
</code></pre>
<p>When you're using this strategy, it's good to know that:</p>
<ul>
<li>It is only one database query to return all posts and their nested comments.</li>
<li>You can't apply this strategy if you are consuming your data sets from a different database or service.</li>
</ul>
<h3 id="heading-2-batch-loading">2) Batch Loading</h3>
<p>In this strategy, your code should follow the below steps:</p>
<ul>
<li>Execute one request to retrieve all posts.</li>
<li>Execute another request to load a batch of posts’ comments instead of loading every post’s comments separately.</li>
<li>Map every comment to its corresponding parent post.</li>
</ul>
<p>Let’s jump into an example:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> posts = <span class="hljs-keyword">await</span> rawSql(<span class="hljs-string">'SELECT * FROM "Post"'</span>), <span class="hljs-comment">// 1- Retrieve all posts in one request</span>
    postsIds = posts.map(<span class="hljs-function"><span class="hljs-params">post</span> =&gt;</span> post.id),
    postsComments = <span class="hljs-keyword">await</span> rawSql(<span class="hljs-string">`SELECT * FROM "Comment" WHERE "post_id" IN (<span class="hljs-subst">${postsIds}</span>)`</span>); <span class="hljs-comment">// 2- retrieve all posts’ comments in another request</span>

<span class="hljs-keyword">for</span> (<span class="hljs-keyword">const</span> post <span class="hljs-keyword">in</span> posts) { <span class="hljs-comment">// 3- Map every comment to its parent post</span>
    <span class="hljs-keyword">const</span> comments = postsComments.filter(<span class="hljs-function"><span class="hljs-params">comment</span> =&gt;</span> comment.post_id === post.id);
    post.comments = comments;
}
</code></pre>
<p>As you see, in this strategy, there are just two requests: one to retrieve all posts and another one to retrieve their comments.</p>
<h3 id="heading-3-caching">3) Caching</h3>
<p>You may be familiar with caching and its impact on any application's performance.</p>
<p>You can implement caching on your client side or server side using <a target="_blank" href="https://redis.io/">Redis</a>, <a target="_blank" href="https://memcached.org/">Memcached</a>, or any other similar tool. Wherever you can properly use caching, it significantly pushes your application's performance.</p>
<p>Let’s get back to our example and cache the posts’ comments in a Redis store.</p>
<pre><code class="lang-js">    <span class="hljs-keyword">const</span> posts = <span class="hljs-keyword">await</span> rawSql(<span class="hljs-string">'SELECT * FROM "Post"'</span>),
        postsIds = posts.map(<span class="hljs-function"><span class="hljs-params">post</span> =&gt;</span> post.id),
        cachedPostsComments = getPostsCommentsFromRedis(postsIds);

<span class="hljs-keyword">for</span> (<span class="hljs-keyword">const</span> post <span class="hljs-keyword">in</span> posts) {
    <span class="hljs-keyword">const</span> comments = cachedPostsComments.filter(<span class="hljs-function"><span class="hljs-params">comment</span> =&gt;</span> comment.post_id === post.id);
    post.comments = comments;
}
</code></pre>
<p>As you might guess, you can cache the posts’ comments or even the posts themselves which significantly minimizes the load on databases.</p>
<h3 id="heading-4-lazy-loading">4) Lazy Loading</h3>
<p>In this strategy, you are distributing the responsibility between the server side and the client side.</p>
<p>You shouldn’t return all data at once from the server side. Instead, you prepare two endpoints for the client side like this:</p>
<ul>
<li><code>GET /api/posts</code>: Retrieves all posts.</li>
<li><code>GET /api/comments/:postId</code>: Retrieves a post’s comments on demand.</li>
</ul>
<p>And now, the data retrieval is up to the client side.</p>
<p>This strategy is very useful because:</p>
<ul>
<li>It enables the client side to load the parent post first and display its content, and then load its related comments lazily. So users don't have to wait for the entire data set to be returned from the server side.</li>
<li>You have full control over sorting, filtering, pagination and so on over every endpoint.</li>
</ul>
<p>The key point of this strategy is that it gets rid of nested data like comments and flattens all data sets in their own endpoint.</p>
<h3 id="heading-5-graphql-dataloader">5) GraphQL Dataloader</h3>
<p>As you might guess, this strategy works with GraphQL APIs.</p>
<p>Dataloader is a GraphQL utility that works by batching multiple database queries into one request. So, it uses the Batch Loading strategy under the hood.</p>
<p>Let’s jump into our example:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> DataLoader = <span class="hljs-built_in">require</span>(<span class="hljs-string">'dataloader'</span>);

<span class="hljs-comment">// 1- GraphQL Schema Definition</span>
<span class="hljs-keyword">const</span> typeDefs = gql<span class="hljs-string">`
  type Post {
    post_id: ID!
        comments: [Comment]
  }

    type Comment {
        comment_id: ID!
    post_id: ID!
  }

  type Query {
    posts: [Post]
  }
`</span>;

<span class="hljs-comment">// 2- Resolve the GraphQL Schema</span>
<span class="hljs-keyword">const</span> resolvers = {
  <span class="hljs-attr">Query</span>: {
    <span class="hljs-attr">posts</span>: <span class="hljs-keyword">async</span> () =&gt; {
      <span class="hljs-keyword">const</span> posts = <span class="hljs-keyword">await</span> rawSql(<span class="hljs-string">'SELECT * FROM "Post"'</span>);
            <span class="hljs-keyword">return</span> posts;
    }
  },

  <span class="hljs-attr">Post</span>: {
    <span class="hljs-attr">comments</span>: <span class="hljs-function">(<span class="hljs-params">post, args, { dataLoaders }</span>) =&gt;</span> {
      <span class="hljs-keyword">return</span> dataLoaders.commentsLoader.load(post.id);
    }
  }
};

<span class="hljs-comment">// 3- Define Dataloaders</span>
<span class="hljs-keyword">const</span> commentsBatchFunction = <span class="hljs-keyword">async</span> postsIds =&gt; {
      <span class="hljs-keyword">const</span> comments = <span class="hljs-keyword">await</span> rawSql(<span class="hljs-string">`SELECT * FROM "Comment" WHERE "post_id" IN (<span class="hljs-subst">${postsIds}</span>)`</span>);
        <span class="hljs-keyword">const</span> groupedComments = comments.reduce(<span class="hljs-function">(<span class="hljs-params">tot, cur</span>) =&gt;</span> {
      <span class="hljs-keyword">if</span> (!tot[cur.post_id]) {
        tot[cur.post_id] = [cur];
      } <span class="hljs-keyword">else</span> {
        tot[cur.post_id].push(cur);
      }
      <span class="hljs-keyword">return</span> tot;
    }, {});
        <span class="hljs-keyword">return</span> postsIds.map(<span class="hljs-function">(<span class="hljs-params">postId</span>) =&gt;</span> groupedComments[postId]);
    },
    createCommentsLoader = <span class="hljs-keyword">new</span> DataLoader(commentsBatchFunction),
    createDataloaders = <span class="hljs-function">() =&gt;</span> ({
        <span class="hljs-attr">commentsLoader</span>: createCommentsLoader()
    });

<span class="hljs-comment">// 4- Inject Dataloaders in the GraphQL Context</span>
<span class="hljs-keyword">const</span> server = <span class="hljs-keyword">new</span> ApolloServer({
    typeDefs,
    resolvers,
    <span class="hljs-attr">context</span>: <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">return</span> {
      <span class="hljs-attr">dataLoaders</span>: createDataloaders(),
    }
  }
});
</code></pre>
<p>So how does it work? To get more detailed information, you can check out the <a target="_blank" href="https://github.com/graphql/dataloader">documentation</a>. But we'll go through the basics here.</p>
<p>The key point of the Dataloader is the <a target="_blank" href="https://github.com/graphql/dataloader#batch-function">Batch Function</a>. Here, the batch function <code>commentsBatchFunction</code> takes an array of keys <code>postsIds</code> and returns a <a target="_blank" href="https://mayallo.com/asynchronous-javascript/">Promise which resolves</a> to an array of values <code>comments</code>, <code>[ [post1comment1, post1comment2], [post2comment1], ... ]</code>.</p>
<p>On top of that, the batch function has two constraints:</p>
<ul>
<li>The size of the keys array <code>postsIds</code> must equal the values array <code>comments</code>. In other words, this expression must be true: <code>postsIds.length === comments.length</code>.</li>
<li>Each index in the keys array <code>postsIds</code> must correspond to the values array <code>comments</code>. So you might note that I looped over the <code>postsIds</code> to map each corresponding comment.</li>
</ul>
<p>As a result, you can see that GraphQL Dataloader uses the second strategy (Batch Loading) under the hood.</p>
<p>Let’s get back to our example to walk through its implementation:</p>
<ol>
<li>First, we defined the GraphQL schema.</li>
<li>Then we resolved the GraphQL schema. Keep in mind, if you resolved the comments in the <code>Post</code> type using this query <code>await rawSql('SELECT * FROM "Comment" WHERE "post_id" = ' + post.id);</code>, you’re going to fall into the N+1 query problem.</li>
<li>Next, we defined the comments batch function and then created the comments dataloader.</li>
<li>Finally, we injected dataloaders in the <a target="_blank" href="https://www.apollographql.com/docs/apollo-server/data/context/">GraphQL Context</a> to be able to use them in resolvers.</li>
</ol>
<p>So, by using GraphQL Dataloader, if you have 10 posts and every post has 5 comments, you would end up with two queries – one to retrieve the 10 posts and another one to retrieve their comments.</p>
<p>Take a look at the following screenshot:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/07/Code_1K9XMH0CHB.png" alt="Database queries with GraphQL Dataloader and without it" width="600" height="400" loading="lazy">
<em>Illustration of process with and without Dataloader</em></p>
<h2 id="heading-benchmarks-about-n1-query-problem">Benchmarks About N+1 Query Problem</h2>
<p>In this section, let’s compare each strategy in terms of performance.</p>
<table>
<thead>
<tr>
<th>N+1 in REST API</th>
<th>Eager Loading Strategy</th>
<th>Batch Loading Strategy</th>
<th>Caching Strategy</th>
<th>N+1 in GraphQL API</th>
<th>GraphQL Dataloader</th>
</tr>
</thead>
<tbody>
<tr>
<td>2.139</td>
<td>0.065</td>
<td>0.048</td>
<td>0.019</td>
<td>2.44</td>
<td>0.397</td>
</tr>
<tr>
<td>2.147</td>
<td>0.081</td>
<td>0.068</td>
<td>0.024</td>
<td>2.38</td>
<td>0.483</td>
</tr>
<tr>
<td>2.152</td>
<td>0.062</td>
<td>0.065</td>
<td>0.035</td>
<td>2.67</td>
<td>0.372</td>
</tr>
<tr>
<td>2.17</td>
<td>0.053</td>
<td>0.047</td>
<td>0.031</td>
<td>2.71</td>
<td>0.377</td>
</tr>
<tr>
<td>2.181</td>
<td>0.052</td>
<td>0.069</td>
<td>0.031</td>
<td>2.38</td>
<td>0.364</td>
</tr>
<tr>
<td>2.14</td>
<td>0.076</td>
<td>0.043</td>
<td>0.017</td>
<td>2.53</td>
<td>0.346</td>
</tr>
<tr>
<td>2.321</td>
<td>0.073</td>
<td>0.045</td>
<td>0.018</td>
<td>2.60</td>
<td>0.451</td>
</tr>
<tr>
<td>2.13</td>
<td>0.061</td>
<td>0.06</td>
<td>0.015</td>
<td>2.35</td>
<td>0.369</td>
</tr>
<tr>
<td>2.149</td>
<td>0.064</td>
<td>0.04</td>
<td>0.015</td>
<td>2.65</td>
<td>0.368</td>
</tr>
<tr>
<td>2.361</td>
<td>0.065</td>
<td>0.045</td>
<td>0.016</td>
<td>2.54</td>
<td>0.424</td>
</tr>
<tr>
<td>2.190</td>
<td>0.065</td>
<td>0.053</td>
<td>0.022</td>
<td>2.525</td>
<td>0.395</td>
</tr>
</tbody>
</table>

<p><em>Note that the results of the Cache strategy are coming just after caching the data set. The first query is ignored as caching is missed.</em></p>
<p>These results were generated from the following environment:</p>
<ul>
<li>Seeded data: 1000 posts and 50 comments for every post.</li>
<li>CPU: AMD Ryzen 5 3600 6-Core Processor 3.60 GHz.</li>
<li>RAM: 32.0 GB.</li>
<li>OS: Windows 10 Pro.</li>
</ul>
<p>To be able to retest these strategies in your environment, follow these steps:</p>
<ul>
<li>Clone this <a target="_blank" href="https://github.com/Mohamed-Mayallo/n_plus_one_problem_benchmarks">repo</a>.</li>
<li>Then run <code>docker-compose up</code>.</li>
<li>For GraphQL, open <code>http://localhost:3000/graphql</code>.</li>
<li><strong>A query suffers from the N+1 problem:</strong> query only <strong><code>commentsWithNPlusOne</code></strong> in the <code>Post</code> type<strong>.</strong></li>
<li><strong>Dataloader strategy</strong>: query only <code>commentsWithDataloader</code> in the <code>Post</code> type.</li>
<li>For REST, follow these endpoints:</li>
<li><strong>A query suffers from the N+1 problem</strong>: <code>http://localhost:3000/api/postsWithNPlusOne</code>.</li>
<li><strong>Eager Loading strategy</strong>: <code>http://localhost:3000/api/postsWithEagerLoading</code>.</li>
<li><strong>Batch Loading strategy</strong>: <code>http://localhost:3000/api/postsWithBatchLoading</code>.</li>
<li><strong>Caching strategy</strong>: <code>http://localhost:3000/api/postsWithCache</code>.</li>
</ul>
<p>My notes about these benchmarks:</p>
<ul>
<li>These strategies are way too efficient.</li>
<li>You may notice that the slower strategy in REST, the Eager Loading strategy, is <strong>about 34 times faster</strong> than the N+1 query in the REST API.</li>
<li>The Dataloader strategy is <strong>about 6.4 times faster</strong> than the N+1 query in the GraphQL API.</li>
<li>If you compared the results of REST and GraphQL APIs, you may notice that REST is faster than GraphQL. I think this is because of the internal implementations of GraphQL, which makes sense.</li>
</ul>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In this article, you learned that the N+1 query problem is a performance issue you might encounter when working with APIs.</p>
<p>You then learned about some strategies you can follow to avoid this problem like:</p>
<ul>
<li>Eager Loading using SQL Joins</li>
<li>Batch Loading by executing fewer requests and then mapping each corresponding item to its parent.</li>
<li>Caching using Redis</li>
<li>Dataloader in the GraphQL world.</li>
</ul>
<p>Finally, we created some benchmarks about the N+1 query problem so we could see how efficiently these strategies improve our API performance.</p>
<h2 id="heading-before-you-leave">Before you leave</h2>
<p>If you found this article useful, you can <a target="_blank" href="https://mayallo.com/blog/">check out some of my other articles on my personal blog as well</a>.</p>
<p>Thanks a lot for staying with me up till this point. I hope you enjoy reading this article.</p>
 ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
