> For the complete documentation index, see [llms.txt](https://fe-qasir.gitbook.io/qiblat-documentation/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://fe-qasir.gitbook.io/qiblat-documentation/integrations/pwa.md).

# PWA

## Features

* Zero config for registering and generating a service worker
* Optimized precache and runtime cache
* Maximize lighthouse score
* Easy to understand examples
* Completely offline support
* Use workbox and workbox-window v6
* Work with cookies out of the box
* No custom server needed for Next.js 9+
* Handle PWA lifecycle events opt-in
* Custom worker to run extra code in service worker with code splitting
* Debug service worker with confidence in development mode without caching
* Internationalization (a.k.a I18N) with `next-i18next`
* Configurable by the same [workbox configuration options](https://developers.google.com/web/tools/workbox/modules/workbox-webpack-plugin) for [GenerateSW](https://developers.google.com/web/tools/workbox/reference-docs/latest/module-workbox-webpack-plugin.GenerateSW) and [InjectManifest](https://developers.google.com/web/tools/workbox/reference-docs/latest/module-workbox-webpack-plugin.InjectManifest)
* Spin up a [GitPod](https://gitpod.io/#https://github.com/shadowwalker/next-pwa/) and try out examples in rocket speed
* (Experimental) precaching `.module.js` when `next.config.js` has `experimental.modern` set to `true`

## How to use

Thanks to **Next.js 9+**, we can use the `public` folder to serve static files from the root `/` URL path. It cuts the need to write custom server only to serve those files. Therefore the setup is easier and concise. We can use `next.config.js` to config `next-pwa` to generates service worker and workbox files into the `public` folder.

### Step 1: Install library

```bash
yarn add next-pwa
```

### Step 2: withPWA

Update or create `next.config.js` with

```jsx
const withPWA = require('next-pwa')

module.exports = withPWA({
  pwa: {
    disable: process.env.NODE_ENV === 'development',
    register: true,
    scope: '/app',
    sw: 'service-worker.js',
    dest: 'public'
  }
})
```

#### Available Options

* disable: boolean - whether to disable pwa feature as a whole
  * default to `false`
  * set `disable: false`, so that it will generate service worker in both `dev` and `prod`
  * set `disable: true` to completely disable PWA
  * if you don't need to debug service worker in `dev`, you can set `disable: process.env.NODE_ENV === 'development'`
* register: boolean - whether to let this plugin register service worker for you
  * default to `true`
  * set to `false` when you want to handle register service worker yourself, this could be done in `componentDidMount` of your root app. you can consider the [register.js](https://github.com/shadowwalker/next-pwa/blob/master/register.js) as an example.
* scope: string - url scope for pwa
  * default to `/`
  * set to `/app` so that path under `/app` will be PWA while others are not
* sw: string - service worker script file name
  * default to `/sw.js`
  * set to another file name if you want to customize the output file name
* runtimeCaching - caching strategies (array or callback function)
  * default: see the **Runtime Caching** section for the default configuration
  * accepts an array of cache entry objects, [please follow the structure here](https://developers.google.com/web/tools/workbox/reference-docs/latest/module-workbox-build#.RuntimeCachingEntry)
  * Note: the order of the array matters. The first rule that matches is effective. Therefore, please **ALWAYS** put rules with larger scope behind the rules with a smaller and specific scope.
* publicExcludes - an array of glob pattern strings to exclude files in the `public` folder from being precached.
  * default: `[]` - this means that the default behavior will precache all the files inside your `public` folder
  * example: `['!img/super-large-image.jpg', '!fonts/not-used-fonts.otf']`
* buildExcludes - an array of extra pattern or function to exclude files from being precached in `.next/static` (or your custom build) folder
  * default: `[]`
  * example: `[/chunks\/images\/.*$/]` - Don't precache files under `.next/static/chunks/images` (Highly recommend this to work with `next-optimized-images` plugin)
  * doc: Array of (string, RegExp, or function()). One or more specifiers used to exclude assets from the precache manifest. This is interpreted following the same rules as Webpack's standard exclude option.
* subdomainPrefix: string - url prefix to allow hosting static files on a subdomain
  * default: `""` - i.e. default with no prefix
  * example: `/subdomain` if the app is hosted on `example.com/subdomain`

### Step 3: Add Manifest File&#x20;

Create a `manifest.json` file in your `public` folder:

```jsx
{
  "name": "Qiblat",
  "short_name": "Qiblat",
  "theme_color": "#F04B32",
  "background_color": "#F04B32",
  "display": "fullscreen",
  "orientation": "portrait",
  "scope": "/",
  "start_url": "/",
  "icons": [
    {
      "src": "img/logo/manifest/logo-72x72.png",
      "sizes": "72x72",
      "type": "image/png"
    },
    {
      "src": "img/logo/manifest/logo-96x96.png",
      "sizes": "96x96",
      "type": "image/png"
    },
    {
      "src": "img/logo/manifest/logo-128x128.png",
      "sizes": "128x128",
      "type": "image/png"
    },
    {
      "src": "img/logo/manifest/logo-144x144.png",
      "sizes": "144x144",
      "type": "image/png"
    },
    {
      "src": "img/logo/manifest/logo-152x152.png",
      "sizes": "152x152",
      "type": "image/png"
    },
    {
      "src": "img/logo/manifest/logo-192x192.png",
      "sizes": "192x192",
      "type": "image/png"
    },
    {
      "src": "img/logo/manifest/logo-384x384.png",
      "sizes": "384x384",
      "type": "image/png"
    },
    {
      "src": "img/logo/manifest/logo-512x512.png",
      "sizes": "512x512",
      "type": "image/png"
    }
  ],
  "splash_pages": null
}
```

### Step 4: Add Head Meta

Add the following into `_document.jsx` or `_document.tsx`, in `<Head>`:

```jsx
<meta name='application-name' content='PWA App' />
<meta name='apple-mobile-web-app-capable' content='yes' />
<meta name='apple-mobile-web-app-status-bar-style' content='default' />
<meta name='apple-mobile-web-app-title' content='PWA App' />
<meta name='description' content='Best PWA App in the world' />
<meta name='format-detection' content='telephone=no' />
<meta name='mobile-web-app-capable' content='yes' />
<meta name='msapplication-config' content='/static/icons/browserconfig.xml' />
<meta name='msapplication-TileColor' content='#2B5797' />
<meta name='msapplication-tap-highlight' content='no' />
<meta name='theme-color' content='#000000' />
          
<link rel='apple-touch-icon' sizes='180x180' href='/static/icons/apple-touch-icon.png' />
<link rel='icon' type='image/png' sizes='32x32' href='/static/icons/favicon-32x32.png' />
<link rel='icon' type='image/png' sizes='16x16' href='/static/icons/favicon-16x16.png' />
<link rel='manifest' href='/static/manifest.json' />
<link rel='mask-icon' href='/static/icons/safari-pinned-tab.svg' color='#5bbad5' />
<link rel='shortcut icon' href='/static/icons/favicon.ico' />
<link rel='stylesheet' href='https://fonts.googleapis.com/css?family=Roboto:300,400,500' />
     
<meta name='twitter:card' content='summary' />
<meta name='twitter:url' content='https://yourdomain.com' />
<meta name='twitter:title' content='PWA App' />
<meta name='twitter:description' content='Best PWA App in the world' />
<meta name='twitter:image' content='https://yourdomain.com/static/icons/android-chrome-192x192.png' />
<meta name='twitter:creator' content='@DavidWShadow' />
<meta property='og:type' content='website' />
<meta property='og:title' content='PWA App' />
<meta property='og:description' content='Best PWA App in the world' />
<meta property='og:site_name' content='PWA App' />
<meta property='og:url' content='https://yourdomain.com' />
<meta property='og:image' content='https://yourdomain.com/static/icons/apple-touch-icon.png' />
```

{% hint style="info" %}
Tip: Put the `viewport` head meta tag into `_app.js` rather than in `_document.js` if you need it.
{% endhint %}

```jsx
<meta name='viewport' content='minimum-scale=1, initial-scale=1, width=device-width, shrink-to-fit=no, user-scalable=no, viewport-fit=cover' />
```


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://fe-qasir.gitbook.io/qiblat-documentation/integrations/pwa.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
