<?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: Meet Dave</title>
    <description>The latest articles on DEV Community by Meet Dave (@meetdave3).</description>
    <link>https://dev.to/meetdave3</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%2F310723%2F3ca70801-0c70-421c-b646-8272a7747a2d.jpeg</url>
      <title>DEV Community: Meet Dave</title>
      <link>https://dev.to/meetdave3</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/meetdave3"/>
    <language>en</language>
    <item>
      <title>domstat - A Puppeteer based CLI tool to check web performance</title>
      <dc:creator>Meet Dave</dc:creator>
      <pubDate>Tue, 02 Aug 2022 14:30:00 +0000</pubDate>
      <link>https://dev.to/meetdave3/domstat-a-puppeteer-based-cli-tool-to-check-web-performance-37bf</link>
      <guid>https://dev.to/meetdave3/domstat-a-puppeteer-based-cli-tool-to-check-web-performance-37bf</guid>
      <description>&lt;p&gt;domstat is a &lt;a href="https://github.com/puppeteer/puppeteer" rel="noopener noreferrer"&gt;Puppeteer&lt;/a&gt; based CLI tool that runs locally and checks for webpage performance statistics. &lt;/p&gt;

&lt;p&gt;Domstat consolidates select Chrome dev tools statistics at one place and gives a bird's eye overview on how a webpage performed at runtime. &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%2Fi.ibb.co%2FNsFkC54%2FScreenshot-2022-06-26-at-00-07-39.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%2Fi.ibb.co%2FNsFkC54%2FScreenshot-2022-06-26-at-00-07-39.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/meetdave3/domstat" rel="noopener noreferrer"&gt;Source code&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To run this, you should have node &amp;amp; npm installed on your machine. You can do so by &lt;a href="https://nodejs.org/en/download/" rel="noopener noreferrer"&gt;downloading node.js&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Using npm&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm i &lt;span class="nt"&gt;-g&lt;/span&gt; domstat 
domstat &lt;span class="nt"&gt;--url&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;example.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Alternatively, using npx&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx domstat &lt;span class="nt"&gt;--url&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;example.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Plot
&lt;/h1&gt;

&lt;p&gt;domstat parses the browser-level API numbers like DOM user timings &amp;amp; code coverage. Similar to httpstat for cURL related information.&lt;/p&gt;

&lt;p&gt;domstat also takes inspiration from &lt;a href="https://web.dev/critical-rendering-path-measure-crp/#navigation-timing" rel="noopener noreferrer"&gt;this web.dev article&lt;/a&gt; which gives an in-detail explanation about measuring critical rendering path using the Navigation Timing API.&lt;/p&gt;

&lt;h1&gt;
  
  
  How does domstat help?
&lt;/h1&gt;

&lt;p&gt;Let's take a look at a scenario where we want to check and compare the dom timings &amp;amp; coverage for different websites.&lt;/p&gt;

&lt;p&gt;Below are the domstats for optimised "movies" web application in different frameworks. You can find the repositories on &lt;a href="https://github.com/orgs/tastejs/repositories" rel="noopener noreferrer"&gt;https://github.com/orgs/tastejs/repositories&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Angular: &lt;br&gt;
&lt;a href="https://media.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%2Fiqe2ig5xh3wyk0v79052.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fiqe2ig5xh3wyk0v79052.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next.js: &lt;br&gt;
&lt;a href="https://media.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%2F9gw4g89iqtztp06c415e.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9gw4g89iqtztp06c415e.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Nuxt:&lt;br&gt;
 &lt;a href="https://media.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%2F61roalqok4hrrv6wf01f.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F61roalqok4hrrv6wf01f.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;All of the above movies web application score a 90+ on Lighthouse / Pagespeed audit, domstat on the other hand leverages the browser's API and helps further by giving insights about the loading behaviour. &lt;/p&gt;

&lt;p&gt;These statistics are available on the Chrome's devtools but they aren't consolidated at one place. Example: The CSS &amp;amp; JS coverage statistics are present in the &lt;a href="https://developer.chrome.com/docs/devtools/coverage/" rel="noopener noreferrer"&gt;Sources tab&lt;/a&gt;, to get the DOM timings, you need to run the Performance audit from the &lt;a href="https://developer.chrome.com/docs/devtools/evaluate-performance/" rel="noopener noreferrer"&gt;Performance tab&lt;/a&gt; and so on. &lt;/p&gt;

&lt;p&gt;Domstat consolidates all these numbers at one place and gives a bird's eye overview on how the webpage performed. &lt;/p&gt;

&lt;p&gt;By default the tests don't have cpu or network throttling yet but I wish to add more such flags soon.&lt;/p&gt;

&lt;h1&gt;
  
  
  Building the CLI
&lt;/h1&gt;

&lt;p&gt;The CLI is built using React. Yes, React! Seems that React can do a lot of things. From Desktop apps with Electron to a fullstack app with Next.js.&lt;/p&gt;

&lt;p&gt;I used &lt;a href="https://github.com/vadimdemedes/create-ink-app" rel="noopener noreferrer"&gt;create-ink-app&lt;/a&gt; to build the CLI tool. The create-ink-app spins up a basic project structure for Ink apps and lets you avoid the boilerplate and get to building beautiful CLIs in no time.&lt;/p&gt;

&lt;p&gt;Checkout &lt;a href="https://www.npmjs.com/package/ink" rel="noopener noreferrer"&gt;ink&lt;/a&gt; to know more about writing CLI tools with React :) &lt;/p&gt;

&lt;h1&gt;
  
  
  Closing notes
&lt;/h1&gt;

&lt;p&gt;I've been using the Chrome DevTools to check site's performance, running tests to check and compare runtime performance of different pages. &lt;/p&gt;

&lt;p&gt;This CLI tool is a step closer to knowing the APIs well, the tools gives quick insights and saves the hassle of clicking around the already overwhelming browser's dev tools.&lt;/p&gt;

