<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Sidharth Mohanty</title>
    <description>The latest articles on DEV Community by Sidharth Mohanty (@sidmohanty11).</description>
    <link>https://dev.to/sidmohanty11</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F652164%2Ff52feb10-22d9-4dba-b358-4c2eefbd96d0.jpeg</url>
      <title>DEV Community: Sidharth Mohanty</title>
      <link>https://dev.to/sidmohanty11</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/sidmohanty11"/>
    <language>en</language>
    <item>
      <title>How to Fix React Hydration Mismatches with a Simple Inline Script Hack (Zero Flicker SSR)</title>
      <dc:creator>Sidharth Mohanty</dc:creator>
      <pubDate>Sun, 29 Jun 2025 14:41:01 +0000</pubDate>
      <link>https://dev.to/sidmohanty11/how-to-fix-react-hydration-mismatches-with-a-simple-inline-script-hack-zero-flicker-ssr-44fi</link>
      <guid>https://dev.to/sidmohanty11/how-to-fix-react-hydration-mismatches-with-a-simple-inline-script-hack-zero-flicker-ssr-44fi</guid>
      <description>&lt;p&gt;React's hydration process is a crucial part of server-side rendering (SSR) where React attaches event handlers to the server-rendered HTML. However, sometimes we encounter situations where the server and client need to render different content, which can lead to hydration mismatches. In this blog post, we'll explore a neat trick to handle this scenario without triggering React's hydration errors.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem
&lt;/h2&gt;

&lt;p&gt;When using React with SSR, you might encounter situations where you need to render different content on the server versus the client. A common example is when we need to render something that depends upon browser cookies. React expects the server-rendered HTML to match exactly what would be rendered on the client during hydration. If there's a mismatch, React throws a hydration error:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Warning: Text content did not match. Server: "Bye World" Client: "Hello World"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Example Approach (That Causes Problems)
&lt;/h2&gt;

&lt;p&gt;Here's a typical example that would cause hydration issues:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Home&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;isBrowser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;undefined&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;isBrowser&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Hello World&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Bye World&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;This code will cause a hydration mismatch because the server renders "Bye World" (since &lt;code&gt;window&lt;/code&gt; is undefined), but the client renders "Hello World".&lt;/p&gt;

&lt;p&gt;&lt;em&gt;You could use useEffect here and render but that would cause a flicker.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Solution: The Inline Script Trick
&lt;/h2&gt;

&lt;p&gt;Here's where our trick comes in. We can use an inline script that executes immediately after the HTML is rendered but before React hydration begins. Here's how it works:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;use client&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;isBrowser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;undefined&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Home&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;inlineScriptFn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;helloElement&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hello&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;helloElement&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;helloElement&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;textContent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Hello World&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;isBrowser&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"hello"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Hello World&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"hello"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Bye World&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;script&lt;/span&gt; &lt;span class="na"&gt;dangerouslySetInnerHTML&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;__html&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`(&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;inlineScriptFn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt;&lt;span class="s2"&gt;)()`&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;Let's break down how this trick works:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;On the server, React renders &lt;code&gt;&amp;lt;h1 id="hello"&amp;gt;Bye World&amp;lt;/h1&amp;gt;&lt;/code&gt; because &lt;code&gt;isBrowser()&lt;/code&gt; returns &lt;code&gt;false&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Immediately after the HTML is sent to the browser, but before React hydration begins, our inline script executes:

&lt;ul&gt;
&lt;li&gt;It finds the element with id "hello"&lt;/li&gt;
&lt;li&gt;Changes its content to "Hello World"&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;When React begins hydration, it sees "Hello World" in both:

