How to build Progressive Web App (PWA)?

A Progressive Web App (PWA) is a type of application software that's designed to work on any platform with a standards-compliant browser, including desktop and mobile devices. It's built using common web technologies including HTML, CSS, JavaScript.


PWAs look and feel like a normal app that you'd download to your phone, tablet or desktop, but they're accessed through your browser. They combine the best features of traditional websites and platform-specific apps.


In this guide, we will learn how to build a Progressive Web App (PWA) for Laravel 10, PWA works with all type of websites but i prefer to use laravel, Ill be using my custom folder structure, You can use default structure but just make sure you know your files location which we will create, So lets get started.

Step 1 : Make Service Worker

This code is for a service worker that handles caching and fetching of resources for a Progressive Web App (PWA), providing offline functionality. It preloads certain files into the cache when the service worker is installed, tries to fetch requests from the network, falls back to cached responses if the network fails, and adds non-HTTP requests to the cache.


We will create a service worker js in : public/pwa/sw.js

// Function to preload files into cache
const preLoad = function () {
    // Open a cache named "offline"
    return caches.open("offline").then(function (cache) {
        // Add all files in 'filesToCache' to the cache
        return cache.addAll(filesToCache);
    });
};

// Add an event listener for the install event
self.addEventListener("install", function (event) {
    // Wait until the 'preLoad' function has completed
    event.waitUntil(preLoad());
});

// List of files to cache
const filesToCache = [
    '/',
    '/offline.html'
];

// Function to check the response of a fetch request
const checkResponse = function (request) {
    // Return a new promise
    return new Promise(function (fulfill, reject) {
        // Fetch the request
        fetch(request).then(function (response) {
            // If the response status is not 404, fulfill the promise
            if (response.status !== 404) {
                fulfill(response);
            } else {
                // Otherwise, reject the promise
                reject();
            }
        }, reject);
    });
};

// Function to add a request to the cache
const addToCache = function (request) {
    // Open the "offline" cache
    return caches.open("offline").then(function (cache) {
        // Fetch the request and then add the request/response pair to the cache
        return fetch(request).then(function (response) {
            return cache.put(request, response);
        });
    });
};

// Function to return a response from the cache
const returnFromCache = function (request) {
    // Open the "offline" cache
    return caches.open("offline").then(function (cache) {
        // Try to match the request in the cache
        return cache.match(request).then(function (matching) {
            // If there's no match or the status is 404, return the 'offline.html' response
            if (!matching || matching.status === 404) {
                return cache.match("offline.html");
            } else {
                // Otherwise, return the matching response
                return matching;
            }
        });
    });
};

// Add an event listener for fetch events
self.addEventListener("fetch", function (event) {
    // Try to fetch the request and fall back to the cached response if the fetch fails
    event.respondWith(checkResponse(event.request).catch(function () {
        return returnFromCache(event.request);
    }));
    // If the request URL doesn't start with 'http', add the request to the cache
    if(!event.request.url.startsWith('http')){
        event.waitUntil(addToCache(event.request));
    }
});
Step 2 : Create Manifest File

The web app manifest is a simple JSON file that tells the browser about your web application and how it should behave when installed on the user's device. It includes information like the app's name, icons, start URL, display properties, and more.


Now lets create manifest.json file in : public/pwa/manifest.json

{
    "name": "CODEONSTRING",
    "short_name": "COS",
    "start_url": "../../index.php",
    "background_color": "#6777ef",
    "description": "CODEONSTRING is a friend of developers",
    "display": "fullscreen",
    "theme_color": "#6777ef",
    "icons": [
        {
            "src": "../logo/favicon.png",
            "sizes": "512x512",
            "type": "image/png",
            "purpose": "any maskable"
        }
    ]
}
Step 3 : Create Offline File

In the context of a Progressive Web App (PWA), offline.html is a custom offline page that is displayed when the user is offline.

This page is stored in the browser's offline cache by a service worker. When the user's device does not have network connectivity, the service worker intercepts network requests and responds with the offline.html page.

The content of the offline.html page can vary based on your application's needs. It could be a simple message informing the user that they're offline, or it could provide some basic functionality or information that's useful even without a network connection.


Now lets create offline.html file in : public/pwa/offline.html

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="title" content="InfyBonus">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">

    <style>
        .error_body {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
            height: 100vh;
            width: 100%;
            background: #f9f9f9;
        }

        .error_container .error_heading {
            color: transparent;
            font-size: 160px;
            margin: 0;
            font-weight: 900;
            letter-spacing: 20px;
            background-size: 100% 100%;
            background: linear-gradient(90deg, #6b719b 38%, #9da3cc 53%, #979dce 65%);
            -webkit-background-clip: text;
            -moz-background-clip: text;
            -ms-background-clip: text;
        }

        @media (max-width: 540px) {
            .error_container .error_heading {
                font-size: 120px;
                letter-spacing: 10px;
            }
        }

        .error_container .error_btn {
            background-color: #6e749e !important;
            border: none;
            outline: none;
        }

        .error_container .error_btn:focus {
            box-shadow: none !important;
        }

        .error_container .error_message,
        .error_container .error_paragraph {
            color: #787878;
        }
    </style>
</head>
<body>
<div class="error_body">
    <div
        class="container error_container d-flex justify-content-center align-items-center flex-column w-100 h-100 p-5 text-center">
        <h2 class="error_message text-center mb-3">Boo! You don't have an internet connection</h2>
        <p class="error_paragraph text-center mb-5">
            Please check your network connection and try again.
        </p>
        <a href="/" class="btn btn-primary error_btn">Back to Home Page</a>
    </div>
</div>
</body>
</html>
Step 4 : Publishing

To publish PWA we need to add this scripts to our master file default is app.blade.php

<meta name="theme-color" content="#6777ef"/>
<link rel="apple-touch-icon" href="{{ asset('assets/logo/favicon.png') }}">
<link rel="manifest" href="{{ asset('assets/pwa/manifest.json') }}">

Now we need to register service worker so lets call sw.js so we can register it to our master file, Add this bottom of you page right before end of body tag.

<script src="{{ asset('assets/pwa/sw.js') }}"></script>
<script>
    if (!navigator.serviceWorker.controller) {
        navigator.serviceWorker.register("{{ asset('assets/pwa/sw.js') }}").then(function (reg) {
            console.log("Service worker has been registered for scope: " + reg.scope);
        });
    }
</script>

We are done now you can open your website and If everything works fine you will see a install icon on top in url section and if you dont see install icon, Please checkout console log for the errors.


If you wish to create a custom install button for progressive web app than please check this post.

Subscribe Our Newsletters