<?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: Rohan Mehta</title>
    <description>The latest articles on DEV Community by Rohan Mehta (@rhnmht30).</description>
    <link>https://dev.to/rhnmht30</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%2F221282%2Fd87a7f73-2f16-4b0b-aefb-f1b316d573b9.jpg</url>
      <title>DEV Community: Rohan Mehta</title>
      <link>https://dev.to/rhnmht30</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/rhnmht30"/>
    <language>en</language>
    <item>
      <title>Using Next.js Image Component with Netlify</title>
      <dc:creator>Rohan Mehta</dc:creator>
      <pubDate>Mon, 15 Feb 2021 14:08:23 +0000</pubDate>
      <link>https://dev.to/rhnmht30/using-next-js-image-component-with-netlify-1lbn</link>
      <guid>https://dev.to/rhnmht30/using-next-js-image-component-with-netlify-1lbn</guid>
      <description>&lt;p&gt;Since Next.js 10’s release, they have added several additional features to their incredible &lt;a href="https://nextjs.org"&gt;React Framework for Production&lt;/a&gt;. Two of the best I fancied were the built-in &lt;a href="https://nextjs.org/blog/next-10#built-in-image-component-and-automatic-image-optimization"&gt;Image Component and Automatic Image Optimisation&lt;/a&gt; features. It serves images in modern formats like WebP if supported by a browser that is smaller than the JPEGs. Google and Vercel team collaboration deliver us this crucial improvement to present images on a webpage in a performant way, following all the best practices.&lt;/p&gt;

&lt;p&gt;E.g., they made &lt;code&gt;width&lt;/code&gt; and &lt;code&gt;height&lt;/code&gt; properties of images a requirement (unless &lt;code&gt;layout=’fill’&lt;/code&gt;) to prevent &lt;a href="https://web.dev/cls/"&gt;cumulative layout shift&lt;/a&gt; (images jumping up and down on page load). It is a core web vital that Google &lt;a href="https://webmasters.googleblog.com/2020/05/evaluating-page-experience.html"&gt;will soon&lt;/a&gt; use in their search ranking. So using the &lt;code&gt;next/image&lt;/code&gt; component in our next-apps is a &lt;strong&gt;&lt;em&gt;no-brainer&lt;/em&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;When deploying on Vercel, the adoption of &lt;code&gt;next/image&lt;/code&gt; is seamless, without hassle. Everything works out-of-the-box. The hurdle arises when you proceed to Netlify or any other platform of your choice. Hence, &lt;code&gt;next/image&lt;/code&gt; and API routes won’t work similarly on such platforms as you would expect them to.&lt;/p&gt;

&lt;p&gt;But don’t dissolve in worry now! In this tutorial, I will discuss how, despite the problems, you can benefit from the reasonable defaults and best practices set by the team behind Next.js. Let’s start! ✨&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Choose to Deploy on Netlify?
&lt;/h2&gt;

&lt;p&gt;Vercel is a logical choice for Next.js apps, their exceptional support for server-side rendering being super cool. However, for organisation and private GitHub accounts, it leaves me with no choice but to move my personal/team projects to Netlify because of their generous free-tier. Another reason for Netlify could be that you have deployed your code on it, and do not want to bear the overhead of shifting to a different platform.&lt;/p&gt;

&lt;p&gt;Recently, the Netlify team has been working round the clock to ease the integration of Next.js apps with their platform, which I will discuss further. Last, they support several frameworks like Gatsby, Vue, CRA, etc., creating a one-stop junction for all your frontend web deployments.&lt;/p&gt;

&lt;h2&gt;
  
  
  Problem Between Next’s Image Component and Netilify.
&lt;/h2&gt;

&lt;p&gt;To deploy Next apps on Netlify, we need to run &lt;code&gt;next export&lt;/code&gt; after building the app. It creates a static HTML export you can deploy to Netlify CDNs. Also, to make SSR work, the Netlify team &lt;a href="https://www.netlify.com/blog/2020/12/07/announcing-one-click-install-next.js-build-plugin-on-netlify/"&gt;introduced a plugin&lt;/a&gt; to build Next.js apps. Previously, this worked like a charm, but since the new Image Component’s arrival, some issues have cropped up.&lt;/p&gt;

