<?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: Naimur Rahman</title>
    <description>The latest articles on Forem by Naimur Rahman (@naimur).</description>
    <link>https://forem.com/naimur</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%2F55468%2Fb83f798d-a906-4997-a548-33a8169beb75.jpeg</url>
      <title>Forem: Naimur Rahman</title>
      <link>https://forem.com/naimur</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/naimur"/>
    <language>en</language>
    <item>
      <title>I built Supatab: Chat with your Chrome tabs like ChatGPT</title>
      <dc:creator>Naimur Rahman</dc:creator>
      <pubDate>Sat, 31 May 2025 08:00:00 +0000</pubDate>
      <link>https://forem.com/naimur/i-built-supatab-chat-with-your-chrome-tabs-like-chatgpt-4h6i</link>
      <guid>https://forem.com/naimur/i-built-supatab-chat-with-your-chrome-tabs-like-chatgpt-4h6i</guid>
      <description>&lt;p&gt;As a developer, I’m often jumping between 10 or more tabs—reading docs, blog posts, GitHub issues, comparing tools, or just trying to figure something out. I realized I was wasting a lot of time switching back and forth, trying to remember where I saw something or copy-pasting between tabs. It was just getting in the way of getting things done.&lt;/p&gt;

&lt;p&gt;So I asked myself:&lt;br&gt;
&lt;strong&gt;What if I could just talk to my tabs and ask questions — like ChatGPT, but for my browser?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That’s how &lt;a href="https://supatab.app" rel="noopener noreferrer"&gt;Supatab&lt;/a&gt; was born.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What Supatab does&lt;/strong&gt;&lt;br&gt;
Supatab is a Chrome extension that lets you:&lt;br&gt;
• Chat with any open tab as if it were an AI assistant&lt;br&gt;
• Summarize long articles, docs, or reports instantly&lt;br&gt;
• Ask specific questions and get relevant answers without re-reading everything&lt;br&gt;
• Extract key points from dense pages&lt;br&gt;
• Stay focused without switching tabs constantly&lt;/p&gt;

&lt;p&gt;It’s like having a mini ChatGPT for every tab you’re working with.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why I built it&lt;/strong&gt;&lt;br&gt;
I initially built this just for myself — to speed up how I understand product requirements, technical articles, or explore new APIs. But after sharing it with a few friends, I realized other devs were facing the same struggles.&lt;/p&gt;

&lt;p&gt;So I decided to polish it a bit and launch it publicly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Want to give it a try?&lt;/strong&gt;&lt;br&gt;
Supatab is &lt;strong&gt;free&lt;/strong&gt;, and I’d really love to hear what you think. You can &lt;a href="https://chromewebstore.google.com/detail/supatab/paegfcicdclnmbkedpnanmnhchfbalfa" rel="noopener noreferrer"&gt;install the extension here&lt;/a&gt; and check it out. If you find it helpful, I’d really appreciate your support on &lt;a href="https://www.producthunt.com/products/supatab?launch=supatab" rel="noopener noreferrer"&gt;Product Hunt&lt;/a&gt;. An upvote would mean a lot and help get Supatab in front of more people who might benefit from it too.&lt;/p&gt;

</description>
      <category>extensions</category>
      <category>productivity</category>
      <category>ai</category>
      <category>saas</category>
    </item>
    <item>
      <title>BroadcastChannel API: Sending Messages Between Tabs</title>
      <dc:creator>Naimur Rahman</dc:creator>
      <pubDate>Wed, 06 Sep 2023 17:22:28 +0000</pubDate>
      <link>https://forem.com/naimur/broadcastchannel-api-sending-messages-between-tabs-59m9</link>
      <guid>https://forem.com/naimur/broadcastchannel-api-sending-messages-between-tabs-59m9</guid>
      <description>&lt;h2&gt;
  
  
  Why Tab Communication in Web Browser Matters
&lt;/h2&gt;

&lt;p&gt;Communicating between different tabs or windows in a web browser is super important for many reasons. Imagine you have several open tabs while shopping online. You put an item in your cart in one tab, and you want all the other tabs to know about it instantly. That's one of the reasons we need this kind of communication. Also, think about logging into a website like your bank account. If we log out in one tab, we'd want to be logged out in all the other tabs, too to keep everything safe. It's like making sure you lock all the doors when leaving your house. So, it's not just convenient; it also makes the web safer and more efficient for us.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is the Broadcast Channel API?
&lt;/h2&gt;