&lt;ul&gt;
&lt;li&gt;The actual DOM (thanks to our script)&lt;/li&gt;
&lt;li&gt;The virtual DOM it wants to render (because &lt;code&gt;isBrowser()&lt;/code&gt; is now &lt;code&gt;true&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;No hydration mismatch occurs because the content matches!&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Why This Works
&lt;/h2&gt;

&lt;p&gt;This approach works because:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The inline script executes synchronously before React's hydration process begins&lt;/li&gt;
&lt;li&gt;By the time React performs hydration, the DOM already contains the client-side content&lt;/li&gt;
&lt;li&gt;React sees matching content in both the real DOM and its virtual DOM&lt;/li&gt;
&lt;/ol&gt;

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

&lt;p&gt;This hydration trick provides a clean solution to handle server/client content differences without triggering React's hydration warnings.&lt;/p&gt;

&lt;p&gt;At &lt;a href="https://builder.io" rel="noopener noreferrer"&gt;Builder.io&lt;/a&gt;, we rely on this very inline-script hydration trick to select the winning variant in our SDKs. You can see the production implementation here: &lt;a href="https://github.com/BuilderIO/builder/blob/main/packages/sdks/src/components/content-variants/inlined-fns.ts" rel="noopener noreferrer"&gt;inlined-fns.ts&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I first discovered the technique while building "&lt;a href="https://www.builder.io/c/docs/variant-containers" rel="noopener noreferrer"&gt;Variant Containers&lt;/a&gt;" in our SDKs (block-level personalization container), essentially A/B testing at the block level, and it felt downright magical once it clicked. If you’re curious, you can peek at its implementation here: &lt;a href="https://github.com/BuilderIO/builder/blob/main/packages/sdks/src/blocks/personalization-container/helpers/inlined-fns.ts#L9" rel="noopener noreferrer"&gt;inlined-fns.ts&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Have you run into hydration mismatches or found other clever solutions? I’d love to hear about your experience. Feel free to reach out, and if you’d like to see what else I’m up to, visit my portfolio at &lt;a href="//sidharthmohanty.com"&gt;sidharthmohanty.com&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>react</category>
      <category>nextjs</category>
    </item>
    <item>
      <title>How to Dynamically Render HTML Tags in Angular 16.2+</title>
      <dc:creator>Sidharth Mohanty</dc:creator>
      <pubDate>Sat, 22 Jun 2024 10:17:16 +0000</pubDate>
      <link>https://dev.to/builderio/how-to-dynamically-render-html-tags-in-angular-162-42b7</link>
      <guid>https://dev.to/builderio/how-to-dynamically-render-html-tags-in-angular-162-42b7</guid>
      <description>&lt;p&gt;At Builder.io, we use &lt;a href="https://mitosis.builder.io/" rel="noopener noreferrer"&gt;Mitosis&lt;/a&gt; to generate multi-framework SDKs, enabling us to maintain one codebase that outputs code for React, Preact, Solid, Vue, Angular, Svelte, and more.. Some frameworks leverage normal JSX syntax like React but not all frameworks use JSX right? In React, achieving dynamic HTML generation is straightforward--simply use state to update the tag directly. However, with Angular, it wasn't possile until the version 16.2, which introduced the &lt;code&gt;ngComponentOutlet&lt;/code&gt; directive.&lt;/p&gt;

&lt;h2&gt;
  
  
  Dynamic HTML Generation in React
&lt;/h2&gt;

&lt;p&gt;Here’s an example of dynamic HTML generation in React:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;App&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;Tag&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setTag&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;div&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;updateTag&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;setTag&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;select&lt;/span&gt; &lt;span class="na"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;updateTag&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;option&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"div"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;div&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;option&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;option&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"span"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;span&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;option&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;option&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"p"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;p&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;option&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;option&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"a"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;a&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;option&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;option&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"h1"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;h1&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;option&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;select&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Tag&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Inside &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;Tag&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Tag&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;In this example, the &lt;code&gt;Tag&lt;/code&gt; state updates based on the selected value, rendering the corresponding HTML tag dynamically. We wanted to replicate this functionality in Angular. Is it possible? Yes, with some modifications!&lt;/p&gt;

&lt;h2&gt;
  
  
  Dynamic Component Generation in Angular
&lt;/h2&gt;

&lt;p&gt;In Angular, you can achieve dynamic component generation using the &lt;code&gt;ngComponentOutlet&lt;/code&gt; directive. Here’s how:&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Define Dynamic Components
&lt;/h3&gt;

&lt;p&gt;First, we create components for each tag we want to generate dynamically (you can automate this using a script):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ViewChild&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ElementRef&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@angular/core&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dynamic-div, DynamicDiv&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`&amp;lt;div #v&amp;gt;&amp;lt;ng-content&amp;gt;&amp;lt;/ng-content&amp;gt;&amp;lt;/div&amp;gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;standalone&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;DynamicDiv&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;ViewChild&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;v&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;read&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ElementRef&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ElementRef&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dynamic-h1, DynamicH1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`&amp;lt;h1 #v&amp;gt;&amp;lt;ng-content&amp;gt;&amp;lt;/ng-content&amp;gt;&amp;lt;/h1&amp;gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;standalone&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;DynamicH1&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;ViewChild&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;v&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;read&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ElementRef&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ElementRef&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dynamic-a, DynamicA&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`&amp;lt;a #v href=""&amp;gt;&amp;lt;ng-content&amp;gt;&amp;lt;/ng-content&amp;gt;&amp;lt;/a&amp;gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;standalone&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;DynamicA&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;ViewChild&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;v&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;read&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ElementRef&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ElementRef&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dynamic-button, DynamicButton&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`&amp;lt;button #v&amp;gt;&amp;lt;ng-content&amp;gt;&amp;lt;/ng-content&amp;gt;&amp;lt;/button&amp;gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;standalone&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;DynamicButton&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;ViewChild&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;v&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;read&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ElementRef&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ElementRef&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Why are there unused refs here you ask? You can extend this functionality to dynamically add attributes or action attributes to any of the elements. A more complete example can be found &lt;a href="https://github.com/BuilderIO/builder/blob/main/packages/sdks/overrides/angular/src/components/dynamic-renderer/dynamic-renderer.ts" rel="noopener noreferrer"&gt;here in our Opensource SDKs repository&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Step 2: Create a Dynamic Renderer Component
&lt;/h3&gt;

&lt;p&gt;Next, we create a &lt;code&gt;DynamicRenderComponent&lt;/code&gt; that will use the &lt;code&gt;ngComponentOutlet&lt;/code&gt; directive to render the selected component dynamically:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;Input&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;ViewChild&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;ViewContainerRef&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;TemplateRef&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;Renderer2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;OnChanges&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@angular/core&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;CommonModule&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@angular/common&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dynamic-renderer&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`
    &amp;lt;ng-template #tagTemplate&amp;gt;&amp;lt;ng-content&amp;gt;&amp;lt;/ng-content&amp;gt;&amp;lt;/ng-template&amp;gt;
    &amp;lt;ng-container
      *ngComponentOutlet="Element; content: myContent"&amp;gt;
    &amp;lt;/ng-container&amp;gt;
  `&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;standalone&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;imports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;CommonModule&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;DynamicRenderComponent&lt;/span&gt; &lt;span class="k"&gt;implements&lt;/span&gt; &lt;span class="nx"&gt;OnChanges&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Input&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="nx"&gt;Tag&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;div&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;ViewChild&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;tagTemplate&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;static&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="nx"&gt;tagTemplate&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;TemplateRef&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nl"&gt;Element&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;DynamicDiv&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;myContent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;vcRef&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ViewContainerRef&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

  &lt;span class="nf"&gt;ngOnChanges&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;switch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Tag&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;div&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Element&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;DynamicDiv&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;button&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Element&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;DynamicButton&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;a&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Element&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;DynamicA&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;h1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Element&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;DynamicH1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nl"&gt;default&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Element&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;DynamicDiv&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;myContent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;vcRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createEmbeddedView&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tagTemplate&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;rootNodes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;];&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 3: Create the Main Component
&lt;/h3&gt;

&lt;p&gt;Finally, we create the main component that includes a dropdown to select the desired tag and renders the dynamic component accordingly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Component&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@angular/core&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;bootstrapApplication&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@angular/platform-browser&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;DynamicRenderComponent&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./dynamic-render.component&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;app-root&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`
    &amp;lt;select (change)="onChange($event)"&amp;gt;
      &amp;lt;option value="div"&amp;gt;div&amp;lt;/option&amp;gt;
      &amp;lt;option value="button"&amp;gt;button&amp;lt;/option&amp;gt;
      &amp;lt;option value="span"&amp;gt;span&amp;lt;/option&amp;gt;
      &amp;lt;option value="p"&amp;gt;p&amp;lt;/option&amp;gt;
      &amp;lt;option value="a"&amp;gt;a&amp;lt;/option&amp;gt;
      &amp;lt;option value="h1"&amp;gt;h1&amp;lt;/option&amp;gt;
    &amp;lt;/select&amp;gt;
    &amp;lt;dynamic-renderer [Tag]="Tag"&amp;gt;Inside {{ Tag }}&amp;lt;/dynamic-renderer&amp;gt;
  `&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;standalone&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;imports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;DynamicRenderComponent&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PlaygroundComponent&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;Tag&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;div&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nf"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Tag&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nf"&gt;bootstrapApplication&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;PlaygroundComponent&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;In this example, the &lt;code&gt;PlaygroundComponent&lt;/code&gt; handles the tag selection, and the &lt;code&gt;DynamicRenderComponent&lt;/code&gt; dynamically renders the selected tag. This approach ensures that we can generate dynamic HTML elements in Angular, similar to how it’s done in React.&lt;/p&gt;

&lt;p&gt;Try it out yourself using this GitHub &lt;a href="https://gist.github.com/sidmohanty11/74a2fb93ce2b512f49bb64020520222c" rel="noopener noreferrer"&gt;gist&lt;/a&gt;. I hope you found this post insightful. While I'm not an Angular expert, we wanted to solve this problem and share our approach. If you know of a better way to handle this specific scenario in Angular, please share your insights in the comments. Your feedback and suggestions are always welcome!&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>angular</category>
      <category>javascript</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Sync your fork from the terminal</title>
      <dc:creator>Sidharth Mohanty</dc:creator>
      <pubDate>Sat, 16 Mar 2024 06:53:46 +0000</pubDate>
      <link>https://dev.to/sidmohanty11/how-i-sync-my-forked-repo-with-the-parent-using-this-cli-tool-saves-me-a-lot-of-time-hoc</link>
      <guid>https://dev.to/sidmohanty11/how-i-sync-my-forked-repo-with-the-parent-using-this-cli-tool-saves-me-a-lot-of-time-hoc</guid>
      <description>&lt;p&gt;As a collaborator on GitHub projects who heavily relies on forks, I found myself performing a repetitive task every morning: syncing my forks with the parent repositories to stay up-to-date. &lt;strong&gt;This manual 3-step process of navigating GitHub, checking for updates, and syncing felt like an everyday chore.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Being a developer, I decided to automate this!&lt;/p&gt;

&lt;p&gt;Introducing &lt;a href="https://github.com/sidmohanty11/syncb" rel="noopener noreferrer"&gt;&lt;strong&gt;syncb&lt;/strong&gt;&lt;/a&gt;, a simple script that streamlines your workflow with a single command. With &lt;code&gt;syncb&lt;/code&gt;, you can effortlessly sync both public and private forks, saving you valuable time and frustration.&lt;/p&gt;

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

&lt;h3&gt;
  
  
  Getting Started
&lt;/h3&gt;

&lt;p&gt;Install &lt;code&gt;syncb&lt;/code&gt; globally using npm:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm i &lt;span class="nt"&gt;-g&lt;/span&gt; syncb
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run &lt;code&gt;syncb&lt;/code&gt; in your terminal.&lt;/p&gt;

&lt;p&gt;That's it! &lt;code&gt;syncb&lt;/code&gt; seamlessly syncs your repository with the latest commits from the parent repository.&lt;/p&gt;

&lt;h3&gt;
  
  
  Using Private Forks
&lt;/h3&gt;

&lt;p&gt;Initially, I encountered authorization issues (401 errors) when syncing private forks. To overcome this, you can securely store a GitHub Personal Access Token (PAT) with repo access in your environment variable as &lt;code&gt;GITHUB_TOKEN&lt;/code&gt; (e.g., .zshrc). &lt;code&gt;syncb&lt;/code&gt; will automatically leverage this token for private repo syncing.&lt;/p&gt;

&lt;h3&gt;
  
  
  Share and Contribute!
&lt;/h3&gt;

&lt;p&gt;Did &lt;code&gt;syncb&lt;/code&gt; make your life easier? Share it with a star ⭐ on the &lt;a href="https://github.com/sidmohanty11/syncb" rel="noopener noreferrer"&gt;repository&lt;/a&gt;! Additionally, I'd love to hear your preferred fork syncing methods – perhaps you have a more efficient approach? Feel free to contribute to the project as well!&lt;/p&gt;

&lt;h3&gt;
  
  
  Connect with me!
&lt;/h3&gt;

&lt;p&gt;Visit &lt;a href="//sidharthmohanty.com"&gt;sidharthmohanty.com&lt;/a&gt; to stay connected.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>github</category>
      <category>opensource</category>
      <category>webdev</category>
    </item>
    <item>
      <title>How to Ensure Pixel-Perfect Comparisons Between Websites?</title>
      <dc:creator>Sidharth Mohanty</dc:creator>
      <pubDate>Sat, 03 Feb 2024 15:26:00 +0000</pubDate>
      <link>https://dev.to/builderio/how-to-ensure-pixel-perfect-comparisons-between-websites-26h6</link>
      <guid>https://dev.to/builderio/how-to-ensure-pixel-perfect-comparisons-between-websites-26h6</guid>
      <description>&lt;p&gt;So here at &lt;a href="https://builder.io/" rel="noopener noreferrer"&gt;Builder.io&lt;/a&gt;, my first task was to ensure that we migrated our site from Next.js to &lt;a href="https://github.com/BuilderIO/qwik" rel="noopener noreferrer"&gt;Qwik&lt;/a&gt; with a 100% pixel match. We aimed to utilize the power of Qwik to enhance our site's performance to unprecedented levels.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Spoiler: We began the migration, and you might think it's just a matter of adjusting HTML and CSS, right? But no, we use Builder CMS to serve our data, meaning we rely on custom components and components from the Builder SDK to make it work. This presented a challenge because you cannot directly change any CSS or other elements that appear different, as they are linked to something else.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We reached a point where it was “almost” ready, and I kept saying it was “almost matching.” Fortunately, Builder had already developed a tool called &lt;a href="https://github.com/BuilderIO/SSDiff" rel="noopener noreferrer"&gt;SSDiff&lt;/a&gt;, which facilitated the comparison of our websites, highlighting both the matches and the differences.&lt;/p&gt;

&lt;p&gt;However, the major limitation for me was the extensive back-and-forth during development. It was cumbersome to switch to another project, run the diff, it will take a screenshot, compare them, and determine the differences. Repeatedly updating CSS and checking for matches became a tedious process.&lt;/p&gt;

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

&lt;p&gt;To streamline this, I developed a Vite plugin called &lt;a href="https://www.npmjs.com/package/vite-plugin-realtime-diff" rel="noopener noreferrer"&gt;&lt;strong&gt;vite-plugin-realtime-diff&lt;/strong&gt;&lt;/a&gt; that allows direct in-browser diffing by simply adding &lt;strong&gt;&lt;code&gt;?_diff=true&lt;/code&gt;&lt;/strong&gt; to the URL. This significantly simplified my workflow, &lt;strong&gt;enabling real-time reflection of local changes in the browser.&lt;/strong&gt;&lt;/p&gt;

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

&lt;h3&gt;
  
  
  Getting Started with the plugin,
&lt;/h3&gt;

&lt;p&gt;Install the plugin in your Vite project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-D&lt;/span&gt; vite-plugin-realtime-diff
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and add this to your vite.config,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// vite.config.ts&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;realtimeDiff&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;vite-plugin-realtime-diff&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nf"&gt;defineConfig&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
       &lt;span class="p"&gt;...,&lt;/span&gt;
       &lt;span class="nf"&gt;realtimeDiff&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://builder.io/&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="c1"&gt;// the base url you want to target the diff to&lt;/span&gt;
     &lt;span class="p"&gt;],&lt;/span&gt; 
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now go to &lt;code&gt;http://localhost:5173/any-path?_diff=true&lt;/code&gt; to diff it with the url you provided to the plugin (for example here: &lt;a href="https://builder.io/any-path" rel="noopener noreferrer"&gt;https://builder.io/any-path&lt;/a&gt;).&lt;/p&gt;

&lt;h3&gt;
  
  
  Approach
&lt;/h3&gt;

&lt;p&gt;So its just a simple approach, imagine taking two websites (hint: iframe) and sandwich them one upon the other and then apply CSS overlay to learn the diff. This method proved so effective that I decided to share it and &lt;a href="https://github.com/BuilderIO/SSDiff/pull/6" rel="noopener noreferrer"&gt;contributed&lt;/a&gt; to the SSDiff project by adding this there. Especially for those undergoing a site migration using a different framework or looking to demonstrate their front-end development skills (imagine someone asking you, do this in pixel perfect fashion and you’re hired: you know what to use now). Essentially, this tool can help you achieve a 100% pixel match in realtime which can save you hours to explain why your margin padding are not matching.&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;If you're interested in contributing, please feel free to reach out; we are open to expanding this project further. For example, in the future we can support for CORS and create pipelines to check frontend snapshots. If you want to take a look at the tool, it has been added into the SSDiff project at Builder within a monorepo &lt;a href="https://github.com/BuilderIO/SSDiff" rel="noopener noreferrer"&gt;here&lt;/a&gt;. Thank you!&lt;/p&gt;

&lt;p&gt;If you want to reach me:&lt;br&gt;
Email : &lt;a href="mailto:sidmohanty11@gmail.com"&gt;sidmohanty11@gmail.com&lt;/a&gt;&lt;br&gt;
GitHub: &lt;a href="https://github.com/sidmohanty11" rel="noopener noreferrer"&gt;https://github.com/sidmohanty11&lt;/a&gt;&lt;br&gt;
LinkedIn: &lt;a href="https://www.linkedin.com/in/sidmohanty11" rel="noopener noreferrer"&gt;https://www.linkedin.com/in/sidmohanty11&lt;/a&gt;&lt;br&gt;
Twitter: &lt;a href="https://twitter.com/sidmohanty11" rel="noopener noreferrer"&gt;https://twitter.com/sidmohanty11&lt;/a&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>vite</category>
      <category>javascript</category>
      <category>frontend</category>
    </item>
    <item>
      <title>My LFX Journey: The Zowe App Store UI Project</title>
      <dc:creator>Sidharth Mohanty</dc:creator>
      <pubDate>Fri, 15 Sep 2023 17:03:20 +0000</pubDate>
      <link>https://dev.to/sidmohanty11/my-lfx-journey-the-zowe-app-store-ui-project-1iao</link>
      <guid>https://dev.to/sidmohanty11/my-lfx-journey-the-zowe-app-store-ui-project-1iao</guid>
      <description>&lt;p&gt;Hi everyone! I am Sidharth Mohanty a final year CS student from India. This summer, I got a chance to work on an awesome project called the App Store for Zowe under The Open Mainframe Project. So, here I wanted to share the complete journey, hope it will help someone get started with their open-source journey and even participate in mentorship programs such as LFX.&lt;/p&gt;

