<?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: Dharan Ganesan</title>
    <description>The latest articles on Forem by Dharan Ganesan (@dhrn).</description>
    <link>https://forem.com/dhrn</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%2F145382%2Fb00f2a7f-f42c-490a-9fe4-30cd97a19901.png</url>
      <title>Forem: Dharan Ganesan</title>
      <link>https://forem.com/dhrn</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/dhrn"/>
    <language>en</language>
    <item>
      <title>We Needed to Send Invoices as PDFs. Here's How We Solved It.</title>
      <dc:creator>Dharan Ganesan</dc:creator>
      <pubDate>Thu, 15 Jan 2026 15:57:28 +0000</pubDate>
      <link>https://forem.com/dhrn/we-needed-to-send-invoices-as-pdfs-heres-how-we-solved-it-oje</link>
      <guid>https://forem.com/dhrn/we-needed-to-send-invoices-as-pdfs-heres-how-we-solved-it-oje</guid>
      <description>&lt;p&gt;A few months ago, our finance team came to us with a very reasonable request.&lt;/p&gt;

&lt;p&gt;They were manually creating invoices in Google Docs, exporting them as PDFs, and emailing them to clients every week. It took about three hours every Monday, and they wanted it automated.&lt;/p&gt;

&lt;p&gt;I remember thinking:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;“This is just PDF generation. I’ve built far more complex things than this.”&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That confidence lasted about five minutes. If you’ve never built PDFs before, this article is for you. If you &lt;em&gt;have&lt;/em&gt; built PDFs before, you already know where this is going — brace yourself, it’s going to hurt a little. 😅&lt;/p&gt;

&lt;p&gt;At the time, the request sounded harmless. Automate invoices. Generate PDFs. Ship it.&lt;/p&gt;

&lt;p&gt;What we didn’t realize was that this small task would turn into a few full weeks of fighting browsers, fonts, tables, pagination, and our own overconfidence.&lt;/p&gt;




&lt;h2&gt;
  
  
  Attempt #1: “Let’s Just Use a PDF Library” 🤡
&lt;/h2&gt;

&lt;p&gt;Like most developers, I started with a PDF library that lets you define documents using JSON.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;docDefinition&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;content&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;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;INVOICE&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;header&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;table&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;body&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Pro Plan&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;$99&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Extra Users&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;$75&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="p"&gt;]&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="nx"&gt;pdfMake&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createPdf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;docDefinition&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;download&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;invoice.pdf&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On paper, it sounded reasonable. In practice, it felt like writing CSS inside a spreadsheet. Everything was deeply nested, styling was awkward, and dynamic tables — the most important part of invoices — were incredibly painful to manage.&lt;/p&gt;

&lt;p&gt;After a few days, it was obvious this wasn’t going to scale.&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%2Fbti548ebmr81put20soo.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%2Fbti548ebmr81put20soo.gif" alt="Confused Developer" width="480" height="268"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Problems showed up immediately:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Tailwind design system was useless — every style had to be rewritten&lt;/li&gt;
&lt;li&gt;Simple layout changes turned into deeply nested config objects&lt;/li&gt;
&lt;li&gt;Dynamic content meant unreadable JSON logic&lt;/li&gt;
&lt;li&gt;Debugging was painful: generate → download → open → squint → repeat&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It also looked like it was designed in 2009.&lt;/p&gt;




&lt;h2&gt;
  
  
  Attempt #2: “What If We Just Print HTML?” 🖨️
&lt;/h2&gt;

&lt;p&gt;Next came the obvious idea: we already had HTML, so why not just use &lt;code&gt;window.print()&lt;/code&gt;?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"invoice"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;Invoice&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;table&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&lt;/span&gt;Pro Plan&lt;span class="nt"&gt;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;&lt;/span&gt;$99&lt;span class="nt"&gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/table&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;onclick=&lt;/span&gt;&lt;span class="s"&gt;"window.print()"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Generate PDF&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At first, it felt like magic ✨&lt;/p&gt;

&lt;p&gt;We could reuse our existing HTML. Our CSS worked. Things looked &lt;em&gt;mostly&lt;/em&gt; correct.&lt;/p&gt;

&lt;p&gt;Then we tested across browsers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Chrome: looks fine&lt;/li&gt;
&lt;li&gt;Safari: weird margins&lt;/li&gt;
&lt;li&gt;Firefox: table headers disappear&lt;/li&gt;
&lt;li&gt;Windows Chrome: footer gone&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Pagination was complete chaos. Product names on one page, prices on the next. Half a logo appearing at the bottom of a page for no reason.&lt;/p&gt;

&lt;p&gt;For internal docs, this might be acceptable. For client-facing invoices, it wasn’t even close.&lt;/p&gt;




&lt;h2&gt;
  
  
  Attempt #3: “Okay Fine, Headless Chrome” 😐
&lt;/h2&gt;

&lt;p&gt;To fix browser inconsistencies, we moved to &lt;strong&gt;Puppeteer&lt;/strong&gt; — headless Chrome running on the server.&lt;/p&gt;

&lt;p&gt;Same browser. Same environment. Same output every time.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;puppeteer&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;puppeteer&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;generateInvoice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;html&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;browser&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;puppeteer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;launch&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;args&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;--no-sandbox&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;--disable-setuid-sandbox&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;page&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;browser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;newPage&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;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setContent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;html&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;waitUntil&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;networkidle0&lt;/span&gt;&lt;span class="dl"&gt;"&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;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pdf&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;A4&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;printBackground&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;margin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;top&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;20mm&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;bottom&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;20mm&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;await&lt;/span&gt; &lt;span class="nx"&gt;browser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;close&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;Consistency improved, but new problems appeared:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Custom fonts were missing on Linux servers&lt;/li&gt;
&lt;li&gt;Images sometimes loaded, sometimes didn’t&lt;/li&gt;
&lt;li&gt;Minor CSS changes broke pagination in surprising ways&lt;/li&gt;
&lt;li&gt;No real control over page breaks&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It felt like building IKEA furniture without instructions. Everything technically fit together, but nothing felt solid.&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%2Fqvfy5l0l2jbk8ea25fsx.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%2Fqvfy5l0l2jbk8ea25fsx.gif" alt="Everything is Fine" width="480" height="270"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  The Real Problem (Nobody Explains This)
&lt;/h2&gt;

