<?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>Forem: sanketmunot</title>
    <description>The latest articles on Forem by sanketmunot (@sanketmunot).</description>
    <link>https://forem.com/sanketmunot</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%2F850484%2F32f9ca43-b1a7-4e5c-aaed-8036e75f628e.jpg</url>
      <title>Forem: sanketmunot</title>
      <link>https://forem.com/sanketmunot</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/sanketmunot"/>
    <language>en</language>
    <item>
      <title>Dynamic Template Injection in Angular: Clean &amp; Scalable</title>
      <dc:creator>sanketmunot</dc:creator>
      <pubDate>Wed, 21 Jan 2026 13:18:58 +0000</pubDate>
      <link>https://forem.com/sanketmunot/dynamic-template-injection-in-angular-clean-scalable-493h</link>
      <guid>https://forem.com/sanketmunot/dynamic-template-injection-in-angular-clean-scalable-493h</guid>
      <description>&lt;h2&gt;
  
  
  Discover how to inject feature-specific templates into a parent layout using ng-template, RxJS, and a slot service — no inputs or outputs needed.
&lt;/h2&gt;




&lt;p&gt;I’m new to Angular.&lt;br&gt;&lt;br&gt;
I come from React.&lt;/p&gt;

&lt;p&gt;So when I needed a layout with &lt;strong&gt;dynamic footer actions&lt;/strong&gt;, my first solution was… chaos.&lt;/p&gt;
&lt;h2&gt;
  
  
  The setup
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;1 &lt;code&gt;LayoutComponent&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;3 feature components
&lt;/li&gt;
&lt;li&gt;A shared footer area
&lt;/li&gt;
&lt;li&gt;Each feature needs &lt;strong&gt;different buttons &amp;amp; info&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The &lt;em&gt;bad&lt;/em&gt; way 👎&lt;br&gt;&lt;br&gt;
Passing configs, callbacks, and flags up and down:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;feature-a&lt;/span&gt; &lt;span class="na"&gt;(footerChange)=&lt;/span&gt;&lt;span class="s"&gt;"setFooter($event)"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/feature-a&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;feature-b&lt;/span&gt; &lt;span class="na"&gt;(footerChange)=&lt;/span&gt;&lt;span class="s"&gt;"setFooter($event)"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/feature-b&amp;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 typescript"&gt;&lt;code&gt;&lt;span class="nf"&gt;setFooter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;FooterConfig&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;footerButtons&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;config&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;It works… but the layout becomes a dumping ground.&lt;/p&gt;




&lt;h2&gt;
  
  
  The idea: make the footer a &lt;em&gt;slot&lt;/em&gt;
&lt;/h2&gt;

&lt;p&gt;Instead of sending data up,&lt;br&gt;
let the feature &lt;strong&gt;inject UI&lt;/strong&gt; into the layout.&lt;/p&gt;

&lt;p&gt;Think: &lt;em&gt;React portals + refs&lt;/em&gt;, but Angular style.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 1: a tiny slot service
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Injectable&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;providedIn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;root&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;class&lt;/span&gt; &lt;span class="nc"&gt;SlotService&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;slots&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;BehaviorSubject&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&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="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="nx"&gt;slot&lt;/span&gt;&lt;span class="nf"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&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="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getSlot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;asObservable&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;setTemplate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;tpl&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="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="nf"&gt;getSlot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tpl&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;clear&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&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="nf"&gt;getSlot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nf"&gt;getSlot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&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;slots&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;has&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="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;slots&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;BehaviorSubject&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&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="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&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="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;slots&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="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&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;h2&gt;
  
  
  Step 2: the layout renders whatever it gets
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- layout.component.html --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"footer"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;ng-container&lt;/span&gt; &lt;span class="na"&gt;*ngTemplateOutlet=&lt;/span&gt;&lt;span class="s"&gt;"footerTpl"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/ng-container&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// layout.component.ts&lt;/span&gt;
&lt;span class="nx"&gt;footerTpl&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="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nf"&gt;ngOnInit&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;slotService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;slot&lt;/span&gt;&lt;span class="nf"&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;footer&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tpl&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;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;footerTpl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;tpl&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;The layout has &lt;strong&gt;no idea&lt;/strong&gt; who owns the footer.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 3: a feature plugs in its footer
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- feature.component.html --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;ng-template&lt;/span&gt; &lt;span class="na"&gt;#footerTemplate&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;(click)=&lt;/span&gt;&lt;span class="s"&gt;"save()"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Save&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;(click)=&lt;/span&gt;&lt;span class="s"&gt;"cancel()"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Cancel&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/ng-template&amp;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 typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// feature.component.ts&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;footerTemplate&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;footerTemplate&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="nf"&gt;ngAfterViewInit&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;slotService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setTemplate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;footer&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;footerTemplate&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nf"&gt;ngOnDestroy&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;slotService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;clear&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;footer&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  What just happened?
&lt;/h2&gt;