&lt;h3&gt;
  
  
  A little backstory of how I got selected.
&lt;/h3&gt;

&lt;p&gt;Long story short, I was browsing through the LFX mentorship portal after I completed my internship to look for some projects to contribute to. Surprisingly there was one project that caught my eye - The App Store which had mentioned all the tech stack that I was familiar with. So I was like, let's give it a shot - "as my mentor always said - never leave stones unturned from your side". I was very late but still I joined the Open Mainframe Project's Slack channel and messaged &lt;a href="https://www.linkedin.com/in/astrakou-software" rel="noopener noreferrer"&gt;Lenny (Leanid Astrakou)&lt;/a&gt;. After his first reply that the project was still accepting applications, I just went through the ZLUX repo and tried to understand as much as I could and get a brief idea about the App Store, I also watched previous meeting videos that explained ZWE's handler support and how it will help architect the App Store and applied for the mentorship program. Just the next day, Lenny messaged that he was conducting interviews for the project and asked to join. I was super nervous as I was very late plus I didn't have a very concrete picture of things. I joined the interview nonetheless and we went through some of my projects, and my work experiences. Then we talked about what is app store and just some brief ideas about what is Zowe, z/OS, and mainframe systems in general. A few days passed, I was exploring the App's framework a bit more and I messaged Lenny that I was super interested and that with a bit more time I could most definitely build the App Store. After a few days, he messages me a Mission Impossible dialogue - "your mission should you choose to accept it" and I was like YEAH! LETS GO! Fingers crossed, I was waking up in the mornings checking my email.. but one day I got the email! I was selected.&lt;/p&gt;

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

&lt;h3&gt;
  
  
  Why I shared this story?
&lt;/h3&gt;

&lt;p&gt;I believe mostly we lack the perseverance to showcase or make the mentors believe that we are the right person for the thing. We just apply and sit like a duck and hope we will get selected but no, it's not just about that - majorly mentors focus on is the candidate "super" interested and have a basic understanding of things, If so, they take a leap of faith that you will be able to perform well upon their expectations (yeah talent matters, not saying it doesn't but to the project I applied, 177 others applied too so my chances should be pretty slim right?). Just communicating frequently, and sharing ideas and implementation details will 10x your chances of getting selected.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is the App Store?
&lt;/h3&gt;

&lt;p&gt;The Zowe App Store is a systems app of Zowe's Virtual Desktop where users can browse, install, and manage apps that run on top of the Zowe App's framework. As part of my LFX mentorship project, I was tasked with implementing the App Store from scratch. Along with me, Priyansh Mehta also got selected for this project to work on the backend side of things.&lt;br&gt;
What did I do in the last 3 months?&lt;br&gt;
This might be a long story, so please bear with me. So we started out our journey and Lenny introduced us to Zowe and mainframe terminologies and gave us our initial tasks to just explore and set up the ZLUX server in our local. After that, we had a major blockade that was we needed a mainframe system to test out the zwe commands as everything depended upon responses from that only.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A brief summary about zwe commands - it's the Zowe CLI tool to set up a Zowe instance easily on a z/OS system. With the release of Zowe 2.5, they introduced "handlers" support for the zwe components commands which means now it was possible to download and install plugins from external sources (registries) directly. This made the rollout for apps pretty fast. So, for example, if the Zlux editor was to be updated, it needed to get updated in one's local machine then either you would have to use FTP or GitHub to clone and setup the app again to see the changes on a z/OS system. This was pretty cumbersome, so now with one command you could install/upgrade/uninstall apps directly with zwe components commands. With this, it introduced one more challenge that you still need to be on the terminal to install apps right? Also, what about browsing open-source apps for the Virtual Desktop? We needed a solution and that was the App Store.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We first explored with IBM's Z trial which provides us with a VM (which is a Windows system) where you can access z/OS from the terminal. We found out that we could not access the internet on the VM which just destroyed our hope to test our code there. Also, another limitation was it was configured with an earlier version of Zowe so it didn't have the latest zwe components commands support so we couldn't even test out the responses. We then tried another approach with IBM's Z Xplore, which gives us a mainframe access to learn about Zowe's products. We, being kids thought it was great that we now have the access, and without any consultation or permission we just copied a Zowe 2.9 instance to that mainframe, and we got banned! Yep, it was not for development purposes, it was handling 50K+ users who were learning Zowe using that mainframe so resources were pretty limited. We tried to play around, and work around things but with no success. A huge shoutout to Ross from IBM who helped us throughout the process. We at least got some knowledge about a z/OS system.&lt;/p&gt;