&lt;p&gt;There's a good potential for improving the tool further &amp;amp; if you're familiar with the Node.js ecosystem and React, you're most welcome to contribute to make this better. &lt;/p&gt;

&lt;p&gt;The goal isn't to make another lighthouse like tool, but only to consolidate the important scattered statistics from the browser's API at one place, using one command. &lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>webperf</category>
      <category>npm</category>
    </item>
    <item>
      <title>Extending Next.js' &lt;Image /&gt; component to improve UX</title>
      <dc:creator>Meet Dave</dc:creator>
      <pubDate>Mon, 22 Nov 2021 14:09:55 +0000</pubDate>
      <link>https://dev.to/meetdave3/extending-nextjs-component-to-improve-ux-415j</link>
      <guid>https://dev.to/meetdave3/extending-nextjs-component-to-improve-ux-415j</guid>
      <description>&lt;p&gt;If you have worked on Next.js, it's a good chance that you might have ended up using the &lt;strong&gt;Image&lt;/strong&gt; component. &lt;/p&gt;

&lt;p&gt;While the Next's Image component already has a lot of built in features like blurring placeholder images when the images are loading or controlling image quality to improve the UX. &lt;/p&gt;

&lt;p&gt;In this article, we explore extending the Next's image component to improve the end user experience alternatively. &lt;/p&gt;

&lt;h2&gt;
  
  
  Plot
&lt;/h2&gt;

&lt;p&gt;Here we address 2 main states when serving images&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Loading state
&lt;/h3&gt;

&lt;p&gt;Lazy loading images contributes to better UX since it helps in reducing the load time among other things, however, to improve it one step further we add something like an intermediate form of display until the image loads. For example, spinner or a skeleton loader&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Errored state
&lt;/h3&gt;

&lt;p&gt;What happens if the image url is incorrect or if the image service API is down for some reason? It would be ideal to have a fallback image so the end user has a seamless experience and doesn't end up seeing something like this. &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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6s4glcpnb84c2lbpsv4p.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6s4glcpnb84c2lbpsv4p.png" alt="Broken image example"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;When using Next.js' Image component, it is important to wire it up with a fallback image because of &lt;a href="https://nextjs.org/docs/api-reference/next/image#domains" rel="noopener noreferrer"&gt;domains&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;After we've taken care of these 2 states, the solution ends up looking like this:&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5vsmlr2y45eyjnposn5q.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5vsmlr2y45eyjnposn5q.png" alt="Image description"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;h2&gt;
  
  
  ImageWithState
&lt;/h2&gt;

&lt;p&gt;Let's dive in and extend the Next.js'  component to further support the aforementioned states.&lt;/p&gt;

&lt;p&gt;Starting with the main imports&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&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="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Image&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ImageProps&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;next/image&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;Now, we create a React component that simply extends the Next's Image component &amp;amp; also the types&lt;/p&gt;

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


&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;ImageWithStateProps&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ImageProps&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;ImageWithState&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ImageWithStateProps&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;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Image&lt;/span&gt; &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;props&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;}&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;So far, we've done nothing other than adding a transparent abstraction over the Image component. The component &lt;strong&gt;ImageWithState&lt;/strong&gt; will work same as Next's &lt;strong&gt;Image&lt;/strong&gt;, only that the component name is different.&lt;/p&gt;

&lt;p&gt;Let's now introduce the states&lt;/p&gt;

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


&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;ImageWithState&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ImageWithStateProps&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;loading&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setLoading&lt;/span&gt;&lt;span class="p"&gt;]&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="nf"&gt;useState&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="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;onErrorSrc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setOnErrorSrc&lt;/span&gt;&lt;span class="p"&gt;]&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;useState&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;undefined&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;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Image&lt;/span&gt; &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;props&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;}&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;When the component mounts, &lt;code&gt;loading&lt;/code&gt; is set to true by default as the image would start loading&lt;/p&gt;

&lt;p&gt;The onErrorSrc prop is the source url for the &lt;code&gt;fallback&lt;/code&gt; image. The fallback image appears when the Image component throws an error. Let's go ahead and create the function to handle the errored state&lt;/p&gt;

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


 &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;handleOnError&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&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;SyntheticEvent&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;HTMLImageElement&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Event&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;currentTarget&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="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fallback&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nf"&gt;setOnErrorSrc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fallback&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;



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

&lt;/div&gt;

&lt;p&gt;This is triggered by the onError event &lt;/p&gt;

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

&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Image&lt;/span&gt; &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;onError&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;handleOnError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&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;gt;&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;The handleOnError function is called when the  component would error. In that case we change the &lt;code&gt;src&lt;/code&gt; prop of the element to the fallback image. &lt;/p&gt;

&lt;p&gt;Now, we manage the loading state&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&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;style&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;relative&lt;/span&gt;&lt;span class="dl"&gt;"&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;gt;&lt;/span&gt;
      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;loading&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;SkeletonLoader&lt;/span&gt;
          &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;absolute&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;zIndex&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;debug&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;true&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="mi"&gt;99&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;auto&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
          &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="na"&gt;height&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="na"&gt;width&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;width&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;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Image&lt;/span&gt;
        &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;onErrorSrc&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="na"&gt;onLoadingComplete&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&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="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;debug&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nf"&gt;setLoading&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="si"&gt;}&lt;/span&gt;
        &lt;span class="na"&gt;onError&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;handleOnError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&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;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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;To represent the loading state, I have used SkeletonLoader component. Feel free to use any other loading indicators like spinners or splash based on your use case. &lt;/p&gt;

&lt;p&gt;Furthermore, there is a &lt;code&gt;debug&lt;/code&gt; prop which can be helpful when developing &amp;amp; styling to check if the loading indicators are styled appropriately. &lt;/p&gt;

