DEV Community

Cover image for How to Make a Progressive Web App
Prince Gupta
Prince Gupta

Posted on • Edited on • Originally published at Medium

How to Make a Progressive Web App

No matter if you’re a pro developer or just starting, you might have heard about this topic. If not, don’t worry! After reading this blog, you’ll know all you need to make a PWA. Even if you’re just curious, get ready to learn a lot about PWAs. So, let’s start this fun learning journey!

the quickest definition for the people who are absolute beginners

How to identify if the website is a pwa

you must have saw this install option for the web apps on your computers and phones, the websites which have this option available is simply a PWA.

First, let’s take a quick trip down memory lane. The term “Progressive Web Apps” or PWAs was first used in 2015 by Frances Berriman and Alex Russell from Google. They used it to describe apps that could use new features from modern browsers. This meant that web apps could be upgraded to PWAs on your device, just like regular apps.


Now, let’s talk about why you’d want to make your web app a PWA. Here are some cool things about PWAs:

  1. Feels Like a Regular App: PWAs feel just like the apps you’re used to on your device.

  2. Easy to Install: You can add PWAs to your device’s home screen, just like a regular app. No need to go to an app store, and it saves space.

  3. Fast and Smooth: PWAs are known for being quick and working well, better than traditional web apps.

  4. Works Everywhere: PWAs are made with standard web technologies, so they can work on many different devices from one set of code.

  5. Works Offline: PWAs can work even when your device is not connected to the internet.

  6. Always Up-to-Date: PWAs update in the background, so you always have the latest version.

  7. Can Send Notifications: Just like regular apps, PWAs can send you notifications to keep you updated.

  8. No Need for App Stores: You can access PWAs directly from the web, no need to go through an app store.

  9. Safe and Secure: PWAs use secure web protocols to keep your data safe.

  10. Saves Time and Money: With PWAs, you don’t need to make separate apps for different platforms, which saves time and money.


The only thing is, your users have to click the Install button on their browser to add the PWA to their device. But don’t worry, you can also put your PWA on the Google Play Store, App Store, or Windows Store. So, if your user isn’t tech-savvy, they won’t even know it’s a website.

You have to learn more to enable it uploadable on the platforms

Watch this video on Trusted Web Activity ( TWA ) by Chrome for Developers


How to make your Website / Web App a PWA ??

So, to make the process buttery smooth. I will recommend you to install this extension on VSCode.

It is a very good extension ( trust me.. )

Manifest.json

make a manifest.json on the public folder of your app. Please see the image to see the illustration to see how to do it via the extension.

Open the extension you’ll see this pane on your screen