&lt;p&gt;I had parallelly started working on the UI part, so I was making progress there. Firstly when I saw some screenshots of the App's framework's Virtual Desktop - I was mindblown by how they had architected a complete Desktop inside a browser and how the apps that were created could be made with multiple frameworks (Angular, React, and iframe). I realized how it helped people working on mainframe systems as someone working on a mainframe means 24x7 being on a terminal working on jobs. But, with this, it was connected with a ZSS server through an API mediation layer which helped users to work directly from their machines (let's say windows/mac/linux) and use the Virtual Desktop (kind of a VM) to directly run jobs or work on a z/OS machine. Just so, I was not stuck with not having a mainframe system, I built a mock server of my own to replicate the behaviors of a ZSS Server that we were going to write in C language.&lt;/p&gt;

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



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



&lt;p&gt;I created an &lt;a href="https://github.com/sidmohanty11/zowe-apps-playground" rel="noopener noreferrer"&gt;apps-playground repo&lt;/a&gt; mimicking a similar setup so that I could re-iterate through the UI pretty fast and host the UI using GitHub pages for faster feedback. After getting a good idea about the implementation of the UI part, I gradually migrated to create "The App Store". We used React to build the app. When I did the migration, I saw the project was using Webpack 4 for packaging apps, so I created a whole new plugin for Webpack 5 (for faster builds and reduced bundle sizes) and used the latest React v18 (previous apps used v16 and class components) for better performance and maintainability. I implemented a carousel for the "Discover" page and built the entire UI fully responsive. It was a bit tricky as we were using a window inside the browser window, so subscribing to a window resizing event was necessary and I built a custom hook to address that.&lt;/p&gt;

&lt;p&gt;Another major challenge was the routing, routing inside an App inside a browser gets tricky as we don’t have access to path URLs and variables. To tackle this part, I used the memory router of React Navigation ​​which stores its locations internally in an array. This allowed to navigate among different views easily.&lt;/p&gt;

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



&lt;p&gt;PRs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/zowe/zlux-app-manager/pull/537" rel="noopener noreferrer"&gt;Add App Store app to system apps&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/zowe/zlux-build/pull/127" rel="noopener noreferrer"&gt;Install config for app store&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/zowe/zlux-app-server/pull/267" rel="noopener noreferrer"&gt;Install app store on init server as a system app&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Other: &lt;a href="https://github.com/zowe/docs-site/pull/2918" rel="noopener noreferrer"&gt;Chore: minor fixes to the zwe components&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Lenny helped us throughout and made sure that we were not blocked and were making progress as we didn't have a mainframe setup we couldn't make much progress with the backend part. But, folks from Vicom were super helpful for extending us a mainframe and allowing us to develop the App Store there. A huge shoutout to Randall from Vicom for that, he also helped us throughout as the mainframe we got access to had Zowe v1, but we needed the latest one, so he set up v2.9 for us which was a huge task. With that, we had access to a mainframe and Zowe v2.9. We were finally able to test out the zwe commands and structured our app based on that.&lt;/p&gt;

&lt;p&gt;With this, I added a new systems app: "The App Store" to the Virtual Desktop and built the entire UI, making a full research documentation for the npm handler implementation and outputs that we will use to design the backend.&lt;/p&gt;

&lt;p&gt;My ZWE Research document can be found &lt;a href="https://wise-cardinal-c76.notion.site/ZWE-research-efd85513b8f64029bf68ef9b7facd770" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

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



&lt;p&gt;Some other contributions that I made include, creating a &lt;a href="https://github.com/sidmohanty11/zlux-todo-app" rel="noopener noreferrer"&gt;Zlux todo app&lt;/a&gt; and publishing it to npm. I analyzed their GitHub actions script and built a &lt;a href="https://github.com/sidmohanty11/zlux-todo-app/tree/main/build/component" rel="noopener noreferrer"&gt;shell script&lt;/a&gt; to build and deploy the package similar to the others (PAX format). This work was pretty interesting and we were able to use this to play around with the "schema for the plugins" that we were planning to use for the apps.&lt;/p&gt;

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


&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;Looking back on the past three months, I am proud of the progress we made on this extensive project. While we faced numerous challenges along the way, we overcame them and were able to achieve significant milestones.&lt;/p&gt;

&lt;p&gt;Although there is still work to be done, such as refining the backend and making additions to Zowe commands and schema changes to the package.json file to add plugin information, our efforts have laid a solid foundation for future development. I am excited to continue contributing to this project and working towards its success in the future.&lt;/p&gt;

&lt;p&gt;Overall, this experience has been both challenging and rewarding. I have gained valuable skills and knowledge that I can apply to future projects, and I look forward to utilizing them in my continued work with this project. Thank you to Lenny who was there for us throughout the journey and being such an amazing mentor, we couldn't have asked more from him - he helped us in every step of the way. Also, Priyansh and I had numerous discussions and meetings to architect things along the way and I liked a lot listening to his perspectives and enjoyed the teamwork overall. This sums up my journey. Thanks for reading this far and stay tuned for major updates coming soon in the near future.&lt;/p&gt;

&lt;p&gt;Here is the YouTube video summarizing our progress with our mentor:&lt;br&gt;
&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/L1tFEe0u4qA?start=3"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;If you want to reach me:&lt;br&gt;
Email: &lt;a href="mailto:sidmohanty11@gmail.com"&gt;sidmohanty11@gmail.com&lt;/a&gt;&lt;br&gt;
GitHub: &lt;a href="https://github.com/sidmohanty11" rel="noopener noreferrer"&gt;https://github.com/sidmohanty11&lt;/a&gt;&lt;br&gt;
LinkedIn: &lt;a href="https://www.linkedin.com/in/sidmohanty11" rel="noopener noreferrer"&gt;https://www.linkedin.com/in/sidmohanty11&lt;/a&gt;&lt;br&gt;
Twitter: &lt;a href="https://twitter.com/sidmohanty11" rel="noopener noreferrer"&gt;https://twitter.com/sidmohanty11&lt;/a&gt;&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>javascript</category>
      <category>react</category>
      <category>webdev</category>
    </item>
    <item>
      <title>How to Add a Custom Domain to GitHub Pages (Hostinger Edition)</title>
      <dc:creator>Sidharth Mohanty</dc:creator>
      <pubDate>Tue, 04 Jul 2023 06:12:47 +0000</pubDate>
      <link>https://dev.to/sidmohanty11/how-to-add-a-custom-domain-to-github-pages-hostinger-edition-p4p</link>
      <guid>https://dev.to/sidmohanty11/how-to-add-a-custom-domain-to-github-pages-hostinger-edition-p4p</guid>
      <description>&lt;p&gt;I recently finished my portfolio website, and it was a dream come true to have a small space of my own on the internet. To make this happen, I bought a domain name from Hostinger. I was already using GitHub Pages to host my site, so I needed to add my new domain name to it.&lt;/p&gt;

&lt;p&gt;There weren't any videos on how to do this, so I went through the documentation. The process is a bit different for Hostinger, but if you're like me and you want to set things up quickly, you can follow this blog post.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Refer to &lt;a href="https://docs.github.com/en/pages/configuring-a-custom-domain-for-your-github-pages-site/managing-a-custom-domain-for-your-github-pages-site" rel="noopener noreferrer"&gt;this&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Step 1: Go to your Hostinger domain DNS settings&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The first step is to go to your Hostinger domain DNS settings. You can do this by visiting &lt;a href="https://hpanel.hostinger.com/domain/yourdomain.com/dns" rel="noopener noreferrer"&gt;https://hpanel.hostinger.com/domain/yourdomain.com/dns&lt;/a&gt;. For example, &lt;a href="https://hpanel.hostinger.com/domain/sidharthmohanty.com/dns" rel="noopener noreferrer"&gt;https://hpanel.hostinger.com/domain/sidharthmohanty.com/dns&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 2: Delete the existing CNAME record and A type record&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;By default, there should be a CNAME record for your domain. This record points your domain to Hostinger's default website. We need to delete this record so that we can create a new CNAME record that points to our GitHub Pages site. Also delete any default &lt;code&gt;A&lt;/code&gt; type records so that there is no collision or clash.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 3: Create two new CNAME records&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We need to create two new CNAME records. The first record will point &lt;code&gt;www.yourdomain.com&lt;/code&gt; to &lt;code&gt;&amp;lt;your-github-username&amp;gt;.github.io&lt;/code&gt;. The second record will point &lt;code&gt;yourdomain.com&lt;/code&gt; to &lt;code&gt;&amp;lt;your-github-username&amp;gt;.github.io&lt;/code&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Enter Type - CNAME, Name - www, Points to - .github.io, TTL you can leave as default. This is for when someone types &lt;code&gt;www.yourdomain.com&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Then we need the same for APEX domains or when someone just types &lt;code&gt;yourdomain.com&lt;/code&gt;, for this enter another CNAME with Name - @ and Points to .github.io. This will automatically set an ALIAS type and add it to the DNS records.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It should look like this when added,&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;Step 4: Add the GitHub Pages IP addresses&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Finally, we need to add the IP addresses for GitHub Pages to our DNS records. Add A type, Name - @, TTL can be left as default records for each of the following IP addresses (should be copied and pasted into “Points to”)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="mf"&gt;185.199&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mf"&gt;108.153&lt;/span&gt;
&lt;span class="mf"&gt;185.199&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mf"&gt;109.153&lt;/span&gt;
&lt;span class="mf"&gt;185.199&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mf"&gt;110.153&lt;/span&gt;
&lt;span class="mf"&gt;185.199&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mf"&gt;111.153&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once you've added the IP addresses, your DNS records should look like this:&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;Step 5: Add the custom domain to GitHub Pages&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The last step is to add the custom domain to GitHub Pages. You can do this by going to your GitHub repository and clicking on the &lt;strong&gt;Settings&lt;/strong&gt; tab. Then, click on the &lt;strong&gt;Pages&lt;/strong&gt; tab and enter your custom domain in the &lt;strong&gt;Custom domain&lt;/strong&gt; field.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkyzldwyetx7pdtykkmln.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkyzldwyetx7pdtykkmln.png" alt="Custom Domain GitHub" width="800" height="583"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2aa6o4z2om9gyqjxllc2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2aa6o4z2om9gyqjxllc2.png" alt="Success DNS Check" width="775" height="182"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This should work out of the box if you’re using any “branch” to deploy your site as GitHub adds a CNAME file to the branch but if you’re using a static site generator, you need to add it manually to your &lt;code&gt;public&lt;/code&gt; folder.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;public/CNAME&lt;/code&gt; (should be capital with no extension)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;yourdomain&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;com&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Refer to &lt;a href="https://github.com/sidmohanty11/sidmohanty11.github.io/blob/main/public/CNAME" rel="noopener noreferrer"&gt;this&lt;/a&gt;. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Once you've followed all these steps, you should be able to access your website by visiting &lt;code&gt;https://yourdomain.com&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Congratulations!&lt;/strong&gt; You've now successfully added a custom domain to GitHub Pages.&lt;/p&gt;

&lt;p&gt;Thanks for reading this post ✨. Let me know if you find it useful. If you'd like to see my portfolio or what I am upto, you can visit my website at &lt;a href="https://sidharthmohanty.com/" rel="noopener noreferrer"&gt;https://sidharthmohanty.com/&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>tutorial</category>
      <category>cloud</category>
      <category>beginners</category>
    </item>
    <item>
      <title>I Switched to Astro for My Portfolio Website, and It's Awesome!</title>
      <dc:creator>Sidharth Mohanty</dc:creator>
      <pubDate>Mon, 03 Jul 2023 20:06:04 +0000</pubDate>
      <link>https://dev.to/sidmohanty11/i-switched-to-astro-for-my-portfolio-website-and-its-awesome-46e9</link>
      <guid>https://dev.to/sidmohanty11/i-switched-to-astro-for-my-portfolio-website-and-its-awesome-46e9</guid>
      <description>&lt;p&gt;&lt;strong&gt;Astro&lt;/strong&gt;, as they say, is the all-in-one web framework designed for speed. You can pull your content from anywhere and deploy it everywhere, all powered by your favorite UI components and libraries. I kind of agree; it's like we're writing pure HTML, CSS, and JS code, reminiscent of the old days of shipping pure HTML to the browser. This allows websites to become interactive in just a few seconds and also means moving away from frontend frameworks that ship JS and are bloated with other stuff, which slows down the initial load of a webpage.&lt;/p&gt;

&lt;p&gt;Okay coming to why I tried out Astro? To be honest, it's YouTube and blogs hyping "blazingly fast" websites. And yes, I wanted a &lt;strong&gt;blazingly fast&lt;/strong&gt; website too!&lt;/p&gt;

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

&lt;p&gt;And it really is &lt;strong&gt;blazingly fast&lt;/strong&gt;!&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A note to remember: This is not a SPA; it's an MPA. The number of pages that you create inside the &lt;code&gt;pages/&lt;/code&gt; directory will be built into different HTML pages.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Just like React or any frontend frameworks, where we think in terms of components, it's the same here as well.&lt;/p&gt;

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

&lt;p&gt;This means less code duplication, and everything can be in order, as opposed to static HTML sites that we used to create.&lt;/p&gt;

&lt;p&gt;Also, this doesn't mean we cannot add any interactivity. We most definitely can, and this is very neat with Astro because we can choose our own frameworks that we are comfortable with and mix and match them as well.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Ref: &lt;a href="https://docs.astro.build/en/core-concepts/framework-components/#using-framework-components" rel="noopener noreferrer"&gt;https://docs.astro.build/en/core-concepts/framework-components/#using-framework-components&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The developer experience is superb, I must say. Coming from a React.js background, I got familiar with the syntax and structure in no time. I explored some things through experimentation and googling. Here are some of them:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The server build time block contains top-level &lt;code&gt;await&lt;/code&gt;, so you can directly fetch your blogs or data.&lt;/li&gt;
&lt;li&gt;It has a pretty similar JSX templating structure (map, conditionals, etc.). The only difference is that for interactivity, you need to use &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; tags like in the old days (&lt;code&gt;getElementById&lt;/code&gt;, :P). But this was quite fun as I was just building my portfolio and didn't want any hefty useEffects or interactions (dynamic behavior).&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;set-html&lt;/code&gt; attribute is great! For every page I created, I wrote down some constant arrays where the values were strings that contained HTML elements. For example, if I needed to add a link to some page under an experience's description, I structured the content using strings, which I can now directly render as HTML without using any third-party libraries.&lt;/li&gt;
&lt;li&gt;Integrations? Please take a look at the number of &lt;a href="https://astro.build/integrations/" rel="noopener noreferrer"&gt;integrations&lt;/a&gt; they have, its enormous. This means all the good work has already been done for you, just plug and play. I used the Tailwind CSS integration, and it works like a charm. Although, in the near future, I am planning to study a bit about website SEO and integrate some other plugins to make my website even cooler.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you want to see the end output that Astro gives, here's a sneak peek: The server builds the entire HTML pages. The client-side &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; that we define inside the Astro components gets attached to the &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt; elements of the respective page HTML.&lt;/p&gt;

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

&lt;p&gt;Also, the SSR feature looks quite promising in Astro, but I'm yet to explore it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Lighthouse report:
&lt;/h3&gt;

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

&lt;h3&gt;
  
  
  Performance Insights (from builder.io): This tells you how bloated your website is with JS/Images/CSS and how you can optimize them.
&lt;/h3&gt;

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

&lt;p&gt;In the end, &lt;strong&gt;performance&lt;/strong&gt; really matters right? :)&lt;/p&gt;

&lt;p&gt;Link: &lt;a href="https://sidharthmohanty.com" rel="noopener noreferrer"&gt;https://sidharthmohanty.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;GitHub Link: &lt;a href="https://github.com/sidmohanty11/sidmohanty11.github.io" rel="noopener noreferrer"&gt;https://github.com/sidmohanty11/sidmohanty11.github.io&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Please let me know your feedback on the site. I would love to make some improvements. If you've explored Astro and want to share some knowledge, that would be amazing! I am in no way an expert on this topic, just sharing my experience with Astro because I loved the developer experience and how fast you can build sites and how fast the sites can be (no pun intended). Cheers!&lt;/p&gt;

&lt;p&gt;Thanks for tuning in! See you next time!&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>astro</category>
      <category>portfolio</category>
    </item>
    <item>
      <title>My Internship Journey at Dragonfruit AI</title>
      <dc:creator>Sidharth Mohanty</dc:creator>
      <pubDate>Thu, 15 Dec 2022 04:30:40 +0000</pubDate>
      <link>https://dev.to/sidmohanty11/my-internship-journey-at-dragonfruit-ai-51j4</link>
      <guid>https://dev.to/sidmohanty11/my-internship-journey-at-dragonfruit-ai-51j4</guid>
      <description>&lt;h3&gt;
  
  
  tldr;
&lt;/h3&gt;

&lt;p&gt;So, it all started with a cold apply to a job post, when I just knew that Dragonfruit does interesting things with videos. I got a reply from &lt;a href="https://in.linkedin.com/in/amol-kulkarni-intel" rel="noopener noreferrer"&gt;Amol Kulkarni&lt;/a&gt; (one of the co-founders of Dragonfruit) that let’s schedule interviews for an internship. Two technical interviews later, I got a call that I was selected. Three months in, I learned about:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;creating APIs in Python (Flask),&lt;/li&gt;
&lt;li&gt;E2E testing using cypress,&lt;/li&gt;
&lt;li&gt;database migrations using alembic,&lt;/li&gt;
&lt;li&gt;data models using sqlalchemy,&lt;/li&gt;
&lt;li&gt;pixi.js graphics&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;From knowing nothing about these technologies to deploying code that is being used by many fortune 500 companies, it has been a mind-blowing journey.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is Dragonfruit AI?
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://dragonfruit.ai/" rel="noopener noreferrer"&gt;Dragonfruit&lt;/a&gt; offers the world's most advanced enterprise AI analytics for digital investigations, occupancy management, real-time alerts, and beyond. It stands at the intersection of video, cloud, and AI, and it aims to be the go-to solution to store videos while providing powerful insights through analytics.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why I chose to intern at Dragonfruit AI?
&lt;/h3&gt;