&lt;p&gt;Eventually, the pattern became clear.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;HTML is designed for scrolling. PDFs are designed for pages.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Web Pages&lt;/th&gt;
&lt;th&gt;PDFs&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Infinite scroll&lt;/td&gt;
&lt;td&gt;Fixed page sizes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Flexible layout&lt;/td&gt;
&lt;td&gt;Exact layout&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;No page rules&lt;/td&gt;
&lt;td&gt;Strict pagination&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Browsers &lt;em&gt;try&lt;/em&gt; to bridge this gap.&lt;/p&gt;

&lt;p&gt;They mostly fail.&lt;/p&gt;

&lt;p&gt;Every team ends up rediscovering this the hard way.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Thing That Finally Worked 🎉
&lt;/h2&gt;

&lt;p&gt;After weeks of frustration, we discovered &lt;strong&gt;pdfn&lt;/strong&gt;, and it completely changed how we generate PDFs. It lets you build invoices, receipts, or contracts as &lt;strong&gt;React components&lt;/strong&gt; with loops, props, and conditionals, while automatically handling pagination, headers, footers, and smart page breaks.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;React Components
  (Invoice, Receipt)
         │
         ▼
 @pdfn/react
  - Pagination-aware rendering
  - Smart page breaks
  - Headers &amp;amp; Footers
         │
         ▼
 @pdfn/serve
  - Headless Chromium / Puppeteer
         │
         ▼
 Perfect PDF Output
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&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;Document&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Page&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;@pdfn/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="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Invoice&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="nc"&gt;Document&lt;/span&gt;
      &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Invoice #001"&lt;/span&gt;
      &lt;span class="na"&gt;fonts&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="c1"&gt;// Google Fonts (loaded from CDN)&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Inter&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;family&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Roboto Mono&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;weights&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;700&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="c1"&gt;// Local fonts (embedded as base64)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;family&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;CustomFont&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./fonts/custom.woff2&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;weight&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;400&lt;/span&gt; &lt;span class="p"&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="nc"&gt;Page&lt;/span&gt; &lt;span class="na"&gt;size&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"A4"&lt;/span&gt; &lt;span class="na"&gt;margin&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"1in"&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;AvoidBreak&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;Table&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;AvoidBreak&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;Page&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;Document&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 architecture makes it easy to maintain and debug your PDF templates.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why pdfn Felt Different
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;You write &lt;strong&gt;React&lt;/strong&gt;, not JSON&lt;/li&gt;
&lt;li&gt;You use &lt;strong&gt;Tailwind&lt;/strong&gt;, not a custom styling system&lt;/li&gt;
&lt;li&gt;Pagination is built-in, not hacked with CSS&lt;/li&gt;
&lt;li&gt;Headers and footers work by default&lt;/li&gt;
&lt;li&gt;Smart page breaks (no mid-row or mid-paragraph splits)&lt;/li&gt;
&lt;li&gt;Dynamic page numbers (Page 1 of 5 works automatically)&lt;/li&gt;
&lt;li&gt;Live preview and hot reload&lt;/li&gt;
&lt;li&gt;Debug overlays to visualize margins, grid, and page breaks&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The code was readable. The output was predictable.&lt;/p&gt;

&lt;p&gt;pdfn is open source (MIT licensed), so there’s no vendor lock-in or surprise pricing later. Inspect the code, self-host it, and adapt it to your needs.&lt;/p&gt;




&lt;h2&gt;
  
  
  Where We Are Now
&lt;/h2&gt;

&lt;p&gt;Today, our entire PDF workflow is fully automated. Invoices, receipts, agreements, and onboarding forms generate automatically. Finance no longer opens Google Docs, fixes spacing, downloads, or emails PDFs by hand.&lt;/p&gt;




&lt;h2&gt;
  
  
  TL;DR (For Tired Developers)
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;PDFs are deceptively hard&lt;/li&gt;
&lt;li&gt;HTML-to-PDF sounds easy (it isn’t)&lt;/li&gt;
&lt;li&gt;Browser printing will betray you&lt;/li&gt;
&lt;li&gt;Page-aware tools matter&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you’re about to build PDF generation, please learn from my mistakes.&lt;/p&gt;

&lt;p&gt;PDFs are hard. You’re not bad at your job.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why We're Sharing This
&lt;/h2&gt;

&lt;p&gt;pdfn is relatively new with a small but responsive team. The maintainers answered our issues. The library is actively maintained. It's MIT licensed, so we're not locked in.&lt;/p&gt;

&lt;p&gt;More developers need to know it exists.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;If this helped:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;⭐ Star &lt;a href="https://pdfn.dev?utm_source=dev.to"&gt;github.com/pdfnjs/pdfn&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;📝 Share your use case if you try it&lt;/li&gt;
&lt;li&gt;🐛 Report issues to help improve it&lt;/li&gt;
&lt;li&gt;💬 Share this article with teams stuck in PDF hell&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Open source only works when we share what works.&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%2Fyhjbc01d3kndr3k0yprh.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%2Fyhjbc01d3kndr3k0yprh.gif" alt="Community" width="370" height="208"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>react</category>
      <category>pdf</category>
      <category>javascript</category>
    </item>
    <item>
      <title>The Untold Story of Comet Browser</title>
      <dc:creator>Dharan Ganesan</dc:creator>
      <pubDate>Sun, 07 Sep 2025 17:00:00 +0000</pubDate>
      <link>https://forem.com/dhrn/the-untold-story-of-comet-browser-1k3e</link>
      <guid>https://forem.com/dhrn/the-untold-story-of-comet-browser-1k3e</guid>
      <description>&lt;p&gt;It all started with headlines claiming that Perplexity was aiming to buy Google’s Chrome browser. That bold move immediately caught my attention. How could a relatively small player even entertain such an audacious idea?&lt;/p&gt;

