<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: József Miskolczy</title>
    <description>The latest articles on DEV Community by József Miskolczy (@fullctxdev).</description>
    <link>https://dev.to/fullctxdev</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F840526%2F74205f97-68c7-4d7f-bcc9-b6a21d928140.png</url>
      <title>DEV Community: József Miskolczy</title>
      <link>https://dev.to/fullctxdev</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/fullctxdev"/>
    <language>en</language>
    <item>
      <title>Master Lazy Loading in React and Next.js Apps</title>
      <dc:creator>József Miskolczy</dc:creator>
      <pubDate>Mon, 17 Jul 2023 20:15:30 +0000</pubDate>
      <link>https://dev.to/fullctxdev/master-lazy-loading-in-react-and-nextjs-apps-4ne6</link>
      <guid>https://dev.to/fullctxdev/master-lazy-loading-in-react-and-nextjs-apps-4ne6</guid>
      <description>&lt;h2&gt;
  
  
  Hey Frontend Ninjas,
&lt;/h2&gt;

&lt;p&gt;I'm going to teach you one of the secret, ultimate techniques of performance grandmasters used to divide and conquer (&lt;em&gt;pun definitely intended&lt;/em&gt;) slow loading websites since the dawn of the web era.&lt;/p&gt;

&lt;p&gt;But before we start training, I have to warn you: lazy loading isn't for the faint of heart! It's an incredibly powerful technique for improving network performance and enhancing the user experience but it can also mess up your React application’s loading behavior if not done right. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;That’s exactly why I will teach you what lazy loading is, what are its effects, its typical use cases, how to identify where it’s best applied, where it’s best avoided and of course how to implement it perfectly with plain React and the tools coming with Next.js.&lt;/strong&gt; Let’s jump right into it!&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;This article was originally posted on my Substack: &lt;a href="https://www.fullctx.dev"&gt;fullctx.dev&lt;/a&gt; This is the first of a series, follow there if you want a complete guide to everything React and Next.js performance.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Lazy Loading: What is it And How it Works
&lt;/h2&gt;

&lt;p&gt;Lazy loading is a technique that allows you to defer the loading of resources, such as images, scripts or React components until they're actually needed. This concept is based on the idea of "just-in-time" delivery of content: instead of loading all resources upfront, you only load what's necessary for the moment, and fetch additional resources as required for user interactions. The result is a faster loading time and more efficient use of network resources. An ideal outcome! 🚀 &lt;/p&gt;

&lt;p&gt;Combined with code splitting, this will become one of the most frequently used tools in your performance tuning toolbox! No wonder, it helps to temporarily increase how much your application resembles the ideal website. (Details are coming in Chapter 3: Learnings From The Fastest Website of The Universe)&lt;/p&gt;

&lt;h2&gt;
  
  
  The DPS of Lazy Loading
&lt;/h2&gt;

&lt;p&gt;So that’s lazy loading in a nutshell, but why is it so useful? Let’s take a look at some real-life results:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;By implementing lazy loading &lt;a href="https://github.com/jamiebuilds/react-loadable/pull/181"&gt;ClearTax improved their initial load time&lt;/a&gt; ~50%.&lt;/li&gt;
&lt;li&gt;Quran.com &lt;a href="https://github.com/quran/quran.com-frontend/pull/701#issuecomment-287908551"&gt;shaved off 50kb from their entry chunk&lt;/a&gt; by lazy loading non-critical components.&lt;/li&gt;
&lt;li&gt;Max Rozen &lt;a href="https://maxrozen.com/react-loadable-half-react-app-load-time#halving-my-react-apps-load-time"&gt;halved the TTI&lt;/a&gt; on one of his previous projects by moving 200kb of code from the main bundle to a lazy loaded chunk.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Those are some massive gains! As we discussed in the introduction chapter, these could translate to serious financial gains on the right projects. The potential is tremendous so let’s get to the implementation details!&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementing Lazy Loading in React
&lt;/h2&gt;

&lt;p&gt;Ever since v.16.6, React has a built-in solution to execute this attack. A bit later I will also show you the legacy solutions and why some of them might still be relevant today. With this simple approach implementing lazy loading is not difficult at all.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;You can lazy load components using&lt;/strong&gt; &lt;code&gt;React.lazy()&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This function takes another function as its argument, which should return a dynamic import() statement for the module you wish to lazy load. Here’s a minimal example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;lazy&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Suspense&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;SneakAttack&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;lazy&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./DelayedComponent&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; 

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;LightningFastApp&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Suspense&lt;/span&gt; &lt;span class="na"&gt;fallback&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Camouflage...&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;SneakAttack&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Suspense&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;LightningFastApp&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let’s break down what’s happening here.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;We are importing the basic moves from ‘react‘ to build up the combo.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;We define the custom component (&lt;code&gt;DelayedComponent&lt;/code&gt;) we want to load in the background, escaping the line of sight of the users. (&lt;em&gt;Well, not exactly in this example, but in real life situations&lt;/em&gt;)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;We create a simple but lightning fast top-level component to house the &lt;code&gt;SneakAttack&lt;/code&gt; we are about to deliver.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;We wrap the &lt;code&gt;SneakAttack&lt;/code&gt; in camouflage while we are preparing the ambush. Meaning, we simply provide fallback content to be displayed while the loading part of lazy loading is in progress.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;We tell React to deliver our &lt;code&gt;SneakAttack&lt;/code&gt; by rendering it as a component. That will initiate the fetching of the &lt;code&gt;DelayedComponent&lt;/code&gt; and replace the fallback with it once arrived over the network or from cache.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You might have noticed that this example really doesn’t make much sense. All it does is delaying the rendering of &lt;code&gt;DelayedComponent&lt;/code&gt; by one render cycle (+ loading time). So this way it likely just worsens performance. You can &lt;a href="https://react.dev/reference/react/lazy#usage"&gt;check out a more meaningful implementation&lt;/a&gt; in the official docs where the loading only happens after a user actually tries to access a feature. However, even this version is good enough to discuss some important tips!&lt;/p&gt;

