loading...
Cover image for How to easily turn your website to a Progressive Web App(PWA)

How to easily turn your website to a Progressive Web App(PWA)

dfiredeveloper profile image Ilemona Achimugu Originally published at Medium ・13 min read

Progressive Web App is the new and trending way to bring a native app feeling into a normal or traditional web app. Progressive Web Apps are very much in use by some of the biggest companies like Twitter, Forbes, Alibaba, Instagram, Flipkart e.t.c and have gained popularity.

So in this tutorial, we’ll be turning our already existing website into a Progressive Web App. Let’s Get Started :)

Intro

I’m sure by now you must have heard or read about Progressive Web Applications and if you haven’t here is it.

A progressive web application (PWA) is a type of application software delivered through the web, built using common web technologies including HTML, CSS, and JavaScript. It is intended to work on any platform that uses a standards-compliant browser. Functionality includes working offline, push notifications, and device hardware access, enabling creating user experiences similar to native applications on desktop and mobile devices.

Progressive Web Apps are largely characterized by the following:

  • Reliable — They load instantly and never show the “No Internet Connection” page, even in uncertain network conditions with help from Service workers caching.

  • Fast — They respond quickly to user interactions with smooth animations.

  • Engaging — They feel like a natural app on the device, with immersive user experience.

Requirements for this tutorial

  1. Basic web design skills (HTML, CSS & JS)

  2. You need to be running on HTTPS

  3. A working website you wish to tun to PWA.

Like I said, building a Progressive Web App is quite simple and easy if you understand the whole concept and how it actually works.

What Makes up a PWA

  1. Web Manifest
  2. Service Worker
  3. Your static website
Let’s Start

For the sake of this tutorial, we’ll be turning a simple random quote web app to a PWA. All the files are hosted here on Github and the demo is available Here

So for the sake of making sure things go right, we’ll rebuild the simple random quote web app using HTML, CSS, and JavaScript.

Final Project
That's how the final project will look like.

So let’s build the UI.

Make a new directory and create these files

  • index.html

  • css/style.css

  • js/app.js

Let's Build the Markup.

Add the below codes in the index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>The Igala Facts you never knew</title>
    <link rel="stylesheet" href="css/style.css">
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.5.0/css/font-awesome.min.css">
    <link href='https://fonts.googleapis.com/css?family=Roboto+Slab:400,700' rel='stylesheet' type='text/css'>
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css">
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/3.2.3/animate.min.css">
</head>
<body>
    <div class="container">
        <div class="row">
          <div class="col-sm-6">
            <h1><span class="main-color">Random Igala</span><br />Facts</h1>
            <p>The best facts about Igala in one place. You can easily see the best facts and  share the ones you love on twitter with one click.</p>
          </div>
          <div class="col-sm-6">
            <div class="row">
              <div class="col-xs-6">
                <a id="next-quote" class="btn btn-lg btn-default btn-block" href="#"><i class="fa fa-refresh"></i> Next Fact</a>
              </div>
              <div class="col-xs-6">
                <a id="share" class="btn btn-lg btn-default btn-block" href="#" target="_top"><i class="fa fa-twitter"></i> Share</a>
              </div>
            </div>

            <div id="quote-box">
              <i id="quote-left" class="fa fa-quote-left"></i>
              <p id="quote"></p>
              <span id="author" class="main-color"></span>
              <i id="quote-right" class="fa fa-quote-right"></i>
            </div>

            <div class="row">       
              <div class="col-xs-12">
                <ul>
                  <li>Follow Us</li>
                  <li><a class="main-color" href="https://facebook.com/theigaladigital" target="_blank">@theigaladigital</a></li>
                    </ul>
                  </div>
              </div>
            </div>
          </div>
        </div>
      </div>

      <div id="hidden"></div>
      <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
      <script src="js/app.js"></script>
</body>
</html>

Like I said earlier, this tutorial is mainly teaching you how to convert your already existing website into a Progressive Web App so I won’t be going in detail on the HTML or rest.

— Add this in css/app.css