![pwa studio builder home page(https://dev-to-uploads.s3.amazonaws.com/uploads/articles/u9f5uiipltadpixa8kel.png)

Now just click on the Generate a Web manifest and it will generate one for you.

Now save the file into the public folder of your code and edit the fields ( you will get the directions on the file itself )

for example :

example of mainfest.json file

Now if you will go the the browser dev tools and check, you can see this on the your manifest section ( You can go to the Application section by inspecting ).

Application Manifest

Service Worker

Now It is the time to generate a service worker. You can choose to generate a basic and a advanced one via the extension. ( Save it in the root directory of your app ).

The basic one looks like this 👇

const HOSTNAME_WHITELIST = [
        self.location.hostname,
        'fonts.gstatic.com',
        'fonts.googleapis.com',
        'cdn.jsdelivr.net'
    ]

    // The Util Function to hack URLs of intercepted requests
    const getFixedUrl = (req) => {
        var now = Date.now()
        var url = new URL(req.url)

        // 1. fixed http URL
        // Just keep syncing with location.protocol
        // fetch(httpURL) belongs to active mixed content.
        // And fetch(httpRequest) is not supported yet.
        url.protocol = self.location.protocol

        // 2. add query for caching-busting.
        // Github Pages served with Cache-Control: max-age=600
        // max-age on mutable content is error-prone, with SW life of bugs can even extend.
        // Until cache mode of Fetch API landed, we have to workaround cache-busting with query string.
        // Cache-Control-Bug: https://bugs.chromium.org/p/chromium/issues/detail?id=453190
        if (url.hostname === self.location.hostname) {
            url.search += (url.search ? '&' : '?') + 'cache-bust=' + now
        }
        return url.href
    }

    /**
     *  @Lifecycle Activate
     *  New one activated when old isnt being used.
     *
     *  waitUntil(): activating ====> activated
     */
    self.addEventListener('activate', event => {
      event.waitUntil(self.clients.claim())
    })

    /**
     *  @Functional Fetch
     *  All network requests are being intercepted here.
     *
     *  void respondWith(Promise<Response> r)
     */
    self.addEventListener('fetch', event => {
    // Skip some of cross-origin requests, like those for Google Analytics.
    if (HOSTNAME_WHITELIST.indexOf(new URL(event.request.url).hostname) > -1) {
        // Stale-while-revalidate
        // similar to HTTP's stale-while-revalidate: https://www.mnot.net/blog/2007/12/12/stale
        // Upgrade from Jake's to Surma's: https://gist.github.com/surma/eb441223daaedf880801ad80006389f1
        const cached = caches.match(event.request)
        const fixedUrl = getFixedUrl(event.request)
        const fetched = fetch(fixedUrl, { cache: 'no-store' })
        const fetchedCopy = fetched.then(resp => resp.clone())

        // Call respondWith() with whatever we get first.
        // If the fetch fails (e.g disconnected), wait for the cache.
        // If there’s nothing in cache, wait for the fetch.
        // If neither yields a response, return offline pages.
        event.respondWith(
        Promise.race([fetched.catch(_ => cached), cached])
            .then(resp => resp || fetched)
            .catch(_ => { /* eat any errors */ })
        )

        // Update the cache with the version we fetched (only for ok status)
        event.waitUntil(
        Promise.all([fetchedCopy, caches.open("pwa-cache")])
            .then(([response, cache]) => response.ok && cache.put(event.request, response))
            .catch(_ => { /* eat any errors */ })
        )
    }
    })
Enter fullscreen mode Exit fullscreen mode

What this code is doing ??

  1. HOSTNAME_WHITELIST: This is a list of hostnames that the service worker should manage. If a network request is made to a hostname not in this list, the service worker will not intercept the request.

  2. getFixedUrl: This function takes a request as input and returns a URL with the same protocol as the current location and a cache-busting query parameter.

  3. activate event listener: This code listens for the ‘activate’ event, which is fired when the service worker starts. The self.clients.claim() line makes this service worker take control of all pages in its scope as soon as it’s activated.

  4. fetch event listener: This code listens for the ‘fetch’ event, which is fired every time a network request is made. If the request’s hostname is in the whitelist, the service worker will try to respond with a cached response, fetch a new response from the network, or return an offline page if both fail.

Now, moving to the advanced one 🏃

The extension will install a package workbox-precaching for you

If you want learn more about the workbox and the things you can achieve with it. consider visiting the chrome’s developer docs on workbox by clicking here

Code of the file 👇

import { precacheAndRoute } from 'workbox-precaching/precacheAndRoute';
  precacheAndRoute([]);
Enter fullscreen mode Exit fullscreen mode

Here’s what the code does:

  1. import { precacheAndRoute } from 'workbox-precaching/precacheAndRoute';: This line imports the precacheAndRoute function from the workbox-precaching module.

  2. precacheAndRoute([]);: This function call sets up a service worker to precache resources. The array passed to precacheAndRoute would normally contain a list of URLs to precache, but it’s empty in this case.

The precacheAndRoute function does two things:

NOTE : Whether you use the basic one or the advanced one you can tailor the code easily based on your needs. and you can do so much things with the service worker.**

Now to check if the service-worker is running properly, go the application section of the dev tools click of the service worker, you’ll see something like this 👇

I have used a random website for showing this

for testing it you can click on the offline tab on top to see whether the service workers are working or not.

we made the website offline by revoking the internet access

So let’s see what guys are doing via service worker on this website

website when we are online
website when we are online

website when we are offline
website when we are offline


Here’s a quick reminder for you guys. Really sorry for interrupting the experience. if you are enjoying blog please consider clicking on the like button. ( pleaseeeee :) )


Things OYO made better by making their website a PWA and Pushing it as OYO Lite as a TWA ( Now you have to learn more don’t worry it is more like a branch of PWA ).

TWA (Trusted Web Activity ):

  • TWAs are a way to open your PWA or web content in a full-screen mode from an Android app, without any browser UI.

  • TWAs make it possible to distribute your PWA via the Google Play Store.

  • A TWA is essentially a Chrome browser window without its own graphic interface (like the URL bar and menu), operating in a trusted mode.

  • TWAs are specific to Android devices.

In summary, while PWAs and TWAs share some similarities, they are used for different purposes. A PWA is a web app that provides an app-like experience, while a TWA is a way to deliver your PWA or web content in a full-screen mode within an Android app.

So back to How a TWA helped OYO meet the needs of its users :

By strategically storing the majority of their app assets in Chrome’s cache, the OYO team managed to slim down the initial download size of OYO Lite to a mere 850 KB.

That’s a whopping 93% smaller than their Android app!

This compact size, coupled with the convenience of being downloadable from the Google Play Store, resulted in a significant boost in user engagement.

The conversion rate was triple that of the PWA’s rate, and on average, there were three times more logged-in users than the PWA. Plus, it earned a commendable 4.1 rating on the Google Play Store.

But the benefits weren’t just for the users. Opting for a TWA also meant that the team had to maintain only a single codebase. This allowed them to roll out updates seamlessly, without having to wait for users to download the latest version of the app.


So let’s end this here, these were the benefits and the steps to make your web app a banger with PWA. You can do more with it. whether it is creating better experience for the users, reminding them to buy the products they added to the cart or anything else. It can turn out to be a plus for your business.


I hope this blog has sparked your curiosity and equipped you with the knowledge to start your own PWA journey. Remember, the road to mastery is always under construction. Keep learning, keep experimenting, and most importantly, have fun along the way! 😊


Didn’t liked something or want to give me the feedback on how can I improve, just fill out this form.

Discover Typeform, where forms = fun

Create a beautiful, interactive form in minutes with no code. Get started for free.

favicon typeform.com

Top comments (0)