<?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: Ziad Alzarka</title>
    <description>The latest articles on DEV Community by Ziad Alzarka (@ziadalzarka).</description>
    <link>https://dev.to/ziadalzarka</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%2F513421%2F26495521-6590-460e-bbe0-254028647e01.jpeg</url>
      <title>DEV Community: Ziad Alzarka</title>
      <link>https://dev.to/ziadalzarka</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ziadalzarka"/>
    <language>en</language>
    <item>
      <title>React Image Gallery with Masonry.js</title>
      <dc:creator>Ziad Alzarka</dc:creator>
      <pubDate>Fri, 20 Nov 2020 08:24:57 +0000</pubDate>
      <link>https://dev.to/ziadalzarka/create-react-image-gallery-with-masonry-js-2jba</link>
      <guid>https://dev.to/ziadalzarka/create-react-image-gallery-with-masonry-js-2jba</guid>
      <description>&lt;p&gt;Creating a responsive image gallery like Google Photos on the web has always been a mystery to me, but &lt;a href="https://masonry.desandro.com/" rel="noopener noreferrer"&gt;Masonry.js&lt;/a&gt; offers a really easy and convenient way to add image galleries to your website whether you are using Vanilla JavaScript or an SPA like React.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Google Photos&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthetuteur.com%2Fwp-content%2Fuploads%2F2020%2F11%2Fgoogle-photos.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthetuteur.com%2Fwp-content%2Fuploads%2F2020%2F11%2Fgoogle-photos.png" title="Google photos example" alt="google photos"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Masonry&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fxuopled%2Freact-responsive-masonry%2FHEAD%2Fdemo%2Fsrc%2Fexample.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fxuopled%2Freact-responsive-masonry%2FHEAD%2Fdemo%2Fsrc%2Fexample.gif" title="Masonry example" alt="masonry example"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Masonry is a JavaScript library for the web. It allows you to create beautiful seamless responsive image galleries. We are using a React implementation &lt;a href="https://www.npmjs.com/package/react-responsive-masonry" rel="noopener noreferrer"&gt;&lt;code&gt;react-responsive-masonry&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;It is a very lightweight library that adds to your bundle 1.5KB of minified and gzipped JavaScript.&lt;/p&gt;

&lt;h2&gt;
  
  
  React Image Gallery Example
&lt;/h2&gt;

&lt;p&gt;Masonry uses flexbox under the hood which makes it very easy to use and you only need one line of CSS to get it to work.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Make images fit their container&lt;/strong&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;

&lt;span class="nt"&gt;img&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100%&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;Masonry React component&lt;/strong&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Masonry&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react-responsive-masonry&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Masonry&lt;/span&gt; &lt;span class="nx"&gt;columnsCount&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;gutter&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;4&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;{&lt;/span&gt;&lt;span class="nx"&gt;images&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;image&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;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;img&lt;/span&gt; &lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;image&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;))}&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Masonry&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;CodePen example&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;See the Pen &lt;a href="https://codepen.io/ziad-alzarka/pen/abZrMNo" rel="noopener noreferrer"&gt;React Image Gallery with Masonry.js&lt;/a&gt; by Ziad Alzarka&lt;br&gt;
  (&lt;a href="https://codepen.io/ziad-alzarka" rel="noopener noreferrer"&gt;@ziad-alzarka&lt;/a&gt;) on &lt;a href="https://codepen.io" rel="noopener noreferrer"&gt;CodePen&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Going Responsive
&lt;/h2&gt;