&lt;p&gt;Curiosity led me to spend a weekend investigating Comet. That exploration revealed an unusual story of engineering trade-offs and surprising truths.&lt;/p&gt;

&lt;p&gt;Every once in a while, a new browser flashes across the tech sky like a comet – bright, fast, and promising to change the way we surf the web. But behind the shine lies a story of engineering, trade-offs, and a few surprising revelations.&lt;/p&gt;

&lt;p&gt;Meet &lt;strong&gt;Comet Browser&lt;/strong&gt;, an ambitious entry into the long-running browser wars. On the surface, it offers lot of AI-powered features. But when you dig deeper, you’ll find that Comet isn’t a full browser in the traditional sense – it’s something far more unconventional.&lt;/p&gt;




&lt;h2&gt;
  
  
  First Impressions: A Shiny Tail
&lt;/h2&gt;

&lt;p&gt;Comet Browser presents itself as a minimalist, fast, and clean browser.&lt;/p&gt;

&lt;p&gt;But the shine is more than skin-deep:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Tabs open fast, almost instantaneously.&lt;/li&gt;
&lt;li&gt;Built-in &lt;strong&gt;ad blocking&lt;/strong&gt; shields you by default.&lt;/li&gt;
&lt;li&gt;AI-assistant and summarization features make browsing feel smarter.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Pulling Back the Curtain: What’s Really Happening
&lt;/h2&gt;

&lt;p&gt;As I dug into Comet, I discovered something fascinating: &lt;strong&gt;Comet isn’t really a standalone browser at all.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Comet works in two main ways:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The UI website&lt;/strong&gt;: Acts as a smart co-pilot, providing suggestions and controlling the sidebar features.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The extension&lt;/strong&gt;: A hidden browser add-on that listens to commands from the website and performs actions like opening tabs or summarizing content.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The website sends structured messages to the extension, which executes them and reports the results back. Together, they create the feel of a full browser, while really running on top of Chromium with a clever helper system.&lt;/p&gt;




&lt;h2&gt;
  
  
  Exposing the Message Flow
&lt;/h2&gt;

&lt;p&gt;The most interesting part of Comet’s design is the &lt;strong&gt;communication layer&lt;/strong&gt; between the extension and the website. Here are a few examples:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;OPEN_TAB&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="nx"&gt;NAV_SEARCH&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="nx"&gt;SEARCH_TABS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="nx"&gt;GET_IS_DEFAULT_BROWSER&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="nx"&gt;SET_AS_DEFAULT_BROWSER&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These cover tab management, ad, quick actions, system-level settings, ...&lt;/p&gt;

&lt;p&gt;Here are simplified examples of how they work:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;OPEN_TAB&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;The website sends: &lt;code&gt;OPEN_TAB(url)&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Extension opens the tab and notifies the website&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;SEARCH_HISTORY&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;Website sends: &lt;code&gt;SEARCH_HISTORY(query)&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Extension searches browser history and returns results&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In effect, the &lt;strong&gt;extension acts as the messenger&lt;/strong&gt;, while the &lt;strong&gt;website handles the logic and processing&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Architecture
&lt;/h2&gt;

&lt;p&gt;Below is a &lt;strong&gt;unified architecture diagram&lt;/strong&gt; showing interactions between the website UI, extension, Chromium, and AI processing.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Website(agent like UI) (interaction)
        |
        v
+---------------------------+
| Extension receives message |
| (open tab / search / get   |
| content / ...)             |
+---------------------------+
        |
        v
  Performs action
        |
        v
  Extension returns result
        |
        v
  Website updates UI
        |
        +----------------------+
        |                      |
        v                      |
Website performs AI-driven actions (clicks, content processing, suggestions)
        |
        +----------------------+
        |
        +----------------------&amp;gt; loop back to Extension receives message
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This diagram shows how the &lt;strong&gt;website&lt;/strong&gt;, &lt;strong&gt;extension&lt;/strong&gt;, &lt;strong&gt;Chromium&lt;/strong&gt;, and &lt;strong&gt;AI engine&lt;/strong&gt; work together to deliver the browser experience.&lt;/p&gt;




&lt;h2&gt;
  
  
  How You Can Test It Yourself
&lt;/h2&gt;

&lt;p&gt;You don’t have to take my word for it. Try it out yourself:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Open Comet Browser&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Visit&lt;/strong&gt;: &lt;a href="https://www.perplexity.ai/sidecar/" rel="noopener noreferrer"&gt;https://www.perplexity.ai/sidecar/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Interact with the page – click buttons and use the features to see it in action.&lt;/li&gt;
&lt;li&gt;To check the extension, open the browser console and run:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Check if Comet is set as the default browser&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;mcjlamohcooanphmebaiigheeeoplihb&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;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;GET_IS_DEFAULT_BROWSER&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Open a new tab via the extension&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;mcjlamohcooanphmebaiigheeeoplihb&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;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;OPEN_TAB&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://google.com&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="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You’ll see how the website and extension communicate in real time.&lt;/p&gt;




&lt;h2&gt;
  
  
  Every Comet Has a Shadow
&lt;/h2&gt;

&lt;p&gt;This design comes with trade-offs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Complexity&lt;/strong&gt;: Two moving parts (extension + website) increase the risk of bugs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Chromium dependency&lt;/strong&gt;: Comet depends on Chromium’s APIs and updates.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Privacy&lt;/strong&gt;: The website may process data outside the normal browser sandbox.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Identity&lt;/strong&gt;: Is Comet truly a browser, or just a clever wrapper? That’s up to the users to decide.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  The People Behind the Curtain
&lt;/h2&gt;