&lt;p&gt;Mostly images are served from disk cache, in that case it becomes difficult to replicate a "loading" state for an image while developing. In such a situation, enabling the debug prop would provide a much efficient dev workflow than network throttling via the browser's dev tools.&lt;/p&gt;

&lt;p&gt;If you haven't noticed yet, we pass the same &lt;code&gt;height&lt;/code&gt; and &lt;code&gt;width&lt;/code&gt; prop to the skeleton loader. This also further helps in avoiding layout shift as the space will be preserved for the image.&lt;/p&gt;

&lt;p&gt;Finally, updating the type &lt;/p&gt;


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

&lt;p&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;ImageWithStateProps&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ImageProps&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;br&gt;
  &lt;span class="na"&gt;fallback&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;br&gt;
  &lt;span class="nl"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;br&gt;
&lt;span class="p"&gt;};&lt;/span&gt;&lt;/p&gt;

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

&lt;/div&gt;
&lt;h2&gt;
&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
  Usage&lt;br&gt;
&lt;/h2&gt;

&lt;p&gt;Using the wrapper component should be same as using the Next's Image component. &lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;ImageWithState&lt;/strong&gt; component added 2 extra props which are for the fallback image in case of an error &amp;amp; a debug prop to help us make sure that the skeleton loader displays appropriately&lt;/p&gt;

&lt;p&gt;Feel free to fork or play around this component on &lt;a href="https://codesandbox.io/s/next-image-with-state-f1icr" rel="noopener noreferrer"&gt;CodeSandbox&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can also visit &lt;a href="https://f1icr.csb.app/" rel="noopener noreferrer"&gt;https://f1icr.csb.app/&lt;/a&gt; to check out the working solution&lt;/p&gt;

&lt;h2&gt;
  
  
  Caveats
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Build size&lt;/strong&gt;: These changes, including adding the svg skeleton loader library which is &lt;code&gt;react-skeleton-loader&lt;/code&gt; adds approximately 5kB to your production build. But keep in mind that this component is reusable across your entire app so the build size won't bloat up further &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Web vitals&lt;/strong&gt;: Next's Image component loads the images lazily by default. If you're loading the images &lt;a href="https://www.abtasty.com/blog/above-the-fold/" rel="noopener noreferrer"&gt;above the fold&lt;/a&gt;, remember to pass the &lt;a href="https://nextjs.org/docs/api-reference/next/image#priority" rel="noopener noreferrer"&gt;priority&lt;/a&gt; prop so the page doesn't lose out on &lt;a href="https://web.dev/lcp/" rel="noopener noreferrer"&gt;LCP&lt;/a&gt; points&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Blur&lt;/strong&gt;: It's possible to display a blurred image placeholder when the image is being loaded. This is supported by the &lt;code&gt;placeholder&lt;/code&gt; property on the Image component.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Unoptimized&lt;/strong&gt;: You may have seen an &lt;code&gt;unoptimized&lt;/code&gt; true prop passed to the Image component. This is because I haven't setup any &lt;a href="https://nextjs.org/docs/api-reference/next/image#loader" rel="noopener noreferrer"&gt;loader configuration&lt;/a&gt; for these images. Make sure to keep your images optimised and pass &lt;code&gt;srcSet&lt;/code&gt;, (now &lt;a href="https://nextjs.org/docs/api-reference/next/image#device-sizes" rel="noopener noreferrer"&gt;device sizes&lt;/a&gt; in Next.js) &amp;amp; responsive images in modern image formats!&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Presently, Next.js' Image component only supports displaying a &lt;code&gt;blurred&lt;/code&gt; placeholder when an image is being loaded, something like what you may have seen on medium.com.&lt;/p&gt;

&lt;p&gt;As one solution doesn't fit all use cases, this write-up represents an alternate way to wire up the Image component while still keeping the end user experience in mind.&lt;/p&gt;

</description>
      <category>nextjs</category>
      <category>javascript</category>
      <category>ux</category>
      <category>react</category>
    </item>
    <item>
      <title>CI/CD tooling for frontend projects using GitHub actions</title>
      <dc:creator>Meet Dave</dc:creator>
      <pubDate>Fri, 23 Apr 2021 09:58:41 +0000</pubDate>
      <link>https://dev.to/meetdave3/ci-cd-tooling-for-frontend-projects-using-github-actions-5998</link>
      <guid>https://dev.to/meetdave3/ci-cd-tooling-for-frontend-projects-using-github-actions-5998</guid>
      <description>&lt;p&gt;Setting up continuous integration pipelines for your frontend project can help you avoid bugs &amp;amp; filter out problems sneaking into production. &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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq4j1jod1u54ixc9htuw3.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq4j1jod1u54ixc9htuw3.png" alt="nathan-dumlao-eksqjXTLpak-unsplash"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Photo by Nathan &lt;a href="https://unsplash.com/@nate_dumlao?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Dumlao&lt;/a&gt; on &lt;a href="https://unsplash.com/?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Unsplash&lt;/a&gt;&lt;br&gt;
Filtering out the best for your end users 👆 &lt;/p&gt;

&lt;p&gt;Having CI/CD in your frontend project from the beginning can help in avoiding “broken windows“ in your project (ref: &lt;a href="https://blog.codinghorror.com/the-broken-window-theory/" rel="noopener noreferrer"&gt;broken window theory&lt;/a&gt;). &lt;/p&gt;

&lt;p&gt;Additionally, setting up the workflow can help &lt;strong&gt;significantly improve developer experience (DX) &amp;amp; user experience (UX)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A pipeline that is setup &lt;strong&gt;early&lt;/strong&gt; on in the project can help the team work with a unified purpose &amp;amp; set guidelines. &lt;/p&gt;

&lt;h2&gt;
  
  
  Plot
&lt;/h2&gt;