&lt;h2&gt;
  
  
  💡 Pro Tips (lots of them…)
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Always Use Suspense&lt;/strong&gt;: &lt;code&gt;Suspense&lt;/code&gt; works &lt;code&gt;with React.lazy&lt;/code&gt; by default, offering you an easy way to provide some content to the users while the resource requested is in transition. Choosing the right placeholder is an art in and of itself, I will share some tips about it down below.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pitfall With The Target of Importing&lt;/strong&gt;: &lt;code&gt;React.lazy&lt;/code&gt; - out of the box - only works with the default export of a module. If you want to lazy load a component exported by name, there’s a workaround: re export it from another file as the default export. (&lt;a href="https://legacy.reactjs.org/docs/code-splitting.html#named-exports"&gt;Read the old docs for an example&lt;/a&gt;). Alternatively you can use this approach:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;LazyNamedComponent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;lazy&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./Named.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;module&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;default&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Named&lt;/span&gt; &lt;span class="p"&gt;}))&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or with a bit more up to date syntax:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;LazyNamedComponent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;lazy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
   &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./Named.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nx"&gt;Named&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Pitfall With The Place of Importing&lt;/strong&gt;: Make sure to import the lazy loaded component outside of any component’s code at the top level of the current module (file). If you move it inside one, a rerender can re-run the import and you will lose the current state of the already mounted lazy-loaded component whenever that happens.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Pitfall With Mixing Import Types&lt;/strong&gt;: If you happen to load a component with the regular (&lt;em&gt;non-dynamic&lt;/em&gt;) import syntax as well as dynamically, the latter will be disregarded and the code will be packed into the main bundle. Keep this in mind to avoid unpleasant surprises on the network tab! 🙈&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Pitfall With Import Path&lt;/strong&gt;: You can not use variables or string templates in the import path. It has to be a direct import with a simple string. You will read about a possible workaround just a bit further down in this list in &lt;em&gt;SSR before React 18&lt;/em&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Pitfall With Tree Shaking&lt;/strong&gt;: As dynamic imports can’t be analyzed at build time, to help bundlers with tree-shaking unused code we need to follow the official workaround and reexport our named components as a default export from a standalone module. This way bundlers can weed them out when necessary.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Pitfall With Deep Linking&lt;/strong&gt;: (&lt;em&gt;Specifically links with an id at the end eg: &lt;a href="http://www.fast.site/#speed"&gt;www.fast.site/#speed&lt;/a&gt;.&lt;/em&gt;) I can tell you from first hand experience, if you want to have deep links and lazy loading at the same time… you don’t get to eat your cake and have it too. At least the browsers are not going to scroll to your content market with the id in the URL as it’s initially not in the &lt;code&gt;DOM&lt;/code&gt; and they don’t care that it appears later. There’s a workaround though! If you want to emulate that behavior just check the URL with JavaScript once the component is loaded and trigger the scroll programmatically when it matches.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Timing Concerns&lt;/strong&gt;: Just as much as lazy loading can improve the user experience by enabling a faster initial load it can also destroy it if you don’t time the starting right. Ensure that loading is triggered as soon as necessary to minimize or completely eliminate the visible loading of the lazily loaded content. I mean, who likes those web shops with infinite loading product lists. slowly crawling for the next batch whenever you hit the bottom of the screen? I don’t for sure.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Avoid Layout Shifts&lt;/strong&gt;: &lt;code&gt;CLS&lt;/code&gt; is a metric in Web Vitals, meaning besides impacting user experience it also impacts search engine ranking so it’s crucial to minimize it. When there’s something on the initial view of a page (not just above the fold!) that you are lazy loading, you face the challenge of having to properly size the placeholder content so that it matches the size of what will be displayed later. It’s necessary to avoid janky shifting of the layout (&lt;a href="https://web.dev/lazy-loading-best-practices/#wrong-layout-shifting"&gt;more on this at web.dev&lt;/a&gt;) leading to a higher &lt;code&gt;CLS&lt;/code&gt; value.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Use Skeletons Instead of Spinners&lt;/strong&gt;: The current best practice is to use low resolution / low detail mock content as placeholders. The next minor challenge with this approach for the performance maximalists is finding the right balance between detail and payload.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Avoiding Fallbacks With The startTransition API&lt;/strong&gt;: Sometimes it makes sense to prevent displaying fallback content while the lazy loading is in progress. A good example is a tab switcher with lazy loaded tabs. It’s a better user experience to see the old tab and have it interactive until the new one is ready than watching a flash of the fallback placeholder whenever the user clicks on another tab. Check the official method &lt;a href="https://legacy.reactjs.org/docs/code-splitting.html#avoiding-fallbacks"&gt;documented in the old React docs&lt;/a&gt; (&lt;em&gt;nope, I couldn’t find it in the new&lt;/em&gt;) how to pull it off with the help of &lt;code&gt;startTransition&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;SSR and React 18&lt;/strong&gt;: &lt;code&gt;React.lazy&lt;/code&gt; and SSR are not used to play nicely together before v18. But that’s now in the past. You can read more about the details in one of &lt;a href="https://github.com/reactwg/react-18/discussions/37"&gt;React’s GitHub discussions on architecture&lt;/a&gt;. In a nutshell lazy now enables you to segment the UI into separately renderable parts so you can stream some high priority content sooner. This naturally means first class support for lazy loaded components on the server.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;SSR Before React 18&lt;/strong&gt;: In the age of old (o_r current projects pre-upgrade_) we used to use either Loadable Component’s SSR support (&lt;a href="https://loadable-components.com/docs/server-side-rendering/"&gt;intro here&lt;/a&gt;) or React Loadable’s (&lt;a href="https://github.com/jamiebuilds/react-loadable#------------server-side-rendering"&gt;read more here&lt;/a&gt;). It’s worth noting that React Loadable is not in active development anymore but some projects still use it just all right (&lt;a href="https://stackoverflow.com/a/54413946"&gt;even with the officially incompatible Bable &amp;amp; Webpack versions&lt;/a&gt;) . Loadable Components is the de-facto successor and &lt;a href="https://loadable-components.com/docs/loadable-vs-react-lazy/"&gt;it has other merits&lt;/a&gt; (&lt;em&gt;docs a bit outdated about SSR&lt;/em&gt;) that might warrant adopting it even with React 18 including the option for truly dynamic importing as you can use variables or string templates to define the import path with it.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Route Based Lazy Loading&lt;/strong&gt;: With &lt;code&gt;React.lazy&lt;/code&gt; you can lazy load anything not just routes. However you might actually want to lazy load routes in a plain React app. React Router supports that use case out of the box with the &lt;code&gt;lazy&lt;/code&gt; prop and dynamic imports. &lt;a href="https://reactrouter.com/en/main/route/lazy"&gt;Read the details here&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Lazy Loading Is The Second Step in a Combo Move: It Starts With Code Splitting
&lt;/h2&gt;

&lt;p&gt;We jumped straight to the finishing move but it’s true, in order to execute the lazy loading attack you first need to prepare something that you will load lazily.&lt;/p&gt;

&lt;p&gt;How can we do that? That’s where code splitting joins the battle! In the world of native ES module support in-browser you could simply write and host a module yourself… but come on, that’s so 1990s. Today, virtually everyone works with a bundler like Webpack, Vite or Turbopack. Those tools will take care of splitting your modules according to what you want to lazy load. Webpack for example uses &lt;a href="https://webpack.js.org/guides/code-splitting/#dynamic-imports"&gt;the presence of a dynamic import&lt;/a&gt; as the indicator to where to split the application to multiple files. In the end it will output pieces of JS code called “&lt;em&gt;chunks&lt;/em&gt;“ that your app will be able to download and use separately.&lt;/p&gt;