&lt;p&gt;On running &lt;code&gt;next export&lt;/code&gt; while using &lt;code&gt;next/image&lt;/code&gt;, the following error occurs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Error: Image Optimisation using Next.js’ default loader is not compatible with &lt;span class="sb"&gt;`&lt;/span&gt;next &lt;span class="nb"&gt;export&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is because Image Component uses a proxy server (provided by Vercel) that optimises images on-demand, as and when users request them.&lt;/p&gt;

&lt;p&gt;The example below shows the conversion:&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="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Image&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;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="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;MyImage&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;Image&lt;/span&gt;
      &lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/boop.jpg&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
      &lt;span class="nx"&gt;alt&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;what a great boop&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
      &lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;1368&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
      &lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;1044&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
      &lt;span class="nx"&gt;layout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;responsive&lt;/span&gt;&lt;span class="dl"&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="p"&gt;}}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The above code is rendered as.&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;div&lt;/span&gt; &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;"display: block; overflow: hidden; position: relative; box-sizing: border-box; margin: 0px;"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;"display: block; box-sizing: border-box; padding-top: 76.3158%;"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt;
    &lt;span class="na"&gt;alt=&lt;/span&gt;&lt;span class="s"&gt;"what a great boop."&lt;/span&gt;
    &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"/_next/image?url=%2Fboop.jpg&amp;amp;w=3840&amp;amp;q=75"&lt;/span&gt;
    &lt;span class="na"&gt;decoding=&lt;/span&gt;&lt;span class="s"&gt;"async"&lt;/span&gt;
    &lt;span class="na"&gt;sizes=&lt;/span&gt;&lt;span class="s"&gt;"(max-width: 640px) 640px, (max-width: 750px) 750px, (max-width: 828px) 828px, (max-width: 1080px) 1080px, (max-width: 1200px) 1200px, (max-width: 1920px) 1920px, (max-width: 2048px) 2048px, 3840px"&lt;/span&gt;
    &lt;span class="na"&gt;srcset=&lt;/span&gt;&lt;span class="s"&gt;"/_next/image?url=%2Fboop.jpg&amp;amp;w=640&amp;amp;q=75 640w,
            /_next/image?url=%2Fboop.jpg&amp;amp;w=750&amp;amp;q=75 750w,
            /_next/image?url=%2Fboop.jpg&amp;amp;w=828&amp;amp;q=75 828w,
            /_next/image?url=%2Fboop.jpg&amp;amp;w=1080&amp;amp;q=75 1080w,
            /_next/image?url=%2Fboop.jpg&amp;amp;w=1200&amp;amp;q=75 1200w,
            /_next/image?url=%2Fboop.jpg&amp;amp;w=1920&amp;amp;q=75 1920w,
            /_next/image?url=%2Fboop.jpg&amp;amp;w=2048&amp;amp;q=75 2048w,
            /_next/image?url=%2Fboop.jpg&amp;amp;w=3840&amp;amp;q=75 3840w"&lt;/span&gt;
    &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;"visibility: visible; position: absolute; inset: 0px; box-sizing: border-box; padding: 0px; border: none; margin: auto; display: block; width: 0px; height: 0px; min-width: 100%; max-width: 100%; min-height: 100%; max-height: 100%;"&lt;/span&gt;
  &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The image URL was changed from &lt;code&gt;/boop.jpg&lt;/code&gt; to &lt;code&gt;/_next/image?url=%2Fboop.jpg&amp;amp;w=750&amp;amp;q=75&lt;/code&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;code&gt;/_next/image&lt;/code&gt; — this is an endpoint where the image will be sent for processing.&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;?url=/boop.jpg&lt;/code&gt; — where the endpoint should load the image from.&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;&amp;amp;w=750&lt;/code&gt; — resize the image to 750px wide.&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;&amp;amp;q=75&lt;/code&gt; — resample the image at 75% quality to reduce the file size.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This proxy URL is unique and thus can be cached, preventing redundant image optimizations. The default loader relies on the Image Optimisation API, which is unavailable for exported-applications, for Next.js tunes images on-demand, as users request them (not at build time).&lt;/p&gt;

&lt;p&gt;Here, we have a list of solutions at hand, that is to&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  use &lt;code&gt;next start&lt;/code&gt;, which starts the Image Optimisation API. This would need a physical or cloud server, rendering you responsible for its management and monitoring.&lt;/li&gt;
&lt;li&gt;  use Vercel for deploying, which supports Image Optimisation.&lt;/li&gt;
&lt;li&gt;  use the solution provided by the &lt;code&gt;next-on-netlify&lt;/code&gt; package.&lt;/li&gt;
&lt;li&gt;  configure a third-party loader in &lt;code&gt;next.config.js&lt;/code&gt;. (e.g., Cloudinary, Akamai and so forth)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For this tutorial, the last two solutions will suffice us. We shall make use of a simple Image Optimiser provided to us by the package &lt;code&gt;next-on-netlify&lt;/code&gt; (&lt;a href="https://github.com/jlengstorf/next-image-on-netlify"&gt;originally demonstrated by Jason&lt;/a&gt; 🙏) which uses &lt;a href="https://www.npmjs.com/package/jimp"&gt;&lt;code&gt;jimp&lt;/code&gt;&lt;/a&gt; under the hood. But that is just a plain API, not performant enough as against the one provided by Vercel. Therefore, we will apply Cloudinary as the default loader, being compatible with Netlify and other hosting platforms.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using the Next-On-Netlify Package.
&lt;/h2&gt;

&lt;p&gt;With sheer perseverance, the team at Netlify have been toiling to provide one-click integrations for Next.js apps. They have prepared a package called &lt;a href="https://github.com/netlify/next-on-netlify"&gt;&lt;code&gt;next-on-netlify&lt;/code&gt;&lt;/a&gt;(currently in beta). You can also install a separate build plugin called &lt;a href="https://github.com/netlify/netlify-plugin-nextjs"&gt;@netlify/plugin&lt;/a&gt;, which uses the above package under the hood. We are going to use the &lt;code&gt;next-on-netlify&lt;/code&gt; for now, just to show the deployment process. So, prep your editors up! 📝&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Can't wait to see the final results? Head on to &lt;a href="https://github.com/rhnmht30/next-on-netlify-demo"&gt;demo repo&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Create a New Next App
&lt;/h3&gt;

&lt;p&gt;The first step involves creating a brand new Next.js app. If you already have one, you can skip this part. Just make sure you have the latest version of Next.js installed.&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;h3&gt;
  
  
  Install the Package
&lt;/h3&gt;

&lt;p&gt;Now we will install the &lt;code&gt;next-on-netlify&lt;/code&gt; package. While drafting this article, I was on &lt;code&gt;v2.8.6&lt;/code&gt;, so update to the latest version as it often inculcates revisions.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;yarn add next-on-netlify
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Create &lt;code&gt;netlify.toml&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;This involves telling Netlify how to build our Next.js app, and which folders to upload to its CDN. We answer that with a &lt;code&gt;netlify.toml&lt;/code&gt; file in our root directory and the instructions below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;&lt;span class="nn"&gt;[build]&lt;/span&gt;
  &lt;span class="py"&gt;command&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"yarn run build"&lt;/span&gt;
  &lt;span class="py"&gt;functions&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"out_functions"&lt;/span&gt;
  &lt;span class="py"&gt;publish&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"out_publish"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This would create two folders: viz &lt;code&gt;out_publish&lt;/code&gt;, including all static elements; &lt;code&gt;out_functions&lt;/code&gt;, containing all the API routes’ implementations.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The names &lt;code&gt;**out_functions**&lt;/code&gt; and &lt;code&gt;**out_publish**&lt;/code&gt; are hard-coded, therefore not configurable at the moment.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Add a &lt;code&gt;postbuild&lt;/code&gt; Hook
&lt;/h3&gt;

&lt;p&gt;Paste the following line of code in your &lt;code&gt;package.json&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"scripts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"dev"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"next"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"build"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"next build"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"postbuild"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"next-on-netlify"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When you run the build command, the &lt;code&gt;postbuild&lt;/code&gt; hook will be fired automatically, driving the &lt;code&gt;next-on-netlify&lt;/code&gt; command for us which makes use of the &lt;code&gt;netlify.toml&lt;/code&gt; file we created earlier.&lt;/p&gt;

&lt;h3&gt;
  
  
  Create &lt;code&gt;next.config.js&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Now the call is to build our Next.js app as a serverless app. Just create a &lt;code&gt;next.config.js&lt;/code&gt; file in your root directory and write:&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="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Target must be serverless&lt;/span&gt;
  &lt;span class="na"&gt;target&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;serverless&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;h3&gt;
  
  
  Let’s Create a Production Build
&lt;/h3&gt;

&lt;p&gt;We are almost there! Time to build our app by running &lt;code&gt;yarn run build&lt;/code&gt;. When the build finishes, you’ll see some terminal messages, where &lt;code&gt;next-on-netlify&lt;/code&gt; creates folders to upload to Netlify CDNs. Add these folders to &lt;code&gt;.gitignore&lt;/code&gt;, having no point in committing them to version control.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Files generated by next-on-netlify command
/out_publish/
/out_functions/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Let’s Deploy 🚀🚀🚀
&lt;/h3&gt;

&lt;p&gt;Last, to deploy using the terminal, you need to install &lt;a href="https://cli.netlify.com/"&gt;&lt;code&gt;netlify-cli&lt;/code&gt;&lt;/a&gt; and log in using the cmd &lt;code&gt;netlify login&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;After your successful login, run &lt;code&gt;netlify deploy&lt;/code&gt; to start a deployment. If a new project, it will ask you to configure one for this site or add this site to an existing project. Now, select appropriately and wait for the deployment to finish.&lt;/p&gt;

&lt;p&gt;Following the fruitful deployment, you will get a preview URL. Check if everything works as intended, and then run &lt;code&gt;netlify deploy --prod&lt;/code&gt; to get the production URL.&lt;/p&gt;

&lt;p&gt;Good going! ⚡ We have deployed our boilerplate application as operational on the web. Let’s add some images and optimise them.&lt;/p&gt;

&lt;h3&gt;
  
  
  Add Images
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/rhnmht30/next-on-netlify-demo/tree/main/public"&gt;Download images&lt;/a&gt; and move them to the public folder.&lt;/p&gt;

&lt;p&gt;Check out the commits on &lt;a href="https://github.com/rhnmht30/next-on-netlify-demo/pull/1"&gt;this PR&lt;/a&gt; where I add basic markup and styling to display images. Also, you can clone &lt;a href="https://github.com/rhnmht30/next-on-netlify-demo/tree/use-next-on-netlify"&gt;&lt;code&gt;use-next-on-netlify&lt;/code&gt; branch&lt;/a&gt; of the demo repo.&lt;/p&gt;

&lt;h3&gt;
  
  
  Rebuild and Deploy
&lt;/h3&gt;

&lt;p&gt;Run &lt;code&gt;yarn build&lt;/code&gt; and wait for the build process to complete.&lt;/p&gt;

&lt;p&gt;Head onto the generated &lt;code&gt;out_functions&lt;/code&gt; folder where you can see a file named &lt;code&gt;next_image.js&lt;/code&gt;. On deployment, this file will be uploaded to Netlify Functions and act as our Image Optimiser. Also, note that the &lt;code&gt;out_functions&lt;/code&gt; folder contains other files as well, which are our API routes implementations. All of these files will be deployed as separate Netlify Functions.&lt;/p&gt;

&lt;p&gt;Now, if look into the &lt;code&gt;out_publish&lt;/code&gt; folder, you will see other static files and images, ready to be uploaded. Here, the &lt;code&gt;next-on-netlify&lt;/code&gt; package has generated a &lt;code&gt;_redirects&lt;/code&gt; file for us, containing the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Next-on-Netlify Redirects
/api/hello  /.netlify/functions/next_api_hello  200
/_next/image*  url=:url w=:width q=:quality  /.netlify/functions/next_image?url=:url&amp;amp;w=:width&amp;amp;q=:quality  200
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The first redirect is for our &lt;code&gt;pages/api/hello.js&lt;/code&gt; which was already present when we created a new next-app. The second redirect is redirecting the traffic going from URLs containing &lt;code&gt;/_next/image&lt;/code&gt; to &lt;code&gt;/.netlify/function/next_image&lt;/code&gt; with all the query parameters.&lt;/p&gt;

&lt;p&gt;This happens because developers of the &lt;code&gt;next-on-netlify&lt;/code&gt; package are currently working to create their image optimiser function, naming it as &lt;code&gt;next_image.js&lt;/code&gt;. If you want to look at how are they doing it, &lt;a href="https://github.com/netlify/next-on-netlify/blob/main/lib/templates/imageFunction.js"&gt;check out this file&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;On the successful build, check the &lt;a href="https://deploy-preview-1--next-with.netlify.app/"&gt;preview URL&lt;/a&gt; by running &lt;code&gt;netlify deploy&lt;/code&gt;. Whereupon, run &lt;code&gt;netlify deploy --prod&lt;/code&gt; to push towards production.&lt;/p&gt;

&lt;p&gt;Bravo! ⚡ We have successfully made the Next.js Image Component work with Netlify! But it does not end here. As you can notice, on visiting the &lt;a href="https://deploy-preview-1--next-with.netlify.app/"&gt;preview URL&lt;/a&gt;, the images load slow. So, let’s advance and solve this in the next section.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using Cloudinary as Default Loader.
&lt;/h2&gt;

&lt;p&gt;The problem with the above Image Optimizer is that it skipped quite a few optimisations like conversion to WebP formats, caching images on the browser, etc. If you go to the &lt;a href="https://deploy-preview-2--next-with.netlify.app/"&gt;deployed version&lt;/a&gt; of this section, you find the first two images load slower than the last two. This is because Cloudinary optimises and caches the final two.&lt;/p&gt;

&lt;p&gt;Implementing these much-needed features alone would be tedious. And you know what they say, &lt;strong&gt;&lt;em&gt;"Don’t reinvent the wheel."&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Set-Up a Cloudinary Account
&lt;/h3&gt;

&lt;p&gt;After finishing the sign-up process, note down your public ID as shown in the image below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--i2bm918w--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/1opmxylwqpg6jmk3slil.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--i2bm918w--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/1opmxylwqpg6jmk3slil.jpg" alt="Image showing where to find your Cloudinary public ID"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, to use our images with Cloudinary, we have two options, either to&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  upload all our images to Cloudinary, and use &lt;code&gt;https://res.cloudinary.com/YOUR_PUBLIC_ID/image/upload/IMAGE_NAME.jpg&lt;/code&gt; to fetch it&lt;/li&gt;
&lt;li&gt;  or provide absolute URL of the image hosted on the platform of our choice to Cloudinary like &lt;code&gt;https://res.cloudinary.com/YOUR_PUBLIC_ID/image/fetch/https://YOUR_PROVIDER.com/IMAGE_NAME.jpg&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;If you get 404 errors on fetching images the second way, log into your Cloudinary account, goto &lt;strong&gt;settings&lt;/strong&gt; -&amp;gt;&lt;strong&gt;security&lt;/strong&gt; and un-check the &lt;strong&gt;Fetched URL&lt;/strong&gt; checkbox under &lt;strong&gt;Restricted media types&lt;/strong&gt; option. It allows us to use any image URL. To prevent misuse, provide the list of accepted domains under the &lt;strong&gt;Allowed fetch domains&lt;/strong&gt; option.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To use Cloudinary as the default loader with Next.js Image Component and get the same results, we have two ways:&lt;/p&gt;

&lt;h3&gt;
  
  
  By Using Loader Prop (requires next v10.0.5)
&lt;/h3&gt;

&lt;p&gt;Since &lt;code&gt;v10.0.5&lt;/code&gt;, Next.js adds loader prop to the Image Component. It takes a custom loader function as the prop, receiving &lt;code&gt;src&lt;/code&gt;, &lt;code&gt;width&lt;/code&gt; and &lt;code&gt;quality&lt;/code&gt; as arguments.&lt;/p&gt;

&lt;p&gt;Here lies the implementation of custom Image Component with loader prop:&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="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Image&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;next/image&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;myLoader&lt;/span&gt; &lt;span class="o"&gt;=&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="nx"&gt;width&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;quality&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="k"&gt;return&lt;/span&gt; &lt;span class="s2"&gt;`https://res.cloudinary.com/YOUR_PUBLIC_ID/image/upload/w_&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="s2"&gt;,q_&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;
        &lt;span class="nx"&gt;quality&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="mi"&gt;75&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="nx"&gt;src&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="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;props&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="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Image&lt;/span&gt; &lt;span class="nx"&gt;loader&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;myLoader&lt;/span&gt;&lt;span class="p"&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="sr"&gt;/&amp;gt;&lt;/span&gt;&lt;span class="err"&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;p&gt;Use the above component as shown below:&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="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;MyImage&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;../components/MyImage&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;//...&lt;/span&gt;

