PWA (Progressive Web Applications)
PWA (Progressive Web Applications) - a website that can be installed on a user's device and used as a native application.
There is no universal and precise definition of PWA, but for the average user, it boils down to two indicators: the ability to install the PWA on a mobile device and the use of the web resource offline. The main goal of PWA is to enable the use of the website as a "native" application on any device.
The PWA technology provides an additional layer of logic for the website, essentially serving as a "wrapper." This feature means we are not limited in our choice of tools for application development. However, there are basic requirements to use all PWA technology capabilities:
- Browsers Chrome or Safari.
Currently, PWA technology is fully supported by Chrome and Safari browsers. Since version 16.4, Safari supports push notifications. - HTTPS protocol for the PWA resource.
For the full operation of both PWA technology and most browser APIs, an HTTPS protocol is required. When running on HTTP, the application will not be able to install and use ServiceWorker. - Registered ServiceWorker (SW) and manifest.json file.
What makes our site a PWA application:
- SW is an event-driven "worker" that runs in a thread separate from the main JavaScript thread on the page, enabling the installation of the application on the device, offline operation, caching strategies, and much more.
- The manifest.json file contains settings to provide native functions for the PWA application.
ServiceWorker Lifecycle
- Registering SW. Check for the presence of the ServiceWorker API in the browser and call the registration method at the application entry point (/public/index.html) or the root file (/src/index.jsx).
- Install Event. Triggered immediately after registration. During the event processing, interaction with the ServiceWorker cache is available, and updates can be monitored for new application updates.
- Activate Event. The ServiceWorker is installed, and the old cache can be deleted during event processing.
- Idle Mode. After installation, the ServiceWorker enters "sleep mode" until the next call.
- Fetch Event. Triggered with every API request. To cache responses and use data offline, caching strategy settings need to be specified in the application.
Data Caching Strategies for ServiceWorker
- "Cache first".
- Essence: The API request is directed to the cache, and if there is no response, it goes to the network.
- Application: Suitable for resources that rarely change (logos, fonts).
- "Network first".
- Essence: First, an API request is made to the network; if the network is unavailable, the cache is checked.
- Application: Suitable for frequently changing content (user data).
- "Cache only".
- Essence: All API requests are directed to the cache; if the resource is not available, it will not be loaded.
- Application: Suitable for static applications (landing pages).
- "Network only".
- Essence: All API requests are directed to the network; the cache is ignored.
- Application: Suitable for data that must always be up-to-date (banking data).
- "Stale-While-Revalidate".
- Essence: The cache is checked first, and the cached resource is returned (if available), while an API request is sent to update the cache.
- Application: Suitable for loading and updating images.
Application Development
When starting a new project, it is best to use ready-made templates (Vite - vite-pwa-plugin, Webpack - cra-template-pwa, etc.), which greatly simplify interaction with the SW and its configuration.
The most common caching strategy is Network first, which reflects the primary purpose of SW: to enable the user to interact with the application offline when there is no network access. If caching strategy settings are not specified in the application, basic resources (JavaScript, CSS, HTML) will be pre-cached during the SW installation, allowing the user to use the application offline but only with the archived resources that were pre-cached.
Development Process
Option for Vite + vite-pwa-plugin + ReactJS
- Create a new application using Vite's template with the command:
npm create vite@latest
- Develop the MVP version of the application on ReactJS.
The process of developing the PWA application interfaces is no different from developing a regular website, but it often requires responsive design for mobile devices. - Install the plugin for generating PWA assets with the command:
npm i @vite-pwa/assets-generator -D
Configure the vite-pwa-plugin in the vite.config.js or vite.config.ts file.
(source link):
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
import { VitePWA } from "vite-plugin-pwa";
export default defineConfig({
plugins: [
react(),
VitePWA({
injectRegister: 'auto',
registerType: 'autoUpdate',
includeAssets: ["favicon.ico", "apple-touch-icon.png", "mask-icon.svg"],
manifest: {
name: "My Awesome App",
short_name: "MyApp",
description: "My Awesome App description",
theme_color: "#ffffff",
icons: [
{
src: "pwa-192x192.png",
sizes: "192x192",
type: "image/png",
},
{
src: "pwa-512x512.png",
sizes: "512x512",
type: "image/png",
},
],
},
}),
],
});
- Specify caching strategy settings in the application using the Network first strategy:
export default defineConfig({
plugins: [
react(),
VitePWA({
...other settings,
workbox: {
runtimeCaching: [
{
urlPattern: /^https:\/\/test-api-domain\.com\/.*$/,
handler: 'NetworkFirst',
options: {
cacheName: 'api-cache',
networkTimeoutSeconds: 10,
expiration: {
maxEntries: 50,
maxAgeSeconds: 5 * 60,
},
}
},
],
}
}),
],
});
- urlPattern - a regular expression for defining the URL pattern for which the caching strategy will be applied. In this example, it is any API request containing the string "https://test-api-domain.com/".
- handler - sets the caching strategy. In this case, 'NetworkFirst'.
- options.cacheName - the name of the cache used to store responses.
- options.networkTimeoutSeconds - network request timeout in seconds.
- options.expiration.maxEntries - the maximum number of entries that can be stored in the cache.
- options.expiration.maxAgeSeconds - maximum storage time in seconds for entries.
- Add a new script in package.json to create PWA assets (source link): "generate-pwa-assets": "pwa-assets-generator --preset minimal public/logo.svg"
- Add the original svg file with the application logo (public/logo.svg) and run the script to create PWA assets: npm run generate-pwa-assets
Specify the code in index.html to use PWA assets (source link):
<head>
...other code
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>My Awesome App</title>
<meta name="description" content="My Awesome App description">
<link rel="icon" href="/favicon.ico">
<link rel="apple-touch-icon" href="/apple-touch-icon.png" sizes="180x180">
<link rel="mask-icon" href="/mask-icon.svg" color="#FFFFFF">
<meta name="theme-color" content="#ffffff">
</head>
- Run the commands in the console:
npm run build
npm run preview
- Check the application:
- Browser → Developer Tools → Application → Service Workers → the tab should display information about the application's SW.
- In the far right corner, a button should appear with the option to install the application on the device.
- Testing the caching strategy:
- Interact with the application to send several API requests to the address specified in the caching strategy settings.
- Responses from successful requests will be saved in the SW cache.
- Disable the network in the developer tools.
- Navigate to the pages from which requests were sent: the data should be displayed offline.
This option allows you to quickly deploy a standard PWA application and also convert an existing web resource into a PWA application, provided that Vite was used initially.
Converting a PWA Application to an APK File
Android OS
For this OS, it is possible to convert a PWA application into an APK file, which can then be installed on a device:
- Online Service PWA Builder (link)
- Go to the website
- Enter the web address of the PWA application and click Start
- The scan results may reveal critical issues that prevent the service from creating a build
- Fix the issues, deploy, and repeat the previous steps
- If the scan is successful, the Package for stores button will be active in the upper right corner → click it, and select Generate package on the Android card
- A zip file will be downloaded, and from the archive, we need the .apk file
- Upload the file to the Android device and install it
- Locally using Bubblewrap + Graddle + Java Development Kit
- Run the following command in the console:
npm install -g @bubblewrap/cli
- Navigate to the PWA application directory and run the command:
bubblewrap init --manifest https://test.pwa/manifest.json
(replace the address with the URL of the Web App Manifest file) - During initialization, download the missing packages and specify the required settings.
- Run the following command in the console:
bubblewrap build
- Check for the presence of the .apk file in our project