&lt;h2&gt;
  
  
  💡 Pro Tips
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Keep an Eye on The Size&lt;/strong&gt;: Next.js will automatically display the size of all the output chunks at build time which makes it easy to manually check how we are doing. For monitoring and enforcing performance budgets on assets sizes you can &lt;a href="https://medium.com/@mtorre4580/performance-budget-for-next-js-e34eb4fda11e"&gt;read a comprehensive guide here&lt;/a&gt;. (&lt;em&gt;Later on I will also cover this topic in detail.&lt;/em&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Without Next&lt;/strong&gt;: Vite can do that same reporting for you by default. In Webpack land there are tons of useful plugins for this same purpose. Although a bit old, this is still &lt;a href="https://medium.com/naukri-engineering/monitor-analyze-asset-sizes-with-every-build-9c814f6ca8b4"&gt;a very cool article&lt;/a&gt; describing how to set them up for some serious performance wizardry.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What to Lazy Load and When?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--H_y2zvnf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/eyfp0og6ffuekjnk0rc9.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--H_y2zvnf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/eyfp0og6ffuekjnk0rc9.jpg" alt="A generic shoe image appearing in the classic Pokemon Gambeboy game's UI in place of the enemy pokemon with the subtitle: A wild product image appeard on the next panel the same product image appears in 3 steps with gradually increasing resolution and quality. The game UI displays the enemy health dropped to zero. Its captions says: Dev used lazy loading - it's supper effective." width="800" height="380"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Product photo by &lt;a href="https://unsplash.com/@ikredenets?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;Irene Kredenets&lt;/a&gt; on &lt;a href="https://unsplash.com/s/photos/product?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;Unsplash&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Now that we’ve learned a few things about what lazy loading is and how to implement it in our React apps let’s focus on our enemies for a bit. You need to know about their weaknesses in order to choose a super effective attack against them! This section will include strategies and generic advice on when lazy loading can best help in improving performance.&lt;/p&gt;
&lt;h2&gt;
  
  
  Weakness #1: Lots of Images or Other Media
&lt;/h2&gt;

&lt;p&gt;Imagine you're building an e-commerce website that showcases a wide range of products. Each product has multiple high-resolution images, making the site extremely image-heavy. Loading all these images upfront would lead to slow load times and a poor user experience.&lt;/p&gt;

&lt;p&gt;By implementing lazy loading for images, you can ensure that only the images visible on the user's screen are loaded, while the rest are fetched on-demand as the user scrolls or clicks around. This saves bandwidth for the users and significantly improves the initial load time and overall performance of your website. And nothing restricts us to only images, we can deal with videos or even audio in the same way.&lt;/p&gt;
&lt;h2&gt;
  
  
  💡 Pro Tips
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Progressive Image Loading&lt;/strong&gt;: One of the best ways to deliver a good user experience while lazy loading images is to inline a very low resolution version of the image, render it blurred, initiate the fetching of the original and replace it with the full image once it’s loaded. Using a placeholder with the correct aspect ratios also helps with preventing a CLS increase. We will cover this technique in much more detail in &lt;em&gt;Chapter 11: The Snappiest Static Assets on The Planet&lt;/em&gt;. In the meanwhile you can take a look at &lt;a href="https://jmperezperez.com/blog/medium-image-progressive-loading-placeholder/"&gt;how Medium implemented this pattern&lt;/a&gt; or check out some of the most popular tools for creating those placeholders: &lt;a href="https://www.guypo.com/introducing-lqip-low-quality-image-placeholders"&gt;LQIP&lt;/a&gt; and &lt;a href="https://github.com/axe312ger/sqip"&gt;SQIP&lt;/a&gt; (&lt;em&gt;used by yours truly on fullcontextdevelopment.com/blog&lt;/em&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Modern Formats&lt;/strong&gt;: Another thing you can do to improve either the lazy or normal loading speed of images is using modern image formats like WebP or AVIF. These formats provide better compression and quality compared to traditional formats like JPEG or PNG.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CDN&lt;/strong&gt;: Consider using an image focused CDN that can help you optimize and serve those visual assets as fast as possible. (&lt;em&gt;Looking for a sponsor here&lt;/em&gt; 🥺)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Weakness #2: Huge Bundle Sizes
&lt;/h2&gt;

&lt;p&gt;For large-scale applications with numerous components and features loading everything at once can be resource-intensive and slow. Many SPAs fall victim to the growing main bundle size syndrome, when slowly but surely the production build size spirals out of control.&lt;/p&gt;

&lt;p&gt;A typical example is the good-old admin dashboard with lots of charts and diagrams, but any client-side-logic-heavy application can easily start to develop the symptoms. To resolve it you can lazy-load individual widgets or even full views of the app so they're only fetched when the user interacts with them.&lt;/p&gt;
&lt;h2&gt;
  
  
  💡 Pro Tips
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;CRP Optimization&lt;/strong&gt;: One of the most frequently used techniques to help with this problem is called Critical (Render) Path Optimization. In a nutshell, it’s about packing &lt;a href="https://www.semrush.com/blog/above-the-fold/"&gt;above-the-fold content&lt;/a&gt; into a separate bundle/chunk than the rest of the page so the users first download only the “critical“ or minimal part needed to interact with the site meaningfully. We will spend a whole chapter on this topic in: &lt;em&gt;Chapter 7 Implementing Critical Render Path Optimization With React and Next.js&lt;/em&gt;. That’s how important this technique is!&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Other Assets&lt;/strong&gt;: You can read a really nice &lt;a href="https://developer.mozilla.org/en-US/docs/Web/Performance/Lazy_loading"&gt;generic introduction to lazy loading on MDN&lt;/a&gt; that also discusses how to use this technique with fonts, images and even iframes. It mentions techniques for reducing the render blocking time of CSS and introduces one of my favorite tools, the &lt;code&gt;Intersection Observer API&lt;/code&gt; too.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use The Intersection Observer API&lt;/strong&gt;: It’s a very effective weapon widely used on the web for killing slow page load times! The basic idea is to only initiate fetching a component’s chunk once the observer tells us it would become visible on the screen. It’s even better if we time it just a bit earlier than that so it will already be there once the users scroll to its position. I’ve used this technique a lot in my own projects and I plan to show some as examples later but for now I will link you to a &lt;a href="https://miyauchi.dev/posts/react-lazy-intersection/"&gt;great tutorial about its implementation&lt;/a&gt; combined with &lt;code&gt;React.lazy&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Weakness #3: 3rd Party Scripts
&lt;/h2&gt;

&lt;p&gt;Very common performance hogs that lazy loading can effectively beat are the 3rd party scripts. They are often loaded immediately as the HTML is just being rendered for the first time. They sometimes even get bundled into the prod build of the application! 🤯 But in reality, they are often not needed immediately for the site to function as intended. It opens up the opportunity to lazy load them.&lt;/p&gt;

&lt;p&gt;Good examples are 3rd party chat or comment widgets, captcha services or the code of any external services. In some cases even analytics or cookie consent code can be deferred! Eliminating these from the initial render of the app can often significantly improve the performance characteristics of a site. A real life example shared by MediaVine is how they &lt;a href="https://www.mediavine.com/lazy-loading-ads-mediavine-ads-load-200-faster/"&gt;improved their initial ad load time by 200%&lt;/a&gt; by &lt;strong&gt;lazy loading ads&lt;/strong&gt;!&lt;/p&gt;
&lt;h2&gt;
  
  
  💡 Pro Tips
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Lazy Loading Scripts&lt;/strong&gt;: The tools of the trade here are the HTML attributes called &lt;code&gt;async&lt;/code&gt; and &lt;code&gt;defer&lt;/code&gt; of the &lt;code&gt;script&lt;/code&gt; tag and the &lt;code&gt;rel&lt;/code&gt; attribute of the &lt;code&gt;link&lt;/code&gt; tag with the &lt;code&gt;preconnect&lt;/code&gt; and &lt;code&gt;dns-prefetch&lt;/code&gt; values. Here’s an awesome &lt;a href="https://web.dev/efficiently-load-third-party-javascript/"&gt;article on web.dev&lt;/a&gt; showing exactly how to use them for some serious speed improvements. Key takeaway from there: use async for highest priority scripts and defer for less critical dependencies. But there are some exceptions, check the article.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lazy Loading Anything&lt;/strong&gt;: You can lazy load just about anything that an ES module can hold. It naturally includes &lt;em&gt;npm packages&lt;/em&gt; too. You can load them at any place or time simply by &lt;code&gt;(await import(‘name‘)).default&lt;/code&gt;-ing them. The Next.js docs have &lt;a href="https://nextjs.org/docs/app/building-your-application/optimizing/lazy-loading#loading-external-libraries"&gt;a practical example&lt;/a&gt; of how to put it to good use. In the next section I will also share some strategies about how to utilize this for the best possible speed improvements.&lt;/p&gt;

&lt;p&gt;Going forward, whenever a wild slow website appears with any of these weaknesses, you will know how to deal a super effective blow to them! In my experience this is really valuable knowledge so you already acquired some good skills! Let’s continue!&lt;/p&gt;
&lt;h2&gt;
  
  
  Identifying The Target 🕵️
&lt;/h2&gt;

&lt;p&gt;Now that you can easily recognize the general patterns where lazy loading can help, we can also look at the generic approach to find good targets for this technique. Here’s what you should be looking for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Components that aren't immediately needed on the initial view&lt;/strong&gt;. Good examples would be &lt;strong&gt;modals, heavy dropdown menus&lt;/strong&gt; or any element of the UI that appears on interaction.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Components that have a significant impact on loading time&lt;/strong&gt;. As usual, doing a performance profile and analyzing the network/render waterfall is the best starting point. Some typical offenders you might find are &lt;strong&gt;large data tables, huge charts or not-always-used npm packages&lt;/strong&gt; (&lt;em&gt;like date handling… moment.js anyone?&lt;/em&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Components that are always conditionally rendered&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Components that are only present in certain routes of the app&lt;/strong&gt; yet are put into the main bundle somehow. (&lt;em&gt;mistakes happen&lt;/em&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Infrequently used features&lt;/strong&gt; are also great targets for lazy loading. You can improve the UX for the majority of the users if you lazy load the least used parts of the app. The best way to identify them is going empirical. Use analytics or monitoring/logging data to see the interaction patterns of your site and look for those less frequently used features. ☢️ &lt;em&gt;Make wise judgements. The least frequently used parts can still have critical importance.&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Imports that are only needed when/after the user starts an interaction&lt;/strong&gt;. If there are imports in a module that fit the description, you can either defer their loading until the user’s first attempt to use them or manually prefetch them even sooner so they wouldn’t have to wait.&lt;/li&gt;
&lt;li&gt;👉 &lt;a href="https://builtin.com/ux-design/infinite-scroll"&gt;Infinite scroll&lt;/a&gt; is also a kind of lazy loading pattern but I’m sure you will know when you need it without any special speed improvement goals.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  🧠 Performance Mindset
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;I found it really helpful in developing a performance mindset to pick up the habit of considering what to lazy load in the design phase of work. Be on the lookout for the above cases and you might avoid the need to “optimize performance” in the future, instead you could “simply“ keep it high all along. &lt;strong&gt;That’s the best thing you can do for your users and company profits too&lt;/strong&gt;!&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;
  
  
  Lazy Loading With Next.js
&lt;/h2&gt;

&lt;p&gt;You have already learned a ton about lazy loading in general and in combination with React. Now let’s go deeper and take a look at the unique tools that Next.js offers for implementing this technique!&lt;/p&gt;

&lt;p&gt;Next takes the DX of lazy loading to a whole new level with its automatic code splitting and dynamic imports. By default, Next.js will split your codebase at the page level, ensuring that users only download the code required for the current URL. That’s a nice little favor from the framework authors, saving us all some time and effort.&lt;/p&gt;

&lt;p&gt;👉 &lt;em&gt;Now with React Server Components (RSC) it can automatically save you from including JS in the output of SSR when the code is only used for rendering but not needed for client-side interactivity.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;To further optimize your Next.js application, you can use &lt;code&gt;dynamic&lt;/code&gt; from &lt;a href="https://github.com/vercel/next.js/blob/canary/packages/next/src/shared/lib/dynamic.tsx"&gt;next/dynamic&lt;/a&gt; to lazy-load individual components. It gives us the same level of control over loading behavior as &lt;code&gt;React.lazy&lt;/code&gt; and a bit more!&lt;/p&gt;

&lt;p&gt;Here's a cookie cutter, basic example of how to use it:&lt;br&gt;
&lt;/p&gt;

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

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;LazyLoadedByNextJS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;dynamic&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./MyComponent&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
  &lt;span class="na"&gt;loading&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Loading placeholder&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;,&lt;/span&gt;
  &lt;span class="na"&gt;ssr&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"App"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;LazyLoadedComponent&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It kind of follows the same pattern as the “&lt;em&gt;native&lt;/em&gt;“ React solution. There’s not much difference between these two now in the v18 era as &lt;code&gt;dynamic&lt;/code&gt; uses &lt;code&gt;Suspense&lt;/code&gt; and &lt;code&gt;React.lazy&lt;/code&gt; internally. Its only significant, added feature is that you can prevent the lazy loaded component from rendering in SSG and SSR mode by passing the ssr: false config option to the dynamic call. Otherwise the component would be loaded and rendered in those situations too. (&lt;em&gt;Of course only if the UI logic is set up that way&lt;/em&gt;.)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;When do you need that ssr: false?&lt;/strong&gt; Most frequently, in case of rendering stuff that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Relies on browser-only APIs, like WebGL or the DOM.&lt;/li&gt;
&lt;li&gt;Displaying real-time data like a chat widget or stock price chart where you might not want to show outdated information on the initial load.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  💡 Pro Tips
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;App and Pages&lt;/strong&gt;: There’s no need to worry, &lt;code&gt;next/dynamic&lt;/code&gt; works the same way in both folders.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Loading Placeholder&lt;/strong&gt;: As you saw in the example, you can provide the placeholder component as a config option to the call.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Importing Default vs Named Exports&lt;/strong&gt;: &lt;code&gt;next/dynamic&lt;/code&gt; has the same issue with named exports as &lt;code&gt;React.lazy&lt;/code&gt; (&lt;em&gt;no wonder considering it’s using that.&lt;/em&gt;) As a work around you can do this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;NamedLazyLoadedComponent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;dynamic&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./NamedComponent&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Named&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Client and Server Components&lt;/strong&gt;: Server components are code split to their own chunks by default and can be streaming-rendered. Lazy loading is only relevant when working with client components. If you try to lazy load a server component only it’s child client components will be lazy loaded (&lt;em&gt;if there’s any&lt;/em&gt;).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Place of Calling Dynamic&lt;/strong&gt;: Invoking &lt;code&gt;dynamic&lt;/code&gt; has to be in the top level scope of the module (&lt;em&gt;file&lt;/em&gt;) in order to work. It means you can’t write it inside functions or React components.&lt;/p&gt;

&lt;p&gt;That’s how you do generic lazy loading with Next.js but it has some additional tools that can be used to implement this method in specialized cases.&lt;/p&gt;

&lt;h2&gt;
  
  
  More Tools in Next’s Arsenal With Lazy Loading Powers
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Next/Image&lt;/strong&gt;: The developers of Next.js have upgraded the img tag with special capabilities and made it available through the &lt;a href="https://nextjs.org/docs/pages/building-your-application/optimizing/images"&gt;next/image component&lt;/a&gt;. Some of those has lots to do with lazy loading. They designed it in a way to only load images when they enter the viewport. You can optionally provide a blurred placeholder with the &lt;a href="https://nextjs.org/docs/app/api-reference/components/image#blurdataurl"&gt;blurDataURL&lt;/a&gt; prop or if you are directly importing an image with a supported format the blurred version will be auto generated for you at build time when you use the &lt;a href="https://nextjs.org/docs/app/api-reference/components/image#placeholder"&gt;placeholder&lt;/a&gt; prop.&lt;/p&gt;

&lt;p&gt;Another neat, performance aware feature is the &lt;a href="https://nextjs.org/docs/pages/building-your-application/optimizing/images#image-sizing"&gt;many built-in ways&lt;/a&gt; the component takes care of CLS as it will always reserve the right size for the image, even before it’s loaded. In addition, you can “&lt;em&gt;mark&lt;/em&gt;“ an image as &lt;a href="https://nextjs.org/docs/pages/building-your-application/optimizing/images#priority"&gt;priority&lt;/a&gt;. This is best used for the LCP (&lt;em&gt;largest contentful paint&lt;/em&gt;) image on each page so that it will be prioritized for the earliest possible load. Make sure to utilize this component to the max. It’s a very powerful and useful optimization tool that can do much more than what’s related to lazy loading!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Next/Font&lt;/strong&gt;: Well, this one is not directly related to lazy loading fonts, just to loading them, but I might as well mention it here. &lt;a href="https://nextjs.org/docs/pages/building-your-application/optimizing/fonts"&gt;next/font&lt;/a&gt; allows you to control when and where the different font files are loaded depending on where you use it. It also depends on whether you are rocking the &lt;code&gt;pages&lt;/code&gt; or the &lt;code&gt;app&lt;/code&gt; folder.&lt;/p&gt;

&lt;p&gt;In the case of pages, fonts requested with &lt;code&gt;next/font&lt;/code&gt; will be preloaded on that single route and fonts requested in the custom app will be preloaded globally.&lt;/p&gt;

&lt;p&gt;Working within the &lt;code&gt;app&lt;/code&gt; directory you have more options. Requesting a font inside a page works the same way, however you can also request them in a layout that will preload the font for every route wrapped by it and non-surprisingly if you request one in the root layout it will be preloaded globally.&lt;/p&gt;

&lt;p&gt;The nice thing about &lt;code&gt;next/font&lt;/code&gt; is that it does a lot more to ensure your app won’t suffer from any related performance issues. Most notably it can load fonts while ensuring zero layout shifts by using the &lt;code&gt;size-adjust&lt;/code&gt; CSS property. A must use if you are dealing with fonts in a Next.js application.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Next/Script&lt;/strong&gt;: You can use &lt;a href="https://nextjs.org/docs/app/building-your-application/optimizing/scripts"&gt;next/script&lt;/a&gt; to control the timing of load and the scope of 3rd party scripts. Again, it can do more to optimize app performance than what’s related to lazy loading so make sure to check out the docs if you are interested. (&lt;em&gt;I will cover those areas in other chapters later.&lt;/em&gt;)&lt;/p&gt;

&lt;p&gt;What’s relevant here are the different loading &lt;a href="https://nextjs.org/docs/app/building-your-application/optimizing/scripts#strategy"&gt;strategies&lt;/a&gt; it offers, which makes it a very clean and easy to use tool for precisely controlling script loading. The most relevant strategy is called &lt;code&gt;lazyOnload&lt;/code&gt;. It delays the loading of the script to the first time the browser’s &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Background_Tasks_API"&gt;main thread becomes idle&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Another interesting strategy is called &lt;code&gt;worker&lt;/code&gt; which moves the loading of the script off-main-thread to a web worker using &lt;a href="https://partytown.builder.io/"&gt;Partytown&lt;/a&gt;. It’s not compatible with the &lt;code&gt;app&lt;/code&gt; folder as of July 2023. But when you are in a position enabling its use, this opens up interesting optimization possibilities. Mostly if the script is doing quite independent stuff from the rest of the application like analytics, A/B testing, or metrics collection.&lt;/p&gt;

&lt;h2&gt;
  
  
  🧠 Performance Mindset
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;These are the options offered by the framework for influence loading behavior. Remember, when you are reaching out for: &lt;strong&gt;React components, libraries, images, fonts&lt;/strong&gt; or &lt;strong&gt;scripts&lt;/strong&gt; you can and likely should use some of these tools on a Next.js based project.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Final Warning: When Not to Lazy Load
&lt;/h2&gt;

&lt;p&gt;Before you go out and naively try to:&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--o_J8Aedt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/om6fir40zrot4gvss3ex.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--o_J8Aedt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/om6fir40zrot4gvss3ex.jpg" alt="All the things meme, showing React.lazy and dynamic import calls all over it" width="620" height="465"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You need to realize, as with all design decisions there are tradeoffs to be made here. I will explain what you need to keep in mind when deciding for or against lazy loading something.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;👉 If you want to see an easy to follow, step by step example of the core issues with naively lazy loading everything check out &lt;a href="https://www.builder.io/blog/the-challenges-of-lazy-loading-in-javascript"&gt;this excellent article&lt;/a&gt; from the authors of Qwik. Highly recommended. As well as the framework itself. It’s so innovative I’m sure it will drive lots of changes in other frameworks too.&lt;/em&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Lazy loading only works properly with client side rendering&lt;/strong&gt;. If you SSR a lazy loaded component you might come out worse in the end than without lazy loading or server side rendering. The JS for the lazy loaded component will be fetched eagerly on the client, as it’s needed for the hydration of the initial HTML. That means we created another unnecessary network request, that’s pure overhead in the process of reaching interactivity. If you had it loaded normally, its code would have been part of the main bundle and be available at this point. However if the lazy loaded component is purely CSR, this whole situation won’t happen. Issue solved.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Lazy loading is only useful for components not present in the current render tree in SSR mode&lt;/strong&gt;. It usually comes down to two cases. One is lazy loading the next route and the other one is conditional rendering of a lazy loaded component. The reason is the same as before. If the code split chunk of the lazy loaded component is eagerly fetched for hydrating the initial SSR’ed HTML we end up shooting ourselves in the foot. However if the component is not present in it, we can still reap the proper benefits of lazy loading and in these two cases that’s surely what will happen.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;You should never lazy load content needed for SEO&lt;/strong&gt;. There’s just no telling whether the crawler will surely wait for the loading to finish or not. If you SSR the lazy loaded component to circumvent this, then we are back to problem #1.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Many lazy loaded components on the same view lead to hard to answer bundling questions&lt;/strong&gt;. If multiple lazy loaded components are requested for the same URL, it might make sense to put them into the same chunk depending on when they will be requested. I’m sure you already feel the combinatorial explosion building up in your head. What would be best paired with what when the app navigates from A to B or from C to A. What about things that are fetched on user interaction. What about prefetching? Not every bundler is capable of handling this question properly so now we developers are responsible to think about this concern too.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Each code split chunk has some overhead&lt;/strong&gt;. You need to be mindful that every chunk contains some additional JS code. The extra size can add up with each new chunk and their loading incurs network overhead too. All these can lead to situations where too many, small, lazy loaded chunks negate every performance benefit they provide otherwise. Evaluating the costs &amp;amp; benefits of a certain chunking setup is tricky, but luckily we don’t have to pioneer the solution. Here’s a &lt;a href="https://medium.com/hackernoon/effective-code-splitting-in-react-a-practical-guide-2195359d5d49"&gt;guide on Hackernoon&lt;/a&gt; how to measure and fine tune chunk sizes and their performance impact.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  🧠 Performance Mindset
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;As a rule of thumb, &lt;strong&gt;start with the assumption that you don't need lazy loading at all&lt;/strong&gt;. Only apply it if you can &lt;strong&gt;validate that it leads to significant improvements&lt;/strong&gt; in the metrics that really matter for your project. Use this approach for all your optimization efforts!&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That’s all the advice I have for you student of the way of ancient performance grandmasters. Now you know how to lazy load, when to lazy and what to lazy load. Use it well and see you in the next one!&lt;/p&gt;

&lt;h2&gt;
  
  
  Challenge: Share The Diff
&lt;/h2&gt;

&lt;p&gt;I would like to ask you to take what you learned here and put it to practice. Use the &lt;a href="https://googlechrome.github.io/lighthouse-ci/difftool/"&gt;Lighthouse Diff Tool&lt;/a&gt; to record how you made a difference by applying lazy loading. If you share your results and a little background story here in the comments I will highlight the best 3 of those in the article on Substack!&lt;/p&gt;




&lt;h2&gt;
  
  
  ✉️ Thanks For Reading All The Way Here! ✉️
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;If you found good advice or interesting stuff in here, please consider sharing this article with some of your friends or colleagues. That would really make me feel a deep sense of accomplishment, even more if you would decide to &lt;a href="https://www.fullctx.dev/"&gt;sign up for my newsletter&lt;/a&gt; where I post more of these guides and other interesting news.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;See you in the next one frontend ninjas,&lt;br&gt;
Joe&lt;/p&gt;

</description>
      <category>react</category>
      <category>nextjs</category>
      <category>javascript</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Weekly Tech Hype #3 - Next vs Astro perf, Signals for web frameworks, Node.js runtimes in browser, Shopify's Hydrogen uses Remix</title>
      <dc:creator>József Miskolczy</dc:creator>
      <pubDate>Sat, 25 Feb 2023 01:08:15 +0000</pubDate>
      <link>https://dev.to/fullctxdev/weekly-tech-hype-3-next-vs-astro-perf-signals-for-web-frameworks-nodejs-runtimes-in-browser-shopifys-hydrogen-uses-remix-366k</link>
      <guid>https://dev.to/fullctxdev/weekly-tech-hype-3-next-vs-astro-perf-signals-for-web-frameworks-nodejs-runtimes-in-browser-shopifys-hydrogen-uses-remix-366k</guid>
      <description>&lt;h3&gt;
  
  
  Hey this is the Weekly Tech Hype #1
&lt;/h3&gt;

&lt;p&gt;It's a quick overview of the recent FE tech news using my own &lt;a href="https://www.fullcontextdevelopment.com/blog/next-full-context-review#review" rel="noopener noreferrer"&gt;Full Context perspective&lt;/a&gt; to fight the hype. Let’s find out what happened this week that can make a difference for the projects we work on, for our users and us software engineers.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;(The headings are links to the covered topic)&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://www.youtube.com/watch?v=wzRSYQ3b-Mk" rel="noopener noreferrer"&gt;#1 Next.js 13 vs Next.js 12 vs Astro 2 performance test&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;A video by &lt;a href="https://twitter.com/jherr" rel="noopener noreferrer"&gt;Jack Herrington&lt;/a&gt; comparing the speed of the same web apps implemented in all 3 frameworks/versions. It got lots of love from the community and I also enjoyed it so please Jack no hard feelings but:&lt;/p&gt;

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

&lt;p&gt;It has it all:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Hot topic of the day FE tools ✅&lt;/li&gt;
&lt;li&gt;Everyone’s favorite obsession: Performance ✅&lt;/li&gt;
&lt;li&gt;Battle of technologies with a possible clear winner triggering tribal instincts ✅ (I know the conclusions were balanced)&lt;/li&gt;
&lt;li&gt;It only missed the celebrity component. ❌
Like Dan Abramov implementing the Next v13 version sharing behind the scenes info about the future of RSCs.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The 100k views wouldn’t have been out of reach. Keep it up Jack! - In all honesty it was a really well done comparison. But…&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;From the Full Context Perspective&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The video compares the TTI and the supporting/correlating info about the size of transferred data. While TTI is a factor in &lt;a href="https://www.fullcontextdevelopment.com/book/chapter-6#f282191e67a44bfc9eb66e9f596b6719" rel="noopener noreferrer"&gt;achieving a good Customer Experience&lt;/a&gt; (&lt;em&gt;link from my book on how tech and CX are related to business outcomes&lt;/em&gt;) but it’s far from the only or the most significant component of it.&lt;/p&gt;

&lt;p&gt;I will be strict, the video as a whole has no added value to increase the impact of the products we are working on.&lt;/p&gt;

&lt;p&gt;In smaller products it’s unlikely that the shown level of difference in TTI will create a bottleneck while developers on huge projects wouldn’t rely on the default output of these frameworks. These small app measurements are sadly irrelevant for that case,&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;That’s why Jack’s advice at the end is absolutely correct, do your own measurements for your own situation.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;But then what’s the value we can take away from this comparison?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The performance comparison gets a 4 / 10 HV score.&lt;/strong&gt;&lt;/p&gt;

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

&lt;h2&gt;
  
  
  &lt;a href="https://www.builder.io/blog/usesignal-is-the-future-of-web-frameworks" rel="noopener noreferrer"&gt;#2 Signals&lt;/a&gt;, &lt;a href="https://twitter.com/sarah_edo/status/1628065696247857152" rel="noopener noreferrer"&gt;Signals&lt;/a&gt;, &lt;a href="https://twitter.com/acdlite/status/1626590880126889984" rel="noopener noreferrer"&gt;everywhere&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://twitter.com/mhevery" rel="noopener noreferrer"&gt;Misko Hevery&lt;/a&gt; (&lt;em&gt;author of Angular.js and Qwik&lt;/em&gt;) released a very interesting, deeply technical article about signals as reactivity primitives in modern FE frameworks. At the same time &lt;a href="https://twitter.com/sarah_edo" rel="noopener noreferrer"&gt;Sarah Drasner&lt;/a&gt; announced that Angular will introduce the use of signals. &lt;a href="https://twitter.com/acdlite" rel="noopener noreferrer"&gt;Andrew Clark&lt;/a&gt; teased the idea that React might add them as a compiler target, or a low level API for library authors.&lt;/p&gt;

&lt;p&gt;Signals are not a new concept, Vue, Preact, Solid, and Qwik all use them, it even existed in Knockout. But recent implementations improve on the DX side significantly.&lt;/p&gt;

&lt;p&gt;This is the type of news that I really appreciate. It shows us how to achieve a goal more effectively through a technical tool, - reactive state updates with high rendering performance - while also creating just enough hype to raise attention.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;From the Full Context Perspective&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This can be a couple hundred &lt;a href="https://www.fullcontextdevelopment.com/blog/next-full-context-review#review" rel="noopener noreferrer"&gt;Impact Point&lt;/a&gt; worth of &lt;a href="https://www.fullcontextdevelopment.com/book/chapter-3#492aef240b5a46f188c2d6a8bfb69b0d" rel="noopener noreferrer"&gt;Productivity&lt;/a&gt; improvement depending on the circumstances that can manifest in a visible value increase.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The signal technology gets a 8 / 10 HV score.&lt;/strong&gt;&lt;/p&gt;

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




&lt;p&gt;This is a repost from my &lt;a href="https://fullctxdev.substack.com/" rel="noopener noreferrer"&gt;Substack&lt;/a&gt;, if you don't want to miss out similar content, subscribe to the newsletter!&lt;/p&gt;

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




&lt;h2&gt;
  
  
  &lt;a href="https://blog.stackblitz.com/posts/webcontainer-api-is-here/" rel="noopener noreferrer"&gt;#3 Node.js runtimes&lt;/a&gt;, &lt;a href="https://codesandbox.io/blog/announcing-sandpack-2" rel="noopener noreferrer"&gt;in the browser&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;CodeSandbox and StackBlitz both announced the next version of their in-browser Node.js implementation, respectively Sandpack 2.0 and the WebContainers API. Here’s a summary of both:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;WebContainers&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;WebContainers are a micro-operating system based on WebAssembly designed to allow spinning up Node.js servers locally inside a browser tab&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;SandPack&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Sandpack 2.0 introduces Nodebox, a new technology that implements its very own abstraction of Node.js in-browser. Nodebox brings a new set of possibilities allowing Sandpack to run almost any JavaScript application you can imagine in any browser.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;These are cool things, but their use-cases are limited. They can mostly be used to create… &lt;strong&gt;&lt;em&gt;cool things&lt;/em&gt;&lt;/strong&gt;. Web IDEs, interactive coding tutorials, no-code/low-code environments or to compile and run Next.js, Vite and Astro projects completely client side.&lt;/p&gt;

&lt;p&gt;These are legitimate technology advancements, totally newsworthy and congratulations to everyone who pulled it off, it’s tremendous work!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;From the Full Context Perspective&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is the stuff that manifests the purest form of &lt;a href="https://www.fullcontextdevelopment.com/book/chapter-3#755ae305b28b4848b6b919b3d8238b8c" rel="noopener noreferrer"&gt;Business Opportunity&lt;/a&gt;. An innovation that creates new markets, that enables the creation of products previously impossible to build. The thing is, if the product you are working on belongs to a different category, the effect of these innovations on your life and on the business’ is 0.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpimkdsyt9eg0vo12wz15.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpimkdsyt9eg0vo12wz15.jpg" alt="For those who want to create these kinds of products" width="666" height="374"&gt;&lt;/a&gt;&lt;em&gt;For those who want to create these kinds of products&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyam1rc1bkisbm69ktcsd.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyam1rc1bkisbm69ktcsd.jpg" alt="For the rest of us" width="500" height="814"&gt;&lt;/a&gt;&lt;em&gt;For the rest of us&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Node.js in-browser tech gets a 7 / 10 HV score.&lt;/strong&gt;&lt;/p&gt;

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

&lt;h2&gt;
  
  
  &lt;a href="https://hydrogen.shopify.dev/updates" rel="noopener noreferrer"&gt;#4 Shopify’s Hydrogen&lt;/a&gt;, &lt;a href="https://twitter.com/remix_run/status/1623744656701026306" rel="noopener noreferrer"&gt;uses Remix&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;This news is delivered without much buzz and I also won’t say too much about it.&lt;/p&gt;

&lt;p&gt;Shopify devs rewrote Hydrogen using Remix. They enjoy all the benefits of Remix now. Well they bought the Remix company so they’ve got to do something with ‘em, right? The real question is the pros vs cons of using Remix over pure React and its ecosystem. I tried to form a well &lt;a href="https://www.fullcontextdevelopment.com/blog/remix-full-context-review#product" rel="noopener noreferrer"&gt;balanced&lt;/a&gt;, &lt;a href="https://www.fullcontextdevelopment.com/blog/remix-full-context-review#software" rel="noopener noreferrer"&gt;opinion &lt;/a&gt;on that last year. It’s not all songs and birds but there are a ton of major benefits. I’m interested in following how it will pay out for Shopify.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;From the Full Context Perspective&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I would have loved to see some measurements of how the Remix implementation did in terms of Real User Metrics or other benchmarks vs the v1 Hydrogen. That would have given us a sense of the impact of the rewrite on business value. Without that I will be optimistic with this one an give&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Hydrogen v2. a 7 / 10 HV score.&lt;/strong&gt;&lt;/p&gt;

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




&lt;p&gt;&lt;strong&gt;I’m super happy&lt;/strong&gt; that you read (&lt;em&gt;or scrolled&lt;/em&gt;) till the end! I feel speechless that people actually do that! If you enjoyed the article and/or found it valuable please consider sharing it with your friends and colleagues.&lt;/p&gt;

&lt;p&gt;I’m at a very early stage of building this Substack publication so even the smallest extra visibility can make a huge difference. My wholehearted thanks if you help with that!&lt;/p&gt;

&lt;p&gt;See you in the next one!&lt;br&gt;
Joe &lt;a href="https://twitter.com/fullctxdev" rel="noopener noreferrer"&gt;@fullctxdev&lt;/a&gt;&lt;/p&gt;

</description>
      <category>watercooler</category>
    </item>
    <item>
      <title>The dark side of Next.js</title>
      <dc:creator>József Miskolczy</dc:creator>
      <pubDate>Sun, 19 Feb 2023 14:49:54 +0000</pubDate>
      <link>https://dev.to/fullctxdev/the-dark-side-of-nextjs-39ae</link>
      <guid>https://dev.to/fullctxdev/the-dark-side-of-nextjs-39ae</guid>
      <description>&lt;p&gt;&lt;em&gt;Header image by &lt;a href="https://unsplash.com/de/@maxwbender?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Max Bender&lt;/a&gt; on &lt;a href="https://unsplash.com/photos/XIVDN9cxOVc?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Unsplash&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Next.js is one of the most popular frontend (meta) frameworks in 2023 and for good reason. However it has a dark side that nobody talks about, yet it can bite you in the back when you try to scale a Next based project. Let me show you the worst parts of Next.js so you can prepare for them in advance. To be upfront, most of these should be rare cases.&lt;/p&gt;

&lt;h2&gt;
  
  
  Scaling concerns
&lt;/h2&gt;

&lt;p&gt;If you host Next.js yourself and do multi-instance scaling, ISR won't be your best friend. Each instance will have its own cache for the generated pages. If your load-balancer is not using &lt;a href="https://www.imperva.com/learn/availability/sticky-session-persistence-and-cookies/" rel="noopener noreferrer"&gt;sticky sessions&lt;/a&gt;, that means trouble. Depending on the status of the regeneration process on each node, the visitor can be served both stale and up-to-date content during the same sessions. That's bad, like really bad from the user experience point of view. &lt;em&gt;Here's a flow diagram to demonstrate it:&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://imgcdn.dev/i/SmXsd" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fs6.imgcdn.dev%2FSmXsd.png" alt="flow diagram of ISR rendering messing up in multi instance next.js projects" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://nextjs.org/docs/basic-features/data-fetching/incremental-static-regeneration#on-demand-revalidation" rel="noopener noreferrer"&gt;on-demand ISR&lt;/a&gt; can help in minimizing this risk, but can't fully eliminate it while also complicating both your codebase and your operational processes quite a lot. That's far from ideal.&lt;/p&gt;

&lt;p&gt;There are four solutions to this problem. &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;First is to avoid it completely by replacing ISR with SSR. Not a what you would prefer, right? &lt;/li&gt;
&lt;li&gt;Second is using &lt;a href="https://www.vercel.com/" rel="noopener noreferrer"&gt;Vercel&lt;/a&gt; to host your project or any similar platforms and let them scale your application. Not an option either? &lt;/li&gt;
&lt;li&gt;Then enter &lt;a href="https://github.com/next-boost/next-boost" rel="noopener noreferrer"&gt;Next Boost&lt;/a&gt; a community library to boost your backend rendering performance by orders of magnitude.&lt;/li&gt;
&lt;li&gt;Set up additional infrastructure around your Next.js instances. (&lt;em&gt;more on this later&lt;/em&gt;)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Next Boost works as a cache in front of SSR-ed pages, like a custom implementation of ISR but here you can configure where to store the results and their &lt;a href="https://github.com/next-boost/redis-cache" rel="noopener noreferrer"&gt;redis-cache&lt;/a&gt; option is ideal to be used with a cluster of Next.js servers. It will be a single-source-of-pages for all the nodes.&lt;/p&gt;

&lt;p&gt;Sadly, this solution is not without downsides either. It complicates your tech stack and adds a new operational and maintenance cost factor. More importantly, the maintainer doesn't seem to be very active, so you might need to fork and customize the package if its current capabilities doesn't suit your project.&lt;/p&gt;

&lt;h4&gt;
  
  
  Back to Option 4:
&lt;/h4&gt;

&lt;blockquote&gt;
&lt;p&gt;The &lt;a href="https://www.reddit.com/r/reactjs/comments/117pc07/the_dark_side_of_nextjs_and_how_to_tackle_it/" rel="noopener noreferrer"&gt;Reddit community&lt;/a&gt; was kind enough to raise my attention to these. Thanks everyone and especially for &lt;a href="https://www.reddit.com/user/beny27/" rel="noopener noreferrer"&gt;beny27&lt;/a&gt;, &lt;a href="https://www.reddit.com/user/dbbk/" rel="noopener noreferrer"&gt;dbbk&lt;/a&gt; and &lt;a href="https://www.reddit.com/user/porcupineapplepieces/" rel="noopener noreferrer"&gt;porcupineapplepieces&lt;/a&gt;!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You can implement a similar solution to Next Boost on your own. The main idea is to add some kind of caching in front of your Next servers like an AWS S3 bucket and configure a load balancer to look up the responses there first or by setting up a CDN. Both of these examples need ISR switched off and using SSR instead.  &lt;/p&gt;

&lt;p&gt;⬆️⬆️⬆️ &lt;strong&gt;&lt;em&gt;If you need to scale custom Next.js servers these are the things you should keep in mind.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Architectural concerns
&lt;/h2&gt;

&lt;p&gt;If you work on a large-scale project, chances are you run multiple applications from the same top-level domain and you need to support i18n. Well, that's a hard situation for Next.js!&lt;/p&gt;

&lt;p&gt;The culprit is the router, Dhanraj Padmashali &lt;a href="https://twitter.com/psygik" rel="noopener noreferrer"&gt;@psygik&lt;/a&gt; wrote about it in detail &lt;a href="https://dhanrajsp.me/blog/the-troubles-with-nextjs#_next-and-cdn" rel="noopener noreferrer"&gt;here&lt;/a&gt;. To sum it up, it's currently &lt;del&gt;not possible&lt;/del&gt; hacky to run multiple Next.js apps under the same domain if their url paths contain a language code prefix. For example: &lt;code&gt;site.com/en/app&lt;/code&gt; or in general: &lt;code&gt;site.com/{:langCode}/{:subApp}&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The community created some workarounds to escape this limitation, but you need to be mindful to either &lt;a href="https://github.com/vercel/next.js/discussions/25681#discussioncomment-2026813" rel="noopener noreferrer"&gt;monkey patch&lt;/a&gt; the &lt;code&gt;next/router&lt;/code&gt; or add an &lt;a href="https://github.com/vercel/next.js/discussions/25883#discussioncomment-2155780" rel="noopener noreferrer"&gt;app wide middleware&lt;/a&gt; to rewrite the URL or use even &lt;a href="https://github.com/vercel/next.js/discussions/17078#discussioncomment-387358" rel="noopener noreferrer"&gt;more drastic measures&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Dhanraj also points out that if your whole application lives under a path of a larger site, e.g.: &lt;code&gt;site.com/cool-apps/next-app&lt;/code&gt; that gets internally proxied to another URL and the app uses dynamic route parameters for SSR'd pages eg: &lt;code&gt;/next-app/users/beastmaster64&lt;/code&gt; it will die on the internal &lt;code&gt;_next/data&lt;/code&gt; requests for the &lt;code&gt;json&lt;/code&gt; page data because that folder doesn't respect the &lt;code&gt;assetPrefix&lt;/code&gt; nor the &lt;code&gt;basePath&lt;/code&gt; values. Yes, complicated, but not uncommon. There's a &lt;a href="https://dhanrajsp.me/blog/the-troubles-with-nextjs#_next-and-cdn" rel="noopener noreferrer"&gt;workaround&lt;/a&gt; in the linked article, but it's again, rather hacky and needs a custom server.&lt;/p&gt;

&lt;p&gt;⬆️⬆️⬆️ &lt;strong&gt;&lt;em&gt;Keep these in mind while planning your architecture.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Router limitations
&lt;/h2&gt;

&lt;p&gt;This is a technical detail which can only become a show-stopper in very few cases, nonetheless, it might affect you. The built-in, file-based router cannot provide "real" client-side dynamic navigation. If your application &lt;strong&gt;really&lt;/strong&gt; needs that, then take a look at &lt;a href="https://colinhacks.com/essays/building-a-spa-with-nextjs" rel="noopener noreferrer"&gt;this guide&lt;/a&gt; showing how to integrate &lt;code&gt;react-router&lt;/code&gt; with Next.js. If that still doesn't meet your needs (&lt;em&gt;main drawback: lack of initial SSR&lt;/em&gt;) than it's sadly time to say goodbye to this framework.&lt;/p&gt;

&lt;p&gt;But what do I mean by the router not supporting SPA navigation? Next.js either creates the pre-built HTML for a page (SSG) or uses server-side rendering to deliver it. The second option can use dynamic runtime path parameters, while the first works only with known paths even if those are fetched dynamically during the build step. This way you can't deliver "truly" SPA style, dynamic, client-side transitions, only if you use query parameters instead of the URL path, like this:&lt;/p&gt;

&lt;p&gt;❌ &lt;code&gt;/product-category/shoes/1&lt;/code&gt; =&amp;gt; ONLY SSG OR SSR&lt;br&gt;
✅ &lt;code&gt;/product-category?category=shoes&amp;amp;page=1&lt;/code&gt; =&amp;gt; YOU IMPLEMENT CSR&lt;/p&gt;

&lt;p&gt;If you are interested in a real life example where this can really make a difference, check out &lt;a href="https://www.singlestore.com/blog/moving-from-next-js/" rel="noopener noreferrer"&gt;this article&lt;/a&gt; from &lt;em&gt;&lt;strong&gt;SingleStore&lt;/strong&gt;&lt;/em&gt; about why they moved away from Next.js, specifically the &lt;em&gt;Dynamic Routing&lt;/em&gt; part.&lt;/p&gt;

&lt;h2&gt;
  
  
  Vercel Telemetry
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Thanks &lt;a href="https://www.reddit.com/user/onems/" rel="noopener noreferrer"&gt;onems&lt;/a&gt;!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Some developers and companies might be unaware of the fact that every Next.js project sends live statistics to Vercel, a private company unless you &lt;strong&gt;opt-out&lt;/strong&gt; of the collection. This is questionable, especially in case of an open source project. If you are interested in what exactly is collected and how to disable it Florian wrote and &lt;a href="https://florian-martens.medium.com/how-to-stop-your-next-js-app-from-sending-telemetry-data-to-vercel-cf499c773f94" rel="noopener noreferrer"&gt;insightful post&lt;/a&gt; about it on Medium.&lt;/p&gt;

&lt;h2&gt;
  
  
  Do you want to learn more &lt;em&gt;less-known facts&lt;/em&gt; and &lt;em&gt;behind-the-scenes&lt;/em&gt; about Next.js?
&lt;/h2&gt;

&lt;p&gt;Then check out my complete &lt;a href="https://www.fullcontextdevelopment.com/blog/next-full-context-review" rel="noopener noreferrer"&gt;Full Context Next.js Review&lt;/a&gt; which goes into waaay more detail. It's long (&lt;em&gt;the table of contents help&lt;/em&gt;), by now is a bit outdated as it's about v.12 but I'm sure there's a lot you would find interesting, relevant and useful.&lt;/p&gt;




&lt;p&gt;I also post similarly insightful articles on my &lt;a href="https://fullctxdev.substack.com/" rel="noopener noreferrer"&gt;Substack&lt;/a&gt; page and newsletter.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvyrkoofy5ny8868d6jz7.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvyrkoofy5ny8868d6jz7.jpg" alt="Substack newsletter cover image" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>gratitude</category>
    </item>
  </channel>
</rss>