&lt;p&gt;When I was a little kid, I was told that all the cool things are made in the valley (Silicon Valley) so I always dreamt of working with one. I learned about Dragonfruit and its work culture through some of the previous fellow interns’ blogs and couldn’t wait to give my 100% in my technical interviews. I was so excited that people from established institutes around the globe (Harvard, Stanford, USC, IITs, VIT) were working there and I’ve gotten a chance to work there as well.&lt;/p&gt;

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

&lt;h3&gt;
  
  
  Interview Rounds
&lt;/h3&gt;

&lt;p&gt;So here we go into the technical rounds:&lt;/p&gt;

&lt;h4&gt;
  
  
  Tech Round - 1
&lt;/h4&gt;

&lt;p&gt;The first round was an overall technical knowledge round taken by &lt;a href="https://in.linkedin.com/in/vshlgl" rel="noopener noreferrer"&gt;Vishal Goel&lt;/a&gt; (Software Architect at Dragonfruit) about my projects, mainly my GSoC project and projects in Golang (mostly where I had used concurrency model of Go). It was a conversation and code walkthrough where I was asked some questions based on them.&lt;/p&gt;

&lt;h4&gt;
  
  
  Tech Round - 2
&lt;/h4&gt;

&lt;p&gt;The second round was a coding challenge round taken by &lt;a href="https://in.linkedin.com/in/naveen-yannamani" rel="noopener noreferrer"&gt;Naveen Yannamani&lt;/a&gt; (Founding Engineer at Dragonfruit) where I was asked to code a mini version of jQuery using JavaScript based on the requirements of the question. It was quite challenging and also a fun challenge where I got to brainstorm a lot. I was able to complete the challenge within the time period and it felt so good that after the interview I was jumping and dancing like a drunk person.&lt;/p&gt;

&lt;p&gt;Both interviewers were amazing and had an amazing sense of aura. I never felt like I was stressed or something. It was quite fun actually. After all the interviews, I got a call - I was selected!&lt;/p&gt;

&lt;h3&gt;
  
  
  “The Dragonfruit Way”
&lt;/h3&gt;

&lt;p&gt;I would say I loved the way the internship was structured to maximize learning and inculcate organizational best practices. I was assigned a mentor, &lt;a href="https://in.linkedin.com/in/shubham-mandal-74a20093" rel="noopener noreferrer"&gt;Shubham Mandal&lt;/a&gt; (Member of the Technical Staff at Dragonfruit) who helped and guided me throughout my internship. He took out time from his busy schedule whenever I needed any help. It is also the same case with other “dragons”, they are there for you whenever you need any help. I fell in love with this super cooperative environment.&lt;/p&gt;

&lt;p&gt;Other than my technical meetings, we had a weekly all-hands meeting where both technical and non-technical aspects were discussed (on what is going on, what are the future plans, infrastructure changes, updates, and business development) and also a five-minute-me where an employee got a chance to share about himself/herself. We also had a weekly intern sync with Amol sir who gave us so many insights on how startups take decisions, how it all started and how it shaped itself to what it is now, advice to 20-year-olds, and many more.&lt;/p&gt;

&lt;h3&gt;
  
  
  What did I do in these three months?
&lt;/h3&gt;

&lt;h4&gt;
  
  
  E2E Testing using Cypress
&lt;/h4&gt;

&lt;p&gt;Firstly, I started out with e2e testing of frontend (React.js), I fixed around 20 tests and made them more generic. I wrote cleanup scripts so that any dangling server-side data can be removed before/afterward a test is run. I reduced the duration of the tests and made them faster by 36.06%.&lt;/p&gt;

&lt;h4&gt;
  
  
  Search filter dependency model
&lt;/h4&gt;

&lt;p&gt;I had zero experience in python but Shubham sir helped me a lot to set up the backend environment in my local and guided me through this. This was a feature that checked if the search filter is used in some place, and if so - notified the user with a modal.&lt;/p&gt;

&lt;h4&gt;
  
  
  Customer Showstopper Issues
&lt;/h4&gt;

&lt;h4&gt;
  
  
  Region Graphics
&lt;/h4&gt;

&lt;p&gt;This was one of the most challenging tasks. I needed to work with graphics (pixi.js) in which I had no previous experience. I improved the map region graphics to include interpoints functionality and then introduced drag functionality for regions and spatial filters.&lt;/p&gt;

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

&lt;h4&gt;
  
  
  Insights settings
&lt;/h4&gt;

&lt;p&gt;I converted the insight settings page to a modal with subgroups.&lt;/p&gt;

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

&lt;h4&gt;
  
  
  Views Folder structure
&lt;/h4&gt;

&lt;p&gt;This feature implementation looked a bit overwhelming to me at first. Previously, I had never changed the database model directly and was just working with APIs. But this needed database migrations, API implementation, and frontend adaptation. I was shit scared, I didn’t want to break anything in production and also their trust. So, I took some time studying Naveen sir’s implementation of Insight groups and made a generic parent-child relationship model which can be extended easily. Both Naveen sir and Shubham sir helped me a lot to achieve this progress.&lt;/p&gt;

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

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

&lt;h3&gt;
  
  
  To End,
&lt;/h3&gt;

&lt;p&gt;I had an exhilarating three months with Dragonfruit. I never thought these types of organizations exist that push and help out lads to give their best. I learned a lot about React.js, best state management workflow practices, and how to scale out stuff so that it is easier in the long run. It was an amazing experience and I would definitely cherish it lifelong.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A tip: If you want to apply for an internship and take your chances with Dragonfruit AI, you may contact &lt;a href="mailto:amol@dragonfruit.ai"&gt;amol@dragonfruit.ai&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>ai</category>
      <category>opensource</category>
      <category>discuss</category>
    </item>
    <item>
      <title>Final Part: GSoC 2022 | Rocket.Chat | EmbeddedChat</title>
      <dc:creator>Sidharth Mohanty</dc:creator>
      <pubDate>Sat, 10 Sep 2022 14:05:16 +0000</pubDate>
      <link>https://dev.to/sidmohanty11/final-part-gsoc-2022-rocketchat-embeddedchat-37g8</link>
      <guid>https://dev.to/sidmohanty11/final-part-gsoc-2022-rocketchat-embeddedchat-37g8</guid>
      <description>&lt;p&gt;Hello everyone, it’s the last week of &lt;strong&gt;Google Summer of Code&lt;/strong&gt; (for medium-term projects) and it feels so amazing when I look back to the day I started it. My project was just an idea at that time; now it’s a product! I am so grateful for the love and support from the &lt;a href="http://Rocket.Chat" rel="noopener noreferrer"&gt;Rocket.Chat&lt;/a&gt; community. My project has got whooping &lt;strong&gt;12+ stars on &lt;a href="https://github.com/RocketChat/EmbeddedChat" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt; now&lt;/strong&gt; and some &lt;strong&gt;potential users&lt;/strong&gt; who are eager to use it! These few months were really hard. We had to face so many challenges, so many edge cases, and so many stages. It was an amazing journey altogether!&lt;/p&gt;

&lt;h3&gt;
  
  
  Some updates on EmbeddedChat:
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuxpjk6a2lcmoedhzgz7m.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuxpjk6a2lcmoedhzgz7m.gif" alt="EmbeddedChat in action" width="720" height="388"&gt;&lt;/a&gt;&lt;br&gt;
This is the component I've worked on for the past few months. &lt;strong&gt;&lt;em&gt;Think like it as a mini version of RocketChat that can be embedded into any web application.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;At last the component looks something like this,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;RCComponent&lt;/span&gt;
  &lt;span class="na"&gt;moreOpts&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;isClosable&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;setClosableState&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;setClosableState&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;width&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"100%"&lt;/span&gt;
  &lt;span class="na"&gt;height&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"35vh"&lt;/span&gt;
  &lt;span class="na"&gt;GOOGLE_CLIENT_ID&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;GOOGLE_CLIENT_ID&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;host&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;ROCKETCHAT_HOST&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;roomId&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;ROCKETCHAT_ROOM_ID&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;channelName&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"general"&lt;/span&gt;
  &lt;span class="na"&gt;anonymousMode&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;headerColor&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'#F5455C'&lt;/span&gt;
&lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  UI/UX improvements
&lt;/h3&gt;

&lt;p&gt;We added a &lt;code&gt;headerColor&lt;/code&gt; property which will automatically predict if the text and icons should be dark/light. This will help EmbeddedChat get camouflaged as a native component of the parent web application. We also removed the dependency of being fullscreen to show &lt;code&gt;moreOptions&lt;/code&gt; rather it can be shown at all times now.&lt;/p&gt;

&lt;h3&gt;
  
  
  Pinning and starring
&lt;/h3&gt;

&lt;p&gt;This feature helps to pin and star messages using EmbeddedChat and has a different UI (page-like) to showcase the pinned and starred messages of a channel.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/DU5C2vlUVjI"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h3&gt;
  
  
  Reactions to messages
&lt;/h3&gt;

&lt;p&gt;This feature allows user to react to messages in real-time.&lt;br&gt;
&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/aQix55Qd7wY"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h3&gt;
  
  
  Handling attachments
&lt;/h3&gt;

&lt;p&gt;This is in progress, we are now handling different types of attachments (video/audio/image/docs) but we are yet to work on sending attachments using EmbeddedChat.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb6as2sp8py7ylejf1cxe.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb6as2sp8py7ylejf1cxe.png" alt="attachments" width="800" height="396"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Proposing an iframe solution to make it framework agnostic
&lt;/h3&gt;

&lt;p&gt;This method will allow users to use EmbeddedChat without worrying about it being a React.js Component. It is now super simple to integrate EmbeddedChat within minutes.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdi9nnim5of5bgl9u1ohl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdi9nnim5of5bgl9u1ohl.png" alt="iframe deploy" width="800" height="422"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;All the coding stuff aside, I created YouTube videos to make it ever so simple for users to set up EmbeddedChat into their applications. I created some demo repositories showing the capabilities and use cases of EmbeddedChat and making it very easy for developers to integrate it.&lt;/p&gt;

&lt;p&gt;Wiki: &lt;a href="https://github.com/RocketChat/EmbeddedChat/wiki" rel="noopener noreferrer"&gt;EmbeddedChat/wiki&lt;/a&gt;&lt;br&gt;
For YouTube Videos: &lt;a href="https://www.youtube.com/channel/UCs7mpsUvJCDVEtxEw2_h0oA/videos" rel="noopener noreferrer"&gt;EmbeddedChat&lt;/a&gt;&lt;br&gt;
Demo Repositories: &lt;a href="https://github.com/sidmohanty11/embeddedchat-demo-deploy" rel="noopener noreferrer"&gt;EmbeddedChat as a component&lt;/a&gt; and &lt;a href="https://github.com/sidmohanty11/embeddedchat-iframe-deploy" rel="noopener noreferrer"&gt;EmbeddedChat as iframe&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Presentation Day (September 8th)
&lt;/h3&gt;