&lt;p&gt;Masonry is designed to be responsive and it is very easy to add breakpoints to the masonry component.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;columnsCountBreakPoints&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="mi"&gt;350&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;750&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;900&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ResponsiveMasonry&lt;/span&gt; &lt;span class="nx"&gt;columnsCountBreakPoints&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;columnsCountBreakPoints&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Masonry&lt;/span&gt; &lt;span class="nx"&gt;gutter&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;4&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;{&lt;/span&gt;&lt;span class="nx"&gt;images&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;image&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;(&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;img&lt;/span&gt; &lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;image&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="p"&gt;))}&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Masonry&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/ResponsiveMasonry&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;CodePen example&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;See the Pen &lt;a href="https://codepen.io/ziad-alzarka/pen/WNxBmyY" rel="noopener noreferrer"&gt;React Responsive Image Gallery with Masonry.js&lt;/a&gt; by Ziad Alzarka&lt;br&gt;
  (&lt;a href="https://codepen.io/ziad-alzarka" rel="noopener noreferrer"&gt;@ziad-alzarka&lt;/a&gt;) on &lt;a href="https://codepen.io" rel="noopener noreferrer"&gt;CodePen&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The article was originally published on my blog &lt;a href="https://thetuteur.com/react-image-gallery-with-masonry-js" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Feel free to follow me on &lt;a href="https://twitter.com/ziad_alzarka" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt;. Hope I could help!&lt;/p&gt;

</description>
      <category>react</category>
      <category>html</category>
      <category>css</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Optimize React Apps PageSpeed Insights Score</title>
      <dc:creator>Ziad Alzarka</dc:creator>
      <pubDate>Sat, 14 Nov 2020 12:16:19 +0000</pubDate>
      <link>https://dev.to/ziadalzarka/optimize-react-apps-pagespeed-insights-score-40o4</link>
      <guid>https://dev.to/ziadalzarka/optimize-react-apps-pagespeed-insights-score-40o4</guid>
      <description>&lt;h3&gt;
  
  
  What we will be working on
&lt;/h3&gt;

&lt;p&gt;We will be working on optimizing the website of the company I work for &lt;code&gt;coatconnect.com&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://developers.google.com/speed/pagespeed/insights/" rel="noopener noreferrer"&gt;PageSpeed Insights&lt;/a&gt; is a very powerful tool by Google. It allows us to analyze our website's performance and figure out ways we can improve it.&lt;/p&gt;

&lt;p&gt;The problem with SPAs (Single-Page Applications) is that they show content after loading JavaScript chunks first, so it takes a little while on the client before it can actually render content and that can destroy PageSpeed Insights score.&lt;/p&gt;

&lt;p&gt;Our app has to be an SSR (Server-Side Rendered) app. We are using React for this project, but really you can use any framework you like, the same concepts apply. This is a framework-agnostic article. It works with:&lt;/p&gt;