&lt;p&gt;The Broadcast Channel API is like a special communication tool for web browsers. It allows different tabs or windows in our browser to talk to each other. It's a way for them to share information instantly. Think of it as a secret chat system just for our browser. It helps web apps work together and stay in sync, making our online experience smoother.&lt;/p&gt;

&lt;h2&gt;
  
  
  How Broadcast Channel API works
&lt;/h2&gt;

&lt;p&gt;Here's how it works in simple terms:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Create a Channel&lt;/strong&gt;: We create a channel with a specific name, like &lt;code&gt;cart_channel&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Send Messages&lt;/strong&gt;: In one tab, we can send a message (like "I added a new item to the cart!") to the &lt;code&gt;cart_channel&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Other Tabs Listen&lt;/strong&gt;: All the other open tabs also tuned into the &lt;code&gt;cart_channel&lt;/code&gt; can hear this message.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Instant Updates&lt;/strong&gt;: So, when we add something to our cart in one tab, all the other tabs can instantly update to show the same thing. It's like magic!&lt;/p&gt;&lt;/li&gt;
&lt;/ol&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%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1694008679571%2Fec49b41b-57be-49fd-9e49-c72d3608908d.png%2520align%3D" 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%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1694008679571%2Fec49b41b-57be-49fd-9e49-c72d3608908d.png%2520align%3D" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To implement Broadcast Channel API in your application read the full article here 👉 &lt;a href="https://naimur.dev/broadcastchannel-api" rel="noopener noreferrer"&gt;https://naimur.dev/broadcastchannel-api&lt;/a&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>broadcastchannelapi</category>
      <category>realtime</category>
      <category>browser</category>
    </item>
    <item>
      <title>Building Offline-Ready Webpage with Service Worker and Cache Storage</title>
      <dc:creator>Naimur Rahman</dc:creator>
      <pubDate>Fri, 01 Sep 2023 19:40:52 +0000</pubDate>
      <link>https://forem.com/naimur/building-offline-ready-webpage-with-service-worker-and-cache-storage-3dbk</link>
      <guid>https://forem.com/naimur/building-offline-ready-webpage-with-service-worker-and-cache-storage-3dbk</guid>
      <description>&lt;h2&gt;
  
  
  Why We Need Offline Web Pages
&lt;/h2&gt;

&lt;p&gt;Sometimes, our internet connection isn't reliable or completely absent. In those moments, we still want to use websites and apps. This is where offline web pages come in handy. They allow us to access content even when we're not online.&lt;/p&gt;

&lt;h2&gt;
  
  
  Introducing Service Workers and Cache Storage
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API" rel="noopener noreferrer"&gt;Service Workers&lt;/a&gt;&lt;/strong&gt; are like web helpers. It work behind the scenes to make offline web pages possible. It can save website stuff (like pictures, fonts and other assets) on our device so we can see them even without the internet. It also control what our web page does when it's online.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/CacheStorage" rel="noopener noreferrer"&gt;Cache Storage&lt;/a&gt;&lt;/strong&gt; is like a storage room for web things. It keeps all the website stuff we might need, organised neatly. Service Workers can go there and grab what's needed for page to load offline. So, when we're not online, we still get to see and use web pages.&lt;/p&gt;

&lt;p&gt;Let's explore how to make a webpage available offline by doing some simple coding. We'll save an HTML file and an image so that users can still see them, even when they are not connected to the internet.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 1: Getting Started&lt;/strong&gt;&lt;br&gt;
First, Let's create a folder for our project and put main HTML file &lt;code&gt;index.html&lt;/code&gt; and the image we want to use &lt;code&gt;cat.jpeg&lt;/code&gt; inside it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 2: Registering the Service Worker&lt;/strong&gt;&lt;br&gt;
Now, let's register the Service Worker in &lt;code&gt;index.html&lt;/code&gt; file. Place the following code:&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="o"&gt;&amp;lt;!&lt;/span&gt;&lt;span class="nx"&gt;DOCTYPE&lt;/span&gt; &lt;span class="nx"&gt;html&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;html&lt;/span&gt; &lt;span class="nx"&gt;lang&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;en&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;head&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;meta&lt;/span&gt; &lt;span class="nx"&gt;charset&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;UTF-8&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;meta&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;viewport&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;width=device-width, initial-scale=1.0&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Document&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/title&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/head&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;h1&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Hi&lt;/span&gt; &lt;span class="nx"&gt;There&lt;/span&gt;&lt;span class="o"&gt;!&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/h1&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;img&lt;/span&gt; &lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./cat.jpeg&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;300&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;300&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;

    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;script&lt;/span&gt;&lt;span class="o"&gt;&amp;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;registerServiceWorker&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;serviceWorker&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;navigator&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="k"&gt;try&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;registration&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&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;serviceWorker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;register&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
              &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;sw.js&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="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
              &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Service Worker registered with scope:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
              &lt;span class="nx"&gt;registration&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;scope&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="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="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="s2"&gt;Service Worker registration failed:&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;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;

      &lt;span class="nf"&gt;registerServiceWorker&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/script&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/body&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/html&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this code we check if the browser supports Service Workers.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 3: Writing the Service Worker Code&lt;/strong&gt;&lt;br&gt;
