This is the docs for master (targeting upcoming gridsome@0.8). For older releases, checkout v0.3.0, v0.2.5
This plugin is based on gridsome-plugin-pwa and @vue/cli-plugin-pwa
, and it is created to be a better alternative. it serves manifest and no-op service worker in development, use similar config structure, just as vue-cli
does
It tries to be more similar to cli-plugin-pwa
, but makes use of gridsome's image processing power.
It uses jest, puppeteer and lighthouse for unit and e2e testing, to stabilize the plugin.
You need register-service-worker
to register service worker yourself.
npm install @allanchain/gridsome-plugin-pwa register-service-worker
# or
yarn add @allanchain/gridsome-plugin-pwa register-service-worker
This plugin should work with zero config (you still nead step 3) if your favicon source image is at least 512x512
// gridsome.config.js
module.exports = {
plugins: [
{
use: '@allanchain/gridsome-plugin-pwa',
options: {}
}
]
}
Checkout Options for detailed explanation of all options.
You can also checkout example gridsome app.
generateSW
mode:
{
manifestOptions: {
short_name: 'Gridsome',
description: 'Gridsome is awesome!',
display: 'standalone',
gcm_sender_id: undefined,
start_url: '/',
categories: ['education'],
lang: 'en-GB',
dir: 'auto'
},
appleMobileWebAppStatusBarStyle: 'default',
manifestPath: 'manifest.json',
icon: 'src/favicon.png',
msTileColor: '#00a672',
workboxOptions: {
cacheId: 'awesome-pwa',
globPatterns: ['assets/css/*', '*.js', 'index.html'],
skipWaiting: true
}
}
injectManifest
mode:
{
workboxPluginMode: 'injectManifest',
workboxOptions: {
swSrc: './src/service-worker.js',
globPatterns: ['assets/css/*', '*.js', 'index.html']
}
}
You need manually register service worker, just as what you do in vue-cli
, which gives you more power.
Create registerServiceWorker.js
and import it in main.js
A good start point is vue-cli
's template. src/registerServiceWorker.js
:
/* eslint-disable no-console */
import { register } from 'register-service-worker'
register('/service-worker.js', {
ready () {
console.log(
'App is being served from cache by a service worker.\n' +
'For more details, visit https://goo.gl/AFskqB'
)
},
registered () {
console.log('Service worker has been registered.')
},
cached () {
console.log('Content has been cached for offline use.')
},
updatefound () {
console.log('New content is downloading.')
},
updated () {
console.log('New content is available; please refresh.')
},
offline () {
console.log('No internet connection found. App is running in offline mode.')
},
error (error) {
console.error('Error during service worker registration:', error)
}
})
src/main.js
:
export default function (Vue, { router, head, isClient }) {
if (isClient && process.env.NODE_ENV === 'production') {
require('./registerServiceWorker')
}
// ...
}
Default: 'generateSW'
This allows you to the choose between the two modes supported by the underlying
workbox-build
.
-
'generateSW'
will lead to a new service worker file being created each time you rebuild your web app. -
'injectManifest'
allows you to start with an existing service worker file, and creates a copy of that file with a "precache manifest" injected into it.
The "Which Plugin to Use?" guide can help you choose between the two modes.
Default: true
Only works in injectManifest
mode. Compile your service-worker.js
with webpack.
Will be applied to compilation if set to an array of webpack plugins.
Default:
{
modifyURLPrefix: { '': config.publicPath },
globDirectory: config.outputDir,
globPatterns: ['assets/css/*', '*.js'],
swDest: path.join(config.outputDir, 'service-worker.js')
sourcemap: false, // if generateSW
cacheId: config.siteName // if generateSW
}
These options are passed on through to the underlying workbox-build
.
For more information on what values are supported, please see the guide for
generateSW
or for injectManifest
.
It is not recommended to precache all files, because your site can be large. Instead, precache important files and consider runtime caching for other files.
Default: null
The relative file path from outputDir
to the html file for app shell. Only makes sense when using navigation fallback.
For example:
- Using
generateSW
mode and setting upnavigateFallback
:{ appShellPath: 'offline/index.html', workboxOptions: { globPatterns: ['assets/css/*', '*.js', 'offline/index.html'], navigateFallback: '/gridsome/offline/index.html', navigateFallbackAllowlist: [/\/$/] } }
- Using
injectManifest
mode and registering aNavigationRoute
inservice-worker.js
.registerRoute( new NavigationRoute(createHandlerBoundToURL(APP_SHELL), { allowlist: [/\/$/] }) )
You may also want to check out examples.
Sourced from gatsby-plugin-offline doc:
The app shell is a minimal amount of user interface that can be cached offline for reliable performance loading on repeat visits.
As for gridsome, it checks window.__INITIAL_STATE__
for data (mostly page query results), falling back to fetch data from json files. All this plugin does are disabling client side hydration in appShellPath
html, and deleting window.__INITIAL_STATE__
in appShellPath
html to tell gridsome to fetch data from json files. You should define app shell behavior in service-worker.js
.
Default: config.siteName
Used as the value for the apple-mobile-web-app-title
and application-name
meta tags in the generated HTML.
Default: '#00a672'
Default: 'no'
This defaults to 'no'
because iOS before 11.3 does not have proper PWA support. See this article for more details.
Default: 'default'
Default: 'manifest.json'
The path of app’s manifest. It will be prefixed with publicPath
(e.g. '/'
, '/gridsome/'
) to generate the final manifest url. Different to vue-cli
, currently you can only use the generated manifest.
Default:
{
start_url: '.',
display: 'standalone',
background_color: '#000000'
}
The object will be used to generate the manifest.json
If the following attributes are not defined in the object, default options will be used instead.
- name:
name
- short_name:
name
- start_url:
'.'
- display:
'standalone'
- theme_color:
themeColor
Default: your favicon, usually ./src/favicon.png
Note: you need a at least 512x512 image to generate every needed icon.
Or in detail
{
androidChrome: [{
src, // your favicon, usually `./src/favicon.png`
sizes: [512, 384, 192, 144, 96, 72, 48],
purpose: 'any',
urls: null
}],
msTileImage: {
src,
size: 144,
url: null
},
appleMaskIcon: {
url: null
}
}
You can use another icon file to generate icons of all sizes:
{
icon: './src/my-icon.png'
}
It is a relative file path, not a relative URL.
Or you can configure Android Chrome (icons in manifest.json
) icon file:
{
icon: {
androidChrome: './src/android.png'
}
}
Also configure output sizes and maskable:
{
icon: {
androidChrome: {
src: './src/maskable-icon.png',
sizes: [512, 384, 192, 144, 96, 72, 48],
purpose: 'maskable'
}
}
}
The above config will generate android-chrome-512x512.png
, android-chrome-384x364.png
... from ./src/my-icon.png
, and mark them as maskable.
And it is also possible to use different source for 'maskable'
and 'any'
:
{
icon: {
androidChrome: [
{
src: './src/my-icon.png',
sizes: [512, 384, 192, 144, 96, 72, 48],
purpose: 'any'
},
{
src: './src/maskable-icon.png',
sizes: [512, 384, 192, 144, 96, 72, 48],
purpose: 'maskable'
}
]
}
}
Although it is possible to set purpose
to 'maskable any'
, it is not recommended, as explained in Adaptive icon support in PWAs with maskable icons:
While you can specify multiple space-separated purposes like
"any maskable"
, in practice you shouldn't. Using"maskable"
icons as"any"
icons is suboptimal as the icon is going to be used as-is, resulting in excess padding and making the core icon content smaller. Ideally, icons for the"any"
purpose should have transparent regions and no extra padding, like your site's favicons, since the browser isn't going to add that for them.
If you don't want icons to be generated, provide URLs:
{
icon: {
androidChrome: {
sizes: [512, 192],
urls: ['/icons/512x512.png', '/icons/192x192.png']
}
}
}
msTileImage
is similar to androidChrome
, but only one icon. e.g.:
{
icon: {
msTileImage: {
url: 'assets/icons/android-chrome-144x144.png'
}
}
}
appleMaskIcon
is a square SVG image, with a transparent (or simply: no) background, and all vectors 100% black. It is not auto generated, and you should provide URL if you want to include it:
{
icon: {
appleMaskIcon: {
url: '/safari-pinned-tab.svg'
}
}
}
Default: '#00a672'
Default: themeColor
Active color of appleMaskIcon
Yarn 2 is used starting from @allanchain/gridsome-plugin-pwa@0.4.0
, making commands much simpler.
# Install for both root and example
yarn
Now you can make modifications to this plugin and run yarn develop
in example project to see the effect.
Or run yarn test
in root dir of this project to see test results.