&lt;p&gt;Rocket.Chat organizes an internal “Demo Presentation” for all students. These presentations are attended by almost the entire Rocket.Chat engineering team including the CEO Gabriel Engel and CTO Rodrigo Nascimento. It was an amazing experience presenting the work that I had done over the past three months.&lt;br&gt;
The entire recording is published at &lt;a href="https://www.youtube.com/c/RocketChatApp/videos" rel="noopener noreferrer"&gt;Rocket.Chat’s YouTube channel&lt;/a&gt;. You can also check it out here:&lt;br&gt;
&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/gcB5c6cvg9w?start=21"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Presentation slides: &lt;a href="https://docs.google.com/presentation/d/1hNO-iGlA0nnyHS5o6XlgwGaYP7IgOtcHdg--HCFNABY/edit?usp=sharing" rel="noopener noreferrer"&gt;Demo Day Presentation Slides&lt;/a&gt;&lt;br&gt;
Work product Repository: &lt;a href="https://github.com/sidmohanty11/GSoC-2022" rel="noopener noreferrer"&gt;Google-Summer-of-Code-2022&lt;/a&gt;&lt;br&gt;
Test out EmbeddedChat here: &lt;a href="https://sidmohanty11.github.io/embeddedchat-demo-deploy/" rel="noopener noreferrer"&gt;EmbeddedChat Demo&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Thanks to my mentor!
&lt;/h3&gt;

&lt;p&gt;I will be forever grateful to my mentor &lt;a href="https://github.com/RonLek" rel="noopener noreferrer"&gt;Rohan Lekhwani sir&lt;/a&gt; for being such an amazing spirit to work with. Just a secret to share here, I had my internal exams around the time of Community Bonding Period and my 4th semester exams around August (10th - 24th) and I was so much worried for them as it was my first offline semester. I had asked my mentor if I could take some days off in between to manage both GSoC and exams and he was so supportive throughout that I got 9.27 GPA in my exams. Also I used to have both personal and professional talks with him about life and career in general which were super helpful for me. He is an amazing person whom I will look up to forever.&lt;/p&gt;

&lt;h3&gt;
  
  
  Thanks to the entire Rocket.Chat community!
&lt;/h3&gt;

&lt;p&gt;Thank you so much to my mentors - &lt;a href="https://github.com/Sing-Li" rel="noopener noreferrer"&gt;SingLi sir&lt;/a&gt;, &lt;a href="https://github.com/dudanogueira" rel="noopener noreferrer"&gt;Duda&lt;/a&gt; and &lt;a href="https://github.com/debdutdeb" rel="noopener noreferrer"&gt;Debdut sir&lt;/a&gt; for all the support and guidance, it means a lot for any student to get appreciation, criticism and encouragement from their mentors to grow in life. I would also like to thank my friends for being there and making these months not just only about learning but enjoyable too. I hope we stay in touch in the future. Thanks!&lt;/p&gt;

&lt;h3&gt;
  
  
  To end,
&lt;/h3&gt;

&lt;p&gt;It was one journey that will stay with me for lifetime. I learnt a lot of things - not just coding but beyond it.&lt;/p&gt;

&lt;h3&gt;
  
  
  What's Next?
&lt;/h3&gt;

&lt;p&gt;I will continue working on adding more features to EmbeddedChat as per user requirements. Next target will be to introduce thread functionality which is the most used feature of RocketChat.&lt;/p&gt;

&lt;p&gt;Connect with me:&lt;br&gt;
Email: &lt;a href="mailto:sidmohanty11@gmail.com"&gt;sidmohanty11@gmail.com&lt;/a&gt;&lt;br&gt;
GitHub: &lt;a href="https://github.com/sidmohanty11" rel="noopener noreferrer"&gt;https://github.com/sidmohanty11&lt;/a&gt;&lt;br&gt;
LinkedIn: &lt;a href="https://www.linkedin.com/in/sidmohanty11" rel="noopener noreferrer"&gt;https://www.linkedin.com/in/sidmohanty11&lt;/a&gt;&lt;br&gt;
Twitter: &lt;a href="https://twitter.com/sidmohanty11" rel="noopener noreferrer"&gt;https://twitter.com/sidmohanty11&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Do check out the project, and if you like it you can star ⭐ it too :)&lt;br&gt;
&lt;a href="https://github.com/RocketChat/EmbeddedChat" rel="noopener noreferrer"&gt;https://github.com/RocketChat/EmbeddedChat&lt;/a&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>react</category>
      <category>opensource</category>
      <category>npm</category>
    </item>
    <item>
      <title>[PART-II] GSoC 2022 | Rocket.Chat | EmbeddedChat</title>
      <dc:creator>Sidharth Mohanty</dc:creator>
      <pubDate>Sat, 23 Jul 2022 09:57:00 +0000</pubDate>
      <link>https://dev.to/sidmohanty11/part-ii-gsoc-2022-rocketchat-embeddedchat-15g3</link>
      <guid>https://dev.to/sidmohanty11/part-ii-gsoc-2022-rocketchat-embeddedchat-15g3</guid>
      <description>&lt;p&gt;This blog is the part-ii of a series where I share my journey in the &lt;strong&gt;Google Summer of Code Program&lt;/strong&gt;, with some tips, learnings, and some design decisions which we (me and my mentor) took to shape the &lt;a href="https://github.com/RocketChat/EmbeddedChat" rel="noopener noreferrer"&gt;EmbeddedChat Project&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;So it's time, first evaluation is coming up (Jul 25th - Jul 29th). I am both excited and nervous at the same time. But let's talk about the usual first.&lt;/p&gt;

&lt;h3&gt;
  
  
  EmbeddedChat till now (Jul 23rd)
&lt;/h3&gt;

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

&lt;h4&gt;
  
  
  Adding Google Single sign-on Authentication in EmbeddedChat
&lt;/h4&gt;

&lt;p&gt;We had chosen to go with SSO Auth as people visiting web apps are always in a hurry. They don't want to go through so many registration steps or even give their login creds. So we went with this approach, i.e, if someone visits a web app for the first time and doesn't have an account in the RocketChat instance of that company, then they can just click the "Sign in with Google" and an account will be created for them. Also, if someone already has an account in the respective RocketChat instance, then they can also login with just a click.&lt;/p&gt;

&lt;p&gt;It seems to be simple at first, but it took a lot of research. At first I thought there must be a library that I could use, right? The closest I got was a library called -&lt;a href="https://github.com/MomenSherif/react-oauth" rel="noopener noreferrer"&gt;@react-oauth/google&lt;/a&gt; but it wasn't compatible with how RocketChat Google OAuth endpoint handled requests. It needed both &lt;code&gt;acessToken&lt;/code&gt; and &lt;code&gt;idToken&lt;/code&gt; but here on successful login we could get either &lt;code&gt;accessToken&lt;/code&gt; &lt;strong&gt;or&lt;/strong&gt; &lt;code&gt;code&lt;/code&gt; object. The &lt;code&gt;idToken&lt;/code&gt; is the JWT hashed version of &lt;code&gt;code&lt;/code&gt; object. You can read more about it &lt;a href="https://developers.google.com/identity/sign-in/web/backend-auth" rel="noopener noreferrer"&gt;here&lt;/a&gt;. So after a while of research, I started implementing a custom hook which could handle this with the plain &lt;a href="https://github.com/partnerhero/gapi-script" rel="noopener noreferrer"&gt;gapi-script&lt;/a&gt; from scratch.&lt;br&gt;
But, the gapi-script introduced some errors/warnings. So, I went and fixed the code and published my own library around it.&lt;/p&gt;
&lt;h4&gt;
  
  
  Created a fixed version of gapi-script library called &lt;a href="https://github.com/sidmohanty11/gapi-cjs" rel="noopener noreferrer"&gt;gapi-cjs&lt;/a&gt;
&lt;/h4&gt;

&lt;p&gt;So, I fixed the &lt;code&gt;use of eval&lt;/code&gt; warnings, jest - &lt;a href="https://github.com/partnerhero/gapi-script/issues/12" rel="noopener noreferrer"&gt;test failed error&lt;/a&gt;, &lt;code&gt;this&lt;/code&gt; is set to be undefined error and published the library. I used it inside of the EmbeddedChat to create the custom hook.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// src/hooks/useGoogleLogin.js&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;gapi&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;gapi-cjs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useEffect&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;useGoogleLogin&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;GOOGLE_CLIENT_ID&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="p"&gt;...&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;signIn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;auth&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;gapi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;auth2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getAuthInstance&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;signIn&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;access_token&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;id_token&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;currentUser&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getAuthResponse&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;access_token&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;id_token&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="p"&gt;...&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;signIn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;signOut&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the &lt;code&gt;signin&lt;/code&gt; function, we return out the &lt;code&gt;accessToken&lt;/code&gt; as well &lt;code&gt;idToken&lt;/code&gt; which were needed to call the &lt;a href="https://developer.rocket.chat/reference/api/rest-api/endpoints/other-important-endpoints/authentication-endpoints/google" rel="noopener noreferrer"&gt;Google OAuth Endpoint&lt;/a&gt; in RocketChat.&lt;/p&gt;

&lt;p&gt;There was another caveat we faced, that was RocketChat asks for the username when a user registers an account. So we handled that case also. You can read more about it here - &lt;a href="https://github.com/RocketChat/EmbeddedChat/wiki/Chapter:-Authentication" rel="noopener noreferrer"&gt;Chapter: Authentication&lt;/a&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Anonymous Mode
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fonz34zu20gjv0wz8ne2j.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fonz34zu20gjv0wz8ne2j.gif" alt="Anonymous-on" width="800" height="363"&gt;&lt;/a&gt;&lt;br&gt;
So there will be a prop to the component called, &lt;code&gt;anoynmousMode&lt;/code&gt;. If the developer or company using EmbeddedChat wants users to read messages without even logging in, then they can set &lt;code&gt;anonymousMode&lt;/code&gt; as true and enable anonymous read in their RocketChat instance.&lt;/p&gt;

&lt;h3&gt;
  
  
  PRs Merged or under review
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/RocketChat/EmbeddedChat/pull/12" rel="noopener noreferrer"&gt;RocketChat/EmbeddedChat - NEW: AUTH (google SSO) 
&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/RocketChat/Rocket.Chat.js.SDK/pull/155" rel="noopener noreferrer"&gt;RocketChat/Rocket.Chat.js.SDK - Fix: eval warnings coming from js-sha256&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Issues raised
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/RocketChat/Rocket.Chat/issues/26266" rel="noopener noreferrer"&gt;RocketChat/Rocket.Chat - User can send message to a channel without joining it&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/RocketChat/Rocket.Chat.js.SDK/issues/154" rel="noopener noreferrer"&gt;RocketChat/Rocket.Chat.js.SDK - BUG: RC node.js SDK deps use eval statements&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Documentation
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/RocketChat/EmbeddedChat/wiki/Chapter:-Authentication" rel="noopener noreferrer"&gt;Wiki: Chapter - Authentication&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/RocketChat/EmbeddedChat/wiki/Chapter:-Emoji-Picker" rel="noopener noreferrer"&gt;Wiki: Chapter - Emoji Picker&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/RocketChat/EmbeddedChat/wiki/Roots-of-EmbeddedChat" rel="noopener noreferrer"&gt;Wiki: Roots of EmbeddedChat&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/RocketChat/EmbeddedChat/pull/15" rel="noopener noreferrer"&gt;PR: Development Documentation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  To end
&lt;/h3&gt;