&lt;p&gt;Your feature &lt;strong&gt;registered UI&lt;/strong&gt;.&lt;br&gt;
Your layout &lt;strong&gt;rendered it&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;No props.&lt;br&gt;
No events.&lt;br&gt;
No tight coupling.&lt;/p&gt;




&lt;h2&gt;
  
  
  The takeaway
&lt;/h2&gt;

&lt;p&gt;If Angular feels awkward, it’s often because we try to use React patterns &lt;em&gt;directly&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Translate the &lt;strong&gt;idea&lt;/strong&gt;, not the code —&lt;br&gt;
and Angular suddenly becomes powerful 🚀&lt;/p&gt;

</description>
      <category>angular</category>
      <category>architecture</category>
      <category>tutorial</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Using Webpack for Easy Development in a Chrome Extension</title>
      <dc:creator>sanketmunot</dc:creator>
      <pubDate>Tue, 24 Sep 2024 13:14:31 +0000</pubDate>
      <link>https://forem.com/sanketmunot/using-webpack-for-easy-development-in-a-chrome-extension-4kpd</link>
      <guid>https://forem.com/sanketmunot/using-webpack-for-easy-development-in-a-chrome-extension-4kpd</guid>
      <description>&lt;p&gt;Developing a Chrome extension requires constant building after every change, which can be a tedious process. To streamline this, we set up &lt;strong&gt;Webpack&lt;/strong&gt; to automate the build process, making development faster and easier. Here's how Webpack helps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Automated Builds&lt;/strong&gt;:&lt;br&gt;&lt;br&gt;