body {
    background-color: rgb(0, 0, 0);
    color: white;
    padding-top: 50px;
    font-size: 18px;
    font-family: 'Roboto Slab', serif;
  }

  h1 {
    font-size: 4em;
    line-height: 70px;
    margin-bottom: 40px;
    font-weight: bold;
  }

  a:hover, a:focus, a:active {
    text-decoration: none;
    color: white;
    transition: color 0.8s;
  }

  .main-color {
    color: yellow;
    text-shadow: 1px 1px 0 rgba(255, 255, 255, 0.2);
    font-weight: bold;
  }

  #quote-box {
    background-color: rgba(255, 255, 255, 0.3);
    border-radius: 10px;
    padding: 100px 40px;
    position: relative;
    margin-top: 20px;
  }

  #quote-left, #quote-right {
    color: yellow;
    font-size: 3em;
    position: absolute;
  }

  #quote-left {
    top: 20px;
    left: 20px;
  }

  #quote-right {
    bottom: 20px;
    right: 20px;
  }

  #quote {
    font-size: 1.5em;
    text-align: center;
  }

  #author {
    position: absolute;
    font-size: 1.1em;
    left: 50px;
    bottom: 30px;
  }

  .btn {
    border-radius: 10px;
    color: yellow;
    border: 1px solid white !important;
    transition: background 0.8s, color 0.8s;
    line-height: 30px;
    margin-top: 30px;
  }

  .btn:hover, .btn:active, .btn:focus {
    color: white !important;
    background-color: yellow !important;
    box-shadow: none;
  }

  ul {
    list-style-type: none;
    padding: 0;
    margin: 10px 0 0 0;
    float: right;
    white-space: nowrap;
    overflow: hidden;
  }

  li {
    display: inline-block;
    margin: 0 0 0 1px;
  }

  #hidden {
    display: none;
  }

Now your app should look like this:
Front Page

If you look up closely, you will discover no quote shows, so we’ll have to add JavaScript functionality that handles that.

— Add this in js/app.js

$(document).ready(function () {  
    $("#next-quote").on("click", function (e) {
      e.preventDefault();

      var randomQuoteNumber = getRandomQuoteNumber();
      updateQuote(randomQuoteNumber);
    });

    var q = location.search.split("?q=")[1];

    if (q >= 0 && q < quotes.length) {
      updateQuote(q);
    } else {
      $("#next-quote").click();
    }
  });

  function updateQuote(quoteNumber) {
    var randomQuote = quotes[quoteNumber];

    $("#quote").html(randomQuote.quote);
    $("#author").html(randomQuote.author);
    $("#quote-box").removeClass().addClass("animated bounceIn").one('webkitAnimationEnd mozAnimationEnd MSAnimationEnd oanimationend animationend', function() {
      $(this).removeClass();
    });

    $("#share").attr("href", "https://twitter.com/intent/tweet?text=\"" + encodeURIComponent($("#hidden").html(randomQuote.quote).text()) + "\" https://igalafacts.igaladigital.org?q=" + quoteNumber);
  }

  function getRandomQuoteNumber() {
    return Math.floor(Math.random() * quotes.length);
  }

  var quotes = [{"author": "IgalaDigital", "quote": "Did You Know That Ojaina is the place where the Attah's of Igala are burried?"},
{"author": "IgalaDigital", "quote": "Did You Know That the first aircraft that visited the Igala Kingdom landed at Idah in 1955?"},
{"author": "IgalaDigital", "quote": "Did You Know That Attah Ameh Oboni, had seen to the completion of an aerodrome in 1954 at Idah?"},

  {"author": "Ilemona", "quote": "Did you know that the Igala alphabet was adopted from the English alphabet. The latter has five (5) vowels: “a,” “e,” “i,” “o,” “u.”?"},
{"author": "Achimugu Ilemona", "quote": "Did you know the Igala alphabet is made up of thirty-one (31) letters: some vowels, others consonants?"},
{"author": "IgalaDigital", "quote": "Did You Know That Ojaina is a restricted place only allowed for members from the Attah Ruling House?"},
{"author": "IgalaDigital", "quote": "Did you know that Ata Ameh Oboni speak fluently in Igala, Ebira & Hausa?"},
{"author": "Onuche Joseph", "quote": "Did you know that the Ígálá language has seven (7) vowels: “a,” “e,” “ẹ,” “i,” “o,” “ọ,” “u” (encompassing both all the 5 English vowels and two indigenous ones, ‘ẹ’ and  ‘ọ’).?"},

  {"author": "Naomi", "quote": "Did You Know That Idah is also called Idah Alu Ogo Oja Abutu Eje?"},

  {"author": "Inikpi", "quote": "Did you know that Abutu- Eje was the first Igala Ruler?"},
{"author": "IgalaDigital", "quote": "Did you know that you may likely come home to meet one of your family member dead if you kill an animal at Ojaina?"},
{"author": "IgalaDigital", "quote": "Did you know that ata Ameh Oboni took his own life on the night of June 26, 1956?"},
{"author": "IgalaDigital", "quote": "Did you know that the mighty Ata Ameh Oboni died at the age of 51?"},
{"author": "IgalaDigital", "quote": "Did you know that attah Ameh Oboni schooled in Okene(Ebira Land) between 1934 and 1939? Learned in Hausa Literature"},
{"author": "IgalaDigital", "quote": "Did you know that ata Ameh Oboni started off as a market stall tax collector for Idah and Ejule market?"},
{"author": "IgalaDigital", "quote": "Did you know that Ata Obaje Ocheje moved Ameh Oboni from being a market stall tax collector to be come a cheif as onu ugwolawo due to his hard work?"},
{"author": "IgalaDigital", "quote": "Did you know that Ameh Oboni was moved to ankpa from ugwolawo as the judge, commonly known as *Wakali, to be in charge of seven districts?"},
{"author": "IgalaDigital", "quote": "Did you know that Patrick A. Okpanachi, Mallam Garba and Peter Achimugwu were the first in Igala Land that speaks and write in English Language?"},
{"author": "IgalaDigital", "quote": "Did you know that Peter Achimugwu was the man that led the campaign to remove Ameh Oboni as the Attah?"}
]

