--- url: /guide/inject-manifest.md --- # Advanced (injectManifest) With this service worker `strategy` you can build your own service worker. The `vite-plugin-pwa` plugin will compile your custom service worker and inject its service worker's precache manifest. By default, the plugin will assume the `service worker` source code is located at the `Vite's public` folder with the name `sw.js`, that's, it will search in the following file: `/public/sw.js`. If you want to change the location and/or the service worker name, you will need to change the following plugin options: * `srcDir`: **must** be relative to the project root folder * `filename`: including the file extension and **must** be relative to the `srcDir` folder For example, if your service worker is located at `/src/my-sw.js` you must configure it using: ```ts import { VitePWA } from 'vite-plugin-pwa' export default defineConfig({ plugins: [ VitePWA({ strategies: 'injectManifest', srcDir: 'src', filename: 'my-sw.js' }) ] }) ``` ## Custom Service worker We recommend you to use [Workbox](https://developer.chrome.com/docs/workbox/) to build your service worker instead using `importScripts`, you will need to include `workbox-*` dependencies as `dev dependencies` to your project. ### Plugin Configuration You **must** configure `strategies: 'injectManifest'` in `vite-plugin-pwa` plugin options in your `vite.config.ts` file: ```ts VitePWA({ strategies: 'injectManifest', }) ``` ### Development If you would like the service worker to run in development, make sure to enable it in the [devOptions](/guide/development#plugin-configuration) and to set the type to [module](/guide/development#injectmanifest-strategy) if required. ### Service Worker Code Your custom service worker (`public/sw.js`) should have at least this code (you also need to install `workbox-precaching` as `dev dependency` to your project): ```js import { precacheAndRoute } from 'workbox-precaching' precacheAndRoute(self.__WB_MANIFEST) ``` If you're not using `precaching` (`self.__WB_MANIFEST`), you need to disable `injection point` to avoid compilation errors (available only from version `^0.14.0`), add the following option to your pwa configuration: ```ts injectManifest: { injectionPoint: undefined } ``` ### Service worker errors on browser ### Cleanup Outdated Caches ### Inject Manifest Source Map ### Custom Rollup and Vite Plugins From `v0.18.0`, you can add custom Rollup and/or Vite plugins to the service worker build, using `rollup` and `vite` options in the new `buildPlugins` option. ::: warning The old `plugins` option has been deprecated, use `buildPlugins.rollup` instead: * if `buildPlugins.rollup` is configured then `plugins` will be ignored * if `buildPlugins.rollup` is not configured then `plugins` will be used ::: You can check the [vue-router example](https://github.com/vite-pwa/vite-plugin-pwa/tree/main/examples/vue-router) using a custom Vite plugin with a simple virtual module consumed by both custom service workers. ## Auto Update Behavior If you need your custom service worker works with `Auto Update` behavior, you need to change the plugin configuration options and add some custom code to your service worker code. ### Plugin Configuration You must configure `registerType: 'autoUpdate'` to `vite-plugin-pwa` plugin options in your `vite.config.ts` file: ```ts VitePWA({ registerType: 'autoUpdate' }) ``` ### Service Worker Code You **must** include in your service worker code at least this code (you also need to install `workbox-core` as `dev dependency` to your project): ```js import { clientsClaim } from 'workbox-core' self.skipWaiting() clientsClaim() ``` ## Prompt For Update Behavior If you need your custom service worker works with `Prompt For Update` behavior, you need to change your service worker code. ### Service Worker Code You need to include on your service worker at least this code: ```js self.addEventListener('message', (event) => { if (event.data && event.data.type === 'SKIP_WAITING') self.skipWaiting() }) ``` ## TypeScript support You can use TypeScript to write your custom service worker. To resolve service worker types, just add `WebWorker` to `lib` entry on your `tsconfig.json` file: ```json { "compilerOptions": { "lib": ["ESNext", "DOM", "WebWorker"] } } ``` ### Plugin Configuration We recommend you to put your custom service worker inside `src` directory. You need to configure `srcDir: 'src'` and `filename: 'sw.ts'` plugin options in your `vite.config.ts` file, configure both options with the directory and the name of your custom service worker properly: ```ts VitePWA({ srcDir: 'src', filename: 'sw.ts' }) ``` ### Service Worker Code You need to define `self` scope with `ServiceWorkerGlobalScope`: ```ts import { precacheAndRoute } from 'workbox-precaching' declare let self: ServiceWorkerGlobalScope precacheAndRoute(self.__WB_MANIFEST) ``` --- --- url: /deployment/apache.md --- # Apache Http Server 2.4+ ## Configure `manifest.webmanifest` mime type You need to configure the following mime type (see basic configuration below): ```ini # Manifest file AddType application/manifest+json webmanifest ``` ## Basic configuration with http to https redirection Update your `httpd.conf` configuration file with: ```ini # httpd.conf ServerRoot "" Listen 80 ServerName www.yourdomain.com DocumentRoot "" # modules LoadModule mime_module modules/mod_mime.so LoadModule rewrite_module modules/mod_rewrite.so # mime types # Manifest file AddType application/manifest+json webmanifest # your https configuration Include conf/extra/https-www.yourdomain.com.conf SSLRandomSeed startup builtin SSLRandomSeed connect builtin ServerName www.yourdomain.com RewriteEngine On # disable TRACE and TRACK methods RewriteCond %{REQUEST_METHOD} ^(TRACE|TRACK) RewriteRule .* - [F] Options +FollowSymlinks RewriteCond %{SERVER_PORT} !443 RewriteRule (.*) https://www.yourdomain.com/ [L,R] ErrorLog logs/www.yourdomain.com-error_log CustomLog logs/www.yourdomain.com-access_log combined ``` --- --- url: /assets-generator/api.md --- # PWA Assets Generator API From `v0.2.0`, `@vite-pwa/assets-generator` is shipped with a CLI, an API (low-level api): refer to [API](#api) for more details. The API can be found in the [api folder](https://github.com/vite-pwa/assets-generator/tree/main/src/api). ## Installation This package is shipped with the `@vite-pwa/assets-generator` package: ::: code-group ```bash [pnpm] pnpm add -D @vite-pwa/assets-generator ``` ```bash [yarn] yarn add -D @vite-pwa/assets-generator ``` ```bash [npm] npm install -D @vite-pwa/assets-generator ``` ::: ## API From version `v0.2.0`, `@vite-pwa/assets-generator` exposes the following packages: * `@vite-pwa/assets-generator/api`: low-level functions api. * new `@vite-pwa/assets-generator/api/instructions`: `instructions` function to collect the icon assets instructions. * new `@vite-pwa/assets-generator/api/generate-assets`: `generateAssets` function to generate icon assets from an instruction. * new `@vite-pwa/assets-generator/api/generate-html-markup`: `generateHtmlMarkup` function to generate all html head links from an instruction. * new `@vite-pwa/assets-generator/api/generate-manifest-icons-entry`: `generateManifestIconsEntry` function to generate the PWA web manifest icons' entry. The API can be found in the [api folder](https://github.com/vite-pwa/assets-generator/tree/main/src/api) and the [JSDOCS documentation](https://paka.dev/npm/@vite-pwa/assets-generator). If you need to generate the PWA assets from your own code, you can use the `instructions`, `generateHtmlMarkup`, `generateAssets` and `generateManifestIconsEntry` functions: 1. [instructions](https://github.com/vite-pwa/assets-generator/tree/main/src/api/instructions.ts): collect the icon assets instructions, provides function helpers to generate each icon asset as a `Buffer` and html head links with `string` and `object` notation. 2. [generateAssets](https://github.com/vite-pwa/assets-generator/tree/main/src/api/generate-assets.ts): once you collect the icon assets instructions, you can use this function to save all the icon assets to the file system. 3. [generateHtmlMarkup](https://github.com/vite-pwa/assets-generator/tree/main/src/api/generate-html-markup.ts): once you collect the icon assets instructions, you can use this function to generate all the html head markup for the icon assets. 4. [generateManifestIconsEntry](https://github.com/vite-pwa/assets-generator/tree/main/src/api/generate-manifest-icons-entry.ts) function to generate the PWA web manifest icons' entry. ::: info We're working to expose the new api in `vite-plugin-pwa` plugin and the integrations. From `v0.19.0`, `vite-plugin-pwa` includes a new experimental feature, check [Integrations](/assets-generator/integrations) section. ::: ### v0.1.0 As mentioned previously, the API is low-level, it means that you have to handle the default values yourself: you can check the default values in the [defaults.ts](https://github.com/vite-pwa/assets-generator/tree/main/src/api/defaults.ts) module. The CLI has been rebuilt on top of the API, you can check the [CLI documentation](/assets-generator/cli) for more details about the default values. --- --- url: /examples/astro.md --- # Astro **NOTE**: when running StackBlitz playground, you will need to stop the dev server once started and then run `npm run build && npm run preview` to see the PWA in action. --- --- url: /frameworks/astro.md --- # Astro ::: warning You will need to update your application to use Vite ^3.1.0 and latest `vite-plugin-pwa` 0.13.1+. ::: ## Astro Integration `vite-plugin-pwa` provides the new `@vite-pwa/astro` integration that will allow you to use `vite-plugin-pwa` in your Astro applications. You will need to install `@vite-pwa/astro` using: ::: code-group ```bash [pnpm] pnpm add -D @vite-pwa/astro ``` ```bash [yarn] yarn add -D @vite-pwa/astro ``` ```bash [npm] npm install -D @vite-pwa/astro ``` ::: To update your project to use the new `vite-plugin-pwa` integration for Astro, you only need to change the Astro config file removing the PWA plugin if present: ```ts import { defineConfig } from 'astro/config' import AstroPWA from '@vite-pwa/astro' // https://astro.build/config export default defineConfig({ integrations: [ AstroPWA({ /* your pwa options */ }) ] }) ``` ## Importing Virtual Modules ::: warning Since Astro will not inject any script in your application when using Astro components, you will need to use/import a PWA virtual module. ::: You can also enable [Development Support](/guide/development) to test your PWA webmanifest and debug your custom service worker logic as you develop your Astro application. ### Auto Update The best place to use/import the PWA virtual module will be in the main layout of the application (you should register it in any layout): ::: details src/layouts/Layout.astro ```astro --- import { pwaInfo } from 'virtual:pwa-info'; export interface Props { title: string; } const { title } = Astro.props as Props; --- {title} { pwaInfo && }
``` ::: ::: details src/pwa.ts ```ts import { registerSW } from 'virtual:pwa-register' registerSW({ immediate: true, onRegisteredSW(swScriptUrl) { console.log('SW registered: ', swScriptUrl) }, onOfflineReady() { console.log('PWA application ready to work offline') }, }) ``` ::: ### Prompt for Update The best place to register the `ReloadPrompt` component will be in the main layout of the application (you should register it in any layout): ::: details src/layouts/Layout.astro ```astro --- import { pwaInfo } from 'virtual:pwa-info'; import ReloadPrompt from '../components/ReloadPrompt.astro'; export interface Props { title: string; } const { title } = Astro.props as Props; --- {title} { pwaInfo && }
``` ::: ::: details src/components/ReloadPrompt.astro ```astro ``` ::: ::: details src/components/pwa.ts ```ts import { registerSW } from 'virtual:pwa-register' window.addEventListener('load', () => { const pwaToast = document.querySelector('#pwa-toast')! const pwaToastMessage = pwaToast.querySelector('.message #toast-message')! const pwaCloseBtn = pwaToast.querySelector('#pwa-close')! const pwaRefreshBtn = pwaToast.querySelector('#pwa-refresh')! let refreshSW: ((reloadPage?: boolean) => Promise) | undefined const refreshCallback = () => refreshSW?.(true) const hidePwaToast = (raf = false) => { if (raf) { requestAnimationFrame(() => hidePwaToast(false)) return } if (pwaToast.classList.contains('refresh')) pwaRefreshBtn.removeEventListener('click', refreshCallback) pwaToast.classList.remove('show', 'refresh') } const showPwaToast = (offline: boolean) => { if (!offline) pwaRefreshBtn.addEventListener('click', refreshCallback) requestAnimationFrame(() => { hidePwaToast(false) if (!offline) pwaToast.classList.add('refresh') pwaToast.classList.add('show') }) } pwaCloseBtn.addEventListener('click', () => hidePwaToast(true)) refreshSW = registerSW({ immediate: true, onOfflineReady() { pwaToastMessage.innerHTML = 'App ready to work offline' showPwaToast(true) }, onNeedRefresh() { pwaToastMessage.innerHTML = 'New content available, click on reload button to update' showPwaToast(false) }, onRegisteredSW(swScriptUrl) { console.log('SW registered: ', swScriptUrl) } }) }) ``` ::: ### Using Application UI Framework If you're using some Application UI Framework in your Astro application, you can use/import the corresponding PWA plugin virtual module: * [Vue 3](/frameworks/vue) * [React](/frameworks/react) * [Svelte](/frameworks/svelte) * [SolidJS](/frameworks/solidjs) * [Preact](/frameworks/preact) Check also the documentation for [Astro Frameworks Components](https://docs.astro.build/en/core-concepts/framework-components/) for more information. ## Navigation Fallback If you have a `404` route, you can use it as the fallback navigation for your service worker. When using `generateSW` strategy, configure the `404` route in the `workbox` pwa integration option: ```ts AstroPWA({ workbox: { navigateFallback: '/404' } }) ``` If you are using `injectManifest` strategy, configure the `404` route in the navigation fallback in your custom service worker: ```ts registerRoute(new NavigationRoute(createHandlerBoundToURL('/404'))) ``` ## Experimental ### Directory and Trailing Slash Handler Check the problem in the following issue: https://github.com/vite-pwa/astro/issues/23. You can find a list of hosts and how they handle trailing slash in this [repository](https://github.com/slorber/trailing-slash-guide). To enable this feature, you need to add the following configuration to your PWA options: ```ts import { defineConfig } from 'astro/config' import AstroPWA from '@vite-pwa/astro' // https://astro.build/config export default defineConfig({ integrations: [ AstroPWA({ experimental: { directoryAndTrailingSlashHandler: true, } }) ] }) ``` If you're using `injectManifest` strategy, you also need to include `directoryIndex` and optionally `cleanURLs` in your custom service worker in the precaching controller: ```ts import { precacheAndRoute } from 'workbox-precaching' precacheAndRoute(self.__WB_MANIFEST, { directoryIndex: 'index.html', cleanURLs: true }) ``` ## PWA Assets `@vite-pwa/astro` plugin will configure `integration` option properly. We suggest you to use external configuration file, Astro dev server will not be restarted when changing the configuration. To inject the PWA icons links and the `theme-color`, you can use the `virtual:pwa-assets/head` virtual module in your layout components: * remove all links with rel `icon`, `apple-touch-icon` and `apple-touch-startup-image` from your html head * remove the `theme-color` meta tag from your html head * add the virtual import * include theme color and icons links using code-snippet shown below ```astro --- import { pwaAssetsHead } from 'virtual:pwa-assets/head'; --- { pwaAssetsHead.themeColor && } { pwaAssetsHead.links.map(link => ( )) } ``` You can find a working example in the [examples folder](https://github.com/vite-pwa/astro/tree/main/examples/pwa-simple-assets-generator). --- --- url: /guide/auto-update.md --- # Automatic reload With this behavior, once the browser detects a new version of your application, then, it will update the caches and will reload any browser windows/tabs with the application opened automatically to take the control. ::: warning In order to reload all client tab/window, you will need to import any virtual module provided by the plugin: if you're not using any virtual, there is no way to interact with the application ui, and so, any client tab/window will not be reloaded (the old service worker will be still controlling the application). Automatic reload is not automatic page reload, you will need to use the following code in your application entry point if you want **automatic page reload**: ```js import { registerSW } from 'virtual:pwa-register' registerSW({ immediate: true }) ``` ::: The disadvantage of using this behavior is that the user can lose data in any browser windows/tabs in which the application is open and is filling in a form. If your application has forms, we recommend you to change the behavior to use default `prompt` option to allow the user decide when to update the content of the application. ::: danger Before you put your application into production, you need to be sure of the behavior you want for the service worker. Changing the behavior of the service worker from `autoUpdate` to `prompt` can be a pain. ::: ## Plugin Configuration With this option, the plugin will force `workbox.clientsClaim` and `workbox.skipWaiting` to `true` on the plugin options. You must add `registerType: 'autoUpdate'` to `vite-plugin-pwa` plugin options in your `vite.config.ts` file: ```ts VitePWA({ registerType: 'autoUpdate' }) ``` ### Cleanup Outdated Caches ### Inject Manifest Source Map ### Generate SW Source Map ## Importing Virtual Modules With this behavior, you **must** import one of the virtual modules exposed by `vite-plugin-pwa` plugin **only** if you need to prompt a dialog to the user when the application is ready to work offline, otherwise you can import or just omit it. If you don't import one of the virtual modules, the automatic reload will still work. ### Ready To Work Offline You must include the following code on your `main.ts` or `main.js` file: ```ts import { registerSW } from 'virtual:pwa-register' const updateSW = registerSW({ onOfflineReady() {}, }) ``` You will need to show a ready to work offline dialog to the user with an `OK` button inside `onOfflineReady` callback. When the user clicks the `OK` button, just hide the prompt shown on `onOfflineReady` method. ### SSR/SSG --- --- url: /deployment/aws.md --- # AWS Amplify ::: info WIP Will coming soon. ::: --- --- url: /guide/change-log.md --- # Change Log Please refer to the corresponding installation section: * [vite-plugin-pwa](https://github.com/vite-pwa/vite-plugin-pwa#-install) * [@vite-pwa/sveltekit](https://github.com/vite-pwa/sveltekit#-install) * [@vite-pwa/vitepress](https://github.com/vite-pwa/vitepress#-install) * [@vite-pwa/astro](https://github.com/vite-pwa/astro#-install) * [@vite-pwa/nuxt](https://github.com/vite-pwa/nuxt#-install) * [@vite-pwa/assets-generator](https://github.com/vite-pwa/assets-generator#-install) * [@vite-pwa/create-pwa](https://github.com/vite-pwa/create-pwa#-usage) You can check the release notes to see the corresponding changes: * [vite-plugin-pwa](https://github.com/vite-pwa/vite-plugin-pwa/releases) * [@vite-pwa/sveltekit](https://github.com/vite-pwa/sveltekit/releases) * [@vite-pwa/vitepress](https://github.com/vite-pwa/vitepress/releases) * [@vite-pwa/astro](https://github.com/vite-pwa/astro/releases) * [@vite-pwa/nuxt](https://github.com/vite-pwa/nuxt/releases) * [@vite-pwa/assets-generator](https://github.com/vite-pwa/assets-generator/releases) * [@vite-pwa/create-pwa](https://github.com/vite-pwa/create-pwa/releases) ## @vite-pwa/create-pwa From version `v1.0.0`, all the templates to use Vite 7, including also the latest frameworks changes. ## @vite-pwa/create-pwa From version `v0.6.0`, all the templates to use Vite 6, including also the latest frameworks changes. Use version `v0.5.0` for Vite 5 and previous versions of the frameworks. ## SvelteKit Single-page App Support From `v0.6.7`, `@vite-pwa/sveltekit` adds support for [single-page apps](https://svelte.dev/docs/kit/single-page-apps), including also: * add `static-adapter` fallback in the service worker precache manifest in SPA mode * update `globPatterns` to include `__data.json` files when using `static-adapter` with `load` functions Check the [SvelteKit documentation](/frameworks/sveltekit) for further details. ## Vite 6 support From `v0.21.1`, `vite-plugin-pwa` adds support for Vite 6: * should also work with Vite 3, 4 and 5. * still not using the Vite 6 [Environment API](https://vite.dev/guide/api-environment). If you want to use `vite-plugin-pwa` with Vite 6 [Environment API](https://vite.dev/guide/api-environment), check this PR: [feat!: add Vite 6 Environment API support](https://github.com/vite-pwa/vite-plugin-pwa/pull/786): install the `vite-plugin-pwa` version from `pkg-pr-new` using the last commit (click on the commit link in the [pkg-pr-new comment](https://github.com/vite-pwa/vite-plugin-pwa/pull/786#issuecomment-2478777537) ): ::: code-group ```bash [pnpm] pnpm add -D https://pkg.pr.new/vite-plugin-pwa@88b2e45 ``` ```bash [yarn] yarn add -D https://pkg.pr.new/vite-plugin-pwa@88b2e45 ``` ```bash [npm] npm i -D https://pkg.pr.new/vite-plugin-pwa@88b2e45 ``` ::: ::: info `vite-plugin-pwa` should still work with Vite 3, 4 and 5. ::: ## Workbox 7.3.0 From `v0.21.0`, `vite-plugin-pwa` updates `workbox` to `7.3.0`. ## Workbox 7.3.0 From `v0.21.0`, `vite-plugin-pwa` updates `workbox` to `7.3.0`. ## Service worker build From `v0.20.2`, the plugin will throw an error if the `maximumFileSizeToCacheInBytes` warning is present when building the service worker. ## Workbox 7.1.0 From `v0.20.0`, `vite-plugin-pwa` updates `workbox` to `7.1.0`. Workbox has deprecated [workbox-google-analytics](https://developer.chrome.com/docs/workbox/modules/workbox-google-analytics/), it is not compatible with newer Google Analytics v4. ## Updated Vite Build **These new features are meant to be used only from integrations.** From `v0.19.6`, `vite-plugin-pwa` adds `envOptions` option to `injectManifest` to allow customizing the environment options for the service worker build output: * `envDir`: you can change the `envDir`, the plugin will use the Vite's [envDir](https://vitejs.dev/config/shared-options.html#envdir) option if not configured * `envPrefix`: you can change the `envPrefix`, the plugin will use the Vite's [envDir](https://vitejs.dev/config/shared-options.html#envprefix) option if not configured `vite-plugin-pwa` also includes the new `configureCustomSWViteBuild` integration option to allow you to change the Vite's build options for the custom service worker build, check the [PWAIntegration type](https://github.com/vite-pwa/vite-plugin-pwa/blob/main/src/types.ts) definition for more details. ## PWA Assets From `v0.19.0`, `vite-plugin-pwa` adds experimental support for `@vite-pwa/assets-generator` to serve, generate and inject PWA assets on the fly. Check the [PWA Assets Generator Integrations](/assets-generator/integrations) section for more details. ## New Vite Build ## Rollup 4 and Vite 5 Rollup 4 has changed the asset name layout format, it is using `ascii` letters (no encoding, including also dash and underscore), previous Rollup versions are using `hex` encoding: * [Using more characters can make the hash length shorter](https://github.com/rollup/rollup/issues/4803) * [Using a faster hash algorithm can make hashing faster](https://github.com/rollup/rollup/issues/4626) * This is the PR that changed the hash algorithm: https://github.com/rollup/rollup/pull/5155 This change breaks the way `vite-plugin-pwa` build plugin builds the service worker, since it is using this regular expression `/[.-][a-f0-9]{8}\./` for [dontCacheBustURLsMatching](https://developer.chrome.com/docs/workbox/reference/workbox-build/) in `workbox` and `injectManifest` options. From version `v0.17.0`, `vite-plugin-pwa` configures `dontCacheBustURLsMatching` with a regular expression using the Vite's [build.assetsDir](https://vitejs.dev/config/build-options.html#build-assetsdir) option (defaults to `assets`): * `workbox.dontCacheBustURLsMatching = /^assets\//` * `injectManifest.dontCacheBustURLsMatching = /^assets\//` You can refer to this issue for more details about `dontCacheBustURLsMatching`: [Workbox appears to be needlessly generating revision hashes](https://github.com/vite-pwa/vite-plugin-pwa/issues/163). ## @vite-pwa/vitepress From version `v0.3.0`, `@vite-pwa/vitepress` configures `dontCacheBustURLsMatching` in a similar way to how `vite-plugin-pwa` does, but using the VitePress' [assetsDir](https://vitepress.dev/reference/site-config#assetsdir) option (defaults to `assets`). ## @vite-pwa/nuxt From version `v0.4.0`, `@vite-pwa/nuxt` requires Vite 5 and Nuxt 3.9+. From version `v0.3.3`, `@vite-pwa/nuxt` configures `dontCacheBustURLsMatching` in a similar way to how `vite-plugin-pwa` does, but using the Nuxt's [app.buildAssetsDir](https://nuxt.com/docs/api/nuxt-config#buildassetsdir) option (defaults to `_nuxt`). ## @vite-pwa/astro From version `v0.3.1`, you can use `import.meta.env.PUBLIC_` variables in your custom service worker when configured using [.env files](https://docs.astro.build/en/guides/environment-variables/#setting-environment-variables). From version `v0.2.0`, `@vite-pwa/astro` configures `dontCacheBustURLsMatching` in a similar way to how `vite-plugin-pwa` does, but using the Astro's [build.assets](https://docs.astro.build/en/reference/configuration-reference/#buildassets) option (defaults to `_astro`). ## @vite-pwa/sveltekit From version `v0.3.0`, `@vite-pwa/sveltekit` supports SvelteKit 2 (should also support SvelteKit 1). From version `v0.2.9`, `@vite-pwa/sveltekit` configures `dontCacheBustURLsMatching` in a similar way to how `vite-plugin-pwa` does, but using the Sveltkit's [appDir](https://kit.svelte.dev/docs/configuration#appdir) option (defaults to `_app`). ::: warning From version `v0.2.0`, `SvelteKitPWA` plugin requires SvelteKit 1.3.1 or above. If you're using a SvelteKit version prior to `v1.3.1`, you should use `SvelteKitPWA` plugin version `0.1.*`. ::: ## Other integrations If you're using `vite-plugin-pwa` or another integration with other meta frameworks (îles), review the generated service worker if you're using Vite 5 or Rollup 4, and update the `dontCacheBustURLsMatching` regular expression properly when required. --- --- url: /assets-generator/cli.md --- # CLI The command line interface: `@vite-pwa/assets-generator`. * 💥 build your PWA assets from a single command, using only 2 options: preset and source * 🔌 supports custom configurations via `pwa-assets.config.js` or `pwa-assets.config.ts` ## Installation This package is shipped with the `@vite-pwa/assets-generator` package: ::: code-group ```bash [pnpm] pnpm add -D @vite-pwa/assets-generator ``` ```bash [yarn] yarn add -D @vite-pwa/assets-generator ``` ```bash [npm] npm install -D @vite-pwa/assets-generator ``` ::: ## Usage ```bash $ pwa-assets-generator [options] [sources] ``` :::info The source files should be relative to `root`. ::: Example using command line: ```bash $ pwa-assets-generator --preset minimal-2023 public/logo.svg ``` or using package configuration: ```json { "scripts": { "generate-pwa-assets": "pwa-assets-generator --preset minimal-2023 public/logo.svg" } } ``` :::info All PWA assets will be generated in the same source folder. ::: ## Options | Options | | |------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------| | `-v, --version` | Display version number | | `-r, --root ` | Define the project root, defaults to `process.cwd()` | | `-c, --config ` | Path to config file | | `-p, --preset ` | Built-in preset name: `minimal` (default), `minimal-2023`, `android`, `windows`, `ios` or `all` | | `-o, --override` | Override assets. Defaults to true (`--override=false` or `-o=false` to disable it) | | `-m, --manifest` | Generate PWA web manifest icons entry. Defaults to true (`--manifest=false` or `-m=false` to disable it) | | `--html [options]` | Available options: `--html.basePath `, `--html.preset `, `--html.xhtml ` and `--html.includeId ` | | `-h, --help` | Display available CLI options | ## Presets PWA Assets Generator has 5 built-in presets, check out the [preset definition](https://github.com/vite-pwa/assets-generator/tree/main/src/preset.ts) and [types definition](https://github.com/vite-pwa/assets-generator/tree/main/src/types.ts): * Minimal Preset 2023 (`minimal-2023`) * Minimal Preset (`minimal`) * iOS Preset (`ios`): (WIP) * Windows Preset (`windows`): (WIP) * Android Preset (`android`): (WIP) * Full Preset (`all`: `android`, `windows` and `ios` presets combined): (WIP) You can also define your own preset, to use it you will need to add [pwa-assets config file](#configurations) to the root of your project. ## Built-in features ### Configurations Create a `pwa-assets.config.js` or `pwa-assets.config.ts` configuration file in the root-level of your project to customize PWA assets generator CLI: ```ts import { defineConfig, minimal2023Preset as preset } from '@vite-pwa/assets-generator/config' export default defineConfig({ headLinkOptions: { preset: '2023' }, preset, images: ['public/logo.svg'] }) ``` :::info CLI options will override the configuration file options. ::: You can use one of the built-in presets or just define your own, this is the [minimal-2023 preset](https://github.com/vite-pwa/assets-generator/tree/main/src/presets/minimal-2023.ts) definition: ```ts import type { Preset } from '@vite-pwa/assets-generator/config'; export const minimal2023Preset: Preset = { transparent: { sizes: [64, 192, 512], favicons: [[48, 'favicon.ico']] }, maskable: { sizes: [512] }, apple: { sizes: [180] } } ``` Then run the CLI from the command line: ```bash $ pwa-assets-generator ``` or configure it in your `package.json` and run it via your package manager from the command line: ```json { "scripts": { "generate-pwa-assets": "pwa-assets-generator" } } ``` ### Favicon and Apple Touch Icon Links From version `v0.1.0`, the `@vite-pwa/assets-generator` CLI will generate the favicon and apple touch icon links. If you're using any of the built-in presets from the CLI, the preset will be auto-detected. If you're using the configuration file, you will need to include the new `headLinkOptions` option in your configuration file to configure the new preset `2023` layout for your favicons and apple touch icon links: ```ts export interface HeadLinkOptions { /** * Base path to generate the html head links. * * @default '/' */ basePath?: string /** * The preset to use. * * If using the built-in presets from CLI (`minimal` or `minimal-2023`), this option will be ignored (will be set to `default` or `2023` for `minimal` and `minimal-2023` respectively). * * @default 'default' */ preset?: HtmlLinkPreset /** * By default, the SVG favicon will use the SVG file name as the name. * * For example, if you provide `public/logo.svg` as the image source, the name will be `logo.svg`. * * @param name The name of the SVG icons. */ resolveSvgName?: (name: string) => string } ``` ### PNG output names The PNG files names will be generated using the following function (can be found in [utils module](https://github.com/vite-pwa/assets-generator/tree/main/src/utils.ts)): ```ts export function defaultAssetName(type: AssetType, size: ResolvedAssetSize) { switch (type) { case 'transparent': return `pwa-${size.width}x${size.height}.png` case 'maskable': return `maskable-icon-${size.width}x${size.height}.png` case 'apple': return `apple-touch-icon-${size.width}x${size.height}.png` } } ``` You can override the PNG output names providing custom `assetName` option: ```ts import { defineConfig, minimal2023Preset } from '@vite-pwa/assets-generator/config' export default defineConfig({ headLinkOptions: { preset: '2023' }, preset: { ...minimal2023Preset, assetName: (type: AssetType, size: ResolvedAssetSize) => { /* your logic here */ } }, images: ['public/logo.svg'] }) ``` ### PNG Padding When generating PNG files, PWA Assets Generator will apply the following padding: * for `transparent` PNG files: `0.05` * for `maskable` and `apple` PNG files: `0.3` `0` is no padding, `0.3` is a typical value for most icons. These values can be customized inside a custom preset: ```ts import type { Preset } from '@vite-pwa/assets-generator/config'; export const minimalPresetNoPadding: Preset = { transparent: { sizes: [64, 192, 512], favicons: [[48, 'favicon.ico']], padding: 0 }, maskable: { sizes: [512], padding: 0 }, apple: { sizes: [180], padding: 0 } } ``` ### PNG optimization/compression By default, all generated PNG files are optimized using: ```txt { compressionLevel: 9, quality: 60 } ``` You can provide your optimization options using `png` option, check the options in [sharp png output options](https://sharp.pixelplumbing.com/api-output#png): ```ts import { defineConfig, minimal2023Preset } from '@vite-pwa/assets-generator/config' export default defineConfig({ headLinkOptions: { preset: '2023' }, preset: { ...minimal2023Preset, png: { compressionLevel: 9, quality: 85 } }, images: ['public/logo.svg'] }) ``` ### Favicons PWA Assets Generator will generate favicons when explicitly defined in the preset. If you want to generate favicons, but not the corresponding PWA icons, add the favicons sizes you want to generate, PWA Assets Generator will generate the PWA icon to generate the corresponding favicon and once generated, the PWA icon will be removed. For example, if you want to generate a `48x48` favicon using the default preset, you can use the following configuration: ```ts import { defineConfig } from '@vite-pwa/assets-generator/config' export default defineConfig({ /* remember to include the preset for favicons and apple touch icon */ headLinkOptions: { preset: '2023' }, preset: { transparent: { sizes: [64, 192, 512], favicons: [[48, 'favicon-48x48.ico'], [64, 'favicon.ico']] }, maskable: { sizes: [512] }, apple: { sizes: [180] } }, images: ['public/logo.svg'], }) ``` PWA Assets Generator will generate the `public/pwa-48x48.png` PWA icon, then generate the corresponding favicon (`public/favicon-48x48.ico`) and finally remove the PWA icon (`public/pwa-48x48.png`). ### PWA Manifest Icons Entry By default, the CLI will show the PWA manifest icons' entry in the terminal. You can disable it using `-m=false` or `--manifest=false` option from CLI or using `manifestIconsEntry: false` in the file configuration. If you have configured `logLevel: 'silent'` in your configuration file, the CLI will not log the PWA manifest icons' entry. ### iOS/iPad Splash Screens PWA Assets Generator will generate iOS/iPad splash screens when explicitly defined in the preset: [iOS and iPadOS in web.dev](https://web.dev/learn/pwa/enhancements/#splash-screens). You can use `createAppleSplashScreens` function to create the splash screens configuration using global configuration and the device names you want to generate the splash screens for. If the device names are not provided in the `createAppleSplashScreens` function, PWA Assets Generator will generate splash screens for all devices (defined in the [splash](https://github.com/vite-pwa/assets-generator/blob/main/src/splash.ts) module). PWA Assets Generator will generate the landscape and portrait PNG files per device. If you also want to generate the dark splash screens, you will end up with four PNG files per device. For example, if you want to generate splash screens for `iPad Air 9.7"` device, you can use the following configuration (the values in the example are the default ones if you don't provide any configuration): ```ts import { createAppleSplashScreens, defineConfig, minimal2023Preset } from '@vite-pwa/assets-generator/config' export default defineConfig({ headLinkOptions: { preset: '2023' }, preset: { ...minimal2023Preset, appleSplashScreens: createAppleSplashScreens({ padding: 0.3, resizeOptions: { background: 'white', fit: 'contain' }, // by default, dark splash screens are exluded // darkResizeOptions: { background: 'black' }, linkMediaOptions: { // will log the links you need to add to your html pages log: true, // add screen to media attribute link? // by default: // addMediaScreen: true, basePath: '/', // add closing link tag? // by default: // // with xhtml enabled: // xhtml: false }, png: { compressionLevel: 9, quality: 60 }, name: (landscape, size, dark) => { return `apple-splash-${landscape ? 'landscape' : 'portrait'}-${typeof dark === 'boolean' ? (dark ? 'dark-' : 'light-') : ''}${size.width}x${size.height}.png` } }, ['iPad Air 9.7"']) }, images: ['public/logo.svg'] }) ``` You can also use `combinePresetAndAppleSplashScreens` to combine the preset and the splash screens configuration: ```ts import { combinePresetAndAppleSplashScreens, defineConfig, minimal2023Preset } from '@vite-pwa/assets-generator/config' export default defineConfig({ headLinkOptions: { preset: '2023' }, preset: combinePresetAndAppleSplashScreens( minimal2023Preset, { padding: 0.3, resizeOptions: { background: 'white', fit: 'contain' }, // by default, dark splash screens are exluded // darkResizeOptions: { background: 'black' }, linkMediaOptions: { // will log the links you need to add to your html pages log: true, // add screen to media attribute link? // by default: // addMediaScreen: true, basePath: '/', // add closing link tag? // by default: // // with xhtml enabled: // xhtml: false }, png: { compressionLevel: 9, quality: 60 }, name: (landscape, size, dark) => { return `apple-splash-${landscape ? 'landscape' : 'portrait'}-${typeof dark === 'boolean' ? (dark ? 'dark-' : 'light-') : ''}${size.width}x${size.height}.png` } }, ['iPad Air 9.7"'] ), images: ['public/logo.svg'] }) ``` #### Dark Splash Screens If you also want to generate `dark` splash screens, you can provide an empty `darkResizeOptions` option (the generator will set `background: 'black'` and `'fit: 'contain'` if missing) or providing any other options. Following with the previous example: ```ts import { combinePresetAndAppleSplashScreens, defineConfig, minimal2023Preset } from '@vite-pwa/assets-generator/config' export default defineConfig({ headLinkOptions: { preset: '2023' }, preset: combinePresetAndAppleSplashScreens(minimal2023Preset, { // dark splash screens using black background (the default) darkResizeOptions: { background: 'black', fit: 'contain' }, // or using a custom background color // darkResizeOptions: { background: '#1f1f1f' }, }, ['iPad Air 9.7"']), images: ['public/logo.svg'] }) ``` #### Advanced Configuration We strongly suggest using the global configuration, providing `padding`, `resizeOptions`, `darkResizeOptions` and `png` options globally, PWA Assets Generator will configure any splash screen device options properly. If you still want to use a custom configuration per device, you can provide `padding`, `resizeOptions`, `darkResizeOptions` and `png` options per device, but you will need to configure them via some custom logic. You can use the following exports from the `config` module (check the [splash](https://github.com/vite-pwa/assets-generator/blob/main/src/splash.ts) module, all splash exports being exported also in the `@vite-pwa/assets-generator/config` module): * `AppleDeviceName`: all Apple device names * `appleSplashScreenSizes`: all Apple splash screen sizes including the scale factor * `AllAppleDeviceNames`: all Apple device names as an array * `createAppleSplashScreens`: the logic inside that function is quite simple, you can use it as a starting point to create your own splash screens configuration `resizeOptions` and `darkResizeOptions` are [ResizeOptions from Sharp](https://github.com/search?q=repo%3Alovell%2Fsharp%20ResizeOptions\&type=code) For example, to create this custom configuration: * generate dark splash screens * global configuration with `0.5` padding, default splash screen names and `#1f1f1f` background color for dark splash screens * create splash screens for `iPad Air 9.7"` device using global configuration * create splash screens for `iPhone 6` device using a custom configuration: * padding: `0.4` * custom splash screen name * `#2f2f2f` background color for dark splash screens you can use the following configuration: ```ts import type { AppleDeviceName, AppleDeviceSize, } from '@vite-pwa/assets-generator/config' import { appleSplashScreenSizes, defineConfig, minimal2023Preset } from '@vite-pwa/assets-generator/config' const devices: AppleDeviceName[] = ['iPad Air 9.7"', 'iPhone 6'] function createCustomAppleSplashScreens( options: { padding?: number resizeOptions?: ResizeOptions darkResizeOptions?: ResizeOptions linkMediaOptions?: AppleTouchStartupImageOptions name?: AppleSplashScreenName } = {} ) { const { padding, resizeOptions, darkResizeOptions, linkMediaOptions, name, } = options return { sizes: devices.map((deviceName) => { const size = appleSplashScreenSizes[deviceName] if (deviceName === 'iPhone 6') { return { size: { ...size, padding: 0.4 }, darkResizeOptions: { background: '#2f2f2f' }, name: (landscape, size, dark) => `iphone6-${landscape ? 'landscape' : 'portrait'}${dark ? '-dark' : ''}.png` } } return size }), padding, resizeOptions, darkResizeOptions, linkMediaOptions, name, } } export default defineConfig({ headLinkOptions: { preset: '2023' }, preset: { ...minimal2023Preset, appleSplashScreens: createCustomAppleSplashScreens({ padding: 0.5, darkResizeOptions: { background: '#1f1f1f' }, }) }, images: ['public/logo.svg'] }) ``` #### Custom Dark Splash Screens Image Source From version `v0.2.2`, you can provide a custom dark splash screens image source using `darkImageResolver` option in the `createAppleSplashScreens` and `combinePresetAndAppleSplashScreens` functions options: * if you're using multiple images, you will need to return the proper dark image using the `imageName` parameter in the `darkImageResolver` function: check the [playground](https://github.com/vite-pwa/assets-generator/blob/main/playground/pwa-assets.config.mts) for an example. * if you're using a single image, you can ignore the `imageName` parameter. --- --- url: /guide/development.md --- # Development From version `v0.11.13` you can use the service worker on development. The PWA will not be registered, only the service worker logic, check the details for each strategy below. ::: warning There will be only one single registration on the service worker precache manifest (`self.__WB_MANIFEST`) when necessary: `navigateFallback`. ::: The service worker on development will be only available if `disabled` plugin option is not `true` and the `enable` development option is `true`. ## Plugin configuration To enable the service worker on development, you only need to add the following options to the plugin configuration: ```ts import { VitePWA } from 'vite-plugin-pwa' export default defineConfig({ plugins: [ VitePWA({ /* other options */ /* enable sw on development */ devOptions: { enabled: true /* other options */ } }) ] }) ``` ## Type declarations ::: warning Since version `0.12.4+`, the `webManifestUrl` has been deprecated, the plugin will use `navigateFallbackAllowlist` instead. ::: ```ts /** * Development options. */ export interface DevOptions { /** * Should the service worker be available on development?. * * @default false */ enabled?: boolean /** * The service worker type. * * @default 'classic' */ type?: WorkerType /** * This option will enable you to not use the `runtimeConfig` configured on `workbox.runtimeConfig` plugin option. * * **WARNING**: this option will only be used when using `generateSW` strategy. * * @default false */ disableRuntimeConfig?: boolean /** * This option will allow you to configure the `navigateFallback` when using `registerRoute` for `offline` support: * configure here the corresponding `url`, for example `navigateFallback: 'index.html'`. * * **WARNING**: this option will only be used when using `injectManifest` strategy. */ navigateFallback?: string /** * This option will allow you to configure the `navigateFallbackAllowlist`: new option from version `v0.12.4`. * * Since we need at least the entry point in the service worker's precache manifest, we don't want the rest of the assets to be intercepted by the service worker. * * If you configure this option, the plugin will use it instead the default. * * **WARNING**: this option will only be used when using `generateSW` strategy. * * @default [/^\/$/] */ navigateFallbackAllowlist?: RegExp[] /** * On dev mode the `manifest.webmanifest` file can be on other path. * * For example, **SvelteKit** will request `/_app/manifest.webmanifest`, when `webmanifest` added to the output bundle, **SvelteKit** will copy it to the `/_app/` folder. * * **WARNING**: this option will only be used when using `generateSW` strategy. * * @default `${vite.base}${pwaOptions.manifestFilename}` * @deprecated This option has been deprecated from version `v0.12.4`, the plugin will use navigateFallbackAllowlist instead. * @see navigateFallbackAllowlist */ webManifestUrl?: string } ``` ## manifest.webmanifest Since version `0.12.1` the `manifest.webmanifest` is also served on development mode: you can now check it on `dev tools`. ## generateSW strategy When using this strategy, the `navigateFallback` on development options will be ignored. The PWA plugin will check if `workbox.navigateFallback` is configured and will only register it on `additionalManifestEntries`. The PWA plugin will force `type: 'classic'` on service worker registration to avoid errors on client side (not yet supported): ```shell Uncaught (in promise) TypeError: Failed to execute 'importScripts' on 'WorkerGlobalScope': Module scripts don't support importScripts(). ``` ::: warning If your pages/routes other than the entry point are being intercepted by the service worker, use `navigateFallbackAllowlist` to include only the entry point: by default, the plugin will use `[/^\/$/]`. You **ONLY** need to add the `navigateFallbackAllowlist` option to the `devOptions` entry in `vite-plugin-pwa` configuration if your pages/routes are being intercepting by the service worker and preventing to work as expected: ```ts export default defineConfig({ plugins: [ VitePWA({ /* other options */ devOptions: { navigateFallbackAllowlist: [/^index.html$/] /* other options */ } }) ] }) ``` ::: ## injectManifest strategy You can use `type: 'module'` when registering the service worker (right now only supported on latest versions of `Chromium` based browsers: `Chromium/Chrome/Edge`): ```ts devOptions: { enabled: true, type: 'module', /* other options */ } ``` ::: warning When building the application, the `vite-plugin-pwa` plugin will always register your service worker with `type: 'classic'` for compatibility with all browsers. ::: ::: tip You should only intercept the entry point of your application, if you don't include the `allowlist` option in the `NavigationRoute`, all your pages/routes might not work as they are being intercepted by the service worker (which will return by default the content of the entry point by not including your pages/routes in its precache manifest): ```ts let allowlist: undefined | RegExp[] if (import.meta.env.DEV) allowlist = [/^\/$/] // to allow work offline registerRoute(new NavigationRoute( createHandlerBoundToURL('index.html'), { allowlist } )) ``` ::: When using this strategy, the `vite-plugin-pwa` plugin will delegate the service worker compilation to `Vite`, so if you're using `import` statements instead `importScripts` in your custom service worker, you **must** configure `type: 'module'` on development options. If you are using `registerRoute` in your custom service worker you should add `navigateFallback` on development options, the `vite-plugin-pwa` plugin will include it in the injection point (`self.__WB_MANIFEST`). You **must** not use `HMR (Hot Module Replacement)` in your custom service worker, since we cannot use yet dynamic imports in service workers: `import.meta.hot`. If you register your custom service worker (not using `vite-plugin-pwa` virtual module and configuring `injectRegister: false` or `injectRegister: null`), use the following code (remember also to add `scope` option if necessary): ```js if ('serviceWorker' in navigator) { navigator.serviceWorker.register( import.meta.env.MODE === 'production' ? '/sw.js' : '/dev-sw.js?dev-sw' ) } ``` If you are also using `import` statements instead `importScripts`, use the following code (remember also to add the `scope` option if necessary): ```ts if ('serviceWorker' in navigator) { navigator.serviceWorker.register( import.meta.env.MODE === 'production' ? '/sw.js' : '/dev-sw.js?dev-sw', { type: import.meta.env.MODE === 'production' ? 'classic' : 'module' } ) } ``` When you change your service worker source code, `Vite` will force a full reload, since we're using `workbox-window` to register it (by default, you can register it manually) you may have some problems with the service worker events. ## Example You can find an example here: [vue-router](https://github.com/antfu/vite-plugin-pwa/tree/main/examples/vue-router). To run the example, you must build the PWA plugin (`pnpm run build` from root folder), change to `vue-router` directory (`cd examples/vue-router`) and run it: * `generateSW` strategy: `pnpm run dev` * `injectManifest` strategy: `pnpm run dev-claims` Since version `0.12.1`, you also have the development scripts for all other frameworks as well. The instructions for running the `dev` or `dev-claims` scripts are the same as for `vue-router` but running them in the corresponding framework directory. --- --- url: /guide/faq.md --- # FAQ ## IDE errors 'Cannot find module' (ts2307) ## Type declarations You can find the full list of the `vite-plugin-pwa` plugin configuration options in the following [types.ts module](https://github.com/antfu/vite-plugin-pwa/blob/main/src/types.ts). You can find all the `vite-plugin-pwa` virtual modules declarations in the following [client.d.ts](https://github.com/antfu/vite-plugin-pwa/blob/main/client.d.ts). ## Web app manifest and 401 status code (Unauthorized) [Browsers send requests for the web manifest without credentials](https://web.dev/articles/add-manifest#link-manifest), so if your site sits behind auth, the request will fail with a 401 Unauthorized error – even if the user is logged in. To send the request with credentials, the `` needs a `crossorigin="use-credentials"` attribute, which you can enable via `useCredentials` in the [plugin options](https://github.com/antfu/vite-plugin-pwa/blob/main/src/types.ts#L79): ```ts useCredentials: true ``` ## Service Worker errors on browser ## Error: Unable to find a place to inject the manifest If you're using a custom service worker without `precaching` (`self.__WB_MANIFEST`) and you're getting this error on build process, you need to disable `injection point` in your pwa plugin configuration (available only from version `^0.14.0`): ```ts injectManifest: { injectionPoint: undefined } ``` ## Service Worker Registration Errors You can handle Service Worker registration errors if you want to notify the user with following code on your `main.ts` or `main.js`: ```ts import { registerSW } from 'virtual:pwa-register' const updateSW = registerSW({ onRegisterError(error) {} }) ``` and then inside `onRegisterError`, just notify the user that there was an error registering the service worker. ## Missing assets from SW precache manifest :::tip From version `0.20.2`, the plugin will throw an error if the `maximumFileSizeToCacheInBytes` warning is present when building the service worker. ::: If you find any assets are missing from the service worker's precache manifest, you should check if they exceed the `maximumFileSizeToCacheInBytes`, the default value is **2 MiB**. You can increase the value to your needs, for example to allow assets up to **3 MiB**: * when using `generateSW` strategy: ```ts workbox: { maximumFileSizeToCacheInBytes: 3000000 } ``` * when using `injectManifest` strategy: ```ts injectManifest: { maximumFileSizeToCacheInBytes: 3000000 } ``` ## Exclude routes If you need to exclude some routes from service worker interception: * [for `generateSW` strategy](/workbox/generate-sw#exclude-routes) * [for `injectManifest` strategy](/workbox/inject-manifest#exclude-routes) ## `navigator / window` is `undefined` If you are getting `navigator is undefined` or `window is undefined` errors when building your application, you have configured your application in an `SSR / SSG` environment. The error could be due to using this plugin or another library not aware of `SSR / SSG`: your code will be called on the client but also on the server side on build process, so when building the application your server logic will be invoked, and there is no `navigator / window` on the server, it is `undefined`. ### Third party libraries If the cause of the error is a third party library that is not aware of the `SSR / SSG` environment, the way to work around the error is to import it with a dynamic import when `window` is defined: ```ts if (typeof window !== 'undefined') import('./library-not-ssr-ssg-aware') ``` Alternatively, if your framework supports component `onMount / onMounted` lifecycle hook, you can import the third party library on the callback, since the frameworks should call this lifecycle hook only on client side, you should check your framework documentation. ### Vite PWA Virtual Module If the cause of the error is the virtual module of this plugin, you can work around this problem following [SSR/SSG: Prompt for update](/guide/prompt-for-update#ssr-ssg) or [SSR/SSG: Automatic reload](/guide/auto-update#ssr-ssg) entries. If you are using `autoUpdate` strategy and a `router` with `isReady` support (that is, the router allow register a callback to be called when the current component route finish loading), you can delay the service worker registration to be on the router callback. For example, using `vue-router`, you can register the service worker for `autoUpdate` strategy using this code: ```ts import type { Router } from 'vue-router' export function registerPWA(router: Router) { router.isReady().then(async () => { const { registerSW } = await import('virtual:pwa-register') registerSW({ immediate: true }) }) } ``` You can see an example for `autoUpdate` strategy on a `SSR / SSG` environment ([vite-ssg](https://github.com/antfu/vite-ssg)) on [Vitesse Template](https://github.com/antfu/vitesse/blob/main/src/modules/pwa.ts). If you are using `prompt` strategy, you will need to load the `ReloadPrompt` component using dynamic import with async fashion, for example, using `vue 3`: ```vue // src/App.vue ``` or using `svelte`: ```html ... {#if ClientReloadPrompt} {/if} ``` You can check your `SSR / SSG` environment to see if it provides some way to register components only on client side. Following with `vite-ssg` on `Vitesse Template`, it provides `ClientOnly` functional component, that will prevent registering components on server side, and so you can use the original code but enclosing `ReloadPrompt` component with it: ```vue // src/App.vue ``` ### VitePress You can check the [ReloadPrompt](https://github.com/antfu/vite-plugin-pwa/blob/main/docs/.vitepress/theme/components/ReloadPrompt.vue) component of this site to call the PWA virtual module: ```vue ``` ## Monorepo with multiple projects and frameworks From version `0.14.5`, `vite-plugin-pwa` includes types for each framework, and so you can import proper virtual module in your monorepo project. Instead using [client.d.ts](https://github.com/vite-pwa/vite-plugin-pwa/blob/main/client.d.ts) via `vite-plugin-pwa/client` (tsconfig.json file or TypeScript reference), use one of the following virtual modules: * `virtual:pwa-register/react`: configure `vite-plugin-pwa/react`. * `virtual:pwa-register/preact`: configure `vite-plugin-pwa/preact`. * `virtual:pwa-register/solid`: configure `vite-plugin-pwa/solid`. * `virtual:pwa-register/svelte`: configure `vite-plugin-pwa/svelte`. * `virtual:pwa-register/vanillajs`: configure `vite-plugin-pwa/vanillajs`. * `virtual:pwa-register/vue`: configure `vite-plugin-pwa/vue`. You can find some examples for `preact`, `solid` and `svelte` in the examples folder in the [vite-plugin-pwa repo](https://github.com/vite-pwa/vite-plugin-pwa/tree/main/examples). ## Suppress workbox-build warnings in dev If you are using `vite-plugin-pwa` with `generateSW` strategy, you can suppress `workbox-build` warnings in dev using `suppressWarnings` dev option: ```ts devOptions: { suppressWarnings: true } ``` Enabling this option, `vite-plugin-pwa` dev plugin will: * generate an empty `suppress-warnings.js` file in the `dev-dist` folder. * change `workbox.globPatterns` option to `[*.js']`. --- --- url: /workbox/generate-sw.md --- # generateSW You must read [Which Mode to Use](https://developer.chrome.com/docs/workbox/modules/workbox-build/#which-mode-to-use) before decide using this strategy on `vite-plugin-pwa` plugin. You can find the documentation for this method on `workbox` site: [generateSW](https://developer.chrome.com/docs/workbox/modules/workbox-build#method-generateSW). You can find a guide for plugins on `workbox` site: [Using Plugins](https://developer.chrome.com/docs/workbox/using-plugins/). ## Cache External Resources If you use some `CDN` to download some resources like `fonts` and `css`, you must include them into the service worker precache, and so your application will work when offline. The following example will use `css` from `https://fonts.googleapis.com` and `fonts` from `https://fonts.gstatic.com`. On `index.html` file you must configure the `css` `link`, you **MUST** also include `crossorigin="anonymous"` attribute for the external resources (see [Handle Third Party Requests](https://developer.chrome.com/docs/workbox/caching-resources-during-runtime#cross-origin_considerations)): ::: details index.html ```html ``` ::: Then on your `vite.config.ts` file add the following code: ::: details VitePWA options ```ts VitePWA({ workbox: { runtimeCaching: [ { urlPattern: /^https:\/\/fonts\.googleapis\.com\/.*/i, handler: 'CacheFirst', options: { cacheName: 'google-fonts-cache', expiration: { maxEntries: 10, maxAgeSeconds: 60 * 60 * 24 * 365 // <== 365 days }, cacheableResponse: { statuses: [0, 200] } } }, { urlPattern: /^https:\/\/fonts\.gstatic\.com\/.*/i, handler: 'CacheFirst', options: { cacheName: 'gstatic-fonts-cache', expiration: { maxEntries: 10, maxAgeSeconds: 60 * 60 * 24 * 365 // <== 365 days }, cacheableResponse: { statuses: [0, 200] }, } } ] } }) ``` ::: ## Exclude routes To exclude some routes from being intercepted by the service worker, you just need to add those routes using a `regex` list to the `navigateFallbackDenylist` option of `workbox`: ```ts VitePWA({ workbox: { navigateFallbackDenylist: [/^\/backoffice/] } }) ``` ::: warning You must deal with offline support for excluded routes: if requesting a page excluded on `navigateFallbackDenylist` you will get `No internet connection`. ::: ## Background Sync You can add this code to the plugin on your `vite.config.ts` file to add a `Background Sync` manager to your service worker: ::: details VitePWA options ```ts VitePWA({ workbox: { runtimeCaching: [{ handler: 'NetworkOnly', urlPattern: /\/api\/.*\.json/, method: 'POST', options: { backgroundSync: { name: 'myQueueName', options: { maxRetentionTime: 24 * 60 } } } }] } }) ``` ::: --- --- url: /deployment.md --- # Getting Started Since you need to install your application as a [Progressive Web App](https://web.dev/explore/progressive-web-apps), you must configure your server to meet [PWA Minimal Requirements](/guide/pwa-minimal-requirements), that is, your server **must**: * serve `manifest.webmanifest` with `application/manifest+json` mime type * you must serve your application over `https` * you must redirect from `http` to `https` ## Cache-Control Ensure you have a very restrictive setup for your `Cache-Control` headers in place. Double check that **you do not** have caching features enabled, especially `immutable`, on locations like: * `/` * `/sw.js` * `/index.html` * `/manifest.webmanifest` ::: danger **Always re-test and re-assure** that the caching for mission critical files is **as low** as possible if not hashed files or you might invalidate clients for a long time. ::: ## Servers * [Netlify](/deployment/netlify) * [AWS Amplify](/deployment/aws) * [Vercel](/deployment/vercel) * [NGINX](/deployment/nginx) * [Apache Http Server 2.4+](/deployment/apache) ## Testing your application on production Once you deploy your application to your server, you can test it using [WebPageTest](https://www.webpagetest.org/). There are many test sites, but we suggest you use `WebPageTest` as this is the most comprehensive in terms of test: * Security. * First byte time. * Keep alive enabled. * Compress transfer. * Cache static content. * Effective use of CDN. * Lighthouse: Core Web Vitals, Performance, Images size optimization... * And more... Enter the url of your application, click `Start Test` button, wait for the test to finish, the `WebPageTest` result will hint you what things on your application must be fixed/changed. The `WebPageTest` result will also score your application, it will also test your site with `Lighthouse`. For example, go to [WebPageTest](https://www.webpagetest.org/), enter `https://vite-pwa-org.netlify.app/`, click `Start Test` button, wait a few seconds for the test to finish, and see the results for this site. --- --- url: /examples.md --- # Getting Started You can find a set of examples projects on [Vite Plugin PWA GitHub repo](https://github.com/antfu/vite-plugin-pwa/tree/main/examples). All the examples projects are under `examples` package/directory of the repo root directory. ::: info The main purpose of these examples projects is to test the service worker and not to meet the [PWA Minimal Requirements](/guide/pwa-minimal-requirements), that is, if you use any of these examples for your projects, you will need to modify the code supplied and then test that it meets the [PWA Minimal Requirements](/guide/pwa-minimal-requirements). Almost all the examples projects should meet [PWA Minimal Requirements](/guide/pwa-minimal-requirements), but you must check it on your target project. All the examples projects use `@rollup/plugin-replace` to configure a timestamp initialized to `now` on each build, and so, the service worker will be regenerated/versioned on each build: this timestamp will help us since the service worker won't be regenerated/versioned if none source code changed (on your project you shouldn't want this behavior, you should want to only regenerate/version the service worker when your source code change). ::: ::: warning TRY TO AVOID INCLUDING AUTOMATIC TIMESTAMP ON YOU APPLICATION IF YOU DON'T CHANGE YOUR CODE We use the timestamp in the examples projects to avoid having to touch a file each time we need to test: for example, to test `Prompt for update`, we need to install the service worker first time (first build), then rebuild and restart the example project and finally refresh the browser to check the `Prompt for update` is shown. ::: ## How to run examples projects? If you want to run any of the examples projects you will need to download/clone to your local machine the `Vite Plugin PWA GitHub repo`. You will need `node 14` (or newer) to be able to build the `Vite Plugin PWA`. ::: warning Before following the instructions below, read the [Contribution Guide](https://github.com/antfu/vite-plugin-pwa/blob/main/CONTRIBUTING.md). ::: If you don't have installed `PNPM`, you must install it globally via `npm`: ```shell npm install -g pnpm ``` Once the repo is on your local machine, you must install project dependencies and build the `vite-plugin-pwa` plugin, just run (from `vite-plugin-pwa` directory cloned locally): ```shell pnpm install pnpm run build ``` We use `PNPM` but should work with any `package manager`, for example, with `YARN`: ```shell yarn && yarn build ``` ::: info From here on, we will only show the commands to run the examples projects using `PNPM`, we leave it to you how to execute them with any other` package manager`. ::: Before we start running the examples projects, you should consider the following: * Use `Chromium based` browser: `Chrome`, `Chromium` or `Edge` * All the examples that are executed in this guide will be done over https, that is, all the projects will respond at address `https://localhost` * When testing an example project, the `service worker` will be installed in `https://localhost`, and so, subsequent tests in another examples projects may interfere with the previous test, because the `service worker` of the previous project will keep installed on the browser * Tests should be done on a private window, and so, browser addons/plugins will not interfere with the test To avoid `service worker` interference, you should do the following tasks when switching between examples projects: * Open `dev tools` (`Option + ⌘ + J` on `macOS`, `Shift + CTRL + J` on `Windows/Linux`) * Go to `Application > Storage`, you should check following checkboxes: * Application: \[x] Unregister service worker * Storage: \[x] Local and session storage * Cache: \[x] Cache storage and \[x] Application cache * Click on `Clear site data` button * Go to `Application > Service Workers` and check the current `service worker` is missing or has the state `deleted` Once we remove the `service worker`, run the corresponding script and just press browser `Refresh` button (or enter `https://localhost` on browser address). ## How to test the examples projects Offline? To test any of the examples projects (or your project) on `offline`, just open `dev tools` (`Option + ⌘ + J` on `macOS`, `Shift + CTRL + J` on `Windows/Linux`) and go to `Application > Network`, then locate `No throttling` selector: open it and select `Offline` option. A common pitfall is to select `Offline` option, then restart the example project (or your project), and refresh the page. In that case, you will have unexpected behavior, and you should remove the service worker. If you click the browser `Refresh` button, you can inspect `Application > Network` tab on `dev tools` to check that the `Service Worker` is serving all assets instead request them to the server. ::: danger Don't do a `hard refresh` since it will force the browser to go to the server, and then you will get `No internet connection` page. ::: ## Available Examples Projects We provide the following examples projects: * [Vue 3](/examples/vue) * [Vue 3 generateSW Router Examples](/examples/vue#generatesw): set of examples with disparate behaviors. * [Vue 3 injectManifest Router Examples](/examples/vue#generatesw): set of examples with disparate behaviors. * [React](/examples/react) * [React generateSW Router Examples](/examples/react#generatesw): set of examples with disparate behaviors. * [React injectManifest Router Examples](/examples/react#generatesw): set of examples with disparate behaviors. * [Svelte](/examples/svelte) * [Svelte generateSW Router Examples](/examples/svelte#generatesw): set of examples with disparate behaviors. * [Svelte injectManifest Router Examples](/examples/svelte#generatesw): set of examples with disparate behaviors. * [SvelteKit](/examples/sveltekit) * [SolidJS](/examples/solidjs) * [SolidJS generateSW Router Examples](/examples/solidjs#generatesw): set of examples with disparate behaviors. * [SolidJS injectManifest Router Examples](/examples/solidjs#generatesw): set of examples with disparate behaviors. * [Preact](/examples/preact) * [Preact generateSW Router Examples](/examples/preact#generatesw): set of examples with disparate behaviors. * [Preact injectManifest Router Examples](/examples/preact#generatesw): set of examples with disparate behaviors. * [VitePress](/examples/vitepress). * [îles](/examples/iles): prompt for update. * [Astro](/examples/astro). --- --- url: /frameworks.md --- # Getting Started ::: tip If you use the default `registerType` which is `prompt`, and you want to prompt the users to reload, then you could use our framework modules. But if you: 1. use `autoUpdate` 2. don't like `autoUpdate`, but also don't feel it's necessary to prompt 3. use `injectManifest` Then, you **don't need** to learn the framework stuff. ::: This plugin is Framework-agnostic and so you can use it with Vanilla JavaScript, TypeScript and with any framework. ## Type declarations You can find all the `vite-plugin-pwa` virtual modules declarations in the following [types.ts module](https://github.com/antfu/vite-plugin-pwa/blob/main/client.d.ts). ::: tip From version `0.14.5` you can also use types definition for each framework, instead of using `vite-plugin-pwa/client`, include only one of the following types: ```json { "compilerOptions": { "types": [ "vite-plugin-pwa/react", "vite-plugin-pwa/preact", "vite-plugin-pwa/solid", "vite-plugin-pwa/svelte", "vite-plugin-pwa/vanillajs", "vite-plugin-pwa/vue" ] } } ``` Or you can add one of following references in any of your `d.ts` files (for example, in `vite-env.d.ts` or `global.d.ts`): ```ts /// /// /// /// /// /// ``` ::: ```ts declare module 'virtual:pwa-register' { import type { RegisterSWOptions } from 'vite-plugin-pwa/types' export type { RegisterSWOptions } export function registerSW(options?: RegisterSWOptions): (reloadPage?: boolean) => Promise } ``` where `vite-plugin-pwa/types` is: ```ts export interface RegisterSWOptions { immediate?: boolean onNeedRefresh?: () => void onOfflineReady?: () => void /** * Called only if `onRegisteredSW` is not provided. * * @deprecated Use `onRegisteredSW` instead. * @param registration The service worker registration if available. */ onRegistered?: (registration: ServiceWorkerRegistration | undefined) => void /** * Called once the service worker is registered (requires version `0.12.8+`). * * @param swScriptUrl The service worker script url. * @param registration The service worker registration if available. */ onRegisteredSW?: (swScriptUrl: string, registration: ServiceWorkerRegistration | undefined) => void onRegisterError?: (error: any) => void } ``` ## Accessing PWA Info From version `0.12.8`, `vite-plugin-pwa` exposes a new Vite virtual module to access the PWA info: [virtual:pwa-info](https://github.com/vite-pwa/vite-plugin-pwa/blob/main/info.d.ts). If your **TypeScript** build step or **IDE** complain about not being able to find modules or type definitions on imports, add the following to the `compilerOptions.types` array of your `tsconfig.json`: ```json { "compilerOptions": { "types": [ "vite-plugin-pwa/info" ] } } ``` Or you can add the following reference in any of your `d.ts` files (for example, in `vite-env.d.ts` or `global.d.ts`): ```ts /// ``` ## Import Virtual Modules `vite-plugin-pwa` plugin exposes a `Vite` virtual module to interact with the service worker. ::: tip You only need to import the virtual modules exposed by `vite-plugin-pwa` plugin when you need to interact with the user, otherwise you don't need to import any of them, that is, when using `registerType: 'prompt'` or when using `registerType: 'autoUpdate'` and you want to inform the user that the application is ready to work offline. ::: ### Auto Update You must import the virtual module when you configure `registerType: 'autoUpdate'` and you want your application inform the user when the application is ready to work `offline`: ```ts import { registerSW } from 'virtual:pwa-register' const updateSW = registerSW({ onOfflineReady() {} }) ``` You need to show a ready to work offline message to the user with an OK button inside `onOfflineReady` method. When the user clicks the `OK` button, just hide the prompt shown on `onOfflineReady` method. ### Prompt For Update When using `registerType: 'prompt'`, you **must** import the virtual module: ```ts import { registerSW } from 'virtual:pwa-register' const updateSW = registerSW({ onNeedRefresh() {}, onOfflineReady() {} }) ``` You will need to: * show a prompt to the user with refresh and cancel buttons inside `onNeedRefresh` method. * show a ready to work offline message to the user with an OK button inside `onOfflineReady` method. When the user clicks the "refresh" button when `onNeedRefresh` called, then call `updateSW()` function; the page will reload and the up-to-date content will be served. In any case, when the user clicks the `Cancel` or `OK` buttons in case `onNeedRefresh` or `onOfflineReady` respectively, close the corresponding showed prompt. ## Custom Vite Virtual Modules `vite-plugin-pwa` plugin also exposes a set of virtual modules for [Vue 3](https://v3.vuejs.org/), [React](https://reactjs.org/), [Svelte](https://svelte.dev/docs), [SolidJS](https://www.solidjs.com/) and [Preact](https://preactjs.com/). These custom virtual modules will expose a wrapper for virtual:pwa-register using framework reactivity system, that is: * virtual:pwa-register/vue: [ref](https://v3.vuejs.org/api/refs-api.html#ref) for Vue 3 * virtual:pwa-register/react: [useState](https://reactjs.org/docs/hooks-reference.html#usestate) for React * virtual:pwa-register/svelte: [writable](https://svelte.dev/docs#writable) for Svelte * virtual:pwa-register/solid: [createSignal](https://www.solidjs.com/docs/latest/api#createsignal) for SolidJS * virtual:pwa-register/preact: [useState](https://preactjs.com/guide/v10/hooks#usestate) for Preact **Note**: for [Vue 2](https://vuejs.org/) you need to use a custom `mixin` provided on [Vue 2](/frameworks/vue#vue-2) section. ## Frameworks These custom virtual modules will expose a wrapper for virtual:pwa-register using framework reactivity system, that is: * [Vue](/frameworks/vue) * [React](/frameworks/react) * [Svelte](/frameworks/svelte) * [SvelteKit](/frameworks/sveltekit) * [SolidJS](/frameworks/solidjs) * [Preact](/frameworks/preact) * [VitePress](/frameworks/vitepress) * [îles](/frameworks/iles) * [Astro](/frameworks/astro) * [Nuxt 3](/frameworks/nuxt) --- --- url: /guide.md --- # Getting Started Progressive Web Apps (PWAs) are web applications built and enhanced with modern APIs to deliver enhanced capabilities, reliability, and installability while reaching anyone, anywhere, on any device—all with a single codebase. At a high level, a PWA consists of a [web application manifest](https://developer.mozilla.org/en-US/docs/Web/Manifest) to give the browser information about your app, and a service worker to manage the offline experience. If you are new to Progressive Web Apps, you might consider reading Google's ["Learn PWA"](https://web.dev/learn/pwa/) course before you begin. ## Service Worker Service workers essentially act as proxy servers that sit between web applications, the browser, and the network (when available). They are intended, among other things, to enable the creation of effective offline experiences, intercept network requests and take appropriate action based on whether the network is available, and update assets residing on the server. They will also allow access to push notifications and background sync APIs. A service worker is an event-driven [worker](https://developer.mozilla.org/en-US/docs/Web/API/Worker) registered against an origin and a path. It takes the form of a JavaScript file that can control the web-page/site that it is associated with, intercepting and modifying navigation and resource requests, and caching resources in a very granular fashion to give you complete control over how your app behaves in certain situations (the most obvious one being when the network is not available). You can find more information about service workers in [Service Worker API](https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API). ## Vite PWA Vite PWA will help you to turn your existing applications into PWAs with very little configuration. It comes preset with sensible defaults for common use cases. The `vite-plugin-pwa` plugin can: * Generate the [web application manifest][webmanifest] and add it to your entry point (see the [setup guide for manifest generation](pwa-minimal-requirements#web-app-manifest)). * Generate the service worker using the `strategies` option (for more information, see ["Service Worker Strategies"](/guide/service-worker-strategies-and-behaviors#service-worker-strategies) section) * Generate a script to register the service worker in the browser (see the ["Register Service Worker"](/guide/register-service-worker) section) ## Scaffolding Your First Vite PWA Project ## Installing vite-plugin-pwa To install the `vite-plugin-pwa` plugin, just add it to your project as a `dev dependency`: ::: code-group ```bash [pnpm] pnpm add -D vite-plugin-pwa ``` ```bash [yarn] yarn add -D vite-plugin-pwa ``` ```bash [npm] npm install -D vite-plugin-pwa ``` ::: ## Configuring vite-plugin-pwa Edit your `vite.config.js / vite.config.ts` file and add the `vite-plugin-pwa`: ```ts import { VitePWA } from 'vite-plugin-pwa' export default defineConfig({ plugins: [ VitePWA({ registerType: 'autoUpdate' }) ] }) ``` With this minimal configuration of the `vite-plugin-pwa` plugin, your application is now able to generate the [Web App Manifest][webmanifest] and inject it at the entry point, generate the service worker and register it in the browser. You can find the full list of the `vite-plugin-pwa` plugin configuration options in the following [client.d.ts](https://github.com/antfu/vite-plugin-pwa/blob/main/src/types.ts). ::: warning If you are **NOT** using `vite-plugin-pwa` version `0.12.2+`, there is a bug handling `injectRegister` (the service worker generated will not include the code required to allow work with `autoUpdate` behavior). If you're using a `vite-plugin-pwa` plugin version prior to `0.12.2`, you can fix the bug using this plugin configuration: ```ts import { VitePWA } from 'vite-plugin-pwa' export default defineConfig({ plugins: [ VitePWA({ registerType: 'autoUpdate', workbox: { clientsClaim: true, skipWaiting: true } }) ] }) ``` ::: If you want to check it in `dev`, add the `devOptions` option to the plugin configuration (you will have the [Web App Manifest][webmanifest] and the generated service worker): ```ts import { VitePWA } from 'vite-plugin-pwa' export default defineConfig({ plugins: [ VitePWA({ registerType: 'autoUpdate', devOptions: { enabled: true } }) ] }) ``` If you build your application, the [Web App Manifest][webmanifest] will be generated and configured on the application entry point, the service worker will be also generated and the script/module to register it in the browser added. ::: info `vite-plugin-pwa` plugin uses [workbox-build](https://developer.chrome.com/docs/workbox/modules/workbox-build) node library to build the service worker, you can find more information in the [Service Worker Strategies And Behaviors](/guide/service-worker-strategies-and-behaviors) and [Workbox](/workbox/) sections. ::: [webmanifest]: https://developer.mozilla.org/en-US/docs/Web/Manifest --- --- url: /assets-generator.md --- # Getting Started [@vite-pwa/assets-generator](https://github.com/vite-pwa/assets-generator) will generate all the icons required for your PWA application using [sharp](https://github.com/lovell/sharp/) and [sharp-ico](https://github.com/ssnangua/sharp-ico) packages. This package has been developed based on the work done in [Elk PWA Icon Generator Script](https://github.com/elk-zone/elk/blob/main/scripts/generate-pwa-icons.ts). With a single image source you can generate all the required icons for your PWA application, via `@vite-pwa/assets-generator` [CLI](/assets-generator/cli) or [API](/assets-generator/api). ## Source images We strongly recommend using SVG images as source images, as they will be resized to the required sizes without losing quality, but should also work with any image type. The svg sources can also be used in for the favicon html head link. ## PWA Minimal Icons Requirements As pointed out in [PWA Minimal Requirements](/guide/pwa-minimal-requirements), you will need: * a 192x192 icon (PWA Manifest icon) * a 512x512 icon (PWA Manifest icon) * a 180x180 icon for iOS/MacOS (html head link: ``) We also suggest you to include: * A 64x64 icon for Windows (Edge) (PWA Manifest icon) * A 512x512 icon for Android with `purpose: 'any'` (PWA Manifest icon) * Avoid using `purpose: 'any maskable'` icon, as it is not supported by all browsers * An `favicon.ico` and `favicon.svg`, check [Preset Minimal 2023](#preset-minimal-2023) for more details ### Preset Minimal 2023 Refer to [Definitive edition of "How to Favicon" in 2023](https://dev.to/masakudamatsu/favicon-nightmare-how-to-maintain-sanity-3al7) for more details. Our minimal recommendation is: * transparent 48x48 ico: register it in the html head: `` * Use SVG image as source image: register it in the html head: `` * transparent 64x64 icon (PWA Manifest icon) * transparent 192x192 icon (PWA Manifest icon) * transparent 512x512 icon with `purpose: 'any'` (PWA Manifest icon) * white 512x512 icon with `purpose: 'maskable'` (PWA Manifest icon): background color can be customized to your needs * white 180x180 icon for iOS/MacOS (html head link: ``): background color can be customized to your needs ### Preset Minimal Our minimal recommendation is: * transparent 64x64 ico: register it in the html head: `` * Use SVG image as source image: register it in the html head: `` * transparent 64x64 icon (PWA Manifest icon) * transparent 192x192 icon (PWA Manifest icon) * transparent 512x512 icon with `purpose: 'any'` (PWA Manifest icon) * white 512x512 icon with `purpose: 'maskable'` (PWA Manifest icon): background color can be customized to your needs * white 180x180 icon for iOS/MacOS (html head link: ``): background color can be customized to your needs ## Example using minimal preset You can generate icons using the `minimal-2023` preset included in [@vite-pwa/assets-generator](https://github.com/vite-pwa/assets-generator) package via a source image, check out the [CLI](/assets-generator/cli) and [API](/assets-generator/api) documentation for more details. Update your PWA manifest icons entry with: ```ts icons: [ { src: 'pwa-64x64.png', sizes: '64x64', type: 'image/png' }, { src: 'pwa-192x192.png', sizes: '192x192', type: 'image/png' }, { src: 'pwa-512x512.png', sizes: '512x512', type: 'image/png', purpose: 'any' }, { src: 'maskable-icon-512x512.png', sizes: '512x512', type: 'image/png', purpose: 'maskable' } ] ``` and use the following HTML head entries in your entry point: ### Using Preset Minimal 2023 ```html ``` ### Using Preset Minimal ```html ``` --- --- url: /workbox.md --- # Getting Started [**Workbox**](https://developer.chrome.com/docs/workbox/) is a massive package with many modules to make service worker development more enjoyable and remove the need to deal with the low-level service worker API. In this document, we focus only on the [workbox-build](https://developer.chrome.com/docs/workbox/modules/workbox-build) module from **Workbox**. :::warning From version `0.16.0`, `vite-plugin-pwa` has been updated to use latest `workbox` version `7.0.0` that requires Node 16 or above. ::: :::tip From version `0.20.2`, the plugin will throw an error if the `maximumFileSizeToCacheInBytes` warning is present when building the service worker. ::: ## workbox-build module This module is for build process purposes (a `node` module); that is, `Vite Plugin PWA` will use it to build your service-worker. We focus on 2 methods of this module: * [generateSW](/workbox/generate-sw): for generating the service worker. * [injectManifest](/workbox/inject-manifest): for when you need more control over your service worker. You should read [Which Mode to Use](https://developer.chrome.com/docs/workbox/modules/workbox-build/#which-mode-to-use) before deciding which strategy to use. In short, the `generateSW` function abstracts away the need to work directly with the service worker API when building the service worker. This method can be configured using plugins instead of writing your own service worker code (`generateSW` will generate the code for you). While the `injectManifest` method will use your existing service worker and build/compile it. ## How is `workbox-build` related to `vite-plugin-pwa`? `vite-plugin-pwa` uses `generateSW` and `injectManifest` Workbox methods internally when the `strategies` option is set to `generateSW` and `injectManifest` respectively. When you configure `strategies: 'generateSW'` option (the default value) in your `vite.config.*` file, the plugin invokes workbox' `generateSW` method. The options passed to the `workbox-build` method will be those provided via the `workbox` option of the plugin configuration. When you configure `strategies: 'injectManifest'` option, the plugin will first build your custom service worker via custom `Vite` build. With the build result, vite-plugin-pwa will call Workbox's `injectManifest` method passing those options provided via the `injectManifest` option of the plugin configuration. --- --- url: /examples/iles.md --- # îles You can test `îles` using the source code from its documentation website, you can find it under [docs](https://github.com/ElMassimo/iles/tree/main/docs) package/directory. The behavior used in this website is [Prompt for update](/guide/prompt-for-update). --- --- url: /frameworks/iles.md --- # îles We have included the integration with `îles` on their repo, adding `@islands/pwa` module. You can find the documentation here: * [@islands/pwa](https://iles-docs.netlify.app/guide/plugins#islandspwa) * [Progressive Web Application (PWA)](https://iles-docs.netlify.app/guide/pwa) --- --- url: /workbox/inject-manifest.md --- # injectManifest You must read [Which Mode to Use](https://developer.chrome.com/docs/workbox/modules/workbox-build/#which-mode-to-use) before decide using this strategy on `vite-plugin-pwa` plugin. Before writing your custom service worker, check if `workbox` can generate the code for you using `generateSW` strategy, looking for some plugin on `workbox` site on [Runtime Caching Entry](https://developer.chrome.com/docs/workbox/modules/workbox-build#type-RuntimeCaching). You can find the documentation for this method on `workbox` site: [injectManifest](https://developer.chrome.com/docs/workbox/modules/workbox-build#method-injectManifest) :::warning From version `0.15.0`, `vite-plugin-pwa` builds your custom service worker using Vite instead of Rollup: configured Vite plugins were reused in the service worker build, which could lead to the generation of bad code in service worker. If you are using any Vite plugin logic within your custom service worker, you need to add those plugins twice, for the development server and the build process: * Vite plugins * `vite-plugin-pwa` plugin options: `injectManifest.plugins` `vite-plugin-pwa` now uses the same approach as Vite to build [WebWorkers](https://vitejs.dev/config/worker-options.html#worker-plugins). ::: ## Exclude routes To exclude some routes from being intercepted by the service worker, you just need to add those routes using a `regex` array to the `denylist` option of `NavigationRoute`: ```ts import { createHandlerBoundToURL, precacheAndRoute } from 'workbox-precaching' import { NavigationRoute, registerRoute } from 'workbox-routing' declare let self: ServiceWorkerGlobalScope // self.__WB_MANIFEST is default injection point precacheAndRoute(self.__WB_MANIFEST) // to allow work offline registerRoute(new NavigationRoute( createHandlerBoundToURL('index.html'), { denylist: [/^\/backoffice/] }, )) ``` ::: warning You must deal with offline support for excluded routes: if requesting a page included on `denylist` you will get `No internet connection`. ::: ## Network First Strategy You can use the following code to create your custom service worker to be used with network first strategy. We also include how to configure [Custom Cache Network Race Strategy](https://jakearchibald.com/2014/offline-cookbook/#cache--network-race). ::: details VitePWA options ```ts VitePWA({ strategies: 'injectManifest', srcDir: 'src', filename: 'sw.ts' }) ``` ::: ::: warning You also need to add the logic to interact from the client logic: [Advanced (injectManifest)](/guide/inject-manifest). ::: Then in your `src/sw.ts` file, remember you will also need to add following `workbox` dependencies as `dev` dependencies: * `workbox-core` * `workbox-routing` * `workbox-strategies` * `workbox-build` ::: details src/sw.ts ```ts import type { ManifestEntry } from 'workbox-build' import type { StrategyHandler } from 'workbox-strategies' import { cacheNames, clientsClaim } from 'workbox-core' import { registerRoute, setCatchHandler, setDefaultHandler } from 'workbox-routing' import { NetworkFirst, NetworkOnly, Strategy } from 'workbox-strategies' // Give TypeScript the correct global. declare let self: ServiceWorkerGlobalScope declare type ExtendableEvent = any const data = { race: false, debug: false, credentials: 'same-origin', networkTimeoutSeconds: 0, fallback: 'index.html' } const cacheName = cacheNames.runtime function buildStrategy(): Strategy { if (race) { class CacheNetworkRace extends Strategy { _handle(request: Request, handler: StrategyHandler): Promise { const fetchAndCachePutDone: Promise = handler.fetchAndCachePut(request) const cacheMatchDone: Promise = handler.cacheMatch(request) return new Promise((resolve, reject) => { fetchAndCachePutDone.then(resolve).catch((e) => { if (debug) console.log(`Cannot fetch resource: ${request.url}`, e) }) cacheMatchDone.then(response => response && resolve(response)) // Reject if both network and cache error or find no response. Promise.allSettled([fetchAndCachePutDone, cacheMatchDone]).then((results) => { const [fetchAndCachePutResult, cacheMatchResult] = results if (fetchAndCachePutResult.status === 'rejected' && !cacheMatchResult.value) reject(fetchAndCachePutResult.reason) }) }) } } return new CacheNetworkRace() } else { if (networkTimeoutSeconds > 0) return new NetworkFirst({ cacheName, networkTimeoutSeconds }) else return new NetworkFirst({ cacheName }) } } const manifest = self.__WB_MANIFEST as Array const cacheEntries: RequestInfo[] = [] const manifestURLs = manifest.map( (entry) => { const url = new URL(entry.url, self.location) cacheEntries.push(new Request(url.href, { credentials: credentials as any })) return url.href } ) self.addEventListener('install', (event: ExtendableEvent) => { event.waitUntil( caches.open(cacheName).then((cache) => { return cache.addAll(cacheEntries) }) ) }) self.addEventListener('activate', (event: ExtendableEvent) => { // - clean up outdated runtime cache event.waitUntil( caches.open(cacheName).then((cache) => { // clean up those who are not listed in manifestURLs cache.keys().then((keys) => { keys.forEach((request) => { debug && console.log(`Checking cache entry to be removed: ${request.url}`) if (!manifestURLs.includes(request.url)) { cache.delete(request).then((deleted) => { if (debug) { if (deleted) console.log(`Precached data removed: ${request.url || request}`) else console.log(`No precache found: ${request.url || request}`) } }) } }) }) }) ) }) registerRoute( ({ url }) => manifestURLs.includes(url.href), buildStrategy() ) setDefaultHandler(new NetworkOnly()) // fallback to app-shell for document request setCatchHandler(({ event }): Promise => { switch (event.request.destination) { case 'document': return caches.match(fallback).then((r) => { return r ? Promise.resolve(r) : Promise.resolve(Response.error()) }) default: return Promise.resolve(Response.error()) } }) // this is necessary, since the new service worker will keep on skipWaiting state // and then, caches will not be cleared since it is not activated self.skipWaiting() clientsClaim() ``` ::: ## Server Push Notifications You should check the `workbox` documentation: [Introduction to push notifications](https://web.dev/explore/notifications). You can check this awesome repo [Elk](https://github.com/elk-zone/elk) using `Server Push Notifications` and some other cool service worker capabilities like [Web Share Target API](https://developer.chrome.com/docs/capabilities/web-apis/web-share-target): using `Nuxt 3` and `vite-plugin-pwa`. ## Background Sync You should check the `workbox` documentation: check [Introducing to Background Sync](https://developer.chrome.com/blog/background-sync/). You can check this awesome repo [YT Playlist Notifier](https://github.com/jeffposnick/yt-playlist-notifier) using `Background Sync` and some other cool service worker capabilities from the major collaborator of [Workbox](https://developer.chrome.com/docs/workbox/). --- --- url: /assets-generator/integrations.md --- # Integrations Starting with `v0.19.0`, `vite-plugin-pwa` provides experimental support for the following `@vite-pwa/assets-generator` integrations for serving, generating, and injecting PWA assets on the fly: * Inlined or external file configuration support * Generate PWA assets on demand in dev server and build from single image file * Auto-inject PWA assets in your HTML entry point * Auto-inject `theme-color` meta tag in your HTML entry point, it will be extracted from your web manifest `theme_color` property * Auto-inject web manifest icons The new experimental feature must be enabled explicitly in your `vite-plugin-pwa` configuration with the `pwaAssets` option. This can be done by either: * using an inlined preset or * using an external configuration file (will take precedence over inlined preset) You can find a working example in the [examples/assets-generator](https://github.com/vite-pwa/vite-plugin-pwa/tree/main/examples/assets-generator) folder. :::warning This feature is experimental and is subject to (potentially breaking) changes without notice. Please [file a GitHub Issue](https://github.com/vite-pwa/vite-plugin-pwa/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc) for any bugs you may find. ::: ## Installation To use the new feature, install the `@vite-pwa/assets-generator` package as a dev dependency: ::: code-group ```bash [pnpm] pnpm add -D @vite-pwa/assets-generator ``` ```bash [yarn] yarn add -D @vite-pwa/assets-generator ``` ```bash [npm] npm install -D @vite-pwa/assets-generator ``` ::: ## Configuration We recommend using an external `pwa-assets.config.js` or `pwa-assets.config.ts` file. The `vite-plugin-pwa` plugin will watch it for changes to avoid dev server restarts. You can still use inline inside your `vite.config.js` file. This will cause Vite to restart the dev server when changing any option. To use the new feature, you only need to configure the new `pwaAssets` option in your PWA configuration: ```ts import { VitePWA } from 'vite-plugin-pwa' export default defineConfig({ plugins: [ VitePWA({ // other pwa options // pwa assets pwaAssets: { // options } }) ] }) ``` Check the [PWA Assets Options](#pwa-assets-options) section for further details. ## Integrations ### îles WIP ### SvelteKit `@vite-pwa/sveltekit` plugin will configure `integration` option properly. We suggest you to use external configuration file, SvelteKit dev server will not be restarted when changing the configuration. Check the [SvelteKit PWA Assets](/frameworks/sveltekit#pwa-assets) section for more details. ### VitePress `@vite-pwa/vitepress` plugin will configure `integration` option properly. VitePress dev server will be restarted when changing the configuration (inlined or using external file). Check the [VitePress PWA Assets](/frameworks/vitepress#pwa-assets) section for more details. ### Astro `@vite-pwa/astro` plugin will configure `integration` option properly. We suggest you to use external configuration file, Astro dev server will not be restarted when changing the configuration. Check the [Astro PWA Assets](/frameworks/astro#pwa-assets) section for more details. ### Nuxt 3 `@vite-pwa/nuxt` plugin will configure `integration` option properly. Nuxt dev server will be restarted when changing the configuration (inlined or using external file). Check the [Nuxt 3 PWA Assets](/frameworks/nuxt#pwa-assets) section for more details about new components, composables and injections. ### Remix Vite dev server will be restarted when changing the configuration (inlined or using external file). Check the [Remix PWA Assets](/frameworks/remix#pwa-assets) section for more details about the components. ## New Virtual Modules `vite-plugin-pwa` plugin exposes two new virtual modules for the integrations, they are not meant to be consumed from your application: * `virtual:pwa-assets/head`: will expose PWA image links and the `theme-color` meta tag * `virtual:pwa-assets/icons`: will expose PWA web manifest icons If you're using TypeScript in your application, you can add `vite-plugin-pwa/pwa-assets` to your `tsconfig.json` file to avoid TypeScript errors: ```json { "compilerOptions": { "types": [ "vite-plugin-pwa/pwa-assets" ] } } ``` You can also add the following reference to the beginning of your application code: ```ts /// ``` You can find the virtual modules types in the [pwa-assets.d.ts](https://github.com/vite-pwa/vite-plugin-pwa/tree/main/pwa-assets.d.ts) file. ## PWA Assets Options ```ts /** * PWA assets generation and injection options. */ export interface PWAAssetsOptions { /** * Enable PWA assets generation and injection. * * @default false */ disabled?: boolean /** * PWA assets generation and injection. * * By default, the plugin will search for the pwa assets generator configuration file in the root directory of your project: * - pwa-assets.config.js * - pwa-assets.config.mjs * - pwa-assets.config.cjs * - pwa-assets.config.ts * - pwa-assets.config.cts * - pwa-assets.config.mts * * If using a string path, it should be relative to the root directory of your project. * * Setting to `false` will disable config resolving. * * **WARNING**: You can use only one image in the configuration file. * * @default false * @see https://vite-pwa-org.netlify.app/assets-generator/cli.html#configurations */ config?: string | boolean /** * Preset to use. * * If the `config` option is enabled, this option will be ignored. * * Setting this option to `false` will disable PWA assets generation (if the `config` option is also disabled). * * @default 'minimal-2023' */ preset?: false | BuiltInPreset | Preset /** * Path relative to `root` folder where to find the image to use for generating PWA assets. * * If the `config` option is enabled, this option will be ignored. * * @default `public/favicon.svg` */ image?: string /** * The preset to use for head links (favicon links). * * If `config` option is enabled, this option will be ignored. * * @see https://vite-pwa-org.netlify.app/assets-generator/#preset-minimal-2023 * @see https://vite-pwa-org.netlify.app/assets-generator/#preset-minimal * @default '2023' */ htmlPreset?: HtmlLinkPreset /** * Should the plugin include html head links? * * @default true */ includeHtmlHeadLinks?: boolean /** * Should the plugin override the PWA web manifest icons' entry? * * The plugin will auto-detect the icons from the manifest, if missing, then the plugin will ignore this option and will include the icons. * * @default false */ overrideManifestIcons?: boolean /** * Should the PWA web manifest `theme_color` be injected in the html head? * * @default true */ injectThemeColor?: boolean /** * PWA Assets integration support. * * This option should be only used by integrations, it is not meant to be used by end users. */ integration?: { /** * The base url for the PWA assets. * * @default `vite.base` */ baseUrl?: string /** * The public directory to resolve the image: should be an absolute path. * * @default `vite.root/vite.publicDir` */ publicDir?: string /** * The output directory: should be an absolute path. * * @default `vite.root/vite.build.outDir` */ outDir?: string } } ``` --- --- url: /frameworks/laravel.md --- # Laravel ## Introduction Using `vite-plugin-pwa` in a Laravel project is made complex by Laravel being a mix of backend and frontend concepts. For example, * Laravel has its own public dir inside the webserver's webroot. This means Vite builds to `/path/to/webroot/public/build/assets`. This different to the usual frontend layout, where `/build/assets` would be in the webroot. * There isn't a default static HTML entrypoint for the PWA. Laravel builds this server-side. The resulting HTML has a `
` into which the Vue app is instantiated. * Laravel will put other things (like [Telescope](https://laravel.com/docs/12.x/telescope)) in the public dir that you do not want offline. * Laravel has its own [plugin for Vite](https://github.com/laravel/vite-plugin) for builds, which adds an extra layer of configuration that vite-pwa does not normally encounter. To make it work, you need to configure vite-plugin-pwa to work around these issues: * configure buildBase and outDir in vite.config.ts to make vite-pwa build to the same place as laravel/vite-plugin. * create a Blade file to act as an HTML entrypoint and add config for this to vite.config.ts. * Add a Service-Worker-Allowed header to your web server to work around the restrictions imposed by the build directory being in a subdir of the webroot. * Configuring caching in vite.config.ts to work around other assets being in the public dir that you do not want to be offline. ## History There's a detailed GitHub issue exploring this problem here: https://github.com/vite-pwa/vite-plugin-pwa/issues/431 The accumulated knowledge within it lead to a Laravel, Vite, Vue3 and TypeScript app working as a PWA with offline support and app install prompts. The issue was asking for a demonstration repository so a repo above was created to share it. It is available here: https://github.com/sfreytag/laravel-vite-pwa ## What's Included The repo above demonstrates a working PWA with install prompts and offline support within Laravel using Vue3, Vite and Typescript. The useful things are: * A [vite.config.ts](https://github.com/sfreytag/vite-pwa-docs/blob/main/vite.config.ts) with settings for `vite-plugin-pwa` that work with Laravel's directory layout * A [Blade template](https://github.com/sfreytag/laravel-vite-pwa/blob/main/resources/views/welcome.blade.php) that works as the entrypoint for the PWA * A [generator for the PWA icons](https://github.com/sfreytag/laravel-vite-pwa/blob/main/package.json#L7) * A [server.php](https://github.com/sfreytag/laravel-vite-pwa/blob/main/server.php) file that supplies the sw.js and the Service-Worker-Allowed header for `php artisan serve` for local development (see [lines 18:23](https://github.com/sfreytag/laravel-vite-pwa/blob/main/server.php#L18-L23)) * A composable [usePwa](https://github.com/sfreytag/laravel-vite-pwa/blob/main/resources/js/composables/usePwa/index.ts) that demonstrates how to access the `vite-plugin-pwa` functionality within Vue3 and TypeScript (eg install and update hooks, online/offline status) * A [PwaStatus component](https://github.com/sfreytag/laravel-vite-pwa/blob/main/resources/js/components/PwaStatus.vue) that shows how it all works * TypeScript [types for the install event](https://github.com/sfreytag/laravel-vite-pwa/blob/main/resources/js/composables/usePwa/types.ts) ## Setup The repo has been built on a vanilla install of Laravel 10 using composer from `composer create-project laravel/laravel`. To add the PWA to your own Laravel project you can review the changes required to set up `vite-plugin-pwa`: * Work through the commit history, which builds it up step-by-step * Or view the entire diff of the HEAD against the vanilla Laravel install: https://github.com/sfreytag/laravel-vite-pwa/compare/a59497..HEAD Or just fork the repo and start from there. ## Build To build the repo, follow the usual Laravel steps. Nothing extra is required for `vite-plugin-pwa`. Assuming you have PHP, NPM and Composer: ``` git clone git@github.com:sfreytag/laravel-vite-pwa.git cd laravel-vite-pwa composer install cp .env.example .env php artisan key:generate npm install npm run build ``` ## Run Before you run it, bear in mind that the PWA installs a service worker and fills a cache. This can conflict with other service workers and caches from your other localhost projects. So it is recommended to use a port unique to each PWA project. To use eg 8082 for Laravel: ``` php artisan serve --port=8082 ``` The app should now be running on `http://localhost:8082`. It should immediately work as a PWA. If you check the dev tools, the service worker should be running. If your browser supports it there will be an intall prompt in the address bar. It should then be installable. And if you use dev tools to take either the network or service worker offline, it should continue working if you reload the page. ## Working on the PWA The PWA is configured to only work with prod builds, rather than dev. This is straightforward to work with and helps stop the PWA offline cache get in the way of refreshing your build during the dev cycle. However this might not suit everyone. It would be a good PR to submit to this repo to get the PWA working with a dev build. In the meantime, before running the PWA and when making changes, to be sure you have the latest version of it, ensure you use: ``` npm run build ``` ## PWA Icons The repo uses [@vite-pwa/assets-generator](https://github.com/vite-pwa/assets-generator) for its icons. The canonical icon should be an SVG file. This is useful for the PWA anyway, so it can be saved in `public/favicon.svg`. Then build the other icons from it by running: ``` npm run pwa-icons ``` This generates a set of icons defined by the minimal preset described [here](/assets-generator/cli.html#presets). They are automatically packaged in the public folder so they are web readable. They are also included in the repo so this process only needs repeating if you change the canonical `favicon.svg` icon. --- --- url: /assets-generator/migrations.md --- # Migrations When migrating from one version to a new one, you should remove all the PWA assets generated previously and generate them again after upgrading `@vite-pwa/assets-generator` package. :::warning If you're using some of the old PWA assets in your application, **don't remove them**. ::: Remember to check the changes before upgrading to a new version in your local environment: * start the current version in your local server, opening your application to check the old PWA assets * upgrade the package to the new version and regenerate the PWA assets * start the new version in your local server, refresh your application to check the new PWA assets ## From `v0.1.0` to `v0.2.0` The `api` and the core has been built from scratch, the CLI has been rebuilt on top of the API. The main changes included in version `v0.2.0` are: * `generatePWAImageAssets` and `generatePWAAssets` functions have been removed from `@vite-pwa/assets-generator` package export: now the package only export types and some utilities. * new `@vite-pwa/assets-generator/api/instructions` package export: new `instructions` function to collect the icon assets instructions. * new `@vite-pwa/assets-generator/api/generate-assets` package export: new `generateAssets` function to generate icon assets from an instruction. * new `@vite-pwa/assets-generator/api/generate-html-markup` package export: new `generateHtmlMarkup` function to generate all html head links from an instruction. * new `@vite-pwa/assets-generator/api/generate-manifest-icons-entry` package export: new `generateManifestIconsEntry` function to generate the PWA web manifest icons' entry. * new CLI options for html head links generation: `xhtml` and `includeId`. If you are using `generatePWAImageAssets` and/or `generatePWAAssets` functions, you need to update your code to use the new `instructions` and `generateAssets` functions. If you're only using the CLI, you don't need to change anything. For more details about the new version `v0.2.0`, check [this comment](https://github.com/vite-pwa/assets-generator/issues/20#issuecomment-1848382903) in the repository. ## From `minimal` to `minimal-2023` Preset If you are using `pwa-assets-generator` in your `package.json` scripts, update the script from: ```json "generate-assets": "pwa-assets-generator --preset minimal " ``` to: ```json "generate-assets": "pwa-assets-generator --preset minimal-2023 " ``` If you are using a configuration file: * update the built-in preset name or update the import to use `minimal2023Preset`: check the code snippets in the [built-in features section](/assets-generator/cli#built-in-features). * include `headLinkOptions.preset = '2023'` in you configuration file The new `minimal-2023` preset changes only the `favicon.ico` size, the `apple-touch-icon` and PWA manifest icons are the same, you need to update your html head favicon entries, from: ```html ``` to: ```html ``` --- --- url: /deployment/netlify.md --- # Netlify ## Configure `manifest.webmanifest` mime type You need to register the correct MIME type for the web manifest by adding a headers table to your `netlify.toml` file (see basic deployment below): ```toml [[headers]] for = "/manifest.webmanifest" [headers.values] Content-Type = "application/manifest+json" ``` ## Cache-Control As a general rule, files in `/assets/` can have a very long cache time, as everything in there should contain a hash in the filename. Add another headers table to your `netlify.toml` file (see basic deployment below): ```toml [[headers]] for = "/assets/*" [headers.values] cache-control = ''' max-age=31536000, immutable ''' ``` ## Configure http to https redirection Netlify will redirect automatically, so you don't worry about it. ## Basic deployment example Add `netlify.toml` file to the root directory with the content: ```toml [build] publish = "dist" command = "pnpm run build" [[redirects]] from = "/*" to = "/index.html" status = 200 [[headers]] for = "/manifest.webmanifest" [headers.values] Content-Type = "application/manifest+json" [[headers]] for = "/assets/*" [headers.values] cache-control = ''' max-age=31536000, immutable ''' ``` --- --- url: /deployment/nginx.md --- # NGINX ## Configure `manifest.webmanifest` mime type You need to register the correct MIME type for the web manifest by adding it either to the [default](https://www.nginx.com/resources/wiki/start/topics/examples/full/#mime-types) file at `/etc/nginx/mime.types` ```nginx # /etc/nginx/mime.types types { # Manifest files application/manifest+json webmanifest; ... } ``` or any `http`, `server` or location `location` block with ```nginx include mime.types; types { application/manifest+json webmanifest; } ``` You can validate the setting by checking the HTTP headers once the app is deployed ```shell script curl -s -I -X GET https://yourserver/manifest.webmanifest | grep content-type -i ``` and check that the result is `content-type: application/manifest+json`. ## Basic configuration with http to https redirection Update your `server.conf` configuration file with: ```nginx server { listen 80; server_name yourdomain.com www.yourdomain.com; return 301 https://yourdomain.com$request_uri; } ``` ## Cache-Control Ensure you have a very restrictive setup for your `Cache-Control` headers in place. Double check that **you do not** have caching features enabled, especially `immutable`, on locations like: * `/` * `/sw.js` * `/index.html` * `/manifest.webmanifest` NGINX will add `E-Tag`-headers itself, so there is not much to in that regard. As a general rule, files in `/assets/` can have a very long cache time, as everything in there should contain a hash in the filename. An example configuration inside your `server` block could be: ```nginx # all assets contain hash in filename, cache forever location ^~ /assets/ { add_header Cache-Control "public, max-age=31536000, s-maxage=31536000, immutable"; ... try_files $uri =404; } # all workbox scripts are compiled with hash in filename, cache forever location ^~ /workbox- { add_header Cache-Control "public, max-age=31536000, s-maxage=31536000, immutable"; ... try_files $uri =404; } # assume that everything else is handled by the application router, by injecting the index.html. location / { autoindex off; expires off; add_header Cache-Control "public, max-age=0, s-maxage=0, must-revalidate" always; ... try_files $uri /index.html =404; } ``` Be aware that this is a very simplistic approach and you must test every change, as the NGINX match precedences for locations are not very intuitive and error prone if you do not know the [exact rules](https://docs.nginx.com/nginx/admin-guide/web-server/web-server/#location_priority). ::: danger **Always re-test and re-assure** that the caching for mission critical files is **as low** as possible if not hashed files or you might invalidate clients for a long time. ::: --- --- url: /examples/nuxt.md --- # Nuxt 3 You need to stop the dev server once started and then to see the PWA in action run: * `nr dev:preview:build`: Nuxt build command + start server * `nr dev:preview:generate`: Nuxt generate command + start server ::: info WIP You can also check [Elk repo](https://github.com/elk-zone/elk) for a real world example: we're working to update the repo. Elk repo is using `Push Notifications` and `Web Share Target API` PWA capabilities and `Prompt for update` register type via `injectManifest` strategy. ::: --- --- url: /frameworks/nuxt.md --- # Nuxt 3 ::: warning This PWA module can only be used with Vite. ::: ## Nuxt 3 Integration `vite-plugin-pwa` provides the new `@vite-pwa/nuxt` module that will allow you to use `vite-plugin-pwa` in your Nuxt 3 applications. You will need to install `@vite-pwa/nuxt` using: ```shell npx nuxi@latest module add @vite-pwa/nuxt ``` To update your project to use the new `@vite-pwa/nuxt` module for Nuxt 3, you only need to change the Nuxt config file adding the `@vite-pwa/nuxt` module, move the `vite-plugin-pwa` options to the module options, and remove the `vite-plugin-pwa` plugin (if present): ```ts export default defineNuxtConfig({ modules: ['@vite-pwa/nuxt'], pwa: { /* your pwa options */ } }) ``` ## Using Nuxt 3 Plugin `@vite-pwa/nuxt` will register a plugin that will provide PWA logic via `$pwa` property when the PWA is enabled (`$pwa` will be `undefined` if PWA disabled or running dev server without PWA dev options enabled). You can access `$pwa` property directly inside your Vue component templates. You can also access to `$pwa` in your Vue script setup or in any other module via `useNuxtApp().$pwa`. The module will provide the following features via `$pwa` property: * Prompt for update and offline ready via `needRefresh` and `offlineReady` properties. * Cancelling prompt for update application and offline via `closePrompt` function. * Update application when using `prompt for update` behaviour via `updateServiceWorker` function. * Intercepting `beforeinstallprompt` event via `showInstallPrompt` property: this feature will prevent the browser to show the default `Install PWA Application` prompt. * Cancelling install prompt via `cancelInstall` function. * `Install PWA application` via `install` function. * Service worker registration status via `swActivated` and `registrationError` properties. * Service worker registration via `getSWActivated` function. You will need to activate `pwa.client.installPrompt` property in your Nuxt config file to enable `beforeinstallprompt` event interception: configure `true` or the key name used in local storage to store the `beforeinstallprompt` cancellation for your install prompt/widget. Additionally, you can also configure periodic sync for updates, you can enable it via `pwa.client.periodicSyncForUpdates` property in your Nuxt config file: configure the interval in seconds in previous property. You can disable this plugin by setting `pwa.client.registerPlugin` property to `false` in your Nuxt config file. In that case, you will need to import `VanillaJS` or `Vue` PWA virtual module in your application, and previous features will not be available (you can only access to the features exposed by the virtual module). ::: info This is the initial release of `@vite-pwa/nuxt` integration, we're working to improve it and add more features. ::: ### PWA Installation Status `@vite-pwa/nuxt` provides the new `$pwa?.isPWAInstalled` reactive property to check if your PWA application is installed. ## Registering Web Manifest To register the PWA web manifest in your Nuxt 3 application, `@vite-pwa/nuxt` provides the functional components `VitePwaManifest` and `NuxtPwaManifest`, you should add one of them to your `app.vue` or to all of your layouts (add only `VitePwaManifest` or `NuxtPwaManifest`). ::: tip You can enable `registerWebManifestInRouteRules` property in PWA configuration to register the web manifest in Nitro `routeRules` property: useful for example if your application is deployed to Netlify. ::: ## Payload Extraction When you enable the experimental `payloadExtraction` flag in your Nuxt configuration file, `@vite-pwa/nuxt` will add `**/_payload.json` to the `globPatterns` array inside `workbox` or `injectManifest` option, depending on the configured `strategy`. ## App Manifest When you enable the experimental `appManifest` flag in your Nuxt configuration file, `@vite-pwa/nuxt` will: * add `_nuxt/builds/**/*.json` to the `globPatterns` array inside `workbox` or `injectManifest` option, depending on the configured `strategy` * remove `revision` entry from all service worker precache manifest files inside `_nuxt/builds/` folder matching `.json` pattern ([UUID](https://en.wikipedia.org/wiki/Universally_unique_identifier) is a random generated string by Nuxt). ## TypeScript ```ts export interface PwaInjection { /** * @deprecated use `isPWAInstalled` instead */ isInstalled: boolean /** * From version v0.3.5+. */ isPWAInstalled: Ref showInstallPrompt: Ref cancelInstall: () => void install: () => Promise swActivated: Ref registrationError: Ref offlineReady: Ref needRefresh: Ref updateServiceWorker: (reloadPage?: boolean | undefined) => Promise cancelPrompt: () => Promise getSWRegistration: () => ServiceWorkerRegistration | undefined } declare module '#app' { interface NuxtApp { $pwa: UnwrapNestedRefs } } ``` ## Examples ### VitePwaManifest/NuxtPwaManifest in app.vue When adding `VitePwaManifest` or `NuxtPwaComponent` component to your `app.vue`: ```vue ``` or ```vue ``` then, the web manifest link will be added to your HTML pages: ```html ``` ### Prompt for update and offline ready ```vue ``` ## PWA Assets This new feature includes: * new `NuxtPwaAssets` component to include the PWA assets in your HTML pages: if you're using `VitePwaManifest` or `NuxtPwaManifest` component, replace it with `NuxtPwaAssets`: it will inject the web manifest link, the `theme-color` meta and the PWA icon links. * new `PwaAppleImage`, `PwaAppleSplashScreenImage`, `PwaFaviconImage`, `PwaMaskableImage` and `PwaTransparentImage` components to use PWA icons in your code base * new `useApplePwaIcon`, `useAppleSplashScreenPwaIcon`, `useFaviconPwaIcon`, `useMaskablePwaIcon` and `useTransparentPwaIcon` composables * injects `$pwaIcons` with all configured PWA icons: you can use them via `useNuxtApp().$pwaIcons` or inside your Vue templates New components, composables and `$pwaIcons` injection are statically analisable, that's, pwa icons types are generated when running `nuxt prepare` command: if you want to disable the PWA assets you don't need to remove the code (you can remove unused components/code later if you want to remove the new feature). --- --- url: /guide/periodic-sw-updates.md --- # Periodic Service Worker Updates :::info If you're not importing any of the virtual modules provided by `vite-plugin-pwa` you'll need to figure out how to configure it, it is out of the scope of this guide. ::: As explained in [Manual Updates](https://web.dev/articles/service-worker-lifecycle#manual_updates) entry in [The Service Worker Lifecycle](https://web.dev/articles/service-worker-lifecycle) article, you can use this code to configure periodic service worker updates on your application on your `main.ts` or `main.js`: ::: details main.ts / main.js ```ts import { registerSW } from 'virtual:pwa-register' const intervalMS = 60 * 60 * 1000 const updateSW = registerSW({ onRegistered(r) { r && setInterval(() => { r.update() }, intervalMS) } }) ``` ::: The interval must be in milliseconds, in the example above it is configured to check the service worker every hour. ## Handling Edge Cases ::: info From version `0.12.8+` we have a new option, `onRegisteredSW`, and `onRegistered` has been deprecated. If `onRegisteredSW` is present, `onRegistered` will never be called. ::: Previous script will allow you to check if there is a new version of your application available, but you will need also to deal with some edge cases like: * server is down when calling the update method * the user can go offline at any time To mitigate previous problems, use this more complex snippet: ::: details main.ts / main.js ```ts import { registerSW } from 'virtual:pwa-register' const intervalMS = 60 * 60 * 1000 const updateSW = registerSW({ onRegisteredSW(swUrl, r) { r && setInterval(async () => { if (r.installing || !navigator) return if (('connection' in navigator) && !navigator.onLine) return const resp = await fetch(swUrl, { cache: 'no-store', headers: { 'cache': 'no-store', 'cache-control': 'no-cache', }, }) if (resp?.status === 200) await r.update() }, intervalMS) } }) ``` ::: --- --- url: /examples/preact.md --- # Preact The `Preact` example project can be found on [examples/preact-router](https://github.com/vite-pwa/vite-plugin-pwa/tree/main/examples/preact-router) package/directory. The router used on this example project is [preact-router](https://github.com/preactjs/preact-router). To test `new content available`, you should rerun the corresponding script, and then refresh the page. If you are running an example with `Periodic SW updates`, you will need to wait 1 minute: ## Executing the examples ## generateSW ## injectManifest --- --- url: /frameworks/preact.md --- # Preact You can use the built-in `Vite` virtual module `virtual:pwa-register/preact` for `Preact` which will return `useState` stateful values (`useState`) for `offlineReady` and `needRefresh`. ::: warning You will need to add `workbox-window` as a `dev` dependency to your `Vite` project. ::: ## Type declarations ::: tip From version `0.14.5` you can also use types definition for preact instead of `vite-plugin-pwa/client`: ```json { "compilerOptions": { "types": [ "vite-plugin-pwa/preact" ] } } ``` Or you can add the following reference in any of your `d.ts` files (for example, in `vite-env.d.ts` or `global.d.ts`): ```ts /// ``` ::: ```ts declare module 'virtual:pwa-register/preact' { import type { StateUpdater } from 'preact/hooks' import type { RegisterSWOptions } from 'vite-plugin-pwa/types' export type { RegisterSWOptions } export function useRegisterSW(options?: RegisterSWOptions): { needRefresh: [boolean, StateUpdater] offlineReady: [boolean, StateUpdater] updateServiceWorker: (reloadPage?: boolean) => Promise } } ``` ## Prompt for update You can use this `ReloadPrompt.tsx` component: ::: details ReloadPrompt.tsx ```tsx import './ReloadPrompt.css' import { useRegisterSW } from 'virtual:pwa-register/preact' function ReloadPrompt() { const { offlineReady: [offlineReady, setOfflineReady], needRefresh: [needRefresh, setNeedRefresh], updateServiceWorker, } = useRegisterSW({ onRegistered(r) { // eslint-disable-next-line prefer-template console.log('SW Registered: ' + r) }, onRegisterError(error) { console.log('SW registration error', error) }, }) const close = () => { setOfflineReady(false) setNeedRefresh(false) } return (
{ (offlineReady || needRefresh) &&
{ offlineReady ? App ready to work offline : New content available, click on reload button to update. }
{ needRefresh && }
}
) } export default ReloadPrompt ``` ::: and its corresponding `ReloadPrompt.css` styles file: ::: details ReloadPrompt.css ```css .ReloadPrompt-container { padding: 0; margin: 0; width: 0; height: 0; } .ReloadPrompt-toast { position: fixed; right: 0; bottom: 0; margin: 16px; padding: 12px; border: 1px solid #8885; border-radius: 4px; z-index: 1; text-align: left; box-shadow: 3px 4px 5px 0 #8885; background-color: white; } .ReloadPrompt-toast-message { margin-bottom: 8px; } .ReloadPrompt-toast-button { border: 1px solid #8885; outline: none; margin-right: 5px; border-radius: 2px; padding: 3px 10px; } ``` ::: ## Periodic SW Updates As explained in [Periodic Service Worker Updates](/guide/periodic-sw-updates), you can use this code to configure this behavior on your application with the virtual module `virtual:pwa-register/preact`: ```ts import { useRegisterSW } from 'virtual:pwa-register/preact' const intervalMS = 60 * 60 * 1000 const updateServiceWorker = useRegisterSW({ onRegistered(r) { r && setInterval(() => { r.update() }, intervalMS) } }) ``` The interval must be in milliseconds, in the example above it is configured to check the service worker every hour. --- --- url: /guide/prompt-for-update.md --- # Prompt for new content refreshing ## Plugin Configuration Since this is the default behavior for the `registerType` plugin option, you don't need to configure it. ### Cleanup Outdated Caches ### Inject Manifest Source Map ### Generate SW Source Map ## Importing Virtual Modules You must include the following code on your `main.ts` or `main.js` file: ```ts import { registerSW } from 'virtual:pwa-register' const updateSW = registerSW({ onNeedRefresh() {}, onOfflineReady() {}, }) ``` You will need to: * show a prompt to the user with refresh and cancel buttons inside `onNeedRefresh` method. * show a ready to work offline message to the user with an OK button inside `onOfflineReady` method. When the user clicks the "refresh" button when `onNeedRefresh` called, then call `updateSW()` function; the page will reload and the up-to-date content will be served. In any case, when the user clicks the `Cancel` or `OK` buttons in case `onNeedRefresh` or `onOfflineReady` respectively, close the corresponding showed prompt. ### SSR/SSG --- --- url: /guide/pwa-minimal-requirements.md --- # PWA Minimal Requirements Previous steps in this guide, are the minimal requirements and configuration to create the [Web App Manifest](https://developer.mozilla.org/en-US/docs/Web/Manifest) and the service worker when you build your application, but you'll need to include more options to meet PWA Minimal Requirements. Your application **must** meet the PWA Minimal Requirements before deploying it to production or when testing your build on local: for example, when testing your PWA application on local using `LightHouse`. To make your PWA application installable (one of the requirements), you will need to modify your application entry point, add some minimal entries to your `Web App Manifest`, allow search engines to crawl all your application pages and configure your server properly (only for production, on local you can use `https-localhost` dependency and `node`). Check also the new [PWA Minimal Requirements](/assets-generator/#pwa-minimal-icons-requirements) page in the [PWA Assets Generator](/assets-generator/) section. ## Entry Point Your application entry point (usually `index.html`) **must** have the following entries in the `` section: * mobile viewport configuration * a title * a description * a favicon, check the following pages: https://dev.to/masakudamatsu/favicon-nightmare-how-to-maintain-sanity-3al7 and this old one https://www.leereamsnyder.com/blog/favicons-in-2021 * a link for `apple-touch-icon` * a link for `mask-icon` (right now there is no need to provide a `mask-icon`) * a meta entry for `theme-color` For example, a minimal configuration (you must provide all the icons and images): ```html My Awesome App ``` ## Web App Manifest Your application [Web App Manifest](https://developer.mozilla.org/en-US/docs/Web/Manifest) **must** have the following entries: * a scope: omitted here for simplicity, the `vite-plugin-pwa` plugin will use the `Vite` base option to configure it (default is `/`) * a name * a short description * a description * a `theme_color`: **must match** the configured one on `Entry Point theme-color` * an icon with `192x192` size * an icon with `512x512` size To configure the [Web App Manifest](https://developer.mozilla.org/en-US/docs/Web/Manifest), add the `manifest` entry to the `vite-plugin-pwa` plugin options. Following with the example, here a minimal configuration (you must provide all the icons and images): ```ts import { VitePWA } from 'vite-plugin-pwa' export default defineConfig({ plugins: [ VitePWA({ 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' } ] } }) ] }) ``` You can also specify `manifest: false` to disable the `Web App Manifest` generation adding your own `manifest.webmanifest/manifest.json` file to the `public` folder on your application. The `vite-plugin-pwa` has the full definition of the `Web App Manifest` options, if you want to have DX support when using your own web manifest, add the following entry to your custom web manifest (VSCode and JetBrains IDEs will use it to provide DX support): ```json { "$schema": "https://json.schemastore.org/web-manifest-combined.json" } ``` ## Icons / Images :::tip Check out the [PWA Assets Generator](/assets-generator/) to generate all the icons and images required for your PWA application. You can also use [PWA Builder Image Generator](https://www.pwabuilder.com/imageGenerator) to generate all your PWA application's icons. ::: For `manifest` icons entry, you will need to create `pwa-192x192.png`, and `pwa-512x512.png` icons. The icons specified above are the minimum required to meet PWA, that is, icons with `192x192` and `512x512` resolutions. We suggest creating a svg or png icon (if it is a png icon, with the maximum resolution possible) for your application and use it to generate your PWA icons: * [PWA Assets Generator](/assets-generator/) (recommended). * [Favicon InBrowser.App](https://favicon.inbrowser.app/tools/favicon-generator) (recommended). * [Favicon Generator](https://realfavicongenerator.net/). For `mask-icon` in the entry point, use the svg or the png used to generate the favicon package. Once generated, download the ZIP and use `android-*` icons for `pwa-*`: * use `android-chrome-192x192.png` for `pwa-192x192.png` * use `android-chrome-512x512.png` for `pwa-512x512.png` * `apple-touch-icon.png` is `apple-touch-icon.png` * `favicon.ico` is `favicon.ico` If you want you can add the `purpose: 'any maskable'` icon to the Web App Manifest, but it is better to add 2 icons with `any` and `maskable` purposes: ```ts icons: [ { src: 'pwa-192x192.png', sizes: '192x192', type: 'image/png' }, { src: 'pwa-512x512.png', sizes: '512x512', type: 'image/png' }, { src: 'pwa-512x512.png', sizes: '512x512', type: 'image/png', purpose: 'any' }, { src: 'pwa-512x512.png', sizes: '512x512', type: 'image/png', purpose: 'maskable' } ] ``` ## Search Engines You **must** add a `robots.txt` file to allow search engines to crawl all your application pages, just add `robots.txt` to the `public` folder on your application: ```txt User-agent: * Allow: / ``` :::warning `public` folder must be on the root folder of your application, not inside the `src` folder. ::: ## Server Configuration You can use the server you want, but your server **must**: * serve `manifest.webmanifest` with `application/manifest+json` mime type * serve your application over `https` * redirect from `http` to `https` You can find more information in the [Deploy](/deployment/) section. --- --- url: /frameworks/qwik.md --- # Qwik Check the [@qwikdev/pwa](https://github.com/QwikDev/pwa) repository for more details, it is still in its early stages. This repository is not using `vite-plugin-pwa` directly (maybe in a future), but it is using Workbox. --- --- url: /examples/qwik.md --- # Qwik Check the [@qwikdev/pwa](https://github.com/QwikDev/pwa) repository for more details, it is still in its early stages. This repository is not using `vite-plugin-pwa` directly (maybe in a future), but it is using Workbox. --- --- url: /examples/react.md --- # React The `React` example project can be found on [examples/react-router](https://github.com/vite-pwa/vite-plugin-pwa/tree/main/examples/react-router) package/directory. The router used on this example project is [react-router](https://reactrouter.com/). To test `new content available`, you should rerun the corresponding script, and then refresh the page. If you are running an example with `Periodic SW updates`, you will need to wait 1 minute: ## Executing the examples ## generateSW ## injectManifest --- --- url: /frameworks/react.md --- # React You can use the built-in `Vite` virtual module `virtual:pwa-register/react` for `React` which will return `useState` stateful values (`useState`) for `offlineReady` and `needRefresh`. ::: warning You will need to add `workbox-window` as a `dev` dependency to your `Vite` project. ::: ## Type declarations ::: tip From version `0.14.5` you can also use types definition for react instead of `vite-plugin-pwa/client`, you can use: ```json { "compilerOptions": { "types": [ "vite-plugin-pwa/react" ] } } ``` Or you can add the following reference in any of your `d.ts` files (for example, in `vite-env.d.ts` or `global.d.ts`): ```ts /// ``` ::: ```ts declare module 'virtual:pwa-register/react' { import type { Dispatch, SetStateAction } from 'react' import type { RegisterSWOptions } from 'vite-plugin-pwa/types' export type { RegisterSWOptions } export function useRegisterSW(options?: RegisterSWOptions): { needRefresh: [boolean, Dispatch>] offlineReady: [boolean, Dispatch>] updateServiceWorker: (reloadPage?: boolean) => Promise } } ``` ## Prompt for update You can use this `ReloadPrompt.tsx` component: :::details ReloadPrompt.tsx ```tsx import React from 'react' import './ReloadPrompt.css' import { useRegisterSW } from 'virtual:pwa-register/react' function ReloadPrompt() { const { offlineReady: [offlineReady, setOfflineReady], needRefresh: [needRefresh, setNeedRefresh], updateServiceWorker, } = useRegisterSW({ onRegistered(r) { // eslint-disable-next-line prefer-template console.log('SW Registered: ' + r) }, onRegisterError(error) { console.log('SW registration error', error) }, }) const close = () => { setOfflineReady(false) setNeedRefresh(false) } return (
{ (offlineReady || needRefresh) &&
{ offlineReady ? App ready to work offline : New content available, click on reload button to update. }
{ needRefresh && }
}
) } export default ReloadPrompt ``` ::: and its corresponding `ReloadPrompt.css` styles file: :::details ReloadPrompt.css ```css .ReloadPrompt-container { padding: 0; margin: 0; width: 0; height: 0; } .ReloadPrompt-toast { position: fixed; right: 0; bottom: 0; margin: 16px; padding: 12px; border: 1px solid #8885; border-radius: 4px; z-index: 1; text-align: left; box-shadow: 3px 4px 5px 0 #8885; background-color: white; } .ReloadPrompt-toast-message { margin-bottom: 8px; } .ReloadPrompt-toast-button { border: 1px solid #8885; outline: none; margin-right: 5px; border-radius: 2px; padding: 3px 10px; } ``` ::: ## Periodic SW Updates As explained in [Periodic Service Worker Updates](/guide/periodic-sw-updates), you can use this code to configure this behavior on your application with the virtual module `virtual:pwa-register/react`: ```ts import { useRegisterSW } from 'virtual:pwa-register/react' const intervalMS = 60 * 60 * 1000 const updateServiceWorker = useRegisterSW({ onRegistered(r) { r && setInterval(() => { r.update() }, intervalMS) } }) ``` The interval must be in milliseconds, in the example above it is configured to check the service worker every hour. --- --- url: /guide/register-service-worker.md --- # Register Service Worker `vite-plugin-pwa` plugin will register the service worker automatically for you, using the `injectRegister` configuration option (**optional**). If you want to configure the `injectRegister` plugin option: ```ts import { VitePWA } from 'vite-plugin-pwa' export default defineConfig({ plugins: [ VitePWA({ injectRegister: 'auto' }) ] }) ``` The `injectRegister` plugin configuration option, will control how to register the service worker in your application: * `inline`: injects a simple register script, inlined in the application entry point * `script`: injects a `script` tag in the `head` with the `src` attribute to a generated script to register the service worker * `script-defer` : injects a `script` tag with `defer` attribute in the `head` with the `src` attribute to a generated script to register the service worker * `null` (manual): do nothing, you will need to register the service worker yourself, or import any of the virtual modules exposed by the plugin * **`auto` (default value)**: depends on whether you use any of the virtual modules exposed by the plugin, it will do nothing or switch to `script` mode You can find more information about the virtual modules exposed by the plugin in the [Frameworks](/frameworks/) section. ## Inline Registration When configuring `injectRegister: 'inline'` in the plugin configuration, the plugin will inline a head script adding in to your application entry point: ::: details **inlined head script** ```html ``` ::: ## Script Registration When configuring `injectRegister: 'script' | 'script-defer'` in the plugin configuration, the plugin will generate a `registerSW.js` script adding it to your application entry point: ::: details **head script** ```html ``` ::: ::: details **/registerSW.js** ```js if ('serviceWorker' in navigator) { window.addEventListener('load', () => { navigator.serviceWorker.register('/sw.js', { scope: '/' }) }) } ``` ::: ## Manual Registration When configuring `injectRegister: null` in the plugin configuration, the plugin will do nothing, you must register the service workbox manually yourself. Or you can import any of the virtual modules exposed by the plugin. If you're using `injectManifest` strategy in development with `devOptions` enabled, you should check [injectManifest development section](/guide/development#injectmanifest-strategy) to get details on getting the right ServiceWorker URL for your development setup. ## Auto Registration If your application code base is not importing any of the virtual modules exposed by the plugin, the plugin will fallback to [Script Registration](/guide/register-service-worker#script-registration), otherwise, the imported virtual module will register the service worker for you. --- --- url: /examples/remix.md --- # Remix You can find a set of examples in the [@vite-pwa/remix integration repo](https://github.com/vite-pwa/remix/tree/main/examples). --- --- url: /frameworks/remix.md --- # Remix ::: warning This PWA module can only be used with Vite. ::: ## Remix PWA module `vite-plugin-pwa` provides the new `@vite-pwa/remix` module that will allow you to use `vite-plugin-pwa` in your Remix applications via `Vite` plugin and `Remix` preset. You will need to install `@vite-pwa/remix`: ::: code-group ```bash [pnpm] pnpm add -D @vite-pwa/remix ``` ```bash [yarn] yarn add -D @vite-pwa/remix ``` ```bash [npm] npm install -D @vite-pwa/remix ``` ::: Then in your Vite configuration file, import the `@vite-pwa/remix` helper and create the Remix PWA Preset and the Vite PWA Plugin and configure them: ```ts // vite.config.js import { vitePlugin as remix } from '@remix-run/dev' import { installGlobals } from '@remix-run/node' import { defineConfig } from 'vite' import { RemixVitePWA } from '@vite-pwa/remix' installGlobals() const { RemixVitePWAPlugin, RemixPWAPreset } = RemixVitePWA() export default defineConfig({ plugins: [ remix({ presets: [RemixPWAPreset()], }), RemixVitePWAPlugin({ // PWA options }) ] }) ``` Check Remix [PWA Options](https://github.com/vite-pwa/remix/blob/main/src/types.ts) for further details. ## Custom Service Worker When using `injectManifest` strategy, `@vite-pwa/remix` exposes a virtual module `virtual:vite-pwa/remix/sw` with the Remix information you can consume in your service worker (configuration from Remix and the `remix` PWA option): ```ts import { cleanupOutdatedCaches, clientsClaimMode, dynamicRoutes, enablePrecaching, navigateFallback, promptForUpdate, routes, staticRoutes, ssr, } from 'virtual:vite-pwa/remix/sw' ``` If you are using TypeScript you can include `@vite-pwa/remix/remix-sw` in your `tsconfig.json`: ```json { "compilerOptions": { "types": ["@vite-pwa/remix/remix-sw"] } } ``` or just include a triple slash comment in your service worker file: ```ts /// ``` You can also import PWA options via `@vite-pwa/remix/sw` (see next section): ```ts import { cleanupOutdatedCaches, clientsClaimMode, enablePrecaching, navigateFallback, promptForUpdate, staticRoutes, dynamicRoutes, routes, ssr, } from '@vite-pwa/remix/sw' ``` ### `setupPwa` helper functions `@vite-pwa/remix` provides an internal `setupPWA` module you can use to register a default implementation (similar to Workbox recipes), using the `remix` \`PWA options and Remix configuration: * cleanup outdated caches: Workbox's `cleanupOutdatedCaches` in `generateSW` Workbox build module for `injectManifest` strategy * clients claim mode: similar to Workbox's `cleanupOutdatedCaches` in `generateSW` Workbox build module for `injectManifest` strategy * precaching and offline configuration You only need to import `setupPWA` from `@vite-pwa/remix/sw` and call it in your service worker: ```ts import { setupPwa } from '@vite-pwa/remix/sw' setupPwa({ manifest: self.__WB_MANIFEST }) ``` ### Enabling Offline Support If your Remix application is an SPA, all routes will be pre-rendered, and you don't need to add additional logic, all html pages will be in the `self.__WB_MANIFEST` array. If you're using Remix SSR application, then you need to add [registerRoute](https://developer.chrome.com/docs/workbox/modules/workbox-routing) to handle the SSR routes to avoid default offline browser page when navigate to them: you can import `dynamicRoutes` and `staticRoutes` from the `virtual:vite-pwa/remix/sw` or `@vite-pwa/remix/sw` to register the SSR routes. Check the [shared-sw.ts module](https://github.com/vite-pwa/remix/blob/main/examples/pwa-simple-sw/app/shared-sw.ts) and the usage in the [service worker](https://github.com/vite-pwa/remix/blob/main/examples/pwa-simple-sw/app/plain-sw.ts), remember to exclude the router in dev server. ## PWA Assets This feature includes the following components: * `PwaManifest` component to include the PWA manifest in your HTML pages: will inject the PWA web manifest in the HTML head * `PwaAssets` component to include the PWA assets in your HTML pages: will inject the PWA assets in the HTML head (PWA web manifest, theme-color, favicon and PWA web manifest) ## Remix PWA Alternative You can use [Remix PWA](https://remix-pwa.run/) to add PWA support to your Remix application. --- --- url: /guide/scaffolding.md --- # Scaffolding Your First Vite PWA Project ::: tip From version `v1.0.0`, all the templates to use Vite 7, including also the latest frameworks changes. From version `v0.6.0`, all the templates to use Vite 6, including also the latest frameworks changes. Use version `v0.5.0` for Vite 5 and previous versions of the frameworks. ::: --- --- url: /guide/service-worker-precache.md --- # Service Worker Precache As explained in the [Service Worker](/guide/#service-worker) section, service workers act as proxies intercepting requests between the browser and the server. To add PWA capability to your application, we need to give it a service worker. The service worker's precache manifest must include all the resources of your application, so that the service worker knows what resources to download into the browser's cache storage for use during `network requests interception` and when the application is offline. ::: tip Network requests interception You can also configure whether to apply network request interception for any of your application resources. You can find more information on [Workbox - Caching Strategies](https://developer.chrome.com/docs/workbox/caching-strategies-overview/#caching-strategies). ::: Once the application registers the service worker, the browser will try to install it. This involves downloading all the resources in the service worker's precache manifest, and then trying to activate the service worker to take the control of the application. ::: tip The browser will **only** download the resources in the service worker's precache manifest **if the service worker is not installed** (the first time the user visits your application) or **if there is a new version of your application** (if you change some resource in your application, the service worker will also change once you build the application, since its precache manifest is modified to include your changes). The browser will always download these resouces **in a background thread** and not in the main browser thread, so that the application is usable even before the service worker is installed. You can see this behaviour on this website or the [VueUse docs site](https://vueuse.org/) in a private window. Just open `Network Tab` on dev tools before visiting the site: the browser will be downloading all the resources while you navigate the site. ::: ## Precache Manifest Since `vite-plugin-pwa` plugin uses the [workbox-build](https://developer.chrome.com/docs/workbox/modules/workbox-build/) node library to build the service worker, it will only include `css`, `js` and `html` resources in the manifest precache (check the `globPatterns` entry in [GlobPartial](https://developer.chrome.com/docs/workbox/modules/workbox-build#type-GlobPartial)). The `workbox-build` node library is file based: it will traverse the build output folder of your application. `Vite` will generate your build in the `dist` folder, and so, `workbox-build` will traverse the `dist` folder adding all resources found in it to the service worker's precache manifest. If you need to include another resource types, you will need to add them to the `globPatterns` entry. Depending on the `strategy` configured in the `vite-plugin-pwa` plugin configuration, you will need to add it under the `workbox` or `injectManifest` configuration option. You can find more information in the [Static assets handling](/guide/static-assets) section. For example, if you need to add `ico`, `png` and `svg` resources in the example from the [Configuring vite-plugin-pwa - Guide](/guide/#configuring-vite-plugin-pwa) section, you will need to add `globPatterns` under `workbox` entry, since we're using the default `vite-plugin-pwa` strategy (`generateSW`): ```ts import { VitePWA } from 'vite-plugin-pwa' export default defineConfig({ plugins: [ VitePWA({ registerType: 'autoUpdate', workbox: { globPatterns: ['**/*.{js,css,html,ico,png,svg}'] } }) ] }) ``` --- --- url: /guide/service-worker-strategies-and-behaviors.md --- # Service Worker Strategies And Behaviors A service worker strategy is related to how the `vite-plugin-pwa` plugin will generate your service worker, while the behavior of a service worker is related to how the service worker will work in the browser once the browser detects a new version of your application. ## Service Worker Strategies As we mention in [Configuring vite-plugin-pwa](/guide/#configuring-vite-plugin-pwa) section, `vite-plugin-pwa` plugin will use `workbox-build` node library to generate your service worker. There are 2 available strategies, `generateSW` and `injectManifest`: * `generateSW`: the `vite-plugin-pwa` will generate the service worker for you, you don't need to write the code for the service worker * `injectManifest`: the `vite-plugin-pwa` plugin will compile your custom service worker and inject its precache manifest To configure the service worker strategy, use the `strategies`' plugin option with `generateSW` (**default strategy**) or `injectManifest` value. You can find more information about the strategies in the [generateSW](/workbox/generate-sw) or [injectManifest](/workbox/inject-manifest) `Workbox` sections. ## Service Worker Behaviors The behavior of the service worker will help you to update the application in the browser, that is, when the browser detects a new version of your application, you can control how the browser updates it. You may want to not bother users and just have the browser update the application when there is a new version: the user will only see a reload of the page they are on. Or you may want to inform the user that there is a new version of the application, and let the user decide when to update it: simply because you want it to behave that way or because your application requires it (for example, to prevent data loss if the user is filling out a form). To configure the service worker behavior, use the `registerType` plugin option with `autoUpdate` or `prompt` (**default strategy**) value. You can find more information about the behaviors in the [auto-update](/guide/auto-update) or [prompt-for-update](/guide/prompt-for-update) sections for `generateSW` strategy or in [inject-manifest](/guide/inject-manifest) section for `injectManifest` strategy. --- --- url: /guide/service-worker-without-pwa-capabilities.md --- # Service Worker without PWA capabilities Sometimes you don't need the full blown PWA functionality like **offline cache** and **manifest file**, but need simple custom Service Worker. You can disable all `vite-plugin-pwa` supported features, and use it just to manage your Service Worker file. ## Service Worker code Suppose you want to have a Service Worker file that captures browser `fetch`: ```js // src/service-worker.js or src/service-worker.ts self.addEventListener('fetch', (event) => { event.respondWith(fetch(event.request)) }) ``` You would like to have this service worker reloaded on each change in **development** and prepared for **production**. ## Plugin Configuration You should configure `vite-plugin-pwa` plugin options in your Vite configuration file with the following options: ```js // vite.config.js or vite.config.ts VitePWA({ srcDir: 'src', filename: 'service-worker.js', strategies: 'injectManifest', injectRegister: false, manifest: false, injectManifest: { injectionPoint: undefined, }, }) ``` ## Development If you would like the service worker to run in development, make sure to enable it in the [devOptions](/guide/development#plugin-configuration) and to set the type to [module](/guide/development#injectmanifest-strategy) if required. ## Registering of the Service Worker in your app Use the code below in your entry point module: ```js // src/main.js or src/main.ts if ('serviceWorker' in navigator) { navigator.serviceWorker.register( import.meta.env.MODE === 'production' ? '/service-worker.js' : '/dev-sw.js?dev-sw' ) } ``` If you're using import statements inside your service worker (will work only on chromium based browsers) check [injectManifest](/guide/development.html#injectmanifest-strategy) section for more info: ```js // src/main.js or src/main.ts if ('serviceWorker' in navigator) { navigator.serviceWorker.register( import.meta.env.MODE === 'production' ? '/service-worker.js' : '/dev-sw.js?dev-sw', { type: import.meta.env.MODE === 'production' ? 'classic' : 'module' } ) } ``` --- --- url: /examples/solidjs.md --- # SolidJS The `SolidJS` example project can be found on [examples/solid-router](https://github.com/vite-pwa/vite-plugin-pwa/tree/main/examples/solid-router) package/directory. The router used on this example project is [solid-app-router](https://github.com/solidjs/solid-app-router). To test `new content available`, you should rerun the corresponding script, and then refresh the page. If you are running an example with `Periodic SW updates`, you will need to wait 1 minute: ## Executing the examples ## generateSW ## injectManifest --- --- url: /frameworks/solidjs.md --- # SolidJS You can use the built-in `Vite` virtual module `virtual:pwa-register/solid` for `SolidJS` which will return `createSignal` stateful values (`createSignal`) for `offlineReady` and `needRefresh`. ::: warning You will need to add `workbox-window` as a `dev` dependency to your `Vite` project. ::: ## Type declarations ::: tip From version `0.14.5` you can also use types definition for solid instead of `vite-plugin-pwa/client`: ```json { "compilerOptions": { "types": [ "vite-plugin-pwa/solid" ] } } ``` Or you can add the following reference in any of your `d.ts` files (for example, in `vite-env.d.ts` or `global.d.ts`): ```ts /// ``` ::: ```ts declare module 'virtual:pwa-register/solid' { import type { Accessor, Setter } from 'solid-js' import type { RegisterSWOptions } from 'vite-plugin-pwa/types' export type { RegisterSWOptions } export function useRegisterSW(options?: RegisterSWOptions): { needRefresh: [Accessor, Setter] offlineReady: [Accessor, Setter] updateServiceWorker: (reloadPage?: boolean) => Promise } } ``` ## Prompt for update You can use this `ReloadPrompt.tsx` component: ::: details ReloadPrompt.tsx ```tsx import type { Component } from 'solid-js' import { Show } from 'solid-js' import { useRegisterSW } from 'virtual:pwa-register/solid' import styles from './ReloadPrompt.module.css' const ReloadPrompt: Component = () => { const { offlineReady: [offlineReady, setOfflineReady], needRefresh: [needRefresh, setNeedRefresh], updateServiceWorker, } = useRegisterSW({ onRegistered(r) { // eslint-disable-next-line prefer-template console.log('SW Registered: ' + r) }, onRegisterError(error) { console.log('SW registration error', error) }, }) const close = () => { setOfflineReady(false) setNeedRefresh(false) } return (
New content available, click on reload button to update.} when={offlineReady()} > App ready to work offline
) } export default ReloadPrompt ``` ::: and its corresponding `ReloadPrompt.module.css` styles module: ::: details ReloadPrompt.module.css ```css .Container { padding: 0; margin: 0; width: 0; height: 0; } .Toast { position: fixed; right: 0; bottom: 0; margin: 16px; padding: 12px; border: 1px solid #8885; border-radius: 4px; z-index: 1; text-align: left; box-shadow: 3px 4px 5px 0 #8885; background-color: white; } .ToastMessage { margin-bottom: 8px; } .ToastButton { border: 1px solid #8885; outline: none; margin-right: 5px; border-radius: 2px; padding: 3px 10px; } ``` ::: ## Periodic SW Updates As explained in [Periodic Service Worker Updates](/guide/periodic-sw-updates), you can use this code to configure this behavior on your application with the virtual module `virtual:pwa-register/solid`: ```ts import { useRegisterSW } from 'virtual:pwa-register/solid' const intervalMS = 60 * 60 * 1000 const updateServiceWorker = useRegisterSW({ onRegistered(r) { r && setInterval(() => { r.update() }, intervalMS) } }) ``` The interval must be in milliseconds, in the example above it is configured to check the service worker every hour. --- --- url: /guide/static-assets.md --- # Static assets handling By default, all icons on `PWA Web App Manifest` option found under Vite's `publicDir` option directory, will be included in the service worker *precache*. You can disable this option using `includeManifestIcons: false`. You can also add other static assets such as `favicon`, `svg` and `font` files using `includeAssets` option. The `includeAssets` option will be resolved using [tinyglobby](https://github.com/SuperchupuDev/tinyglobby) found under Vite's `publicDir` option directory, and so you can use regular expressions to include those assets, for example: `includeAssets: ['fonts/*.ttf', 'images/*.png']`. You don't need to configure `PWA Manifest icons` on `includeAssets` option. ## Reusing src/assets images ::: warning This feature is not yet available. ::: If you are using images in your application via `src/assets` directory (or any other directory), and you want to reuse those images in your `PWA Manifest` icons, you can use them with these 3 limitations: * any image under `src/assets` directory (or any other directory) must be used in your application via static import or directly on the `src` attribute * you must reference the images in the `PWA Manifest` icons using the assets directory path relative to the root folder: `./src/assets/logo.png` or `src/assets/logo.png` * inlined icons cannot be used, in that case you will need to copy/move those images to the Vite's `publicDir` option directory: refer to [Importing Asset as URL](https://vitejs.dev/guide/assets.html#importing-asset-as-url) and [Vite's assetsInlineLimit option](https://vitejs.dev/config/build-options.html#build-assetsinlinelimit) ::: warning If you're using `PWA Manifest` icons from any asset folder, but you are not using those images in your application (via static import or in src attribute), Vite will not emit those assets, and so missing from the build output: ```shell Error while trying to use the following icon from the Manifest: https://localhost/src/assets/pwa-192x192.png (Download error or resource isn't a valid image) ``` In that case, you need to copy or move those images to the Vite's `publicDir` option directory (defaults to `public`) and configure the icons properly. ::: For example, if you have the following image `src/assets/logo-192x192.png` you can add it to your `PWA Manifest` icon using: ```json { "src": "./src/assets/logo-192x192.png", "sizes": "192x192", "type": "image/png" } ``` then, in your codebase, you must use it via static import: ```js // src/main.js or src/main.ts // can be any js/ts/jsx/tsx module or single file component import logo from './assets/logo-192x192.png' document.getElementById('logo-img').src = logo ``` or using the `src` attribute: ```js // src/main.js or src/main.ts // can be any js/ts/jsx/tsx module or single file component document.getElementById('#app').innerHTML = ` Logo ` ``` ## globPatterns If you need to include other assets that are not under Vite's `publicDir` option directory, you can use the `globPatterns` parameter of [workbox](https://developer.chrome.com/docs/workbox/modules/workbox-build#generatesw) or [injectManifest](https://developer.chrome.com/docs/workbox/modules/workbox-build#injectmanifest) plugin options. ::: warning If you configure `globPatterns` on `workbox` or `injectManifest` plugin option, you **MUST** include all your assets patterns: `globPatterns` will be used by `workbox-build` to match files on `dist` folder. By default, `globPatterns` will be `**/*.{js,css,html}`: `workbox` will use [glob primer](https://github.com/isaacs/node-glob#glob-primer) to match files using `globPatterns` as filter. A common pitfall is to only include some assets and forget to add `css`, `js` and `html` assets pattern, and then your service worker will complain about missing resources. For example, if you don't include `html` assets pattern, you will get this error from your service worker: **WorkboxError non-precached-url index.html**. ::: To configure `globPatterns` you need to use `workbox` or `injectManifest` plugin option for`generateSW` and `injectManifest` strategies respectively: ::: code-group ```ts [generateSW] VitePWA({ workbox: { globPatterns: ['**/*.{js,css,html}'], } }) ``` ```ts [injectManifest] VitePWA({ injectManifest: { globPatterns: ['**/*.{js,css,html}'], } }) ``` ::: --- --- url: /examples/svelte.md --- # Svelte The `Svelte` example project can be found on [examples/svelte-routify](https://github.com/vite-pwa/vite-plugin-pwa/tree/main/examples/svelte-routify) package/directory. The router used on this example project is [@roxi/routify](https://routify.dev/). To test `new content available`, you should rerun the corresponding script, and then refresh the page. If you are running an example with `Periodic SW updates`, you will need to wait 1 minute: ## Executing the examples ## generateSW ## injectManifest --- --- url: /frameworks/svelte.md --- # Svelte You can use the built-in `Vite` virtual module `virtual:pwa-register/svelte` for `Svelte` which will return `writable` stores (`Writable`) for `offlineReady` and `needRefresh`. ::: warning You will need to add `workbox-window` as a `dev` dependency to your `Vite` project. ::: ## Type declarations ::: tip From version `0.14.5` you can also use types definition for svelte instead of `vite-plugin-pwa/client`: ```json { "compilerOptions": { "types": [ "vite-plugin-pwa/svelte" ] } } ``` Or you can add the following reference in any of your `d.ts` files (for example, in `vite-env.d.ts` or `global.d.ts`): ```ts /// ``` ::: ```ts declare module 'virtual:pwa-register/svelte' { import type { Writable } from 'svelte/store' import type { RegisterSWOptions } from 'vite-plugin-pwa/types' export type { RegisterSWOptions } export function useRegisterSW(options?: RegisterSWOptions): { needRefresh: Writable offlineReady: Writable updateServiceWorker: (reloadPage?: boolean) => Promise } } ``` ## Prompt for update You can use this `ReloadPrompt.svelte` component: ::: details ReloadPrompt.svelte ```html {#if toast} {/if} ``` ::: ## Periodic SW Updates As explained in [Periodic Service Worker Updates](/guide/periodic-sw-updates), you can use this code to configure this behavior on your application with the virtual module `virtual:pwa-register/svelte`: ```ts import { useRegisterSW } from 'virtual:pwa-register/svelte' const intervalMS = 60 * 60 * 1000 const updateServiceWorker = useRegisterSW({ onRegistered(r) { r && setInterval(() => { r.update() }, intervalMS) } }) ``` The interval must be in milliseconds, in the example above it is configured to check the service worker every hour. --- --- url: /examples/sveltekit.md --- # SvelteKit You can find a set of examples in the [@vite-pwa/sveltekit integration repo](https://github.com/vite-pwa/sveltekit/tree/main/examples). --- --- url: /frameworks/sveltekit.md --- # SvelteKit ::: tip From version `^0.6.7`, `SvelteKitPWA` adds support for [Single-page apps](https://svelte.dev/docs/kit/single-page-apps): check [SPA](#spa) section for more information. ::: ::: tip From version `^0.1.0`, `SvelteKitPWA` has SvelteKit `^1.0.0` as peer dependency. ::: ::: info For `Type declarations`, `Prompt for update` and `Periodic SW Updates` go to [Svelte](/frameworks/svelte) entry. ::: ::: tip If you're using `0.1.*` version of `SvelteKitPWA`, you should remove all references to [SvelteKit service worker module](https://kit.svelte.dev/docs/service-workers) to disable it on your application. ::: ## Installing @vite-pwa/sveltekit To install the `@vite-pwa/sveltekit` plugin, just add it to your project as a `dev dependency`: ::: code-group ```bash [pnpm] pnpm add -D @vite-pwa/sveltekit ``` ```bash [yarn] yarn add -D @vite-pwa/sveltekit ``` ```bash [npm] npm install -D @vite-pwa/sveltekit ``` ::: ## Workbox Configuration ### globPatterns `@vite-pwa/sveltekit` configures the following `globPatterns` for you (`workbox` or `injectManifest` option depending on the strategy configured): * `workbox: { globPatterns: ['client/**/*.{js,css,ico,png,svg,webp,webmanifest}', 'prerendered/**/*.{html,json}'] }` or * `injectManifest: { globPatterns: ['client/**/*.{js,css,ico,png,svg,webp,webmanifest}', 'prerendered/**/*.{html,json}'] }` `@vite-pwa/sveltekit` configures the `.svelte-kit/output` directory as the `globDirectory` for the `workbox-build` process (`workbox` or `injectManifest` option depending on the strategy configured). This directory will contain all the files generated by SvelteKit when building your application as an intermediate step before the final adapter build. This directory will have the following structure: * `client` directory: will contain all the client side files generated by SvelteKit (`.js`, `.css`) and all assets files in the static directory (`.ico`, `.png`, `.svg`, `.webp`). * `prerendered/pages` directory: will contain all the prerendered pages (`.html`). * `prerendered/dependencies//__data.json` files: `load` functions payload when using `static-adapter`. * `server` directory: will contain all the server side files generated by SvelteKit (`.js`, `.css`). If you want to add some extra files to the `globPatterns` configuration, remember to include the glob adding the `client/` prefix, or you will end up including server assets in the service worker precache manifest and your application will fail when registering the service worker. If you want to add the SvelteKit `_app/version.json` file to your service worker precache manifest, enable the `kit.includeVersionFile` option in your PWA configuration. ## Generate Custom Service Worker From version `0.2.0`, `SvelteKitPWA` plugin will delegate your custom service worker build to SvelteKit, and so by default you will be expected to put your service worker in `src/service-worker.js`. If you would like, you can use a custom file location by changing the corresponding SvelteKit option: ```js // svelte.config.js /** @type {import('@sveltejs/kit').Config} */ const config = { kit: { files: { serviceWorker: 'src/my-sw.js', // or `src/my-sw.ts` } } }; export default config; ``` Then in your Vite config file: ```js // vite.config.js or vite.config.ts /** @type {import('vite').UserConfig} */ const config = { plugins: [ sveltekit(), SvelteKitPWA({ strategies: 'injectManifest', srcDir: 'src', filename: 'my-sw.js', // or `my-sw.ts` /* other pwa options */ }) ], }; export default config; ``` You can check SvelteKit docs for more information about [service workers](https://kit.svelte.dev/docs/service-workers). You will need to exclude the service worker registration from the SvelteKit configuration if you're using any pwa virtual module (`virtual:pwa-register` or `virtual:pwa-register/svelte`): ```js // svelte.config.js /** @type {import('@sveltejs/kit').Config} */ const config = { kit: { serviceWorker: { register: false } } }; export default config; ``` ::: warning If your custom service working is importing any `workbox-*` module (`workbox-routing`, `workbox-strategies`, etc), you will need to hack Vite build process in order to remove non `ESM` special replacements from the build process (if you don't include `process.env.NODE_ENV`, the service worker will not be registered). You only need to add this entry in your Vite config file: ```js // vite.config.js or vite.config.ts /** @type {import('vite').UserConfig} */ const config = { define: { 'process.env.NODE_ENV': process.env.NODE_ENV === 'production' ? '"production"' : '"development"' } }; export default config; ``` ::: ## SvelteKit PWA Plugin `vite-plugin-pwa` provides the new `SvelteKitPWA` plugin that will allow you to use `vite-plugin-pwa` in your SvelteKit applications. To update your project to use the new `vite-plugin-pwa` for SvelteKit, you only need to change the Vite config file (you don't need oldest `pwa` and `pwa-configuration` modules): ```js // vite.config.js / vite.config.ts import { SvelteKitPWA } from '@vite-pwa/sveltekit' /** @type {import('vite').UserConfig} */ const config = { plugins: [ sveltekit(), SvelteKitPWA({/* pwa options */}) ], } export default config ``` In addition to the configuration above, it's necessary to add the PWA web manifest, currently the easiest way to do this, is to add it to any layout to your kit project: ```svelte // src/routes/+layout.svelte {@html webManifestLink} ``` Check out the [virtual:pwa-info](/frameworks/#accessing-pwa-info) documentation to learn more about the virtually exposed module `pwa-info`. ## SvelteKit PWA Plugin Options ::: details SvelteKit PWA Plugin options ```ts import type { VitePWAOptions } from 'vite-plugin-pwa' export interface KitOptions { /** * The base path for your application: by default will use the Vite base. * * @deprecated since ^0.1.0 version, the plugin has SvelteKit ^1.0.0 as peer dependency, Vite's base is now properly configured. * @default '/' * @see https://kit.svelte.dev/docs/configuration#paths */ base?: string /** * @default '.svelte-kit' * @see https://kit.svelte.dev/docs/configuration#outdir */ outDir?: string /** * @see https://github.com/sveltejs/kit/tree/master/packages/adapter-static#fallback */ adapterFallback?: string /** * @default 'never' * @see https://kit.svelte.dev/docs/configuration#trailingslash */ trailingSlash?: 'never' | 'always' | 'ignore' /** * @default `_app` * @see https://kit.svelte.dev/docs/configuration#appdir */ appDir?: string /** * Include `${appDir}/version.json` in the service worker precache manifest? * * @default false */ includeVersionFile?: boolean /** * Enable SPA mode for the application. * * By default, the plugin will use `adapterFallback` to include the entry in the service worker * precache manifest. * * If you are using a logical name for the fallback, you can use the object syntax with the * `fallbackMapping`. * * For example, if you're using `fallback: 'app.html'` in your static adapter and your server * is redirecting to `/app`, you can configure `fallbackMapping: '/app'`. * * Since the static adapter will run after the PWA plugin generates the service worker, * the PWA plugin doesn't have access to the adapter fallback page to include the revision in the * service worker precache manifest. * To generate the revision for the fallback page, the PWA plugin will use the * `.svelte-kit/output/client/_app/version.json` file. * You can configure the `fallbackRevision` to generate a custom revision. * * @see https://svelte.dev/docs/kit/single-page-apps */ spa?: true | { fallbackMapping?: string fallbackRevision?: () => Promise } } export interface SvelteKitPWAOptions extends Partial { kit?: KitOptions } ``` ::: ## SvelteKit Pages If you want your application to work offline, you should ensure you have not set `csr: false` on any of your pages since it will prevent injecting JavaScript into the layout for offline support. ### Auto Update Since SvelteKit uses SSR/SSG, we need to call the `vite-plugin-pwa` virtual module using a dynamic `import`. The best place to include the virtual call will be in main layout of the application (you should register it in any layout): ::: details src/routes/+layout.svelte ```svelte {@html webManifest}
``` ::: ### Prompt for update Since SvelteKit uses SSR/SSG, we need to add the `ReloadPrompt` component using a dynamic `import`. The best place to include the `ReloadPrompt` component will be in main layout of the application (you should register it in any layout): ::: details src/routes/+layout.svelte ```html {@html webManifest}
{#await import('$lib/ReloadPrompt.svelte') then { default: ReloadPrompt}} {/await} ``` ::: ::: details $lib/ReloadPrompt.svelte ```html {#if toast} {/if} ``` ::: ## SvelteKit and Adapters If you set certain SvelteKit options, you should also configure the PWA plugin properly using the `kit` option: * [outDir](https://kit.svelte.dev/docs/configuration#outdir) * [adapterFallback](https://github.com/sveltejs/kit/tree/master/packages/adapter-static#fallback) * [trailingSlash](https://kit.svelte.dev/docs/configuration#trailingslash) ::: warning Some kit options may have been moved/deprecated, review the SvelteKit documentation site: * [trailingSlash](https://kit.svelte.dev/docs/page-options#trailingslash): now it should be configured in the page options, and so, we cannot control it in the plugin. ::: ### SPA If you are using SvelteKit SPA mode, the `static-adapter` will create the fallback after `@vite-pwa/sveltekit` plugin generates the service worker, and so the plugin doesn't have access to the adapter fallback page to include the revision in the service worker precache manifest. To generate the revision for the fallback page, the plugin will use the `.svelte-kit/output/client/_app/version.json` file. You can configure the `spa.fallbackRevision` function to generate a custom revision. ## PWA Assets We suggest you using external configuration file, `@vite-pwa/sveltekit` plugin will watch it for changes, avoiding dev server restarts. If you use inlined configuration, Vite will restart the dev server when changing any option. To inject the PWA icons links and the `theme-color`, you can use the `virtual:pwa-assets/head` virtual module in your `+layout.svelte` component: * add `import 'vite-plugin-pwa/pwa-assets';` to your `src/app.d.ts` file * remove all links with rel `icon`, `apple-touch-icon` and `apple-touch-startup-image` from `` or from your `app.html` file * remove the `theme-color` meta tag from `` or from your `app.html` file * add the virtual import * include theme color and icons links using code-snippet shown below ```html {#if pwaAssetsHead.themeColor} {/if} {#each pwaAssetsHead.links as link} {/each} ``` You can find a working example in the [examples folder](https://github.com/vite-pwa/sveltekit/tree/main/examples/sveltekit-ts-assets-generator). --- --- url: /guide/testing-service-worker.md --- # Testing Service Worker There are quite a few test libraries, `vite-plugin-pwa` uses [Vitest](https://vitest.dev/) for build testing and [Playwright](https://playwright.dev/) for in-browser testing (with the Chromium browser only). You can check any framework example in the `examples` folder in the corresponding repo: * [vite-plugin-pwa](https://github.com/vite-pwa/vite-plugin-pwa/tree/main/examples) * [@vite-pwa/nuxt](https://github.com/vite-pwa/nuxt) (in root folder) * [@vite-pwa/sveltekit](https://github.com/vite-pwa/sveltekit/tree/main/examples) and the corresponding contributing guide: * [running tests in vite-plugin-pwa](https://github.com/vite-pwa/vite-plugin-pwa/blob/main/CONTRIBUTING.md#running-tests) * [running tests in @vite-pwa/nuxt](https://github.com/vite-pwa/nuxt/blob/main/CONTRIBUTING.md#running-tests) * [running tests in @vite-pwa/sveltekit](https://github.com/vite-pwa/sveltekit/blob/main/CONTRIBUTING.md#running-tests) `vite-plugin-pwa` and `@vite-pwa/nuxt` have been added to the [Vite ecosystem-ci](https://github.com/vitejs/vite-ecosystem-ci) and [Nuxt ecosystem-ci](https://github.com/nuxt/ecosystem-ci) respectively to detect possible regressions in new Vite/Nuxt versions: * [Discord Vite ecosystem-ci](https://discord.com/channels/804011606160703521/928398470086291456) * [Discord Nuxt ecosystem-ci](https://discord.com/channels/473401852243869706/1098558476483055656) We're also working to include `@vite-pwa/sveltekit` in the [Svelte ecosystem-ci](https://github.com/sveltejs/svelte-ecosystem-ci). ## Testing build Check `vitest.config.mts` in the root folder and the `test` folder in each example. You have a `test` script in each example `package.json` file to run build and in-browser tests. ## Testing in-browser Check `playwright.config.ts` in the root folder and the `client-test` folder in each example. You have a `test` script in each example `package.json` file to run build and in-browser tests. In this case, we also need to start a server to run the tests, check `webServer` in `playwright.config.ts`. --- --- url: /guide/unregister-service-worker.md --- # Unregister Service Worker If you want to unregister the service worker from your PWA application, you only need to add `selfDestroying: true` to the plugin configuration. `vite-plugin-pwa` plugin will create a new special service worker and replace the existing one in your application once deployed in production: it has to be put in the place of the previous broken/unwanted service worker, with the same name. ::: info From version `0.17.2+`, the service worker will delete all of its cache storage entries. ::: ::: danger It is **IMPORTANT TO NOT CHANGE ANYTHING** in the plugin configuration, especially **DO NOT CHANGE THE SERVICE WORKER NAME**, just keep the options and the PWA UI components (if included), the plugin will take care of changing the service worker and avoid interacting with the UI if configured. ::: In a future, if you want to add the PWA again to your application, you only need to remove the `selfDestroying` option or just disable it: `selfDestroying: false`. ## Custom `selfDestroying` Service Worker If you want to remove the current deployed service worker but installing a new one, don't use `selfDestroying`: * create a new JavaScript file with the current deployed service worker name in the `public` folder, check the example below * change `filename` in the PWA configuration (this will generate a new service worker with the new name) For example, if you don't specify the `filename`, the service worker name will be `sw.js` (default). Change the `filename` PWA option to `service-worker.js` or other name different to `sw.js`, then add the following code to `public/sw.js` file (the current deployed service worker): ```js // public/sw.js self.addEventListener('install', (e) => { self.skipWaiting() }) self.addEventListener('activate', (e) => { self.registration.unregister() .then(() => self.clients.matchAll()) .then((clients) => { clients.forEach((client) => { if (client instanceof WindowClient) client.navigate(client.url) }) return Promise.resolve() }) .then(() => { self.caches.keys().then((cacheNames) => { Promise.all( cacheNames.map((cacheName) => { return self.caches.delete(cacheName) }) ) }) }) }) ``` You can repeat the above process as many times as necessary, **remember not to delete** any service worker from the public directory (you don't know what version the users of your application have installed). ## Development You can also check the `selfDestroying` plugin option in the dev server with development options enabled: check [Development section](/guide/development) for more info. ## Examples You have in the examples folder the `**-destroy` scripts in their corresponding `package.json`, you can try it on the development server or from the production build. ## Credits The implementation is based on this GitHub repo [Self-destroying ServiceWorker](https://github.com/NekR/self-destroying-sw), for more info read [Medium: Self-destroying ServiceWorker](https://medium.com/@nekrtemplar/self-destroying-serviceworker-73d62921d717). --- --- url: /.vitepress/theme/components/TypeScriptError2307.md --- If your **TypeScript** build step or **IDE** complain about not being able to find modules or type definitions on imports, add the following to the `compilerOptions.types` array of your `tsconfig.json`: ```json { "compilerOptions": { "types": [ "vite-plugin-pwa/client" ] } } ``` Or you can add the following reference in any of your `d.ts` files (for example, in `vite-env.d.ts` or `global.d.ts`): ```ts /// ``` --- --- url: /.vitepress/theme/components/ScaffoldingPWAProject.md --- ::: tip Compatibility Note Vite requires [Node.js](https://nodejs.org/en/) version 18.x.x or 20+. However, some templates may require a higher Node.js version to work, please upgrade Node if your package manager warns about it. ::: ::: code-group ```bash [pnpm] $ pnpm create @vite-pwa/pwa ``` ```bash [yarn] $ yarn create @vite-pwa/pwa ``` ```bash [npm] $ npm create @vite-pwa/pwa@latest ``` ```bash [bun] $ bun create @vite-pwa/pwa ``` ::: Then follow the prompts! You can also directly specify the project name and the template you want to use via additional command line options. For example, to scaffold a Vite PWA + Vue project, run: ::: code-group ```bash [pnpm] $ pnpm create @vite-pwa/pwa my-vue-app --template vue ``` ```bash [yarn] $ yarn create @vite-pwa/pwa my-vue-app --template vue ``` ```bash [npm] $ npm create @vite-pwa/pwa@latest my-vue-app -- --template vue ``` ```bash [bun] $ bun create @vite-pwa/pwa my-vue-app --template vue ``` ::: See [create-pwa](https://github.com/vite-pwa/create-pwa) for more details on each supported template: `vanilla`, `vanilla-ts`, `vue`, `vue-ts`, `react`, `react-ts`, `preact`, `preact-ts`, `lit`, `lit-ts`, `svelte`, `svelte-ts`, `solid`, `solid-ts` (templates can be found inside the `templates` folder). --- --- url: /.vitepress/theme/components/ServiceWorkerClientErrors.md --- Check [New Vite Build](/guide/change-log#new-vite-build) section for more details, the error described below has been fixed in `v0.18.0+` and there is no need to use `iife` format to build your service worker. If your service worker code is being compiled with unexpected `exports` (for example: `export default require_sw();`), you can change the build output format to `iife`, add the following code to your pwa configuration: ```ts injectManifest: { rollupFormat: 'iife' } ``` --- --- url: /.vitepress/theme/components/ExamplesGenerateSW.md --- `generateSW` has the following behaviors: --- --- url: /.vitepress/theme/components/InjectManifestCleanupOutdatedCaches.md --- When the user installs the new version of the application, we will have on the service worker cache all new assets and also the old ones. To delete old assets (from previous versions that are no longer necessary), and since you are building your own service worker, you will need to add the following code to your custom service worker: ```js import { cleanupOutdatedCaches, precacheAndRoute } from 'workbox-precaching' cleanupOutdatedCaches() precacheAndRoute(self.__WB_MANIFEST) ``` We strongly recommend you to include previous code on your custom service worker. --- --- url: /.vitepress/theme/components/GenerateSWSourceMap.md --- Since plugin version `0.11.2`, your service worker's source map will not be generated as it uses the `build.sourcemap` option from the Vite config, which by default is `false`. Your service worker source map will be generated when Vite's `build.sourcemap` configuration option has the value `true`, `'inline'` or `'hidden'`, and you have not configured the `workbox.sourcemap` option in the plugin configuration. If you configure the `workbox.sourcemap` option, the plugin will not change that value. If you want to generate the source map of your service worker, you can use this code: ```ts import { VitePWA } from 'vite-plugin-pwa' export default defineConfig({ plugins: [ VitePWA({ workbox: { sourcemap: true } }) ] }) ``` --- --- url: /.vitepress/theme/components/GenerateSWCleanupOutdatedCaches.md --- When the browser detects and installs the new version of your application, it will have in the cache storage all new assets and also the old ones. To delete old assets (from previous versions that are no longer necessary), you have to configure an option in the `workbox` entry of the plugin configuration. When using the `generateSW` strategy, it is not necessary to configure it, the plugin will activate it by default. We strongly recommend you to **NOT** deactivate the option. If you are curious, you can deactivate it using the following code in your plugin configuration: ```ts import { VitePWA } from 'vite-plugin-pwa' export default defineConfig({ plugins: [ VitePWA({ workbox: { cleanupOutdatedCaches: false } }) ] }) ``` --- --- url: /.vitepress/theme/components/ChangeLog.md --- ::: info Check [change log page for more info](/guide/change-log.html). ::: --- --- url: /.vitepress/theme/components/InjectManifestSourceMap.md --- ::: info From `v0.18.0+` you can use `minify`, `sourcemap` and `enableWorkboxModulesLogs` in your `injectManifest` configuration option, check [New Vite Build](/guide/change-log#new-vite-build) section for more details. ::: Since you are building your own service worker, this plugin will use Vite's `build.sourcemap` configuration option, which default value is `false`, to generate the source map. If you want to generate the source map for your service worker, you will need to generate the source map for the entire application. --- --- url: /.vitepress/theme/components/ReactReactiveWarning.md --- ::: warning The options provided to hooks are not reactive. Therefore, the callback references will be the first rendered options instead of the latest hook’s options. If you are doing complex logic with state changes, you will need to provide a stable reference function. ::: --- --- url: /.vitepress/theme/components/InjectManifestBuild.md --- From `v0.18.0`, `vite-plugin-pwa` adds five new options to `injectManifest` option to allow customizing the service worker build output: * `target`: you can change the `target` build, the plugin will use the Vite's [build.target](https://vitejs.dev/config/build-options.html#build-target) option if not configured * `minify`: you can change the `minify` build, the plugin will use the Vite's [build.minify](https://vitejs.dev/config/build-options.html#build-minify) option if not configured * `sourcemap`: you can change the `sourcemap` build, the plugin will use the Vite's [build.sourcemap](https://vitejs.dev/config/build-options.html#build-sourcemap) option if not configured * `enableWorkboxModulesLogs`: you can enable/disable the `workbox` modules log for a development or production build, by default, the plugin will use `process.env.NODE_ENV` (Workbox modules logs logic will be removed from the service worker in `production` build: dead code elimination) * `buildPlugins`: you can add custom Rollup and/or Vite plugins to the service worker build The new Vite build will allow you to use [.env Files](https://vitejs.dev/guide/env-and-mode.html#env-files), the `mode` option in your PWA configuration will not be used when using `injectManifest` strategy, the plugin will use the Vite's [mode](https://vitejs.dev/config/#mode) option instead: * use `import.meta.env.MODE` to access the Vite mode inside your service worker. * use `import.meta.env.DEV` or `import.meta.env.PROD` to check if the service worker is running on development or production (equivalent to `process.env.NODE_ENV`), check Vite [NODE\_ENV and Modes](https://vitejs.dev/guide/env-and-mode#node-env-and-modes) docs. ::: tip If you are using TypeScript in your service worker accessing `import.meta.env` variables, if TypeScript complains, add the following reference to the beginning of your service worker code: ```ts /// ``` ::: --- --- url: /.vitepress/theme/components/CleanupOutdatedCaches.md --- The service worker will store all your application assets in a browser cache (or set of caches). Every time you make changes to your application and rebuild it, the `service worker` will also be rebuilt, including in its precache manifest all new modified assets, which will have their revision changed (all assets that have been modified will have a new version). Assets that have not been modified will also be included in the service worker precache manifest, but their revision will not change from the previous one. ::: tip Precache Manifest Entry Revision The precache manifest entry revision is just a `MD5` hash of the asset content, if an asset is not modified, the calculated hash will be always the same. ::: --- --- url: /.vitepress/theme/components/SsrSsg.md --- If you are using `SSR/SSG`, you need to import `virtual:pwa-register` module using dynamic import and checking if `window` is not `undefined`. You can register the service worker on `src/pwa.ts` module: ```ts import { registerSW } from 'virtual:pwa-register' registerSW({ /* ... */ }) ``` and then import it from your `main.ts`: ```ts if (typeof window !== 'undefined') import('./pwa') ``` You can see the [FAQ](/guide/faq#navigator-window-is-undefined) entry for more info. --- --- url: /.vitepress/theme/components/ExamplesInjectManifest.md --- `injectManifest` has the following behavior: --- --- url: /.vitepress/theme/components/RunExamples.md --- ::: warning Before following the instructions below, read the [Contribution Guide](https://github.com/antfu/vite-plugin-pwa/blob/main/CONTRIBUTING.md). ::: Make sure you install project dependencies, and build the repo on your local clone/fork: ```bash cd vite-plugin-pwa pnpm install pnpm run build ``` To run the examples, execute the following script from your shell (from root folder), it will start a CLI where you will select the framework and the pwa options: ```shell pnpm run examples ``` If you don't run `pnpm build` first, you may see an error like, `failed to load config` or `Please verify that the package.json has a valid "main" entry`. --- --- url: /.vitepress/theme/components/HeuristicWorkboxWindow.md --- ::: warning **This only applies when importing any of the virtual modules or using `workbox-window` module**. Since `workbox-window` uses a time-based `heuristic` algorithm to handle service worker updates, if you build your service worker and register it again, if the time between last registration and the new one is less than 1 minute, then, `workbox-window` will handle the `service worker update found` event as an external event, and so the behavior could be strange (for example, if using `prompt`, instead showing the dialog for new content available, the ready to work offline dialog will be shown; if using `autoUpdate`, the ready to work offline dialog will be shown and shouldn't be shown). ::: --- --- url: /.vitepress/theme/components/ExamplesBehaviors.md --- * `Prompt for update`: * Show `Ready to work offline` on first visit and once the `service worker` ready. * Show `Prompt for update` when new `service worker` available. * `Auto update`: * Show `Ready to work offline` on first visit and once the `service worker` ready. * When new content available, the service worker will be updated automatically. * `Prompt for update` with `Periodic service worker updates`: * Show `Ready to work offline` on first visit and once the `service worker` ready. * Show `Prompt for update` when new `service worker` available. * The example project will register a `Periodic service worker updates` * `Auto update` with `Periodic service worker updates`: * Show `Ready to work offline` on first visit and once the `service worker` ready. * The example project will register a `Periodic service worker updates` * When new content available, the service worker will be updated automatically. --- --- url: /deployment/vercel.md --- # Vercel ## Instructions This guide provides step-by-step instructions on how to deploy a Vite PWA on Vercel, including specific configurations for HTTP headers using a `vercel.json` file. ### Step 1: Prepare Your Vite PWA Ensure your application is deployment-ready. This includes having all necessary dependencies listed in your `package.json` and ensuring your application compiles without errors. ### Step 2: Create the `vercel.json` File Create a `vercel.json` file at the root of your project to manage HTTP headers and redirects. This configuration mirrors some settings you might use with Netlify but adapted for Vercel's platform. ```json { "headers": [ { "source": "/(.*).html", "headers": [ { "key": "Cache-Control", "value": "public, max-age=0, must-revalidate" } ] }, { "source": "/sw.js", "headers": [ { "key": "Cache-Control", "value": "public, max-age=0, must-revalidate" } ] }, { "source": "/manifest.webmanifest", "headers": [ { "key": "Content-Type", "value": "application/manifest+json" } ] }, { "source": "/assets/(.*)", "headers": [ { "key": "Cache-Control", "value": "max-age=31536000, immutable" } ] }, { "source": "/(.*)", "headers": [ { "key": "X-Content-Type-Options", "value": "nosniff" }, { "key": "X-Frame-Options", "value": "DENY" }, { "key": "X-XSS-Protection", "value": "1; mode=block" } ] } ], "rewrites": [ { "source": "/(.*)", "destination": "/index.html" } ] } ``` ### Step 3: Set Up Your Project on Vercel 1. **Log into Vercel**: Create an account or log in at [Vercel](https://vercel.com). 2. **Deploy Your Project**: Click on **New Project**, then select the Git repository where your Vite PWA is located. 3. **Configure the Deployment**: Vercel will automatically detect that it's a Vite project and suggest default configurations. Adjust these settings as needed. 4. **Deploy**: After verifying the configuration, click on **Deploy** to start the deployment process. ### Step 4: Verify the Deployment Once deployment is complete, Vercel will provide a URL to access your deployed application. Check that everything works as expected, especially that the HTTP headers are applied correctly by inspecting the server responses using your browser's developer tools. ### Clearing the Data Cache in Vercel's Administration It might be useful to clear the data cache in Vercel's administration panel, especially if you are experiencing issues with stale content or deployment errors that seem unrelated to your current build. Clearing the cache ensures that all previous build settings, dependencies, and stored data are removed, allowing a fresh start for a new deployment. This can help in resolving unexpected behavior and improving the reliability of deployment processes. Here is an explanation of the `vercel.json` configuration file, suitable for adding to your documentation: ## Understanding the `vercel.json` Configuration for Vercel Deployment The `vercel.json` file is a crucial component for configuring deployments on Vercel. It allows you to customize how Vercel serves your application, including how it handles HTTP headers, redirects, rewrites, caching, and more. This file should be placed in the root directory of your project. [Vercel docs](https://vercel.com/docs/projects/project-configuration) Below is a detailed explanation of each part of the `vercel.json` file provided in the setup instructions: ### HTTP Headers Configuration The `headers` section of the `vercel.json` file allows you to specify HTTP response headers that should be added to responses serving files from specified paths: * **HTML Files**: ```json { "source": "/(.*).html", "headers": [ { "key": "Cache-Control", "value": "public, max-age=0, must-revalidate" } ] } ``` This rule applies a `Cache-Control` header to all HTML files, indicating that they should not be cached (`max-age=0`) and must be revalidated with the server on each request. * **Service Worker**: ```json { "source": "/sw.js", "headers": [ { "key": "Cache-Control", "value": "public, max-age=0, must-revalidate" } ] } ``` Similar to HTML files, the service worker is set to no caching and must be checked for updates frequently to ensure it is up-to-date. * **Web Manifest**: ```json { "source": "/manifest.webmanifest", "headers": [ { "key": "Content-Type", "value": "application/manifest+json" } ] } ``` Ensures that the manifest file has the correct `Content-Type` header to be properly recognized by browsers. * **Assets**: ```json { "source": "/assets/(.*)", "headers": [ { "key": "Cache-Control", "value": "max-age=31536000, immutable" } ] } ``` Caches assets like images, scripts, and stylesheets aggressively, using a long `max-age` to improve loading times for returning visitors. * **Security Headers**: ```json { "source": "/(.*)", "headers": [ { "key": "X-Content-Type-Options", "value": "nosniff" }, { "key": "X-Frame-Options", "value": "DENY" }, { "key": "X-XSS-Protection", "value": "1; mode=block" } ] } ``` These headers enhance security by preventing sniffing attacks, framing your site from another site, and activating browser mechanisms to block reflected XSS attacks. ### Redirects and Rewrites * **Rewrites**: ```json { "source": "/(.*)", "destination": "/index.html" } ``` This rewrite rule is essential for single-page applications (SPAs). It directs any request to any path back to your `index.html`, allowing the front-end routing in your SPA to handle the path. --- --- url: /guide/cookbook.md --- # Vite, Rollup, PWA and Workbox cookbook In this page we're going to explain how `vite-plugin-pwa` builds the service worker. You can open Excalidraw source diagram for the SVG images. ## Vite config file ## Vite Build CLI ## vite-plugin-pwa closeBundle hook ## workbox-build injectManifest --- --- url: /examples/vitepress.md --- # VitePress You can find a set of examples in the [@vite-pwa/vitepress integration repo](https://github.com/vite-pwa/vitepress/tree/main/examples). You can also test `VitePress` integration using the source code of this documentation website, you can find it in the [documentation repo](https://github.com/vite-pwa/vite-pwa-docs). The behavior used in this website is [Prompt for update](/guide/prompt-for-update). To run this site on your local, execute the following script from your shell (from root folder): ```shell pnpm run preview ``` --- --- url: /frameworks/vitepress.md --- # VitePress ::: warning We recommend you use the latest version of VitePress. The latest versions will also require you to update your application to use Vite ^3.1.0. ::: ::: info For `Type declarations`, `Prompt for update` and `Periodic SW Updates` go to [Vue 3](/frameworks/vue#vue-3) entry. ::: ## VitePress PWA Module `vite-plugin-pwa` provides the new `withPwa` module augmentation that will allow you to use `vite-plugin-pwa` in your VitePress applications. You will need to install `@vite-pwa/vitepress` using: ::: code-group ```bash [pnpm] pnpm add -D @vite-pwa/vitepress ``` ```bash [yarn] yarn add -D @vite-pwa/vitepress ``` ```bash [npm] npm install -D @vite-pwa/vitepress ``` ::: To update your project to use the new `vite-plugin-pwa` for VitePress, you only need to wrap your VitePress config with `withPwa` (you don't need oldest `pwa` and `pwa-configuration` modules): ```ts // .vitepress/config.ts import { defineConfig } from 'vitepress' import { withPwa } from '@vite-pwa/vitepress' export default withPwa(defineConfig({ /* your VitePress options */ /* Vite PWA Options */ pwa: {} })) ``` ## Import Virtual Modules Since VitePress uses SSR/SSG, we need to call the `vite-plugin-pwa` virtual module using a dynamic `import`. This can be done in the [theme](https://vitepress.vuejs.org/guide/theme-introduction). You can either configure the plugin to auto update or prompt for update. Refer below for examples. ### Auto Update ::: details .vitepress/theme/index.ts ```ts import { h } from 'vue' import Theme from 'vitepress/theme' import RegisterSW from './components/RegisterSW.vue' export default { ...Theme, Layout() { return h(Theme.Layout, null, { 'layout-bottom': () => h(RegisterSW) }) } } ``` ::: ::: details .vitepress/theme/components/RegisterSW.vue ```vue ``` ::: ### Prompt for update ::: details .vitepress/theme/index.ts ```ts import { h } from 'vue' import Theme from 'vitepress/theme' import ReloadPrompt from './components/ReloadPrompt.vue' export default { ...Theme, Layout() { return h(Theme.Layout, null, { 'layout-bottom': () => h(ReloadPrompt) }) } } ``` ::: ::: details .vitepress/theme/components/ReloadPrompt.vue ```vue ``` ::: ## Experimental ### includeAllowlist To prevent breaking Vitepress layout when the user visits a page that does not exist, you can enable the new experimental option `includeAllowlist`, requires VitePress `1.0.0-rc.14+`. Check the problem in the following issue: https://github.com/vite-pwa/vitepress/issues/22. You also need to force your server to return response with status code 404 when the requested page doesn't exist. This option is only available for the `generateSW` strategy, to enable it, you need to add the following configuration: ```ts // .vitepress/config.ts import { defineConfig } from 'vitepress' import { withPwa } from '@vite-pwa/vitepress' export default withPwa(defineConfig({ /* your VitePress options */ /* Vite PWA Options */ pwa: { strategies: 'generateSW', // <== if omitted, defaults to `generateSW` workbox: { /* your workbox configuration if any */ }, experimental: { includeAllowlist: true } } })) ``` If you're using `injectManifest` strategy, you can find the required logic in the following [experimiental service worker](https://github.com/vite-pwa/vitepress/blob/main/examples/pwa-simple-sw/.vitepress/sw.ts). ## PWA Assets `@vite-pwa/vitepress` plugin will configure `integration` option properly. VitePress dev server will be restarted when changing the configuration (inlined or using external file). To inject the PWA icons links and the `theme-color`: * remove all links with rel `icon`, `apple-touch-icon` and `apple-touch-startup-image` from `head` entry in your VitePress configuration * remove the `theme-color` meta tag from `head` entry in your VitePress configuration You can find a working example in the [examples folder](https://github.com/vite-pwa/vitepress/tree/main/examples/pwa-simple-assets-generator). --- --- url: /examples/vue.md --- # Vue The `Vue 3` example project can be found on [examples/vue-router](https://github.com/vite-pwa/vite-plugin-pwa/tree/main/examples/vue-router) package/directory. The router used on this example project is [vue-router](https://next.router.vuejs.org/). To test `new content available`, you should rerun the corresponding script, and then refresh the page. If you are running an example with `Periodic SW updates`, you will need to wait 1 minute: ## Executing the examples ## generateSW ## injectManifest --- --- url: /frameworks/vue.md --- # Vue ## Vue 3 You can use the built-in `Vite` virtual module `virtual:pwa-register/vue` for `Vue 3` which will return `composition api` references (`ref`) for `offlineReady` and `needRefresh`. ### Type declarations ::: tip From version `0.14.5` you can also use types definition for vue instead of `vite-plugin-pwa/client`: ```json { "compilerOptions": { "types": [ "vite-plugin-pwa/vue" ] } } ``` Or you can add the following reference in any of your `d.ts` files (for example, in `vite-env.d.ts` or `global.d.ts`): ```ts /// ``` ::: ```ts declare module 'virtual:pwa-register/vue' { import type { Ref } from 'vue' import type { RegisterSWOptions } from 'vite-plugin-pwa/types' export type { RegisterSWOptions } export function useRegisterSW(options?: RegisterSWOptions): { needRefresh: Ref offlineReady: Ref updateServiceWorker: (reloadPage?: boolean) => Promise } } ``` ### Prompt for update You can use this `ReloadPrompt.vue` component: ::: details ReloadPrompt.vue ```vue ``` ::: ### Periodic SW Updates As explained in [Periodic Service Worker Updates](/guide/periodic-sw-updates), you can use this code to configure this behavior on your application with the virtual module `virtual:pwa-register/vue`: ```ts import { useRegisterSW } from 'virtual:pwa-register/vue' const intervalMS = 60 * 60 * 1000 const updateServiceWorker = useRegisterSW({ onRegistered(r) { r && setInterval(() => { r.update() }, intervalMS) } }) ``` The interval must be in milliseconds, in the example above it is configured to check the service worker every hour. ## Vue 2 Since this plugin only supports `Vue 3`, you cannot use the virtual module `virtual:pwa-register/vue`. You can copy `useRegisterSW.js` `mixin` to your `@/mixins/` directory in your application to make it working: ::: details useRegisterSW.js ```js export default { name: 'useRegisterSW', data() { return { updateSW: undefined, offlineReady: false, needRefresh: false } }, async mounted() { try { const { registerSW } = await import('virtual:pwa-register') const vm = this this.updateSW = registerSW({ immediate: true, onOfflineReady() { vm.offlineReady = true vm.onOfflineReadyFn() }, onNeedRefresh() { vm.needRefresh = true vm.onNeedRefreshFn() }, onRegistered(swRegistration) { swRegistration && vm.handleSWManualUpdates(swRegistration) }, onRegisterError(e) { vm.handleSWRegisterError(e) } }) } catch { console.log('PWA disabled.') } }, methods: { async closePromptUpdateSW() { this.offlineReady = false this.needRefresh = false }, onOfflineReadyFn() { console.log('onOfflineReady') }, onNeedRefreshFn() { console.log('onNeedRefresh') }, updateServiceWorker() { this.updateSW && this.updateSW(true) }, handleSWManualUpdates(swRegistration) {}, handleSWRegisterError(error) {} } } ``` ::: ### Prompt for update You can use this `ReloadPrompt.vue` component: ::: details ReloadPrompt.vue ```vue ``` ::: ### Periodic SW Updates As explained in [Periodic Service Worker Updates](/guide/periodic-sw-updates), you can use this code to configure this behavior on your application with the `useRegisterSW.js` `mixin`: ```vue ``` The interval must be in milliseconds, in the example above it is configured to check the service worker every hour.