&lt;p&gt;This article demonstrates a continuous integration pipeline setup for a starter &lt;a href="https://nextjs.org" rel="noopener noreferrer"&gt;Next.js&lt;/a&gt; app deployed on &lt;a href="https://vercel.com" rel="noopener noreferrer"&gt;Vercel&lt;/a&gt; living on a Github repository. The pipeline makes use open-source Github actions from the &lt;a href="https://github.com/marketplace?type=actions" rel="noopener noreferrer"&gt;Github marketplace&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;The CI jobs runs synchronously. If a job fails, the process would exit.&lt;/p&gt;

&lt;p&gt;For this article I have chosen to setup the following jobs:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Linting (eslint + stylelint) - Helps with consistent DX&lt;/li&gt;
&lt;li&gt;Vercel deployment - Helps with deployment previews useful for CI&lt;/li&gt;
&lt;li&gt;Lighthouse budget checks - Helps in UX integrity &amp;amp; maintain consistency throughout the software lifecycle&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Additional jobs you can add in your CI pipeline: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/marketplace?type=actions&amp;amp;query=slack+notifications" rel="noopener noreferrer"&gt;Send slack notification&lt;/a&gt; if a job fails&lt;/li&gt;
&lt;li&gt;Run &lt;a href="https://docs.cypress.io/guides/continuous-integration/github-actions" rel="noopener noreferrer"&gt;Cypress tests&lt;/a&gt; / Jest tests against preview urls&lt;/li&gt;
&lt;li&gt;Setup semantic versioning / &lt;a href="https://github.com/semantic-release/semantic-release" rel="noopener noreferrer"&gt;semantic release&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you find yourself using something else than the options I have chosen above. Here are some reasons why I have opinionated myself with the selected tools for this example:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Why &lt;strong&gt;Next.js&lt;/strong&gt; instead of Angular, Nuxt.js, etc?&lt;br&gt;
Next.js gives flexibility to statically generate a page and / or use server side rendering. Smaller overall bundle size helps in achieving better UX.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Why &lt;strong&gt;Vercel&lt;/strong&gt; instead of AWS Amplify or Netlify, etc?&lt;br&gt;
Deployment previews! Each PR generates a deployment preview URL. Makes it easy and efficient to run E2E tests or Lighthouse checks against a preview URL. Also since I’m using Next.js.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Why &lt;strong&gt;Github&lt;/strong&gt; actions instead of Gitlab or Bitbucket, etc&lt;br&gt;
Ability to use and/or write open-source Github actions.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  1. Getting started
&lt;/h2&gt;

&lt;p&gt;In this example I’m setting up the CI pipeline for a boilerplate Next.js app.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;npx create-next-app&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;After the boilerplate next app is generated, I initialise the ESLint setup: &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;eslint —init&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;ESLint initialisation will take you through a set of questions and help you set up the correct lint rules for your project. It automatically generates the configuration file &amp;amp; installs the dependencies.&lt;/p&gt;

&lt;p&gt;For linting styles, I mainly prefer using &lt;a href="https://stylelint.io" rel="noopener noreferrer"&gt;stylelint&lt;/a&gt;, helps in enforcing css / scss conventions &amp;amp; avoid errors for stylesheets. Equivalent to using ESLint for Javascript files. Read more about &lt;a href="https://stylelint.io/user-guide/get-started" rel="noopener noreferrer"&gt;configuring stylelint&lt;/a&gt; for your frontend project.&lt;/p&gt;

&lt;p&gt;If you are writing styles in CSS-in-JS land, stylelint has a styled-components &lt;a href="https://styled-components.com/docs/tooling#stylelint" rel="noopener noreferrer"&gt;extension&lt;/a&gt; that you can configure as well :)&lt;/p&gt;

&lt;p&gt;Finally, add the lint check scripts inside the &lt;a href="https://github.com/snowballdigital/nextjs-tooling/blob/main/package.json#L9" rel="noopener noreferrer"&gt;package.json&lt;/a&gt; file so we can set it up with our CI pipeline next.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Creating the Github actions workflow
&lt;/h2&gt;

&lt;p&gt;To write the Github actions, we need to create &lt;strong&gt;&lt;em&gt;main.yml&lt;/em&gt;&lt;/strong&gt; workflow file inside &lt;strong&gt;.github/workflows/&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In this CI example we have 3 jobs in our workflow. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Lint source code (ESLint + Stylelint)&lt;/li&gt;
&lt;li&gt;If no lint errors then -&amp;gt; deploy on Vercel&lt;/li&gt;
&lt;li&gt;If deploy build is successful then -&amp;gt; run performance check with Lighthouse&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We get started by defining that the jobs should run whenever there is a &lt;strong&gt;PUSH&lt;/strong&gt; event on any branch. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;name: CI&lt;br&gt;
on: [push] &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Based on your use-case, you can also chose to have different events. Checkout the different &lt;a href="https://docs.github.com/en/actions/reference/events-that-trigger-workflows" rel="noopener noreferrer"&gt;events that trigger a workflow&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Setup the linting job
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;lint&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Begin linting&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v2&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;fetch-depth&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Use Node &lt;/span&gt;&lt;span class="m"&gt;12&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/setup-node@v1&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;node-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;12.x&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Use cached node_modules&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/cache@v2&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;node_modules&lt;/span&gt;
          &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nodeModules-${{ hashFiles('**/yarn.lock') }}&lt;/span&gt;
          &lt;span class="na"&gt;restore-keys&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
            &lt;span class="s"&gt;nodeModules-&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Install dependencies&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;yarn install --frozen-lockfile&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Run ESLint&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;yarn lint&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Run stylelint&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;yarn stylelint&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This job checks if the code / changes adhere to the lint rules. As you can see, the job checks for eslint and stylelint problems.&lt;/p&gt;