&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;MyImage&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;i&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="s2"&gt;`/coffee-1.jpg`&lt;/span&gt;&lt;span class="p"&gt;}&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="mi"&gt;640&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="mi"&gt;426&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="c1"&gt;//...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Check out &lt;a href="https://github.com/rhnmht30/next-on-netlify-demo/pull/2"&gt;the PR&lt;/a&gt; and &lt;a href="https://deploy-preview-2--next-with.netlify.app/"&gt;the deploy preview URL&lt;/a&gt; for this method and compare the performance difference.&lt;/p&gt;

&lt;h3&gt;
  
  
  By Specifying Loader and Path in &lt;code&gt;next-config.js&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Now, we will discuss another method to use Cloudinary as the default loader in which you need not create a new component as we did in the previous method.&lt;/p&gt;

&lt;p&gt;In the &lt;code&gt;next-config.js&lt;/code&gt;, add the following code to use Cloudinary as the default loader:&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="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Target must be serverless&lt;/span&gt;
  &lt;span class="na"&gt;target&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;serverless&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;images&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;loader&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;cloudinary&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://res.cloudinary.com/YOUR_PUBLIC_ID/image/upload/&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;blockquote&gt;
&lt;p&gt;Since the Next.js docs officially list Cloudinary as an option for loaders, the second method scores better. On debugging, I found, by using loader prop for Cloudinary, images weren’t being converted to WebP, while in the second method it was. I assume there is some kind of extra configuration by the Next.js team under the hood.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Check out &lt;a href="https://github.com/rhnmht30/next-on-netlify-demo/pull/3"&gt;the PR&lt;/a&gt; and &lt;a href="https://deploy-preview-3--next-with.netlify.app/"&gt;the deploy preview URL&lt;/a&gt; for this method and compare the performance difference.&lt;/p&gt;

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