Webpack bundles our JavaScript, CSS, and other assets into a single output directory (&lt;code&gt;dist&lt;/code&gt;). Every time we make changes to our code, Webpack automatically builds the project, generating the necessary files for the Chrome extension.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Entry Point&lt;/strong&gt;:&lt;br&gt;&lt;br&gt;
In this setup, Webpack starts from the &lt;code&gt;index.js&lt;/code&gt; file, which serves as the entry point to bundle the React code and other scripts.&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;  &lt;span class="nx"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./index.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Babel Transpiling&lt;/strong&gt;:&lt;br&gt;&lt;br&gt;
Webpack uses &lt;code&gt;babel-loader&lt;/code&gt; to transpile modern JavaScript (ES6+) and JSX (React) into browser-compatible code. This ensures our code works across different browsers, including older ones.&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;  &lt;span class="nx"&gt;use&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;loader&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;babel-loader&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="nl"&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="s1"&gt;@babel/preset-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="s1"&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="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;CSS Handling&lt;/strong&gt;:&lt;br&gt;&lt;br&gt;
With the &lt;code&gt;MiniCssExtractPlugin&lt;/code&gt;, Webpack extracts CSS into a separate file (&lt;code&gt;styles.css&lt;/code&gt;), allowing us to keep the styling modular and separate from JavaScript.&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;  &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;MiniCssExtractPlugin&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;filename&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;styles.css&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;}),&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;HTML File Generation&lt;/strong&gt;:&lt;br&gt;&lt;br&gt;
Webpack generates an HTML file with the &lt;code&gt;HtmlWebpackPlugin&lt;/code&gt; that links the bundled JavaScript (&lt;code&gt;bundle.js&lt;/code&gt;). This is useful for dynamically inserting the scripts required for the React-based popup.&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;  &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;HtmlWebpackPlugin&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./index.html&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;}),&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Copying Static Assets&lt;/strong&gt;:&lt;br&gt;&lt;br&gt;
The &lt;code&gt;copy-webpack-plugin&lt;/code&gt; is used to copy essential files like &lt;code&gt;manifest.json&lt;/code&gt;, &lt;code&gt;background.js&lt;/code&gt;, &lt;code&gt;contentScripts.js&lt;/code&gt;, &lt;code&gt;live-score.css&lt;/code&gt;, and the extension icon to the &lt;code&gt;dist&lt;/code&gt; folder. This ensures all the necessary files for the Chrome extension are ready in one place after every build.&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;  &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;CopyPlugin&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;patterns&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;from&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;manifest.json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;to&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;path&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="nx"&gt;__dirname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dist&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="na"&gt;from&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;contentScripts.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;to&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;path&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="nx"&gt;__dirname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dist&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="na"&gt;from&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;background.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;to&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;path&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="nx"&gt;__dirname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dist&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="na"&gt;from&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;live-score.css&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;to&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;path&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="nx"&gt;__dirname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dist&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="na"&gt;from&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;icon128.png&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;to&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;path&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="nx"&gt;__dirname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dist&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="p"&gt;}),&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Source Maps for Debugging&lt;/strong&gt;:&lt;br&gt;&lt;br&gt;
The &lt;code&gt;devtool: 'cheap-module-source-map'&lt;/code&gt; option generates source maps, which help in debugging by mapping the minified code back to the original source code, making it easier to trace errors during development.&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;  &lt;span class="nx"&gt;devtool&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;cheap-module-source-map&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Summary
&lt;/h3&gt;

&lt;p&gt;By using Webpack, we automate the entire build process of the extension, handle JavaScript and CSS bundling, and ensure that all static assets are moved into the final &lt;code&gt;dist&lt;/code&gt; directory. This approach significantly speeds up development and eliminates the need to manually rebuild the extension after every code change.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Implementing a Message-Driven Architecture for Live IPL Scores in a Chrome Extension</title>
      <dc:creator>sanketmunot</dc:creator>
      <pubDate>Tue, 24 Sep 2024 13:13:21 +0000</pubDate>
      <link>https://forem.com/sanketmunot/implementing-a-message-driven-architecture-for-live-ipl-scores-in-a-chrome-extension-468l</link>
      <guid>https://forem.com/sanketmunot/implementing-a-message-driven-architecture-for-live-ipl-scores-in-a-chrome-extension-468l</guid>
      <description>&lt;p&gt;As discussed in the previous architecture flow, our extension relies on message passing between the background worker and the content script. The background script fetches live scores from an external API, while the content script renders the data into the DOM of the active tab. Let’s break down how this works step by step:&lt;/p&gt;

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

&lt;h3&gt;
  
  
  Step-by-Step Flow
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Initialization&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Upon loading, the content script checks whether the scoreboard display is enabled. It sends an initialization message (&lt;code&gt;"init"&lt;/code&gt;) to the background script to determine if it should start fetching and displaying scores.&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;init&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;let&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;isEnabled&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;chrome&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;storage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sync&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;isEnabled&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;chrome&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;runtime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sendMessage&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;action&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;init&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;isEnabled&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;isEnabled&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;init&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;