&lt;p&gt;To improve the DX and catch these lint issues while developing, it’s best to setup your IDE with the respective plugins. Since I use VSCode, here are the &lt;a href="https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint" rel="noopener noreferrer"&gt;eslint&lt;/a&gt; or &lt;a href="https://marketplace.visualstudio.com/items?itemName=stylelint.vscode-stylelint" rel="noopener noreferrer"&gt;stylelint&lt;/a&gt; plugins that I use. I also like to set up the &lt;strong&gt;format on save&lt;/strong&gt; in the VSCode &lt;a href="https://www.digitalocean.com/community/tutorials/linting-and-formatting-with-eslint-in-vs-code#step-4-%E2%80%94-formatting-on-save" rel="noopener noreferrer"&gt;settings.json&lt;/a&gt; file to &lt;strong&gt;automatically&lt;/strong&gt; format &amp;amp; fix all fixable problems when I hit save.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Generate deployment previews with Vercel
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;deploy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;needs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;lint&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v2&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;amondnet/vercel-action@v20&lt;/span&gt;
        &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;vercel-deployment&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;github-token&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.GH_TOKEN }}&lt;/span&gt;
          &lt;span class="na"&gt;vercel-token&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.VERCEL_TOKEN }}&lt;/span&gt;
          &lt;span class="na"&gt;vercel-org-id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.ORG_ID}}&lt;/span&gt;
          &lt;span class="na"&gt;vercel-project-id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.PROJECT_ID}}&lt;/span&gt;
          &lt;span class="na"&gt;vercel-project-name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;nextjs-tooling'&lt;/span&gt;
    &lt;span class="na"&gt;outputs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;preview-url&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ steps.vercel-deployment.outputs.preview-url }}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This job makes the use of the opensource GitHub action: &lt;a href="https://github.com/marketplace/actions/vercel-action" rel="noopener noreferrer"&gt;Vercel actions&lt;/a&gt;&lt;br&gt;
The opensource action makes it easy for us to generate Vercel deployments, whether they are preview deployments or production deployments. &lt;/p&gt;

&lt;p&gt;Here, we are also checking if the &lt;strong&gt;production build&lt;/strong&gt; succeeds or not since we are making a deployment. &lt;/p&gt;

&lt;p&gt;Using this action in the CI pipeline is better than setting up the Vercel for Github Integration, since the Github integration is asynchronous and runs independently of the pipeline state. &lt;/p&gt;

&lt;p&gt;Once the deployment is complete, &lt;a href="https://nextjs.org/docs/deployment#dps-develop-preview-ship" rel="noopener noreferrer"&gt;Vercel generates a preview-url&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;You may chose to run Cypress tests against the preview-url. In this article, we will be setting up the Lighthouse job which will make use of this preview-url. &lt;/p&gt;

&lt;h2&gt;
  
  
  5. Run Lighthouse budget checks against the deployment previews
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;lighthouse&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;needs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;deploy&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v2&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Run Lighthouse on urls and validate with lighthouserc&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;treosh/lighthouse-ci-action@v7&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;urls&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
            &lt;span class="s"&gt;${{ needs.deploy.outputs.preview-url }}&lt;/span&gt;
            &lt;span class="s"&gt;${{ needs.deploy.outputs.preview-url }}/some-other-path&lt;/span&gt;
          &lt;span class="na"&gt;budgetPath&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;./budget.json&lt;/span&gt;
          &lt;span class="na"&gt;runs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This job makes use of the opensource &lt;a href="https://github.com/treosh/lighthouse-ci-action" rel="noopener noreferrer"&gt;treosh/lighthouse-ci-action&lt;/a&gt; Github action. The action makes use of the Lighthouse CI and audits our deployments. The action allows us to set numerous options like &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;testing against multiple paths&lt;/li&gt;
&lt;li&gt;providing a budget path&lt;/li&gt;
&lt;li&gt;number of runs (how many times the CI should audit an URL?)&lt;/li&gt;
&lt;li&gt;and many more ..&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In this job, setting up a budget is the most important task. As you may have known, with the &lt;a href="https://www.searchenginewatch.com/2021/01/04/google-page-experience-update-is-all-set-to-launch-in-may-2021-webmasters-hang-in-there/" rel="noopener noreferrer"&gt;Google page experience update&lt;/a&gt; coming up in May / June 2021, Lighthouse scores and page speed performance are going to be prioritised in search rankings. &lt;/p&gt;

&lt;p&gt;Therefore, setting up this Github action would help immensely for websites that rely on Google search traffic. If not taken care of in the early stage, it’s quite normal for the bundle sizes to bloat up as a website is iterated, then that results in a lower &lt;strong&gt;lighthouse score&lt;/strong&gt;. This Lighthouse Github action helps us keep an eye on any discrepancy in every commit. &lt;/p&gt;

&lt;p&gt;Based on your project, it can also be important to setup a correct Lighthouse budget. The budget for the example repo is: &lt;a href="https://github.com/snowballdigital/nextjs-tooling/blob/main/budget.json" rel="noopener noreferrer"&gt;https://github.com/snowballdigital/nextjs-tooling/blob/main/budget.json&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  6. CI in Action
&lt;/h2&gt;

&lt;p&gt;Working Github repo: &lt;a href="https://github.com/snowballdigital/nextjs-tooling" rel="noopener noreferrer"&gt;https://github.com/snowballdigital/nextjs-tooling&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now we have all 3 jobs setup in the CI pipeline, on each push to a branch the following 3 jobs would run like so:&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzk5lg2xmxh44jgdg0t76.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzk5lg2xmxh44jgdg0t76.png" alt="Screenshot 2021-04-21 at 20.58.32"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Additionally, if there is a PR, &lt;strong&gt;vercel-actions&lt;/strong&gt; will comment on the PR once the preview URL is deployed successfully. &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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9d3pu0qh2dvvdf9s6v9k.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9d3pu0qh2dvvdf9s6v9k.png" alt="Screenshot 2021-04-16 at 15.51.02"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  In conclusion
&lt;/h2&gt;

&lt;p&gt;Simply, any commit which violates your CI rules will not make it to production. And in the 3 jobs we have defined in this article has a core focus on UX and DX. &lt;/p&gt;

