Unleashing the Power of Progressive Web Applications (PWA) with NextJS

Introduction

(Note: This guide was created with Next.js version 12 and earlier in mind. Happy reading!)

Progressive Web Apps (PWA) is a web application technology that offers a mobile app-like user experience through web browsers. It is an enhanced version of a website that can be downloaded and installed on a user's device, providing offline access to content and other features.

The purpose of PWA is to provide users with an app-like experience without requiring them to install an app from an app store. PWAs can be accessed through a web browser, which eliminates the need to download, install and update native mobile apps.

Advantages of Progressive Web Apps

  • Installable: Users can add PWAs to their home screens, making them easily accessible and discoverable.

  • Discoverable: PWAs are discoverable through search engines, making them more visible to potential users.

  • Secure: PWAs are served over HTTPS, ensuring a secure connection between the user and the server.

  • Reliable: PWAs are built to work in all network conditions, including offline.

  • Fast: PWAs are optimized for performance and load quickly, providing a smooth user experience.

Real-world examples of successful PWAs

Some examples of successful PWAs include:

  • Twitter Lite: a fast and reliable version of Twitter that works on all devices and network conditions.

  • Starbucks: a PWA that allows users to order and pay for drinks online, and offers a seamless user experience across devices.

  • Pinterest: a PWA that offers an engaging and personalized experience to users, with features like push notifications and offline support.

PWA Architecture

PWAs are built using a specific architecture that includes the combination of the App Shell, Manifest File, and most importantly Service Worker.

App Shell

The app shell is the minimal HTML, CSS, and JavaScript required to load the user interface of a PWA. It is designed to load quickly and provide a seamless user experience, even on slow networks. This can be your ReactJS Application or NextJs Application.

Service Worker

A service worker is a JavaScript file that runs separately from the main browser thread, allowing it to intercept network requests and cache assets for offline use. The service worker is responsible for handling push notifications, background sync, and other PWA features.

A Service Worker is a script that runs in the background of the PWA, intercepts network requests, and caches the application's assets and data. This enables the PWA to load quickly, even when there is no network connection.

Manifest File

The manifest file is a JSON file that contains information about the PWA, such as its name, icon, and theme color. It is used by the browser to display a native-like app experience, such as adding the app to the home screen and showing an app icon in the task switcher.

Configuring the manifest file

To create a manifest file for your PWA, you'll need to include the following information:

  • name: The name of your PWA

  • short_name: A shorter name for your PWA (used when space is limited)

  • icons: An array of icons in different sizes and formats for different devices

  • start_url: The URL that the PWA should launch from

  • background_color: The background color of your PWA

  • theme_color: The theme color of your PWA, which affects the color of the browser UI elements when the PWA is open.

  • display: The display mode of your PWA, which can be one of fullscreen, standalone, minimal-ui, or browser.

  • description: A short description of your PWA.

To configure the manifest file in your application, you can create a public/manifest.json file and include the necessary fields. Here's an example:

{
  "name": "My PWA",
  "short_name": "My PWA",
  "icons": [
    {
      "src": "/icons/icon-192x192.png",
      "sizes": "192x192",
      "type": "image/png"
    },
    {
      "src": "/icons/icon-512x512.png",
      "sizes": "512x512",
      "type": "image/png"
    }
  ],
  "start_url": "/",
  "background_color": "#ffffff",
  "theme_color": "#3367D6",
  "display": "standalone",
  "description": "My Progressive Web App"
}

There are various tools available online that help generate manifest files like simicart.com, app-manifest

Building a PWA with Next.js

Next.js is a popular open-source framework for building server-rendered React applications. It provides various features and optimizations that make it well-suited for building PWAs, including server-side rendering, automatic code splitting, and client-side hydration.

The high-level process steps for converting a React or Next.js application into a PWA are:

  1. Add a Web App Manifest: Create a manifest.json file that includes metadata about the PWA, such as the name, description, icons, and starting URL.

  2. Implement a Service Worker: Register a Service Worker that intercepts network requests and caches your application's assets for offline access.

  3. Implement App Shell Architecture: Structure your application so that the shell is loaded first and the content is loaded later, using tools like React.lazy and React Suspense, code splitting and bundling, etc. Most of these things are already being used by NextJS itself.

  4. Ensure Security: Serve the PWA over HTTPS to ensure secure data transmission.

These steps involve adding PWA-specific features to the existing React or Next.js application, such as the Web App Manifest and Service Worker. By following this process, you can provide your users with a fast, reliable, and engaging PWA experience.

We can use the ‘next-pwa’ package with our next.js application to easily convert and configure above mentioned steps for our PWA application.