&lt;p&gt;Comet’s developers are practical. Building a full browser engine from scratch is nearly impossible today. By using the &lt;strong&gt;website + extension approach&lt;/strong&gt;, they deliver new ideas while staying compatible.&lt;/p&gt;

&lt;p&gt;Users get the feel of a new browser, while developers avoid reinventing the wheel.&lt;/p&gt;




&lt;h2&gt;
  
  
  Will Comet Burn Out or Shine On?
&lt;/h2&gt;

&lt;p&gt;Comet’s approach is unconventional and bold. If users embrace it, similar setups may follow. If not, it could fade into obscurity.&lt;/p&gt;

&lt;p&gt;The question remains: can a &lt;strong&gt;smart website paired with an extension&lt;/strong&gt; compete with Chrome, Firefox, or Brave?&lt;/p&gt;




&lt;h2&gt;
  
  
  Next Steps: A Dream Port
&lt;/h2&gt;

&lt;p&gt;One wild idea that keeps crossing my mind – what if Comet could live inside Chrome itself?&lt;/p&gt;

&lt;p&gt;In theory, it is possible to port the above into a Chrome, so Chrome users could tap into Comet’s smart features without switching browsers.&lt;/p&gt;

&lt;p&gt;It’s just a dream for now – creating such an extension would take effort and time. But the concept is open for anyone curious enough to explore. If you ever get a chance to tinker with it, I’d love to see what you build.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>typescript</category>
      <category>webdev</category>
      <category>web</category>
    </item>
    <item>
      <title>🛠️ Browser Extensions</title>
      <dc:creator>Dharan Ganesan</dc:creator>
      <pubDate>Sat, 13 Jul 2024 16:30:00 +0000</pubDate>
      <link>https://forem.com/dhrn/browser-extensions-4oac</link>
      <guid>https://forem.com/dhrn/browser-extensions-4oac</guid>
      <description>&lt;p&gt;In today's digital landscape, browser extensions have become an integral part of our online experience. But how did we get here, and what makes these small yet powerful tools so important? This comprehensive guide will take you on a journey through the history, development, and future of browser extensions, providing valuable insights for both casual users and aspiring developers.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Historical Journey of Browser Extensions
&lt;/h2&gt;

&lt;h4&gt;
  
  
  From Mainframes to Modern Browsers
&lt;/h4&gt;

&lt;p&gt;The story of browser extensions is rooted in the history of software plugins, dating back to the 1970s:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Mainframe Era&lt;/strong&gt;: Early plugins allowed users to modify and extend program functionality on massive computers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Early Internet Age&lt;/strong&gt;: As the web grew, browser plugins like Java applets, Adobe Flash, and Microsoft Silverlight emerged.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Transition Period&lt;/strong&gt;: Security and usability issues with early plugins led to a shift towards more integrated solutions.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  The Birth of Modern Browser Extensions
&lt;/h4&gt;

&lt;p&gt;The landscape changed dramatically in 2009:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Google Chrome introduced the first modern browser extensions.&lt;/li&gt;
&lt;li&gt;These extensions utilized familiar web technologies: HTML, CSS, and JavaScript.&lt;/li&gt;
&lt;li&gt;The ease of development and use led to rapid adoption and a thriving ecosystem.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Cross-Browser Compatibility
&lt;/h4&gt;

&lt;p&gt;The success of Chrome's model influenced other major browsers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Firefox, Safari, and Microsoft Edge adopted similar extension frameworks.&lt;/li&gt;
&lt;li&gt;This convergence created a rich, cross-browser landscape of extensions.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Power and Versatility of Browser Extensions
&lt;/h2&gt;

&lt;p&gt;Browser extensions have become indispensable tools, serving a wide array of purposes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Ad and Tracking Blockers&lt;/strong&gt;: Enhance browsing speed and protect user privacy.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Password Managers&lt;/strong&gt;: Secure credentials and defend against phishing attempts.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Writing and Grammar Tools&lt;/strong&gt;: Improve writing quality across the web.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tab Management&lt;/strong&gt;: Streamline workflow with advanced tab control.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Content and Link Managers&lt;/strong&gt;: Organize and save web content efficiently.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Accessibility Enhancements&lt;/strong&gt;: Make the web more inclusive for all users.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Screen Recording and Sharing&lt;/strong&gt;: Facilitate easy content capture and collaboration.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;API Integrations&lt;/strong&gt;: Connect web services and enhance data sharing.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Developer Tools&lt;/strong&gt;: Provide powerful debugging and inspection capabilities.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Digital Currency Wallets&lt;/strong&gt;: Manage cryptocurrencies securely within the browser.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Developing Your Own Browser Extension
&lt;/h2&gt;

&lt;p&gt;For those inspired to create their own extensions, here's a brief overview of the process:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Choose Your Browser&lt;/strong&gt;: Start with Chrome or Firefox for the widest reach.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Plan Your Extension&lt;/strong&gt;: Define its purpose and core functionality.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Set Up Your Development Environment&lt;/strong&gt;: Use familiar web development tools.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Create the Manifest File&lt;/strong&gt;: This JSON file is the blueprint of your extension.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Develop Your Extension&lt;/strong&gt;: Write the HTML, CSS, and JavaScript code.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Test Thoroughly&lt;/strong&gt;: Ensure your extension works as intended across different scenarios.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Publish Your Extension&lt;/strong&gt;: Submit it to the browser's extension store for review.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  The Future of Browser Extensions
&lt;/h2&gt;

&lt;p&gt;The future of browser extensions looks bright and full of potential:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Standardization&lt;/strong&gt;: The WebExtensions Community Group (W3C) is working towards a unified extension model across browsers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Enhanced Security&lt;/strong&gt;: Browsers are implementing stricter security measures for extensions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AI Integration&lt;/strong&gt;: Expect to see more extensions leveraging artificial intelligence and machine learning.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Performance Improvements&lt;/strong&gt;: Future extensions will likely have less impact on browser performance.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Expanded Capabilities&lt;/strong&gt;: As web technologies evolve, so too will the power of extensions.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;Browser extensions have come a long way from their plugin predecessors, becoming an essential part of our online experience. Whether you're a casual user looking to enhance your browsing or a developer seeking to create the next game-changing extension, understanding this ecosystem is crucial in today's digital world.&lt;/p&gt;