&lt;p&gt;These pipelines setup are best suited for any frontend project since the successful pipelines give you that the extra finesse and assurance to deliver a solid, consistent end user experience &amp;amp; also an improved developer experience for your team &amp;amp; co-contributors.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Interested in building lightning fast web applications on React? We’re in search for senior frontend developers, &lt;a href="https://snowball.digital/careers/senior-frontend-developer" rel="noopener noreferrer"&gt;Apply here!&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>github</category>
      <category>devops</category>
      <category>ci</category>
      <category>performance</category>
    </item>
    <item>
      <title>HTML autocomplete value for "city"</title>
      <dc:creator>Meet Dave</dc:creator>
      <pubDate>Wed, 31 Mar 2021 13:14:58 +0000</pubDate>
      <link>https://dev.to/meetdave3/html-autocomplete-value-for-city-4jai</link>
      <guid>https://dev.to/meetdave3/html-autocomplete-value-for-city-4jai</guid>
      <description>&lt;h1&gt;
  
  
  Plot
&lt;/h1&gt;

&lt;p&gt;A few days ago I was building a form in React that would take in user's address fields such as address lines, postal code, city, country, etc. &lt;/p&gt;

&lt;p&gt;Following some practices, I wanted to make use of the HTML's native attributes such as &lt;em&gt;autocomplete&lt;/em&gt;, &lt;em&gt;placeholder&lt;/em&gt;, &lt;em&gt;inputMode&lt;/em&gt;, etc. on form fields as that would result in a good end &lt;strong&gt;user experience&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The &lt;em&gt;autocomplete&lt;/em&gt; attribute provides an automated assistance in filling out form field values, as well as guidance to the browser regarding the type of information to expect in the field. &lt;/p&gt;

&lt;p&gt;Generally, when the autocomplete attribute is not provided, the input field suggestions are random, and up-to the browser. &lt;/p&gt;

&lt;h1&gt;
  
  
  Why this blog post?
&lt;/h1&gt;

&lt;p&gt;While implementing the autocomplete attribute for an address form, I referred to the web development bible: The &lt;a href="https://developer.mozilla.org/en-US"&gt;MDN&lt;/a&gt;, specifically the docs for the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/autocomplete"&gt;autocomplete attribute&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Surprisingly the docs don't mention the value for autofilling a "city" input field. &lt;/p&gt;

&lt;h1&gt;
  
  
  Solution
&lt;/h1&gt;

&lt;p&gt;After some research I stumbled upon the correct usage for autofilling a city field:&lt;br&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;input&lt;/span&gt;
  &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt;
  &lt;span class="na"&gt;autoComplete=&lt;/span&gt;&lt;span class="s"&gt;"home city"&lt;/span&gt;
&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;After using the &lt;strong&gt;autocomplete&lt;/strong&gt; attribute for my form fields, I was conscious about this browser feature whenever I would visit other websites to fill out forms. &lt;/p&gt;

&lt;p&gt;Astonishingly, I see that many large scale websites / brands don't use this attribute yet 😐&lt;/p&gt;

&lt;p&gt;I also noticed the payment gateway providers make good use of the attributes (like: autocomplete="cc-number") that help in autofilling appropriate credit card information 🤔&lt;/p&gt;

&lt;p&gt;Now, whenever I'm building forms, a typical input field would have the following attributes / properties.&lt;br&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;input&lt;/span&gt;
  &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"personalNumber"&lt;/span&gt;
  &lt;span class="na"&gt;autocomplete=&lt;/span&gt;&lt;span class="s"&gt;"tel"&lt;/span&gt;
  &lt;span class="na"&gt;placeholder=&lt;/span&gt;&lt;span class="s"&gt;{t(`contractFormPlaceholders.personalNumber`)}&lt;/span&gt;
  &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"number"&lt;/span&gt;
  &lt;span class="na"&gt;inputMode=&lt;/span&gt;&lt;span class="s"&gt;"decimal"&lt;/span&gt;
  &lt;span class="na"&gt;required&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;As you can see, the input field is using much of assistive native HTML features &amp;amp; not relying on javascript (example for input validations).&lt;/p&gt;

&lt;p&gt;Do you make use of any other native HTML attributes that further improve the end user experience than the one's mentioned above? Feel free to voice some helpful one's in the comments below 👇&lt;/p&gt;

&lt;p&gt;Cheers!&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>html</category>
      <category>react</category>
      <category>ux</category>
    </item>
    <item>
      <title>Handling runtime errors when server side rendering with Next.js</title>
      <dc:creator>Meet Dave</dc:creator>
      <pubDate>Wed, 10 Feb 2021 16:44:01 +0000</pubDate>
      <link>https://dev.to/meetdave3/handling-runtime-errors-when-server-side-rendering-with-next-js-59da</link>
      <guid>https://dev.to/meetdave3/handling-runtime-errors-when-server-side-rendering-with-next-js-59da</guid>
      <description>&lt;p&gt;Avoid bad user experience by exploring different ways to manage runtime errors with Next.js&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%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F99srfng8jezfzrbqulu5.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%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F99srfng8jezfzrbqulu5.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Intro
&lt;/h1&gt;

&lt;p&gt;If you are working with Next.js, there is quite a good chance to bump into internal server errors (5xx) when on production. If not handled correctly, a single error can bring down the complete page. Imagine a user shopping online for their favourite gadget and they end up seeing this page resulting in a bad UX.  &lt;/p&gt;

&lt;p&gt;&lt;a href="https://nextjs.org/blog/next-9-3" rel="noopener noreferrer"&gt;Nextjs shipped SSG support with version 9.3&lt;/a&gt; and brought in a lot of positives. For instance: getting &lt;strong&gt;errors at build time rather than runtime&lt;/strong&gt;. Switching from SSR to SSG, ended up in an amazing user experience as everything was statically generated before the site was deployed.&lt;/p&gt;