Using the ‘next-pwa’ package

next-pwa is a package that makes it easy to convert a Next.js application into a PWA by automating much of the configuration process. It provides a simple API to add PWA-specific features to a Next.js application, such as caching, offline support, and Web App Manifest generation.

The high-level overview of the next-pwa package is as follows:

  • Installation: You can install next-pwa using npm or yarn by running npm install next-pwa or yarn add next-pwa.

  • Configuration: To configure next-pwa, you need to create a next.config.js file in your Next.js application and add the necessary configuration. You can set options such as the PWA's name, description, icons, and caching strategy.

const runtimeCaching = require('next-pwa/cache')

const withPWA = require("next-pwa")({
  dest: "public",
  register: true,
  skipWaiting: true,
  runtimeCaching,
  manifest: 'public/manifest.json',
  // buildExcludes: [/middleware-manifest.json$/],
});

// For Vanila Nextjs  
const nextConfig = withPWA({
  reactStrictMode: true,
})

module.exports = nextConfig

// For Sitecore NextJS JSS SDK boilerplates will have the below line of code for 
// the module export of the next config.
module.exports = () => {
  // Run the base config through any configured plugins
  return Object.values(plugins).reduce((acc, plugin) => plugin(acc), nextConfig);
};

// wrap the nextconfig with withPWA like below for PWA with NextjsJSS
module.exports = () => {
  // Run the base config through any configured plugins
  return Object.values(plugins).reduce((acc, plugin) => plugin(acc), withPWA(nextConfig));
};

You can check out the PWA plugin for more configuration options.

  • Service Worker Generation: next-pwa automatically generates a Service Worker file that caches your application's assets and provides offline support. You can customize the caching strategy by specifying an sw.js file in your Next.js application.

  • Web App Manifest Generation: The next step is to create a manifest.json file, which tells the browser how the Progressive Web App should behave when installed on the user's desktop or mobile device, and there are two ways to do this. You can either create the manifest file manually or use a manifest generator.

  • Creating a document.js file: In the pages folder, you should create a document.js file to override the default document in Next.js. And link the manifest file in <Head> meta tags.

      import { Html, Head, Main, NextScript } from "next/document";
      export default function Document() {
        return (
          <Html>
            <Head>
              <link rel="manifest" href="/manifest.json" />
              <link rel="apple-touch-icon" href="/icon.png"></link>
              <meta name="theme-color" content="#fff" />
            </Head>
            <body>
              <Main />
              <NextScript />
            </body>
          </Html>
        );
      }
    
    • Automatic Refresh: next-pwa automatically refreshes the page when a new version of the PWA is available, ensuring that users always see the latest version of the PWA.

By using next-pwa, you can quickly and easily convert your Next.js application into a PWA without having to write a lot of boilerplate code.

Note: Currently ‘next-pwa’ only works with the Pages folder structure and does not support the ‘App directory router’ introduced in NextJS 13.
  • In alternative to ‘next-pwa’, you can also try out PWA with the ‘next-offline’ package with the required configuration to leverage service workers created for offline support to configure the PWA application.

Offline Fallbacks

Offline fallbacks are useful when the fetch failed from both cache and network, a precached resource is served instead of presenting an error from the browser.

To get started simply add a /_offline page such as pages/_offline.js or pages/_offline.jsx or pages/_offline.ts or pages/_offline.tsx. Then you are all set! When the user is offline, all pages which are not cached will fall back to '/_offline'.

Testing and Debugging PWA Applications

Now your app is PWA-ready. You just need to test this. When we use next-pwa, the service workers are enabled only on production. So, we should build our app with an npm run build or yarn build.

Go to a deployed application. If you are on Google Chrome, run a Lighthouse Audit and select Progressive Web App. If your PWA is configured correctly, you should see something like this:

Make sure the app is installable

There may be times when the web browser thinks your app isn't ready to be installed, and it is not always straightforward to know why. To debug this problem, you can review the installability information in the Application tool.

To review this information:

  • Open DevTools.

  • Open the Application tool by clicking the + sign in the toolbar and finding the tool name in the list.

  • Once in the tool, go to the Manifest tab in the left sidebar.

You may see a number of warnings that prevent your application from being installable.

Checking if your service worker is running

To find information about your PWA service worker:

  • Open DevTools.

  • Open the Application tool by clicking the + sign in the toolbar and finding the tool name in the list.

  • Once in the tool, go to the Service Workers tab in the left sidebar.

    From there a few different pieces of information are provided including the name of the service worker file (which you can click to open it) and its status. This tool makes it easy to see whether the worker is running but can also be used to stop the service worker and, more usefully, update it.