How to build a Progressive Web App that works offline for a software project documentation.

Introduction

A Progressive Web App (PWA) is a type of web application that offers the same experience as a native mobile application but is built using web technologies. PWAs are designed to work across different platforms and devices, and they can be installed on the user's device and accessed from the home screen, just like a native app. In this tutorial, we will walk you through the process of building a PWA that works even when offline, specifically for the documentation of software project.

Set Up a New Project

To get started, you will need to create a new project directory and initialize it with npm. You can do this by opening a terminal and running the following commands:

mkdir my-pwa-app
cd my-pwa-app
npm init -y

This will create a new project directory called my-pwa-app and initialize it with a package.json file.

Install the Required Dependencies

To build a PWA, you will need to install a few dependencies. Specifically, you will need to install express, compression, and pwa-asset-generator. You can install these dependencies by running the following command:

npm install express compression pwa-asset-generator --save

These dependencies will provide the necessary tools for building and serving your PWA.

Create a Server and Build the App

Next, you will need to create a server to serve your PWA. You can create a file called server.js in the root directory of your project, and add the following code:

const express = require('express');
const compression = require('compression');
const app = express();

app.use(compression());
app.use(express.static('public'));

const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
  console.log(`Server started on port ${PORT}`);
});

This code sets up a server using the express framework and serves the files in the public directory. The compression middleware is used to compress the response data, which improves the performance of your app.

Next, you will need to create the public directory and add the necessary files for your PWA. Specifically, you will need to create a manifest.json file and an icon file for your app. You can use the pwa-asset-generator package to generate the icon files in different sizes. You can run the following command to generate the icons:

npx pwa-asset-generator logo.png public/icons

This command will generate icon files in different sizes and save them in the public/icons directory.

Finally, you can create a index.html file in the public directory and add the necessary HTML and JavaScript code to create your PWA. For example, you can add the following code to create a simple PWA that displays documentation of your software:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>My PWA App</title>
    <link rel="manifest" href="/manifest.json" />
    <link rel="icon" type="image/png" href="/icons/icon-192x192.png" sizes="192x192" />
  </head>
  <body>
    <h1>Documentation of My Software</h1>
    <p>This is the documentation of my software.</p>
    <script>
      if ('serviceWorker' in navigator) {
        window.addEventListener('load', () => {
          navigator.serviceWorker.register('/service-worker.js').then((reg) => { });
        });
      }
    </script>
  </body>
</html>

Add the service worker to the manifest.json file

You will type this code into the manifest.json file, what this does is create a service worker file required for the PWA to function.

{
  "name": "My PWA App",
  "short_name": "My PWA App",
  "start_url": "/",
  "display": "standalone",
  "background_color": "#fff",
  "theme_color": "#3f51b5",
  "description": "This is my PWA app.",
  "icons": [
    {
      "src": "/icons/icon-72x72.png",
      "sizes": "72x72",
      "type": "image/png"
    },
    {
      "src": "/icons/icon-96x96.png",
      "sizes": "96x96",
      "type": "image/png"
    },
    {
      "src": "/icons/icon-128x128.png",
      "sizes": "128x128",
      "type": "image/png"
    },
    {
      "src": "/icons/icon-144x144.png",
      "sizes": "144x144",
      "type": "image/png"
    },
    {
      "src": "/icons/icon-152x152.png",
      "sizes": "152x152",
      "type": "image/png"
    },
    {
      "src": "/icons/icon-192x192.png",
      "sizes": "192x192",
      "type": "image/png"
    },
    {
      "src": "/icons/icon-384x384.png",
      "sizes": "384x384",
      "type": "image/png"
    },
    {
      "src": "/icons/icon-512x512.png",
      "sizes": "512x512",
      "type": "image/png"
    }
  ],
  "serviceworker": {
    "src": "/service-worker.js",
    "scope":"/",
    "use_cache": true
  }
}

Step 4: Add the service worker to the index.html file

You will add this code to the HTML file, preferably in the head section or after the body section closes toward the closing HTML tag.

<script>
  if ('serviceWorker' in navigator) {
    window.addEventListener('load', function() {
      navigator.serviceWorker.register('/service-worker.js').then(function(registration) {
        // Registration was successful
        console.log('ServiceWorker registration successful with scope: ', registration.scope);
      }, function(err) {
        // registration failed :(
        console.log('ServiceWorker registration failed: ', err);
      });
    });
  }
</script>

Add the service-worker.js file

