{"id":20618660,"url":"https://github.com/allanchain/gridsome-plugin-pwa","last_synced_at":"2025-10-13T16:08:18.667Z","repository":{"id":54751216,"uuid":"277435578","full_name":"AllanChain/gridsome-plugin-pwa","owner":"AllanChain","description":"Yet another PWA plugin for Gridsome.","archived":false,"fork":false,"pushed_at":"2023-06-03T14:57:13.000Z","size":4786,"stargazers_count":7,"open_issues_count":4,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-03-28T19:38:41.154Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/AllanChain.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2020-07-06T03:41:55.000Z","updated_at":"2021-11-21T02:29:36.000Z","dependencies_parsed_at":"2023-01-21T16:46:04.557Z","dependency_job_id":null,"html_url":"https://github.com/AllanChain/gridsome-plugin-pwa","commit_stats":null,"previous_names":[],"tags_count":16,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AllanChain%2Fgridsome-plugin-pwa","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AllanChain%2Fgridsome-plugin-pwa/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AllanChain%2Fgridsome-plugin-pwa/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AllanChain%2Fgridsome-plugin-pwa/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/AllanChain","download_url":"https://codeload.github.com/AllanChain/gridsome-plugin-pwa/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":249062308,"owners_count":21206661,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-16T12:09:07.883Z","updated_at":"2025-10-13T16:08:13.629Z","avatar_url":"https://github.com/AllanChain.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# @allanchain/gridsome-plugin-pwa\n\n[![npm (scoped)](https://img.shields.io/npm/v/@allanchain/gridsome-plugin-pwa)](https://www.npmjs.com/package/@allanchain/gridsome-plugin-pwa)\n![License](https://img.shields.io/github/license/AllanChain/gridsome-plugin-pwa)\n![Run Tests](https://github.com/AllanChain/gridsome-plugin-pwa/workflows/Run%20Tests/badge.svg)\n[![codecov](https://codecov.io/gh/AllanChain/gridsome-plugin-pwa/branch/master/graph/badge.svg)](https://codecov.io/gh/AllanChain/gridsome-plugin-pwa)\n\n:warning: **status: not so stable, contributions welcome**\n\nThis is the docs for **master (targeting upcoming gridsome@0.8)**. For older releases, checkout\n[v0.3.0](https://github.com/AllanChain/gridsome-plugin-pwa/blob/v0.3.0/README.md),\n[v0.2.5](https://github.com/AllanChain/gridsome-plugin-pwa/blob/v0.2.5/README.md)\n\n---\n\n- [Overview](#overview)\n- [Installation](#installation)\n  - [1. Add to Dependencies](#1-add-to-dependencies)\n  - [2. Register as Gridsome Plugin](#2-register-as-gridsome-plugin)\n    - [Example Configuration](#example-configuration)\n  - [3. Register service worker](#3-register-service-worker)\n- [Options](#options)\n  - [workboxPluginMode](#workboxpluginmode)\n  - [workboxCompileSrc](#workboxcompilesrc)\n  - [workboxOptions](#workboxoptions)\n  - [appShellPath](#appshellpath)\n  - [name](#name)\n  - [themeColor](#themecolor)\n  - [appleMobileWebAppCapable](#applemobilewebappcapable)\n  - [appleMobileWebAppStatusBarStyle](#applemobilewebappstatusbarstyle)\n  - [manifestPath](#manifestpath)\n  - [manifestOptions](#manifestoptions)\n  - [icon](#icon)\n  - [msTileColor](#mstilecolor)\n  - [appleMaskIconColor](#applemaskiconcolor)\n- [Developing and Testing](#developing-and-testing)\n- [LICENSE](#license)\n\n## Overview\n\nThis plugin is based on [gridsome-plugin-pwa](https://github.com/rishabh3112/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\n\nIt tries to be more similar to `cli-plugin-pwa`, but makes use of gridsome's image processing power.\n\nIt uses jest, puppeteer and lighthouse for unit and e2e testing, to stabilize the plugin.\n\n## Installation\n\n### 1. Add to Dependencies\n\nYou need `register-service-worker` to register service worker yourself.\n\n```bash\nnpm install @allanchain/gridsome-plugin-pwa register-service-worker\n# or\nyarn add @allanchain/gridsome-plugin-pwa register-service-worker\n```\n\n### 2. Register as Gridsome Plugin\n\nThis plugin should work with zero config (you still nead step 3) if your favicon source image is at least `512x512`\n\n```js\n// gridsome.config.js\nmodule.exports = {\n  plugins: [\n    {\n      use: '@allanchain/gridsome-plugin-pwa',\n      options: {}\n    }\n  ]\n}\n```\n\nCheckout [Options](#options) for detailed explanation of all options.\n\n#### Example Configuration\n\nYou can also checkout [example gridsome app](examples/basic/gridsome.config.js).\n\n`generateSW` mode:\n\n```js\n{\n  manifestOptions: {\n    short_name: 'Gridsome',\n    description: 'Gridsome is awesome!',\n    display: 'standalone',\n    gcm_sender_id: undefined,\n    start_url: '/',\n    categories: ['education'],\n    lang: 'en-GB',\n    dir: 'auto'\n  },\n  appleMobileWebAppStatusBarStyle: 'default',\n  manifestPath: 'manifest.json',\n  icon: 'src/favicon.png',\n  msTileColor: '#00a672',\n  workboxOptions: {\n    cacheId: 'awesome-pwa',\n    globPatterns: ['assets/css/*', '*.js', 'index.html'],\n    skipWaiting: true\n  }\n}\n```\n\n`injectManifest` mode:\n\n```js\n{\n  workboxPluginMode: 'injectManifest',\n  workboxOptions: {\n    swSrc: './src/service-worker.js',\n    globPatterns: ['assets/css/*', '*.js', 'index.html']\n  }\n}\n```\n\n### 3. Register service worker\n\nYou need manually register service worker, just as what you do in `vue-cli`, which gives you more power.\n\nCreate `registerServiceWorker.js` and import it in `main.js`\n\nA good start point is `vue-cli`'s template. `src/registerServiceWorker.js`:\n\n```js\n/* eslint-disable no-console */\n\nimport { register } from 'register-service-worker'\n\nregister('/service-worker.js', {\n  ready () {\n    console.log(\n      'App is being served from cache by a service worker.\\n' +\n      'For more details, visit https://goo.gl/AFskqB'\n    )\n  },\n  registered () {\n    console.log('Service worker has been registered.')\n  },\n  cached () {\n    console.log('Content has been cached for offline use.')\n  },\n  updatefound () {\n    console.log('New content is downloading.')\n  },\n  updated () {\n    console.log('New content is available; please refresh.')\n  },\n  offline () {\n    console.log('No internet connection found. App is running in offline mode.')\n  },\n  error (error) {\n    console.error('Error during service worker registration:', error)\n  }\n})\n\n```\n\n`src/main.js`:\n\n```js\nexport default function (Vue, { router, head, isClient }) {\n    if (isClient \u0026\u0026 process.env.NODE_ENV === 'production') {\n      require('./registerServiceWorker')\n    }\n  // ...\n}\n```\n\n## Options\n\n### workboxPluginMode\n\nDefault: `'generateSW'`\n\nThis allows you to the choose between the two modes supported by the underlying\n[`workbox-build`](https://developers.google.com/web/tools/workbox/modules/workbox-build).\n\n- `'generateSW'` will lead to a new service worker file being created\neach time you rebuild your web app.\n\n- `'injectManifest'` allows you to start with an existing service worker file,\nand creates a copy of that file with a \"precache manifest\" injected into it.\n\nThe \"[Which Plugin to Use?](https://developers.google.com/web/tools/workbox/modules/workbox-build#which_plugin_to_use)\"\nguide can help you choose between the two modes.\n\n### workboxCompileSrc\n\nDefault: `true`\n\nOnly works in `injectManifest` mode. Compile your `service-worker.js` with webpack.\n\nWill be applied to compilation if set to an array of webpack plugins.\n\n### workboxOptions\n\nDefault:\n\n```js\n{\n  modifyURLPrefix: { '': config.publicPath },\n  globDirectory: config.outputDir,\n  globPatterns: ['assets/css/*', '*.js'],\n  swDest: path.join(config.outputDir, 'service-worker.js')\n  sourcemap: false, // if generateSW\n  cacheId: config.siteName // if generateSW\n}\n```\n\nThese options are passed on through to the underlying `workbox-build`.\n\nFor more information on what values are supported, please see the guide for\n[`generateSW`](https://developers.google.com/web/tools/workbox/modules/workbox-build#full_generateSW_config)\nor for [`injectManifest`](https://developers.google.com/web/tools/workbox/modules/workbox-build#full_injectManifest_config).\n\n**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.\n\n### appShellPath\n\nDefault: `null`\n\n:warning: This is a very experimental feature, or rather, a proof of concept.\n\nThe relative file path from `outputDir` to the html file for app shell. Only makes sense when using navigation fallback.\n\nFor example:\n\n- Using `generateSW` mode and setting up `navigateFallback`:\n  ```js\n  {\n    appShellPath: 'offline/index.html',\n    workboxOptions: {\n      globPatterns: ['assets/css/*', '*.js', 'offline/index.html'],\n      navigateFallback: '/gridsome/offline/index.html',\n      navigateFallbackAllowlist: [/\\/$/]\n    }\n  }\n  ```\n- Using `injectManifest` mode and registering a `NavigationRoute` in `service-worker.js`.\n  ```js\n  registerRoute(\n    new NavigationRoute(createHandlerBoundToURL(APP_SHELL), {\n      allowlist: [/\\/$/]\n    })\n  )\n  ```\n\nYou may also want to check out [examples](examples).\n\nSourced from [gatsby-plugin-offline doc](https://www.gatsbyjs.com/plugins/gatsby-plugin-offline/#app-shell-and-server-logs):\n\n\u003e The app shell is a minimal amount of user interface that can be cached offline for reliable performance loading on repeat visits.\n\nAs 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](https://ssr.vuejs.org/guide/hydration.html) 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`.\n\n### name\n\nDefault: `config.siteName`\n\nUsed as the value for the `apple-mobile-web-app-title` and `application-name` meta tags in the generated HTML.\n\n### themeColor\n\nDefault: `'#00a672'`\n\n### appleMobileWebAppCapable\n\nDefault: `'no'`\n\nThis defaults to `'no'` because iOS before 11.3 does not have proper PWA support. See [this article](https://medium.com/@firt/dont-use-ios-web-app-meta-tag-irresponsibly-in-your-progressive-web-apps-85d70f4438cb) for more details.\n\n### appleMobileWebAppStatusBarStyle\n\nDefault: `'default'`\n\n### manifestPath\n\nDefault: `'manifest.json'`\n\nThe 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.\n\n### manifestOptions\n\nDefault:\n```js\n{\n  start_url: '.',\n  display: 'standalone',\n  background_color: '#000000'\n}\n```\n\nThe object will be used to generate the `manifest.json`\n\nIf the following attributes are not defined in the object, default options will be used instead.\n  - name: `name`\n  - short_name: `name`\n  - start_url: `'.'`\n  - display: `'standalone'`\n  - theme_color: `themeColor`\n\n### icon\n\nDefault: your favicon, usually `./src/favicon.png`\n\nNote: you need a **at least 512x512** image to generate every needed icon.\n\n\u003cdetails\u003e\u003csummary\u003eOr in detail\u003c/summary\u003e\n\n```js\n{\n  androidChrome: [{\n    src, // your favicon, usually `./src/favicon.png`\n    sizes: [512, 384, 192, 144, 96, 72, 48],\n    purpose: 'any',\n    urls: null\n  }],\n  msTileImage: {\n    src,\n    size: 144,\n    url: null\n  },\n  appleMaskIcon: {\n    url: null\n  }\n}\n```\n\u003c/details\u003e\n\nYou can use another icon file to generate icons of all sizes:\n\n```js\n{\n  icon: './src/my-icon.png'\n}\n```\n\nIt is a relative **file path**, not a relative URL.\n\nOr you can configure Android Chrome (icons in `manifest.json`) icon file:\n\n```js\n{\n  icon: {\n    androidChrome: './src/android.png'\n  }\n}\n```\n\nAlso configure output sizes and maskable:\n\n```js\n{\n  icon: {\n    androidChrome: {\n      src: './src/maskable-icon.png',\n      sizes: [512, 384, 192, 144, 96, 72, 48],\n      purpose: 'maskable'\n    }\n  }\n}\n```\n\nThe above config will generate `android-chrome-512x512.png`, `android-chrome-384x364.png`... from `./src/my-icon.png`, and mark them as maskable.\n\nAnd it is also possible to use different source for `'maskable'` and `'any'`:\n\n```js\n{\n  icon: {\n    androidChrome: [\n      {\n        src: './src/my-icon.png',\n        sizes: [512, 384, 192, 144, 96, 72, 48],\n        purpose: 'any'\n      },\n      {\n        src: './src/maskable-icon.png',\n        sizes: [512, 384, 192, 144, 96, 72, 48],\n        purpose: 'maskable'\n      }\n    ]\n  }\n}\n```\n\nAlthough it is possible to set `purpose` to `'maskable any'`, it is not recommended, as explained in [Adaptive icon support in PWAs with maskable icons](https://web.dev/maskable-icon/):\n\n\u003e 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.\n\nIf you don't want icons to be generated, provide URLs:\n\n```js\n{\n  icon: {\n    androidChrome: {\n      sizes: [512, 192],\n      urls: ['/icons/512x512.png', '/icons/192x192.png']\n    }\n  }\n}\n```\n\n`msTileImage` is similar to `androidChrome`, but only one icon. e.g.:\n\n```js\n{\n  icon: {\n    msTileImage: {\n      url: 'assets/icons/android-chrome-144x144.png'\n    }\n  }\n}\n```\n\n`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:\n\n```js\n{\n  icon: {\n    appleMaskIcon: {\n      url: '/safari-pinned-tab.svg'\n    }\n  }\n}\n```\n\n### msTileColor\n\nDefault: `'#00a672'`\n\n### appleMaskIconColor\n\nDefault: `themeColor`\n\nActive color of `appleMaskIcon`\n\n## Developing and Testing\n\nYarn 2 is used starting from `@allanchain/gridsome-plugin-pwa@0.4.0`, making commands much simpler.\n\n```bash\n# Install for both root and example\nyarn\n```\n\nNow you can make modifications to this plugin and run `yarn develop` in example project to see the effect.\n\nOr run `yarn test` in root dir of this project to see test results.\n\n## LICENSE\n\n[MIT](LICENSE)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fallanchain%2Fgridsome-plugin-pwa","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fallanchain%2Fgridsome-plugin-pwa","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fallanchain%2Fgridsome-plugin-pwa/lists"}