This is just basic JavaScript, if you have no idea what all this means, you should get JavaScript Teacher’s Grammar JavaScript book. This will teach you all the basics and contents of Modern JavaScript. Get a free copy here

Now you should have a functioning app with the facts showing.

Functioning App

Let’s Turn it to a PWA

The three basic criteria for a PWA:

  • Web Manifest

The web app manifest is a JSON file that tells the browser about your Progressive Web App and how it should behave when installed on the user’s desktop or mobile device. A typical manifest file includes the app name, the icons the app should use, and the URL that should be opened when the app is launched.

  • Service Worker
    A service worker is a script that allows your browser to run in the background, separate from a web page, opening the door to features that don’t need a web page or user interaction. Today, they already include features like push notifications and background sync.

  • Icons
    These icons control your application and are provided in different sizes for different devices. Your PWA app will not work without them.

Now let’s get started.

Before we proceed, ensure you’re using a live server
Use (Web server for Chrome, or VSCode Live Server

Create the following files:

sw.js (In root directory)

manifest.json (In root directory)

img/icons (Where we’d store our icons

First, we need to check if the browser supports service workers and register a new one.

In js/app.js add

if ('serviceWorker' in navigator) {
  window.addEventListener('load', () => {
   navigator.serviceWorker.register('../sw.js').then( () => {
    console.log('Service Worker Registered')
   })
 })
}

Dev Tool

Dev Tool

Your final app.js should look like this

$(document).ready(function () {  
    $("#next-quote").on("click", function (e) {
      e.preventDefault();

      var randomQuoteNumber = getRandomQuoteNumber();
      updateQuote(randomQuoteNumber);
    });

    var q = location.search.split("?q=")[1];

    if (q >= 0 && q < quotes.length) {
      updateQuote(q);
    } else {
      $("#next-quote").click();
    }
  });

  function updateQuote(quoteNumber) {
    var randomQuote = quotes[quoteNumber];

    $("#quote").html(randomQuote.quote);
    $("#author").html(randomQuote.author);
    $("#quote-box").removeClass().addClass("animated bounceIn").one('webkitAnimationEnd mozAnimationEnd MSAnimationEnd oanimationend animationend', function() {
      $(this).removeClass();
    });

    $("#share").attr("href", "https://twitter.com/intent/tweet?text=\"" + encodeURIComponent($("#hidden").html(randomQuote.quote).text()) + "\" https://igalafacts.igaladigital.org?q=" + quoteNumber);
  }

  function getRandomQuoteNumber() {
    return Math.floor(Math.random() * quotes.length);
  }

  var quotes = [{"author": "IgalaDigital", "quote": "Did You Know That Ojaina is the place where the Attah's of Igala are burried?"},
{"author": "IgalaDigital", "quote": "Did You Know That the first aircraft that visited the Igala Kingdom landed at Idah in 1955?"},
{"author": "IgalaDigital", "quote": "Did You Know That Attah Ameh Oboni, had seen to the completion of an aerodrome in 1954 at Idah?"},

  {"author": "Ilemona", "quote": "Did you know that the Igala alphabet was adopted from the English alphabet. The latter has five (5) vowels: “a,” “e,” “i,” “o,” “u.”?"},
{"author": "Achimugu Ilemona", "quote": "Did you know the Igala alphabet is made up of thirty-one (31) letters: some vowels, others consonants?"},
{"author": "IgalaDigital", "quote": "Did You Know That Ojaina is a restricted place only allowed for members from the Attah Ruling House?"},
{"author": "IgalaDigital", "quote": "Did you know that Ata Ameh Oboni speak fluently in Igala, Ebira & Hausa?"},
{"author": "Onuche Joseph", "quote": "Did you know that the Ígálá language has seven (7) vowels: “a,” “e,” “ẹ,” “i,” “o,” “ọ,” “u” (encompassing both all the 5 English vowels and two indigenous ones, ‘ẹ’ and  ‘ọ’).?"},

  {"author": "Naomi", "quote": "Did You Know That Idah is also called Idah Alu Ogo Oja Abutu Eje?"},

  {"author": "Inikpi", "quote": "Did you know that Abutu- Eje was the first Igala Ruler?"},
{"author": "IgalaDigital", "quote": "Did you know that you may likely come home to meet one of your family member dead if you kill an animal at Ojaina?"},
{"author": "IgalaDigital", "quote": "Did you know that ata Ameh Oboni took his own life on the night of June 26, 1956?"},
{"author": "IgalaDigital", "quote": "Did you know that the mighty Ata Ameh Oboni died at the age of 51?"},
{"author": "IgalaDigital", "quote": "Did you know that attah Ameh Oboni schooled in Okene(Ebira Land) between 1934 and 1939? Learned in Hausa Literature"},
{"author": "IgalaDigital", "quote": "Did you know that ata Ameh Oboni started off as a market stall tax collector for Idah and Ejule market?"},
{"author": "IgalaDigital", "quote": "Did you know that Ata Obaje Ocheje moved Ameh Oboni from being a market stall tax collector to be come a cheif as onu ugwolawo due to his hard work?"},
{"author": "IgalaDigital", "quote": "Did you know that Ameh Oboni was moved to ankpa from ugwolawo as the judge, commonly known as *Wakali, to be in charge of seven districts?"},
{"author": "IgalaDigital", "quote": "Did you know that Patrick A. Okpanachi, Mallam Garba and Peter Achimugwu were the first in Igala Land that speaks and write in English Language?"},
{"author": "IgalaDigital", "quote": "Did you know that Peter Achimugwu was the man that led the campaign to remove Ameh Oboni as the Attah?"}
]
if ('serviceWorker' in navigator) {
  window.addEventListener('load', () => {
   navigator.serviceWorker.register('../sw.js').then( () => {
    console.log('Service Worker Registered')
   })
 })
}

We’re going to use the Workbox library to power our service worker

Workbox is a set of libraries and Node modules developed by Google that make it easy to cache assets and take full advantage of features used to build Progressive Web Apps.

The idea of our service worker is to cache all files (Fonts, JavaScript, CSS, Images, e.t.c) so we can access them offline after the page loads.

The important thing to understand about the Service Worker is that you are in control of the network. You get to decide what is cached, how it is cached, and how it should be returned to the user.

— In sw.js add this:

importScripts('https://storage.googleapis.com/workbox-cdn/releases/4.3.1/workbox-sw.js');
if (workbox) {
    console.log("Yay! Workbox is loaded !");
    workbox.precaching.precacheAndRoute([]);
/*  cache images in the e.g others folder; edit to other folders you got
   and config in the sw-config.js file
    */
    workbox.routing.registerRoute(
        /(.*)others(.*)\.(?:png|gif|jpg)/,
        new workbox.strategies.CacheFirst({
            cacheName: "images",
            plugins: [
                new workbox.expiration.Plugin({
                    maxEntries: 50,
                    maxAgeSeconds: 30 * 24 * 60 * 60, // 30 Days
                })
            ]
        })
    );
    /* Make your JS and CSS âš¡ fast by returning the assets from the cache,
  while making sure they are updated in the background for the next use.
  */
    workbox.routing.registerRoute(
    // cache js, css, scc files
        /.*\.(?:css|js|scss|)/,
        // use cache but update in the background ASAP
        new workbox.strategies.StaleWhileRevalidate({
            // use a custom cache name
            cacheName: "assets",
        })
    );
// cache google fonts
    workbox.routing.registerRoute(
        new RegExp("https://fonts.(?:googleapis|gstatic).com/(.*)"),
        new workbox.strategies.CacheFirst({
            cacheName: "google-fonts",
            plugins: [
                new workbox.cacheableResponse.Plugin({
                    statuses: [0, 200],
                }),
            ],
        })
    );
// add offline analytics
    workbox.googleAnalytics.initialize();
/* Install a new service worker and have it update
and control a web page as soon as possible
*/
workbox.core.skipWaiting();
    workbox.core.clientsClaim();
} else {
    console.log("Oops! Workbox didn't load 👺");
}

Now our service worker works and would cache files once the page loads.

Now let’s make our app installable.

— Add this in manifest.json

{
    "name": "Igala Facts",
    "short_name": "Igala Facts",
    "icons": [
      {
        "src": "img/icons/icon-72x72.png",
        "sizes": "72x72",
        "type": "image/png"
      },
      {
        "src": "img/icons/icon-96x96.png",
        "sizes": "96x96",
        "type": "image/png"
      },
      {
        "src": "img/icons/icon-128x128.png",
        "sizes": "128x128",
        "type": "image/png"
      },
      {
        "src": "img/icons/icon-144x144.png",
        "sizes": "144x144",
        "type": "image/png"
      },
      {
        "src": "img/icons/icon-152x152.png",
        "sizes": "152x152",
        "type": "image/png"
      },
      {
        "src": "img/icons/icon-192x192.png",
        "sizes": "192x192",
        "type": "image/png"
      },
      {
        "src": "img/icons/icon-384x384.png",
        "sizes": "384x384",
        "type": "image/png"
      },
      {
        "src": "img/icons/icon-512x512.png",
        "sizes": "512x512",
        "type": "image/png"
      }
    ],
    "start_url": "/index.html",
    "display": "standalone",
    "background_color": "#000",
    "theme_color": "#ffff00"
  }

Your PWA Icons sizes should be in px and in the following sizes: 72x72 , 96x96 , 128x128 , 144x144 , 152x152 , 192x192 , 384x384 , 512x512
You can use the Web Manifest Generator to generate your manifest.json

Manifest in Dev tools

Now we need to connect our web app to the manifest to allow “add to home screen” from that page. Add this to your index.html

<link rel="manifest" href="/manifest.json" />
<meta name="theme-color" content="#333" />

If you have multiple pages, you need to add this to all of them.
You can also use the same theme-color you used in manifest.json here

Now your final index.html should look like this

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>The Igala Facts you never knew</title>
    <link rel="stylesheet" href="css/style.css">
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.5.0/css/font-awesome.min.css">
    <link href='https://fonts.googleapis.com/css?family=Roboto+Slab:400,700' rel='stylesheet' type='text/css'>
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css">
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/3.2.3/animate.min.css">
    <link rel="manifest" href="manifest.json" />
  <meta name="theme-color" content="yellow" />
</head>
<body>
    <div class="container">
        <div class="row">
          <div class="col-sm-6">
            <h1><span class="main-color">Random Igala</span><br />Facts</h1>
            <p>The best facts about Igala in one place. You can easily see the best facts and  share the ones you love on twitter with one click.</p>
          </div>
          <div class="col-sm-6">
            <div class="row">
              <div class="col-xs-6">
                <a id="next-quote" class="btn btn-lg btn-default btn-block" href="#"><i class="fa fa-refresh"></i> Next Fact</a>
              </div>
              <div class="col-xs-6">
                <a id="share" class="btn btn-lg btn-default btn-block" href="#" target="_top"><i class="fa fa-twitter"></i> Share</a>
              </div>
            </div>

            <div id="quote-box">
              <i id="quote-left" class="fa fa-quote-left"></i>
              <p id="quote"></p>
              <span id="author" class="main-color"></span>
              <i id="quote-right" class="fa fa-quote-right"></i>
            </div>

            <div class="row">       
              <div class="col-xs-12">
                <ul>
                  <li>Follow Us</li>
                  <li><a class="main-color" href="https://facebook.com/theigaladigital" target="_blank">@theigaladigital</a></li>
                    </ul>
                  </div>
              </div>
            </div>
          </div>
        </div>
      </div>

      <div id="hidden"></div>
      <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
      <script src="js/app.js"></script>
</body>
</html>

Congratulations, you’ve successfully turned your website to a Progressive Web App.

Conclusion

Throughout this article, we have seen how simple and fast it is to build a PWA by adding a manifest file and a service worker, it increases a lot the user experience of our traditional web app. Because PWAs are fast, secure, reliable and the most important, they support offline mode.

Many frameworks out there comes now with a service worker file already set-up for us, however, knowing how to implement it with Vanilla JavaScript can help you understand PWAs.

P.S: If you ran into issues or problem, it’s probably a problem with HTTPS. PWA doesn’t work on HTTP, so make sure you’re running this with either http-server or live-server if you’re working from your local machine

Thank you for reading!

Follow me on Twitter or Facebook I’m everywhere @dfiredeveloper

Discussion

pic
Editor guide
Collapse
criticalwill profile image
CriticalWill

Thanks for the well written, great article and explanation! I had no idea it was that simple!

Collapse
dfiredeveloper profile image
Ilemona Achimugu Author

I'm glad you found it helpful 😊

Collapse
alliwalk profile image
Allison Walker

Do you think this is overkill for static websites?

Collapse
raja_anbazhagan profile image
Raja Anbazhagan

This is subject to use case of the website. But I have used PWA in the past for static websites to have a custom offline pages.

Collapse
alliwalk profile image
Allison Walker

How would a custom offline page be different from the site with regular connectivity? Do you have an example?

Thread Thread
raja_anbazhagan profile image
Raja Anbazhagan

dev.to website itself uses pwa for its offline pages. Go offline and check it out yourself.

here is a screenshot

Thread Thread
alliwalk profile image
Allison Walker

dev.to isn't a static website. You said you built a custom offline page for a static website so I was asking for an example.

Collapse
hayatu89 profile image
Hayatu Mohammed

Great article. This is a better guide than the one I read on Google

Collapse
dfiredeveloper profile image
Ilemona Achimugu Author

Thanks, I'm glad you found this helpful

Collapse
joeyd473 profile image
Joey

This may be the best intro to PWA that I've seen

Collapse
wassimbj profile image
Wassim

Great article, i think this is just ready for u to use in React.js apps no ?

Collapse
dfiredeveloper profile image
Collapse
emmanueloreva12 profile image
emmanueloreva

Thank you so much for this, I didn't know it was this easy as have always wanted to use a PWA for a site I built

Collapse
yeahch profile image
C & H

Great explanation for PWA.
and I want to introduce about serviceworker-rails in this opportunity.

Collapse
dfiredeveloper profile image
Collapse
cvieira850 profile image
cvieira850

Thanks for the explanation!

Collapse
dfiredeveloper profile image
Ilemona Achimugu Author

Thank you 😊

Collapse
milg15 profile image
Maria Isabel Lopez

Thanks!! I always deleted the ServiceWorker file from my react project but I'm happy to know what it does now. Great explanation!

Collapse
dfiredeveloper profile image
Collapse
steevn profile image
steevn

Great article and thanks for the explanation!