<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/">
    <channel>
        <title>Blogs by Shubham Verma</title>
        <link>https://shubhamverma.me</link>
        <description>I blog about open source tools, writing blogs on problems and solutions faced by developers, and other stuff.</description>
        <lastBuildDate>Fri, 06 Mar 2026 03:07:04 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <language>en</language>
        <copyright>Copyright © 2026 Shubham Verma</copyright>
        <item>
            <title><![CDATA[Why Google Photos Uses CSS Translate Instead of Top/Left Insets for Positioning]]></title>
            <link>https://shubhamverma.me/blog/why-google-photos-uses-css-translate-instead-of-top-left-insets-for-positioning</link>
            <guid>d11f34c7-2848-463e-8552-ce7f1b44b82d</guid>
            <pubDate>Sat, 14 Feb 2026 13:01:10 GMT</pubDate>
            <content:encoded><![CDATA[<p><img src="https://cdn.sanity.io/images/bqrb5wuc/prod/f1eac0b31fe998817a9001b911f1f5f2dfa840a6-1200x675.png" alt=""></p>
<p>I have been learning frontend system design by reverse engineering real products, and Google Photos was my first deep dive. One thing that stood out immediately was how they position thousands of thumbnail images in their grid. Instead of using <code>top</code> and <code>left</code> and other inset properties, they rely heavily on <code>transform: translate3d(x, y, 0)</code>.</p>
<p>At first, this felt odd. Why would you use transforms for static positioning? Aren't transforms for animations and movement? The answer lies in understanding the browser rendering pipeline and the performance trade-offs involved.</p>
<h3>The Browser Rendering Pipeline</h3>
<p>When the browser renders a frame, it typically goes through these stages:</p>
<ol>
<li><strong>JavaScript</strong>: your code runs (event handlers, <code>requestAnimationFrame</code>, etc.)</li>
<li><strong>Style</strong>: the browser computes which CSS rules apply to each element</li>
<li><strong>Layout</strong>: the browser calculates the size and position of each element (geometry)</li>
<li><strong>Paint</strong>: the browser turns those boxes into pixels (backgrounds, text, borders, images)</li>
<li><strong>Composite</strong>: the browser assembles painted layers into the final frame you see</li>
</ol>
<p>Not every change triggers every stage. The key difference between inset offsets and <code>transform: translate()</code> is which stages they force the browser to run.</p>
<p><img src="https://web.dev/static/articles/rendering-performance/image/the-full-pixel-pipeline-8f8a7297e4f77_856.jpg" alt="The full rendering pipeline"></p>
<h3>Why inset offsets can be expensive</h3>
<p>When you use inset offsets like <code>top</code> and <code>left</code> to position an element (assuming it is positioned with <code>absolute</code>, <code>relative</code>, or <code>fixed</code>), you are changing the element's layout geometry. That means the browser often has to run the <strong>Layout</strong> stage again to figure out where everything should be, and then repaint affected areas.</p>
<p>If you are moving hundreds of thumbnails during scroll or zoom, doing layout work every frame can cause jank and dropped frames because layout runs on the main thread and blocks JavaScript execution.</p>
<h3>Why Transform: Translate Is Faster</h3>
<p><code>transform: translate(x, y)</code> does not change the element's layout box. The browser computes layout once (where the "reserved seat" is), and then it applies the transform visually during the <strong>Composite</strong> stage.</p>
<p>Because compositing can often happen on a separate compositor thread (sometimes GPU-accelerated), updating transforms can be much cheaper than triggering layout and paint repeatedly.</p>
<p>This is why <code>transform</code> is the go-to property for animations and frequent repositioning. It skips the expensive layout and paint steps in many cases.</p>
<h3>What Does "Layout Space vs Visual Space" Actually Mean?</h3>
<p>This was the concept that finally clicked for me.</p>
<p>When you use <code>top/left</code>, you are changing where the browser thinks the element's box <strong>is</strong> during layout. If you move element A with <code>top/left</code>, other elements might reflow around it (depending on positioning context).</p>
<p>When you use <code>transform: translate()</code>, you are keeping the layout box in the same place, but rendering the pixels somewhere else. That is why translated elements can overlap siblings without pushing them away. The layout "seat" stays reserved in the original spot, but the element is drawn offset from there.</p>
<p>A quick way to test this: put two inline-block divs side by side. Apply <code>transform: translateX(50px)</code> to the first one and it will overlap the second. Apply <code>margin-left: 50px</code> instead and the second will get pushed because layout space changed.</p>
<p><img src="https://cdn.sanity.io/images/bqrb5wuc/prod/8fcc78c634cd94babcf9d4171138481a6e03a924-1069x285.png" alt="side by side comparision of using translate and margin"></p>
<h3>So Why Does Google Photos Use Translate for "Static" Images?</h3>
<p>Google Photos is not actually static. Here is what is happening behind the scenes:</p>
<ul>
<li><strong>Scrolling</strong>: as you scroll, the positions of visible tiles may need to shift (especially during smooth scroll or inertial scrolling).</li>
<li><strong>Virtualization</strong>: Google Photos only renders the thumbnails that are in or near the viewport. As you scroll, new DOM nodes are created for newly visible items, and old ones are destroyed. Each visible thumbnail still needs to be positioned at its correct x/y coordinate in the grid.</li>
<li><strong>Zoom and density changes</strong>: Google Photos lets you change the grid density (number of columns). When that happens, every thumbnail needs to move to a new position.</li>
<li><strong>Responsive layout</strong>: as the window resizes or the device orientation changes, the grid reflows and tiles move.</li>
</ul>
<p>All of these interactions involve repositioning many elements frequently. Using <code>transform: translate3d(x, y, 0)</code> for that positioning keeps those updates smooth because they can often bypass layout and paint work.</p>
<p>Even in a virtualized list where nodes are being created and destroyed, you still need to position each visible node. Using transforms for that initial placement and any subsequent adjustments is cheaper than using <code>top/left</code>.</p>
<p><img src="https://cdn.sanity.io/images/bqrb5wuc/prod/4e4b7e9b5adc88230c67d0bd50649825806320a3-1920x1080.png" alt="Image of dev tools showing translate3d being used and on the left the browser reflecting the layout space (green) and visual space (blue)"></p>
<h3>The Trade-Offs: Memory and Complexity</h3>
<p>Using transforms is not free. There are trade-offs you need to be aware of:</p>
<ul>
<li><strong>Increased memory usage</strong>: transforms can promote elements to their own composited layers, which are stored as textures (often in GPU memory). For a grid with hundreds of visible tiles, this can add up.</li>
<li><strong>Layer management overhead</strong>: the browser has to manage those layers, which has CPU and GPU cost. Too many layers can hurt performance instead of helping it.</li>
<li><strong>Stacking context issues</strong>: transforms create a new stacking context, which can affect <code>z-index</code>, fixed-position children, and overlays. This can complicate your CSS architecture.</li>
<li><strong>Layout doesn't update</strong>: since transforms do not change layout, overlaps can happen. If you want siblings to reflow around a moved element, you need layout-based positioning instead.</li>
</ul>
<p>For Google Photos, the memory and layer overhead is worth it because the smoothness gains are significant for a highly interactive, scroll-heavy UI with thousands of items.</p>
<h3>When Should You Use Top/Left vs Translate?</h3>
<p>Here is a simple rule:</p>
<ul>
<li><strong>Use <code>top/left</code> (or normal layout like flexbox/grid)</strong> when you want to define layout position, siblings should reflow around changes, and you are not updating positions every frame.</li>
<li><strong>Use <code>transform: translate(...)</code></strong> when you are moving elements frequently (animations, drag, scroll positioning, interactive transforms), and you want smoothness without triggering layout and paint repeatedly.</li>
</ul>
<h3>Could Google Photos Have Used Top/Left Instead?</h3>
<p>Yes, technically. But the performance and frame rate loss would have been noticeable, especially on lower-end devices. Smooth 60fps scrolling with hundreds of thumbnails updating position is hard to achieve if you trigger layout work every frame.</p>
<p>Using transforms is a deliberate architectural choice that prioritizes interaction smoothness over simplicity and memory efficiency.</p>
<h3>My Takeaway</h3>
<p>The key insight for me was understanding that <code>top/left</code> and <code>transform: translate()</code> are not just two ways to do the same thing. They operate at different stages of the rendering pipeline and have very different performance characteristics.</p>
<p>For highly interactive UIs (photo grids, drag-and-drop, smooth scroll experiences), treating <code>transform</code> as the default tool for movement makes sense. For more static layouts where you want layout to be the source of truth, stick with layout-based positioning.</p>
<p>If you are building a similar system, profile it. Use the Performance tab and Layers panel in DevTools to see which approach works better for your specific case. Do not just copy patterns blindly.</p>
]]></content:encoded>
            <author>hi@shubhamverma.me (Shubham Verma)</author>
        </item>
        <item>
            <title><![CDATA[Fuzzy Matching URLs in the AI and LLM Hallucination Era]]></title>
            <link>https://shubhamverma.me/blog/fuzzy-matching-urls-in-the-ai-and-llm-hallucination-era</link>
            <guid>5539d33c-aa90-45b9-8541-c07c338c0a48</guid>
            <pubDate>Tue, 06 Jan 2026 15:55:00 GMT</pubDate>
            <content:encoded><![CDATA[<p>In the LLM era, one subtle but important problem has started to show up more often:</p>
<p>If a large language model cites a blog post and slightly hallucinates or mutates the URL slug, the link it generates can easily 404.</p>
<p>That is bad for:</p>
<ul>
<li>Readers who click a broken link and never find the content.</li>
<li>Creators who lose traffic and context.</li>
<li>The web because machine-generated citations become fragile.</li>
</ul>
<p>To make my blog more resilient to this, I implemented fuzzy slug routing using fuse.js, so that even if an LLM or a human slightly messes up the slug, the user can still land on the right post.</p>
<h2>The Problem: Generative Text, Fragile URLs</h2>
<p>A typical blog URL looks like this:</p>
<pre><code>`/blog/my-awesome-post-about-slugs`
</code></pre>
<p>This slug is usually:</p>
<ul>
<li>Derived from the post title.</li>
<li>Treated as a strict, exact identifier.</li>
<li>Assumed to match perfectly.</li>
</ul>
<p>In a world where LLMs generate text, that assumption is increasingly weak.</p>
<p>An LLM might:</p>
<ul>
<li>Drop a word.</li>
<li>Add an extra word.</li>
<li>Change singular to plural.</li>
<li>Slightly rephrase the title before slugifying.</li>
</ul>
<p>For example:</p>
<ul>
<li>
<p>Original slug:</p>
<pre><code>`/blog/understanding-static-site-generation`
</code></pre>
</li>
<li>
<p>LLM-generated slug:</p>
<p><code>/blog/understanding-static-site-generators</code></p>
</li>
</ul>
<p>To a human, that is clearly the same idea. To a traditional router, it is a
completely different path that results in a 404.</p>
<p>What I really want is something like this: you are close enough, let me find the post you most likely meant.</p>
<h2>The Idea: Treat the Slug as a Fuzzy Query</h2>
<p>Instead of treating the slug as a hard, exact key, I treat it as a fuzzy search
query over all my posts.</p>
<p>Conceptually, the flow is:</p>
<ol>
<li>Read the incoming slug from the URL.</li>
<li>Use fuse.js to run a fuzzy search against a list of all posts.</li>
<li>If there is a strong enough match, resolve that post and render it.</li>
<li>If not, fall back to a proper 404.</li>
</ol>
<p>This means that even if an LLM changes the slug slightly, there is still a good
chance the user lands on the intended article.</p>
<p>Imagine the canonical slug is:</p>
<pre><code>`/blog/fuzzy-slug-routing-for-blogs-in-the-llm-era`
</code></pre>
<p>But an LLM outputs:</p>
<pre><code>`/blog/fuzzy-slug-routing-in-llm-era`
</code></pre>
<p>A traditional router sees a completely unknown slug and returns 404.</p>
<p>With this setup, that incoming slug is treated as a query, and as long as the
similarity is high enough, it still resolves to the correct post.</p>
<h2>Live demo</h2>
<p>You can see this idea in action with two URLs.</p>
<ul>
<li><a href="https://shubhamverma.me/blog/fuzzy-matching-urls-in-the-ai-and-llm-hallucination-era">fuzzy-matching-urls-in-the-ai-and-llm-hallucination-era</a> is the canonical slug for this post.</li>
<li><a href="https://shubhamverma.me/blog/fuzzy-matching-urls-in-the-hallucination-era">fuzzy-matching-urls-in-the-hallucination-era</a> is a slightly altered slug that should still land on the same post.</li>
</ul>
<h2>Data Strategy: Precomputing data.json at Build Time</h2>
<p>I use a CMS as the source of truth for my blog posts. A naive approach would be to call the CMS API on every request to resolve the slug.</p>
<p>That would be slower, dependent on external network calls, and unnecessary given that the content is mostly static.</p>
<p>Instead, I decided to handle this at build time.</p>
<p>During the build, I fetch all blog posts from the CMS and extract the core
fields needed for routing and search, such as title and slug, and optionally
tags or summary. I then serialize them into a static data.json file.</p>
<p>Here is the build time script that generates that file.</p>
<pre><code>import { mkdir, writeFile } from 'node:fs/promises';
import path from 'node:path';
import { getClient } from './sanity-server';

async function generateBlogFuseData() {
  const blogs = await getBlogs();

  const filePath = 'src/fuse/data.json';

  await mkdir(path.dirname(filePath), { recursive: true });
  await writeFile(filePath, JSON.stringify(blogs), 'utf8');
}

generateBlogFuseData();
</code></pre>
<p>At runtime, the slug resolution layer does three simple things:</p>
<ol>
<li>Load data.json.</li>
<li>Instantiate Fuse with that dataset.</li>
<li>Run a fuzzy search against slug and optionally title.</li>
</ol>
<p>For my use case, slug is the primary field, and title can be a secondary field to catch more aggressive mutations.</p>
<p>The resolution logic looks like this conceptually.</p>
<p>In code, the core of the resolution function looks like this.</p>
<pre><code>import Fuse from 'fuse.js';
import blogs from '../../../src/fuse/data.json';

async function getData(params: { slug: string }) {
  if (!params || !params.slug) throw new Error('No slug found in params');

  const fuse = new Fuse(blogs as Array&#x3C;{ slug: string; title: string }>, {
    keys: ['slug', 'title'],
    useExtendedSearch: true,
    ignoreLocation: true,
    threshold: 0.44,
    minMatchCharLength: 6
  });

  const slugLength = params.slug?.split('-').length || 0;
  const relatedBlogs =
    slugLength >= 3
      ? fuse.search(params.slug).map(({ item }) => item)
      : [{ slug: '', title: '' }];

  const slug = relatedBlogs?.[0]?.slug;

  return { slug };
}
</code></pre>
<p>Take the incoming slug string from the URL. Run fuse.search on that slug.
Inspect the top result. If its score is within a safe threshold, treat it as the
resolved post. Otherwise, return a 404.</p>
<p>Because fuse.js runs on a static data.json that is generated at build time, this lookup is cheap and fast.</p>
<h2>Why Bother: Robustness in an AI Heavy Web</h2>
<p>This entire approach is about robustness.</p>
<p>LLMs will increasingly generate links. Some will be perfect, many will be close enough but technically wrong.
Traditional slug routing is brittle: a single character off and the request fails.</p>
<p>Fuzzy routing offers graceful degradation: minor hallucinations still resolve to useful content.</p>
<p>It is also a small step toward making URLs more semantic instead of strictly
token based.</p>
<h2>Trade Offs and Considerations</h2>
<p>This is not magic, and there are trade offs.</p>
<p>Ambiguity can show up if multiple posts are very similar, because fuzzy search might pick the wrong one. Threshold tuning matters a lot. You need to experiment to find the sweet spot between overly strict and overly forgiving. SEO still relies on canonical URLs. The fuzzy match is a way to serve content, but the canonical slug remains the source of truth.</p>
<p>In practice, for a personal blog or small content site, these trade offs are
acceptable.</p>
<h2>Conclusion</h2>
<p>In a world where content is generated, links are machine written, and
hallucinations are inevitable, relying on exact string equality for slugs feels
outdated.</p>
<p>By precomputing a simple data.json at build time, using fuse.js to fuzzily match incoming slugs, and falling back to a 404 only when there is truly no good match, I have made my blog more resilient to LLM hallucinations and minor human errors while keeping the implementation simple and friendly to static hosting.</p>
<p>If you run a content site and expect LLMs to link to you, fuzzy slug routing is a small but meaningful upgrade to your URL strategy.</p>
<blockquote>
<p>NOTE: LLM was used to help with grammar fixes in this blog post.</p>
</blockquote>
]]></content:encoded>
            <author>hi@shubhamverma.me (Shubham Verma)</author>
        </item>
        <item>
            <title><![CDATA[Building Dynamic Seat Layout Rendering in React from Sparse JSON (BookMyShow/District-style)]]></title>
            <link>https://shubhamverma.me/blog/building-dynamic-seat-layout-rendering-in-react-from-sparse-json-book-my-show-district-style</link>
            <guid>04aa1d29-73bc-47ad-a4ea-be14c6820f24</guid>
            <pubDate>Thu, 18 Dec 2025 17:30:00 GMT</pubDate>
            <content:encoded><![CDATA[<p><img src="https://cdn.sanity.io/images/bqrb5wuc/prod/8d9ef20328e1130df7b0374fd232504f0405ef26-1200x675.png" alt=""></p>
<p>Seat-selection UIs (BookMyShow, District, Ticketmaster, etc.) look straightforward: show rows, show seats, let me click one.</p>
<p>But theatre layouts in the real world are messy:</p>
<ul>
<li>Seats are missing because there are aisles / stairs / empty spaces</li>
<li>Some rows are shorter, some are split into blocks</li>
<li>Different sections have different prices (“areas”)</li>
<li>And the backend doesn’t hand you a clean 2D matrix - it’s usually <strong>sparse data</strong></li>
</ul>
<p>This post is basically a walkthrough of how I took a District API seat-layout response and turned it into a UI that can render <em>any</em> layout dynamically (without hardcoding positions).</p>
<blockquote>
<p>This blog focuses on <strong>data structure + layout strategy</strong>. For curious ones, here's the <a href="https://frontend-prep-react-repl.vercel.app/">demo link</a></p>
</blockquote>
<hr>
<h2>What the backend JSON looks like (District API response)</h2>
<p>The JSON I used came from a District API response. The file is an <strong>array of layout objects</strong>, and each object contains a <code>seatLayout</code>.</p>
<p>The important nested path is:</p>
<ul>
<li><code>seatLayout.colAreas.objArea[]</code> → pricing sections (“areas”)</li>
<li><code>objArea.objRow[]</code> → rows</li>
<li><code>objRow.objSeat[]</code> → seats</li>
</ul>
<p>Here’s a <strong>minimal representative</strong> snippet (one layout → one area → one row → two seats):</p>
<pre><code>[
  {
    "seatLayout": {
      "name": "PVR",
      "colAreas": {
        "objArea": [
          {
            "AreaNum": 1,
            "AreaDesc": "Recliners",
            "AreaCode": "RE",
            "HasCurrentOrder": true,
            "AreaPrice": 385,
            "objRow": [
              {
                "GridRowId": 1,
                "PhyRowId": "P",
                "objSeat": [
                  {
                    "GridSeatNum": 4,
                    "SeatStatus": "1",
                    "seatNumber": 1,
                    "displaySeatNumber": "1"
                  },
                  {
                    "GridSeatNum": 12,
                    "SeatStatus": "0",
                    "seatNumber": 5,
                    "displaySeatNumber": "5"
                  }
                ]
              }
            ]
          }
        ]
      }
    }
  }
]
</code></pre>
<p>The detail that matters most for layout: <code>GridSeatNum</code> can jump (<code>4</code> → <code>12</code>). That jump is literally your aisle/gap. The backend doesn’t send “empty seats” for <code>5..11</code> - it just doesn’t include them.</p>
<h3>What each field means for UI</h3>
<ul>
<li><code>AreaDesc</code> / <code>AreaPrice</code>: what you show above a section (like “Recliners ₹385”)</li>
<li><code>PhyRowId</code>: the row label you show on the left (“A”, “B”, “P”, “N”…)</li>
<li><code>GridRowId</code>: row position (vertical placement)</li>
<li><code>GridSeatNum</code>: seat position within the row (horizontal placement)</li>
<li><code>SeatStatus</code>:
<ul>
<li><code>"0"</code> → available</li>
<li><code>"1"</code> → occupied/unavailable</li>
<li>everything else (for this dataset) → treat as gap</li>
</ul>
</li>
</ul>
<p><img src="https://cdn.sanity.io/images/bqrb5wuc/prod/21ae60944076b17a3d60dae0fb33da00ad46f8ba-1904x1024.png" alt=""></p>
<hr>
<h2>The core problem: sparse lists don’t render like a theatre</h2>
<p>If you render seats like this:</p>
<ul>
<li><code>row.objSeat.map(seat => &#x3C;Seat />)</code></li>
</ul>
<p>you’ll get something that <em>technically</em> shows seats… but it won’t look like the theatre map.</p>
<p>Because the UI needs to reflect things like:</p>
<ul>
<li>empty space between seat blocks</li>
<li>aisles</li>
<li>rows that are split in the middle</li>
<li>missing rows (walking space)</li>
</ul>
<p>A plain <code>.map()</code> compresses everything. The gaps disappear.</p>
<p>So the problem becomes:</p>
<blockquote>
<p>How do you keep the “holes” in the data so the UI preserves spacing?</p>
</blockquote>
<hr>
<h2>The strategy: indexed placement into pre-sized arrays</h2>
<p>This is the entire trick.</p>
<p>Instead of rendering the sparse list directly, I convert it into something that behaves like a grid:</p>
<ol>
<li>Create an array of length <strong>X</strong> filled with <code>undefined</code></li>
<li>For every real item, place it at the index that represents its position</li>
</ol>
<p>Then when you render the array, the missing indices stay missing - and that’s how you get gaps.</p>
<p>so your array would look something like <code>[undefined, undefined, {...}, {...}, undefined]</code></p>
<h3>Why this works</h3>
<ul>
<li>Missing indices stay <code>undefined</code> → that becomes a gap</li>
<li>Rendering is stable because index == coordinate</li>
<li>A “gap cell” can be rendered as an invisible placeholder with the same size as a seat</li>
</ul>
<hr>
<h2>Building a “grid” for the UI</h2>
<p>There are two places where this idea shows up:</p>
<h3>Row-level grid (vertical positioning)</h3>
<p>Rows come as a list, but the <code>GridRowId</code> gives you a placement order/position. Sometimes there are intentional skips.</p>
<p>So you can build an array of rows where:</p>
<ul>
<li><code>rows[rowIndex] = row</code></li>
<li>missing row indices remain <code>undefined</code></li>
</ul>
<p>Later, when rendering:</p>
<ul>
<li><code>undefined</code> row → render a spacer row (or just keep the vertical gap)</li>
</ul>
<p>That’s how you get gaps between rows without writing a bunch of layout-specific CSS.</p>
<h3>Seat-level grid (horizontal positioning)</h3>
<p>Same idea inside a row.</p>
<p>Seats come as a list, but each seat has <code>GridSeatNum</code> (think “column index”).</p>
<p>So you build:</p>
<ul>
<li><code>seats[colIndex] = seat</code></li>
<li>missing indices remain <code>undefined</code> → aisle/gap</li>
</ul>
<p>When you render the seats array:</p>
<ul>
<li>real seat → render a button</li>
<li>missing seat → render a placeholder cell</li>
</ul>
<hr>
<h2>Rendering becomes trivial after grid alignment</h2>
<p>Once the data is “grid-aligned”, rendering is boring (which is what you want):</p>
<ul>
<li>render areas (pricing sections)</li>
<li>for each area, render rows (including empty slots)</li>
<li>for each row, render seats (including empty slots)</li>
</ul>
<p>The only important UI rule is:</p>
<blockquote>
<p>A gap must still occupy space.</p>
</blockquote>
<p>So even if a seat slot is missing, the placeholder should have the same width/height as a real seat cell. That keeps everything aligned.</p>
<hr>
<h2>Flexibility: any seat at any 2D point</h2>
<p>At this point every seat effectively has a coordinate:</p>
<ul>
<li>row index → Y</li>
<li>column index → X</li>
</ul>
<p>And because the backend is giving you these indices (<code>GridRowId</code>, <code>GridSeatNum</code>), you’re not guessing. You’re just placing items where the backend intended.</p>
<h2>Practical notes / lessons learned</h2>
<ul>
<li>Stable sizing matters</li>
</ul>
<p>If a seat cell is <code>size-9</code>, then your “gap cell” also needs to be <code>size-9</code>. Otherwise alignment breaks.</p>
<ul>
<li>Don’t let layout collapse</li>
</ul>
<p>If you rely purely on flex without placeholders, the browser will naturally collapse empty space. The whole point of the indexed placement is to <em>preserve</em> those empty slots.</p>
<ul>
<li>Keys and rerenders</li>
</ul>
<p>If you generate random keys on every render, React can’t reconcile properly and you’ll get unnecessary rerenders.</p>
<p>For production, prefer stable keys like:</p>
<ul>
<li><code>area.id</code></li>
<li><code>row.id</code></li>
<li><code>seat.id</code></li>
</ul>
<hr>
<h2>Summary</h2>
<p>If I had to summarize the whole approach:</p>
<ul>
<li>The API gives you sparse lists + placement indices (<code>GridRowId</code>, <code>GridSeatNum</code>)</li>
<li>Convert sparse lists into index-addressable arrays</li>
<li>Render those arrays, and treat missing slots as real “gap cells”</li>
</ul>
<p>That’s it. No magic. Just respecting the indices and making sure “missing” still takes up space.</p>
<hr>
<p>If you’re reading this alongside the code:</p>
<ul>
<li>one step converts the District response into internal <code>Area/Row/Seat</code> objects</li>
<li>another step grid-aligns rows and seats into index-based arrays</li>
<li>the UI renders those arrays, and missing indices become visible spacing</li>
</ul>
<p>Optional future improvement:</p>
<ul>
<li>If seat selection/state management grows complex, add <strong>Redux-style normalization</strong> (entities-by-id + selectors). That optimizes updates/lookups - it’s separate from the grid geometry problem</li>
</ul>
<hr>
<h3>References</h3>
<ul>
<li>Repo - https://github.com/shubhamverma1811/frontend-prep</li>
<li>Code - https://github.com/ShubhamVerma1811/frontend-prep/tree/main/frontend-system-design/bookmyshow_district/src</li>
<li>Live - https://frontend-prep-react-repl.vercel.app/</li>
</ul>
<blockquote>
<p>NOTE: LLM was used for grammatically fixes.</p>
</blockquote>
<hr>
]]></content:encoded>
            <author>hi@shubhamverma.me (Shubham Verma)</author>
        </item>
        <item>
            <title><![CDATA[I tried to build a rate-limiter using Go and Redis]]></title>
            <link>https://shubhamverma.me/blog/i-tried-to-build-a-rate-limiter-using-go-and-redis</link>
            <guid>cce82055-f372-42f5-8a93-c94d0d446ff2</guid>
            <pubDate>Thu, 21 Mar 2024 14:41:00 GMT</pubDate>
            <description><![CDATA[building a simple rate limiting using go and redis.]]></description>
            <content:encoded><![CDATA[<p>On my <a href="https://shubhamverma.me/blog/my-software-journey-in-2024">journey</a> of learning, I decided to learn about rate-limiters and try and implement one.</p>
<p>I tried to implement two of the algorithm, Fixed bucket and Sliding Window Counter, using Go(Golang) and Redis.</p>
<p>You can know more about rate limiters and their algorithms from the resources below.</p>
<p>Here are some screenshots:</p>
<p>Fixed (without and with limit):</p>
<p><img src="https://cdn.sanity.io/images/bqrb5wuc/prod/2e1ae13b365cb7f0afa6d934d23767b1328dac62-1920x1080.png?w=800" alt="image"></p>
<p><img src="https://cdn.sanity.io/images/bqrb5wuc/prod/ec36b7bb6b390652a2ae6d6672fc2d8db1c003c4-1920x1080.png?w=800" alt="image"></p>
<p>Sliding window counter:</p>
<ul>
<li>Without rate limit, we can see that within the past 5 mins, 10 reqs were made</li>
</ul>
<p><img src="https://cdn.sanity.io/images/bqrb5wuc/prod/5ee50ffe192446edc13293aedff46f5e6e00de22-1920x1080.png?w=800" alt="image"></p>
<p><img src="https://cdn.sanity.io/images/bqrb5wuc/prod/a62aab69bda6ab01580ea7e4d70295db3087f8e3-1940x1088.png?w=800" alt="image"></p>
<ul>
<li>With rate limit, within the past 5 mins, more than 10 reqs were made, so the API is now rate limited</li>
</ul>
<p><img src="https://cdn.sanity.io/images/bqrb5wuc/prod/85cd3886d7e449dd28e847eeb9e1f1a241290221-1920x1080.png?w=800" alt="image"></p>
<p><img src="https://cdn.sanity.io/images/bqrb5wuc/prod/963e7b5520ed3ffb6013b1fe01b5e371d78d70a1-1938x1028.png?w=800" alt="image"></p>
<p>The <code>main</code> function contains a http server with two endpoints for each algo.
I created a RateLimiter middleware for each of these endpoints, if rate limiter is not enabled, the handler functions execute.</p>
<pre><code>func main() {
	mux := http.NewServeMux()
	rl := &#x26;RateLimiter{}

	mux.HandleFunc("GET /fixed", rl.FixedBucket(func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "application/json")
		w.WriteHeader(http.StatusOK)

		res := APIResponse{
			Message: "Fixed API endpoint",
		}

		json.NewEncoder(w).Encode(res)
	}))

	mux.HandleFunc("GET /window", rl.WindowCounter(func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "application/json")
		w.WriteHeader(http.StatusOK)

		res := APIResponse{
			Message: "Window API endpoint",
		}

		json.NewEncoder(w).Encode(res)
	}))

	log.Fatal(http.ListenAndServe(":8080", mux))
}
</code></pre>
<p>Rate Limiter is a struct with two methods.</p>
<pre><code>type RateLimiter struct{}
</code></pre>
<h3>Fixed Bucket</h3>
<p>This algo is pretty simple, you have a bucket of "counts". If the counts runs out you are rate limited.
The bucket is also refilled at a specific rate, I've used go routine to refill it at 1 count per second.</p>
<p>For every request hit, we decrement the count.
Oh, and I am using Redis to store the bucket and it's count.</p>
<pre><code>func (rl *RateLimiter) FixedBucket(next http.HandlerFunc) http.HandlerFunc {
	rdb.Set(ctx, "bucket", LIMIT, redis.KeepTTL)

// Refills every 1 second until the bucket is filled
	go func() {
		for {
			time.Sleep(time.Second)
			if v, _ := strconv.Atoi(rdb.Get(ctx, "bucket").Val()); v &#x3C; LIMIT {
				rdb.Incr(ctx, "bucket")
			}
		}
	}()

	return func(w http.ResponseWriter, r *http.Request) {
		val, err := strconv.Atoi(rdb.Get(ctx, "bucket").Val())

		if err != nil {
			log.Panic(err)
			os.Exit(1)
		}

		w.Header().Add(HRLIMIT, fmt.Sprint(LIMIT))
		w.Header().Add(HRREM, fmt.Sprint(val))

// if bucket becomes empty, throw rate limit error and status code
		if val &#x3C;= 0 {
			w.Header().Set("Content-Type", "application/json")
			w.WriteHeader(http.StatusTooManyRequests)
			res := APIResponse{
				Message: "Rate Limit reached",
			}
			json.NewEncoder(w).Encode(res)
		} else {
		// For every hit, decrement the count
			rdb.Decr(ctx, "bucket")
			next.ServeHTTP(w, r)
		}
	}
}
</code></pre>
<h3>Sliding Window Counter</h3>
<p>This is one of the most efficient algo.
It basically checks if in the past time window, did you go over the rate limit count.</p>
<p>For example at 10 req/5 min - for every hit it will check if from now to 5 mins ago, did the endpoint hit 10 request.</p>
<p>If yes - rate limit, else - increment the count for current unix time.
And, we delete all the keys stored in the redis that were older than the window time.</p>
<pre><code>func (rl *RateLimiter) WindowCounter(next http.HandlerFunc) http.HandlerFunc {

	return func(w http.ResponseWriter, r *http.Request) {
		ok, err := rl.isAllowed(rdb)

		if err != nil {
			log.Panic(err)
			os.Exit(1)
		}

		if !ok {
			w.Header().Set("Content-Type", "application/json")
			w.WriteHeader(http.StatusTooManyRequests)
			res := APIResponse{
				Message: "Rate Limit reached",
			}
			json.NewEncoder(w).Encode(res)
		} else {
			next.ServeHTTP(w, r)
		}
	}
}
</code></pre>
<p>The <code>isAllowed</code> method takes in reference to redis and returns is rate limiting should be allowed or not.</p>
<pre><code>func (rl *RateLimiter) isAllowed(r *redis.Client) (bool, error) {

	now := time.Now()
// We truncate the API hit time to only it's minute value, so 14:23:43 converts to 14:23:00
	timeStamp := strconv.FormatInt(now.Truncate(time.Minute).Unix(), 10)

// then we store it in the redis KV
	v, err := r.HIncrBy(ctx, "window", timeStamp, 1).Result()

	if err != nil {
		return false, err
	}

// If the value for the current minute itself passes the limit, then we rate limit
// so 14:23:00 had a count of more that LIMIT
	if v > LIMIT {
		return false, nil
	}

// Then we also delete all the keys from the redis that are older than the window.
// Ex: 5, keys that contained the timestap older that 5 mins from before are deleted
	vals, err := r.HGetAll(ctx, "window").Result()

	if err != nil {
		return false, err
	}

	total := 0
// this code, takes the time when API hit, subtracts window time, truncates it and gets the Unix value
// so, if API hits at 15:00:53, this would return 14:55:00
	threshold := now.Add(-time.Minute * time.Duration(WINDOW)).Truncate(time.Minute).Unix()


// loop for all the keys, some error handling and type conversion
	for k, v := range vals {
		intKey, err := strconv.Atoi(k)

		if err != nil {
			return false, err
		}

// if key in redis is still uder the window, increment the total count, else delete that key
		if int64(intKey) > threshold {
			val, err := strconv.Atoi(v)

			if err != nil {
				return false, err
			}

			total += val
		} else {

			r.HDel(ctx, "window", k)
		}
	}

// If the total within the WINDOW time exceeds limit then we rate limit
	if total > LIMIT {
		return false, nil
	}

	return true, nil
}