Now, let's create a JavaScript file called &lt;code&gt;sw.js&lt;/code&gt; in project folder. This file will contain the code for Service Worker.&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;cacheName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;offline-cache-v1&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;cacheUrls&lt;/span&gt; &lt;span class="o"&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;index.html&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;cat.jpeg&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="c1"&gt;// Installing the Service Worker&lt;/span&gt;
&lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;install&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="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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;try&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;cache&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;caches&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cacheName&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;cache&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cacheUrls&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="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="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="s2"&gt;Service Worker installation failed:&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;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// Fetching resources&lt;/span&gt;
&lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;fetch&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;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;respondWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cache&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;caches&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cacheName&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

      &lt;span class="k"&gt;try&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;cachedResponse&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;cache&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;match&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;request&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;cachedResponse&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="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;cachedResponse: &lt;/span&gt;&lt;span class="dl"&gt;"&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;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
          &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;cachedResponse&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;fetchResponse&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&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;request&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;fetchResponse&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="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;fetchResponse: &lt;/span&gt;&lt;span class="dl"&gt;"&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;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;url&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;cache&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;put&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;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;fetchResponse&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;clone&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
          &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;fetchResponse&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="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="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Fetch failed: &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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cachedResponse&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;cache&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;match&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="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;cachedResponse&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;THere's what's happening in the code:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We give a name to our cache (cacheName) and list the URLs (cacheUrls) we want to store for offline use.&lt;/li&gt;
&lt;li&gt;In the "install" part, we prepare our cache and add the URLs to it.&lt;/li&gt;
&lt;li&gt;We open the cache and attempt to match the request with the cached responses.&lt;/li&gt;
&lt;li&gt;If a cached response is found, it's returned. If not, we fetch the resource from the network, cache it for future use, and return the network response.&lt;/li&gt;
&lt;li&gt;In case of any errors during the fetch process, we handle it by returning a cached version of "index.html" to ensure the user still sees something.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Step 4: Testing our Offline-Friendly webpage&lt;/strong&gt;&lt;br&gt;
To check if the page works offline:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Open the page while the device is online to make sure it loads correctly, including the image.&lt;/li&gt;
&lt;li&gt;Disconnect from the internet (turn off Wi-Fi or unplug network cable).&lt;/li&gt;
&lt;li&gt;Reload the page. We should still see the page, including the image, even though there's no internet.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We can also test from the chrome browser, here's the steps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Open the page while the device is online&lt;/li&gt;
&lt;li&gt;Open devtools in chrome browser and go to the &lt;code&gt;Application&lt;/code&gt; tab&lt;/li&gt;
&lt;li&gt;Click on &lt;code&gt;Service Workers&lt;/code&gt; from the sidebar and check the &lt;code&gt;Offline&lt;/code&gt; option&lt;/li&gt;
&lt;li&gt;Reload the page and we can see the contents loading offline&lt;/li&gt;
&lt;/ul&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%2Ftfjbg2k6kgv0cgx4dr2m.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftfjbg2k6kgv0cgx4dr2m.png" alt="Cate image" width="800" height="421"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We've now created a webpage that can work offline using Service Workers. This technique can be expanded to store more things and make websites robust even when there's no internet.&lt;/p&gt;

&lt;p&gt;Full Code 👉 &lt;a href="https://github.com/nsourov/offline-web-page" rel="noopener noreferrer"&gt;https://github.com/nsourov/offline-web-page&lt;/a&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>frontend</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
