pwa
Make your VuePress site a Progressive Web Application (PWA)[1].
Usage
npm i -D @vuepress/plugin-pwa@nextimport { pwaPlugin } from '@vuepress/plugin-pwa'
export default {
plugins: [
pwaPlugin({
// options
}),
],
}The plugin uses workbox-build to generate the service worker file, and register-service-worker to register the service worker.
A PWA uses a Service Worker[2] (SW for short) to cache and proxy site content.
Warning
If you have enabled this plugin once and want to disable it, you might need @vuepress/plugin-remove-pwa to remove the existing service worker.
Guide
Web App Manifests
To make your website fully compliant with PWA, a Web App Manifest[3] file is needed, and your PWA should satisfy the installability[4] specification.
You can set the manifest option to customize the manifest file, or provide a manifest.webmanifest or manifest.json in the public folder. The former has higher priority.
The plugin automatically generates manifest.webmanifest for you and adds a manifest link declaration in each page, while you should still at least set a valid icon through manifest.icons or other icon-related options.
Warning
The installability[4:1] specification requires at least one valid icon to be declared in the manifest.
So if you do not configure manifest.icons, visitors can only enjoy the offline accessibility brought by the Service Worker cache, but cannot install your site as a PWA.
Some manifest fields have a fallback when you do not set them:
name:siteConfig.title||siteConfig.locales['/'].title||"Site"short_name:siteConfig.title||siteConfig.locales['/'].title||"Site"description:siteConfig.description||siteConfig.locales['/'].description||"A site built with vuepress"lang:siteConfig.locales['/'].lang||siteConfig.langstart_url:context.basescope:context.basedisplay:"standalone"theme_color:themeColor||"#46bd87"background_color:"#ffffff"orientation:"portrait-primary"prefer_related_applications:false
It is recommended to set favicon for your site.
The plugin does not process anything in the manifest by default, but outputs them as-is. This means that if you plan to deploy to a subdirectory, you should append the URL prefix to manifest URLs yourself. If everything you need is all under the base directory, you can set appendBase to true to let the plugin append base to any links in the manifest.
Cache Control
To better control what the Service Worker can pre-cache, the plugin provides related options for cache control.
Default Cache
By default, the plugin pre-caches all js and css files, and only the homepage and 404 HTML are cached. The plugin also caches font files (woff, woff2, eot, ttf, otf) and SVG icons.
Image Cache
If your site has only a few important images and you want them displayed in offline mode, you can cache site images by setting cacheImage to true.
Images are recognized by file extension. Any file ending with .png, .jpg, .jpeg, .gif, .bmp or .webp is regarded as an image.
HTML Cache
If you have a small site and would like to make documents fully available offline, you can set cacheHTML to true to cache all HTML files.
Why are only home and 404 pages cached by default?
Though VuePress generates HTML files through SSG[5] for all pages, these files are mainly used for SEO[6] and allow you to directly visit any link without configuring the backend as SPA[7].
VuePress is essentially an SPA. This means that you only need to cache the home page and enter from the home page to access all pages normally. Therefore, not caching other HTML by default can effectively reduce the cache size (40% smaller in size) and speed up the SW update speed.
But this also has disadvantages. If the user enters the site directly from a non-home page, the HTML file for the first page still needs to be loaded from the internet. Also, in an offline environment, users can only enter through the homepage and then navigate to the corresponding page by themselves. If they directly access a link, an inaccessible prompt will appear.
Size Control
To prevent large files from being included in the pre-cache list, any file > 2 MB or image > 1 MB will be omitted. You can customize these limits with maxSize and maxImageSize (in KB unit).
maxSize has the highest priority, and any file exceeding it will be excluded. So if you generate very large HTML or JS files, please consider increasing it, otherwise your PWA may not work normally in offline mode.
maxImageSize must not be greater than maxSize.
Update Control
The update option controls how users receive updates. Its default value is "available".
"available": The new SW is installed and its resources are fetched silently in the background. A pop-up window appears once the new SW is ready, and users can choose whether to refresh immediately to view new content. This means users are reading old content before a new SW is ready."hint": Users are notified that new content has been published within seconds after visiting the docs, and can choose to refresh immediately. If the user chooses to refresh, the page is reloaded at once, then the new SW installs and takes control of the page. The negative effect is that the user needs to get all the resources of the page from the internet before the new SW installs and controls the page."disable": The new SW is installed completely silently in the background and starts waiting. When all pages controlled by the old SW are closed, the new SW starts to take control and provides users with new content during the next visit. This setting prevents users from being disturbed during their visit."force": The page is force-reloaded as soon as a new SW is detected, ensuring that users always browse the latest content. The biggest disadvantage is that all users experience an unexpected sudden refresh within seconds after re-entering an updated site.
Tips
How docs are updated is controlled by the previous version, so the current option only affects the next update from this version.
Popups
When new content is detected (a new SW is detected), an update found popup appears; and when the new content is ready, an update ready popup appears.
If you are not satisfied with the default popup content, you can use your own component. Import PwaFoundPopup or PwaReadyPopup from @vuepress/plugin-pwa/client and use its slot to customize the popup content, then pass the component path to foundComponent or readyComponent option:
<script setup lang="ts">
import { PwaFoundPopup } from '@vuepress/plugin-pwa/client'
</script>
<template>
<PwaFoundPopup v-slot="{ found, refresh }">
<div v-if="found">
New content is found.
<button type="button" @click="refresh">Refresh</button>
</div>
</PwaFoundPopup>
</template><script setup lang="ts">
import { PwaReadyPopup } from '@vuepress/plugin-pwa/client'
</script>
<template>
<PwaReadyPopup v-slot="{ isReady, reload }">
<div v-if="isReady">
New content is ready.
<button type="button" @click="reload">Apply</button>
</div>
</PwaReadyPopup>
</template>Other Options
The plugin also provides other PWA-related options, such as Microsoft tile icon and color settings, Apple icons (apple), and so on. If you are an advanced user, you can also set generateSWConfig to configure workbox-build.
Options
string'service-worker.js'Service Worker file path.
booleantrueWhether to display the install button when the Service Worker is first registered successfully.
AppManifestThe object to be parsed to manifest.webmanifest, which is generated and injected into every page by the plugin.
See also: Web App Manifests.
stringLink of favicon.ico.
string'#46bd87'Theme color of the PWA.
booleanfalseWhether to cache HTML files besides the home page and the 404 page.
See also: HTML Cache.
'available' | 'disable' | 'force' | 'hint''available'How users receive updates.
See also: Update Control.
ApplePwaOptions | falseSpecial settings for better supporting Safari, ignoring these options is safe.
stringIcon link used by Safari, recommend 152×152 size.
stringSafari mask icon.
'black-translucent' | 'black' | 'default''default'Status bar color for Safari. The related tag is unstandardized, so you should avoid declaring it.
string'PwaReadyPopup'Path of the custom update popup component.
See also: Popups.
booleanfalseWhether to append base to all absolute links in options.
See also: Web App Manifests.
Partial<GenerateSWOptions>Options passed to workbox-build, see Workbox documentation.
LocaleConfig<PwaPluginLocaleData>Locales config for the PWA plugin. The locale data is a partial of PwaPluginLocaleData.
See also: Locales.
stringInstall button text.
stringIOS install hint text.
stringCancel button text.
stringClose button text.
stringPrevious image text.
stringNext image text.
stringInstall explain text.
stringDescription label text.
stringFeature label text.
stringUpdate hint text.
stringUpdate available text.
Composition API
usePwaEvent
Type:
() => PwaEventReturns: Event emitter of this plugin
Details: Returns the event emitter of this plugin. You can add listener function to events that provided by register-service-worker.
Example:
import { usePwaEvent } from '@vuepress/plugin-pwa/client' export default { setup(): void { const event = usePwaEvent() event.on('ready', (registration) => { console.log('Service worker is active.') }) }, }
Utilities
forceUpdate
Type:
() => voidDetails: Force update the page when an update is found.
Example:
import { forceUpdate } from '@vuepress/plugin-pwa/client' import { onMounted } from 'vue' export default { setup(): void { onMounted(() => { forceUpdate() }) }, }
registerSW
Type:
(serviceWorkerPath: string, hooks?: Hooks, showStatus?: boolean) => Promise<void>Parameters:
Parameter Type Description serviceWorkerPath stringPath of the service worker hooks objectHooks of service worker showStatus booleanLog service worker status in console interface Hooks { registrationOptions?: RegistrationOptions ready?: (registration: ServiceWorkerRegistration) => void registered?: (registration: ServiceWorkerRegistration) => void cached?: (registration: ServiceWorkerRegistration) => void updated?: (registration: ServiceWorkerRegistration) => void updatefound?: (registration: ServiceWorkerRegistration) => void offline?: () => void error?: (error: Error) => void }Details: Register service worker manually.
Example:
import { registerSW } from '@vuepress/plugin-pwa/client' import { onMounted } from 'vue' export default { setup(): void { onMounted(() => { registerSW('/service-worker.js', { ready(registration) { console.log('Service worker is active.') }, }) }) }, }
skipWaiting
Type:
(registration: ServiceWorkerRegistration) => voidParameters:
Parameter Type Description registration ServiceWorkerRegistrationThe registration of the service worker you want activate Details: Activate the waiting service worker.
Example:
import { skipWaiting, usePwaEvent } from '@vuepress/plugin-pwa/client' export default { setup(): void { const event = usePwaEvent() event.on('updated', (registration) => { console.log('The waiting service worker is available.') // activate the waiting service worker skipWaiting(registration) }) }, }
unregisterSW
Type:
() => Promise<boolean>Returns:
trueif unregister success,falseif unregister failedDetails: Unregister service worker manually.
Example:
import { unregisterSW } from '@vuepress/plugin-pwa/client' import { onMounted } from 'vue' export default { setup(): void { onMounted(() => { unregisterSW() }) }, }
Styles
You can customize the style via CSS variables:
:root {
--pwa-z-index: 10;
--pwa-c-bg: var(--vp-c-bg-elv);
--pwa-c-text: var(--vp-c-text);
--pwa-c-shadow: var(--vp-c-shadow);
--pwa-c-accent-bg: var(--vp-c-accent-bg);
--pwa-c-accent-hover: var(--vp-c-accent-hover);
--pwa-c-accent-text: var(--vp-c-accent-text);
--pwa-c-control: var(--vp-c-control);
--pwa-c-control-hover: var(--vp-c-control-hover);
--pwa-c-text-mute: var(--vp-c-text-mute);
}Further Reading
For more details, please see:
PWA Introduction
PWA, full name Progressive Web App, is a standard stipulated by W3C.
It allows sites to install themselves as an App on supported platforms through browsers that support this feature.
See https://developer.mozilla.org/en-US/docs/Web/Progressive_web_apps for details. ↩︎
Service Worker Introduction
The Service Worker will get and cache all the files registered in it during the registration process.
After the registration completes, the Service Worker is activated and starts to proxy and control all your requests.
Whenever you want to initiate an access request through the browser, the Service Worker will check whether it exists in its own cache list. If it exists, it will directly return the cached result; otherwise, it will call its own fetch method to get it. You can use a custom fetch method to fully control the result of requests for resources in the web page, such as providing a fallback web page when offline.
Every time the user reopens the site, the Service Worker will request the link where it was registered. If a new version of Service Worker is detected, it will update itself and start caching the list of resources registered in the new Service Worker. After the content update is successfully obtained, the Service Worker will trigger the
updateevent. The user can be notified through this event, for example, a pop-up window will be displayed in the lower right corner, prompting the user that new content is available and allowing the user to trigger an update.
Manifest File
The manifest file uses the JSON format and is responsible for declaring various information of the PWA, such as name, description, icon, and shortcut actions.
In order for your site to be registered as a PWA, you need to meet the basic specifications of the manifest to make the browser consider the site as an installable PWA and allow users to install it.
↩︎Tips
For Manifest standards and specifications, please see MDN Web App manifests and W3C Manifest.
Installable
To let the site be registered as a PWA, the site needs to successfully register a valid service worker by itself, and declare a valid manifest file with its link in meta tag.
The manifest file should contain at least
name(orshort_name)iconsstart_url.On Safari, the maximum cache size of the service worker is 50 MB. ↩︎ ↩︎
SSG: Static Site Generation ↩︎
SEO: Search Engine Optimization ↩︎
SPA: Single Page Application, most of them only have the homepage and use history mode to handle routing instead of actually navigating between pages. ↩︎