&lt;p&gt;Congratulations on reaching the end! 🎉&lt;/p&gt;

&lt;p&gt;Now you know the two ways to function the Next.js Image Component with Netlify. I would suggest using Cloudinary as the default loader until the wonderful developers of &lt;code&gt;next-on-netlify&lt;/code&gt; release a performant Image Optimiser.&lt;/p&gt;

&lt;p&gt;In my &lt;a href="https://next-with.netlify.app/"&gt;deployed demo&lt;/a&gt;, I have used the most performant one. But you can check these deploy URLs and respective PRs to get an understanding.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Using &lt;code&gt;next-on-netlify&lt;/code&gt;: &lt;a href="https://github.com/rhnmht30/next-on-netlify-demo/pull/1"&gt;PR(#1)&lt;/a&gt; and &lt;a href="https://deploy-preview-1--next-with.netlify.app/"&gt;deploy preview&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;  Using custom loader prop: &lt;a href="https://github.com/rhnmht30/next-on-netlify-demo/pull/2"&gt;PR(#2)&lt;/a&gt; and &lt;a href="https://deploy-preview-2--next-with.netlify.app/"&gt;deploy preview&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;  Using Cloudinary as default loader: &lt;a href="https://github.com/rhnmht30/next-on-netlify-demo/pull/3"&gt;PR(#3)&lt;/a&gt; and &lt;a href="https://deploy-preview-3--next-with.netlify.app/"&gt;deploy preview&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In search of more examples? Check out &lt;a href="https://github.com/dsckiet/website/pull/33"&gt;my PR on this repo&lt;/a&gt; where I am converting my community’s website, deployed on Netlify, to use Next 10 and Tailwind CSS.&lt;/p&gt;

</description>
      <category>nextjs</category>
      <category>netlify</category>
      <category>webdev</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>I over-engineered my blog, and here’s what I’ve learned</title>
      <dc:creator>Rohan Mehta</dc:creator>
      <pubDate>Wed, 06 Jan 2021 07:23:36 +0000</pubDate>
      <link>https://dev.to/rhnmht30/i-over-engineered-my-blog-and-here-s-what-i-ve-learned-520d</link>
      <guid>https://dev.to/rhnmht30/i-over-engineered-my-blog-and-here-s-what-i-ve-learned-520d</guid>
      <description>&lt;p&gt;Are you the type of person who wants to build something big? Something that doesn’t overwhelm you but gives enough exposure to different technologies that work together. Here, I hope to detail my journey of building a blog afresh (technologies used, suggestions, red flags, pointers).&lt;/p&gt;

&lt;p&gt;It took me eight months to launch. But if we’re being honest, had I not slacked off, it wouldn’t have taken me more than a couple of months to get my tasks done.&lt;/p&gt;

&lt;p&gt;The following points discuss ways to help you get started and to not make the same mistakes that I did:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Why Do You Want to Have Your Own Platform?
&lt;/li&gt;
&lt;li&gt;  Choose Your Tech the Wise Way
&lt;/li&gt;
&lt;li&gt;  Design First, Code Later
&lt;/li&gt;
&lt;li&gt;  Research, Learn, Research
&lt;/li&gt;
&lt;li&gt;  Escape Tutorial Hell and Start Actual Coding
&lt;/li&gt;
&lt;li&gt;  What to Do When You Feel Stuck?
&lt;/li&gt;
&lt;li&gt;  My Month-Long Hustle
&lt;/li&gt;
&lt;li&gt;  A Note to the Beginners
&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;A fair warning&lt;/strong&gt;: you might need a hot cup of beverage because this isn’t ending anytime soon!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Why Do You Want to Have Your Own Platform?
&lt;/h2&gt;

&lt;p&gt;We already have several tools of experienced groups of people, serving everyone to start their blog, with no hassle (e.g., ThePracticalDev, Medium, Hashnode, etc.). In a nutshell, it removes distractions and allows creators to focus on the content.&lt;/p&gt;

&lt;p&gt;But as a web developer, I am always tinkering with tools to build stuff for the web. It is the best playground out there. So, I made a raw static blog. With my custom tweaks, it wasn’t too much of a vast project for me, and it boosted my skill set, assuring me I can build stuff of my own.&lt;/p&gt;

&lt;p&gt;I had little ideas to blog on. Therefore, I did what I knew at that moment and converted whatever I had learned while developing into a blog post.&lt;/p&gt;

&lt;p&gt;Also, having your own platform feels a bit more personal, and you can change it whenever, to whatever, or however you want. But yes, no one can deny the value of a community that the above sites bring. So, I suggest that you get the best of both worlds, and cross-post your content on the above sites, linking it to the original source.&lt;/p&gt;

&lt;h2&gt;
  
  
  Choose Your Tech the Wise Way
&lt;/h2&gt;

&lt;p&gt;Prior to jumping onto the code, put some time aside to plan tasks out. Before proceeding with the tech stack, I wanted to have a mental model of things that I had to accomplish. My initial ambitions included&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  a combination of my blog and portfolio, so that people can see my projects too&lt;/li&gt;
&lt;li&gt;  a proper design of colours and font that are eye-catching&lt;/li&gt;
&lt;li&gt;  a dark mode support&lt;/li&gt;
&lt;li&gt;  some basic animations like background colour change while hovering, button click shadows, etc.
fast page loads with a good SEO&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It’s agreeable to have a clear picture in front of you, so you can remain driven in the face of blockages.&lt;/p&gt;

&lt;p&gt;After a bit of research on recent trends, I went with the following tools initially that complemented my ambitions well:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;a href="https://nextjs.org/" rel="noopener noreferrer"&gt;&lt;strong&gt;Next.js&lt;/strong&gt;&lt;/a&gt;, for generating a static site.&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://styled-components.com/" rel="noopener noreferrer"&gt;&lt;strong&gt;styled-components&lt;/strong&gt;&lt;/a&gt;, for easing the styling process.&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://github.com/hashicorp/next-mdx-remote" rel="noopener noreferrer"&gt;&lt;strong&gt;next-mdx-remote&lt;/strong&gt;&lt;/a&gt;, for managing mdx files.&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://github.com/mapbox/rehype-prism" rel="noopener noreferrer"&gt;&lt;strong&gt;rehype-prism&lt;/strong&gt;&lt;/a&gt;, for highlighting code syntax.&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://github.com/garmeeh/next-seo" rel="noopener noreferrer"&gt;&lt;strong&gt;next-seo&lt;/strong&gt;&lt;/a&gt;, for managing SEO stuff.&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://github.com/shadowwalker/next-pwa#readme" rel="noopener noreferrer"&gt;&lt;strong&gt;next-pwa&lt;/strong&gt;&lt;/a&gt;, for PWA support.&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://github.com/donavon/use-dark-mode" rel="noopener noreferrer"&gt;&lt;strong&gt;use-dark-mode&lt;/strong&gt;&lt;/a&gt;, for handling dark mode.&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://splitbee.io/" rel="noopener noreferrer"&gt;&lt;strong&gt;splitbee&lt;/strong&gt;&lt;/a&gt;, for site analytics.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you want to learn a specific tech or tool, that fits the use of something that you are working on, then you should add it to your tech stack list. In this way, you grasp while creating&lt;br&gt;
(slam dunk! 🏀).&lt;/p&gt;
&lt;h2&gt;
  
  
  Design First, Code Later
&lt;/h2&gt;

&lt;p&gt;“Let’s get this party started!” cheering to myself, I created a next-app. I installed a few dependencies and set up the initial folder structure.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;But wait, hold up! Where are the designs? Should I code with a hazy picture of my future blog that always varies? Or should I let my thought-process get finer by creating designs? &lt;strong&gt;Obviously, the latter.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Getting your designs ready before coding helps you stay on track and saves you from bad UI/UX in the beginning.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;But I am not a designer. Designing is hard!&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.figma.com/" rel="noopener noreferrer"&gt;&lt;strong&gt;Figma&lt;/strong&gt;&lt;/a&gt; is an easy-to-use, collaborative app, accessible on your browser. It has a wide community of designers, who provide amazing plugins to start with basic wireframing and creating low-level designs. Plus, you could always use a simple pen and paper. Just have something visual in front of you.&lt;/p&gt;

&lt;p&gt;In the beginning, I had spent a couple of days to figure out the perfect colour combination and fonts. My overflowing concern in colours for dark and light modes left me overwhelmed. It restricted me to direct attention on critical topics.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Colours and font decisions are fun, but first, try to form a basic structure for the website, and try to tackle the hard parts like spacing, mobile responsiveness, etc.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Designing can be time-consuming if you try to be a perfectionist. It exhausted me after dedicating a month to it. A week is doable, but nothing more than that. Your designs help solidify your initial understanding of the layouts and structure.&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%2F8zzl1i942u3trsra1hua.jpg" 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%2F8zzl1i942u3trsra1hua.jpg" alt="homepage showing under construction timer"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;One of my many hard-learned mistakes, I had put up a timer for three months on the index page, saying ‘Under Construction’. Don’t do this, as it could heavily harm your SEO and page ranking on Google search.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;
  
  
  Research, Learn, Research
&lt;/h2&gt;

&lt;p&gt;After my internship finished in August, I took a sabbatical leave from coding. This prevented me from reaching burnout and cleared out a way for more ideas.&lt;/p&gt;

&lt;p&gt;Before resuming my work, I glanced at the list of ideas I was maintaining, all of it coming back to me. Going through it again, I realised that my previous designs lacked polish. This allowed me to punch in a few more ideas and improve the previous ones.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Maintain an idea or feature log to give yourself a head start as and when you are back at it. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;As I wanted things to pick up a pace, I turned over to Tailwind CSS for a try. A lot of time on hands-on tutorials on YouTube also provided me with fresh ideas.&lt;/p&gt;

&lt;p&gt;This phase was quite rewarding. I had figured out a couple of things like&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  MDX integration&lt;/li&gt;
&lt;li&gt;  animation with framer-motion&lt;/li&gt;
&lt;li&gt;  lighthouse optimisations&lt;/li&gt;
&lt;li&gt;  native feel on mobile devices, using bottom navigation instead of sidebar navigation.&lt;/li&gt;
&lt;li&gt;  typography and putting the main content in the middle for better readability&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Escape Tutorial Hell and Start Actual Coding
&lt;/h2&gt;

&lt;p&gt;In time, I realised that tutorial hell had trapped me, watching other people build things on a loop.&lt;br&gt;
Not knowing when to actually begin, sometimes watching tutorials can be pretty comfortable. But in reality, you aren’t putting that newly got knowledge to any use. It would just vanish away in a week. Such a realisation should come early, as it could protect a lot of your time. Stop watching tutorials until you are in a tight corner again.&lt;/p&gt;

&lt;p&gt;To get yourself all pumped up before coding, I would suggest creating a list of activities to carry out on a per-day or a per-week basis. Create a month-long plan, outlining things that you’d do every day. Planning a list in such a way did not overpower me, and also allowed me to take minor breaks in between if I were to get stuck.&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%2Fvxh4syssuqzi0unw6ywx.jpg" 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%2Fvxh4syssuqzi0unw6ywx.jpg" alt="My timeline for the launch."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I upgraded and removed several packages and re-setup my project. My designs were becoming a reality. With a tool like Tailwind CSS, a non-designer like me was able to create decent-looking websites. From then on, Tailwind CSS was my go-to CSS framework for my side-projects.&lt;/p&gt;

&lt;p&gt;During the build process, it's nice to have a different opinion from someone you know. I gave a sneak peek to a couple of my friends, and their initial reactions were inspiring. They liked the new design better than the previous one, assuring me I was moving in the right direction. This could also help you fix those features you were content with but had mixed reactions from others.&lt;/p&gt;
&lt;h2&gt;
  
  
  What to Do When You Feel Stuck?
&lt;/h2&gt;

&lt;p&gt;Everybody gets stuck sometimes, and it’s alright. I like to think of it hopefully. Because then I get to chase that feeling of accomplishment upon solving it. And if I cannot, then there is always room for more learning. &lt;strong&gt;&lt;em&gt;You fail, you learn; you win, you grow&lt;/em&gt;&lt;/strong&gt;.&lt;br&gt;
Don’t want to sound pretentious, but sometimes a problem can be quite hard to solve. My advice would be to get up, leave everything, go for a stroll, or watch a movie. Clear your mind and start afresh.&lt;/p&gt;
&lt;h2&gt;
  
  
  My Month-Long Hustle
&lt;/h2&gt;

&lt;p&gt;During the last month, the most challenging part for me was MDX integration. Good thing I had watched a lot of tutorials, so I was aware of what I was doing (ha-ha).&lt;/p&gt;

&lt;p&gt;I used &lt;code&gt;next-mdx-remote&lt;/code&gt; to read and convert MDX (markdown with jsx) to HTML.&lt;br&gt;
It works in the following steps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Process MDX to HTML&lt;/strong&gt;. With custom components, it passes raw markdown content. This saves us from importing components in the MDX file itself.
&lt;/li&gt;
&lt;/ul&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;getFileData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;filePath&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// read the file contents&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fileSource&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;readFileSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;filePath&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;// extract frontMatter data and raw markdown&lt;/span&gt;
    &lt;span class="c1"&gt;// I am using a `matter` for this.&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;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;content&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;matter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fileSource&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// process the markdown with your custom components&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;mdxSource&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;renderToString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;components&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;img&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;CustomImage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
         &lt;span class="na"&gt;code&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;MyCodeBlock&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="c1"&gt;// pass them here&lt;/span&gt;
        &lt;span class="na"&gt;mdxOptions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;remarkPlugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
                &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;remark-autolink-headings&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;remark-slug&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;remark-code-titles&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@fec/remark-a11y-emoji&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="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="nx"&gt;mdxSource&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;frontMatter&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;span class="nx"&gt;data&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;ul&gt;
&lt;li&gt;  &lt;strong&gt;Hydrate the content&lt;/strong&gt;. Combine both processed markdown and jsx components, and render them on the client-side.
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Blog&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;mdxSource&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;frontMatter&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="nx"&gt;content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;hydrate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;mdxSource&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// pass again for hydration&lt;/span&gt;
        &lt;span class="na"&gt;components&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;img&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;CustomImage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;code&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;MyCodeBlock&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="c1"&gt;// use common layout to render a blog post&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;BlogLayout&lt;/span&gt; &lt;span class="nx"&gt;frontMatter&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;frontMatter&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;content&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;/BlogLayout&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Add optional plugins&lt;/strong&gt;. To use &lt;a href="https://remark.js.org/" rel="noopener noreferrer"&gt;remark&lt;/a&gt; and &lt;a href="https://github.com/rehypejs/rehype" rel="noopener noreferrer"&gt;rehype&lt;/a&gt; plugins, specify them in the &lt;code&gt;remarkPlugins&lt;/code&gt; array in the first step.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://github.com/hashicorp/next-mdx-remote#background--theory" rel="noopener noreferrer"&gt;Read more &lt;/a&gt;&lt;br&gt;
why it’s better than &lt;code&gt;next-mdx-enhanced&lt;/code&gt;, and what it is solving.&lt;/p&gt;

&lt;p&gt;While shaping this, it cramped me in a scenario that I had to implement a ‘copy to clipboard’ feature for the code blocks.&lt;/p&gt;

&lt;p&gt;Initially, I was going with &lt;code&gt;@mapbox/rehype-prism&lt;/code&gt;, a rehype plugin for syntax highlighting that also supports line highlighting. I used it by specifying it in the plugin array of &lt;code&gt;next-mdx-remote&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;In this method, when the &lt;code&gt;next-mdx-remote&lt;/code&gt; finishes with the conversion, it splits out the HTML. It contains divs and span with class names around the elements, which need different styles according to their type. (See the example conversion below.)&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="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Flex&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="s2"&gt;@chakra-ui/react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;// generated html for above code.
&lt;span class="nt"&gt;&amp;lt;pre&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"language-jsx"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;code&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"language-jsx"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;span&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"token keyword module"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;import&lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;span&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"token punctuation"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;{&lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;span&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"token maybe-class-name"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Flex&lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;span&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"token punctuation"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;}&lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;span&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"token keyword module"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;from&lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;span&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"token string"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;'@chakra-ui/react'&lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;span&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"token punctuation"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;;&lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/code&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/pre&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For syntax highlighting, I needed to specify styles for every token by targeting all the generated classes. For example, in the above code &lt;code&gt;class="token string"&lt;/code&gt; is generated class to target the styles for the word &lt;code&gt;@chakra-ui/react&lt;/code&gt;. To apply those styles, I target those elements using CSS class selector.&lt;/p&gt;

&lt;p&gt;The issue is that I would not be available to grab the raw text that I want to stick to the clipboard whenever the user clicks the 'copy to clipboard’ button. Because &lt;code&gt;@mapbox/rehype-prism&lt;/code&gt; inserts its own divs and spans among the code text, sticking to the user’s clipboard.&lt;/p&gt;

&lt;p&gt;As I didn’t have enough time to play with it, I went with another package, &lt;a href="https://github.com/FormidableLabs/prism-react-renderer" rel="noopener noreferrer"&gt;prism-react-renderer&lt;/a&gt;. It allowed me to access the raw code text in between the conversion process of &lt;code&gt;next-mdx-remote&lt;/code&gt;, for it is a wrapper around the &lt;code&gt;&amp;lt;code&amp;gt;&lt;/code&gt; block.Therefore, I use it to stick it to the clipboard on button click with ease.&lt;/p&gt;

&lt;p&gt;I could then style each line of code separately if I wanted or use a pre-defined theme such as &lt;a href="https://github.com/FormidableLabs/prism-react-renderer/blob/master/src/themes/nightOwl.js" rel="noopener noreferrer"&gt;Night Owl&lt;/a&gt; by Sarah Drasner.&lt;/p&gt;

&lt;p&gt;As I am writing this, I realised that I could have targeted the &lt;code&gt;&amp;lt;code&amp;gt;&lt;/code&gt; element from the DOM on button click using &lt;code&gt;document.querySelector&lt;/code&gt;. And copy the inner text using &lt;code&gt;innerText&lt;/code&gt; method on that DOM element.&lt;/p&gt;

&lt;p&gt;I will try it after launch since &lt;code&gt;prism-react-renderer&lt;/code&gt; has contributed to low lighthouse scores. On inspecting, I found a lot of unused JavaScript, being parsed on the client-side, increasing the total blocking time.&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%2Fkikgt8fjukuzhjpdb3j4.jpg" 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%2Fkikgt8fjukuzhjpdb3j4.jpg" alt="A screenshot showing low lighthouse score because of large blocking time."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I felt held back on a few more things, like the dreaded light flicker issue because&lt;br&gt;
of dark mode and the flash of unstyled text (FOUT) because of slow downloading of&lt;br&gt;
fonts.&lt;/p&gt;

&lt;p&gt;I solved the dark mode flash issue after reading a &lt;a href="https://www.joshwcomeau.com/react/dark-mode/" rel="noopener noreferrer"&gt;comprehensive blog about it by Josh Comeau&lt;/a&gt;. And for the FOUT, I stopped using Google fonts and self-hosted my fonts, with the font-display property set to optional. Read more about this &lt;a href="https://web.dev/optimize-webfont-loading/" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Finally, I concluded all of my initial requirements with some added features. I am merry with what I have and quite glad of my efforts.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Note to the Beginners
&lt;/h2&gt;

&lt;p&gt;Had anyone asked me to model a blog two years ago, by all means, I’d have surrendered in five minutes! When I had set off with web development, I did a bunch of JavaScript exercises. And only when I was comfortable enough, I created my first website, &lt;a href="https://v0.rhnmht30.dev/" rel="noopener noreferrer"&gt;my portfolio&lt;/a&gt;. Although plain, it was the start of building small things, deepening my knowledge pool.&lt;/p&gt;

&lt;p&gt;As a beginner, I know things can be pretty bewildering. You want to build cool stuff and put it out there, but sometimes, fear of things not working out, or not having enough experience with tools, can pull you back.&lt;/p&gt;

&lt;p&gt;I can only suggest to keep learning, exploring new things, and creating an initial understanding. Then you move forward to develop something out of it. Strengthening such initial concepts will guide you to make much bigger things in the future.&lt;/p&gt;

&lt;p&gt;Therefore, over-engineering my blog served me to culminate all those small lessons into a project of great size.&lt;/p&gt;

&lt;p&gt;I still need to improve and optimize things, but I am at peace with it right now. 😌&lt;/p&gt;

&lt;p&gt;If you made it to the end, go &lt;a href="https://rhnmht30.dev" rel="noopener noreferrer"&gt;checkout my website&lt;/a&gt;. Also, hit me up on &lt;a href="https://twitter.com/rhnmht30" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt; if you have suggestions, query or just want to talk.&lt;/p&gt;

&lt;p&gt;Have a great one!&lt;/p&gt;

&lt;p&gt;Rohan.&lt;/p&gt;

</description>
      <category>nextjs</category>
      <category>todayilearned</category>
      <category>productivity</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