&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Fetching Live Scores&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
The background script listens for messages, and when triggered, it begins polling an API every 5 seconds to fetch live IPL scores.&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;chrome&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;runtime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onMessage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;sender&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;sendResponse&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;isEnabled&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;message&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;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;action&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;init&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;isEnabled&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;getLatestScoresAndRender&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;action&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;toggleLogging&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;isEnabled&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;startCricket&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// Runs getLatestScoresAndRender every 5 seconds&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;stopCricket&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;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Rendering Data&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
When the background script receives the latest scores, it sends the data to the active tab's content script, which then updates the DOM dynamically with the latest match data.&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;//background.js&lt;/span&gt;
&lt;span class="nx"&gt;chrome&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tabs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sendMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tabId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;action&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;polling&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;allIplMatches&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;And in the content script:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;chrome&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;runtime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onMessage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;sender&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;sendResponse&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;action&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;polling&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="c1"&gt;// Use match data from the message to update the DOM&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;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;User Interaction (Toggle On/Off)&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Users can toggle the scoreboard on or off with a single click. This toggle sends a &lt;code&gt;"toggleLogging"&lt;/code&gt; message to the background script, which starts or stops the polling accordingly.&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;chrome&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;runtime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onMessage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;action&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;toggleLogging&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;isEnabled&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;startCricket&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;stopCricket&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;/li&gt;
&lt;/ol&gt;




&lt;h3&gt;
  
  
  Yes we had to use react for our popup, here's how -
&lt;/h3&gt;

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

&lt;p&gt;We need to specify an HTML file in the manifest that will serve as our extension's popup. For the extension's control interface, we developed it as a React component and linked the corresponding script in the index.html.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nl"&gt;"action"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"default_popup"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"index.html"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;  &lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"bundle.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt; //bundle.js is the built react file
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;While at it you can also give a read to &lt;a href="https://medium.com/@nehamalvia2016/catch-every-moment-explore-our-live-ipl-score-chrome-extension-0170916a096e" rel="noopener noreferrer"&gt;Medium article from Neha Malvia&lt;/a&gt; which explains bits of repository&lt;/p&gt;

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

&lt;p&gt;By leveraging Chrome's message-passing APIs, we split the responsibilities between background workers (handling API requests) and content scripts (handling DOM updates). This event-driven architecture ensures smooth, real-time updates across multiple tabs, creating a seamless user experience without unnecessary refreshes or interruptions.&lt;/p&gt;

&lt;p&gt;This modular approach allows the extension to be highly efficient, responsive, and user-friendly, with the ability to toggle the score display on or off easily.&lt;/p&gt;




&lt;p&gt;Dont miss the extras &lt;a href="https://dev.to/sanketmunot/test-series-2-11a8"&gt;webpack for chrome extension&lt;/a&gt; where we defined a webpack config to streamline our build.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Architecture Breakdown of IPL Live Score Chrome Extension</title>
      <dc:creator>sanketmunot</dc:creator>
      <pubDate>Tue, 24 Sep 2024 13:07:56 +0000</pubDate>
      <link>https://forem.com/sanketmunot/architecture-breakdown-of-ipl-live-score-chrome-extension-1cak</link>
      <guid>https://forem.com/sanketmunot/architecture-breakdown-of-ipl-live-score-chrome-extension-1cak</guid>
      <description>&lt;h2&gt;
  
  
  Architecture Overview
&lt;/h2&gt;

&lt;p&gt;The architecture of our IPL live score Chrome extension is divided into key components that handle specific responsibilities. These components work together to ensure real-time updates, an intuitive user interface, and efficient performance.&lt;/p&gt;

&lt;p&gt;The application architecture looks like this below&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F203sf6nk6c6c9rvjn6e3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F203sf6nk6c6c9rvjn6e3.png" alt="High-level architecture"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  1. &lt;strong&gt;Manifest File&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;manifest.json&lt;/code&gt; file is the backbone of any Chrome extension. It defines the metadata, permissions, and structure of the extension, such as which files serve as the popup, background script, and content scripts.&lt;/p&gt;

&lt;p&gt;Key responsibilities:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Declares the permissions needed to access certain Chrome APIs (e.g., tabs, storage).
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"permissions": ["activeTab", "storage", "tabs"]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Specifies which scripts (content scripts, background workers) will run and how they will interact.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"content_scripts": [
    {
      "all_frames": true,
      "matches": ["&amp;lt;all_urls&amp;gt;"],
      "js": ["contentScripts.js"],
      "css": ["live-score.css"]
    }
  ],
  "background": {
    "service_worker": "background.js"
  }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Links to the popup file for the UI.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"action": {
    "default_popup": "index.html"
  }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. &lt;strong&gt;Chrome Tabs and Content Scripts&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Each Chrome tab where the extension operates has an injected &lt;strong&gt;content script&lt;/strong&gt;. This content script is responsible for interacting with the DOM of the tab, displaying the live scorecard, and responding to user interactions like drag-and-drop.&lt;/li&gt;
