DEV Community

Cover image for Make a web app installable in a breeze
Anwar
Anwar

Posted on • Edited on

Make a web app installable in a breeze

Welcome to this tutorial on making your web app installable in a few simple steps.

Summary

 What is a progressive web app?

For a web app to be considered installable, a Progressive Web App (PWA), it must adhere to several criteria:

  • It must define a manifest describing how the app behaves and interacts with the UI.
  • It should register a Service Worker to enable offline browsing.
  • It needs to have a responsive design suitable for small devices.

Other secondary criteria exist, but we'll focus on the essential information here.

 Defining a web manifest

Start by adding a "manifest.json" file to your project's root:

{
  "name": "Dev.to",
  "short_name": "DEV",
  "start_url": "/",
  "display": "standalone",
  "icons": [
    {
      "src": "images/touch/homescreen48.png",
      "sizes": "48x48",
      "type": "image/png"
    }
}
Enter fullscreen mode Exit fullscreen mode
  • The "start_url" determines the URL shown when launching the app.
  • The "display" specifies how the browser renders the UI when launching the app.

Refer to the manifest MDN documentation for a comprehensive list of configuration options..

Include the manifest file in your HTML:

<!DOCTYPE html>
<html>
  <head>
    <!-- ... !-->
    <link rel="manifest" href="manifest.json" />
  </head>
  <body>
    <!-- ... -->
  </body>
</html>
Enter fullscreen mode Exit fullscreen mode

Registering a service worker

Service Workers introduce powerful caching patterns for fine-grained control over how the browser handles requests. Let's implement the simple Network First pattern using Workbox.js.

This pattern tells the browser:

If you encounter a resource, wether it be an image, an HTML document, or anything, if the connectivity is on, grab the content of the resource from the server and store it in the cache.

If the network is off, and the resource is present in the cache, grab it from there, else behave like usual.

You can learn more on all the various caching strategies on the Workbox.js documentation about caching strategies.

Install the library:

npm install workbox-core workbox-routing workbox-strategies
Enter fullscreen mode Exit fullscreen mode

Create a "service-worker.js" file:

const { clientsClaim } = require("workbox-core");
const { registerRoute } = require("workbox-routing");
const { NetworkFirst } = require("workbox-strategies");

clientsClaim();

registerRoute(
    /.*/u,
    new NetworkFirst({
        cacheName: "nf-v1",
    })
);
Enter fullscreen mode Exit fullscreen mode

Update the "app.js" entry point to start the service worker:

if (navigator.serviceWorker instanceof ServiceWorkerContainer) {
    navigator.serviceWorker.register("/service-worker.js", { scope: "/" });
}
Enter fullscreen mode Exit fullscreen mode

Include the script in your HTML:

<!DOCTYPE html>
<html>
  <head>
    <!-- ... !-->
    <link rel="manifest" href="manifest.json" />
  </head>
  <body>
    <!-- ... -->
    <script type="text/javascript" src="app.js"></script>
  </body>
</html>
Enter fullscreen mode Exit fullscreen mode

Show an install button

To make your web app more discoverable, register it on Store.app. This platform can increase your app's visibility, and they provide a convenient install modal.

Install the NPM package:

npm install @storedotapp/pwa-install-dialog
Enter fullscreen mode Exit fullscreen mode

Import the code in your main entry javascript file:

require("@storedotapp/pwa-install-dialog");

if (navigator.serviceWorker instanceof ServiceWorkerContainer) {
    navigator.serviceWorker.register("/service-worker.js", { scope: "/" });
}
Enter fullscreen mode Exit fullscreen mode

Add a button to your HTML for users to install the app:

<!DOCTYPE html>
<html>
  <head>
    <!-- ... !-->
    <link rel="manifest" href="manifest.json" />
  </head>
  <body>
    <button id="install-button">Install the app</button>    

    <pwa-install-dialog id="install-dialog" app="fitness-app" theme="dark"></pwa-install-dialog>

    <script type="text/javascript" src="app.js"></script>
  </body>
</html>
Enter fullscreen mode Exit fullscreen mode

Register an "onClick" listener to show the modal when clicking the button:

require("@storedotapp/pwa-install-dialog");

if (navigator.serviceWorker instanceof ServiceWorkerContainer) {
    navigator.serviceWorker.register("/service-worker.js", { scope: "/" });
}

document.addEventListener("DOMContentLoaded", () => {
  const button = document.getElementById("install-button");

  if (button instanceof HTMLButtonElement) {
    button.addEventListener("click", () => {
      const dialog = document.getElementById("install-dialog");

      if (dialog instanceof HTMLElement) {
        dialog.show();
      }
    });
  }
});
Enter fullscreen mode Exit fullscreen mode

Conclusion

In just a few lines of code, we've transformed a website or web app into an installable web app. The evolution of the web into a platform with capabilities rivaling native apps is truly fascinating.

Installable web apps are shaping the future for a seamless, unified experience across all devices, offering lightweight, capable, and rich applications.

One limitation with the actual setup is that our app will still display the "install the app" button even if the app is installed (e.g. displayed as a standalone app).

Let us improve it by hiding the button if the app is already installed.

Create an "app.css" file with the following code:

@media all and (display-mode: standalone) {
  #install-button {
    display: none;
  }
}
Enter fullscreen mode Exit fullscreen mode

Now, only users who haven't installed your app will see the install button.

You can see this in action as I implemented it on Predzo.

I hope this tutorial has helped you understand PWAs better and demonstrated how easy it is to create an outstanding offline-ready installable web experience.

Happy web building!

Cover image by Roberto Nickson from Pexels.

Top comments (0)