&lt;p&gt;By embracing the power of browser extensions, you're not just customizing your web experience – you're participating in the ongoing evolution of the internet itself. So explore, experiment, and perhaps even develop your own extension. The future of the web is in your hands!&lt;/p&gt;

</description>
      <category>extensions</category>
      <category>javascript</category>
      <category>typescript</category>
      <category>html</category>
    </item>
    <item>
      <title>Day 100: Last Day</title>
      <dc:creator>Dharan Ganesan</dc:creator>
      <pubDate>Mon, 18 Dec 2023 16:30:00 +0000</pubDate>
      <link>https://forem.com/dhrn/day-100-last-day-11k2</link>
      <guid>https://forem.com/dhrn/day-100-last-day-11k2</guid>
      <description>&lt;p&gt;Hello fellow developers and enthusiasts! 🚀 Today marks the end of my 100 Days Learning Challenge as a frontend engineer. I can't believe how fast time has flown and how much I've grown during this incredible journey. As I bid farewell to this challenge, I want to express my deepest gratitude to all of you who have been a part of this ride. &lt;/p&gt;

&lt;h2&gt;
  
  
  🌟 A Heartfelt Thank You
&lt;/h2&gt;

&lt;p&gt;First and foremost, I want to thank each and every one of you who took the time to read my articles, follow my progress, and provide encouragement along the way. Your support has been invaluable and has fueled my determination to push through the highs and lows of this learning adventure. &lt;/p&gt;

&lt;h2&gt;
  
  
  📚 What Did I Learn?
&lt;/h2&gt;

&lt;p&gt;Throughout these 100 days, I delved into the vast world of frontend development, exploring everything from the basics of HTML and CSS to advanced JavaScript concepts and modern frameworks like Angular and React. I conquered challenges, embraced new technologies, and honed my problem-solving skills. The learning never stops, and I'm excited to carry this knowledge forward in my career.&lt;/p&gt;

&lt;h2&gt;
  
  
  🤝 Seeking Your Feedback
&lt;/h2&gt;

&lt;p&gt;As I wrap up this challenge, I'm eager to hear your thoughts. Your feedback is crucial to my growth as a developer and content creator. What articles did you find most helpful? Are there specific topics you'd like me to explore further? Your insights will shape the direction of my future content.&lt;/p&gt;

&lt;p&gt;Please take a moment to share your feedback through this &lt;a href="https://forms.gle/GPqHDeKWZvVb3nzP6" rel="noopener noreferrer"&gt;Feedback Form&lt;/a&gt;. I genuinely appreciate your input, and together, we can make the learning experience even better. &lt;/p&gt;

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

&lt;p&gt;As I close the chapter on my 100 Days Learning Challenge, I extend my heartfelt thanks once again. Whether you're a seasoned developer or just starting out, remember that the journey of learning is ongoing. Let's continue to support each other and build a thriving community of passionate developers. &lt;/p&gt;

</description>
      <category>100daysofcode</category>
      <category>webdev</category>
      <category>frontend</category>
    </item>
    <item>
      <title>Day 99: Match Pair</title>
      <dc:creator>Dharan Ganesan</dc:creator>
      <pubDate>Sun, 17 Dec 2023 16:30:00 +0000</pubDate>
      <link>https://forem.com/dhrn/day-98-match-pair-1j1</link>
      <guid>https://forem.com/dhrn/day-98-match-pair-1j1</guid>
      <description>&lt;h2&gt;
  
  
  Question
&lt;/h2&gt;

&lt;p&gt;Create React or Angular code snippet that should allow the user to play &lt;a href="https://en.wikipedia.org/wiki/Matching_game#:~:text=Participants%20need%20to%20find%20a,pair%2C%20by%20using%20their%20memory." rel="noopener noreferrer"&gt;match pair&lt;/a&gt; game&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%2F8lwkgk9rnrozpnyxkjah.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%2F8lwkgk9rnrozpnyxkjah.gif" alt=" " width="800" height="520"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;
  &lt;strong&gt;Show Hint&lt;/strong&gt;
  &lt;ol&gt;
&lt;li&gt;Create an array of card symbols, shuffle it for randomization.&lt;/li&gt;
&lt;li&gt;Implement a click handler to flip cards and check for matches.&lt;/li&gt;
&lt;li&gt;Use CSS or animations for visual feedback, and track matched pairs to determine game completion.&lt;/li&gt;
&lt;/ol&gt;



&lt;/p&gt;

&lt;p&gt;Check the comment below to see answer.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>frontend</category>
      <category>javascript</category>
      <category>angular</category>
    </item>
    <item>
      <title>Day 98: OTP</title>
      <dc:creator>Dharan Ganesan</dc:creator>
      <pubDate>Thu, 14 Dec 2023 16:10:00 +0000</pubDate>
      <link>https://forem.com/dhrn/day-98-otp-5fda</link>
      <guid>https://forem.com/dhrn/day-98-otp-5fda</guid>
      <description>&lt;h2&gt;
  
  
  Question
&lt;/h2&gt;

&lt;p&gt;Create React or Angular code snippet that should allow the user to add OTP as below&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%2Fiykr3t5gc5zrc6dcmhcd.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%2Fiykr3t5gc5zrc6dcmhcd.gif" alt=" " width="600" height="276"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Hint:&lt;/strong&gt; write function to listen keyboard left and right arrow key codes and focus on the previous or next input accordingly.&lt;/p&gt;

&lt;p&gt;Check the comment below to see answer.&lt;/p&gt;