&lt;p&gt;At the end of this month, we will have a fully working product in place (to demo). &lt;strong&gt;Then, will move forward to add more features like pinning, starring, threads and reacting to messages.&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;If you want to connect:&lt;br&gt;
Email: &lt;a href="mailto:sidmohanty11@gmail.com"&gt;sidmohanty11@gmail.com&lt;/a&gt;&lt;br&gt;
GitHub: &lt;a href="https://github.com/sidmohanty11" rel="noopener noreferrer"&gt;https://github.com/sidmohanty11&lt;/a&gt;&lt;br&gt;
LinkedIn: &lt;a href="https://www.linkedin.com/in/sidmohanty11" rel="noopener noreferrer"&gt;https://www.linkedin.com/in/sidmohanty11&lt;/a&gt;&lt;br&gt;
Twitter: &lt;a href="https://twitter.com/sidmohanty11" rel="noopener noreferrer"&gt;https://twitter.com/sidmohanty11&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Do check out the project, and if you like it you can star it too :)&lt;br&gt;
&lt;a href="https://github.com/RocketChat/EmbeddedChat" rel="noopener noreferrer"&gt;https://github.com/RocketChat/EmbeddedChat&lt;/a&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>react</category>
      <category>opensource</category>
    </item>
    <item>
      <title>[PART-I] GSoC 2022 | Rocket.Chat | EmbeddedChat</title>
      <dc:creator>Sidharth Mohanty</dc:creator>
      <pubDate>Fri, 01 Jul 2022 11:00:00 +0000</pubDate>
      <link>https://dev.to/sidmohanty11/part-i-gsoc-2022-rocketchat-embeddedchat-3njh</link>
      <guid>https://dev.to/sidmohanty11/part-i-gsoc-2022-rocketchat-embeddedchat-3njh</guid>
      <description>&lt;p&gt;This blog marks the start of a series I am going to write, sharing my journey in the &lt;strong&gt;Google Summer of Code Program&lt;/strong&gt;, with some tips, learnings, and some design decisions which we (me and my mentor) took to shape the &lt;a href="https://github.com/RocketChat/EmbeddedChat" rel="noopener noreferrer"&gt;EmbeddedChat Project&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is EmbeddedChat?
&lt;/h2&gt;

&lt;p&gt;Think like EmbeddedChat as a mini-version of Rocket.Chat packed in an npm module, as simple as that!&lt;/p&gt;

&lt;p&gt;If you need the wiki definition, &lt;em&gt;EmbeddedChat is a full-stack React component node module of the RocketChat application that is fully configurable, extensible, and flexible for use. It is tightly bound with the &lt;/em&gt;&lt;em&gt;RocketChat server using Rocket.Chat nodejs SDK&lt;/em&gt;&lt;em&gt; and its &lt;/em&gt;&lt;em&gt;UI&lt;/em&gt;&lt;em&gt; using &lt;/em&gt;&lt;em&gt;RocketChat's Fuselage Design System&lt;/em&gt;&lt;em&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why EmbeddedChat?
&lt;/h2&gt;

&lt;p&gt;It will provide a business solution to every sector of those who want to integrate/embed a chat application in their own application. The fact being, whether its Google Meet, the games you play, or the e-commerce platforms you make, you at some point have thought I really need to chat and ask the other person for more details (in case of a shop, this is the reason why people still prefer to go to an offline store rather buying online) or you want to chat in games and store it for future reference. You don’t have any solution…. Until now!&lt;/p&gt;

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

&lt;p&gt;&lt;a href="http://Rocket.Chat" rel="noopener noreferrer"&gt;Rocket.Chat&lt;/a&gt; now strives to provide you with its robust solution by providing a simple react component that you can embed in just about any application. With its robust backend connected with its simplistic yet intuitive Fuselage Design System UI, let us worry about setting up functionalities for you. You can just do,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;RCComponent /&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;provide your custom props and you are ready to go (within minutes)!&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Did you think we stopped there?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Nope! We will provide you with an &lt;strong&gt;RCAPIWrapper&lt;/strong&gt; which will be a frontend SDK of RocketChat that can be used within any framework or even vanilla JavaScript.&lt;/p&gt;

&lt;h2&gt;
  
  
  EmbeddedChat till now (July 1st)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Initialization of the React component library
&lt;/h3&gt;

&lt;p&gt;I will not take much time here, I’ve already shared a blog where I stated how we did so. So, if you are interested you can check that out.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.to/sidmohanty11/how-to-create-and-publish-a-react-component-library-not-the-storybook-way-3b07"&gt;How to create and publish a react component library (not the storybook way)&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Responsiveness
&lt;/h3&gt;

&lt;p&gt;Making the EmbeddedChat responsive for all screens was an important task to cover and we added another option where the user can choose if he/she wants a fullscreen or minimized screen.&lt;/p&gt;

&lt;h3&gt;
  
  
  Connecting to &lt;a href="http://Rocket.Chat" rel="noopener noreferrer"&gt;Rocket.Chat&lt;/a&gt; server and the real-time messaging functionality
&lt;/h3&gt;

&lt;p&gt;You may have some idea about real-time messaging functionality or heard about web sockets or the third-party providers such as pusher which provide us functionality to introduce real-time connections. “Scaling” these types of APIs requires a lot of engineering and &lt;a href="http://Rocket.Chat" rel="noopener noreferrer"&gt;Rocket.Chat&lt;/a&gt; has nailed it. It has its own API built on top of MeteorJS and has a concept of &lt;a href="https://developer.rocket.chat/reference/api/realtime-api" rel="noopener noreferrer"&gt;“Realtime API”&lt;/a&gt; which they have strengthened a lot in the past 7 years.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqsu3sl92zlmqkg04iidy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqsu3sl92zlmqkg04iidy.png" alt="Realtime messaging" width="600" height="547"&gt;&lt;/a&gt; &lt;/p&gt;
&lt;h3&gt;
  
  
  The EmojiPicker Component
&lt;/h3&gt;

&lt;p&gt;&lt;a href="http://Rocket.Chat" rel="noopener noreferrer"&gt;Rocket.Chat&lt;/a&gt; uses joypixels emoji, and there were not many npm libraries that supported this anymore. But, luckily I found a cool combination I could use to provide joypixels emojis &lt;a href="https://codesandbox.io/s/qqmvo5924?file=/src/App.js" rel="noopener noreferrer"&gt;here&lt;/a&gt; and I used it. You need to be good at googling things!&lt;/p&gt;

&lt;p&gt;But here is the main part! We thought to ourselves that we really need to parse emojis in the message box because that will improve UX and provide a way for mobile users to use their native emoji set. We were getting a unified property from the emoji picker package which is a 5 letter code that can be converted to an HTML entity by embedding it between &lt;strong&gt;&amp;amp;#x;&lt;/strong&gt; You can check it out &lt;a href="https://unicode.org/emoji/charts/full-emoji-list.html" rel="noopener noreferrer"&gt;here&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;Still, we were just using state to control the message value which was ultimately a string. The question was how could we parse this inside of the input box? Yes, dangerouslySetInnerHtml was an option I guess but we researched a bit and at last went with a better way, with a better package called &lt;a href="https://www.npmjs.com/package/he" rel="noopener noreferrer"&gt;he&lt;/a&gt; which is used to encode and decode HTML entities.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Did the story end there?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Nope. The flag emojis were breaking because the package was giving us two unicodes. I and my mentor had a brainstorming session during our weekly catch-up, we discussed the possibilities and how to convert two unicodes into a flag! Then after in-depth research about UTF-8 encoding we found the way. If you come across this, just know flag emojis are a combination of two unicodes. Those two unicodes are letters indicating the country code of countries. You can definitely go with an approach where you store each unicode in a js object and map through it to convert it into a native emoji or you can use String.fromCodePoint. &lt;em&gt;But I found out a much easier way which was just to split the unicodes and embed them between ““, and at last, we managed to get all emojis working with the native ones!&lt;/em&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo9ra9clrpkrj4yvawyix.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo9ra9clrpkrj4yvawyix.png" alt="parsing emoji in the message box" width="721" height="347"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  PRs (merged and being reviewed)
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/RocketChat/EmbeddedChat/pull/1" rel="noopener noreferrer"&gt;[NEW] initialize project and base setup&lt;/a&gt;&lt;br&gt;
&lt;a href="https://github.com/RocketChat/EmbeddedChat/pull/4" rel="noopener noreferrer"&gt;NEW: issue and pr template&lt;/a&gt;&lt;br&gt;
&lt;a href="https://github.com/RocketChat/EmbeddedChat/pull/5" rel="noopener noreferrer"&gt;IMPROVE: Responsiveness&lt;/a&gt;&lt;br&gt;
&lt;a href="https://github.com/RocketChat/EmbeddedChat/pull/7" rel="noopener noreferrer"&gt;NEW: sending and receiving msgs (the oop way)&lt;/a&gt;&lt;br&gt;
&lt;a href="https://github.com/RocketChat/EmbeddedChat/pull/11" rel="noopener noreferrer"&gt;Parsing emojis in message box&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  To end
&lt;/h2&gt;

&lt;p&gt;I started maintaining the project &lt;a href="https://github.com/RocketChat/EmbeddedChat/wiki" rel="noopener noreferrer"&gt;wiki&lt;/a&gt; and with time I would like to introduce full end-to-end documentation of all features that we are building, including the rationale behind architectural decisions we take. &lt;strong&gt;For the next weeks, we are planning to make a Google SSO Auth system that will be totally connected with RocketChat’s Auth environment and then move on to add API features like pinning, starring, and reacting to messages (with emojis).&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I was also selected as the &lt;strong&gt;community member of the month&lt;/strong&gt; (JUNE) in &lt;a href="http://Rocket.Chat" rel="noopener noreferrer"&gt;Rocket.Chat&lt;/a&gt; and I was invited to speak a few lines in their community call. It’s published on YouTube on Rocket.Chat’s own channel. Had a lot of fun. You can check it out here:&lt;br&gt;
&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/l45Z6crFKXo?start=2514"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;If you want to connect:&lt;br&gt;
Email :&lt;a href="//mailto:sidmohanty11@gmail.com"&gt;sidmohanty11@gmail.com&lt;/a&gt;&lt;br&gt;
GitHub: &lt;a href="https://github.com/sidmohanty11" rel="noopener noreferrer"&gt;https://github.com/sidmohanty11&lt;/a&gt;&lt;br&gt;
LinkedIn:&lt;a href="https://www.linkedin.com/in/sidmohanty11" rel="noopener noreferrer"&gt;https://www.linkedin.com/in/sidmohanty11&lt;/a&gt;&lt;br&gt;
Twitter:&lt;a href="https://twitter.com/sidmohanty11" rel="noopener noreferrer"&gt;https://twitter.com/sidmohanty11&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A huge shoutout to my mentor &lt;a href="https://github.com/RonLek" rel="noopener noreferrer"&gt;Rohan Lekhwani sir&lt;/a&gt;! Thanks a lot for guiding me and helping me all the time!&lt;/p&gt;

&lt;p&gt;Do check out the project, and if you like it you can star it too :)&lt;br&gt;
&lt;a href="https://github.com/RocketChat/EmbeddedChat" rel="noopener noreferrer"&gt;https://github.com/RocketChat/EmbeddedChat&lt;/a&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>react</category>
      <category>opensource</category>
      <category>webdev</category>
    </item>
    <item>
      <title>How to create and publish a react component library (not the storybook way)</title>
      <dc:creator>Sidharth Mohanty</dc:creator>
      <pubDate>Mon, 20 Jun 2022 14:20:52 +0000</pubDate>
      <link>https://dev.to/sidmohanty11/how-to-create-and-publish-a-react-component-library-not-the-storybook-way-3b07</link>
      <guid>https://dev.to/sidmohanty11/how-to-create-and-publish-a-react-component-library-not-the-storybook-way-3b07</guid>
      <description>&lt;p&gt;Hello everyone! Just some backstory before we start, I got selected for GSoC this year (2022) with Rocket.Chat organization. The project in which I was selected is to create an easy-to-embed React component of Rocket.Chat (like a mini-version of it) that can be plugged into any web application made in React.&lt;/p&gt;