&lt;p&gt;You can go about this in a lot of different ways. You can use:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;React and Express (which I'm using)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://nextjs.org/" rel="noopener noreferrer"&gt;Next.js&lt;/a&gt; for React&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://nuxtjs.org/" rel="noopener noreferrer"&gt;Nuxt.js&lt;/a&gt; for Vue&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://sapper.svelte.dev/" rel="noopener noreferrer"&gt;Sapper&lt;/a&gt; for Svelte&lt;/li&gt;
&lt;li&gt;&lt;a href="https://angular.io/guide/universal" rel="noopener noreferrer"&gt;Angular Universal&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.gatsbyjs.com/" rel="noopener noreferrer"&gt;Gatsby&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://jamstack.org/" rel="noopener noreferrer"&gt;JAM Stack&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;...etc&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here's is the final architecture we'll be using:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthetuteur.com%2Fwp-content%2Fuploads%2F2020%2F11%2Farchitecture.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthetuteur.com%2Fwp-content%2Fuploads%2F2020%2F11%2Farchitecture.png" alt="architecture"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Score before optimization (Mobile)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthetuteur.com%2Fwp-content%2Fuploads%2F2020%2F11%2Fcoatconnect-live-performance.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthetuteur.com%2Fwp-content%2Fuploads%2F2020%2F11%2Fcoatconnect-live-performance.png" alt="mobile score before optimization"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Score before optimization (Desktop)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthetuteur.com%2Fwp-content%2Fuploads%2F2020%2F11%2Fcoatconnect-live-performance-desktop.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthetuteur.com%2Fwp-content%2Fuploads%2F2020%2F11%2Fcoatconnect-live-performance-desktop.png" alt="desktop score before optimization"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We notice there are some major problems that PageSpeed Insights has uncovered for us right out of the box.&lt;/p&gt;

&lt;h3&gt;
  
  
  Remove unused JavaScript
&lt;/h3&gt;

&lt;p&gt;This can be a tough task for SPAs and a general problem in all frameworks, however, I will only be talking about React, but the same concepts apply in all frameworks.&lt;/p&gt;

&lt;h4&gt;
  
  
  Bundlephobia
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://bundlephobia.com/" rel="noopener noreferrer"&gt;Bundlephobia&lt;/a&gt; is a great tool for analyzing bundle sizes of packages you install with NPM.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Moment.js&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.npmjs.com/package/moment" rel="noopener noreferrer"&gt;&lt;code&gt;moment&lt;/code&gt;&lt;/a&gt; is a huge library with a large bundle size compared to its alternative &lt;a href="https://www.npmjs.com/package/dayjs" rel="noopener noreferrer"&gt;&lt;code&gt;dayjs&lt;/code&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthetuteur.com%2Fwp-content%2Fuploads%2F2020%2F11%2Fmoment-bundle.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthetuteur.com%2Fwp-content%2Fuploads%2F2020%2F11%2Fmoment-bundle.png" alt="moment bundlephobia"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Day.js&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthetuteur.com%2Fwp-content%2Fuploads%2F2020%2F11%2Fdayjs-bundle.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthetuteur.com%2Fwp-content%2Fuploads%2F2020%2F11%2Fdayjs-bundle.png" alt="dayjs bundlephobia"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Lazy load components
&lt;/h4&gt;

&lt;p&gt;Since we're using Express and React, we can use &lt;a href="https://www.npmjs.com/package/react-universal-component" rel="noopener noreferrer"&gt;&lt;code&gt;react-universal-component&lt;/code&gt;&lt;/a&gt; to split the app into chunks and lazy-load them accordingly.&lt;/p&gt;

&lt;p&gt;But really, you can use any framework or any library you want!&lt;/p&gt;

&lt;h3&gt;
  
  
  Reduce initial server response time (TTFB)
&lt;/h3&gt;

&lt;p&gt;We'll start with the easy one. High TTFB (Time-To-First-Byte) could be caused by a lot of different factors:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Server resources are low&lt;/li&gt;
&lt;li&gt;Static pages are not cached&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The first problem is obvious, we just need to upgrade the server to handle more traffic, but before we do that, let's make sure our pages are properly cached first!&lt;/p&gt;

&lt;p&gt;You can use any method you like when caching static pages, you can cache using a CDN like Cloudflare or AWS Cloudfront.&lt;/p&gt;

&lt;p&gt;If your website's cache policy depends on custom parameters, you can implement your own caching layer above the SSR middleware in React.&lt;/p&gt;

&lt;p&gt;Here at CoatConnect, we cache based on different parameters, for example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;User's language&lt;/li&gt;
&lt;li&gt;Currency based on the user's location&lt;/li&gt;
&lt;li&gt;Device type (mobile, tablet, or desktop)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Add cache key generator middleware&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This middleware generates a unique cache key for each different version of the website. It looks different on mobile than it does on desktop and it has different data for users based in the USA than people in the Middle East for example.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cacheMiddleware&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;next&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;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;}${&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;currency&lt;/span&gt;&lt;span class="p"&gt;}${&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;initialLanguage&lt;/span&gt;&lt;span class="p"&gt;}${&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;deviceType&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&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;cacheKey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;md5&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cacheKey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;cacheKey&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;We can later use this cache key to store the resulting HTML in memory or in files. We can use &lt;code&gt;node-cache&lt;/code&gt; for that.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cacheHolder&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;NodeCache&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;stdTTL&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3600&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;checkperiod&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;600&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;useClones&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cacheHTML&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;html&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;{&lt;/span&gt;
  &lt;span class="nx"&gt;cacheHolder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;html&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;We can call this &lt;code&gt;cacheHTML&lt;/code&gt; method, and pass it the &lt;code&gt;cacheKey&lt;/code&gt; and rendered HTML. We can also store different cache keys under the same request path to be able to invalidate the cache whenever the data changes.&lt;/p&gt;

&lt;h3&gt;
  
  
  Defer offscreen images
&lt;/h3&gt;

&lt;p&gt;When you open a website that has &lt;code&gt;img&lt;/code&gt; tags in it, the browser goes ahead and fetches all these images and the document will be loaded when all the images are downloaded.&lt;/p&gt;

&lt;p&gt;Most of the time we have images that the user does not see until they scroll down the page. Those images must be lazy-loaded to avoid big load times on websites. For that, we will use &lt;a href="https://www.npmjs.com/package/react-lazy-load-image-component" rel="noopener noreferrer"&gt;&lt;code&gt;react-lazy-load-image-component&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This component is very easy to use, you just use it like you would use a normal &lt;code&gt;img&lt;/code&gt; tag:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&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="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="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;LazyLoadImage&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-lazy-load-image-component&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;MyImage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;image&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;(&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;LazyLoadImage&lt;/span&gt;
      &lt;span class="nx"&gt;alt&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;image&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;alt&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;image&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;image&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="c1"&gt;// use normal &amp;lt;img&amp;gt; attributes as props&lt;/span&gt;
      &lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;image&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;span&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;image&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;caption&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/span&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;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;MyImage&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  Minimize main thread work
&lt;/h3&gt;

&lt;p&gt;Figuring out what's blocking the main thread can be a tough task, but here are common problems:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Whole page is hydrated while loading&lt;/li&gt;
&lt;li&gt;Third-party scripts are not deferred&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One of the ways to optimize blocking time is to lazy hydrate the page, and for that we will use &lt;a href="https://www.npmjs.com/package/react-lazy-hydration" rel="noopener noreferrer"&gt;&lt;code&gt;react-lazy-hydration&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;SSR Only&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This option should be used with static content that never changes on the page with JavaScript because, &lt;em&gt;ssrOnly&lt;/em&gt; skips hydration all-together.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&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="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;LazyHydrate&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react-lazy-hydration&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="nf"&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;LazyHydrate&lt;/span&gt; &lt;span class="nx"&gt;ssrOnly&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;{...}&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/LazyHydrate&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;When Idle&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Please keep in mind that this step is very important for the &lt;a href="https://web.dev/lcp/" rel="noopener noreferrer"&gt;&lt;strong&gt;LCP&lt;/strong&gt;&lt;/a&gt; too. &lt;a href="https://web.dev/lcp/" rel="noopener noreferrer"&gt;&lt;strong&gt;LCP&lt;/strong&gt;&lt;/a&gt; is calculated after the dom has stopped shifting and changing, so instantly hydrating the part the user sees on the screen first is very important to avoid big &lt;a href="https://web.dev/lcp/" rel="noopener noreferrer"&gt;&lt;strong&gt;LCP&lt;/strong&gt;&lt;/a&gt; time.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;LazyHydrate&lt;/span&gt; &lt;span class="nx"&gt;whenIdle&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;{...}&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/LazyHydrate&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;When Visible&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You have to mark every part on the page that the user does not see instantly as &lt;em&gt;whenVisible&lt;/em&gt; to avoid blocking the DOM while hydrating these parts.&lt;/p&gt;

&lt;p&gt;One of the reasons we had issues at &lt;a href="https://coatconnect.com" rel="noopener noreferrer"&gt;CoatConnect&lt;/a&gt; is that we had &lt;em&gt;Google Maps&lt;/em&gt; on some of our pages and the Google Maps scripts were loaded and executed alongside our code while the page was being hydrated which destroyed our blocking time, so it is very important to use &lt;code&gt;whenVisible&lt;/code&gt; with the parts on the page that the user does not see instantly.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;LazyHydrate&lt;/span&gt; &lt;span class="nx"&gt;whenVisible&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;{...}&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/LazyHydrate&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Make sure every third-party script added and all JavaScript chunks are &lt;a href="https://www.w3schools.com/tags/att_script_defer.asp" rel="noopener noreferrer"&gt;deferred&lt;/a&gt;.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;

&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"[some-third-party-script].js"&lt;/span&gt; &lt;span class="na"&gt;defer&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"[some-chunk].[hash].js"&lt;/span&gt; &lt;span class="na"&gt;defer&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  Avoid redirects at all costs
&lt;/h3&gt;

&lt;p&gt;Redirects cause a delay in page load and whatever that delay maybe every millisecond matters! If a delay in page redirect is 300ms, that's 300ms you could save on page load time.&lt;/p&gt;

&lt;p&gt;If you are using a URL shortener for assets especially images, that's a 300ms delay on each image and sometimes that image could be your &lt;a href="https://web.dev/lcp/" rel="noopener noreferrer"&gt;&lt;strong&gt;LCP&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Load CSS asynchronously
&lt;/h3&gt;

&lt;p&gt;CSS is a pretty expensive asset that can block the main UI thread. To prevent CSS from blocking the main UI thread we have to do two things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Load CSS asynchronously&lt;/li&gt;
&lt;li&gt;Generate our critical path CSS&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can load CSS asynchronously using JavaScript like this:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;

&lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"CSS_ASSET"&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"stylesheet"&lt;/span&gt; &lt;span class="na"&gt;media=&lt;/span&gt;&lt;span class="s"&gt;"print"&lt;/span&gt; &lt;span class="na"&gt;onload=&lt;/span&gt;&lt;span class="s"&gt;"this.media='all';this.onload=null;"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Adding this &lt;code&gt;onload="this.media='all';this.onload=null;"&lt;/code&gt; will cause CSS to load asynchronously preventing it from blocking the main thread, but doing that would make our website with no styles at all until the CSS loads and cause &lt;a href="https://web.dev/cls/" rel="noopener noreferrer"&gt;&lt;strong&gt;CLS&lt;/strong&gt;&lt;/a&gt; and delay of &lt;a href="https://web.dev/lcp/" rel="noopener noreferrer"&gt;&lt;strong&gt;LCP&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Critical Path CSS
&lt;/h3&gt;

&lt;p&gt;To optimize for a high &lt;a href="https://web.dev/lcp/" rel="noopener noreferrer"&gt;&lt;strong&gt;LCP&lt;/strong&gt;&lt;/a&gt; score, we have to show styled content on the screen as fast as possible and not wait for external CSS or for JavaScript to edit the DOM.&lt;/p&gt;

&lt;p&gt;Here's the content we want to show to the user eventually:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;JavaScript Enabled&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthetuteur.com%2Fwp-content%2Fuploads%2F2020%2F11%2Fjs-css.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthetuteur.com%2Fwp-content%2Fuploads%2F2020%2F11%2Fjs-css.png" alt="coatconnect"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Previously, we made CSS load asynchronously using JavaScript. Now, let's try disabling your JavaScript.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Open the Inspector (Ctrl+Shift+I)&lt;/li&gt;
&lt;li&gt;Hit Ctrl+P&lt;/li&gt;
&lt;li&gt;Type in &lt;code&gt;&amp;gt; Disable JavaScript&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthetuteur.com%2Fwp-content%2Fuploads%2F2020%2F11%2Fdisable-javascript.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthetuteur.com%2Fwp-content%2Fuploads%2F2020%2F11%2Fdisable-javascript.png" alt="disable javascript"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;JavaScript Disabled (No CSS)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Since we load CSS using JavaScript, CSS is not loaded, and as you can see, the page does not have any styles at all!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthetuteur.com%2Fwp-content%2Fuploads%2F2020%2F11%2Fno-js-no-css.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthetuteur.com%2Fwp-content%2Fuploads%2F2020%2F11%2Fno-js-no-css.png" alt="javascript disabled"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To fix that, we need to generate the Critical Path CSS (CCSS). It is basically the CSS needed to only render what the user sees on the screen first.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;JavaScript disabled (CCSS)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You can see here that the page has the &lt;em&gt;critical&lt;/em&gt; CSS on it without the need of downloading the full CSS stylesheet or JavaScript. As a matter of fact, there are images that are not shown here because they are lazy-loaded and JavaScript is not enabled.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthetuteur.com%2Fwp-content%2Fuploads%2F2020%2F11%2Fccss-no-js.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthetuteur.com%2Fwp-content%2Fuploads%2F2020%2F11%2Fccss-no-js.png" alt="critical path css"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To generate CCSS, you can use the npm package &lt;a href="https://www.npmjs.com/package/critical" rel="noopener noreferrer"&gt;&lt;code&gt;critical&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="c1"&gt;// eslint-disable-next-line prefer-const&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;html&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;uncritical&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;critical&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;generate&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;base&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;build/public&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// Local path to public assets&lt;/span&gt;
  &lt;span class="na"&gt;html&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;renderedHTML&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// Result of Server-Side rendered code&lt;/span&gt;
  &lt;span class="na"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;viewPort&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// User's device view port&lt;/span&gt;
  &lt;span class="na"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;viewPort&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// User's device view port&lt;/span&gt;
  &lt;span class="na"&gt;inline&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// Inlines css to improve performance&lt;/span&gt;
  &lt;span class="na"&gt;minify&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// Minifies css put into the &amp;lt;style&amp;gt; tag in the head&lt;/span&gt;
  &lt;span class="na"&gt;rebase&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;asset&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;...,&lt;/span&gt; &lt;span class="c1"&gt;// Post process paths to assets in your css e.g. images, fonts, ...etc&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;Getting the viewport of the user&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We can use the &lt;code&gt;User-Agent&lt;/code&gt; header to detect which type of device the user is using and we can use the npm package &lt;a href="https://www.npmjs.com/package/mobile-detect" rel="noopener noreferrer"&gt;&lt;code&gt;mobile-detect&lt;/code&gt;&lt;/a&gt; for that.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;MobileDetect&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;mobile-detect&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getDeviceType&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;md&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;MobileDetect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;user-agent&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;md&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;tablet&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;tablet&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="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;md&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mobile&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;mobile&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="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;desktop&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;We can then use this express middleware to inject &lt;code&gt;viewPort&lt;/code&gt; property in the request.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;deviceTypeMiddleware&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;next&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;{&lt;/span&gt;
  &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;deviceType&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getDeviceType&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;viewPort&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;mobile&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;414&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;896&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;tablet&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;768&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1024&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;desktop&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1366&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;842&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;}[&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;deviceType&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
  &lt;span class="nf"&gt;next&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;Width and height for mobile, tablet, and desktop are referenced online from this &lt;a href="https://www.hobo-web.co.uk/best-screen-size/" rel="noopener noreferrer"&gt;article&lt;/a&gt; and personal experience.&lt;/p&gt;

&lt;p&gt;This critical path CSS generator does not require you to use express for server-side rendering your app. It can sit in the middle between your server and your clients and act as a cache layer.&lt;/p&gt;

&lt;p&gt;The article was originally published on my blog &lt;a href="https://thetuteur.com/optimize-react-apps-pagespeed-insights-score/" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Feel free to follow me on &lt;a href="https://twitter.com/ziad_alzarka" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt;. Hope I could help!&lt;/p&gt;

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