</description>
      <category>frontend</category>
      <category>webdev</category>
      <category>angular</category>
      <category>react</category>
    </item>
    <item>
      <title>Day 97: Typed Effect</title>
      <dc:creator>Dharan Ganesan</dc:creator>
      <pubDate>Tue, 12 Dec 2023 15:18:39 +0000</pubDate>
      <link>https://forem.com/dhrn/day-97-typed-effect-4lcb</link>
      <guid>https://forem.com/dhrn/day-97-typed-effect-4lcb</guid>
      <description>&lt;h2&gt;
  
  
  Question
&lt;/h2&gt;

&lt;p&gt;Create React or Angular code snippet that implements typed effect as below&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%2Fwa8z0bwdnj9z2jvlhfjm.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%2Fwa8z0bwdnj9z2jvlhfjm.gif" alt=" " width="600" height="221"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Hint:&lt;/strong&gt; Use an array to store multiple strings, and modify the JavaScript to type each string one after the other, with a brief pause in between.&lt;/p&gt;

&lt;p&gt;Check the comment below to see answer.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>frontend</category>
      <category>angular</category>
      <category>react</category>
    </item>
    <item>
      <title>Day 96: Type Tester</title>
      <dc:creator>Dharan Ganesan</dc:creator>
      <pubDate>Mon, 11 Dec 2023 13:40:00 +0000</pubDate>
      <link>https://forem.com/dhrn/day-96-speed-test-5i6</link>
      <guid>https://forem.com/dhrn/day-96-speed-test-5i6</guid>
      <description>&lt;h2&gt;
  
  
  Question
&lt;/h2&gt;

&lt;p&gt;Create React or Angular code snippet that implements type speed tester as below&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%2F6o53uhwra5li1rsb0aps.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%2F6o53uhwra5li1rsb0aps.gif" alt=" " width="600" height="283"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Hint:&lt;/strong&gt; The component keeps track of the user's input using  state. An event handler is used to update this state whenever the user types in the input field.&lt;/p&gt;

&lt;p&gt;Check the comment below to see answer.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>frontend</category>
      <category>anuglar</category>
      <category>react</category>
    </item>
    <item>
      <title>Day 95: Skeleton</title>
      <dc:creator>Dharan Ganesan</dc:creator>
      <pubDate>Fri, 24 Nov 2023 17:24:23 +0000</pubDate>
      <link>https://forem.com/dhrn/day-95-skeleton-lnp</link>
      <guid>https://forem.com/dhrn/day-95-skeleton-lnp</guid>
      <description>&lt;h2&gt;
  
  
  Question
&lt;/h2&gt;

&lt;p&gt;Create React or Angular code snippet that implements an skeleton container as below&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%2Fakzdqymrtznk4q0y8jhc.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%2Fakzdqymrtznk4q0y8jhc.gif" alt=" " width="600" height="548"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Hint: Use a container with a background gradient animation to simulate a loading effect.&lt;/p&gt;

&lt;p&gt;Check the comment below to see answer.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>frontend</category>
      <category>100daysofcode</category>
    </item>
    <item>
      <title>Day 94: Frameworks</title>
      <dc:creator>Dharan Ganesan</dc:creator>
      <pubDate>Thu, 23 Nov 2023 17:40:00 +0000</pubDate>
      <link>https://forem.com/dhrn/day-94-frameworks-3g2p</link>
      <guid>https://forem.com/dhrn/day-94-frameworks-3g2p</guid>
      <description>&lt;p&gt;In the ever-evolving landscape of web development, choosing the right frontend framework can be a daunting task. With a plethora of options available, each with its strengths and weaknesses, developers often find themselves at a crossroads. In this article, we'll look into some popular frontend frameworks, exploring their features to make an informed decision.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;1. Angular: The Full-Fledged Framework&lt;/strong&gt; 🅰️
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://angular.dev/" rel="noopener noreferrer"&gt;Angular&lt;/a&gt;, developed and maintained by Google, is a comprehensive, opinionated framework that comes with everything you need to build robust and scalable applications. It uses TypeScript, a superset of JavaScript, providing static typing for enhanced code quality.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Usage&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Angular shines in large-scale enterprise applications. Its modular architecture, two-way data binding, and dependency injection make it an excellent choice for projects where maintainability and structure are paramount.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Tips&lt;/strong&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Angular Component&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;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="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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;lt;h1&amp;gt;Hello Angular!&amp;lt;/h1&amp;gt;&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;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AppComponent&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Leverage Angular CLI for scaffolding and managing your project.&lt;/li&gt;
&lt;li&gt;Utilize reactive forms for complex form handling.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;2. React: The Declarative Library ⚛️&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://react.dev/" rel="noopener noreferrer"&gt;React&lt;/a&gt;, developed by Facebook, is a JavaScript library for building user interfaces. It follows a declarative paradigm, allowing developers to describe how the UI should look based on the application's state.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Usage&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;React is widely adopted, powering many high-profile applications, including Facebook, Instagram, and Airbnb. Its component-based architecture makes it versatile, suitable for projects of any size.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Tips&lt;/strong&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// React Component&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="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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;MyComponent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Hello React!&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Use React hooks for state and side effects.&lt;/li&gt;
&lt;li&gt;Embrace JSX for a more expressive and readable code.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;3. Vue.js: The Progressive Framework 🖖&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://vuejs.org/" rel="noopener noreferrer"&gt;Vue.js&lt;/a&gt; is a progressive JavaScript framework that focuses on simplicity and ease of integration. It is incrementally adoptable, allowing developers to use as much or as little of its features as needed.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Usage&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Vue.js is often chosen for its gentle learning curve, making it an excellent fit for startups and small to medium-sized projects. Its reactivity system and component-based architecture contribute to a flexible and maintainable codebase.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Tips&lt;/strong&gt;
&lt;/h3&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;!-- Vue Component --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;template&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;Hello Vue.js!&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/template&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Options API&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Leverage Vue CLI for scaffolding and managing your project.&lt;/li&gt;
&lt;li&gt;Utilize Vuex for state management in larger applications.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;4. Svelte: The Compiler Approach 🚀&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Svelte takes a different approach by shifting the work from the browser to the build step. It compiles components into highly optimized JavaScript at build time, resulting in smaller bundle sizes and improved runtime performance.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Usage&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://svelte.dev/" rel="noopener noreferrer"&gt;Svelte&lt;/a&gt; is gaining popularity for its simplicity and efficient output. It's an excellent choice for projects where performance is a top priority, such as single-page applications and interactive websites.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Tips&lt;/strong&gt;
&lt;/h3&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;!-- Svelte Component --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;message&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 Svelte!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;{message}&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Embrace the simplicity of Svelte's reactive assignments.&lt;/li&gt;
&lt;li&gt;Utilize stores for global state management.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Comparative Analysis&lt;/strong&gt;
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Learning Curve:&lt;/strong&gt; React has a more gradual learning curve, while Angular's is steeper due to its opinionated structure. Vue.js and Svelte are known for their gentle learning curves.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Performance:&lt;/strong&gt; Svelte often outperforms React, Angular, and Vue.js in terms of bundle size and runtime efficiency.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Community and Ecosystem:&lt;/strong&gt; React boasts a large and active community, while Vue.js and Angular have vibrant communities as well. Svelte is gaining traction but is relatively newer.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>webdev</category>
      <category>frontend</category>
      <category>100daysofcode</category>
    </item>
    <item>
      <title>Day 93: Web components</title>
      <dc:creator>Dharan Ganesan</dc:creator>
      <pubDate>Wed, 22 Nov 2023 17:00:00 +0000</pubDate>
      <link>https://forem.com/dhrn/day-93-web-components-1dik</link>
      <guid>https://forem.com/dhrn/day-93-web-components-1dik</guid>
      <description>&lt;p&gt;Web development has evolved significantly over the years, with a constant quest for more modular, reusable, and maintainable code. Web Components provides a set of web platform APIs that enable the creation of custom, reusable, and encapsulated HTML elements. &lt;/p&gt;