&lt;li&gt;Only the &lt;strong&gt;active tab&lt;/strong&gt; displays live scores, while the content scripts in inactive tabs are on standby.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Key responsibilities:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Display the live scores by injecting the scorecard into the DOM.&lt;/li&gt;
&lt;li&gt;Listen for messages from the background script to update or clear the scoreboard.&lt;/li&gt;
&lt;li&gt;Handle the user interaction within the tab, such as dragging and repositioning the scoreboard.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  3. &lt;strong&gt;Background Script&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;The background script serves as the central coordinator for all tabs. It runs continuously in the background, independent of individual tabs.&lt;/li&gt;
&lt;li&gt;It periodically fetches the live match scores from the external IPL scores API and maintains the global state of the extension, such as whether the scoreboard is toggled on or off.&lt;/li&gt;
&lt;li&gt;The background script broadcasts updated score data to the content script of the active tab, ensuring real-time updates without reloading the page.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Key responsibilities:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Fetch live match scores every 5 seconds from the external API.&lt;/li&gt;
&lt;li&gt;Store and manage the extension's global state (e.g., scoreboard on/off status).&lt;/li&gt;
&lt;li&gt;Communicate with content scripts via messages to push live score updates or clear the scoreboard.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  4. &lt;strong&gt;Popup Interface&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;The popup is the user interface that opens when the user clicks on the extension’s icon in the toolbar. It provides controls for toggling the score display on or off.&lt;/li&gt;
&lt;li&gt;The popup sends the user's action (toggle on/off) to the background script, which then updates the content script in the active tab.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Key responsibilities:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Allow the user to control the extension’s behavior (e.g., turning the scoreboard on or off).&lt;/li&gt;
&lt;li&gt;Serve as an interaction point between the user and the background script.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  5. &lt;strong&gt;Flow of Communication&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;The diagrams provided illustrate the flow of communication between these components:&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Initialization:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;When the extension is loaded, the background script checks Chrome’s storage to restore the last saved state (scoreboard on or off).&lt;/li&gt;
&lt;li&gt;If the scoreboard is on, the background script fetches match scores and sends the data to the content script in the active tab to display the scoreboard in the DOM.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;Toggle On/Off:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;When the user toggles the scoreboard on or off via the popup, the popup sends this toggle action to the background script.&lt;/li&gt;
&lt;li&gt;If toggled on, the background script starts fetching live scores and sends the data to the active tab’s content script to display the scoreboard.&lt;/li&gt;
&lt;li&gt;If toggled off, the background script clears the set interval for fetching scores and sends a message to the content script to remove the scoreboard from the DOM.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;Polling:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Every 5 seconds, the background script fetches the latest match scores and pushes this data to the content script in the active tab, ensuring the scoreboard is updated in real-time.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  6. &lt;strong&gt;Efficient Performance Management&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;The background script fetches match scores only once, regardless of the number of open tabs. The content script is injected only into the active tab to reduce overhead.&lt;/li&gt;
&lt;li&gt;By isolating DOM manipulations to a single active tab and using efficient messaging between scripts, the architecture minimizes the number of API calls and ensures smooth performance even when multiple tabs are open.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That covers the architectural aspects. Next, we'll explore various implementation strategies for different workflows. &lt;a href="https://dev.to/sanketmunot/test-series-1-51l7"&gt;Click here -&amp;gt;&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Gathering Requirements and Introducing IPL Score Tracker Chrome Extension</title>
      <dc:creator>sanketmunot</dc:creator>
      <pubDate>Tue, 24 Sep 2024 13:07:48 +0000</pubDate>
      <link>https://forem.com/sanketmunot/gathering-requirements-and-introducing-ipl-score-tracker-chrome-extension-5ck</link>
      <guid>https://forem.com/sanketmunot/gathering-requirements-and-introducing-ipl-score-tracker-chrome-extension-5ck</guid>
      <description>&lt;p&gt;This guide is quite detailed, so I've broken it down into smaller sections. In this series, we’ll walk through the process of building a Chrome extension that tracks IPL scores in real-time. Each part focuses on a different step, from setting up the basics to fetching live match data. The series will dive deep into the &lt;em&gt;idea-to-product&lt;/em&gt; development experience and the engineering decisions we made to build graceful software.&lt;/p&gt;