&lt;p&gt;Something like this,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;RCComponent&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="err"&gt;‘&lt;/span&gt;&lt;span class="nx"&gt;rc&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;react&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;component&lt;/span&gt;&lt;span class="err"&gt;’&lt;/span&gt;

&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;RCComponent&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So when I was writing my proposal, I researched a lot about the ways in which we can create a React component library.&lt;/p&gt;

&lt;p&gt;As my project demanded that it should be a single component that should be tightly coupled up with the backend features provided by the RocketChat API, I and my mentor decided to go with a traditional approach of creating a React component library i.e, by not using Storybook.&lt;/p&gt;

&lt;p&gt;I wanted to share this way, where you can get started with creating a component library instantly and naturally (without worrying about learning any other technology). For a detailed approach about why I chose some things over the others, I will be writing bi-weekly blogs about my progress in the &lt;a href="https://github.com/RocketChat/EmbeddedChat" rel="noopener noreferrer"&gt;EmbeddedChat project&lt;/a&gt;. But for now, let's create a &lt;a href="https://github.com/RocketChat/EmbeddedChat" rel="noopener noreferrer"&gt;simple counter component&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;First of all create a project directory and initialize your npm project with,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm init -y
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Install react and react-dom as peer dependencies by,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm i —save-peer react react-dom
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I went with rollup as my bundler of choice but you can go with any bundler of your preference. I am linking some articles that made up my mind about choosing rollup for creating component libraries:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://blog.logrocket.com/benchmarking-bundlers-2020-rollup-parcel-webpack/" rel="noopener noreferrer"&gt;Benchmarking different bundlers&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://medium.com/webpack/webpack-and-rollup-the-same-but-different-a41ad427058c" rel="noopener noreferrer"&gt;webpack vs rollup&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I have also made a separate repository containing configuration files and example libraries created using both rollup and webpack. You can &lt;a href="https://github.com/sidmohanty11/crl-templates" rel="noopener noreferrer"&gt;check it&lt;/a&gt; out too if you want to go with webpack.&lt;/p&gt;

&lt;p&gt;Now, let's install rollup and all the plugin dependencies&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm i —save-dev rollup rollup-plugin-postcss @rollup/plugin-babel @rollup/plugin-commonjs @rollup/plugin-node-resolve rollup-plugin-peer-deps-external
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After installation, lets create a &lt;code&gt;rollup.config.js&lt;/code&gt; file which will contain our configuration for desired output files. I went with both &lt;code&gt;cjs&lt;/code&gt; and &lt;code&gt;esm&lt;/code&gt; modules.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// rollup.config.js&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;resolve&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@rollup/plugin-node-resolve&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;commonjs&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@rollup/plugin-commonjs&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;babel&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@rollup/plugin-babel&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;postcss&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;rollup-plugin-postcss&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;external&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;rollup-plugin-peer-deps-external&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;packageJson&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./package.json&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;input&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;src/index.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;output&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;file&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;packageJson&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;format&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;cjs&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;sourcemap&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;file&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;packageJson&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;format&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;esm&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;sourcemap&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
      &lt;span class="nf"&gt;commonjs&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;include&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;node_modules/**&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;}),&lt;/span&gt;
      &lt;span class="nf"&gt;babel&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;exclude&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;node_modules/**&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;presets&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@babel/env&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@babel/preset-react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="na"&gt;babelHelpers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;bundled&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
      &lt;span class="p"&gt;}),&lt;/span&gt;
      &lt;span class="nf"&gt;postcss&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
      &lt;span class="nf"&gt;external&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see we are using &lt;code&gt;packageJson.main&lt;/code&gt; and &lt;code&gt;packageJson.module&lt;/code&gt; so let's add them,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// package.json
{
...
"main": "dist/cjs/index.js",
"module": "dist/esm/index.js",
...
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Install babel and all the required dependencies to work with React.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm i --save-dev @babel/core @babel/preset-env @babel/preset-react babel-jest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create a &lt;code&gt;babel.config.js&lt;/code&gt; file and add these,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// babel.config.js
module.exports = {
  presets: [
    [
      "@babel/preset-env",
      {
        modules: false,
        bugfixes: true,
        targets: { browsers: "&amp;gt; 0.25%, ie 11, not op_mini all, not dead" },
      },
    ],
    "@babel/preset-react",
  ],
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For testing, I am going with jest and react-testing-library and these can be installed by,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm i --save-dev jest @testing-library/react react-scripts identity-obj-proxy
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add the jest configuration file, create &lt;code&gt;jest.config.js&lt;/code&gt; and add,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// jest.config.js
module.exports = {
  testEnvironment: "jsdom",
  moduleNameMapper: {
    ".(css|less|scss)$": "identity-obj-proxy",
  },
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We need &lt;code&gt;react-scripts&lt;/code&gt; to run tests and to use it inside the playground for running all the scripts (start, build, test and eject) this will ensure we get no conflicts. &lt;code&gt;identity-obj-proxy&lt;/code&gt; is needed because when we will be running tests, jest cannot determine what we are importing from module CSS, so it will proxy it to an empty object of sorts.&lt;/p&gt;

&lt;p&gt;We will be needing some more dependencies to run our project and use them in our scripts, lets's install them too,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm i --save-dev npm-run-all concurrently cross-env rimraf
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let’s add some scripts to run our project now,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// package.json
{
"scripts": {
    "prebuild": "rimraf dist",
    "build": "rollup -c",
    "watch": "rollup -c --watch",
    "dev": "concurrently \" npm run watch \" \" npm run start --prefix playground \"",
    "test": "run-s test:unit test:build",
    "test:unit": "cross-env CI=1 react-scripts test --env=jsdom",
    "test:watch": "react-scripts test --env=jsdom --coverage --collectCoverageFrom=src/components/**/*.js",
    "test:build": "run-s build",
    "prepublish": "npm run build"
  },
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Lets create the component now,&lt;/p&gt;

&lt;p&gt;Create &lt;code&gt;src&lt;/code&gt; directory and inside this create &lt;code&gt;index.js&lt;/code&gt;, &lt;code&gt;index.test.js&lt;/code&gt;, and &lt;code&gt;index.module.css&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// index.js&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;styles&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./index.module.css&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;SimpleCounterComponent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;counter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setCounter&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;red&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Counter Component&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;counter&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt; &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setCounter&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;prev&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;prev&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;increment&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// index.test.js&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;render&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@testing-library/react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;SimpleCounterComponent&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./index&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;SimpleCounterComponent Component&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;renders the SimpleCounterComponent component&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;SimpleCounterComponent&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// index.module.css
.red {
  color: red;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, when you run &lt;code&gt;npm run build&lt;/code&gt; it will create a &lt;code&gt;dist&lt;/code&gt; directory with our bundled output files (in both cjs and esm formats) but you definitely need to test your component before you ship, right?&lt;/p&gt;

&lt;p&gt;Create a playground app by running &lt;code&gt;npx create-react-app playground&lt;/code&gt;. Remember we downloaded &lt;code&gt;react-scripts&lt;/code&gt;, change package.json of the playground app as follows,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// playground/package.json
{
    "dependencies": {
    "@testing-library/jest-dom": "^5.16.4",
    "@testing-library/react": "^13.3.0",
    "@testing-library/user-event": "^13.5.0",
    "react": "file:../node_modules/react",
    "react-dom": "file:../node_modules/react-dom",
    "react-scripts": "file:../node_modules/react-scripts",
    "simple-counter-component": "file:../",
    "web-vitals": "^2.1.4"
  },
    "scripts": {
    "start": "node ../node_modules/react-scripts/bin/react-scripts.js start",
    "build": "node ../node_modules/react-scripts/bin/react-scripts.js build",
    "test": "node ../node_modules/react-scripts/bin/react-scripts.js test",
    "eject": "node ../node_modules/react-scripts/bin/react-scripts.js eject"
  },
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will make use of the react-scripts downloaded in the root and also point to use react, react-dom that’s installed in the root. This will save you from 3 days of headache if you are not familiar with how &lt;code&gt;npm link&lt;/code&gt; works, and will throw an error that different &lt;code&gt;react&lt;/code&gt; versions are used in your project and hooks cannot be used etc. &lt;/p&gt;

&lt;p&gt;Now do an &lt;code&gt;npm install&lt;/code&gt; in the playground, and you are ready to go.&lt;/p&gt;

&lt;p&gt;Use your component inside the playground,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// playground/src/App.js&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;SimpleCounterComponent&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;simple-counter-component&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./App.css&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

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

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

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

&lt;/div&gt;



&lt;p&gt;Go back to the root directory and run &lt;code&gt;npm run dev&lt;/code&gt; it will open up the playground application and you can do your changes in the component while watching the changes reflect real-time in the playground environment.&lt;/p&gt;

&lt;p&gt;Now for publishing your component, make sure you use a name that has not been taken yet. After you come up with a name, you can use it in &lt;code&gt;package.json&lt;/code&gt;'s &lt;code&gt;name&lt;/code&gt; attribute.&lt;/p&gt;

&lt;p&gt;You can just do &lt;code&gt;npm publish&lt;/code&gt; to publish your package, but it can show you an error if this is your first time. You need to create an account in &lt;a href="https://www.npmjs.com/" rel="noopener noreferrer"&gt;https://www.npmjs.com/&lt;/a&gt; and after that login using &lt;code&gt;npm login&lt;/code&gt; in your terminal. After you’ve successfully logged in yourself, &lt;code&gt;npm publish&lt;/code&gt;!&lt;/p&gt;

&lt;p&gt;You can further improve your project by adding ESlint, prettier, terser-plugin (to minify) etc. which I am not including in this blog.&lt;/p&gt;

&lt;p&gt;Last important thing, make sure you are shipping only the required module and not everything. This will heavily determine the size of your package. So if you want to just ship the &lt;code&gt;dist&lt;/code&gt; directory, add this in your &lt;code&gt;package.json&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// package.json
 "files": [
    "dist"
  ],
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Checkout the repository &lt;a href="https://github.com/sidmohanty11/simple-counter-component" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Hooray! Our package has been published. You can do &lt;code&gt;npm i simple-counter-component&lt;/code&gt; to check it out. To manage semantic versioning, you can use a great library called &lt;a href="https://www.npmjs.com/package/np" rel="noopener noreferrer"&gt;np&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Please let me know the things that can be improved in the comment section below. Thank you.&lt;/p&gt;

&lt;p&gt;If you want to connect:&lt;br&gt;
Email : &lt;a href="mailto:sidmohanty11@gmail.com"&gt;sidmohanty11@gmail.com&lt;/a&gt;&lt;br&gt;
GitHub: &lt;a href="https://github.com/sidmohanty11" rel="noopener noreferrer"&gt;https://github.com/sidmohanty11&lt;/a&gt;&lt;br&gt;
LinkedIn: &lt;a href="https://www.linkedin.com/in/sidmohanty11" rel="noopener noreferrer"&gt;https://www.linkedin.com/in/sidmohanty11&lt;/a&gt;&lt;br&gt;
Twitter: &lt;a href="https://twitter.com/sidmohanty11" rel="noopener noreferrer"&gt;https://twitter.com/sidmohanty11&lt;/a&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>react</category>
      <category>tutorial</category>
      <category>beginners</category>
    </item>
  </channel>
</rss>