&lt;h3&gt;
  
  
  HTML Templates 🎨
&lt;/h3&gt;

&lt;p&gt;HTML Templates are the foundation of Web Components, providing a way to declare fragments of markup that can be cloned and inserted into the document later. This helps in creating modular and reusable pieces of UI.&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;template&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"my-template"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;style&amp;gt;&lt;/span&gt;
    &lt;span class="c"&gt;/* Styles specific to this template */&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/style&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;"component"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;Hello, &lt;span class="nt"&gt;&amp;lt;slot&amp;gt;&amp;lt;/slot&amp;gt;&lt;/span&gt;!&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/template&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, we've defined a template with a placeholder (&lt;code&gt;&amp;lt;slot&amp;gt;&amp;lt;/slot&amp;gt;&lt;/code&gt;) that can be filled with content when the template is used.&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;script&amp;gt;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;template&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;my-template&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;clone&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;importNode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;template&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;clone&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;slot&lt;/span&gt;&lt;span class="dl"&gt;'&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;World&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;appendChild&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;clone&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Custom Elements 🚀
&lt;/h3&gt;

&lt;p&gt;Custom Elements allow developers to create their own HTML elements with custom behavior. They encapsulate functionality, making it easy to reuse and share across different projects.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyComponent&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;HTMLElement&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="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;super&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;shadowRoot&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="nf"&gt;attachShadow&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;open&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="c1"&gt;// Use the template directly within the class&lt;/span&gt;
    &lt;span class="nx"&gt;shadowRoot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerHTML&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`
      &amp;lt;style&amp;gt;
        p {
          color: #3498db;
        }
      &amp;lt;/style&amp;gt;
      &amp;lt;p&amp;gt;Hello, &amp;lt;slot&amp;gt;&amp;lt;/slot&amp;gt;!&amp;lt;/p&amp;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="nx"&gt;customElements&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;define&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;my-component&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;MyComponent&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, you can use &lt;code&gt;&amp;lt;my-component&amp;gt;&lt;/code&gt; in your HTML:&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;my-component&amp;gt;&amp;lt;/my-component&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Shadow DOM 🔍
&lt;/h3&gt;

&lt;p&gt;Shadow DOM provides encapsulation for your web components, shielding their styles and structure from the rest of the document. This ensures that styles and scripts in your component do not interfere with the rest of the page.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyComponent&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;HTMLElement&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="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="c1"&gt;// Attach a shadow DOM to encapsulate styles and structure&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;shadowRoot&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="nf"&gt;attachShadow&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;open&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="nx"&gt;shadowRoot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerHTML&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`
      &amp;lt;style&amp;gt;
        p {
          color: #3498db;
        }
      &amp;lt;/style&amp;gt;
      &amp;lt;p&amp;gt;Hello, &amp;lt;slot&amp;gt;&amp;lt;/slot&amp;gt;!&amp;lt;/p&amp;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="nx"&gt;customElements&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;define&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;my-component&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;MyComponent&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Tips  💡
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Keep it modular:&lt;/strong&gt; Break down complex UIs into smaller, manageable components to maximize reusability.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use Shadow DOM judiciously:&lt;/strong&gt; Leverage Shadow DOM to encapsulate styles and scripts, preventing unintended interference.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Explore component libraries:&lt;/strong&gt; Many libraries, such as LitElement and Stencil, simplify the creation and management of Web Components.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Events&lt;/strong&gt;: Use Custom Events to establish communication between Web Components, enabling a more modular architecture.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lifecycle Hooks&lt;/strong&gt;: Implement lifecycle hooks (e.g., &lt;code&gt;connectedCallback&lt;/code&gt;, &lt;code&gt;disconnectedCallback&lt;/code&gt;) to perform actions when a component is added or removed from the DOM.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Usage 🌐
&lt;/h3&gt;