self.addEventListener('install', function(event) {
  event.waitUntil(
    caches.open('v1').then(function(cache) {
      return cache.addAll([
        '/',
        '/index.html',
        '/restaurant.html',
        '/css/styles.css',
        '/js/dbhelper.js',
        '/js/main.js',
        '/js/restaurant_info.js',
        '/data/restaurants.json',
        '/img/1.jpg',
        '/img/2.jpg',
        '/img/3.jpg',
        '/img/4.jpg',
        '/img/5.jpg',
        '/img/6.jpg',
        '/img/7.jpg',
        '/img/8.jpg',
        '/img/9.jpg',
        '/img/10.jpg'
      ]);
    })
  );
});

self.addEventListener('fetch', function(event) {
  event.respondWith(
    caches.match(event.request).then(function(response) {
      return response || fetch(event.request);
    })
  );
});

Add the Service Worker to the index.html File

To add the service worker to your PWA, you will need to register it in the index.html file. Open the index.html file in your text editor and add the following code to the bottom of the file:

<script>
  if ('serviceWorker' in navigator) {
    window.addEventListener('load', function() {
      navigator.serviceWorker.register('/sw.js').then(function(registration) {
        console.log('ServiceWorker registration successful with scope: ', registration.scope);
      }, function(err) {
        console.log('ServiceWorker registration failed: ', err);
      });
    });
  }
</script>

This code checks if the navigator.serviceWorker API is available and registers the sw.js file as the service worker for your PWA. If registration is successful, the code logs a message to the console.

Test Your PWA with the Service Worker

You can now test your PWA by running the server and accessing it from your browser. Open a terminal and run the following command to start the server:

node server.js

This will start the server and you can access your PWA by opening a browser and navigating to http://localhost:3000/.

When it loads in the browser and is visible at the above address; follow these steps

  1. In your browser toggle/navigate to the network tab in the developer tools.

  2. Reload the page and verify that all the assets are loaded from the network.

  3. Turn off your network connection and reload the page.

  4. Verify that the page still loads and that the assets are served from the cache.

If the PWA loads and the assets are served from the cache, then the service worker is working correctly.

Create New Pages

To create new pages in your PWA, you will need to add additional HTML and JavaScript code to your index.html file. Specifically, you will need to add links to navigate to the new pages and JavaScript code to handle the navigation.

First, create a new HTML file for each page you want to create. For example, you could create a file called about.html in the public directory. Add the following HTML code to the file:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>About Us</title>
    <link rel="manifest" href="/manifest.json" />
    <link rel="icon" type="image/png" href="/icons/icon-192x192.png" sizes="192x192" />
  </head>
  <body>
    <h1>About Us</h1>
    <p>We are a software development company.</p>
    <script src="/js/app.js"></script>
  </body>
</html>

This code sets up the basic structure for the about.html page and includes the necessary links to the manifest.json file and icon file.

Next, add a link to the about.html page in the index.html file. For example, you could add the following code to the index.html file:

<a href="/about.html">About Us</a>

This code creates a link to the about.html page.

Finally, you will need to add JavaScript code to handle the navigation between pages. Add the following code to a new file called app.js in the public/js directory:

(function () {
  'use strict';

  var app = {
    isLoading: true,
    visibleCards: {},
    selectedCities: [],
    spinner: document.querySelector('.loader')
  };

  document.getElementById('nav').addEventListener('click', function (event) {
    event.preventDefault();
    if (event.target.getAttribute('href') === '/about.html') {
      app.showAboutPage();
    }
  });

  app.showAboutPage = function () {
    var aboutPage = document.getElementById('about-page');
    aboutPage.classList.remove('hidden');
  };
})();

This code sets up a click event listener on the navigation links and handles the navigation to the about.html page by showing the about-page element.

Publish Your PWA

Once you have built and tested your PWA, you can publish it to a hosting service. There are several hosting services that support PWAs, including Firebase Hosting and Netlify. To publish your PWA, follow these steps:

  1. Create an account with a hosting service that supports PWAs.(I prefer Vercel)

  2. Follow the hosting service's instructions for deploying your PWA.

  3. Test your PWA on the hosting service to make sure it works correctly.

Conclusion

In this tutorial, I have shown you how to build a Progressive Web App that works even when offline, specifically for the documentation of software. We have covered the steps for building a new project, installing the necessary dependencies, creating a server and building your app, adding new pages to your PWA, adding a service worker, and testing and publishing your PWA. By following these steps, you can create a PWA that provides a native app-like experience for your users, while still being accessible from the web.

Did you find this article valuable?

Support Were Samson Bruno by becoming a sponsor. Any amount is appreciated!