&lt;p&gt;This is the first part of the series.&lt;/p&gt;

&lt;p&gt;Here’s a short overview before we start: My colleague and I became fascinated with Chrome extensions and decided to build one ourselves. After brainstorming ideas, we finalized a live cricket score tracker for the IPL. We aimed to make it as SOLID as possible, with a focus on readability and modularity. I’ll describe each step we took and the lessons we learned in this article.&lt;/p&gt;

&lt;h2&gt;
  
  
  Defining the problem: User’s point of view
&lt;/h2&gt;

&lt;p&gt;I am a cricket fan, especially interested in the IPL. I want to keep track of IPL scores during work hours without needing to constantly switch tabs to get the latest updates. &lt;/p&gt;

&lt;p&gt;Below is the list of functional and non-functional requirements we identified during the development of our application.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Functional Requirements:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Real-time score tracking&lt;/strong&gt;: Users must be able to view live scores of ongoing IPL matches directly within the Chrome extension.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Persistent score display&lt;/strong&gt;: Match scores should continue to display on the active tab, even when users switch between different tabs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Single-click control&lt;/strong&gt;: Implement a one-click toggle to turn the score display on or off. The user experience should be streamlined, avoiding the need for complex configuration steps or multiple actions.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Non-Functional Requirements:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;State persistence&lt;/strong&gt;: The extension should remember the scoreboard’s last on/off state and restore it when users reopen Chrome.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Efficient API usage&lt;/strong&gt;: Minimize the number of API calls to retrieve live scores, reducing server load and ensuring optimal performance.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Drag-and-drop functionality&lt;/strong&gt;: Allow users to reposition the scoreboard on the screen via drag-and-drop for enhanced flexibility.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Performance optimization&lt;/strong&gt;: Ensure that DOM manipulations are limited to a single active tab, preventing performance issues across multiple tabs. &lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;What exactly is a Chrome extension, and how can I build one?&lt;br&gt;
My first thought when I asked this was: &lt;em&gt;Ha! Looks simple, maybe another client-side frontend project I can whip up in no time.&lt;/em&gt; But yeah, it wasn’t that simple when we started building one ourselves.&lt;/p&gt;

&lt;p&gt;A Chrome extension is like software (or a plugin) that can be installed on Google Chrome to use native Chrome features, manipulate the DOM, run service workers, track activities, and more. Building a Chrome extension is somewhat similar to developing a frontend web application, though it has a specific architecture to perform certain actions in designated files. Some of the main components are:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Popup:&lt;/strong&gt; The box that appears when you click the extension icon, like this:&lt;br&gt;
&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnbhm2c5xwiher61ie1oe.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnbhm2c5xwiher61ie1oe.png" alt="Chrome extension popup" width="" height=""&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Content scripts:&lt;/strong&gt; A JavaScript file that’s added to each tab individually. It has access to the DOM of the tab and can inject HTML elements into the existing DOM.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Background worker:&lt;/strong&gt; As the name suggests, this is a service worker used to perform actions or send events to the extension. Unlike content scripts, which are loaded individually for each tab, the background worker is loaded only once, and all tabs interact with a single instance. This is a great place to handle synchronization logic for your application.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;References and tools used:&lt;br&gt;
&lt;a href="https://github.com/nehasm/cricket-score-extension" rel="noopener noreferrer"&gt;Github repo&lt;/a&gt;&lt;br&gt;
&lt;a href="https://chromewebstore.google.com/detail/cricket-now-live-ipl-scor/jebachengnnmfepclihpnklcfdejgfci" rel="noopener noreferrer"&gt;Chrome extension link&lt;/a&gt;&lt;br&gt;
&lt;a href="https://play.d2lang.com/" rel="noopener noreferrer"&gt;D2Lang&lt;/a&gt; for flow diagram&lt;br&gt;
&lt;a href="https://www.drawio.com/" rel="noopener noreferrer"&gt;Draw.io&lt;/a&gt; for architecture diagram&lt;/p&gt;