&lt;p&gt;Web Components find extensive use in various scenarios, from UI libraries to large-scale applications. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;UI Libraries:&lt;/strong&gt; Build modular UI components that can be easily shared and reused across projects.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Micro-frontends:&lt;/strong&gt; Use Web Components to create self-contained, independently deployable parts of a larger application.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Third-Party Integration:&lt;/strong&gt; Develop widgets or components that can be embedded seamlessly into other websites.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>webdev</category>
      <category>frontend</category>
      <category>100daysofcode</category>
      <category>webcomponents</category>
    </item>
    <item>
      <title>Day 92: WebRTC</title>
      <dc:creator>Dharan Ganesan</dc:creator>
      <pubDate>Tue, 21 Nov 2023 17:26:44 +0000</pubDate>
      <link>https://forem.com/dhrn/day-92-webrtc-276</link>
      <guid>https://forem.com/dhrn/day-92-webrtc-276</guid>
      <description>&lt;h3&gt;
  
  
  What is WebRTC?
&lt;/h3&gt;

&lt;p&gt;WebRTC is an open-source project that provides web browsers and mobile applications with real-time communication via simple application programming interfaces (APIs). It empowers developers to create robust, real-time communication applications without the need for plugins or third-party software.&lt;/p&gt;

&lt;h3&gt;
  
  
  Core Components:
&lt;/h3&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;getUserMedia API: 📷&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;The &lt;code&gt;getUserMedia&lt;/code&gt; API is the gateway to accessing a user's camera and microphone. It prompts the user for permission and returns a media stream that can be used for various real-time communication scenarios.&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="nb"&gt;navigator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;mediaDevices&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getUserMedia&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;video&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;audio&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="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;stream&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Use the stream for video and audio&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Error accessing media devices:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  &lt;strong&gt;RTCPeerConnection: 🔗&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;&lt;code&gt;RTCPeerConnection&lt;/code&gt; establishes and manages the connection between peers, handling the negotiation and transfer of audio, video, and data streams. It employs a series of protocols to ensure a secure and reliable connection.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;peerConnection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;RTCPeerConnection&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// Add local stream to the connection&lt;/span&gt;
&lt;span class="nx"&gt;peerConnection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addStream&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;localStream&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Set up event handlers for various connection events&lt;/span&gt;
&lt;span class="nx"&gt;peerConnection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onicecandidate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &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="nx"&gt;candidate&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Send the candidate to the remote peer&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;h4&gt;
  
  
  &lt;strong&gt;RTCDataChannel: 📤📥&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;&lt;code&gt;RTCDataChannel&lt;/code&gt; allows for bidirectional communication of arbitrary data between peers. This is particularly useful for scenarios where additional data needs to be transmitted alongside audio and video streams.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;dataChannel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;peerConnection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createDataChannel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;myDataChannel&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;dataChannel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onopen&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="c1"&gt;// Data channel is open and ready to use&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="nx"&gt;dataChannel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onmessage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Handle incoming messages&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Chat Application 🎥💬
&lt;/h2&gt;

&lt;h3&gt;
  
  
  HTML (index.html):
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&lt;/span&gt; &lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;"en"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;charset=&lt;/span&gt;&lt;span class="s"&gt;"UTF-8"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"viewport"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"width=device-width, initial-scale=1.0"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;WebRTC Video Chat&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;video&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"localVideo"&lt;/span&gt; &lt;span class="na"&gt;autoplay&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/video&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;video&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"remoteVideo"&lt;/span&gt; &lt;span class="na"&gt;autoplay&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/video&amp;gt;&lt;/span&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;"app.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  JavaScript (app.js):
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;localVideo&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;localVideo&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;remoteVideo&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;remoteVideo&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nb"&gt;navigator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;mediaDevices&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getUserMedia&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;video&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;audio&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="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;localStream&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;localVideo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;srcObject&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;localStream&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;peerConnection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;RTCPeerConnection&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="c1"&gt;// Add local stream to the connection&lt;/span&gt;
    &lt;span class="nx"&gt;peerConnection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addStream&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;localStream&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="nx"&gt;peerConnection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onicecandidate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;if &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="nx"&gt;candidate&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Send the candidate to the remote peer&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;

    &lt;span class="c1"&gt;// Create offer and set local description&lt;/span&gt;
    &lt;span class="nx"&gt;peerConnection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createOffer&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;offer&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;peerConnection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setLocalDescription&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;offer&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&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="c1"&gt;// Send the offer to the remote peer&lt;/span&gt;
      &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="c1"&gt;// Handle incoming stream from the remote peer&lt;/span&gt;
    &lt;span class="nx"&gt;peerConnection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onaddstream&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;remoteVideo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;srcObject&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;stream&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Error accessing media devices:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Tips 🛠️
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Handling Connectivity Issues ⚠️:&lt;/strong&gt; Implement robust error handling to manage unexpected disconnections and network fluctuations.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Bandwidth Considerations 🌐:&lt;/strong&gt; Optimize media streams based on available bandwidth to ensure a smooth user experience.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Security Best Practices 🔒:&lt;/strong&gt; Use secure connections (HTTPS) and implement proper authentication mechanisms to protect against potential security threats.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Cross-Browser Compatibility 🌐:&lt;/strong&gt; Test your WebRTC application on various browsers to ensure consistent functionality.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Debugging Tools 🛠️:&lt;/strong&gt; Leverage browser developer tools and third-party libraries like &lt;code&gt;webrtc-internals&lt;/code&gt; for in-depth debugging.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Usage
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Video Conferencing Apps:&lt;/strong&gt; Services like Zoom and Google Meet utilize WebRTC for real-time video conferencing.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Live Streaming:&lt;/strong&gt; Platforms such as Twitch and YouTube Live leverage WebRTC for low-latency live streaming.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Online Gaming 🎮:&lt;/strong&gt; Multiplayer online games leverage WebRTC for real-time communication between players, enhancing the gaming experience.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;File Sharing Services 📂:&lt;/strong&gt; WebRTC facilitates peer-to-peer file sharing directly in the browser, making it ideal for applications that require secure and efficient file transfers.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>webdev</category>
      <category>frontend</category>
      <category>100daysofcode</category>
      <category>javascript</category>
    </item>
  </channel>
</rss>