&lt;p&gt;However, in some cases, we still require our website pages to use server side rendering (SSR) instead of static site generation (SSG). Example: checking if the user is logged in or not?&lt;/p&gt;

&lt;h1&gt;
  
  
  Plot
&lt;/h1&gt;

&lt;p&gt;In this article, let’s take a look at a typical error, the “TypeError“&lt;/p&gt;

&lt;p&gt;Consider our web-application consuming data from a CMS. At some point the marketing team tries to change a property and they accidentally end up removing one. Or, for the sake of this article let’s consider the CMS backend server goes offline. We fail fetching the data from the CMS and the TypeError is born.&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%2Fmedia.crystallize.com%2Fdolphin-tuna%2F21%2F2%2F9%2F1%2Fscreenshot-2021-02-09-at-17-57-51.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%2Fmedia.crystallize.com%2Fdolphin-tuna%2F21%2F2%2F9%2F1%2Fscreenshot-2021-02-09-at-17-57-51.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This example considers a scenario when your webpage uses Server side rendering.&lt;/p&gt;

&lt;p&gt;The source code is spun out of a simple next.js boilerplate, Deployed on &lt;a href="https://ssr-error-handling-git-main.meetdave3.vercel.app" rel="noopener noreferrer"&gt;https://ssr-error-handling-git-main.meetdave3.vercel.app&lt;/a&gt; and available on Github: &lt;a href="https://github.com/meetdave3/ssr-error-handling" rel="noopener noreferrer"&gt;https://github.com/meetdave3/ssr-error-handling&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let’s take a look of ways how can we avoid a webpage from crashing in production? &lt;/p&gt;

&lt;h1&gt;
  
  
  1. Error boundary
&lt;/h1&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Tile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&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;ErrorBoundary&lt;/span&gt; &lt;span class="nx"&gt;FallbackComponent&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;ErrorFallback&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&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;a&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;href&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;link&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;card&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;h3&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;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;rarr&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;/h3&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;p&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;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;para&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;para&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;para&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;/p&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;/a&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;/ErrorBoundary&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;Since we’re using React, we are aware of using error boundaries as React exposes getDerivedStateFromError or componentDidCatch lifecycle methods so we can handle the runtime errors. &lt;/p&gt;

&lt;p&gt;These lifecycle method won’t run in Next.js as &lt;a href="https://github.com/vercel/next.js/issues/5070" rel="noopener noreferrer"&gt;componentDidCatch does not work when using SSR&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If an error occurs in the Error Boundary, the webpage will simply throw a internal server error (500) and result in an errored page.&lt;/p&gt;

&lt;p&gt;So if you are using error boundaries to handle runtime errors &amp;amp; if an error occurs on production, the page will render like so: &lt;a href="https://ssr-error-handling-git-main.meetdave3.vercel.app/error-boundary" rel="noopener noreferrer"&gt;https://ssr-error-handling-git-main.meetdave3.vercel.app/error-boundary&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You will see a 500 internal server error. Yes, it’s annoying and we don’t want our end users to see it either.&lt;/p&gt;

&lt;h1&gt;
  
  
  2. Try ... catch
&lt;/h1&gt;

&lt;p&gt;When server side rendering, Our old friend Try … catch is a good replacement to the error boundary as it works expectedly on server side, helps us avoiding the annoying 500 internal server error.&lt;/p&gt;

&lt;p&gt;You can wrap your &lt;strong&gt;risky&lt;/strong&gt; component with a try catch like so&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Tile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;try&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;a&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;href&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;link&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;card&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;h3&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;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;rarr&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;/h3&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;p&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;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;para&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;para&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;para&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;/p&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;/a&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;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Send to an error monitoring solution or log it.&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;null&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;Check: &lt;a href="https://ssr-error-handling-git-main.meetdave3.vercel.app/try-catch" rel="noopener noreferrer"&gt;https://ssr-error-handling-git-main.meetdave3.vercel.app/try-catch&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;and you can see how the complete page doesn’t crash any more&lt;/strong&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  3. Optional Chaining
&lt;/h1&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Tile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&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;a&lt;/span&gt; &lt;span class="nx"&gt;href&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;link&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;card&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;h3&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;props&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;rarr&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;/h3&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;p&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;props&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;para&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;para&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;para&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;/p&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;/a&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;This method is the best case from all the options when we want to solve a TypeError. It’s minimal, it’s fast, still it can only help us in accessing chained properties without throwing any error.&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;It’s not necessary to use any of these methods if you are statically generating the site (SSG)&lt;/p&gt;

&lt;p&gt;Why? Because we will get the TypeError at build time when running &lt;code&gt;next build&lt;/code&gt; and a production build won’t be created.&lt;/p&gt;

&lt;p&gt;When using SSR, we need to fallback to the try .. catch solution when we are trying to do something more error prone like &lt;strong&gt;calculating the total tax of the shopping basket&lt;/strong&gt; when rendering the checkout page. &lt;/p&gt;

&lt;p&gt;It’s best to use a mix of optional chaining and try catch to avoid server side errors. &lt;strong&gt;Avoid falling into the trap of using React error boundaries when creating a server side rendered page.&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>nextjs</category>
      <category>react</category>
    </item>
    <item>
      <title>Styled components vs Emotion js: A performance perspective</title>
      <dc:creator>Meet Dave</dc:creator>
      <pubDate>Wed, 19 Aug 2020 20:28:46 +0000</pubDate>
      <link>https://dev.to/meetdave3/styled-components-vs-emotion-js-a-performance-perspective-4eia</link>
      <guid>https://dev.to/meetdave3/styled-components-vs-emotion-js-a-performance-perspective-4eia</guid>
      <description>&lt;p&gt;This article demonstrates the bare minimum difference on build size when using a css-in-js library &amp;amp; it's performance implications.&lt;/p&gt;