</code></pre>
<p>That's it. These were the two algos that I tried to implement in Go using Redis.
Rate limiters used in production are more complex than this, they have something called config store and other pieces to them.</p>
<p>And they also use a dynamic keys like IP address or user ids to track each individual requests unlike in this blog with fixed key names like "bucket" and "window".
You can read more on them from the refs.</p>
<p>References:</p>
<ul>
<li><a href="https://github.com/ShubhamVerma1811/rate-limiter-go-redis">Source code of this blog</a></li>
<li><a href="https://www.figma.com/blog/an-alternative-approach-to-rate-limiting/">An alternative approach to rate limiting</a></li>
<li><a href="https://www.youtube.com/watch?v=SgWb6tWx3S8">System Design Mock Interview: Design a Rate Limiter (with Meta Engineering Manager)</a></li>
<li><a href="https://arpitbhayani.me/blogs/sliding-window-ratelimiter">Designing and implementing a sliding window based rate limiter</a></li>
</ul>
]]></content:encoded>
            <author>hi@shubhamverma.me (Shubham Verma)</author>
        </item>
        <item>
            <title><![CDATA[Build literally anything]]></title>
            <link>https://shubhamverma.me/blog/build-literally-anything</link>
            <guid>e3bab1a0-810a-4726-a6bd-04105eeffcee</guid>
            <pubDate>Wed, 06 Mar 2024 16:16:42 GMT</pubDate>
            <description><![CDATA[Raw thoughts on building side projects]]></description>
            <content:encoded><![CDATA[<p>This blog was inspired by <a href="https://aaronfrancis.com/2024/do-literally-anything">this blog</a> by <a href="https://twitter.com/aarondfrancis">Aaron Francis</a>(Y'all need to check out his twitter and courses, amazing teacher).</p>
<p>His blog talks about starting initiative for doing anything. I am gonna keep my blog more on the lines of tech.</p>
<p>We as software engineers often have some side or hobby projects. Some for learning purposes, some for building out real world products. But they all start with an idea.</p>
<p>I am sure we all at one point must had an idea of building something, It happens with me all the time, I have list of such ideas where I list down new ideas from time to time.</p>
<p>But I never get started on them. I've had ideas of products that were eventually made by people out there who took the intiative.</p>
<p>Lemme share the screenshots of some my ideas from my list:</p>
<ul>
<li>I had this idea to build a extension that would translate YT audio before it was even a thing on YT. But now, it's an actual feature on YT.</li>
</ul>
<p><img src="https://cdn.sanity.io/images/bqrb5wuc/prod/973c9ebcdd955491e0beedac9efd96b3c4b19338-659x245.png" alt="screenshot of the idea titled &#x22;A YT extension to dub audio&#x22;"></p>
<p><img src="https://cdn.sanity.io/images/bqrb5wuc/prod/d0052dfd3ddf07baa936266c569e6c59a87306bb-702x521.png" alt="screenshot of the YouTube player with options to change audio tracks of a video"></p>
<ul>
<li>Had the idea to check load diff in a Figma file (like a Git diff) before it was a thing. I think a year back Figma announced this feature.</li>
</ul>
<p><img src="https://cdn.sanity.io/images/bqrb5wuc/prod/ac332a3526cf6c5ed9f512352dc1c71ed1385627-631x331.png" alt="screenshot of an idea from my list named &#x22;Figma diff&#x22;"></p>
<p><img src="https://cdn.sanity.io/images/bqrb5wuc/prod/e732cfee07b1d5af3b59088eb256c82d3fdffc3a-1250x703.png" alt="screenshot of the Figma conferance announcing the feature called &#x22;Compare changes&#x22;"></p>
<p>The point I am making is, if you have an idea to build something, do it.
Does not matter if you are starting it out thinking of turning it into an actual product or building it to just try out a tech stack.</p>
<p><em>Just build stupid shit.</em></p>
<p>I feel every portfolio website of an engineer must have a section or a page dedicated to side projects they tried out and abandoned it half way.
(//TODO: Add a URL of my site when I eventually have a page for it).</p>
<p>Half baked projects tell more about a engineer than completed ones.</p>
<p>Currently, I've been playing around with a lot of tech (those who read my <a href="https://shubhamverma.me/blog/my-software-journey-in-2024">prev blog</a>) be it FE, System design, Go lang and so on..</p>
<p>Hopefully, I'll follow my own thoughts and continue building stupid shit.</p>
<p>These were my raw thoughts that I always had in the back of my mind from quite some time and the blog by Aaron nudged me to put it out here.</p>
]]></content:encoded>
            <author>hi@shubhamverma.me (Shubham Verma)</author>
        </item>
        <item>
            <title><![CDATA[My Software Journey in 2024]]></title>
            <link>https://shubhamverma.me/blog/my-software-journey-in-2024</link>
            <guid>a6eb167e-f734-4e24-840e-84b38429b96c</guid>
            <pubDate>Wed, 17 Jan 2024 17:56:00 GMT</pubDate>
            <description><![CDATA[predictions for my software journey in 2024]]></description>
            <content:encoded><![CDATA[<p>Around this time last year I had published <a href="https://shubhamverma.me/blog/my-tech-progress">this blog</a> which also happened to be my last blog.
It contained my raw thoughts on the technologies I knew and wanted to learn in 2023.</p>
<p>Before starting with 2024, let's see which points/technologies I had chance to try out.</p>
<h3><strong>2023</strong></h3>
<ul>
<li>
<p><strong>React</strong>. This one shouldn't be a surprise, every other project uses React. Although, I did get to work with the infamous RSC for my personal projects.</p>
</li>
<li>
<p><strong>Next.JS</strong>. Shouldn't be surprise either. Worked with the RSC and app directory.</p>
</li>
<li>
<p><strong>Mobx</strong>. I use it every day at work for production projects. Love the simplicity.</p>
</li>
<li>
<p><strong>Javascript/Typescript/Node</strong>. Every day at work.</p>
</li>
<li>
<p><strong>Tailwind</strong>. My go to for styling every personal projects.</p>
</li>
<li>
<p><strong>Nativebase</strong>. I use it every day at work for production projects.</p>
</li>
<li>
<p><strong>Testing</strong>: <strong>Cypress and Percy</strong>. Got to work with Cypress to implement E2E flows and UI testing with Percy.</p>
</li>
<li>
<p><strong>Go</strong>. Go wasn't in the prev list, I picked it up around Nov last year and absolutely loving it.</p>
</li>
<li>
<p><strong>Rust</strong>. Started learning Rust around September last year. Wrote rust for solving advent of code problems.</p>
</li>
</ul>
<h4>Projects that I built in 2023:</h4>
<ol>
<li><a href="https://github.com/raycast/extensions/pull/5512">Added new features in the Feedly extension I made for Raycast</a></li>
<li><a href="https://twitter.com/verma__shubham/status/1647147854845349888">Built First "Craft" using CSS</a></li>
<li><a href="https://twitter.com/verma__shubham/status/1741639449942048886">Released "Delete shorts from YT" browser extension</a></li>
<li><a href="https://github.com/ohmybash/oh-my-bash/pull/477">Added Chezmoi completions to oh-my-bash</a></li>
<li><a href="https://github.com/ShubhamVerma1811/cx">Built CX, A URL shortner in Go</a></li>
<li><a href="https://github.com/shubhamVerma1811/x">Built X, A CLI Bookmarks manager in Go</a></li>
</ol>
<h3><strong>2024</strong></h3>
<p>This year I am more interested in learning about the paradigms, patterns, methodology, working of a technology rather than learning the frameworks themselves.</p>
<p>Gonna stick to 1-2 languages and their frameworks. But would be open to try out new tech stuff.</p>
<h4>Languages:</h4>
<ul>
<li>
<p><strong>Typescript/Javascript</strong>. Would continue using TS/JS without any doubt. For this year, I'd try to improve my TS types knowledge by trying Type challenges.</p>
</li>
<li>
<p><strong>Node/Bun</strong>. Already started to switch from Bun to Node in personal projects, and started to you Bun for writing scripts.</p>
</li>
<li>
<p><strong>Go</strong>. I really want to learn a low language this year, gave Go a try recently and I am abosultey loving it. This language is easier than Python yet packs so much. Definetly would be my go to language for backend related stuff.</p>
</li>
<li>
<p><strong>Rust</strong>. As of now, Rust is my "advent-of-code" language, I haven't found my usecase of Rust other than building Tauri Apps. I'd probably use Rust to solve DSA-ish problems and build Tauri Apps or in a very rare case contribute to OSS project.</p>
</li>
<li>
<p><strong>CSS</strong>. I really thought I knew CSS until I saw these tweets from <a href="https://twitter.com/jh3yy/status/1742015267490685417">Jhey</a>, <a href="https://twitter.com/jamesm/status/1734891084826952094">James</a> and <a href="https://twitter.com/NevFlynn/status/1617896721270591488">Nev</a>. Trying to reproduce these effects and learning about these CSS properties would be on my list.</p>
</li>
<li>
<p><strong>HTML</strong>. Explore the Canvas and the SVG elements more. The above CSS tweets use canvas and svg elements extensively.</p>
</li>
<li>
<p><strong>Python</strong>. I call Python my GPT language, sure I can write scripts using python but I do not want to. The only reason I use python is to visualize charts for some data. And I'll often create a notebook and use GPT to help me achieve it.</p>
</li>
</ul>
<h4>Frontend Frameworks:</h4>
<p>I am gonna stick with React and Svelte but open to try other frameworks.</p>
<ul>
<li>
<p><strong>React/Next.JS</strong>. Would continue to work on only because it's needed at work. Kinda lost interest in React after all the new RSC stuff.</p>
</li>
<li>
<p><strong>Svelte/Svelte-kit</strong>. Would be my go to choice for FE from now on for personal projects.</p>
</li>
<li>
<p><strong>Framer Motion</strong>. Really want to get into building micro/macro animations on the web using framer motion, the only other reason to continue using React.</p>
</li>
<li>
<p><strong>React Native</strong>. The whole native ecosystem is quite overwhelming for me. I can build basic RN apps with screens and navigation, not sure if I'd try more of this stuff in this year.</p>
</li>
</ul>
<h4>Backend:</h4>
<p>I have been interested in diving deep in the backend for a while. The backend I know as of now is to be able build a web server using Express, creating routes, middlewares and REST endpoints.</p>
<p>People like <a href="https://twitter.com/hnasr/">Hussein</a>, <a href="https://twitter.com/aarondfrancis">Aaron</a>, <a href="https://twitter.com/arpit_bhayani">Arpit</a> and <a href="https://twitter.com/alexxubyte">Alex</a> would be my go to learn BE, DB, System Design and Networking related stuff.</p>
<p>Do not have any particular frameworks in mind for BE. Probably gonna follow Roadmap.sh for BE.</p>
<ul>
<li>
<p><strong>Fiber</strong>. Fiber is web framework for Go inspired by Express. This would be my go to to implement any server in Go.</p>
</li>
<li>
<p><strong>Gorm</strong>. Gorm is data modelling for Go, I'd be using it model Database schemas</p>
</li>
</ul>
<h4>Databases:</h4>
<p>I know very little knowledge about DBs, I can write simple CRUD queries, perform joins, create basic normalized modals. But, can I write better queries, performant and fast queries? Nope.</p>
<p>DBs is a vast topic with dedicated Database engineers, I do not aim to be that.
My aim is to be able to write and understand day-to-day topics that a typical BE engineer in a mid sized company would do.</p>
<ul>
<li>
<p><strong>SQL</strong>. PostgreSQL/MySQL, dive a bit deeper on the topics I know now and want to explore.</p>
</li>
<li>
<p><strong>Redis</strong>. Kinda have gist of it, it's a hashmap, want to try out it's practical usecases.</p>
</li>
<li>
<p><strong>NoSQL</strong>. I have worked with Firebase and tried Mongo. Not necessarily anything particular I am trying to look for this year.</p>
</li>
</ul>
<h4>DevOps:</h4>
<p>Not really a devops fan. If I can automate a task by deploying it on a cloud machine, you have my attention.</p>
<ul>
<li><strong>Docker</strong>. I had followed docker tutorials from YT and have a basic gist of what it's capable of. Now I want to try it out by actually dockerzing a simple project and deploying it somewhere.</li>
</ul>
<h4>AI/LLMs:</h4>
<p>LLMs and the products that utilize them are definetly here to stay.</p>
<p>I am not really into training models and customizing the params.
Rather, I am interested into using the existing models and creating useful tools.</p>
<p>Probably be on the lookout for interesting models on <strong>HuggingFace</strong>, <strong>Replicate</strong>.</p>
<h4>System Design</h4>
<p>Don't really know much on this, follow ByteByteGo and other SD channels to understand basic principles of building apps.</p>
<h4>Role related things</h4>
<p>For the more SE related things, I've already started reading <a href="https://twitter.com/EngGuidebook">this book</a> by <a href="https://twitter.com/GergelyOrosz">Gergely</a>.</p>
<h4>Other things</h4>
<p>Well, I might not get to try everything I mentioned above, or I might try things that are not mentioned here.
You never know.</p>
]]></content:encoded>
            <author>hi@shubhamverma.me (Shubham Verma)</author>
        </item>
        <item>
            <title><![CDATA[My Tech Progress]]></title>
            <link>https://shubhamverma.me/blog/my-tech-progress</link>
            <guid>a263ad11-08fa-4080-adba-aff60b304ba0</guid>
            <pubDate>Thu, 02 Feb 2023 11:21:51 GMT</pubDate>
            <description><![CDATA[This is a pretty raw blog for me to keep on referencing and reflecting on from time to time.]]></description>
            <content:encoded><![CDATA[<p>This is a pretty raw blog for me to keep on referencing and reflecting on from time to time.</p>
<h2>Worked with</h2>
<ul>
<li>React</li>
<li>NextJS</li>
<li>MobX</li>
<li>Tailwind</li>
<li>NativeBase</li>
<li>Typescript</li>
</ul>
<h2>Want to learn</h2>
<h3>Tech</h3>
<ul>
<li>Remix</li>
<li>Solid JS</li>
<li>Zustand,  Jotai</li>
<li>Bascically understand the diff b/w these frameworks. What are signals in Solid, Evolution of these frameworks (Kent's blog)</li>
<li>React Native - Architecture before the code</li>
<li>What is Reactivity. Why is React reactivity. What are other stuff like this.</li>
<li>TRPC - Why.What.How</li>
<li>Zod</li>
<li>GraphQL / Apollo</li>
<li>Redis</li>
<li>Docker</li>
<li>Cloudflare and CF Workers</li>
<li>System Design</li>
<li>Design Patterns</li>
<li>Monorepos</li>
<li>Monoliths</li>
<li>System / Design Architectures</li>
<li>Edge runtime stuff</li>
<li>React 18 stuff, concurrent mode, streaming, ssr, use hook</li>
<li>Next 13 app dir stuff</li>
<li>Micro animations</li>
<li>Typescript - understand types better</li>
<li>Role related things like SE practices, daily things, what makes a senior dev</li>
<li>Rust</li>
<li>CSS ecosystem</li>
<li>CSS in JS, CSS server side</li>
<li>Chakra</li>
<li>Radix UI</li>
<li>emotion WHy What</li>
<li>Styled comps?</li>
<li>Web components?</li>
<li>Accessibility</li>
<li>React patterns</li>
<li>State mgmt patterns</li>
<li>Testing related stuff</li>
<li>TDD, unit tests, integrations..</li>
</ul>
]]></content:encoded>
            <author>hi@shubhamverma.me (Shubham Verma)</author>
        </item>
        <item>
            <title><![CDATA[Resizing Images in Markdown and using it in Next.JS with Image Component.]]></title>
            <link>https://shubhamverma.me/blog/resizing-images-in-markdown-and-using-it-in-next-js-with-image-component</link>
            <guid>4f88e7ad-51cb-4e3d-9655-841435fb037e</guid>
            <pubDate>Sun, 11 Sep 2022 04:05:00 GMT</pubDate>
            <content:encoded><![CDATA[<p>Let's say you have a self hosted blogs in your website and you are using
Markdown to write your blog posts.</p>
<p>You might want to use <code>next/image</code> component to render your images in your blog
posts for better performance.</p>
<p>But there is no way to resize your images in Markdown.</p>
<p>So, We can use a simple plugin that I've created called
<a href="https://npmjs.com/package/rehype-image-resize">rehype-image-resize</a> to resize
your images in Markdown. You can head over to the NPM page to know more about
the plugin.</p>
<p>This blog is my way of demonstrating that the plugin works.</p>
<p>All the images in this blog are resized using the plugin.</p>
<blockquote>
<p>You can inspect any image in this article and see that the next/image is being
used.</p>
</blockquote>
<h2>Images from Unsplash rendered using Next/Image</h2>
<h3>Image 1</h3>
<p><img src="https://picsum.photos/800/600" alt="Image 1 [[800 x 600]]"></p>
<h3>Image 2</h3>
<p><img src="https://picsum.photos/1200/600" alt="Image 2 [[1200 x 600]]"></p>
<h3>Image 3</h3>
<p><img src="https://picsum.photos/1920/1080" alt="Image 3 [[1920 x 1080]]"></p>
]]></content:encoded>
            <author>hi@shubhamverma.me (Shubham Verma)</author>
        </item>
        <item>
            <title><![CDATA[Server Side Rendering of Tailwind CSS styles in NextJS]]></title>
            <link>https://shubhamverma.me/blog/server-side-rendering-of-tailwind-css-styles-in-next-js</link>
            <guid>9bb9753b-ddcd-42c9-a5b7-f310396d1ef2</guid>
            <pubDate>Thu, 11 Aug 2022 15:19:00 GMT</pubDate>
            <content:encoded><![CDATA[<p>NextJS provides us with SSR capabilities by rendering the page in the server.</p>
<p>Although, if you are Tailwind for styling, you'll notice that the styles are not applied on the server rendered pages.</p>
<p>For this to work, we need to enable an experimental feature in <code>next.config.js</code></p>
<pre><code>const nextConfig = {
  //...
  experimental: {
    optimizeCss: true, // enabling this will enable SSR for Tailwind
  },
};
</code></pre>
<p>We also need to install Critters</p>
<pre><code>yarn add -D critters
</code></pre>
<blockquote>
<p>Next.JS will internally use this library called <a href="https://github.com/GoogleChromeLabs/critters">Critters</a></p>
</blockquote>
<p>Now, all you do is <code>yarn build</code> and then <code>yarn start</code>.</p>
<p>Make a Postman call and under "Preview" you could see that the Tailwind styles are now getting applied at the server!</p>
<p>Here are the before and after screenshots:</p>
<h2>Before</h2>
<p>You can see that no styles are applied on the server rendered page.</p>
<p><img src="https://cdn.sanity.io/images/bqrb5wuc/prod/38d40bbbf88060bc100235b53de8e48572e000b2-1920x1080.png" alt="Screenshot of before the change"></p>
<h2>After</h2>
<p>After the changes are made, you can see that the styles are applied on the server rendered page.</p>
<p><img src="https://cdn.sanity.io/images/bqrb5wuc/prod/cae3ac5adf8bfff74cdbb00059838a48332493dd-1920x1080.png" alt="Screenshot of after the change"></p>
<p>Gotcha:</p>
<p>If you are using the <code>@tailwindcss/typography</code> plugin, you'd notice these warnings in your logs.</p>
<p>More info <a href="https://github.com/tailwindlabs/tailwindcss/discussions/4722">here</a></p>
]]></content:encoded>
            <author>hi@shubhamverma.me (Shubham Verma)</author>
        </item>
        <item>
            <title><![CDATA[Server Side Rendering of Tailwind CSS styles in NextJS]]></title>
            <link>https://shubhamverma.me/blog/server-side-rendering-of-tailwind-css-styles-in-next-js</link>
            <guid>drafts.9bb9753b-ddcd-42c9-a5b7-f310396d1ef2</guid>
            <pubDate>Thu, 11 Aug 2022 15:19:00 GMT</pubDate>
            <content:encoded><![CDATA[<p>NextJS provides us with SSR capabilities by rendering the page in the server.</p>
<p>Although, if you are Tailwind for styling, you'll notice that the styles are not applied on the server rendered pages.</p>
<p>For this to work, we need to enable an experimental feature in <code>next.config.js</code></p>
<pre><code>const nextConfig = {
  //...
  experimental: {
    optimizeCss: true, // enabling this will enable SSR for Tailwind
  },
};
</code></pre>
<p>We also need to install Critters</p>
<pre><code>yarn add -D critters
</code></pre>
<blockquote>
<p>Next.JS will internally use this library called <a href="https://github.com/GoogleChromeLabs/critters">Critters</a></p>
</blockquote>
<p>Now, all you do is <code>yarn build</code> and then <code>yarn start</code>.</p>
<p>Make a Postman call and under "Preview" you could see that the Tailwind styles are now getting applied at the server!</p>
<p>Here are the before and after screenshots:</p>
<h2>Before</h2>
<p>You can see that no styles are applied on the server rendered page.</p>
<p><img src="https://cdn.sanity.io/images/bqrb5wuc/prod/38d40bbbf88060bc100235b53de8e48572e000b2-1920x1080.png" alt="Screenshot of before the change"></p>
<h2>After</h2>
<p>After the changes are made, you can see that the styles are applied on the server rendered page.</p>
<p><img src="https://cdn.sanity.io/images/bqrb5wuc/prod/cae3ac5adf8bfff74cdbb00059838a48332493dd-1920x1080.png" alt="Screenshot of after the change"></p>
<p>Gotcha:</p>
<p>If you are using the <code>@tailwindcss/typography</code> plugin, you'd notice these warnings in your logs.</p>
<p>More info <a href="https://github.com/tailwindlabs/tailwindcss/discussions/4722">here</a></p>
]]></content:encoded>
            <author>hi@shubhamverma.me (Shubham Verma)</author>
        </item>
        <item>
            <title><![CDATA[Authentication and Protected Routes using Remix + Auth0 + Prisma]]></title>
            <link>https://shubhamverma.me/blog/authentication-and-protected-routes-with-remix-auth-0-and-prisma</link>
            <guid>f593c01d-6120-4c0b-8d2b-5665fcfe8ceb</guid>
            <pubDate>Tue, 12 Jul 2022 02:14:00 GMT</pubDate>
            <content:encoded><![CDATA[<p><img src="https://cdn.sanity.io/images/bqrb5wuc/dev/ac4b5d21bb40027aa4dc5959666235119331cb3a-1080x1080.png" alt="Twitter screenshot of me crying over how I managed to get it to work. [[1080 x 1080]]"></p>
<blockquote>
<p>This blog is not meant to be a tutorial for Remix, Prisma or Auth0. It is only
meant to show how to setup a simple authentication system using them.</p>
</blockquote>
<hr>
<h2>Getting Started</h2>
<p>For the curious ones, here’s the direct Repo link:
https://github.com/ShubhamVerma1811/remix-prisma-auth0-starter</p>
<p>Or you can start off by installing these dependencies in the <strong>existing Remix
project.</strong>.</p>
<p>I chose Vercel as the hosting platform while creating the project so you might
see some file differences and remix config differences. But those should not
matter.</p>
<pre><code>yarn add @prisma/client remix-auth remix-auth-auth0
</code></pre>
<pre><code>yarn add -D prisma ts-node typescript
</code></pre>
<hr>
<h2>Project structure</h2>
<pre><code>.
|-- README.md
|-- app
|   |-- entry.client.tsx
|   |-- entry.server.tsx
|   |-- root.tsx
|   |-- routes
|   |   |-- auth
|   |   |   |-- auth0
|   |   |   |   `-- callback.tsx
|   |   |   `-- auth0.tsx
|   |   |-- index.tsx
|   |   |-- login.tsx
|   |   `-- logout.tsx
|   |-- services
|   |   `-- session.server.ts
|   `-- utils
|       |-- auth.server.ts
|       `-- db.server.ts
|-- package.json
|-- prisma
|   |-- schema.prisma
|   `-- seed.ts
|-- public
|   |-- build
|   `-- favicon.ico
|-- remix.config.js
|-- remix.env.d.ts
|-- server.js
|-- tsconfig.json
`-- yarn.lock
</code></pre>
<hr>
<h2>Integration</h2>
<h3>Setup Prisma</h3>
<p>You can directly follow the steps for this written in the Remix docs for Prisma</p>
<blockquote>
<p>https://remix.run/docs/en/v1/tutorials/jokes#connect-to-the-database</p>
</blockquote>
<pre><code>// app/utils/db.server.ts
import { PrismaClient } from '@prisma/client'

let db: PrismaClient

declare global {
  var __db: PrismaClient | undefined
}

// this is needed because in development we don't want to restart
// the server with every change, but we want to make sure we don't
// create a new connection to the DB with every change either.
if (process.env.NODE_ENV === 'production') {
  db = new PrismaClient()
} else {
  if (!global.__db) {
    global.__db = new PrismaClient()
  }
  db = global.__db
}

export { db }
</code></pre>
<h3>Creating session in Remix</h3>
<p>So we can store the user’s session in the cookies</p>
<blockquote>
<p>More info on sessions in the Remix docs.
https://remix.run/docs/en/v1/api/remix#using-sessions</p>
</blockquote>
<pre><code>// app/services/session.server.ts
import { createCookieSessionStorage } from '@remix-run/node'

// export the whole sessionStorage object
export let sessionStorage = createCookieSessionStorage({
  cookie: {
    name: '_session', // use any name you want here
    sameSite: 'lax', // this helps with CSRF
    path: '/', // remember to add this so the cookie will work in all routes
    httpOnly: true, // for security reasons, make this cookie http only
    secrets: ['s3cr3t'], // replace this with an actual secret
    secure: process.env.NODE_ENV === 'production' // enable this in prod only
  }
})

// you can also export the methods individually for your own usage
export let { getSession, commitSession, destroySession } = sessionStorage
</code></pre>
<h3>Creating the authenticator client that uses Auth0 strategy.</h3>
<ul>
<li>In this file, you’ll be setting up the Auth0 strategy using remix-auth. You’ll
be needing callback URL, client ID, client secret and tenant ID of your
application.</li>
<li>Here were are creating a new instance of the Authenticator from remix-auth.</li>
<li>And creating Auth0 strategy config to the authenticator.</li>
<li>The 2nd argument of the strategy takes a callback that would return you the
Auth0 profile after successful login.</li>
<li>We take that profile data and make an <code>upsert</code> operation using Prisma.</li>
<li><code>upsert</code> would either create a new user in the DB or return as the user that
already exists.</li>
</ul>
<pre><code>// app/utils/auth.server.ts
import { Authenticator } from 'remix-auth'
import { Auth0Strategy } from 'remix-auth-auth0'
import { sessionStorage } from '~/services/session.server'
import { db as prisma } from './db.server'

// Create an instance of the authenticator, pass a generic (optional) with what your
// strategies will return and will be stored in the session

export const authenticator = new Authenticator(sessionStorage)

let auth0Strategy = new Auth0Strategy(
  {
    callbackURL: process.env.AUTH0_CALLBACK_URL!,
    clientID: process.env.AUTH0_CLIENT_ID!,
    clientSecret: process.env.AUTH0_CLIENT_SECRET!,
    domain: process.env.AUTH0_DOMAIN_URL!
  },
  async ({ accessToken, refreshToken, extraParams, profile }) => {
    const email = profile.emails?.[0]?.value
    // Get the user data from your DB or API using the tokens and profile
    return prisma.user.upsert({
      where: {
        email
      },
      create: {
        email,
        name: profile.displayName
      },
      update: {}
    })
  }
)

authenticator.use(auth0Strategy)
</code></pre>
<hr>
<h3>Routing</h3>
<h3>Create auth0 route.</h3>
<pre><code>// app/routes/app/auth0/auth0.tsx
import type { ActionFunction, LoaderFunction } from '@remix-run/node'
import { redirect } from '@remix-run/node'
import { authenticator } from '~/utils/auth.server'

// If user directly goes to this page, we redirect to login
export const loader: LoaderFunction = () => redirect('/login')

// Post request sent to this route would be handled by the authenticator and redirect you to the Auth0's login page.
export const action: ActionFunction = ({ request }) => {
  return authenticator.authenticate('auth0', request)
}
</code></pre>
<h3>Creating callback route</h3>
<pre><code>// app/routes/app/auth0/callback.tsx
import type { LoaderFunction } from '@remix-run/node'
import { authenticator } from '~/utils/auth.server'

/*
We import the authenticator and based on the login state we redirect them to the
either success or failure redirect
*/

export const loader: LoaderFunction = ({ request }) => {
  return authenticator.authenticate('auth0', request, {
    successRedirect: '/',
    failureRedirect: '/login'
  })
}
</code></pre>
<h3>Creating login route</h3>
<pre><code>import type { LoaderFunction } from '@remix-run/node'
import { Form } from '@remix-run/react'
import { authenticator } from '~/utils/auth.server'

// If the user lands on this page, we redirect back to / if they are already logged in.
export const loader: LoaderFunction = async ({ request }) => {
  return await authenticator.isAuthenticated(request, {
    successRedirect: '/'
  })
}

// This form would take us to the auth0 route, which would redirect to the Auth0 login page.

export default function Login() {
  return (
    &#x3C;Form action='/auth/auth0' method='post'>
      &#x3C;button>Login with Auth0&#x3C;/button>
    &#x3C;/Form>
  )
}
</code></pre>
<h3>Creating the logout route</h3>
<pre><code>// app/routes/app/auth0/logout.tsx
import type { LoaderFunction } from '@remix-run/node'
import { authenticator } from '~/utils/auth.server'

// Here we use the logout function of the authenticator to logout the user and clear the Auth0 session.
export const loader: LoaderFunction = async ({ request }) => {
  return authenticator.logout(request, {
    redirectTo: '/login'
  })
}
</code></pre>
<hr>
<h2>Protecting routes using our Authenticator.</h2>
<p>We are now ready for our routes to be protected.You can simple add the
authenticator to the route’s loader.</p>
<p>For example, If you want to protect the route <code>/</code>, you can do the following:</p>
<pre><code>
import type { LoaderFunction } from "@remix-run/node";
import { authenticator } from "~/utils/auth.server";

// When the loader of this page is ran, we will check if the user is logged in.
//  and on failure we redirect to the login page.
export const loader: LoaderFunction = async ({ request }) => {
   await authenticator.isAuthenticated(request, {
    failureRedirect: "/login",
  });

  //... other code here that returns something from the loader..

};

export default function Index() {
  return (
    // ...
  );
}

</code></pre>
<p>That’s it! You have now added Authentication and Protected routes for your
application using Remix + Prisma + Auth0.</p>
<hr>
<h2>References:</h2>
<ul>
<li><a href="https://github.com/ShubhamVerma1811/remix-prisma-auth0-starter">Starter Template for this blog</a></li>
<li><a href="https://github.com/sergiodxa/remix-auth/">Remix-Auth</a></li>
<li><a href="https://github.com/danestves/remix-auth-auth0">Remix-Auth-Auth0</a></li>
<li><a href="https://www.prisma.io/docs/reference/api-reference/prisma-client-reference#upsert">Prisma Upsert</a></li>
</ul>
]]></content:encoded>
            <author>hi@shubhamverma.me (Shubham Verma)</author>
        </item>
        <item>
            <title><![CDATA[Creating Dynamic Open Graph images for your blogs!]]></title>
            <link>https://shubhamverma.me/blog/creating-dynamic-open-graph-images-for-your-blogs</link>
            <guid>750bc4e4-bae9-43bc-8605-f2eaf084a1a2</guid>
            <pubDate>Wed, 11 May 2022 02:17:00 GMT</pubDate>
            <description><![CDATA[Automate that shit of creating the images!]]></description>
            <content:encoded><![CDATA[<p>If you are into writing articles or into SEO stuff, you might know about the
meta tags.</p>
<p>One of them is the Open Graph meta tag. It is used to display a thumbnail of the
article sites like Twitter, Discord and many more.</p>
<pre><code>&#x3C;meta property="og:image" content="http://example.com/image.jpg" />
</code></pre>
<p>We’ll need to handle the following:</p>
<ul>
<li>Styling</li>
<li>Font family</li>
<li>Responsiveness</li>
</ul>
<p>There are many image manipulation libraries like
<a href="https://github.com/oliver-moran/jimp">Jimp</a> or
<a href="https://github.com/lovell/sharp/">Sharp</a>, but they can’t handle the above
points.</p>
<p>You know what can handle it? It’s HTML!</p>
<p>So we will be using Puppeteer that would spin up a headless browser and take a
screenshot of the html page.</p>
<p>We will be using the following libraries:</p>
<ul>
<li>Express - For spinning up the server</li>
<li>Puppeteer - For spinning up the browser</li>
<li>Handlerbars - For rendering the html</li>
<li>Tailwind CSS - For styling the html</li>
</ul>
<p>And all this would be deployed on Vercel. This way we could use the Serverless
Functions.</p>
<p>Let’s get started.</p>
<p>Here is the file structure:</p>
<h2>File Structure</h2>
<pre><code>.
|-- api
|   `-- index.ts
|-- package.json
|-- src
|   `-- templates
|       |-- basic
|       |   `-- index.hbs
|       `-- fancy
|           `-- index.hbs
|-- tailwind.config.js
|-- vercel.json
`-- yarn.lock
</code></pre>
<hr>
<h2>Creating the HTML/HBS Template</h2>
<p>The HTML code could be anything, that’s up to you. For sake of this blog, we are
using a simple template.</p>
<p>I am using Tailwind CDN for styling.
<a href="https://frontstuff.io/no-utility-classes-arent-the-same-as-inline-styles">Utility Classes FTW!</a></p>
<h3>Head of the HTML</h3>
<p>We are importing fonts, and using TailwindCSS CDN for styling.</p>
<pre><code>&#x3C;!-- templates/basic/index.hbs -->

&#x3C;html lang="en">
  &#x3C;head>
    &#x3C;meta charset="UTF-8" />
    &#x3C;meta http-equiv="X-UA-Compatible" content="IE=edge" />
    &#x3C;meta name="viewport" content="width=device-width, initial-scale=1.0" />
    &#x3C;title>{{title}}&#x3C;/title>
    &#x3C;link rel="preconnect" href="https://fonts.googleapis.com" />
    &#x3C;link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
    &#x3C;link
      href="https://fonts.googleapis.com/css2?family=Karla&#x26;display=swap"
      rel="stylesheet"
    />
    &#x3C;script src="https://cdn.tailwindcss.com?plugins=line-clamp">&#x3C;/script>
  &#x3C;/head>
  &#x3C;!-- body ... -->
&#x3C;/html>
</code></pre>
<h3>Body of the HTML</h3>
<p>Nothing much here apart from Tailwind CSS classes, just a title and date that
handlebars would dynamically update.</p>
<pre><code>&#x3C;!-- templates/basic/index.hbs -->

&#x3C;body
  class="image relative bg-black font-bold w-[2240px] h-[1260px] p-32 font-[Karla]"
>
  &#x3C;h1 class="text-gray-300 text-4xl">SV.&#x3C;/h1>
  &#x3C;h1
    class="text-white my-32 py-2 leading-[80px] text-6xl line-clamp-3 font-medium"
  >
    {{title}}
  &#x3C;/h1>
  &#x3C;h1 class="text-white font-normal my-32 text-3xl line-clamp-3">
    {{date}} | by Shubham Verma
  &#x3C;/h1>

  &#x3C;div class="bg-inherit w-full h-full absolute -z-10">&#x3C;/div>

  &#x3C;h1 class="text-gray-300 mb-32 absolute bottom-0 text-4xl">shbm.fyi&#x3C;/h1>
&#x3C;/body>
</code></pre>
<hr>
<h2>Creating the Server and the Handlerbars Template.</h2>
<h3>Imports</h3>
<pre><code>// api/index.ts
import chromium from 'chrome-aws-lambda' // required for deploying on Vercel
import express, { Request, Response } from 'express'
import { readFileSync } from 'fs'
import Handlebars from 'handlebars'
import path from 'path'

const app = express()
</code></pre>
<h3>Creating the get Route</h3>
<p><strong>Overview of the get route:</strong></p>
<ol>
<li>We spin up the puppeteer browser.</li>
<li>Get the title and date from the query string.</li>
<li>Compile the hbs template and pass in the title and date.</li>
<li>Render the html.</li>
<li>Take a screenshot of the html.</li>
<li>Close the browser.</li>
<li>Return the screenshot as a response.</li>
</ol>
<p>In the very end we are adding this line</p>
<blockquote>
<p>module.exports = app;</p>
</blockquote>
<blockquote>
<p>This is for Vercel to deploy a serverless function.</p>
</blockquote>
<pre><code>app.get('/', async (req: Request, res: Response) => {
  try {
    // All these configurations are required for puppeteer, if you are deploying on Vercel!
    // https://github.com/vercel/community/discussions/124
    const browser = await chromium.puppeteer.launch({
      args: [...chromium.args, '--hide-scrollbars', '--disable-web-security'],
      defaultViewport: chromium.defaultViewport,
      executablePath: await chromium.executablePath,
      headless: true,
      ignoreHTTPSErrors: true
    })
    // const browser = await chromium.puppeteer.launch()
    const [page] = await browser.pages()

    const { template = 'basic', title, date } = req.query

    // Reading the template
    const _template = readFileSync(
      path.join(process.cwd(), `src/templates/${template}/index.hbs`),
      'utf8'
    )

    // Compiling the template
    const html = Handlebars.compile(_template)({
      title,
      // get date in this format - 21st April 2020
      date:
        date ??
        new Date().toLocaleDateString('en-GB', {
          day: 'numeric',
          month: 'long',
          year: 'numeric'
        })
    })

    // Rendering the html and taking a screenshot
    await page.setContent(html)
    const take = await page.$('.image')
    const ss = await take.screenshot()
    await browser.close()

    // Returning the buffer of the screenshot.
    res.setHeader('Content-Type', 'image/png')
    res.setHeader('Cache-Control', 's-max-age=1, stale-while-revalidate')
    res.send(ss)
  } catch (err) {
    console.error(err)
    res.send('Error')
  }
})

// Required if you are deplying Express on Vercel as a Serverless Function.
module.exports = app
</code></pre>
<hr>
<h2>Deploying on Vercel</h2>
<p>Create a vercel.json and add the following:</p>
<pre><code>// vercel.json

{
  "rewrites": [
    {
      "destination": "/api",
      "source": "/(.*)"
    }
  ]
}
</code></pre>
<p>All set! You can now deploy the server on Vercel.</p>
<p>You can try it out by going to
<a href="https://og.shubhamverma.me/?title=Hey">https://og.shubhamverma.me/?title=Hey there</a>
.It will take time to load up, because first it’s serverless and second we are
spinning up puppeteer.</p>
<blockquote>
<p>Please don’t over do it. I’ve got Vercel Serverless Limits 😅</p>
</blockquote>
<hr>
<h2>References:</h2>
<p>I have Open Sourced the code for this project on Github.</p>
<p>Here is the Repo link - https://github.com/ShubhamVerma1811/open-graph-api</p>
]]></content:encoded>
            <author>hi@shubhamverma.me (Shubham Verma)</author>
        </item>
        <item>
            <title><![CDATA[Let's add a Command Palette on our website]]></title>
            <link>https://shubhamverma.me/blog/lets-add-a-command-palette-on-our-web</link>
            <guid>d810c46d-f8db-492d-ab07-337a0c0a7e7a</guid>
            <pubDate>Sat, 02 Apr 2022 18:30:00 GMT</pubDate>
            <description><![CDATA[Add a raycast style command palette to your website]]></description>
            <content:encoded><![CDATA[<p>Before you start, let’s see what we are going to build.</p>
<p>Try it out – press <code>cmd</code>+<code>k</code> (macOS) or <code>ctrl</code>+<code>k</code> (Linux/Windows), or click the
CMD icon in the header above.</p>
<p>Awesome! Now let’s start.</p>
<p>All the code used in this blog is available on this CodeSandbox Link.
<a href="https://codesandbox.io/s/lucid-satoshi-4k109k?file=%2Fsrc%2Findex.js%3A295-915">CSB LINK</a></p>
<p>We will be using a library called <a href="https://github.com/timc1/kbar">KBar</a></p>
<hr>
<h2>Adding Provider and actions</h2>
<p>In your root file, wrap the App with a KbarProvider and pass it the default
<code>actions</code> prop</p>
<pre><code>// index.js

import { KBarProvider } from 'kbar'

const actions = [
  {
    id: 'youtube',
    name: 'Youtube',
    shortcut: ['g', 'y'],
    perform: () =>
      (window.location.href = 'https://www.youtube.com/watch?v=dQw4w9WgXcQ')
  },
  {
    id: 'twitter',
    name: 'Twitter',
    shortcut: ['g', 't'],
    keywords: 'twitter',
    perform: () => (window.location.href = 'https://twitter.com/verma__shubham')
  }
]

return (
  &#x3C;KBarProvider actions={actions}>
    &#x3C;App />
  &#x3C;/KBarProvider>
)
</code></pre>
<p>Now if you press the shortcut, you will see that nothing happens. This is
because we haven’t added the other utilities that Kbar provides.</p>
<hr>
<h2>Adding KBar utilities</h2>
<p>Let’s add the below code.</p>
<pre><code>// index.js

import {
  KBarAnimator,
  KBarPortal,
  KBarPositioner,
  KBarProvider,
  KBarResults,
  KBarSearch
} from 'kbar'

const actions = [
  //...
]

return (
  &#x3C;KBarProvider actions={actions}>
    &#x3C;KBarPortal>
      &#x3C;KBarPositioner>
        &#x3C;KBarAnimator>
          &#x3C;KBarSearch />
        &#x3C;/KBarAnimator>
      &#x3C;/KBarPositioner>
    &#x3C;/KBarPortal>
    &#x3C;App />
  &#x3C;/KBarProvider>
)
</code></pre>
<p>Now we are able to see a search box when you press the shortcut! But you’ll
notice nothing happens when we search.</p>
<p>Why are our default <code>actions</code> not rendered?</p>
<h3>Adding the KBarResults</h3>
<ul>
<li>Create a component called <code>Results</code>.</li>
<li>The <code>useMatches()</code> hooks returns us the results of the searched query.</li>
<li>We will use the <code>KBarResults</code> component to render the results.</li>
</ul>
<pre><code>const Results = () => {
  const { results } = useMatches()
  return (
    &#x3C;KBarResults
      items={results}
      onRender={({ item, active }) => {
        return typeof item === 'string' ? (
          // For sections.
          &#x3C;div> {item}&#x3C;/div>
        ) : (
          // For the items.
          &#x3C;p
            style={{
              backgroundColor: active ? 'gray' : 'white',
              height: '50px'
            }}
          >
            {item.name}
          &#x3C;/p>
        )
      }}
    />
  )
}

// USE THE ABOVE COMPONENT right after the KBarSearch />

// ...
;&#x3C;KBarProvider>
  &#x3C;KBarPortal>
    &#x3C;KBarPositioner>
      &#x3C;KBarAnimator>
        &#x3C;KBarSearch />
        {/* USE THE Results COMPONENT here*/}
        &#x3C;Results />
      &#x3C;/KBarAnimator>
    &#x3C;/KBarPositioner>
  &#x3C;/KBarPortal>
  &#x3C;App />
&#x3C;/KBarProvider>
// ...
</code></pre>
<hr>
<h2>Adding nested Results</h2>
<p>If you open up Kbar on this website, you will see a “Search Blogs” item which
opens up nested results. Let’s see how its done.</p>
<ul>
<li>All we need to do it add a action and reference the other actions with a
<code>parent</code> key.</li>
</ul>
<pre><code>// Change the actions variable to this

const actions = [
  {
    id: 'youtube',
    name: 'Youtube',
    shortcut: ['g', 'y'],
    perform: () =>
      (window.location.href = 'https://www.youtube.com/watch?v=dQw4w9WgXcQ')
  },
  {
    id: 'twitter',
    name: 'Twitter',
    shortcut: ['g', 't'],
    keywords: 'twitter',
    perform: () => (window.location.href = 'https://twitter.com/verma__shubham')
  },
  {
    id: 'search-blogs',
    name: 'Search Blogs',
    shortcut: ['s', 'b']
  },
  {
    id: 'blog-1',
    name: 'Blog 1',
    parent: 'search-blogs'
  },
  {
    id: 'blog-2',
    name: 'Blog 2',
    parent: 'search-blogs'
  }
]
</code></pre>
<hr>
<h2>Toggling KBar using the useKar hook</h2>
<p>In our App.js file, we will use the <code>useKBar()</code> hook to toggle KBar.</p>
<pre><code>import { useKBar } from 'kbar'
import './styles.css'

export default function App() {
  const kbar = useKBar()

  return (
    &#x3C;div className='App'>
      &#x3C;h1>Hit Ctrl + K or Cmd + K&#x3C;/h1>
      &#x3C;button
        onClick={() => {
          kbar.query.toggle()
        }}
      >
        Toggle Kbar
      &#x3C;/button>
    &#x3C;/div>
  )
}
</code></pre>
<p>That's it! Now you can toggle KBar by pressing <code>Cmd</code> + <code>K</code> on macOS</p>
<p>or <code>Ctrl</code>+<code>K</code> on Windows/Linux. And also by clicking the CMD icon button.</p>
<hr>
<h2>My Socials</h2>
<ul>
<li>Twitter - <a href="https://shbm.fyi/tw">@verma__shubham</a></li>
<li>GitHub - <a href="https://github.com/ShubhamVerma1811">ShubhamVerma1811</a></li>
</ul>
]]></content:encoded>
            <author>hi@shubhamverma.me (Shubham Verma)</author>
        </item>
        <item>
            <title><![CDATA[Setup Tailwind CSS with Turborepo!]]></title>
            <link>https://shubhamverma.me/blog/setup-tailwind-css-with-turborepo</link>
            <guid>3d2d5cc1-6182-48c5-a3f8-adffccdfe69e</guid>
            <pubDate>Sun, 20 Feb 2022 18:30:00 GMT</pubDate>
            <description><![CDATA[In this article, I’ll show you how to setup Tailwind CSS with your Turborepo.]]></description>
            <content:encoded><![CDATA[<p>In this article, I’ll show you how to setup Tailwind CSS with your Turborepo.</p>
<p>The GitHub repo for this blog is added in the references.</p>
<p>We have created a basic app template using the <code>npx create-turbo@latest</code>.</p>
<p>I have made a small change in that template, by moving pages, styles into the
<code>src</code> folder, so the folder structure would look something like:</p>
<pre><code>.
|-- apps
|   |-- docs
|   |   `-- src
|   |       |-- pages
|   |       `-- styles
|   `-- web
|       `-- src
|           |-- pages
|           `-- styles
`-- packages
    |-- config
    |-- tsconfig
    `-- ui
        `-- components
</code></pre>
<h2>1. Installing Tailwind.</h2>
<p>We’ll start off by installing tailwindcss, postcss and autoprefixer at the root
of your project.</p>
<pre><code>yarn add -DW tailwindcss postcss autoprefixer
</code></pre>
<blockquote>
<p>Optionally you can also install <code>prettier-plugin-tailwindcss</code>for sorting those
tailwind classes in the components. Check the references below to learn more.</p>
</blockquote>
<p>Our root package.json would look like:</p>
<pre><code>{
  // ...
  "devDependencies": {
    "autoprefixer": "^10.4.2",
    "postcss": "^8.4.6",
    "prettier": "^2.5.1",
    "prettier-plugin-tailwindcss": "^0.1.7",
    "tailwindcss": "^3.0.23",
    "turbo": "latest"
  }
  // ....
}
</code></pre>
<hr>
<h2>2. Creating tailwind.config.js and postcss.config.js</h2>
<p>In our <code>packages/config</code>, let’s create <code>tailwind.config.js</code> and
<code>postcss.config.js</code></p>
<ul>
<li>In <code>tailwind.config.js</code>, add the following:</li>
</ul>
<pre><code>module.exports = {
  content: [
    '../../packages/ui/components/**/*.{ts,tsx}',
    './src/**/*.{ts,tsx}'
  ],
  theme: {
    extend: {}
  },
  plugins: []
}
</code></pre>
<ul>
<li>In <code>postcss.config.js</code>, add the following:</li>
</ul>
<pre><code>module.exports = {
  plugins: {
    tailwindcss: {},
    autoprefixer: {}
  }
}
</code></pre>
<hr>
<h2>3. Using the above configs in our apps and packages</h2>
<ul>
<li>We have created the common configs, Now we are ready to use them in our
<code>apps/web</code>, <code>apps/docs</code> or <code>app/{name}</code> directories.</li>
<li>Again create <code>tailwind.config.js</code> and <code>postcss.config.js</code> in our <code>apps/{name}</code>
directories and in <code>packages/ui</code></li>
</ul>
<p>Add the following in the files:</p>
<pre><code>module.exports = require('config/tailwind.config')
</code></pre>
<pre><code>module.exports = require('config/postcss.config')
</code></pre>
<p>Lastly, in our <code>next.config.js</code> for both <code>web</code> and <code>docs</code> add this if it’s not
already present:</p>
<pre><code>const withTM = require('next-transpile-modules')(['ui'])

module.exports = withTM({
  reactStrictMode: true
})
</code></pre>
<hr>
<p>That’s it! You are now ready to use Tailwind CSS with Turborepo!</p>
<h3>References</h3>
<ul>
<li><a href="https://github.com/ShubhamVerma1811/turbo-tailwind">Github Repo for this blog</a></li>
<li><a href="https://tailwindcss.com/blog/automatic-class-sorting-with-prettier">Automatic Tailwind CSS Class Sorting</a></li>
</ul>
]]></content:encoded>
            <author>hi@shubhamverma.me (Shubham Verma)</author>
        </item>
        <item>
            <title><![CDATA[Enable outlines and symbols support for React in VSCode!]]></title>
            <link>https://shubhamverma.me/blog/vs-code-extension-that-enable-symbols-and-outlines-support-for-your-react-files</link>
            <guid>2204610e-50bf-48ca-8d45-9a0c2a6528cb</guid>
            <pubDate>Fri, 03 Dec 2021 18:30:00 GMT</pubDate>
            <description><![CDATA[This is a simple extension that shows the symbols and outlines for a React
  file.]]></description>
            <content:encoded><![CDATA[<p>While working on React files in VSCode the most annoying thing is the lack of
symbols &#x26; outlines support.</p>
<p>🎉 So I created an extension that can finally support that for your React files!</p>
<blockquote>
<p>Links Below</p>
</blockquote>
<p>Here are the before and after screenshots:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1638578318646/mQqcc9dmi.png" alt="Image with React Outline enabled."></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1638578313783/mrVx5YR-2.png" alt="Image without React Outline enabled."></p>
<h2>Contributing</h2>
<p>I am open for contributions.Feel free to raise features requests or PRs!</p>
<p>Head over to the
<a href="https://github.com/ShubhamVerma1811/vscode-react-outline">Github repo</a> and make
a pull request or raise features requests or issues.</p>
<h3>Running Locally</h3>
<p>Clone this <a href="https://github.com/ShubhamVerma1811/vscode-react-outline">repo</a> and
start the “Debug: Start Debugging” command</p>
<hr>
<h2>Support</h2>
<p>If you liked this extensions then check out my other
<a href="https://marketplace.visualstudio.com/publishers/ShubhamVerma18">extensions</a> and
<a href="https://shbm.fyi/tw">follow me on twitter</a>.</p>
<hr>
<p>Made with ❤️ by <a href="https://shbm.fyi/">Shubham Verma</a></p>
]]></content:encoded>
            <author>hi@shubhamverma.me (Shubham Verma)</author>
        </item>
        <item>
            <title><![CDATA[Write Markdown In NextJS]]></title>
            <link>https://shubhamverma.me/blog/write-markdown-in-next-js</link>
            <guid>de874dce-fe47-44fa-8fa9-9ec035134fb9</guid>
            <pubDate>Mon, 28 Jun 2021 18:30:00 GMT</pubDate>
            <description><![CDATA[MDX is awesome!]]></description>
            <content:encoded><![CDATA[<p>In this short blog, I’ll show you how you can write Markdown in NextJS using
MDX.</p>
<h2>Installation</h2>
<ul>
<li>Before getting starting, I assume you have already initialized a NextJS
project.</li>
</ul>
<pre><code>yarn add @next/mdx @mdx-js/loader
</code></pre>
<p>OR</p>
<pre><code>npm install --save @next/mdx @mdx-js/loader
</code></pre>
<hr>
<h2>Configuration</h2>
<ul>
<li>In our <code>next.config.js</code>, add the following</li>
</ul>
<pre><code>const withMDX = require('@next/mdx')({
  extension: /\.mdx$/
})

module.exports = withMDX({
  pageExtensions: ['js', 'jsx', 'ts', 'tsx', 'md', 'mdx']
})
</code></pre>
<hr>
<h2>Usage</h2>
<p>Now we can create a <code>index.mdx</code> file in our <code>src</code></p>
<pre><code>&#x3C;!-- src/pages/index.mdx -->

# This is a Markdown Syntax

## React starts from here

import { useState } from "react";

export const Home = () => {
  const [count, setCount] = useState(0);
  return (
    &#x3C;div>
      &#x3C;h1>Count {count} &#x3C;/h1>
      &#x3C;button onClick={() => setCount((prev) => prev + 1)}> Increment &#x3C;/button>
    &#x3C;/div>
  );
};

&#x3C;Home />

## React ends here

## I can continue to write Markdown here
</code></pre>
<hr>
<h2>Output</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1624967131224/2GinYtCFs.gif?auto=compress" alt=""></p>
<hr>
<h2>References</h2>
<ul>
<li><a href="https://nextjs.org/docs/api-reference/next.config.js/custom-page-extensions">NextJS PageExtensions</a></li>
<li><a href="https://mdxjs.com/">MDXJS</a></li>
<li><a href="https://mdxjs.com/getting-started/next">MDX and NextJS</a></li>
</ul>
<hr>
<h2>Socials</h2>
<h3>If you like my content then do follow me on Twitter <a href="https://shbm.fyi/tw">Shubham Verma</a></h3>
]]></content:encoded>
            <author>hi@shubhamverma.me (Shubham Verma)</author>
        </item>
        <item>
            <title><![CDATA[Let's Polyfill - map(), filter() and reduce()]]></title>
            <link>https://shubhamverma.me/blog/lets-polyfill-map-filter-and-reduce</link>
            <guid>23613e06-2bf8-4574-a07e-f15a9c8d67c8</guid>
            <pubDate>Mon, 17 May 2021 18:30:00 GMT</pubDate>
            <description><![CDATA[The hello world of Polyfills]]></description>
            <content:encoded><![CDATA[<h2>Map</h2>
<p>map is an Array method that takes in a callback and returns an array of items
that were returned from the callback</p>
<p>Example:</p>
<pre><code>const arr = [1, 2, 3, 4];
const res = arr.map((el) => el * 2);

console.log(res); // returns [2,4,6,8]
</code></pre>
<p>Let’s create our own <code>map</code> method called <code>myMap</code></p>
<ul>
<li><code>myMap()</code> takes in a parameter which a callback/function.</li>
<li>It has a results array that gets returned by the <code>myMap</code> function.</li>
<li>The returned values from our <code>cb</code> are pushed in the <code>results</code> array.</li>
<li>The <code>this</code> here would be the array that we will use this <code>myMap</code> function on.</li>
<li>The traditional <code>map()</code> callback can take 3 args. element, index and the
source arr. We have done the same.</li>
</ul>
<pre><code>function myMap(cb, thisArg) {
  const arr = [];

  for (let i = 0; i &#x3C; this.length; i++) {
    if (!Object.hasOwn(this, i)) {
      arr.push(this[i]);
    } else {
      arr.push(callbackFn.call(thisArg, this[i], i, this));
    }
  }

  return arr;
}

// Doing this will allow us to use arr.myMap() syntax
Array.prototype.myMap = myMap;

const arr = [1, 2, 3, 4, 5, 6];
const myMapResult = arr.myMap((el, _idx, _arr) => {
  return el * 2;
});

console.log(myMapResult); //[2, 4, 6, 8, 10, 12];
</code></pre>
<hr>
<h2>Filter</h2>
<p><code>filter()</code> is an Array method that takes in a callback and returns an array of
items that satisfy the condition provided in our callback</p>
<p>Example:</p>
<pre><code>const arr = [1, 2, 3, 4];
const res = arr.filter((el) => el % 2); // only return even numbers

console.log(res); // [2,4]
</code></pre>
<p>Let’s create our own <code>filter</code> method called <code>myFilter</code></p>
<ul>
<li><code>myFilter()</code> takes in a parameter which a callback/function.</li>
<li>It has a results array that gets returned at the end.</li>
<li>The returned values from our <code>cb</code> are pushed in the <code>results</code> array.</li>
<li>The <code>this</code> here would be the array that we will use this <code>myFilter</code> function
on.</li>
<li>The traditional <code>filter()</code> callback can take 3 args. element, index and the
source arr. We have done the same.</li>
</ul>
<pre><code>function myFilter(cb, thisArgs) {
  if (!Array.isArray(this)) {
    throw new TypeError('FIlter must be run on array');
  }

  const arr = [];

  for (let i = 0; i &#x3C; this.length; i++) {
    if (callbackFn.call(thisArg, this[i], i, this)) {
      arr.push(this[i]);
    }
  }

  return arr;
}

// Doing this will allow us to use arr.myFilter() syntax
Array.prototype.myFilter = myFilter;

const arr = [1, 2, 3, 4, 5, 6];

const foo = [
  { name: 'S', age: 2 },
  { name: 'V', age: 3 },
];

const myFilterResult = foo.myFilter((el, _idx, _arr) => {
  return el.name !== 'S';
});

console.log(myFilterResult); // [{ name: "V", age: 3 }]
</code></pre>
<hr>
<h2>Reduce</h2>
<p>Here the MDN definition of it.</p>
<p>The <code>reduce()</code> method executes a reducer function (that you provide) on each
element of the array, resulting in a single output value.</p>
<p>It takes in two important parameters. <code>accumulater</code> and <code>currentValue</code></p>
<p>Example:</p>
<pre><code>const arr = [1, 2, 3, 4];
const res = arr.reduce((acc, curr) => {
  acc += curr;
  return acc;
}); // 10

console.log(res); // 10
</code></pre>
<p>Lets create our own <code>reduce()</code> method called <code>myReduce()</code></p>
<ul>
<li><code>myReduce()</code> takes in a parameter which a callback/function.</li>
<li>It returns a single reduced value.</li>
<li>The returned values from our <code>cb</code> is assigned to the <code>acc</code>.</li>
<li>The <code>this</code> here would be the array that we will use this <code>myReduced</code> function
on.</li>
<li>The traditional <code>reduced()</code> callback can take 4 args. accumulator,
currentValue, index and the source arr. We have done the same.</li>
</ul>
<pre><code>function myReduce(cb, initialValue) {
  let prev = typeof initialValue !== 'undefined' ? initialValue : this?.[0];
  if (!this.length &#x26;&#x26; typeof prev === 'undefined')
    throw new Error('emoty lenfth');

  let i = typeof initialValue !== 'undefined' ? 0 : 1;

  for (; i &#x3C; this.length; i++) {
    if (Object.hasOwn(this, i)) {
      prev = cb.call(this, prev, this[i], i, this);
    }
  }

  return prev;
}

// Doing this will allow us to use arr.myReduce() syntax
Array.prototype.myReduce = myReduce;

const myReduceResult = arr.myReduce((acc, curr, _idx, _arr) => {
  acc += curr;
  return acc;
});

console.log(myReduceResult); // 21
</code></pre>
<hr>
<p>If you find any errors or edge cases in the above code then please let me know.
I am happy to learn about them and add them here.</p>
<p>In the next blog in this series, I’ll try and write our own debounce function
from the loadash library</p>
<p>Also, if you guys want to see polyfills of your libs then let me know in the
comments.</p>
<p>Hope this blog was helpful to you.</p>
]]></content:encoded>
            <author>hi@shubhamverma.me (Shubham Verma)</author>
        </item>
        <item>
            <title><![CDATA[Search a User's Hashnode blogs right from your VSCode!]]></title>
            <link>https://shubhamverma.me/blog/search-a-users-hashnode-blogs-right-from-your-vs-code</link>
            <guid>drafts.cf6d6f81-166e-470f-abe6-f482aba83965</guid>
            <pubDate>Wed, 17 Feb 2021 18:30:00 GMT</pubDate>
            <author>hi@shubhamverma.me (Shubham Verma)</author>
        </item>
        <item>
            <title><![CDATA[Implement Protected Routes in NextJS!]]></title>
            <link>https://shubhamverma.me/blog/implement-protected-routes-in-next-js</link>
            <guid>ff8a08aa-8064-4ca2-ba47-2b2f481cbb83</guid>
            <pubDate>Wed, 20 Jan 2021 02:18:00 GMT</pubDate>
            <description><![CDATA[Protecting Routes from unauthenticated users is a crucial part of any app]]></description>
            <content:encoded><![CDATA[<p>Protecting Routes from unauthenticated users is a crucial part of any app.</p>
<p>In this blog, I’ll show you exactly how to do that with your NextJS pages using
Higher-Order Components 1</p>
<p>There can be several ways of authenticating a user like using cookies or JWT
tokens.2</p>
<p>I’ll be using JWT token as an example, where the <code>accessToken</code> is stored in the
<code>localStorage</code></p>
<p>Let’s consider a page “/dashboard”. This page should be only accessed by
authenticated users</p>
<h3>In our <code>Dashboard.jsx</code></h3>
<pre><code>// pages/dashboard.jsx
import withAuth from 'HOC/withAuth.js'
const Dashboard = ({ user }) => {
  return (
    &#x3C;div>
      &#x3C;h1>Dashboard&#x3C;/h1>
      &#x3C;h2>{user.name}&#x3C;/h2>
    &#x3C;/div>
  )
}

export default withAuth(Dashboard)
</code></pre>
<p>Notice that we are importing <code>withAuth.jsx</code> and exporting the page by passing it
as an argument. That is all we need to do for our pages.</p>
<hr>
<h3>In our <code>withAuth.jsx</code></h3>
<p>I’ll show you two methods of implementations:</p>
<ul>
<li>Method 1: We don’t verify the token</li>
<li>Method 2: We verify the token</li>
</ul>
<h3>Method 1: (We don’t verify the token)</h3>
<pre><code>// HOC/withAuth.jsx
import { useRouter } from 'next/router'
const withAuth = (WrappedComponent) => {
  return (props) => {
    // checks whether we are on client / browser or server.
    if (typeof window !== 'undefined') {
      const Router = useRouter()

      const accessToken = localStorage.getItem('accessToken')

      // If there is no access token we redirect to "/" page.
      if (!accessToken) {
        Router.replace('/')
        return null
      }

      // If this is an accessToken we just render the component that was passed with all its props

      return &#x3C;WrappedComponent {...props} />
    }

    // If we are on server, return null
    return null
  }
}

export default withAuth
</code></pre>
<hr>
<h3>Method 2: We need to verify the token.</h3>
<pre><code>// HOC/withAuth.jsx
import { useRouter } from 'next/router'
import { useEffect, useState } from 'react'
import verifyToken from 'services/verifyToken'

const withAuth = (WrappedComponent) => {
  return (props) => {
    const Router = useRouter()
    const [verified, setVerified] = useState(false)

    useEffect(async () => {
      const accessToken = localStorage.getItem('accessToken')
      // if no accessToken was found,then we redirect to "/" page.
      if (!accessToken) {
        Router.replace('/')
      } else {
        // we call the api that verifies the token.
        const data = await verifyToken(accessToken)
        // if token was verified we set the state.
        if (data.verified) {
          setVerified(data.verified)
        } else {
          // If the token was fraud we first remove it from localStorage and then redirect to "/"
          localStorage.removeItem('accessToken')
          Router.replace('/')
        }
      }
    }, [])

    if (verified) {
      return &#x3C;WrappedComponent {...props} />
    } else {
      return null
    }
  }
}

export default withAuth
</code></pre>
<hr>
<p>Footers:</p>
<ol>
<li><a href="https://reactjs.org/docs/higher-order-components.html">React Higher-Order Components</a></li>
<li><a href="https://debbie.hashnode.dev/a-beginners-guide-to-user-authentication-and-authorization-with-json-web-tokens-versus-sessions-in-nodejs">User authentication in NodeJS</a></li>
</ol>
<hr>
<p>Wasn’t that easy!</p>
<p>I hope this blog helped you. If you got any queries or feedback then let me know
😀</p>
]]></content:encoded>
            <author>hi@shubhamverma.me (Shubham Verma)</author>
        </item>
    </channel>
</rss>