&lt;p&gt;Up next is an overview of the application's architecture. &lt;a href="https://dev.to/sanketmunot/architecture-breakdown-of-ipl-live-score-chrome-extension-1cak"&gt;Click here&lt;/a&gt; -&amp;gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>node</category>
      <category>extensions</category>
      <category>cricket</category>
    </item>
    <item>
      <title>Sharing State Between Vanilla and React Apps with Redux</title>
      <dc:creator>sanketmunot</dc:creator>
      <pubDate>Wed, 14 Aug 2024 12:03:41 +0000</pubDate>
      <link>https://forem.com/sanketmunot/sharing-state-between-vanilla-and-react-apps-with-redux-1g65</link>
      <guid>https://forem.com/sanketmunot/sharing-state-between-vanilla-and-react-apps-with-redux-1g65</guid>
      <description>&lt;h2&gt;
  
  
  The problem statement
&lt;/h2&gt;

&lt;p&gt;I want to share a common data state between vanilla js and react app.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is in this POC
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;We will create two similar counter apps in vanilla and react.&lt;/li&gt;
&lt;li&gt;The count should be stored in a common state&lt;/li&gt;
&lt;li&gt;If we update the count in vanilla, it should be reflected in react and vice-verse&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Project Structure
&lt;/h2&gt;

&lt;p&gt;Our project is divided into two main sections:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Root Directory&lt;/strong&gt;: Contains core files for the vanilla JavaScript portion of the app.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;react-mf&lt;/code&gt; Directory&lt;/strong&gt;: Houses the React micro-frontend which interacts with the vanilla JavaScript part.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The architecture of the app can be checked at &lt;a href="https://raw.githubusercontent.com/sanketmunot/common-state/main/architecture.png" rel="noopener noreferrer"&gt;link&lt;/a&gt; here&lt;/p&gt;

&lt;h2&gt;
  
  
  Key Files and Their Roles
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Root Directory
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;code&gt;index.html&lt;/code&gt;&lt;/strong&gt;: This is the entry point of our app, setting up the HTML structure and including links to stylesheets and JavaScript files. It features two key &lt;code&gt;div&lt;/code&gt; elements with &lt;code&gt;id="app"&lt;/code&gt; and &lt;code&gt;id="root"&lt;/code&gt;, which are used to mount the vanilla JS app and the React micro-frontend, respectively.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;code&gt;main.js&lt;/code&gt;&lt;/strong&gt;: Acts as the main JavaScript file for initializing the vanilla JS part of the app. It handles the core logic and interacts with the shared state.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;code&gt;counter.js&lt;/code&gt;&lt;/strong&gt;: Contains the code responsible for dispatching actions to the Redux store. For instance, it dispatches an &lt;code&gt;INCREMENT&lt;/code&gt; action to update the counter.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;code&gt;store.js&lt;/code&gt;&lt;/strong&gt;: Sets up the Redux store, which manages the application's state and ensures consistency between the vanilla JS and React parts of the app.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;react-mf&lt;/code&gt; Directory
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;code&gt;App.jsx&lt;/code&gt;&lt;/strong&gt;: The main React component of our micro-frontend. It utilizes the &lt;code&gt;useState&lt;/code&gt; hook for local state management and subscribes to the Redux store to reflect the global state. It renders a button to dispatch an &lt;code&gt;INCREMENT&lt;/code&gt; action and displays the current count from the store.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;code&gt;main.jsx&lt;/code&gt;&lt;/strong&gt;: The entry point for the React micro-frontend, where the React app is initialized and rendered.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How does it work
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Create a basic vanilla js website using redux store.&lt;/li&gt;
&lt;li&gt;Expose the created store to &lt;code&gt;window&lt;/code&gt; element.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const store = createStore(reducer);
window.customStore = store
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Make use of &lt;code&gt;store.dispatch&lt;/code&gt; function in react to fire a store action.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;button onClick={() =&amp;gt; store.dispatch({type: 'INCREMENT'})}&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Listen to changes in store using &lt;code&gt;store.subscribe&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;store.subscribe(() =&amp;gt; {
    setCount(store.getState().counter)
  })
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can find the full code in the &lt;a href="https://github.com/sanketmunot/common-state.git" rel="noopener noreferrer"&gt;GitHub repository&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>react</category>
      <category>webdev</category>
      <category>javascript</category>
      <category>frontend</category>
    </item>
    <item>
      <title>Smart meal tracking on whatsapp [POC]</title>
      <dc:creator>sanketmunot</dc:creator>
      <pubDate>Wed, 19 Jun 2024 18:01:48 +0000</pubDate>
      <link>https://forem.com/sanketmunot/smart-meal-tracking-on-whatsapp-poc-474h</link>
      <guid>https://forem.com/sanketmunot/smart-meal-tracking-on-whatsapp-poc-474h</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for &lt;a href="https://dev.to/challenges/twilio"&gt;Twilio Challenge v24.06.12&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Built