&lt;p&gt;Ever wondered how your styles make it to the browser when using CSS-in-JS library like styled-components or emotion? &lt;/p&gt;

&lt;p&gt;When we're defining our styles, we're actually creating a normal React component that has the styles attached to it. This means we are shipping the styles in a .js file rather than a .css file.&lt;/p&gt;

&lt;p&gt;We're going to take a look at build sizes for the two most used CSS-in-JS libraries: emotion.js vs styled-components. &lt;/p&gt;

&lt;p&gt;Apart from page rendering performance, build sizes directly affect the load time. Shipping large builds will naturally have lower load times &amp;amp; an increase in site's time to interactive. If the website relies on traffic from organic search and PPC campaigns, page speed is an important factor.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://searchengineland.com/page-load-time-and-crawl-budget-rank-will-be-the-most-important-seo-indicators-in-2020-326847" rel="noopener noreferrer"&gt;Page load time and crawl budget rank will be the most important SEO indicators in 2020&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://crystallize.com/blog/site-speed-affects-adwords-pricing" rel="noopener noreferrer"&gt;Site Speed Affects Adwords Pricing&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In my setup, I spin up a Next.js boilerplate. We can do this by running&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;npx create-next-app
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;OR&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;yarn create next-app
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Boilerplate build
&lt;/h2&gt;

&lt;p&gt;Now, without doing any further changes, Let’s create a boilerplate production build.&lt;/p&gt;

&lt;p&gt;We have 61.1 kB of FIRST LOAD JS.&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%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fvatoesp2pv0r574zyhfi.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%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fvatoesp2pv0r574zyhfi.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Plot
&lt;/h2&gt;

&lt;p&gt;In this assessment, We only add a styled header component which we create in the  component.&lt;/p&gt;

&lt;p&gt;mycomponent/styles.js&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;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Header&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;styled&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;h1&lt;/span&gt;&lt;span class="s2"&gt;`
  color: blue;
`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;mycomponent/index.js&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Header&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;./styles&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;MyComponent&lt;/span&gt; &lt;span class="o"&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="nc"&gt;Header&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Styling this component with emotion-js&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Header&lt;/span&gt;&lt;span class="p"&gt;&amp;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;MyComponent&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Versions used:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"react": "16.13.1"&lt;/li&gt;
&lt;li&gt;"@emotion/core": "10.0.35"&lt;/li&gt;
&lt;li&gt;"next": "9.5.2"&lt;/li&gt;
&lt;li&gt;"styled-components": "5.1.1"&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let’s go!&lt;/p&gt;

&lt;h2&gt;
  
  
  First up - styled-components
&lt;/h2&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%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fbhkmhusj1s3ud0l1bl3j.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%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fbhkmhusj1s3ud0l1bl3j.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We have a 20% increase in our build size right away. &lt;/p&gt;

&lt;p&gt;One can argue that a 13kB increase does not make any difference, however, in page speed performance - milliseconds matter &amp;amp; so do the amount of bytes we ship across the network.&lt;/p&gt;

&lt;p&gt;Let’s take both builds on a test drive and deploy them on Vercel. &lt;/p&gt;

&lt;p&gt;After deploying, I ran a page speed comparison on &lt;a href="https://developers.google.com/speed/pagespeed/insights/" rel="noopener noreferrer"&gt;https://developers.google.com/speed/pagespeed/insights/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Results: &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%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fhw0kcb4ey1soerpbu6m1.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%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fhw0kcb4ey1soerpbu6m1.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F5miyfi5upsvfhomntacv.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%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F5miyfi5upsvfhomntacv.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;19% difference in Time to interactive&lt;br&gt;
28% difference in First contentful paint&lt;br&gt;
And 2 points skimmed off from the page speed score &lt;/p&gt;

&lt;p&gt;Apart from the build sizes, the other performance hit is “rendering“ &amp;amp; “react re-renders“. The CSS-in-JS libraries depend on a runtime that helps them dynamically update the styles of a component. The CSS-in-JS libraries don’t create CSS classes at build-time, but instead dynamically generate and update style tags in the document whenever a component mounts and/or has it's props changed, making it favourable for theming &amp;amp; complex use of css with React.&lt;/p&gt;

&lt;p&gt;If there’s such a difference in the tiniest example possible, an even more complex app can have heavier build sizes. Also, since we’re shipping our styles in a javascript file, it’s evident that increasing the number of styled components will increase the build size and hence reduce the page speed. &lt;/p&gt;

&lt;h2&gt;
  
  
  Next up - Emotion.js
&lt;/h2&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%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fqaz3lpdexdztp8cx9ev3.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%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fqaz3lpdexdztp8cx9ev3.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Emotion.js performs slightly better than styled-components. &lt;/p&gt;

&lt;p&gt;Here’s the Page speed comparison for both the libraries -&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%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F5miyfi5upsvfhomntacv.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%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F5miyfi5upsvfhomntacv.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F84fo3xio5e6sh95wcb5j.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%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F84fo3xio5e6sh95wcb5j.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In terms of build size, we can see emotion js stands somewhere midway between a plain boilerplate and styled-components. &lt;/p&gt;

&lt;p&gt;After working with both the libraries extensively, I did not find a big difference in the JS APIs. There wasn't much difference in developer experience (DX) as well. If you’re using an older version of styled-components, your build sizes will tend to be much larger. Lately, the styled-components team have bridged the gap by reducing their build sizes.&lt;/p&gt;

&lt;p&gt;If your project doesn’t handle theming or complex css, linaria can be a suitable option as it compiles js into css at build time.&lt;/p&gt;

&lt;p&gt;Given that we know the how these libraries perform with build sizes, It will be interesting to see which one is faster when the styles mount (renders). Faster rendering on browsers will give us a lower “time to interactive“. This should be an interesting case study that demands an article of its own.&lt;/p&gt;

</description>
      <category>react</category>
      <category>css</category>
      <category>javascript</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