&lt;/h2&gt;

&lt;p&gt;I developed a proof-of-concept WhatsApp bot that accepts an image of the meal you're having. In return, it provides the calorie intake along with detailed nutrition information such as carbohydrates, fats, and proteins.&lt;/p&gt;

&lt;p&gt;This is just a proof of concept; we can significantly enhance it by incorporating a database to store user data and generate regular reports. Use background workers for image saving and calorie estimation from AI, and employing another worker to send the messages.&lt;/p&gt;

&lt;p&gt;Read more about functionality and flow on github &lt;a href="https://github.com/sanketmunot/twilio-ai-challenge-meal-alerts/blob/main/README.md"&gt;readme&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;p&gt;I cannot provide a demo because I used ngrok to route WhatsApp webhook requests to localhost. But here are some screenshots -&amp;gt;&lt;/p&gt;

&lt;p&gt;Positive case I send an image of Indian thali&lt;br&gt;
&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feks15q1xbm3ddtpchti4.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feks15q1xbm3ddtpchti4.jpeg" alt="Indian thali" width="540" height="1200"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Positive case I send an image of burger meal&lt;br&gt;
&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdm1p9xgfr2igwv5lchlg.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdm1p9xgfr2igwv5lchlg.jpeg" alt="Burger meal" width="540" height="1200"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Negative case Naruto, When he is kept away from Ramen (IYKYK)&lt;br&gt;
&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frp95r6rr0ljjuxb5ief7.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frp95r6rr0ljjuxb5ief7.jpeg" alt="When you keep Naruto away from Ramen" width="540" height="1200"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Twilio and AI
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Twilio's API&lt;/strong&gt; is used to receive images of food sent by users via WhatsApp.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Google's Generative AI model - Gemeni&lt;/strong&gt; analyzes the received images to estimate the caloric content and nutritional breakdown.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Twilio&lt;/strong&gt; sends back the detailed nutritional information to the user on WhatsApp.&lt;/li&gt;
&lt;li&gt;The integration of &lt;strong&gt;Twilio and AI&lt;/strong&gt; enhances user interaction by providing instant and informative responses.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Additional Prize Categories
&lt;/h2&gt;

&lt;p&gt;Twilio Times Two&lt;br&gt;
Impactful Innovators&lt;/p&gt;

&lt;p&gt;Thanks for reading my post, connect me on Linkedin @ &lt;a href="https://www.linkedin.com/in/sanket-munot/"&gt;Sanket Munot&lt;/a&gt;&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>twiliochallenge</category>
      <category>ai</category>
      <category>twilio</category>
    </item>
  </channel>
</rss>
