├── test ├── fixture │ ├── static │ │ ├── .gitkeep │ │ ├── precache.js │ │ ├── OneSignalSDKUpdaterWorker.js │ │ ├── icon.png │ │ ├── offline.png │ │ ├── OneSignalSDKWorker.js │ │ ├── offline.html │ │ └── custom-sw.js │ ├── .gitignore │ ├── sw │ │ ├── caching.js │ │ ├── routing.js │ │ └── workbox.js │ ├── pages │ │ ├── _page.vue │ │ └── index.vue │ ├── tsconfig.json │ ├── layouts │ │ └── default.vue │ └── nuxt.config.ts ├── pwa.test.js └── __snapshots__ │ └── pwa.test.js.snap ├── .github ├── ISSUE_TEMPLATE.md └── workflows │ └── test.yml ├── docs ├── .gitignore ├── static │ ├── icon.png │ ├── preview.png │ ├── preview-dark.png │ ├── logo-dark.svg │ └── logo-light.svg ├── content │ ├── en │ │ ├── onesignal.md │ │ ├── index.md │ │ ├── setup.md │ │ ├── icon.md │ │ ├── meta.md │ │ ├── manifest.md │ │ └── workbox.md │ └── settings.json ├── nuxt.config.js ├── package.json ├── tailwind.config.js └── README.md ├── templates ├── meta.json ├── meta.plugin.js ├── icon.plugin.js └── workbox │ ├── sw.unregister.js │ ├── workbox.js │ ├── workbox.unregister.js │ └── sw.js ├── renovate.json ├── jest.config.js ├── .eslintrc ├── .gitignore ├── .eslintignore ├── types ├── index.d.ts ├── pwa.d.ts ├── manifest.d.ts ├── icon.d.ts ├── meta.d.ts └── workbox.d.ts ├── .editorconfig ├── tsconfig.json ├── netlify.toml ├── lib ├── meta.utils.js └── resize.js ├── LICENSE ├── README.md ├── src ├── workbox │ ├── defaults.ts │ ├── index.ts │ └── options.ts ├── manifest.ts ├── pwa.ts ├── utils.ts ├── icon.ts └── meta.ts ├── package.json ├── CODE_OF_CONDUCT.md └── CHANGELOG.md /test/fixture/static/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /test/fixture/static/precache.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/fixture/.gitignore: -------------------------------------------------------------------------------- 1 | sw.* 2 | workbox-* 3 | -------------------------------------------------------------------------------- /test/fixture/sw/caching.js: -------------------------------------------------------------------------------- 1 | // Caching Extension 2 | -------------------------------------------------------------------------------- /test/fixture/sw/routing.js: -------------------------------------------------------------------------------- 1 | // Routing Extension 2 | -------------------------------------------------------------------------------- /test/fixture/sw/workbox.js: -------------------------------------------------------------------------------- 1 | // Workbox Extension 2 | -------------------------------------------------------------------------------- /docs/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | .nuxt 4 | sw.* 5 | -------------------------------------------------------------------------------- /templates/meta.json: -------------------------------------------------------------------------------- 1 | <%= JSON.stringify(options.head, null, 2) %> 2 | -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "@nuxtjs" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | preset: '@nuxt/test-utils' 3 | } 4 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "@nuxtjs/eslint-config-typescript" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /docs/static/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nuxt-community/pwa-module/main/docs/static/icon.png -------------------------------------------------------------------------------- /docs/static/preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nuxt-community/pwa-module/main/docs/static/preview.png -------------------------------------------------------------------------------- /docs/static/preview-dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nuxt-community/pwa-module/main/docs/static/preview-dark.png -------------------------------------------------------------------------------- /test/fixture/static/OneSignalSDKUpdaterWorker.js: -------------------------------------------------------------------------------- 1 | importScripts('https://cdn.onesignal.com/sdks/OneSignalSDK.js') 2 | -------------------------------------------------------------------------------- /test/fixture/static/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nuxt-community/pwa-module/main/test/fixture/static/icon.png -------------------------------------------------------------------------------- /test/fixture/static/offline.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nuxt-community/pwa-module/main/test/fixture/static/offline.png -------------------------------------------------------------------------------- /test/fixture/pages/_page.vue: -------------------------------------------------------------------------------- 1 | 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | *.iml 3 | .idea 4 | *.log* 5 | .nuxt 6 | .vscode 7 | .DS_Store 8 | coverage 9 | dist 10 | .cache 11 | -------------------------------------------------------------------------------- /test/fixture/static/OneSignalSDKWorker.js: -------------------------------------------------------------------------------- 1 | importScripts('/sw.js?1552851140562', 'https://cdn.onesignal.com/sdks/OneSignalSDK.js') 2 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | # Common 2 | node_modules 3 | dist 4 | .nuxt 5 | coverage 6 | 7 | # Plugin 8 | templates 9 | 10 | # Fixtures 11 | test/fixture/**/static 12 | -------------------------------------------------------------------------------- /test/fixture/static/offline.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Offline 4 | 5 | 6 |

Website is Offline :(

7 | 8 | 9 | -------------------------------------------------------------------------------- /templates/meta.plugin.js: -------------------------------------------------------------------------------- 1 | import { mergeMeta } from './meta.utils' 2 | import meta from './meta.json' 3 | 4 | export default function ({ app }) { 5 | mergeMeta(app.head, meta) 6 | } 7 | -------------------------------------------------------------------------------- /types/index.d.ts: -------------------------------------------------------------------------------- 1 | export { MetaOptions } from './meta' 2 | export { IconOptions } from './icon' 3 | export { WorkboxOptions } from './workbox' 4 | export { ManifestOptions } from './manifest' 5 | export { PWAContext } from './pwa' 6 | -------------------------------------------------------------------------------- /docs/content/en/onesignal.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: OneSignal Module 3 | description: OneSignal Module 4 | position: 6 5 | category: Modules 6 | --- 7 | 8 | 9 | Please see [nuxt-community/onesignal-module](https://github.com/nuxt-community/onesignal-module) 10 | -------------------------------------------------------------------------------- /templates/icon.plugin.js: -------------------------------------------------------------------------------- 1 | export default async function (ctx, inject) { 2 | const icons = <%= JSON.stringify(options.icons) %> 3 | const getIcon = size => icons[size + 'x' + size] || '' 4 | inject('<%= options.pluginName.replace('$', '') %>', getIcon) 5 | } 6 | -------------------------------------------------------------------------------- /docs/content/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "Nuxt PWA", 3 | "url": "https://pwa.nuxtjs.org", 4 | "logo": { 5 | "light": "/logo-light.svg", 6 | "dark": "/logo-dark.svg" 7 | }, 8 | "github": "nuxt-community/pwa-module", 9 | "twitter": "nuxt_js" 10 | } 11 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_size = 2 6 | indent_style = space 7 | end_of_line = lf 8 | charset = utf-8 9 | trim_trailing_whitespace = true 10 | insert_final_newline = true 11 | 12 | [*.md] 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /test/fixture/static/custom-sw.js: -------------------------------------------------------------------------------- 1 | console.log('Custom service worker!') 2 | 3 | self.addEventListener('install', function (e) { 4 | console.log('Install event:', e) 5 | }) 6 | 7 | self.addEventListener('activate', function (e) { 8 | console.log('Activate event:', e) 9 | }) 10 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ESNext", 4 | "module": "ESNext", 5 | "moduleResolution": "Node", 6 | "outDir": "dist", 7 | "declaration": true, 8 | "resolveJsonModule": true, 9 | "esModuleInterop": true, 10 | "types": [ 11 | "@nuxt/types" 12 | ] 13 | }, 14 | "include": [ 15 | "src" 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /types/pwa.d.ts: -------------------------------------------------------------------------------- 1 | import { MetaOptions } from './meta' 2 | import { IconOptions } from './icon' 3 | import { WorkboxOptions } from './workbox' 4 | import { ManifestOptions } from './manifest' 5 | 6 | export interface PWAContext { 7 | meta?: MetaOptions 8 | icon?: IconOptions 9 | workbox?: WorkboxOptions 10 | manifest?: ManifestOptions 11 | 12 | _manifestMeta: any // vue-meta record 13 | } 14 | -------------------------------------------------------------------------------- /docs/nuxt.config.js: -------------------------------------------------------------------------------- 1 | import theme from '@nuxt/content-theme-docs' 2 | 3 | export default theme({ 4 | loading: { color: '#5A0FC8' }, 5 | buildModules: ['nuxt-ackee'], 6 | ackee: { 7 | server: 'https://ackee.nuxtjs.com', 8 | domainId: 'a2998bc2-56dd-47fa-9d94-9781411bd1f9', 9 | detailed: true 10 | }, 11 | pwa: { 12 | manifest: { 13 | name: 'Nuxt PWA' 14 | } 15 | } 16 | }) 17 | -------------------------------------------------------------------------------- /docs/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "docs", 3 | "version": "3.0.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "nuxt", 7 | "build": "nuxt build", 8 | "start": "nuxt start", 9 | "generate": "nuxt generate" 10 | }, 11 | "dependencies": { 12 | "@nuxt/content-theme-docs": "^0.8.2", 13 | "nuxt": "^2.14.12" 14 | }, 15 | "devDependencies": { 16 | "nuxt-ackee": "^2.0.0" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /docs/tailwind.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | theme: { 3 | extend: { 4 | colors: { 5 | primary: { 6 | 100: '#F4EEFB', 7 | 200: '#E2D5F6', 8 | 300: '#D1BCF0', 9 | 400: '#AF89E4', 10 | 500: '#8C57D9', 11 | 600: '#7E4EC3', 12 | 700: '#543482', 13 | 800: '#3F2762', 14 | 900: '#2A1A41' 15 | } 16 | } 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /netlify.toml: -------------------------------------------------------------------------------- 1 | # Global settings applied to the whole site. 2 | # 3 | # “base” is the directory to change to before starting build. If you set base: 4 | # that is where we will look for package.json/.nvmrc/etc, not repo root! 5 | # “command” is your build command. 6 | # “publish” is the directory to publish (relative to the root of your repo). 7 | 8 | [build] 9 | base = "docs" 10 | command = "yarn generate" 11 | publish = "dist" 12 | -------------------------------------------------------------------------------- /templates/workbox/sw.unregister.js: -------------------------------------------------------------------------------- 1 | // THIS FILE SHOULD NOT BE VERSION CONTROLLED 2 | 3 | // https://github.com/NekR/self-destroying-sw 4 | 5 | self.addEventListener('install', function (e) { 6 | self.skipWaiting() 7 | }) 8 | 9 | self.addEventListener('activate', function (e) { 10 | self.registration.unregister() 11 | .then(function () { 12 | return self.clients.matchAll() 13 | }) 14 | .then(function (clients) { 15 | clients.forEach(client => client.navigate(client.url)) 16 | }) 17 | }) 18 | -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | # docs 2 | 3 | ## Setup 4 | 5 | Install dependencies: 6 | 7 | ```bash 8 | yarn install 9 | ``` 10 | 11 | ## Development 12 | 13 | ```bash 14 | yarn dev 15 | ``` 16 | 17 | ## Static Generation 18 | 19 | This will create the `dist/` directory for publishing to static hosting: 20 | 21 | ```bash 22 | yarn generate 23 | ``` 24 | 25 | To preview the static generated app, run `yarn start` 26 | 27 | For detailed explanation on how things work, checkout [nuxt/content](https://content.nuxtjs.org) and [@nuxt/content theme docs](https://content.nuxtjs.org/themes-docs). 28 | -------------------------------------------------------------------------------- /templates/workbox/workbox.js: -------------------------------------------------------------------------------- 1 | async function register() { 2 | if (!'serviceWorker' in navigator) { 3 | throw new Error('serviceWorker is not supported in current browser!') 4 | } 5 | 6 | const { Workbox } = await import('workbox-cdn/workbox/workbox-window.<%= options.dev ? 'dev' : 'prod' %>.es5.mjs') 7 | 8 | const workbox = new Workbox('<%= options.swURL %>', { 9 | scope: '<%= options.swScope %>' 10 | }) 11 | 12 | await workbox.register() 13 | 14 | return workbox 15 | } 16 | 17 | window.$workbox = register() 18 | .catch(error => {<% if (options.dev) { %> console.error('Error registering workbox:', error) <% } %>}) 19 | -------------------------------------------------------------------------------- /test/fixture/pages/index.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 29 | 30 | 35 | -------------------------------------------------------------------------------- /templates/workbox/workbox.unregister.js: -------------------------------------------------------------------------------- 1 | if ('serviceWorker' in navigator) { 2 | navigator.serviceWorker.getRegistrations().then((registrations) => { 3 | for (const registration of registrations) { 4 | console.info('[pwa] [workbox] Unregistering service worker:', registration) 5 | registration.unregister() 6 | } 7 | }) 8 | } 9 | 10 | if ('caches' in window) { 11 | caches.keys() 12 | .then((keys) => { 13 | if (keys.length) { 14 | console.info('[pwa] [workbox] Cleaning cache for:', keys.join(', ')) 15 | for (const key of keys) { 16 | caches.delete(key) 17 | } 18 | } 19 | }) 20 | } 21 | -------------------------------------------------------------------------------- /test/fixture/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2018", 4 | "module": "ESNext", 5 | "moduleResolution": "Node", 6 | "lib": [ 7 | "ESNext", 8 | "ESNext.AsyncIterable", 9 | "DOM" 10 | ], 11 | "esModuleInterop": true, 12 | "allowJs": true, 13 | "sourceMap": true, 14 | "strict": true, 15 | "noEmit": true, 16 | "baseUrl": ".", 17 | "paths": { 18 | "~/*": [ 19 | "./*" 20 | ], 21 | "@/*": [ 22 | "./*" 23 | ] 24 | }, 25 | "types": [ 26 | "@types/node", 27 | "@nuxt/types" 28 | ] 29 | }, 30 | "exclude": [ 31 | "node_modules" 32 | ] 33 | } 34 | -------------------------------------------------------------------------------- /docs/content/en/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Introduction 3 | description: 'Supercharge Nuxt with a heavily tested, updated and stable PWA solution' 4 | position: 1 5 | category: '' 6 | features: 7 | - Registers a service worker for offline caching. 8 | - Automatically generate manifest.json file. 9 | - Automatically adds SEO friendly meta data with manifest integration. 10 | - Automatically generates app icons with different sizes. 11 | - Free background push notifications using OneSignal. 12 | --- 13 | 14 | 15 | 16 | 17 | Zero config [PWA](https://developers.google.com/web/progressive-web-apps) solution for [Nuxt.js](https://nuxtjs.org) 18 | 19 | ## Features 20 | 21 | 22 | 23 |

Enjoy light and dark mode: 

24 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: test 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | pull_request: 8 | branches: 9 | - master 10 | 11 | jobs: 12 | ci: 13 | runs-on: ${{ matrix.os }} 14 | 15 | strategy: 16 | matrix: 17 | os: [ubuntu-latest] 18 | node: [12] 19 | 20 | steps: 21 | - uses: actions/setup-node@v2 22 | with: 23 | node-version: ${{ matrix.node }} 24 | 25 | - name: checkout 26 | uses: actions/checkout@master 27 | 28 | - name: cache node_modules 29 | uses: actions/cache@v2 30 | with: 31 | path: node_modules 32 | key: ${{ matrix.os }}-node-v${{ matrix.node }}-deps-${{ hashFiles(format('{0}{1}', github.workspace, '/yarn.lock')) }} 33 | 34 | - name: Install dependencies 35 | if: steps.cache.outputs.cache-hit != 'true' 36 | run: yarn 37 | 38 | - name: Lint 39 | run: yarn lint 40 | 41 | - name: Test 42 | run: yarn jest 43 | 44 | - name: Coverage 45 | uses: codecov/codecov-action@v1 46 | -------------------------------------------------------------------------------- /lib/meta.utils.js: -------------------------------------------------------------------------------- 1 | export function mergeMeta (to, from) { 2 | if (typeof to === 'function') { 3 | // eslint-disable-next-line no-console 4 | console.warn('Cannot merge meta. Avoid using head as a function!') 5 | return 6 | } 7 | 8 | for (const key in from) { 9 | const value = from[key] 10 | if (Array.isArray(value)) { 11 | to[key] = to[key] || [] 12 | for (const item of value) { 13 | // Avoid duplicates 14 | if ( 15 | (item.hid && hasMeta(to[key], 'hid', item.hid)) || 16 | (item.name && hasMeta(to[key], 'name', item.name)) 17 | ) { 18 | continue 19 | } 20 | // Add meta 21 | to[key].push(item) 22 | } 23 | } else if (typeof value === 'object') { 24 | to[key] = to[key] || {} 25 | for (const attr in value) { 26 | to[key][attr] = value[attr] 27 | } 28 | } else if (to[key] === undefined) { 29 | to[key] = value 30 | } 31 | } 32 | } 33 | 34 | function hasMeta (arr, key, val) { 35 | return arr.find(obj => val ? obj[key] === val : obj[key]) 36 | } 37 | -------------------------------------------------------------------------------- /test/fixture/layouts/default.vue: -------------------------------------------------------------------------------- 1 | 23 | 24 | 33 | 34 | 61 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) Nuxt Community 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /types/manifest.d.ts: -------------------------------------------------------------------------------- 1 | /* eslint camelcase: 0 */ 2 | 3 | export interface ManifestOptions { 4 | /** 5 | * Default: _npm_package_name_ 6 | */ 7 | name: string, 8 | /** 9 | * Default: _npm_package_name_ 10 | */ 11 | short_name: string, 12 | /** 13 | * Default: _npm_package_description_ 14 | */ 15 | description: string, 16 | /** 17 | * 18 | */ 19 | icons: Record[], 20 | /** 21 | * Default: `routerBase + '?standalone=true'` 22 | */ 23 | start_url: string, 24 | /** 25 | * Default: `standalone` 26 | */ 27 | display: string, 28 | /** 29 | * Default: `#ffffff` 30 | */ 31 | background_color: string, 32 | /** 33 | * Default: undefined 34 | */ 35 | theme_color: string, 36 | /** 37 | * Default: `ltr` 38 | */ 39 | dir: 'ltr' | 'rtl', 40 | /** 41 | * Default: `en` 42 | */ 43 | lang: string, 44 | /** 45 | * Default: `false` 46 | */ 47 | useWebmanifestExtension: boolean, 48 | /** 49 | * Default: A combination of `routerBase` and `options.build.publicPath` 50 | */ 51 | publicPath: string, 52 | 53 | fileName: string, 54 | crossorigin: boolean 55 | } 56 | -------------------------------------------------------------------------------- /lib/resize.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | const jimp = require('jimp-compact') 3 | 4 | async function resize ({ input, distDir, sizes }) { 5 | const inputFile = await jimp.read(input) 6 | 7 | // Icons 8 | await Promise.all(sizes.map(normalizeSize).map((size) => { 9 | const name = sizeName(size) 10 | const distFile = path.join(distDir, `${name}.png`) 11 | return new Promise((resolve) => { 12 | inputFile.clone().contain(size[0], size[1]).write(distFile, () => resolve()) 13 | }) 14 | })) 15 | } 16 | 17 | resize(JSON.parse(process.argv[2])).then(() => { 18 | process.exit(0) 19 | }).catch((error) => { 20 | console.error(error) // eslint-disable-line no-console 21 | process.exit(1) 22 | }) 23 | 24 | // TODO: Dedup 25 | function sizeName (size) { 26 | size = normalizeSize(size) 27 | const prefix = size[2] ? (size[2] + '_') : '' 28 | return prefix + size[0] + 'x' + size[1] 29 | } 30 | 31 | // TODO: Dedup 32 | function normalizeSize (size) { 33 | if (!Array.isArray(size)) { 34 | size = [size, size] 35 | } 36 | if (size.length === 1) { 37 | size = [size, size] 38 | } else if (size.length === 0) { 39 | size = 64 40 | } 41 | return size 42 | } 43 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PWA Module 2 | 3 | [![npm version][npm-version-src]][npm-version-href] 4 | [![npm downloads][npm-downloads-src]][npm-downloads-href] 5 | [![Checks][checks-src]][checks-href] 6 | [![Codecov][codecov-src]][codecov-href] 7 | 8 | > Zero config PWA solution for Nuxt.js 9 | 10 | 📖 [**Read Documentation**](https://pwa.nuxtjs.org) 11 | 12 | ## Development 13 | 14 | 1. Clone this repository 15 | 2. Install dependencies using `yarn install` or `npm install` 16 | 3. Start development server using `npm run dev` 17 | 18 | ## License 19 | 20 | [MIT License](./LICENSE) 21 | 22 | Copyright (c) - Nuxt Community 23 | 24 | 25 | [npm-version-src]: https://img.shields.io/npm/v/@nuxtjs/pwa/latest.svg?style=flat-square 26 | [npm-version-href]: https://npmjs.com/package/@nuxtjs/pwa 27 | 28 | [npm-downloads-src]: https://img.shields.io/npm/dm/@nuxtjs/pwa.svg?style=flat-square 29 | [npm-downloads-href]: https://npmjs.com/package/@nuxtjs/pwa 30 | 31 | [checks-src]: https://flat.badgen.net/github/checks/nuxt-community/pwa-module/dev 32 | [checks-href]: https://github.com/nuxt-community/pwa-module/actions 33 | 34 | [codecov-src]: https://img.shields.io/codecov/c/github/nuxt-community/pwa-module.svg?style=flat-square 35 | [codecov-href]: https://codecov.io/gh/nuxt-community/pwa-module 36 | -------------------------------------------------------------------------------- /src/workbox/defaults.ts: -------------------------------------------------------------------------------- 1 | import { version as workboxVersion } from 'workbox-cdn/package.json' 2 | import type { WorkboxOptions } from '../../types' 3 | 4 | export const defaults: WorkboxOptions = { 5 | // General 6 | workboxVersion, 7 | workboxURL: undefined, 8 | importScripts: [], 9 | autoRegister: true, 10 | enabled: undefined, 11 | 12 | // Config 13 | config: {}, 14 | clientsClaim: true, 15 | skipWaiting: true, 16 | offlineAnalytics: false, 17 | workboxExtensions: [], 18 | 19 | // Precache 20 | preCaching: [], 21 | cacheOptions: { 22 | cacheId: undefined, 23 | directoryIndex: '/', 24 | revision: undefined 25 | }, 26 | cachingExtensions: [], 27 | cleanupOutdatedCaches: true, 28 | 29 | // Offline 30 | offline: true, 31 | offlineStrategy: 'NetworkFirst', 32 | offlinePage: null, 33 | offlineAssets: [], 34 | 35 | // Runtime Caching 36 | runtimeCaching: [], 37 | routingExtensions: [], 38 | cacheAssets: true, 39 | assetsURLPattern: undefined, 40 | pagesURLPattern: undefined, 41 | 42 | // Sw 43 | swTemplate: undefined, 44 | swURL: undefined, 45 | swScope: undefined, 46 | swDest: undefined, 47 | 48 | // Router 49 | routerBase: undefined, 50 | publicPath: undefined, 51 | 52 | dev: undefined, 53 | cacheNames: undefined 54 | } 55 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@nuxtjs/pwa", 3 | "version": "3.3.5", 4 | "description": "Zero config PWA solution for Nuxt.js", 5 | "repository": "nuxt-community/pwa-module", 6 | "license": "MIT", 7 | "main": "dist/pwa.js", 8 | "types": "./dist/pwa.d.ts", 9 | "files": [ 10 | "lib", 11 | "dist", 12 | "templates" 13 | ], 14 | "scripts": { 15 | "build": "siroc build", 16 | "dev": "nuxt-ts test/fixture", 17 | "lint": "eslint --ext .js,.vue,.ts .", 18 | "release": "yarn test && yarn build && standard-version && git push --follow-tags && npm publish", 19 | "test": "yarn lint && jest" 20 | }, 21 | "dependencies": { 22 | "clone-deep": "^4.0.1", 23 | "defu": "^3.2.2", 24 | "execa": "^5.0.0", 25 | "fs-extra": "^9.1.0", 26 | "hasha": "^5.2.2", 27 | "jimp-compact": "^0.16.1", 28 | "lodash.template": "^4.5.0", 29 | "serve-static": "^1.14.1", 30 | "workbox-cdn": "^5.1.4" 31 | }, 32 | "devDependencies": { 33 | "@babel/preset-typescript": "^7.12.7", 34 | "@nuxt/test-utils": "^0.1.2", 35 | "@nuxt/types": "^2.14.12", 36 | "@nuxt/typescript-build": "^2.0.4", 37 | "@nuxt/typescript-runtime": "^2.0.1", 38 | "@nuxtjs/eslint-config": "latest", 39 | "@nuxtjs/eslint-config-typescript": "^5.0.0", 40 | "@nuxtjs/module-test-utils": "latest", 41 | "@types/workbox-sw": "^4.3.1", 42 | "babel-eslint": "latest", 43 | "codecov": "latest", 44 | "eslint": "latest", 45 | "jest": "latest", 46 | "klaw-sync": "latest", 47 | "node-fetch": "latest", 48 | "nuxt-edge": "latest", 49 | "siroc": "^0.6.3", 50 | "standard-version": "latest", 51 | "typescript": "^4.1.3" 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/workbox/index.ts: -------------------------------------------------------------------------------- 1 | import { resolve } from 'path' 2 | import { readJSFiles, pick, copyTemplate, PKG_DIR } from '../utils' 3 | import { getOptions } from './options' 4 | 5 | export async function workbox (nuxt, pwa, moduleContainer) { 6 | const options = getOptions(nuxt, pwa) 7 | 8 | // Warning for dev option 9 | if (options.dev) { 10 | // eslint-disable-next-line no-console 11 | console.warn('Workbox is running in development mode') 12 | } 13 | 14 | // Register plugin 15 | if (options.autoRegister) { 16 | moduleContainer.addPlugin({ 17 | src: resolve(PKG_DIR, `templates/workbox/workbox${options.enabled ? '' : '.unregister'}.js`), 18 | ssr: false, 19 | fileName: 'workbox.js', 20 | options: { 21 | ...options 22 | } 23 | }) 24 | } 25 | 26 | // Add sw.js 27 | if (options.swTemplate) { 28 | copyTemplate({ 29 | src: options.swTemplate, 30 | dst: options.swDest, 31 | options: { 32 | dev: nuxt.options.dev, 33 | swOptions: pick(options, [ 34 | 'workboxURL', 35 | 'importScripts', 36 | 'config', 37 | 'cacheNames', 38 | 'cacheOptions', 39 | 'clientsClaim', 40 | 'skipWaiting', 41 | 'cleanupOutdatedCaches', 42 | 'offlineAnalytics', 43 | 'preCaching', 44 | 'runtimeCaching', 45 | 'offlinePage', 46 | 'pagesURLPattern', 47 | 'offlineStrategy' 48 | ]), 49 | routingExtensions: await readJSFiles(nuxt, options.routingExtensions), 50 | cachingExtensions: await readJSFiles(nuxt, options.cachingExtensions), 51 | workboxExtensions: await readJSFiles(nuxt, options.workboxExtensions) 52 | } 53 | }) 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /docs/content/en/setup.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Setup 3 | description: 'Supercharge Nuxt with a heavily tested, updated and stable PWA solution' 4 | position: 1 5 | category: Guide 6 | --- 7 | 8 | Check the [Nuxt.js documentation](https://nuxtjs.org/api/configuration-modules#the-modules-property) for more information about installing and using modules in Nuxt.js. 9 | 10 | ## Installation 11 | 12 | Add `@nuxtjs/pwa` dependency to your project: 13 | 14 | 15 | 16 | 17 | ```bash 18 | yarn add --dev @nuxtjs/pwa 19 | ``` 20 | 21 | 22 | 23 | 24 | ```bash 25 | npm i --save-dev @nuxtjs/pwa 26 | ``` 27 | 28 | 29 | 30 | 31 | Edit your `nuxt.config.js` file to add pwa module:: 32 | 33 | ```js{}[nuxt.config.js] 34 | { 35 | buildModules: [ 36 | '@nuxtjs/pwa', 37 | ] 38 | } 39 | ``` 40 | 41 | **NOTE:** If using `ssr: false` with production mode without `nuxt generate`, you have to use `modules` instead of `buildModules` 42 | 43 | ### Add Icon 44 | 45 | Ensure `static` dir exists and optionally create `static/icon.png`. (Recommended to be square png and >= `512x512px`) 46 | 47 | ### Ignore Service Worker 48 | 49 | Create or add this to `.gitignore`: 50 | 51 | ```{}[.gitignore] 52 | sw.* 53 | ``` 54 | 55 | ## Configuration 56 | 57 | PWA module is a collection of smaller modules that are designed to magically work out of the box together. To disable each sub-module, you can pass `false` option with its name as key. For example to disable _icon_ module: 58 | 59 | ```js{}[nuxt.config.js] 60 | { 61 | pwa: { 62 | icon: false // disables the icon module 63 | } 64 | } 65 | ``` 66 | 67 | Also each sub-module has its own configuration. Continue reading docs for detailed info. 68 | -------------------------------------------------------------------------------- /docs/content/en/icon.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Icon Module 3 | description: This module automatically generates app icons and favicon with different sizes 4 | position: 2 5 | category: Modules 6 | --- 7 | 8 | This module automatically generates app icons and favicon with different sizes using [jimp](https://github.com/oliver-moran/jimp) and fills `manifest.icons[]` with proper paths to generated assets that is used by manifest module. Source icon is being resized using *cover* method. 9 | 10 | 11 | You can pass options to `pwa.icon` in `nuxt.config.js` to override defaults. 12 | 13 | ```js{}[nuxt.config.js] 14 | pwa: { 15 | icon: { 16 | /* icon options */ 17 | } 18 | } 19 | ``` 20 | 21 | ## options 22 | 23 | **source** 24 | - Default: `[srcDir]/[staticDir]/icon.png` 25 | 26 | **fileName** 27 | - Default: `icon.png` 28 | 29 | **sizes** 30 | - Default: `[64, 120, 144, 152, 192, 384, 512]` 31 | 32 | Array of sizes to be generated (Square). 33 | 34 | **targetDir** 35 | - Default: `icons` 36 | 37 | **plugin** 38 | - Default: true 39 | 40 | Make icons accessible through `ctx` or Vue instances. 41 | 42 | Example: `ctx.$icon(512)` will return the url for the icon with the size of `512px`. 43 | Will return an empty string when no icon in the given size is available (eg. when the size is not in `sizes` array). 44 | 45 | **pluginName** 46 | - Default: '$icon' 47 | 48 | Name of property for accessible icons. 49 | 50 | **purpose** 51 | - Default: `['any', 'maskable']` 52 | 53 | Array or string of icon purpose. 54 | 55 | Example: 56 | 57 | ```js 58 | purpose: 'maskable' 59 | ``` 60 | 61 | More detail of "purpose": [https://w3c.github.io/manifest/#purpose-member](https://w3c.github.io/manifest/#purpose-member) 62 | 63 | 64 | **cacheDir** 65 | - Default: `{rootDir}/node_modules/.cache/pwa/icon` 66 | 67 | Cache dir for generated icons 68 | -------------------------------------------------------------------------------- /types/icon.d.ts: -------------------------------------------------------------------------------- 1 | export type iOSType = 'ipad' | 'ipadpro9' | 'ipadpro9' | 'ipadpro10' | 'ipadpro12' | 'iphonese' | 'iphone6' | 'iphoneplus' | 'iphonex' | 'iphonexr' | 'iphonexsmax' 2 | export type iOSSize = [number, number, iOSType] 3 | 4 | export interface IconOptions { 5 | /** 6 | * Default: `[srcDir]/[staticDir]/icon.png` 7 | */ 8 | source: string, 9 | /** 10 | * Default: `icon.png` 11 | */ 12 | fileName: string, 13 | /** 14 | * Array of sizes to be generated (Square). 15 | * Default: `[64, 120, 144, 152, 192, 384, 512]` 16 | */ 17 | sizes: number[], 18 | 19 | /** 20 | * Default: 21 | * ```javascript 22 | * [ 23 | * [1536, 2048, 'ipad'], // Ipad 24 | * [1536, 2048, 'ipadpro9'], // Ipad Pro 9.7" 25 | * [1668, 2224, 'ipadpro10'], // Ipad Pro 10.5" 26 | * [2048, 2732, 'ipadpro12'], // Ipad Pro 12.9" 27 | * [640, 1136, 'iphonese'], // Iphone SE 28 | * [50, 1334, 'iphone6'], // Iphone 6 29 | * [1080, 1920, 'iphoneplus'], // Iphone Plus 30 | * [1125, 2436, 'iphonex'], // Iphone X 31 | * [828, 1792, 'iphonexr'], // Iphone XR 32 | * [1242, 2688, 'iphonexsmax'] // Iphone XS Max 33 | * ] 34 | * ``` 35 | */ 36 | iosSizes: iOSSize[], 37 | /** 38 | * Default: `icons` 39 | */ 40 | targetDir: string, 41 | /** 42 | * Make icons accessible through `ctx` or Vue instances. 43 | * 44 | * Default: `true` 45 | */ 46 | plugin: boolean, 47 | /** 48 | * Name of property for accessible icons. 49 | * 50 | * Default: `$icon` 51 | */ 52 | pluginName: string, 53 | /** 54 | * Array or string of icon purpose. 55 | * 56 | * Default: `['any', 'maskable']` 57 | */ 58 | purpose: string[] | string, 59 | /** 60 | * Cache dir for generated icons 61 | * 62 | * Default: `{rootDir}/node_modules/.cache/icon` 63 | */ 64 | cacheDir: string, 65 | 66 | publicPath: string 67 | } 68 | -------------------------------------------------------------------------------- /test/fixture/nuxt.config.ts: -------------------------------------------------------------------------------- 1 | import pwaModule from '../../src/pwa' 2 | 3 | export default { 4 | target: 'static', 5 | 6 | generate: { 7 | staticAssets: { 8 | version: 'default' 9 | } 10 | }, 11 | 12 | buildModules: [ 13 | pwaModule 14 | ], 15 | 16 | manifest: { 17 | name: 'Test Project Name', 18 | description: 'Test Project Description', 19 | 20 | useWebmanifestExtension: true, 21 | fileName: 'manifest_test.[ext]?[hash]', 22 | orientation: 'portrait' 23 | }, 24 | 25 | meta: { 26 | nativeUI: true 27 | }, 28 | 29 | workbox: { 30 | offlineAnalytics: true, 31 | dev: true, 32 | config: { 33 | debug: true 34 | }, 35 | cacheNames: { 36 | prefix: 'test', 37 | googleAnalytics: 'test-ga' 38 | }, 39 | cacheOptions: { 40 | revision: 'test-rev' 41 | }, 42 | importScripts: [ 43 | 'custom-sw.js' 44 | ], 45 | workboxExtensions: [ 46 | '~/sw/workbox' 47 | ], 48 | cachingExtensions: [ 49 | '~/sw/caching' 50 | ], 51 | routingExtensions: [ 52 | '~/sw/routing' 53 | ], 54 | preCaching: [ 55 | 'precache.js' 56 | ], 57 | // offlinePage: '/offline.html', 58 | // offlineAssets: [ 59 | // '/offline.png' 60 | // ], 61 | runtimeCaching: [ 62 | { 63 | urlPattern: 'https://google.com/.*', 64 | handler: 'cacheFirst', 65 | method: 'GET' 66 | }, 67 | { 68 | urlPattern: 'https://pwa.nuxtjs.org/.*', 69 | handler: 'CacheFirst', 70 | method: 'GET', 71 | strategyOptions: { 72 | cacheName: 'nuxt-pwa' 73 | }, 74 | strategyPlugins: [ 75 | { 76 | use: 'Expiration', 77 | config: { 78 | maxEntries: 10, 79 | maxAgeSeconds: 300 80 | } 81 | } 82 | ] 83 | } 84 | ] 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /src/manifest.ts: -------------------------------------------------------------------------------- 1 | import hasha from 'hasha' 2 | import type { ManifestOptions, PWAContext } from '../types' 3 | import { joinUrl, getRouteParams, emitAsset } from './utils' 4 | 5 | export function manifest (nuxt, pwa: PWAContext) { 6 | const { routerBase, publicPath } = getRouteParams(nuxt.options) 7 | 8 | // Combine sources 9 | const defaults: ManifestOptions = { 10 | name: process.env.npm_package_name, 11 | short_name: process.env.npm_package_name, 12 | description: process.env.npm_package_description, 13 | publicPath, 14 | icons: [], 15 | start_url: routerBase + '?standalone=true', 16 | display: 'standalone', 17 | background_color: '#ffffff', 18 | theme_color: pwa.meta.theme_color, 19 | lang: 'en', 20 | useWebmanifestExtension: false, 21 | fileName: 'manifest.[hash].[ext]', 22 | dir: undefined, 23 | crossorigin: undefined 24 | } 25 | 26 | const options: ManifestOptions = { ...defaults, ...pwa.manifest } 27 | 28 | // Remove extra fields from manifest 29 | const manifest = { ...options } 30 | // @ts-ignore 31 | delete manifest.src 32 | delete manifest.publicPath 33 | delete manifest.useWebmanifestExtension 34 | delete manifest.fileName 35 | 36 | // Generate file name 37 | const manifestFileName = options.fileName 38 | .replace('[hash]', hasha(JSON.stringify(manifest)).substr(0, 8)) 39 | .replace('[ext]', options.useWebmanifestExtension ? 'webmanifest' : 'json') 40 | 41 | // Merge final manifest into options.manifest for other modules 42 | if (!nuxt.options.manifest) { 43 | nuxt.options.manifest = {} 44 | } 45 | Object.assign(nuxt.options.manifest, manifest) 46 | Object.assign(pwa.manifest, manifest) 47 | 48 | // Register webpack plugin to emit manifest 49 | const manifestSource = JSON.stringify(manifest, null, 2) 50 | emitAsset(nuxt, manifestFileName, manifestSource) 51 | 52 | // Add manifest meta 53 | const manifestMeta = { rel: 'manifest', href: joinUrl(options.publicPath, manifestFileName), hid: 'manifest' } as any 54 | if (manifest.crossorigin) { 55 | manifestMeta.crossorigin = manifest.crossorigin 56 | } 57 | pwa._manifestMeta = manifestMeta 58 | } 59 | -------------------------------------------------------------------------------- /test/pwa.test.js: -------------------------------------------------------------------------------- 1 | import path from 'path' 2 | import { setupTest, getNuxt } from '@nuxt/test-utils' 3 | import klawSync from 'klaw-sync' 4 | import fs from 'fs-extra' 5 | 6 | const getRelativePath = fileObj => path.relative(__dirname, fileObj.path) 7 | const noJS = item => !/\.js/.test(item) 8 | 9 | console.warn = jest.fn() // eslint-disable-line no-console 10 | 11 | describe('pwa', () => { 12 | setupTest({ 13 | testDir: __dirname, 14 | fixture: 'fixture', 15 | configFile: 'nuxt.config.ts', 16 | build: true, 17 | generate: true, 18 | config: {} 19 | }) 20 | 21 | test('workbox dev warning', () => { 22 | expect(console.warn).toHaveBeenCalledWith('Workbox is running in development mode') // eslint-disable-line no-console 23 | }) 24 | 25 | test('generate files (dist)', () => { 26 | const nuxt = getNuxt() 27 | const generateFiles = klawSync(nuxt.options.generate.dir).map(getRelativePath) 28 | 29 | expect(generateFiles.filter(noJS)).toMatchSnapshot() 30 | }) 31 | 32 | test('accessible icons', async () => { 33 | const nuxt = getNuxt() 34 | const { html } = await nuxt.renderRoute('/') 35 | expect(html).toContain('/_nuxt/icons/icon_512x512.b8f3a1.png') 36 | }) 37 | 38 | test('icons purpose', () => { 39 | const nuxt = getNuxt() 40 | const assetDir = path.join(nuxt.options.generate.dir, '_nuxt') 41 | const manifestFileName = fs.readdirSync(assetDir).find(item => item.match(/^manifest./i)) 42 | const manifestContent = JSON.parse(fs.readFileSync(path.join(assetDir, manifestFileName.split('?')[0]))) 43 | expect(manifestContent.icons).toEqual( 44 | expect.arrayContaining([ 45 | expect.objectContaining({ 46 | purpose: expect.stringMatching(/( ?(any|maskable|badge))+/) 47 | }) 48 | ]) 49 | ) 50 | }) 51 | 52 | test('sw.js', async () => { 53 | const nuxt = getNuxt() 54 | const swContents = await fs.readFile(path.resolve(nuxt.options.generate.dir, 'sw.js'), 'utf-8') 55 | 56 | expect(swContents.replace(/@[^/]*/, '')).toMatchSnapshot() 57 | }) 58 | 59 | test('manifest.json', async () => { 60 | const nuxt = getNuxt() 61 | const manifestContents = await fs.readFile(path.resolve(nuxt.options.generate.dir, '_nuxt/manifest_test.webmanifest'), 'utf-8') 62 | 63 | expect(manifestContents).toMatchSnapshot() 64 | }) 65 | }) 66 | -------------------------------------------------------------------------------- /src/pwa.ts: -------------------------------------------------------------------------------- 1 | import { resolve } from 'path' 2 | import serveStatic from 'serve-static' 3 | import type { MetaOptions, ManifestOptions, IconOptions, PWAContext, WorkboxOptions } from '../types' 4 | import { PKG } from './utils' 5 | import { icon } from './icon' 6 | import { manifest } from './manifest' 7 | import { meta, metaRuntime } from './meta' 8 | import { workbox } from './workbox' 9 | 10 | interface PWAOptions { 11 | meta?: Partial | false 12 | icon?: Partial | false 13 | workbox?: Partial | false 14 | manifest?: Partial | false 15 | } 16 | 17 | export default async function pwa (moduleOptions: PWAOptions) { 18 | const { nuxt } = this 19 | const moduleContainer = this // TODO: remove dependency when module-utils 20 | 21 | const isBuild = nuxt.options._build 22 | const isGenerate = nuxt.options.target === 'static' && !nuxt.options.dev 23 | const isRuntime = !isBuild && !isGenerate 24 | 25 | if (isRuntime) { 26 | // Load meta.json for SPA renderer 27 | metaRuntime(nuxt) 28 | return 29 | } 30 | 31 | const modules = { icon, manifest, meta, workbox } 32 | 33 | // Shared options context 34 | nuxt.options.pwa = { ...(nuxt.options.pwa || {}), ...(moduleOptions || {}) } 35 | const pwa: PWAContext = nuxt.options.pwa 36 | 37 | // Normalize options 38 | for (const name in modules) { 39 | // Skip disabled modules 40 | if (pwa[name] === false || nuxt.options[name] === false) { 41 | continue 42 | } 43 | // Ensure options are an object 44 | if (pwa[name] === undefined) { 45 | pwa[name] = {} 46 | } 47 | // Backward compatibility for top-level options 48 | if (nuxt.options[name] !== undefined) { 49 | pwa[name] = { ...nuxt.options[name], ...pwa[name] } 50 | } 51 | } 52 | 53 | // Execute modules in sequence 54 | for (const name in modules) { 55 | if (pwa[name] === false) { 56 | continue 57 | } 58 | await modules[name](nuxt, pwa, moduleContainer) 59 | } 60 | 61 | // Serve dist from disk 62 | if (nuxt.options.dev) { 63 | const clientDir = resolve(nuxt.options.buildDir, 'dist/client') 64 | nuxt.options.serverMiddleware.push({ 65 | path: nuxt.options.build.publicPath, 66 | handler: serveStatic(clientDir) 67 | }) 68 | } 69 | } 70 | 71 | declare module '@nuxt/types/config/index' { 72 | interface NuxtOptions { 73 | pwa?: Partial 74 | meta?: Partial | false 75 | icon?: Partial | false 76 | workbox?: Partial | false 77 | manifest?: Partial | false 78 | } 79 | } 80 | 81 | pwa.meta = PKG 82 | -------------------------------------------------------------------------------- /types/meta.d.ts: -------------------------------------------------------------------------------- 1 | /* eslint camelcase: 0 */ 2 | import { ManifestOptions } from './manifest' 3 | 4 | export type OgImageObject = { 5 | path?: string, 6 | width?: number, 7 | height?: number, 8 | type?: string 9 | } 10 | 11 | export interface MetaOptions extends Partial { 12 | /** 13 | * Default: `utf-8` 14 | */ 15 | charset: string, 16 | /** 17 | * Default: `width=device-width, initial-scale=1` 18 | * 19 | * Meta: `viewport` 20 | */ 21 | viewport: string, 22 | /** 23 | * Default: `true` 24 | * 25 | * Meta: `mobile-web-app-capable` 26 | */ 27 | mobileApp: boolean, 28 | /** 29 | * Default: `false` 30 | * 31 | * Meta: `apple-mobile-web-app-capable` 32 | */ 33 | mobileAppIOS: boolean, 34 | /** 35 | * Default: `default` 36 | */ 37 | appleStatusBarStyle: string, 38 | /** 39 | * Default: `true` (to use options.icons) 40 | * 41 | * Meta: `shortcut icon` + `apple-touch-icon` 42 | */ 43 | favicon: boolean, 44 | /** 45 | * Default: _npm_package_name_ 46 | * 47 | * Meta: `title` 48 | */ 49 | name: string, 50 | /** 51 | * @deprecated use meta.name 52 | */ 53 | title?: string, 54 | /** 55 | * Default: _npm_package_author_name_ 56 | * 57 | * Meta: `author` 58 | */ 59 | author: string, 60 | /** 61 | * Default: _npm_package_description_ 62 | * 63 | * Meta: `description` 64 | */ 65 | description: string, 66 | /** 67 | * Default: `options.loading.color` 68 | * 69 | * Meta: `description` 70 | */ 71 | theme_color: string, 72 | /** 73 | * Default: `en` 74 | * 75 | * Meta: `lang` 76 | */ 77 | lang: string, 78 | /** 79 | * Default: `website` 80 | * 81 | * Meta: `og:type` 82 | */ 83 | ogType: string, 84 | /** 85 | * Default: _npm_package_name_ 86 | * 87 | * Meta: `og:site_name` 88 | */ 89 | ogSiteName: string | true, 90 | /** 91 | * Default: _npm_package_name_ 92 | * 93 | * Meta: `og:title` 94 | */ 95 | ogTitle: string | true, 96 | /** 97 | * Default: _npm_package_description_ 98 | * 99 | * Meta: `og:description` 100 | */ 101 | ogDescription: string | true, 102 | /** 103 | * Default: `undefined` 104 | * 105 | * Meta: `N/A` 106 | */ 107 | ogHost: string | undefined, 108 | /** 109 | * Default: `true` 110 | * 111 | * Meta: `og:image` and sub-tags 112 | */ 113 | ogImage: boolean | string | OgImageObject, 114 | /** 115 | * Default: ogHost (if defined) 116 | * 117 | * Meta: `og:url` 118 | */ 119 | ogUrl: string | undefined | true, 120 | /** 121 | * Default: `undefined` 122 | * 123 | * Meta: `twitter:card` 124 | */ 125 | twitterCard: string | undefined, 126 | /** 127 | * Default: `undefined` 128 | * 129 | * Meta: `twitter:site` 130 | */ 131 | twitterSite: string | undefined, 132 | /** 133 | * Default: `undefined` 134 | * 135 | * Meta: `twitter:creator` 136 | */ 137 | twitterCreator: string | undefined, 138 | /** 139 | * Default: `false` 140 | */ 141 | nativeUI: boolean 142 | } 143 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. 6 | 7 | ## Our Standards 8 | 9 | Examples of behavior that contributes to creating a positive environment include: 10 | 11 | * Using welcoming and inclusive language 12 | * Being respectful of differing viewpoints and experiences 13 | * Gracefully accepting constructive criticism 14 | * Focusing on what is best for the community 15 | * Showing empathy towards other community members 16 | 17 | Examples of unacceptable behavior by participants include: 18 | 19 | * The use of sexualized language or imagery and unwelcome sexual attention or advances 20 | * Trolling, insulting/derogatory comments, and personal or political attacks 21 | * Public or private harassment 22 | * Publishing others' private information, such as a physical or electronic address, without explicit permission 23 | * Other conduct which could reasonably be considered inappropriate in a professional setting 24 | 25 | ## Our Responsibilities 26 | 27 | Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. 28 | 29 | Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. 30 | 31 | ## Scope 32 | 33 | This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. 34 | 35 | ## Enforcement 36 | 37 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at pooya@pi0.ir. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. 38 | 39 | Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. 40 | 41 | ## Attribution 42 | 43 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] 44 | 45 | [homepage]: http://contributor-covenant.org 46 | [version]: http://contributor-covenant.org/version/1/4/ 47 | -------------------------------------------------------------------------------- /src/utils.ts: -------------------------------------------------------------------------------- 1 | import { posix, resolve, dirname } from 'path' 2 | import { mkdirp, readFile, existsSync, writeFile } from 'fs-extra' 3 | import template from 'lodash.template' 4 | import { name, version } from '../package.json' 5 | 6 | export const PKG = { 7 | name, 8 | version 9 | } 10 | 11 | export const PKG_DIR = resolve(__dirname, '..') 12 | 13 | export function isUrl (url) { 14 | return url.indexOf('http') === 0 || url.indexOf('//') === 0 15 | } 16 | 17 | export function joinUrl (...args) { 18 | return posix.join(...args).replace(':/', '://') 19 | } 20 | 21 | export function normalizeSize (size) { 22 | if (!Array.isArray(size)) { 23 | size = [size, size] 24 | } 25 | if (size.length === 1) { 26 | size = [size, size] 27 | } else if (size.length === 0) { 28 | size = 64 29 | } 30 | return size 31 | } 32 | 33 | export function sizeName (size) { 34 | size = normalizeSize(size) 35 | const prefix = size[2] ? (size[2] + '_') : '' 36 | return prefix + size[0] + 'x' + size[1] 37 | } 38 | 39 | export function getRouteParams (options) { 40 | // routerBase 41 | const routerBase = options.router.base 42 | 43 | // publicPath 44 | let publicPath 45 | if (isUrl(options.build.publicPath)) { 46 | publicPath = options.build.publicPath 47 | } else { 48 | publicPath = joinUrl(routerBase, options.build.publicPath) 49 | } 50 | 51 | return { 52 | routerBase, 53 | publicPath 54 | } 55 | } 56 | 57 | export function startCase (str) { 58 | return typeof str === 'string' ? str[0].toUpperCase() + str.substr(1) : str 59 | } 60 | 61 | export async function writeData (path, data) { 62 | path = path.split('?')[0] 63 | await mkdirp(dirname(path)) 64 | await writeFile(path, await data) 65 | } 66 | 67 | export function emitAsset (nuxt, fileName, data) { 68 | const emitAsset = async () => { 69 | const buildPath = resolve(nuxt.options.buildDir, 'dist/client', fileName) 70 | await writeData(buildPath, data) 71 | } 72 | 73 | nuxt.hook('build:done', () => emitAsset()) 74 | 75 | const isGenerate = nuxt.options.target === 'static' && !nuxt.options.dev 76 | if (isGenerate) { 77 | nuxt.hook('modules:done', () => emitAsset()) 78 | } 79 | } 80 | 81 | export async function readJSFiles (nuxt, files) { 82 | const contents = [] 83 | 84 | for (const file of Array.isArray(files) ? files : [files]) { 85 | const path = nuxt.resolver.resolvePath(file) 86 | if (path && existsSync(path)) { 87 | contents.push(await readFile(path, 'utf8').then(s => s.trim())) 88 | } else { 89 | throw new Error('Can not read ' + path) 90 | } 91 | } 92 | 93 | return contents.join('\n\n') 94 | } 95 | 96 | export function pick (obj, props) { 97 | const newObj = {} 98 | props.forEach((prop) => { 99 | newObj[prop] = obj[prop] 100 | }) 101 | return newObj 102 | } 103 | 104 | export async function copyTemplate ({ src, dst, options }) { 105 | const compile = template(await readFile(src, 'utf8')) 106 | await writeFile(dst, compile({ options })) 107 | } 108 | 109 | export function randomString (length) { 110 | const result = [] 111 | const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789' 112 | 113 | for (let i = 0; i < length; i++) { 114 | const char = characters.charAt(Math.floor(Math.random() * characters.length)) 115 | result.push(char) 116 | } 117 | 118 | return result.join('') 119 | } 120 | -------------------------------------------------------------------------------- /templates/workbox/sw.js: -------------------------------------------------------------------------------- 1 | const options = <%= JSON.stringify(options.swOptions) %> 2 | 3 | importScripts(...[options.workboxURL, ...options.importScripts]) 4 | 5 | initWorkbox(workbox, options) 6 | workboxExtensions(workbox, options) 7 | precacheAssets(workbox, options) 8 | cachingExtensions(workbox, options) 9 | runtimeCaching(workbox, options) 10 | offlinePage(workbox, options) 11 | routingExtensions(workbox, options) 12 | 13 | function getProp(obj, prop) { 14 | return prop.split('.').reduce((p, c) => p[c], obj) 15 | } 16 | 17 | function initWorkbox(workbox, options) { 18 | if (options.config) { 19 | // Set workbox config 20 | workbox.setConfig(options.config) 21 | } 22 | 23 | if (options.cacheNames) { 24 | // Set workbox cache names 25 | workbox.core.setCacheNameDetails(options.cacheNames) 26 | } 27 | 28 | if (options.clientsClaim) { 29 | // Start controlling any existing clients as soon as it activates 30 | workbox.core.clientsClaim() 31 | } 32 | 33 | if (options.skipWaiting) { 34 | workbox.core.skipWaiting() 35 | } 36 | 37 | if (options.cleanupOutdatedCaches) { 38 | workbox.precaching.cleanupOutdatedCaches() 39 | } 40 | 41 | if (options.offlineAnalytics) { 42 | // Enable offline Google Analytics tracking 43 | workbox.googleAnalytics.initialize() 44 | } 45 | } 46 | 47 | function precacheAssets(workbox, options) { 48 | if (options.preCaching.length) { 49 | workbox.precaching.precacheAndRoute(options.preCaching, options.cacheOptions) 50 | } 51 | } 52 | 53 | 54 | function runtimeCaching(workbox, options) { 55 | const requestInterceptor = { 56 | requestWillFetch({ request }) { 57 | if (request.cache === 'only-if-cached' && request.mode === 'no-cors') { 58 | return new Request(request.url, { ...request, cache: 'default', mode: 'no-cors' }) 59 | } 60 | return request 61 | }, 62 | fetchDidFail(ctx) { 63 | ctx.error.message = 64 | '[workbox] Network request for ' + ctx.request.url + ' threw an error: ' + ctx.error.message 65 | console.error(ctx.error, 'Details:', ctx) 66 | }, 67 | handlerDidError(ctx) { 68 | ctx.error.message = 69 | `[workbox] Network handler threw an error: ` + ctx.error.message 70 | console.error(ctx.error, 'Details:', ctx) 71 | return null 72 | } 73 | } 74 | 75 | for (const entry of options.runtimeCaching) { 76 | const urlPattern = new RegExp(entry.urlPattern) 77 | const method = entry.method || 'GET' 78 | 79 | const plugins = (entry.strategyPlugins || []) 80 | .map(p => new (getProp(workbox, p.use))(...p.config)) 81 | 82 | plugins.unshift(requestInterceptor) 83 | 84 | const strategyOptions = { ...entry.strategyOptions, plugins } 85 | 86 | const strategy = new workbox.strategies[entry.handler](strategyOptions) 87 | 88 | workbox.routing.registerRoute(urlPattern, strategy, method) 89 | } 90 | } 91 | 92 | function offlinePage(workbox, options) { 93 | if (options.offlinePage) { 94 | // Register router handler for offlinePage 95 | workbox.routing.registerRoute(new RegExp(options.pagesURLPattern), ({ request, event }) => { 96 | const strategy = new workbox.strategies[options.offlineStrategy] 97 | return strategy 98 | .handle({ request, event }) 99 | .catch(() => caches.match(options.offlinePage)) 100 | }) 101 | } 102 | } 103 | 104 | function workboxExtensions(workbox, options) { 105 | <%= options.workboxExtensions %> 106 | } 107 | 108 | function cachingExtensions(workbox, options) { 109 | <%= options.cachingExtensions %> 110 | } 111 | 112 | function routingExtensions(workbox, options) { 113 | <%= options.routingExtensions %> 114 | } 115 | -------------------------------------------------------------------------------- /types/workbox.d.ts: -------------------------------------------------------------------------------- 1 | import { HTTPMethod } from 'workbox-routing' 2 | import { Plugin as BackgroundSyncPlugin } from 'workbox-background-sync' 3 | import { Plugin as BroadcastUpdatePlugin } from 'workbox-broadcast-update' 4 | import { Plugin as CacheableResponsePlugin } from 'workbox-cacheable-response' 5 | import { Plugin as ExpirationPlugin } from 'workbox-expiration' 6 | import { Plugin as RangeRequestsPlugin } from 'workbox-range-requests' 7 | import { 8 | StaleWhileRevalidateOptions, 9 | CacheFirstOptions, 10 | NetworkFirstOptions, 11 | NetworkOnlyOptions, 12 | CacheOnlyOptions 13 | } from 'workbox-strategies' 14 | 15 | export type CachingStrategy = 'CacheFirst' | 'CacheOnly' | 'NetworkFirst' | 'NetworkOnly' | 'StaleWhileRevalidate' 16 | 17 | export type StrategyOptions = 18 | Omit 19 | 20 | type StrategyPluginOf = { 21 | use: name 22 | config: ConstructorParameters[0] | ConstructorParameters 23 | } 24 | 25 | export type BackgroundSync = StrategyPluginOf<'BackgroundSync', BackgroundSyncPlugin> 26 | export type BroadcastUpdate = StrategyPluginOf<'BroadcastUpdate', BroadcastUpdatePlugin> 27 | export type CacheableResponse = StrategyPluginOf<'CacheableResponse', CacheableResponsePlugin> 28 | export type Expiration = StrategyPluginOf<'Expiration', ExpirationPlugin> 29 | export type RangeRequests = StrategyPluginOf<'RangeRequests', RangeRequestsPlugin> 30 | 31 | export type StrategyPlugin = BackgroundSync | BroadcastUpdate | CacheableResponse | Expiration | RangeRequests 32 | 33 | export interface RuntimeCaching { 34 | urlPattern: string 35 | handler?: CachingStrategy 36 | method?: HTTPMethod 37 | strategyOptions?: StrategyOptions 38 | strategyPlugins?: StrategyPlugin[] 39 | } 40 | 41 | export interface WorkboxOptions { 42 | dev: boolean, 43 | workboxVersion: string, 44 | workboxURL: string, 45 | importScripts: string[], 46 | /** 47 | * Default: `true` 48 | */ 49 | autoRegister: boolean, 50 | /** 51 | * Default: `true` for production mode 52 | */ 53 | enabled: boolean, 54 | cacheNames: Record, 55 | config: Record, 56 | /** 57 | * Default: `true` 58 | */ 59 | clientsClaim: boolean, 60 | /** 61 | * Default: `true` 62 | */ 63 | skipWaiting: boolean, 64 | /** 65 | * Default: `false` 66 | */ 67 | offlineAnalytics: boolean, 68 | workboxExtensions: string | string[], 69 | /** 70 | * Default: `[]` 71 | */ 72 | preCaching: string[] | {url: string, revision: string}[], 73 | cacheOptions: { 74 | /** 75 | * Default: ` || nuxt` 76 | */ 77 | cacheId: string, 78 | /** 79 | * Default: `/` 80 | */ 81 | directoryIndex: string, 82 | /** 83 | * Default: `undefined` 84 | */ 85 | revision: string | undefined 86 | }, 87 | cachingExtensions: string | string[], 88 | cleanupOutdatedCaches: boolean, 89 | /** 90 | * Default: `true` 91 | */ 92 | offline: boolean, 93 | /** 94 | * Default: `NetworkFirst` 95 | */ 96 | offlineStrategy: CachingStrategy, 97 | offlinePage: string, 98 | offlineAssets: string[], 99 | runtimeCaching: RuntimeCaching[], 100 | /** 101 | * Default: `true` 102 | */ 103 | cacheAssets: boolean, 104 | routingExtensions: string | string[], 105 | /** 106 | * Default: `/_nuxt/` 107 | */ 108 | assetsURLPattern: string, 109 | /** 110 | * Auto generated based on `router.base` 111 | * 112 | * Default: `/` 113 | */ 114 | pagesURLPattern: string, 115 | swTemplate: string, 116 | swURL: string, 117 | swDest: string, 118 | /** 119 | * Default: `routerBase` 120 | */ 121 | swScope: string, 122 | /** 123 | * Default: `/` 124 | */ 125 | routerBase: string, 126 | /** 127 | * Default: `/_nuxt` 128 | */ 129 | publicPath: string 130 | } 131 | -------------------------------------------------------------------------------- /docs/static/logo-dark.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /docs/static/logo-light.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /docs/content/en/meta.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Meta Module 3 | description: Meta easily adds common meta tags into your project with zero-config needed 4 | position: 3 5 | category: Modules 6 | --- 7 | 8 | 9 | [![npm](https://img.shields.io/npm/dt/@nuxtjs/meta.svg?style=flat-square)](https://npmjs.com/package/@nuxtjs/meta) 10 | [![npm (scoped with tag)](https://img.shields.io/npm/v/@nuxtjs/meta/latest.svg?style=flat-square)](https://npmjs.com/package/@nuxtjs/meta) 11 | 12 | Meta easily adds common meta tags into your project with zero-config needed. 13 | You can optionally override meta using `pwa.meta` in `nuxt.config.js`: 14 | 15 | ```js{}[nuxt.config.js] 16 | pwa: { 17 | meta: { 18 | /* meta options */ 19 | } 20 | } 21 | ``` 22 | 23 | ## options 24 | 25 | ### `charset` 26 | - Default: `utf-8` 27 | 28 | ### `viewport` 29 | 30 | - Default: `width=device-width, initial-scale=1` 31 | - Meta: `viewport` 32 | 33 | ### `mobileApp` 34 | - Default: `true` 35 | - Meta: `mobile-web-app-capable` 36 | 37 | ### `mobileAppIOS` 38 | - Default: `false` 39 | - Meta: `apple-mobile-web-app-capable` 40 | 41 | Please read this resources before you enable `mobileAppIOS` option: 42 | 43 | - https://developer.apple.com/library/content/documentation/AppleApplications/Reference/SafariHTMLRef/Articles/MetaTags.html 44 | - https://medium.com/@firt/dont-use-ios-web-app-meta-tag-irresponsibly-in-your-progressive-web-apps-85d70f4438cb 45 | 46 | ### `appleStatusBarStyle` 47 | - Default: `default` 48 | - Meta: `apple-mobile-web-app-status-bar-style` 49 | 50 | There are three options for the status bar style: 51 | 1. `default`: The default status bar style for Safari PWAs; white background with black text and icons. 52 | 2. `black`: Black background with white text and icons. 53 | 3. `black-translucent`: Transparent background with white text and icons. It is [not possible](https://stackoverflow.com/a/40786240/8677167) to have a transparent status bar with black text and icons. 54 | 55 | Note that with `black-translucent`, the web content is displayed on the entire screen, partially obscured by the status bar. 56 | 57 | These articles will help you decide an appropriate value: 58 | - https://medium.com/appscope/changing-the-ios-status-bar-of-your-progressive-web-app-9fc8fbe8e6ab. 59 | - https://developer.apple.com/library/archive/documentation/AppleApplications/Reference/SafariHTMLRef/Articles/MetaTags.html#//apple_ref/doc/uid/TP40008193-SW4 60 | 61 | ### `favicon` 62 | - Default: `true` (to use options.icons) 63 | - Meta: `shortcut icon` + `apple-touch-icon` 64 | 65 | ### `name` 66 | - Default: *npm_package_name* 67 | - Meta: `title` 68 | 69 | ### `author` 70 | - Default: *npm_package_author_name* 71 | - Meta: `author` 72 | 73 | ### `description` 74 | - Default: *npm_package_description* 75 | - Meta: `description` 76 | 77 | ### `theme_color` 78 | - Default: `undefined` 79 | - Meta: `theme-color` 80 | 81 | ### `lang` 82 | - Default: `en` 83 | - Meta: `lang` 84 | 85 | ### `ogType` 86 | - Default: `website` 87 | - Meta: `og:type` 88 | 89 | ### `ogSiteName` 90 | - Default: same as options.name 91 | - Meta: `og:site_name` 92 | 93 | ### `ogTitle` 94 | - Default: same as options.name 95 | - Meta: `og:title` 96 | 97 | ### `ogDescription` 98 | - Default: same as options.description 99 | - Meta: `og:description` 100 | 101 | ### `ogHost` 102 | Specify the domain that the site is hosted. Required for ogImage. 103 | - Default: `undefined` 104 | - Meta: `N/A` 105 | 106 | ### `ogImage` 107 | - Default: `true` 108 | - Meta: `og:image` and sub-tags 109 | 110 | These types are accepted: 111 | 112 | - Boolean: the icons from the `icon` module are used. 113 | - String: the path is used. 114 | - Object: 115 | * `path`: specify the path. 116 | * `width`, `height`: specify the dimensions, respectively. 117 | * `type`: specify the MIME type. 118 | 119 | ### `ogUrl` 120 | - Default: ogHost (if defined) 121 | - Meta: `og:url` 122 | 123 | 124 | ### `twitterCard` 125 | - Default: `undefined` 126 | - Meta: `twitter:card` 127 | 128 | ### `twitterSite` 129 | - Default: `undefined` 130 | - Meta: `twitter:site` 131 | 132 | ### `twitterCreator` 133 | - Default: `undefined` 134 | - Meta: `twitter:creator` 135 | 136 | ### `nativeUI` 137 | - Default: `false` 138 | 139 | By setting `meta.nativeUI` to `true` (Defaults to `false`) `viewport` defaults to `width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0, minimal-ui` and `mobileAppIOS` will be enabled if not explicitly set to `false` which is suitable for native looking mobile apps. 140 | -------------------------------------------------------------------------------- /src/workbox/options.ts: -------------------------------------------------------------------------------- 1 | import { resolve } from 'path' 2 | import cloneDeep from 'clone-deep' 3 | import { joinUrl, getRouteParams, startCase, randomString, PKG_DIR } from '../utils' 4 | import type { WorkboxOptions, PWAContext } from '../../types' 5 | import { defaults } from './defaults' 6 | 7 | export function getOptions (nuxt, pwa: PWAContext): WorkboxOptions { 8 | const options: WorkboxOptions = cloneDeep({ ...defaults, ...pwa.workbox }) 9 | 10 | // enabled 11 | if (options.enabled === undefined) { 12 | options.enabled = !nuxt.options.dev || options.dev /* backward compat */ 13 | } 14 | 15 | // routerBase 16 | if (!options.routerBase) { 17 | options.routerBase = nuxt.options.router.base 18 | } 19 | 20 | // publicPath 21 | if (!options.publicPath) { 22 | const { publicPath } = getRouteParams(nuxt.options) 23 | options.publicPath = publicPath 24 | } 25 | 26 | // swTemplate 27 | if (!options.swTemplate) { 28 | options.swTemplate = resolve(PKG_DIR, `templates/workbox/sw${options.enabled ? '' : '.unregister'}.js`) 29 | } 30 | 31 | // swDest 32 | if (!options.swDest) { 33 | options.swDest = resolve(nuxt.options.srcDir, nuxt.options.dir.static || 'static', 'sw.js') 34 | } 35 | 36 | // swURL 37 | options.swURL = joinUrl(options.routerBase, options.swURL || 'sw.js') 38 | 39 | // swScope 40 | if (!options.swScope) { 41 | options.swScope = options.routerBase 42 | } 43 | 44 | // Cache all _nuxt resources at runtime 45 | if (!options.assetsURLPattern) { 46 | options.assetsURLPattern = options.publicPath 47 | } 48 | if (options.cacheAssets) { 49 | options.runtimeCaching.push({ 50 | urlPattern: options.assetsURLPattern, 51 | handler: nuxt.options.dev ? 'NetworkFirst' : 'CacheFirst' 52 | }) 53 | } 54 | 55 | // Optionally cache other routes for offline 56 | if (!options.pagesURLPattern) { 57 | options.pagesURLPattern = options.routerBase 58 | } 59 | if (options.offline && !options.offlinePage) { 60 | options.runtimeCaching.push({ 61 | urlPattern: options.pagesURLPattern, 62 | handler: options.offlineStrategy 63 | }) 64 | } 65 | 66 | // Default revision 67 | if (!options.cacheOptions.revision) { 68 | options.cacheOptions.revision = randomString(12) 69 | } 70 | const normalizePreCaching = (arr: any | any[]) => [].concat(arr).map(url => ({ 71 | revision: options.cacheOptions.revision, 72 | ...(typeof url === 'string' ? { url } : url) 73 | })) 74 | 75 | // Add start_url to precaching 76 | if (pwa.manifest && pwa.manifest.start_url) { 77 | options.preCaching.unshift(...normalizePreCaching(pwa.manifest.start_url)) 78 | } 79 | 80 | // Add offlineAssets to precaching 81 | if (options.offlineAssets.length) { 82 | options.preCaching.unshift(...normalizePreCaching(options.offlineAssets)) 83 | } 84 | 85 | // Add offlinePage to precaching 86 | if (options.offlinePage) { 87 | options.preCaching.unshift(...(normalizePreCaching(options.offlinePage))) 88 | } 89 | 90 | // Default cacheId 91 | if (options.cacheOptions.cacheId === undefined) { 92 | options.cacheOptions.cacheId = (process.env.npm_package_name || 'nuxt') + (nuxt.options.dev ? '-dev' : '-prod') 93 | } 94 | 95 | // Normalize preCaching 96 | options.preCaching = normalizePreCaching(options.preCaching) 97 | 98 | // Normalize runtimeCaching 99 | const pluginModules = { 100 | BackgroundSync: 'backgroundSync.BackgroundSyncPlugin', 101 | BroadcastUpdate: 'broadcastUpdate.BroadcastUpdatePlugin', 102 | CacheableResponse: 'cacheableResponse.CacheableResponsePlugin', 103 | Expiration: 'expiration.ExpirationPlugin', 104 | RangeRequests: 'rangeRequests.RangeRequestsPlugin' 105 | } 106 | 107 | options.runtimeCaching = options.runtimeCaching.map((entry) => { 108 | return { 109 | ...entry, 110 | handler: startCase(entry.handler) || 'NetworkFirst', 111 | method: entry.method || 'GET', 112 | strategyPlugins: (entry.strategyPlugins || []).map((plugin) => { 113 | const use = pluginModules[plugin.use] 114 | if (!use) { 115 | // eslint-disable-next-line no-console 116 | console.warn(`Invalid strategy plugin ${plugin.use}`) 117 | return false 118 | } 119 | return { 120 | use, 121 | config: Array.isArray(plugin.config) ? plugin.config : [plugin.config] 122 | } 123 | }).filter(Boolean) 124 | } 125 | }) 126 | 127 | // Workbox URL 128 | if (!options.workboxURL) { 129 | options.workboxURL = `https://cdn.jsdelivr.net/npm/workbox-cdn@${options.workboxVersion}/workbox/workbox-sw.js` 130 | } 131 | 132 | // Workbox Config 133 | if (options.config.debug === undefined) { 134 | // Debug field is by default set to true for localhost domain which is not always ideal 135 | options.config.debug = options.dev || nuxt.options.dev 136 | } 137 | 138 | return options 139 | } 140 | -------------------------------------------------------------------------------- /docs/content/en/manifest.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Manifest Module 3 | description: Manifest adds Web App Manifest with no pain 4 | position: 4 5 | category: Modules 6 | --- 7 | 8 | Manifest adds [Web App Manifest](https://developer.mozilla.org/en-US/docs/Web/Manifest) with no pain. 9 | 10 | You can pass options to `pwa.manifest` in `nuxt.config.js` to override defaults. Check the 11 | [valid options](https://developer.mozilla.org/en-US/docs/Web/Manifest#Members) available and and its 12 | [default options](#default-options) for deeper insights. 13 | 14 | ```js{}[nuxt.config.js] 15 | pwa: { 16 | manifest: { 17 | name: 'My Awesome App', 18 | lang: 'fa', 19 | useWebmanifestExtension: false 20 | } 21 | } 22 | ``` 23 | 24 | ## Default options 25 | 26 | | Property | Type | Default | Description | 27 | | --------------------------------- | --------------- | ------------------------------------------------------------ | --------------------------------------------------------------- | 28 | | `name` \*1 | `String` | `package.json`'s name property | [maximum of 45 characters] | 29 | | `short_name` \*1 | `String` | `package.json`'s name property | [maximum of 12 characters] | 30 | | `description` \*2 | `String` | `package.json`'s description property | | 31 | | `icons` \*1 | `Array` | `[]` | (See the [icon module]) | 32 | | `start_url` \*1 | `String` | `routerBase + '?standalone=true'` | It has to be relative to where the manifest is placed | 33 | | `display` \*1 | `String` | `'standalone'` | | 34 | | `background_color` \*2 | `String` | `'#ffffff'` | | 35 | | `theme_color` \*2 | `String` | `pwa.meta.theme_color` | This module's meta theme-color (see the [meta module]) | 36 | | `dir` | `String` | `'ltr'` | `ltr` or `rtl`. Used with `lang` | 37 | | `lang` | `String` | `'en'` | Recommended if used `dir` | 38 | | `useWebmanifestExtension` \*3 | `Boolean` | `false` | Whether to use `webmanifest` file extension (or default `json`) | 39 | | `publicPath` | `String` | A combination of `routerBase` and `options.build.publicPath` | | 40 | 41 | - \*1 Mandatory (according [to Google](https://web.dev/add-manifest)). 42 | Although [official documentation](https://w3c.github.io/manifest/#json-schema) only mentions `name` and `icons` 43 | - \*2 Recommended (according [to Google](https://web.dev/add-manifest)) 44 | - \*3 Please see [wiki](https://github.com/nuxt-community/pwa-module/wiki/.webmanifest) 45 | 46 | [icon module]: https://pwa.nuxtjs.org/icon 47 | [meta module]: https://pwa.nuxtjs.org/meta 48 | [maximum of 45 characters]: https://developer.chrome.com/apps/manifest/name 49 | [maximum of 12 characters]: https://developer.chrome.com/apps/manifest/name 50 | [loading color]: https://nuxtjs.org/api/configuration-loading/#customizing-the-progress-bar 51 | 52 | For more information, check out: 53 | 54 | - the spec: https://w3c.github.io/manifest/ 55 | - Pete LePage's article: https://web.dev/add-manifest/ 56 | - MDN Docs: https://developer.mozilla.org/en-US/docs/Web/Manifest 57 | 58 | ## Difference between `name` and `short_name`: 59 | 60 | ### `name` 61 | 62 | > The name (maximum of 45 characters) is the primary identifier of the app and is a required field. It is displayed in the following locations: 63 | > 64 | > - Install dialog 65 | > - Extension management UI 66 | > - Chrome Web Store 67 | 68 | Source: https://developer.chrome.com/apps/manifest/name 69 | 70 | ### `short_name` 71 | 72 | > The short_name (maximum of 12 characters recommended) is a short version of the app's name. It is an optional field and if not specified, the name will be used, > though it will likely be truncated. The short name is typically used where there is insufficient space to display the full name, such as: 73 | > 74 | > - Device home screens 75 | > - New Tab page 76 | 77 | Source: https://developer.chrome.com/apps/manifest/name 78 | 79 | ## `useWebmanifestExtension`: 80 | 81 | This options sets the manifest file extension to `.json` or `.webmanifest`. For more information, check 82 | [this wiki page](https://github.com/nuxt-community/pwa-module/wiki/.webmanifest). 83 | -------------------------------------------------------------------------------- /src/icon.ts: -------------------------------------------------------------------------------- 1 | import { join, resolve } from 'path' 2 | import { fork } from 'child_process' 3 | import fs from 'fs-extra' 4 | import hasha from 'hasha' 5 | import type { PWAContext, IconOptions } from '../types' 6 | import { joinUrl, getRouteParams, sizeName, emitAsset, PKG, PKG_DIR } from './utils' 7 | 8 | export async function icon (nuxt, pwa: PWAContext, moduleContainer) { 9 | const { publicPath } = getRouteParams(nuxt.options) 10 | 11 | // Defaults 12 | const defaults: IconOptions = { 13 | sizes: [64, 120, 144, 152, 192, 384, 512], 14 | 15 | iosSizes: [ 16 | [1536, 2048, 'ipad'], // Ipad 17 | [1536, 2048, 'ipadpro9'], // Ipad Pro 9.7" 18 | [1668, 2224, 'ipadpro10'], // Ipad Pro 10.5" 19 | [2048, 2732, 'ipadpro12'], // Ipad Pro 12.9" 20 | [640, 1136, 'iphonese'], // Iphone SE 21 | [50, 1334, 'iphone6'], // Iphone 6 22 | [1080, 1920, 'iphoneplus'], // Iphone Plus 23 | [1125, 2436, 'iphonex'], // Iphone X 24 | [828, 1792, 'iphonexr'], // Iphone XR 25 | [1242, 2688, 'iphonexsmax'] // Iphone XS Max 26 | ], 27 | 28 | fileName: 'icon.png', 29 | source: null, 30 | purpose: ['any', 'maskable'], 31 | cacheDir: join(nuxt.options.rootDir, 'node_modules/.cache/pwa/icon'), 32 | 33 | targetDir: 'icons', 34 | 35 | plugin: true, 36 | pluginName: '$icon', 37 | 38 | publicPath, 39 | 40 | // @ts-ignore 41 | _iconHash: null, 42 | _assets: null, 43 | _manifestIcons: null, 44 | _iosSplash: null 45 | } 46 | 47 | // Merge options 48 | const options: IconOptions = { 49 | ...defaults, 50 | ...pwa.icon 51 | } 52 | 53 | // Find source 54 | options.source = await findIcon(nuxt, options) 55 | 56 | // Disable module if no icon specified 57 | if (!options.source) { 58 | // eslint-disable-next-line no-console 59 | console.warn('[pwa] [icon] Icon not found in ' + resolve(nuxt.options.srcDir, nuxt.options.dir.static, options.fileName)) 60 | return 61 | } 62 | 63 | // Verify purpose 64 | if (options.purpose) { 65 | if (!Array.isArray(options.purpose)) { 66 | options.purpose = [options.purpose] 67 | } 68 | const validPurpose = ['badge', 'maskable', 'any'] 69 | if (options.purpose.find(p => !validPurpose.includes(p))) { 70 | // eslint-disable-next-line no-console 71 | console.warn('[pwa] [icon] Some invalid items removed from `options.purpose`. Valid values: ' + validPurpose) 72 | } 73 | } 74 | 75 | // Generate icons 76 | await generateIcons(nuxt, options) 77 | 78 | // Add manifest 79 | addManifest(nuxt, options, pwa) 80 | 81 | // Add plugin 82 | if (options.plugin) { 83 | addPlugin(nuxt, options, moduleContainer) 84 | } 85 | 86 | // Emit assets in background 87 | emitAssets(nuxt, options) 88 | } 89 | 90 | function findIcon (nuxt, options) { 91 | const iconSearchPath = [ 92 | options.source, 93 | resolve(nuxt.options.srcDir, nuxt.options.dir.static, options.fileName), 94 | resolve(nuxt.options.srcDir, nuxt.options.dir.assets, options.fileName) 95 | ].filter(p => p) 96 | 97 | for (const source of iconSearchPath) { 98 | if (fs.existsSync(source)) { 99 | return source 100 | } 101 | } 102 | } 103 | 104 | function addPlugin (_nuxt, options, moduleContainer) { 105 | const icons = {} 106 | for (const asset of options._assets) { 107 | icons[asset.name] = joinUrl(options.publicPath, asset.target) 108 | } 109 | 110 | if (options.plugin) { 111 | moduleContainer.addPlugin({ 112 | src: resolve(PKG_DIR, 'templates/icon.plugin.js'), 113 | fileName: 'pwa/icon.plugin.js', 114 | options: { 115 | pluginName: options.pluginName, 116 | icons 117 | } 118 | }) 119 | } 120 | } 121 | 122 | async function generateIcons (_nuxt, options) { 123 | // Get hash of source image 124 | if (!options.iconHash) { 125 | options.iconHash = await hasha.fromFile(options.source).then(h => h.substring(0, 6)) 126 | } 127 | 128 | // Icons to be emited by webpack 129 | options._assets = [] 130 | 131 | // Manifest icons 132 | const purpose = options.purpose ? options.purpose.join(' ') : undefined 133 | options._manifestIcons = [] 134 | for (const size of options.sizes) { 135 | const name = sizeName(size) 136 | const target = `${options.targetDir}/icon_${name}.${options.iconHash}.png` 137 | options._assets.push({ name, target }) 138 | options._manifestIcons.push({ 139 | src: joinUrl(options.publicPath, target), 140 | sizes: name, 141 | type: 'image/png', 142 | purpose 143 | }) 144 | } 145 | 146 | // Generate _iosSplash 147 | options._iosSplash = {} 148 | for (const size of options.iosSizes) { 149 | const name = sizeName(size) 150 | const target = `${options.targetDir}/splash_${name}.${options.iconHash}.png` 151 | options._assets.push({ name, target }) 152 | options._iosSplash[size[2]] = joinUrl(options.publicPath, target) 153 | } 154 | } 155 | 156 | function addManifest (_nuxt, options, pwa) { 157 | if (!pwa.manifest) { 158 | pwa.manifest = {} 159 | } 160 | 161 | if (!pwa.manifest.icons) { 162 | pwa.manifest.icons = [] 163 | } 164 | pwa.manifest.icons.push(...options._manifestIcons) 165 | 166 | pwa._iosSplash = { 167 | ...options._iosSplash 168 | } 169 | } 170 | 171 | function emitAssets (nuxt, options) { 172 | // Start resize task in background 173 | const resizePromise = resizeIcons(nuxt, options) 174 | 175 | for (const { name, target } of options._assets) { 176 | const srcFileName = join(options.cacheDir, `${name}.png`) 177 | emitAsset(nuxt, target, resizePromise.then(() => fs.readFile(srcFileName))) 178 | } 179 | } 180 | 181 | async function resizeIcons (_nuxt, options) { 182 | const resizeOpts = JSON.stringify({ 183 | version: PKG.version, 184 | input: options.source, 185 | distDir: options.cacheDir, 186 | sizes: [ 187 | ...options.sizes, 188 | ...options.iosSizes 189 | ] 190 | }) 191 | 192 | const integrityFile = join(options.cacheDir, '.' + hasha(resizeOpts).substr(0, 8)) 193 | 194 | if (fs.existsSync(integrityFile)) { 195 | return 196 | } 197 | await fs.remove(options.cacheDir) 198 | await fs.mkdirp(options.cacheDir) 199 | 200 | // eslint-disable-next-line promise/param-names 201 | await new Promise((_resolve, _reject) => { 202 | const child = fork(resolve(PKG_DIR, 'lib/resize.js'), [resizeOpts], { execArgv: [] }) 203 | child.on('exit', (code) => { 204 | return code ? _reject(code) : _resolve() 205 | }) 206 | }) 207 | 208 | await fs.writeFile(integrityFile, '') 209 | } 210 | -------------------------------------------------------------------------------- /test/__snapshots__/pwa.test.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`pwa generate files (dist) 1`] = ` 4 | Array [ 5 | "fixture/dist/.gitkeep", 6 | "fixture/dist/.nojekyll", 7 | "fixture/dist/200.html", 8 | "fixture/dist/_nuxt", 9 | "fixture/dist/_nuxt/LICENSES", 10 | "fixture/dist/_nuxt/icons", 11 | "fixture/dist/_nuxt/icons/icon_120x120.b8f3a1.png", 12 | "fixture/dist/_nuxt/icons/icon_144x144.b8f3a1.png", 13 | "fixture/dist/_nuxt/icons/icon_152x152.b8f3a1.png", 14 | "fixture/dist/_nuxt/icons/icon_192x192.b8f3a1.png", 15 | "fixture/dist/_nuxt/icons/icon_384x384.b8f3a1.png", 16 | "fixture/dist/_nuxt/icons/icon_512x512.b8f3a1.png", 17 | "fixture/dist/_nuxt/icons/icon_64x64.b8f3a1.png", 18 | "fixture/dist/_nuxt/icons/splash_ipad_1536x2048.b8f3a1.png", 19 | "fixture/dist/_nuxt/icons/splash_ipadpro10_1668x2224.b8f3a1.png", 20 | "fixture/dist/_nuxt/icons/splash_ipadpro12_2048x2732.b8f3a1.png", 21 | "fixture/dist/_nuxt/icons/splash_ipadpro9_1536x2048.b8f3a1.png", 22 | "fixture/dist/_nuxt/icons/splash_iphone6_50x1334.b8f3a1.png", 23 | "fixture/dist/_nuxt/icons/splash_iphoneplus_1080x1920.b8f3a1.png", 24 | "fixture/dist/_nuxt/icons/splash_iphonese_640x1136.b8f3a1.png", 25 | "fixture/dist/_nuxt/icons/splash_iphonex_1125x2436.b8f3a1.png", 26 | "fixture/dist/_nuxt/icons/splash_iphonexr_828x1792.b8f3a1.png", 27 | "fixture/dist/_nuxt/icons/splash_iphonexsmax_1242x2688.b8f3a1.png", 28 | "fixture/dist/_nuxt/manifest_test.webmanifest", 29 | "fixture/dist/_nuxt/static", 30 | "fixture/dist/_nuxt/static/default", 31 | "fixture/dist/_nuxt/static/default/bar", 32 | "fixture/dist/_nuxt/static/default/baz", 33 | "fixture/dist/_nuxt/static/default/foo", 34 | "fixture/dist/bar", 35 | "fixture/dist/bar/index.html", 36 | "fixture/dist/baz", 37 | "fixture/dist/baz/index.html", 38 | "fixture/dist/foo", 39 | "fixture/dist/foo/index.html", 40 | "fixture/dist/icon.png", 41 | "fixture/dist/index.html", 42 | "fixture/dist/offline.html", 43 | "fixture/dist/offline.png", 44 | ] 45 | `; 46 | 47 | exports[`pwa manifest.json 1`] = ` 48 | "{ 49 | \\"name\\": \\"Test Project Name\\", 50 | \\"short_name\\": \\"@nuxtjs/pwa\\", 51 | \\"description\\": \\"Test Project Description\\", 52 | \\"icons\\": [ 53 | { 54 | \\"src\\": \\"/_nuxt/icons/icon_64x64.b8f3a1.png\\", 55 | \\"sizes\\": \\"64x64\\", 56 | \\"type\\": \\"image/png\\", 57 | \\"purpose\\": \\"any maskable\\" 58 | }, 59 | { 60 | \\"src\\": \\"/_nuxt/icons/icon_120x120.b8f3a1.png\\", 61 | \\"sizes\\": \\"120x120\\", 62 | \\"type\\": \\"image/png\\", 63 | \\"purpose\\": \\"any maskable\\" 64 | }, 65 | { 66 | \\"src\\": \\"/_nuxt/icons/icon_144x144.b8f3a1.png\\", 67 | \\"sizes\\": \\"144x144\\", 68 | \\"type\\": \\"image/png\\", 69 | \\"purpose\\": \\"any maskable\\" 70 | }, 71 | { 72 | \\"src\\": \\"/_nuxt/icons/icon_152x152.b8f3a1.png\\", 73 | \\"sizes\\": \\"152x152\\", 74 | \\"type\\": \\"image/png\\", 75 | \\"purpose\\": \\"any maskable\\" 76 | }, 77 | { 78 | \\"src\\": \\"/_nuxt/icons/icon_192x192.b8f3a1.png\\", 79 | \\"sizes\\": \\"192x192\\", 80 | \\"type\\": \\"image/png\\", 81 | \\"purpose\\": \\"any maskable\\" 82 | }, 83 | { 84 | \\"src\\": \\"/_nuxt/icons/icon_384x384.b8f3a1.png\\", 85 | \\"sizes\\": \\"384x384\\", 86 | \\"type\\": \\"image/png\\", 87 | \\"purpose\\": \\"any maskable\\" 88 | }, 89 | { 90 | \\"src\\": \\"/_nuxt/icons/icon_512x512.b8f3a1.png\\", 91 | \\"sizes\\": \\"512x512\\", 92 | \\"type\\": \\"image/png\\", 93 | \\"purpose\\": \\"any maskable\\" 94 | } 95 | ], 96 | \\"start_url\\": \\"/?standalone=true\\", 97 | \\"display\\": \\"standalone\\", 98 | \\"background_color\\": \\"#ffffff\\", 99 | \\"lang\\": \\"en\\", 100 | \\"orientation\\": \\"portrait\\" 101 | }" 102 | `; 103 | 104 | exports[`pwa sw.js 1`] = ` 105 | "const options = {\\"workboxURL\\":\\"https://cdn.jsdelivr.net/npm/workbox-cdn/workbox/workbox-sw.js\\",\\"importScripts\\":[\\"custom-sw.js\\"],\\"config\\":{\\"debug\\":true},\\"cacheNames\\":{\\"prefix\\":\\"test\\",\\"googleAnalytics\\":\\"test-ga\\"},\\"cacheOptions\\":{\\"revision\\":\\"test-rev\\",\\"cacheId\\":\\"@nuxtjs/pwa-prod\\"},\\"clientsClaim\\":true,\\"skipWaiting\\":true,\\"cleanupOutdatedCaches\\":true,\\"offlineAnalytics\\":true,\\"preCaching\\":[{\\"revision\\":\\"test-rev\\",\\"url\\":\\"/?standalone=true\\"},{\\"revision\\":\\"test-rev\\",\\"url\\":\\"precache.js\\"}],\\"runtimeCaching\\":[{\\"urlPattern\\":\\"https://google.com/.*\\",\\"handler\\":\\"CacheFirst\\",\\"method\\":\\"GET\\",\\"strategyPlugins\\":[]},{\\"urlPattern\\":\\"https://pwa.nuxtjs.org/.*\\",\\"handler\\":\\"CacheFirst\\",\\"method\\":\\"GET\\",\\"strategyOptions\\":{\\"cacheName\\":\\"nuxt-pwa\\"},\\"strategyPlugins\\":[{\\"use\\":\\"expiration.ExpirationPlugin\\",\\"config\\":[{\\"maxEntries\\":10,\\"maxAgeSeconds\\":300}]}]},{\\"urlPattern\\":\\"/_nuxt/\\",\\"handler\\":\\"CacheFirst\\",\\"method\\":\\"GET\\",\\"strategyPlugins\\":[]},{\\"urlPattern\\":\\"/\\",\\"handler\\":\\"NetworkFirst\\",\\"method\\":\\"GET\\",\\"strategyPlugins\\":[]}],\\"offlinePage\\":null,\\"pagesURLPattern\\":\\"/\\",\\"offlineStrategy\\":\\"NetworkFirst\\"} 106 | 107 | importScripts(...[options.workboxURL, ...options.importScripts]) 108 | 109 | initWorkbox(workbox, options) 110 | workboxExtensions(workbox, options) 111 | precacheAssets(workbox, options) 112 | cachingExtensions(workbox, options) 113 | runtimeCaching(workbox, options) 114 | offlinePage(workbox, options) 115 | routingExtensions(workbox, options) 116 | 117 | function getProp(obj, prop) { 118 | return prop.split('.').reduce((p, c) => p[c], obj) 119 | } 120 | 121 | function initWorkbox(workbox, options) { 122 | if (options.config) { 123 | // Set workbox config 124 | workbox.setConfig(options.config) 125 | } 126 | 127 | if (options.cacheNames) { 128 | // Set workbox cache names 129 | workbox.core.setCacheNameDetails(options.cacheNames) 130 | } 131 | 132 | if (options.clientsClaim) { 133 | // Start controlling any existing clients as soon as it activates 134 | workbox.core.clientsClaim() 135 | } 136 | 137 | if (options.skipWaiting) { 138 | workbox.core.skipWaiting() 139 | } 140 | 141 | if (options.cleanupOutdatedCaches) { 142 | workbox.precaching.cleanupOutdatedCaches() 143 | } 144 | 145 | if (options.offlineAnalytics) { 146 | // Enable offline Google Analytics tracking 147 | workbox.googleAnalytics.initialize() 148 | } 149 | } 150 | 151 | function precacheAssets(workbox, options) { 152 | if (options.preCaching.length) { 153 | workbox.precaching.precacheAndRoute(options.preCaching, options.cacheOptions) 154 | } 155 | } 156 | 157 | 158 | function runtimeCaching(workbox, options) { 159 | const requestInterceptor = { 160 | requestWillFetch({ request }) { 161 | if (request.cache === 'only-if-cached' && request.mode === 'no-cors') { 162 | return new Request(request.url, { ...request, cache: 'default', mode: 'no-cors' }) 163 | } 164 | return request 165 | }, 166 | fetchDidFail(ctx) { 167 | ctx.error.message = 168 | '[workbox] Network request for ' + ctx.request.url + ' threw an error: ' + ctx.error.message 169 | console.error(ctx.error, 'Details:', ctx) 170 | }, 171 | handlerDidError(ctx) { 172 | ctx.error.message = 173 | \`[workbox] Network handler threw an error: \` + ctx.error.message 174 | console.error(ctx.error, 'Details:', ctx) 175 | return null 176 | } 177 | } 178 | 179 | for (const entry of options.runtimeCaching) { 180 | const urlPattern = new RegExp(entry.urlPattern) 181 | const method = entry.method || 'GET' 182 | 183 | const plugins = (entry.strategyPlugins || []) 184 | .map(p => new (getProp(workbox, p.use))(...p.config)) 185 | 186 | plugins.unshift(requestInterceptor) 187 | 188 | const strategyOptions = { ...entry.strategyOptions, plugins } 189 | 190 | const strategy = new workbox.strategies[entry.handler](strategyOptions) 191 | 192 | workbox.routing.registerRoute(urlPattern, strategy, method) 193 | } 194 | } 195 | 196 | function offlinePage(workbox, options) { 197 | if (options.offlinePage) { 198 | // Register router handler for offlinePage 199 | workbox.routing.registerRoute(new RegExp(options.pagesURLPattern), ({ request, event }) => { 200 | const strategy = new workbox.strategies[options.offlineStrategy] 201 | return strategy 202 | .handle({ request, event }) 203 | .catch(() => caches.match(options.offlinePage)) 204 | }) 205 | } 206 | } 207 | 208 | function workboxExtensions(workbox, options) { 209 | // Workbox Extension 210 | } 211 | 212 | function cachingExtensions(workbox, options) { 213 | // Caching Extension 214 | } 215 | 216 | function routingExtensions(workbox, options) { 217 | // Routing Extension 218 | } 219 | " 220 | `; 221 | -------------------------------------------------------------------------------- /src/meta.ts: -------------------------------------------------------------------------------- 1 | import { join, resolve } from 'path' 2 | import { existsSync, readJsonSync } from 'fs-extra' 3 | import { mergeMeta } from '../lib/meta.utils' 4 | import type { MetaOptions, PWAContext } from '../types' 5 | import { isUrl, PKG_DIR } from './utils' 6 | 7 | export function meta (nuxt, pwa: PWAContext, moduleContainer) { 8 | // Defaults 9 | const defaults: MetaOptions = { 10 | name: process.env.npm_package_name, 11 | author: process.env.npm_package_author_name, 12 | description: process.env.npm_package_description, 13 | charset: 'utf-8', 14 | viewport: undefined, 15 | mobileApp: true, 16 | nativeUI: false, 17 | favicon: true, 18 | mobileAppIOS: undefined, 19 | appleStatusBarStyle: undefined, 20 | theme_color: undefined, 21 | lang: 'en', 22 | ogType: 'website', 23 | ogSiteName: true, 24 | ogTitle: true, 25 | ogDescription: true, 26 | ogImage: true, 27 | ogHost: undefined, 28 | ogUrl: true, 29 | twitterCard: undefined, 30 | twitterSite: undefined, 31 | twitterCreator: undefined 32 | } 33 | 34 | // Combine sources 35 | const options: MetaOptions = { ...defaults, ...pwa.manifest, ...pwa.meta } 36 | 37 | // Default value for viewport 38 | if (options.viewport === undefined) { 39 | options.viewport = options.nativeUI 40 | ? 'width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0, minimal-ui' 41 | : 'width=device-width, initial-scale=1' 42 | } 43 | 44 | // Default value for mobileAppIOS 45 | if (options.mobileAppIOS === undefined) { 46 | options.mobileAppIOS = !!options.nativeUI 47 | } 48 | 49 | const head = { 50 | title: '', 51 | meta: [], 52 | link: [], 53 | htmlAttrs: {} as any 54 | } 55 | 56 | // Charset 57 | if (options.charset) { 58 | head.meta.push({ hid: 'charset', charset: options.charset }) 59 | } 60 | 61 | // Viewport 62 | if (options.viewport) { 63 | head.meta.push({ hid: 'viewport', name: 'viewport', content: options.viewport }) 64 | } 65 | 66 | // mobileApp 67 | if (options.mobileApp) { 68 | head.meta.push({ hid: 'mobile-web-app-capable', name: 'mobile-web-app-capable', content: 'yes' }) 69 | } 70 | 71 | // mobileApp (IOS) 72 | if (options.mobileAppIOS) { 73 | head.meta.push({ hid: 'apple-mobile-web-app-capable', name: 'apple-mobile-web-app-capable', content: 'yes' }) 74 | } 75 | 76 | // statusBarStyle (IOS) 77 | if (options.mobileAppIOS || options.appleStatusBarStyle) { 78 | head.meta.push({ 79 | hid: 'apple-mobile-web-app-status-bar-style', 80 | name: 'apple-mobile-web-app-status-bar-style', 81 | content: options.appleStatusBarStyle || 'default' 82 | }) 83 | } 84 | 85 | // Icons 86 | if (options.icons && options.icons.length > 0) { 87 | const iconSmall = options.icons[0] 88 | const iconBig = options.icons[options.icons.length - 1] 89 | 90 | // Shortcut icon 91 | if (options.favicon) { 92 | head.link.push({ hid: 'shortcut-icon', rel: 'shortcut icon', href: iconSmall.src }) 93 | head.link.push({ hid: 'apple-touch-icon', rel: 'apple-touch-icon', href: iconBig.src, sizes: iconBig.sizes }) 94 | } 95 | 96 | // Launch Screen Image (IOS) 97 | if (options.mobileAppIOS && pwa._iosSplash) { 98 | const splashes = [ 99 | ['iphonese', '(device-width: 320px) and (device-height: 568px) and (-webkit-device-pixel-ratio: 2)'], 100 | ['iphone6', '(device-width: 375px) and (device-height: 667px) and (-webkit-device-pixel-ratio: 2)'], 101 | ['iphoneplus', '(device-width: 621px) and (device-height: 1104px) and (-webkit-device-pixel-ratio: 3)'], 102 | ['iphonex', '(device-width: 375px) and (device-height: 812px) and (-webkit-device-pixel-ratio: 3)'], 103 | ['iphonexr', '(device-width: 414px) and (device-height: 896px) and (-webkit-device-pixel-ratio: 2)'], 104 | ['iphonexsmax', '(device-width: 414px) and (device-height: 896px) and (-webkit-device-pixel-ratio: 3)'], 105 | ['ipad', '(device-width: 768px) and (device-height: 1024px) and (-webkit-device-pixel-ratio: 2)'], 106 | ['ipadpro1', '(device-width: 834px) and (device-height: 1112px) and (-webkit-device-pixel-ratio: 2)'], 107 | ['ipadpro2', '(device-width: 834px) and (device-height: 1194px) and (-webkit-device-pixel-ratio: 2)'], 108 | ['ipadpro3', '(device-width: 1024px) and (device-height: 1366px) and (-webkit-device-pixel-ratio: 2)'] 109 | ] 110 | 111 | for (const [type, media] of splashes) { 112 | head.link.push({ 113 | href: pwa._iosSplash[type], 114 | media, 115 | rel: 'apple-touch-startup-image', 116 | hid: 'apple-touch-startup-image-' + type 117 | }) 118 | } 119 | } 120 | } else { 121 | // favicon.ico as fallback 122 | // TODO: Drop support as it is harmful: https://mathiasbynens.be/notes/rel-shortcut-icon 123 | const favicon = join(nuxt.options.srcDir, nuxt.options.dir.static, 'favicon.ico') 124 | if (existsSync(favicon)) { 125 | head.link.push({ hid: 'shortcut-icon', rel: 'shortcut icon', href: nuxt.options.router.base + 'favicon.ico' }) 126 | } 127 | } 128 | 129 | // Title 130 | const title = options.name || options.title 131 | if (title) { 132 | head.title = options.name 133 | // IOS launch icon title 134 | head.meta.push({ hid: 'apple-mobile-web-app-title', name: 'apple-mobile-web-app-title', content: title }) 135 | } 136 | 137 | // Author 138 | if (options.author) { 139 | head.meta.push({ hid: 'author', name: 'author', content: options.author }) 140 | } 141 | 142 | // description meta 143 | if (options.description) { 144 | head.meta.push({ hid: 'description', name: 'description', content: options.description }) 145 | } 146 | 147 | // theme-color meta 148 | if (options.theme_color) { 149 | head.meta.push({ hid: 'theme-color', name: 'theme-color', content: options.theme_color }) 150 | } 151 | 152 | // Add lang to html tag 153 | if (options.lang) { 154 | head.htmlAttrs.lang = options.lang 155 | } 156 | 157 | // og:type 158 | if (options.ogType) { 159 | head.meta.push({ hid: 'og:type', name: 'og:type', property: 'og:type', content: options.ogType }) 160 | } 161 | 162 | // og:title 163 | if (options.ogTitle === true) { 164 | options.ogTitle = options.name 165 | } 166 | if (options.ogTitle) { 167 | head.meta.push({ hid: 'og:title', name: 'og:title', property: 'og:title', content: options.ogTitle }) 168 | } 169 | // og:site_name 170 | if (options.ogSiteName === true) { 171 | options.ogSiteName = options.name 172 | } 173 | if (options.ogSiteName) { 174 | head.meta.push({ hid: 'og:site_name', name: 'og:site_name', property: 'og:site_name', content: options.ogSiteName }) 175 | } 176 | 177 | // og:description 178 | if (options.ogDescription === true) { 179 | options.ogDescription = options.description 180 | } 181 | if (options.ogDescription) { 182 | head.meta.push({ hid: 'og:description', name: 'og:description', property: 'og:description', content: options.ogDescription }) 183 | } 184 | 185 | // og:url 186 | if (options.ogHost && options.ogUrl === true) { 187 | options.ogUrl = options.ogHost 188 | } 189 | if (options.ogUrl && options.ogUrl !== true) { 190 | head.meta.push({ hid: 'og:url', name: 'og:url', property: 'og:url', content: options.ogUrl }) 191 | } 192 | 193 | // og:image 194 | if (options.ogImage === true) { 195 | if (options.icons && options.icons.length > 0) { 196 | const iconBig = options.icons[options.icons.length - 1] 197 | const [width, height] = iconBig.sizes.split('x').map(x => parseInt(x)) 198 | options.ogImage = { path: iconBig.src, width, height, type: iconBig.type } 199 | } else { 200 | options.ogImage = false 201 | } 202 | } else if (typeof options.ogImage === 'string') { 203 | options.ogImage = { path: options.ogImage } 204 | } 205 | if (options.ogImage) { 206 | if (options.ogHost || isUrl(options.ogImage.path)) { 207 | head.meta.push({ 208 | hid: 'og:image', 209 | name: 'og:image', 210 | property: 'og:image', 211 | content: isUrl(options.ogImage.path) ? options.ogImage.path : options.ogHost + options.ogImage.path 212 | }) 213 | if (options.ogImage.width && options.ogImage.height) { 214 | head.meta.push({ 215 | hid: 'og:image:width', 216 | name: 'og:image:width', 217 | property: 'og:image:width', 218 | content: options.ogImage.width 219 | }) 220 | head.meta.push({ 221 | hid: 'og:image:height', 222 | name: 'og:image:height', 223 | property: 'og:image:height', 224 | content: options.ogImage.height 225 | }) 226 | } 227 | if (options.ogImage.type) { 228 | head.meta.push({ 229 | hid: 'og:image:type', 230 | name: 'og:image:type', 231 | property: 'og:image:type', 232 | content: options.ogImage.type 233 | }) 234 | } 235 | } 236 | } 237 | 238 | // twitter:card 239 | if (options.twitterCard) { 240 | head.meta.push({ hid: 'twitter:card', name: 'twitter:card', property: 'twitter:card', content: options.twitterCard }) 241 | } 242 | 243 | // twitter:site 244 | if (options.twitterSite) { 245 | head.meta.push({ hid: 'twitter:site', name: 'twitter:site', property: 'twitter:site', content: options.twitterSite }) 246 | } 247 | 248 | // twitter:creator 249 | if (options.twitterCreator) { 250 | head.meta.push({ hid: 'twitter:creator', name: 'twitter:creator', property: 'twitter:creator', content: options.twitterCreator }) 251 | } 252 | 253 | // manifest meta 254 | if (pwa._manifestMeta) { 255 | head.link.push(pwa._manifestMeta) 256 | } 257 | 258 | moduleContainer.addPlugin({ 259 | src: resolve(PKG_DIR, 'templates/meta.plugin.js'), 260 | fileName: 'pwa/meta.plugin.js', 261 | options: {} 262 | }) 263 | 264 | moduleContainer.addTemplate({ 265 | src: resolve(PKG_DIR, 'templates/meta.json'), 266 | fileName: 'pwa/meta.json', 267 | options: { head } 268 | }) 269 | 270 | moduleContainer.addTemplate({ 271 | src: resolve(PKG_DIR, 'lib/meta.utils.js'), 272 | fileName: 'pwa/meta.utils.js', 273 | options: { head } 274 | }) 275 | 276 | metaRuntime(nuxt) 277 | } 278 | 279 | export function metaRuntime (nuxt) { 280 | const spaSupport = () => { 281 | try { 282 | const metaJSON = readJsonSync(resolve(nuxt.options.buildDir, 'pwa/meta.json')) 283 | mergeMeta(nuxt.options.head, metaJSON) 284 | } catch (_err) {} 285 | } 286 | 287 | nuxt.hook('render:resourcesLoaded', () => spaSupport()) 288 | } 289 | -------------------------------------------------------------------------------- /docs/content/en/workbox.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Workbox Module 3 | description: Workbox is a collection of JavaScript libraries for Progressive Web Apps 4 | position: 5 5 | category: Modules 6 | --- 7 | 8 | Workbox is a collection of JavaScript libraries for Progressive Web Apps. 9 | ([Learn more](https://developers.google.com/web/tools/workbox)). This module adds full offline support using workbox. 10 | 11 | You can pass options to `pwa.workbox` in `nuxt.config.js` to override the [defaults](https://github.com/nuxt-community/pwa-module/blob/dev/lib/workbox/defaults.js). 12 | 13 | ```js{}[nuxt.config.js] 14 | pwa: { 15 | workbox: { 16 | /* workbox options */ 17 | } 18 | } 19 | ``` 20 | 21 | ## Options 22 | 23 | 24 | 25 | ### `workboxVersion` 26 | 27 | (String) Version of workbox. Default value is latest tested version which will be updated by updating this package. 28 | 29 | ### `workboxURL` 30 | 31 | (String) URL for workbox CDN. Default is JSDelivr - See [Workbox CDN](https://github.com/nuxt-community/workbox-cdn). You can also use `config.modulePathPrefix` if you need to rewrite module paths. 32 | 33 | ### `importScripts` 34 | 35 | (Array) Additional scripts to be imported in service worker script. (Relative to `/`. Can be placed in `assets/` directory) 36 | 37 | ### `autoRegister` 38 | 39 | (Boolean) Automatically register `/sw.js` on page load. Enabled by default. 40 | 41 | ### `enabled` 42 | 43 | (Boolean) Enable workbox module. Workbox is **only enabled for production mode by default**. 44 | 45 | **IMPORTANT NOTES:** 46 | 47 | - It is recommended to test workbox using `nuxt build`/`nuxt start`. You can enable debug mode using `workbox.config.debug` for production to debug. 48 | - When setting `enabled` to `true`, remember to clean application data and unregister service workers in your browser when changing mode between dev or prod to avoid issues. 49 | - When `enabled` is set to `false` (default for `nuxt dev`) workbox module registers a self-destroying worker and cleans `window.caches`. To completely disable module you can set `pwa.workbox: false` in `nuxt.config`. 50 | 51 | 52 | 53 | ### `cacheNames` 54 | 55 | (Object) Configure the workbox cache names. See [workbox docs](https://developers.google.com/web/tools/workbox/guides/configure-workbox#configure_cache_names) for more information on this. 56 | 57 | ### `config` 58 | 59 | (Object) Options to be passed to workbox before using it's modules. By default `debug` field will be set to `false` for production builds. 60 | 61 | ### `clientsClaim` 62 | 63 | (Boolean) Start controlling any existing clients as soon as it activates. Enabled by default. 64 | 65 | ### `skipWaiting` 66 | 67 | (Boolean) Skip over the SW waiting lifecycle stage. Enabled by default. 68 | 69 | 70 | ### `offlineAnalytics` 71 | 72 | (Boolean) Enable offline Google Analytics tracking [through workbox](https://developers.google.com/web/tools/workbox/guides/enable-offline-analytics) (Disabled by default) 73 | 74 | ### `workboxExtensions` 75 | 76 | (String|String[]) Loads and inserts the contents of the specified file path into the service worker script before any call to `precacheAndRoute`. You may add as many extra calls as you want to these files. 77 | 78 | 79 | 80 | ### `preCaching` 81 | 82 | (Array) Cache a set of files when registering service worker. Default is `[]` 83 | 84 | Workbox takes a lot of the heavy lifting out of precaching by simplifying the API and ensuring assets are downloaded efficiently. 85 | 86 | ### `cacheOptions` 87 | 88 | (Object) Default: 89 | 90 | ```js 91 | { 92 | cacheId: ' || nuxt', 93 | directoryIndex: '/', 94 | revision: undefined 95 | } 96 | ``` 97 | 98 | ### `cachingExtensions` 99 | 100 | (String|String[]) Loads and inserts the contents of the specified file path into the service worker script, below autogenerated calls to `workbox.precaching.*`. You may add as many extra calls as you want to these files. 101 | 102 | ### `cleanupOutdatedCaches` 103 | 104 | (Boolean) Find and remove any of the older precaches that might have been used by previous versions of Workbox. 105 | 106 | 107 | 108 | ### `offline` 109 | 110 | (Boolean) Cache all routes. Enabled by default. 111 | 112 | ### `offlineStrategy` 113 | 114 | (String) Strategy for caching routes. Default is `NetworkFirst`. 115 | 116 | ### `offlinePage` 117 | 118 | (String) Enables routing all offline requests to the specified path. (Example: `/offline.html`) 119 | 120 | **Please note** that enabling `offlinePage` will disable `/.*` caching (`offline` option) and will route all offline requests to the specified path. 121 | 122 | ### `offlineAssets` 123 | 124 | (Array) List of assets to precache, in case you need extra files precached other than on the fly caching (`_nuxt/*` etc) or you want to ensure assets used by your `offlinePage`. (Example: `['/offline.png']`) 125 | 126 | 127 | 128 | ### `runtimeCaching` 129 | 130 | (Array) Custom routes to cache with specific strategy. Useful for caching requests to other origins. 131 | 132 | ### `cacheAssets` 133 | 134 | (Boolean) Cache requests to the `/_nuxt/*` with **CacheFirst** strategy on the fly. Enabled by default. 135 | 136 | **NOTE:** This is considered safe because all assets should be correctly hashed there. 137 | 138 | **NOTE:** Nuxt smart links trigger chunk downloads for next pages when user sees a link to a non-cached page. 139 | 140 | ### `routingExtensions` 141 | 142 | (String|String[]) Loads and inserts the contents of the specified file path into the service worker script, below autogenerated calls to `workbox.routing.*`. You may add as many extra calls as you want to these files. 143 | 144 | ### `assetsURLPattern` 145 | 146 | (String/Regex) Pattern to match assets for runtime caching. 147 | 148 | Default is auto generated based on `publicPath`. Supports CDN too. 149 | 150 | Default: `/_nuxt/` 151 | 152 | ### `pagesURLPattern` 153 | 154 | (String/Regex) Pattern to match pages to be offlined. 155 | 156 | Default is auto generated based on `router.base`. 157 | 158 | Default: `/` 159 | 160 | 161 | 162 | ### `swTemplate` 163 | 164 | (String) You can use this to customize generated `sw.js`. Not recommended to be directly used. 165 | 166 | ### `swURL` 167 | 168 | (String) If you need to register another service worker (OneSignal, etc) you can use this option. 169 | 170 | ### `swDest` 171 | 172 | (String) If you want to change the name of service worker, you must use this option with swURL. 173 | 174 | ### `swScope` 175 | 176 | (String) Defaults to `routerBase`. 177 | 178 | 179 | 180 | ### `routerBase` 181 | 182 | (String) Defaults to router base. 183 | 184 | ### `publicPath` 185 | 186 | (String) Defaults to `/_nuxt`. 187 | 188 | 189 | ## Workbox Window 190 | 191 | This module uses [workbox-window](https://developer.chrome.com/docs/workbox/modules/workbox-window/) to register and communicate with workbox service worker. 192 | See docs for more information about use cases. 193 | 194 | As service worker is registered in background, to access instance you have to await on a promise: 195 | 196 | ```js 197 | const workbox = await window.$workbox 198 | 199 | if (workbox) { 200 | // Service worker is available 201 | } 202 | ``` 203 | 204 | ## Examples 205 | 206 | ### Adding custom runtimeCaching items (For CDN) 207 | 208 | By default resources in dist (`/_nuxt/`) will be cached with `CacheFirst` and other requests to same domain will be cached with `NetworkFirst` strategy. 209 | 210 | If you have a custom CDN and need to cache requests for it, simply use `runtimeCaching`: 211 | 212 | **IMPORTANT:** Please note that workbox will **not** cache opaque responses. So please only use either `NetworkFirst` or `StaleWhileRevalidate` strategies. Please see [Handle Third Party Requests](https://developers.google.com/web/tools/workbox/guides/handle-third-party-requests). 213 | 214 | ```js{}[nuxt.config.js] 215 | workbox: { 216 | runtimeCaching: [ 217 | { 218 | // Should be a regex string. Compiles into new RegExp('https://my-cdn.com/.*') 219 | urlPattern: 'https://my-cdn.com/.*', 220 | // Defaults to `NetworkFirst` if omitted 221 | // handler: 'NetworkFirst', 222 | // Defaults to `GET` if omitted 223 | // method: 'GET' 224 | } 225 | ] 226 | } 227 | ``` 228 | 229 | ### Adding custom cache 230 | 231 | [StrategyOption](https://developers.google.com/web/tools/workbox/modules/workbox-strategies) 232 | 233 | ```js{}[nuxt.config.js] 234 | workbox: { 235 | runtimeCaching: [ 236 | { 237 | urlPattern: 'https://my-cdn.com/posts/.*', 238 | strategyOptions: { 239 | cacheName: 'our-cache', 240 | }, 241 | strategyPlugins: [{ 242 | use: 'Expiration', 243 | config: { 244 | maxEntries: 10, 245 | maxAgeSeconds: 300 246 | } 247 | }] 248 | } 249 | ] 250 | } 251 | ``` 252 | 253 | This strategy plugins are supported (possible values for `strategyPlugins[].use`): 254 | 255 | - BackgroundSync 256 | - BroadcastUpdate 257 | - CacheableResponse 258 | - Expiration 259 | - RangeRequests 260 | 261 | You can pass an array for `strategyPlugins[].config` if it supports more than one argument. Only JSON serializable values are supported (for example you cannot pass an inline function as config) 262 | 263 | ### Adding custom service worker 264 | 265 | Create `static/custom-sw.js` file: 266 | 267 | ```js{}[static/custom-sw.js] 268 | console.log('Custom service worker!') 269 | ``` 270 | 271 | Add it with `importScripts` option in `nuxt.config.js`: 272 | 273 | ```js{}[nuxt.config.js] 274 | workbox: { 275 | importScripts: [ 276 | 'custom-sw.js' 277 | ], 278 | } 279 | ``` 280 | 281 | ### Hooking on service worker registration life cycle 282 | 283 | Create `plugins/sw.client.js`. The `client` suffix tells Nuxt that the plugin should only be loaded on client-side: 284 | 285 | ```js{}[plugins/sw.client.js] 286 | if ('serviceWorker' in navigator) { 287 | navigator.serviceWorker.getRegistrations().then((registrations) => { 288 | for (const worker of registrations) { 289 | console.log('Service worker:', worker) 290 | } 291 | }); 292 | } 293 | ``` 294 | 295 | Add it to the `plugins` section of `nuxt.config.js`: 296 | 297 | ```js{}[nuxt.config.js] 298 | { 299 | plugins: [ 300 | '~/plugins/sw.client.js' 301 | ] 302 | } 303 | ``` 304 | 305 | ### Basic Auth 306 | 307 | As a workaround for making basic auth working as described [here](https://thatemil.com/blog/2018/02/21/pwa-basic-auth) 308 | you have to enable `manifest.crossorigin` in `nuxt.config.js`: 309 | 310 | ```js{}[nuxt.config.js] 311 | { 312 | manifest: { 313 | crossorigin: 'use-credentials' 314 | } 315 | } 316 | ``` 317 | 318 | Thanks to [@henrixapp](https://github.com/henrixapp) for the tip. 319 | 320 | ### Enable rangeRequests 321 | 322 | Safari requires rangeRequests. 323 | 324 | `plugins/workbox-range-request.js`: 325 | 326 | ```js{}[plugins/workbox-range-request.js] 327 | workbox.routing.registerRoute( 328 | /\.(mp4|webm)/, 329 | new workbox.strategies.CacheFirst({ 330 | plugins: [ 331 | new workbox.rangeRequests.RangeRequestsPlugin(), 332 | ], 333 | }), 334 | 'GET' 335 | ); 336 | ``` 337 | 338 | `nuxt.config.js`: 339 | 340 | ```js{}[nuxt.config.js] 341 | { 342 | workbox: { 343 | cachingExtensions: '@/plugins/workbox-range-request.js' 344 | } 345 | } 346 | ``` 347 | 348 | Thanks to [@CarterLi](https://github.com/CarterLi) for the tip. 349 | 350 | 351 | ### Disable Add to Home Screen button (the mini-infobar) 352 | 353 | A PWA can be installed by the user if it meets a set of **criteria** and as installable it can trigger an "Add to Home Screen" button (the mini-infobar) as described [here](https://developers.google.com/web/fundamentals/app-install-banners/). 354 | 355 | One **criteria** is that `display` must be either `fullscreen`, `standalone`, or `minimal-ui`. If you want to _prevent_ the mini-infobar from appearing in your App, you can set the `pwa.manifest.display` to `browser` in `nuxt.config.js`: 356 | 357 | ```js{}[nuxt.config.js] 358 | { 359 | pwa { 360 | manifest: { 361 | display: 'browser' 362 | } 363 | } 364 | } 365 | ``` 366 | 367 | ### Refresh to Update Notification 368 | 369 | In `layouts/default.vue` (or wherever you want, maybe in a plugin): 370 | 371 | ```js{}[layouts/default.vue] 372 | const workbox = await window.$workbox; 373 | if (workbox) { 374 | workbox.addEventListener('installed', (event) => { 375 | // If we don't do this we'll be displaying the notification after the initial installation, which isn't perferred. 376 | if (event.isUpdate) { 377 | // whatever logic you want to use to notify the user that they need to refresh the page. 378 | } 379 | }); 380 | } 381 | ``` 382 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. 4 | 5 | ### [3.3.5](https://github.com/nuxt-community/pwa-module/compare/v3.3.4...v3.3.5) (2021-01-26) 6 | 7 | 8 | ### Bug Fixes 9 | 10 | * **meta:** add missing `hid` to icon tags ([#428](https://github.com/nuxt-community/pwa-module/issues/428)) ([d9addb7](https://github.com/nuxt-community/pwa-module/commit/d9addb7917363e812fe277acc1cf228018a8342b)) 11 | 12 | ### [3.3.4](https://github.com/nuxt-community/pwa-module/compare/v3.3.3...v3.3.4) (2021-01-07) 13 | 14 | 15 | ### Bug Fixes 16 | 17 | * **types:** mark module options fields as optional ([#420](https://github.com/nuxt-community/pwa-module/issues/420)) ([7d75c28](https://github.com/nuxt-community/pwa-module/commit/7d75c285485efde4081127ff3bb899565a771c7e)) 18 | 19 | ### [3.3.3](https://github.com/nuxt-community/pwa-module/compare/v3.3.2...v3.3.3) (2020-12-20) 20 | 21 | 22 | ### Bug Fixes 23 | 24 | * **workbox:** add additional details for uncaught errors and fix chromium CORS ([#417](https://github.com/nuxt-community/pwa-module/issues/417)) ([f20489c](https://github.com/nuxt-community/pwa-module/commit/f20489c2cc289b9d6f90143078f415d97b3cf4c1)) 25 | * **workbox:** deepClone options to avoid cross-build mutation ([e39027e](https://github.com/nuxt-community/pwa-module/commit/e39027ee7159103d755fe67c1c105235f3257739)) 26 | 27 | ### [3.3.2](https://github.com/nuxt-community/pwa-module/compare/v3.3.1...v3.3.2) (2020-11-30) 28 | 29 | 30 | ### Bug Fixes 31 | 32 | * avoid adding revision to start_url ([1c44cff](https://github.com/nuxt-community/pwa-module/commit/1c44cffbe1ae7c9096c5696d6b6521f60b3fe32f)) 33 | 34 | ### [3.3.1](https://github.com/nuxt-community/pwa-module/compare/v3.3.0...v3.3.1) (2020-11-29) 35 | 36 | 37 | ### Bug Fixes 38 | 39 | * append to start_url without query param (fixes [#403](https://github.com/nuxt-community/pwa-module/issues/403)) ([054b8a2](https://github.com/nuxt-community/pwa-module/commit/054b8a299274fafc61275b50374b4eb1e83e7e46)) 40 | 41 | ## [3.3.0](https://github.com/nuxt-community/pwa-module/compare/v3.2.2...v3.3.0) (2020-11-28) 42 | 43 | 44 | ### Features 45 | 46 | * **manifest:** add revision to start_url ([ad26827](https://github.com/nuxt-community/pwa-module/commit/ad26827a9d76b6a4f1123f8a06fd0c946b90b5dd)) 47 | 48 | 49 | ### Bug Fixes 50 | 51 | * **manifest:** invalidate start_url cache ([240d4a1](https://github.com/nuxt-community/pwa-module/commit/240d4a14868fe46ab98bb79ba3a22c7973875d45)) 52 | * precached files are not updated ([#386](https://github.com/nuxt-community/pwa-module/issues/386)) ([872dce1](https://github.com/nuxt-community/pwa-module/commit/872dce1ec2df58cbf6efcfe4a080f632510ea32b)) 53 | 54 | ### [3.2.2](https://github.com/nuxt-community/pwa-module/compare/v3.2.1...v3.2.2) (2020-10-13) 55 | 56 | 57 | ### Bug Fixes 58 | 59 | * serve static webpack assets from disk in dev mode (fixes [#373](https://github.com/nuxt-community/pwa-module/issues/373)) ([8298f95](https://github.com/nuxt-community/pwa-module/commit/8298f955bf80eb44090cfb7b56070dc7e1a50aa8)) 60 | 61 | ### [3.2.1](https://github.com/nuxt-community/pwa-module/compare/v3.2.0...v3.2.1) (2020-10-13) 62 | 63 | 64 | ### Bug Fixes 65 | 66 | * **workbox:** precache `start_url` (resolves [#372](https://github.com/nuxt-community/pwa-module/issues/372)) ([27e19a0](https://github.com/nuxt-community/pwa-module/commit/27e19a04d6f2b14943a0bb4a9b7414382591d4e0)) 67 | 68 | ## [3.2.0](https://github.com/nuxt-community/pwa-module/compare/v3.1.2...v3.2.0) (2020-10-13) 69 | 70 | 71 | ### Bug Fixes 72 | 73 | * support build cache ([#371](https://github.com/nuxt-community/pwa-module/issues/371)) ([9a825c9](https://github.com/nuxt-community/pwa-module/commit/9a825c9d47c057c5934030142cb6e46d23a46e21)) 74 | * **meta:** fix `mergeMeta` cjs export ([774f1a8](https://github.com/nuxt-community/pwa-module/commit/774f1a87d8c102ad3754374e53a41b434a01b82c)) 75 | * **workbox:** restore `sw.js` with smart build (fixes [#352](https://github.com/nuxt-community/pwa-module/issues/352)) ([491f440](https://github.com/nuxt-community/pwa-module/commit/491f440936e107c424864a1aa1121e6995d4e87b)) 76 | 77 | ### [3.1.2](https://github.com/nuxt-community/pwa-module/compare/v3.1.1...v3.1.2) (2020-10-07) 78 | 79 | 80 | ### Bug Fixes 81 | 82 | * **meta:** avoid unnecessary log for meta.json ([de8e039](https://github.com/nuxt-community/pwa-module/commit/de8e039740a5618b59312682ecdea4f023d88414)) 83 | * **meta:** fix issues regarding favicon.ico fallback ([7a1e773](https://github.com/nuxt-community/pwa-module/commit/7a1e77384eb88f0886180bc784efa242ae59e5ad)) 84 | 85 | ### [3.1.1](https://github.com/nuxt-community/pwa-module/compare/v3.1.0...v3.1.1) (2020-10-07) 86 | 87 | 88 | ### Bug Fixes 89 | 90 | * **meta:** load meta when `ssr` is disable and using `nuxt dev` (fixes [#219](https://github.com/nuxt-community/pwa-module/issues/219)) ([b6a5ead](https://github.com/nuxt-community/pwa-module/commit/b6a5ead17cdb8f2edff9d12c326ae59d8ac372be)) 91 | * **workbox:** handle `offlinePage` options (fixes [#365](https://github.com/nuxt-community/pwa-module/issues/365)) ([2b9856e](https://github.com/nuxt-community/pwa-module/commit/2b9856e9c226c5f286acb5116cb381e2fc550248)) 92 | 93 | ## [3.1.0](https://github.com/nuxt-community/pwa-module/compare/v3.0.2...v3.1.0) (2020-10-06) 94 | 95 | 96 | ### Features 97 | 98 | * **meta:** merge head at runtime ([#363](https://github.com/nuxt-community/pwa-module/issues/363)) ([c0d86ea](https://github.com/nuxt-community/pwa-module/commit/c0d86ead374efcfd66282959e65055262e4a27cf)) 99 | 100 | 101 | ### Bug Fixes 102 | 103 | * **icon:** fork without original process args ([#343](https://github.com/nuxt-community/pwa-module/issues/343)) ([8b1f19f](https://github.com/nuxt-community/pwa-module/commit/8b1f19f56ddc31a49445334ddc8abe2162b4b760)) 104 | * **manifest:** do not use nuxt loading bar color as default `theme_color` ([#344](https://github.com/nuxt-community/pwa-module/issues/344)) ([a18a79f](https://github.com/nuxt-community/pwa-module/commit/a18a79f62a49a3a563621929e30fc8703c3c133a)) 105 | * **meta:** add missing `router.base` prefix to favicon ([#354](https://github.com/nuxt-community/pwa-module/issues/354)) ([3e910ae](https://github.com/nuxt-community/pwa-module/commit/3e910ae7e87d341c6a6ea018d013105ce1721b5b)) 106 | * **meta:** allow setting `appleStatusBarStyle` without `mobileAppIOS` ([b0f226a](https://github.com/nuxt-community/pwa-module/commit/b0f226aadeee50b47790ac064852b444e33d9b95)), closes [#338](https://github.com/nuxt-community/pwa-module/issues/338) 107 | * **meta:** prevent build failure for ios splash image when no icon is used ([#362](https://github.com/nuxt-community/pwa-module/issues/362)) ([494eed5](https://github.com/nuxt-community/pwa-module/commit/494eed5db00e7cf6863fc854e6ccb6b7bb8c0ba4)) 108 | * **workbox:** New configuration for specifying plugins when configuring a strategy ([#337](https://github.com/nuxt-community/pwa-module/issues/337)) ([dacf7ec](https://github.com/nuxt-community/pwa-module/commit/dacf7ec3613a6cb985990eab6c78879b78bdbbbc)), closes [/github.com/nuxt-community/pwa-module/pull/337#issuecomment-681870522](https://github.com/nuxt-community//github.com/nuxt-community/pwa-module/pull/337/issues/issuecomment-681870522) 109 | 110 | ### [3.0.2](https://github.com/nuxt-community/pwa-module/compare/v3.0.1...v3.0.2) (2020-08-26) 111 | 112 | 113 | ### Bug Fixes 114 | 115 | * **workbox:** missing required parameter request for `handle()` ([#335](https://github.com/nuxt-community/pwa-module/issues/335)) ([eedf23f](https://github.com/nuxt-community/pwa-module/commit/eedf23fa3ab478f8a449817528d0270507babfc8)) 116 | 117 | ### [3.0.1](https://github.com/nuxt-community/pwa-module/compare/v3.0.0...v3.0.1) (2020-08-17) 118 | 119 | 120 | ### Bug Fixes 121 | 122 | * **icon:** update warning url to docs ([#329](https://github.com/nuxt-community/pwa-module/issues/329)) ([61633fa](https://github.com/nuxt-community/pwa-module/commit/61633fa640793c344748efdf790a56456fad8e2f)) 123 | 124 | ## [3.0.0](https://github.com/nuxt-community/pwa-module/compare/v3.0.0-beta.20...v3.0.0) (2020-08-16) 125 | 126 | ### ⭐ What's new? 127 | 128 | - Using workbox 5 129 | - Support `purpose` option and defaulting to `any maskable` 130 | - Brand new docs powered by [nuxt/content](https://github.com/nuxt/content) 131 | 132 | ### 🚀 Features 133 | 134 | * Update to workbox `5.x` 135 | * Add types ([#323](https://github.com/nuxt-community/pwa-module/issues/323)) ([8723d07](https://github.com/nuxt-community/pwa-module/commit/8723d076cb87ff9e583ba755f72f4d62360d6eb1)) 136 | * **icon:** Support for icon purpose ([#246](https://github.com/nuxt-community/pwa-module/issues/246)) ([9248174](https://github.com/nuxt-community/pwa-module/commit/9248174fe8bac352318c8fe292012156ccfd56ad)) 137 | * **icon:** Default purpose to `any maskable` ([30f0f63](https://github.com/nuxt-community/pwa-module/commit/30f0f63bcd1601cc6aa5595a851de965dde9af88)) 138 | * **icon:** Expose `options.cacheDir` ([f8dbf1d](https://github.com/nuxt-community/pwa-module/commit/f8dbf1dac99519648a53dc22ab4019af25a677aa)) 139 | * **icon:** Use `favicon.ico` when available with warning ([#258](https://github.com/nuxt-community/pwa-module/issues/258)) ([7a48d2a](https://github.com/nuxt-community/pwa-module/commit/7a48d2a60b1f2ccaa1287789adb846806afd5224)) 140 | * **icon:** Rename `accessibleIcons` to `iconPlugin` ([3e175f9](https://github.com/nuxt-community/pwa-module/commit/3e175f93c046028b6f3f9479085ec98d014b460b)) 141 | * **icon** Rename `iconSrc`, `iconFileName`, `iconPlugin` and `iconProperty` to `source`, `fileName`, `plugin` and `pluginName` 142 | * **icon:** Support for iOS splash screens ([#308](https://github.com/nuxt-community/pwa-module/issues/308)) ([f4eeda7](https://github.com/nuxt-community/pwa-module/commit/f4eeda7ce05cdd7dda4e4c4ab81e986f6c94a951)) 143 | * **module:** Allow disabling sub-modules with top-level options ([65800f9](https://github.com/nuxt-community/pwa-module/commit/65800f91a671e61d59a9faf885c2ff7ecc9d9ca0)) 144 | * **workbox:** Support `enabled` option and self destroying sw ([c64226c](https://github.com/nuxt-community/pwa-module/commit/c64226cea36c1b0b9f0efe7640439e6bb134ddce)) 145 | * Support `manifest.fileName` with template ([f05353b](https://github.com/nuxt-community/pwa-module/commit/f05353b7ccfef88f5f95f0fa7b0109c2ece4236b)), closes [#193](https://github.com/nuxt-community/pwa-module/issues/193) 146 | * Use integraty file to invalidate icon cache ([6661a09](https://github.com/nuxt-community/pwa-module/commit/6661a09f86bbc169a99effac3d9cb1620f530b3d)) 147 | * **manifest:** Add `useWebmanifestExtension` option and improve docs ([#241](https://github.com/nuxt-community/pwa-module/issues/241)) ([4484e6c](https://github.com/nuxt-community/pwa-module/commit/4484e6c697c5534103969894252f1d356d4016ee)) 148 | 149 | 150 | ### 📝 Docs 151 | 152 | * Fix a typo on icon (#235) 153 | * Add tip for `pwa.manifest.display: 'browser'` (#249) 154 | * Fix typo in `icon.md` (#253) 155 | * Use `CacheFirst` instead of `cacheFirst` (#251) 156 | * Fix wrong position of a description (#270) 157 | * Add an example for refresh to update implementation (#271) 158 | * Document `workbox.swDest` (#285) 159 | * Add title to external links (#288) 160 | * Migrate to nuxt content (#313) 161 | 162 | 163 | ### 🐛 Bug Fixes 164 | 165 | * **icon:** Clean `cacheDir` when generating icons ([1e6eb19](https://github.com/nuxt-community/pwa-module/commit/1e6eb19851bbb6bcb51106cea5611475edec75cc)) 166 | 167 | ### ⚠ BREAKING CHANGES 168 | 169 | * Requeires Node 10.x 170 | * Updated to workbox 5.x (optional: [migration guide](https://developers.google.com/web/tools/workbox/guides/migrations/migrate-from-v4)) 171 | * Icon options renamed: `iconSrc`, `iconFileName`, `iconPlugin`, `iconProperty`, `accessibleIcons` (see docs) 172 | * Icon purpose is now `any maskable` by default which means you have to consider minimum safe-zone ([read more](https://web.dev/maskable-icon)) 173 | 174 | ### 💖 Contributors 175 | 176 | - @alperbicer 177 | - @danbeneventano 178 | - @danielroe 179 | - @daniel-tikken 180 | - @DCsunset 181 | - @debs-obrien 182 | - @dvarnai 183 | - @gangsthub 184 | - @Gomah 185 | - @hans00 186 | - @Hxmic 187 | - @jefrydco 188 | - @jeremy21212121 189 | - @jsulpis 190 | - @ricardogobbosouza 191 | - @s-pace 192 | - @svale 193 | - @Timibadass 194 | - @Wisdom132 195 | - @zachjharris 196 | 197 | ## [3.0.0-beta.20](https://github.com/nuxt-community/pwa-module/compare/v3.0.0-beta.19...v3.0.0-beta.20) (2020-02-02) 198 | 199 | ## [3.0.0-beta.19](https://github.com/nuxt-community/pwa-module/compare/v3.0.0-beta.18...v3.0.0-beta.19) (2019-09-11) 200 | 201 | 202 | ### Bug Fixes 203 | 204 | * expose modified pwa context to the config ([c325e44](https://github.com/nuxt-community/pwa-module/commit/c325e44)) 205 | * truncate manifest hash ([5c74621](https://github.com/nuxt-community/pwa-module/commit/5c74621)) 206 | 207 | ## [3.0.0-beta.18](https://github.com/nuxt-community/pwa-module/compare/v3.0.0-beta.17...v3.0.0-beta.18) (2019-09-09) 208 | 209 | 210 | ### Bug Fixes 211 | 212 | * revert compileTemplate as is fixed by nuxt/nuxt.js[#6283](https://github.com/nuxt-community/pwa-module/issues/6283) for 2.9.x ([d0f96de](https://github.com/nuxt-community/pwa-module/commit/d0f96de)) 213 | * use shared pwa context ([3c19bae](https://github.com/nuxt-community/pwa-module/commit/3c19bae)) 214 | 215 | ## [3.0.0-beta.17](https://github.com/nuxt-community/pwa-module/compare/v3.0.0-beta.16...v3.0.0-beta.17) (2019-09-05) 216 | 217 | 218 | ### Features 219 | 220 | * `pwa.` scopped options ([010fe0e](https://github.com/nuxt-community/pwa-module/commit/010fe0e)) 221 | * use `jimp-compact` ([5e37b58](https://github.com/nuxt-community/pwa-module/commit/5e37b58)) 222 | 223 | # [3.0.0-beta.16](https://github.com/nuxt-community/pwa-module/compare/v3.0.0-beta.15...v3.0.0-beta.16) (2019-05-07) 224 | 225 | 226 | ### Bug Fixes 227 | 228 | * **icon:** handle situation where the iconSrc is `null` or `undefined` ([#187](https://github.com/nuxt-community/pwa-module/issues/187)) ([66be874](https://github.com/nuxt-community/pwa-module/commit/66be874)) 229 | 230 | 231 | 232 | 233 | 234 | # [3.0.0-beta.15](https://github.com/nuxt-community/pwa-module/compare/v3.0.0-beta.14...v3.0.0-beta.15) (2019-05-07) 235 | 236 | 237 | ### Bug Fixes 238 | 239 | * **workbox:** disable `cacheAssets` for dev mode ([dbf6d67](https://github.com/nuxt-community/pwa-module/commit/dbf6d67)) 240 | * **workbox:** use `NetworkFirst `for dev ([9a67580](https://github.com/nuxt-community/pwa-module/commit/9a67580)) 241 | 242 | 243 | ### Features 244 | 245 | * **workbox:** support `offlineStrategy` ([e377436](https://github.com/nuxt-community/pwa-module/commit/e377436)) 246 | * rewrite icon with async image resizer ([#171](https://github.com/nuxt-community/pwa-module/issues/171)) 247 | 248 | 249 | ### Reverts 250 | 251 | * revert unnecessary HMR regex ([1ac5f5c](https://github.com/nuxt-community/pwa-module/commit/1ac5f5c)) 252 | 253 | 254 | ### BREAKING CHANGES 255 | 256 | * **workbox:** default `offlineStrategy` changed from `NetworkOnly` to `NetworkFirst` when `offlinePage` is enabled 257 | 258 | 259 | 260 | 261 | 262 | # [3.0.0-beta.14](https://github.com/nuxt-community/pwa-module/compare/v3.0.0-beta.13...v3.0.0-beta.14) (2019-03-17) 263 | 264 | 265 | ### Bug Fixes 266 | 267 | * **onesignal:** ensure no duplicate script is added ([#161](https://github.com/nuxt-community/pwa-module/issues/161)) ([89c1a1d](https://github.com/nuxt-community/pwa-module/commit/89c1a1d)) 268 | 269 | 270 | ### Features 271 | 272 | * **workbox:** make plugin fully asynchronous ([1eb1190](https://github.com/nuxt-community/pwa-module/commit/1eb1190)) 273 | * improve computed cacheId ([cd6c9cc](https://github.com/nuxt-community/pwa-module/commit/cd6c9cc)) 274 | * improve sw.register error handling ([9aa76f8](https://github.com/nuxt-community/pwa-module/commit/9aa76f8)) 275 | 276 | 277 | 278 | 279 | 280 | # [3.0.0-beta.13](https://github.com/nuxt-community/pwa-module/compare/v3.0.0-beta.12...v3.0.0-beta.13) (2019-03-17) 281 | 282 | 283 | ### Features 284 | 285 | * **workbox:** improve sw.register ([c35f610](https://github.com/nuxt-community/pwa-module/commit/c35f610)) 286 | * sync workbox version with workbox-window ([9a3632a](https://github.com/nuxt-community/pwa-module/commit/9a3632a)) 287 | 288 | 289 | 290 | 291 | 292 | # [3.0.0-beta.12](https://github.com/nuxt-community/pwa-module/compare/v3.0.0-beta.11...v3.0.0-beta.12) (2019-03-05) 293 | 294 | 295 | ### Bug Fixes 296 | 297 | * **pwa-utils:** don't combine with esm ([fddfa7a](https://github.com/nuxt-community/pwa-module/commit/fddfa7a)), closes [#147](https://github.com/nuxt-community/pwa-module/issues/147) 298 | 299 | 300 | 301 | 302 | 303 | # [3.0.0-beta.11](https://github.com/nuxt-community/pwa-module/compare/v3.0.0-beta.10...v3.0.0-beta.11) (2019-03-05) 304 | 305 | 306 | ### Bug Fixes 307 | 308 | * **workbox:** always prepend routerBase to swURL ([d3a52b6](https://github.com/nuxt-community/pwa-module/commit/d3a52b6)), closes [#157](https://github.com/nuxt-community/pwa-module/issues/157) 309 | 310 | 311 | ### Features 312 | 313 | * **workbox:** allow cache names to be configured ([#154](https://github.com/nuxt-community/pwa-module/issues/154)) ([2d7ed53](https://github.com/nuxt-community/pwa-module/commit/2d7ed53)) 314 | * **workbox:** workbox-window support ([2e356d0](https://github.com/nuxt-community/pwa-module/commit/2e356d0)) 315 | 316 | 317 | 318 | 319 | 320 | # [3.0.0-beta.10](https://github.com/nuxt-community/pwa-module/compare/v3.0.0-beta.9...v3.0.0-beta.10) (2019-02-27) 321 | 322 | 323 | ### Features 324 | 325 | * **workbox:** use workbox 4.0.0-0 ([70813ef](https://github.com/nuxt-community/pwa-module/commit/70813ef)) 326 | 327 | 328 | 329 | 330 | 331 | # [3.0.0-beta.9](https://github.com/nuxt-community/pwa-module/compare/v3.0.0-beta.8...v3.0.0-beta.9) (2019-02-27) 332 | 333 | 334 | ### Bug Fixes 335 | 336 | * **pwa-utils:** handle non-strings in `startCase` ([#150](https://github.com/nuxt-community/pwa-module/issues/150)) ([782217a](https://github.com/nuxt-community/pwa-module/commit/782217a)) 337 | 338 | 339 | 340 | 341 | 342 | # [3.0.0-beta.8](https://github.com/nuxt-community/pwa-module/compare/v3.0.0-beta.7...v3.0.0-beta.8) (2019-02-18) 343 | 344 | 345 | ### Bug Fixes 346 | 347 | * **manifest:** remove publicPath field ([b03dc14](https://github.com/nuxt-community/pwa-module/commit/b03dc14)) 348 | 349 | 350 | 351 | 352 | 353 | # [3.0.0-beta.7](https://github.com/nuxt-community/pwa-module/compare/v3.0.0-beta.6...v3.0.0-beta.7) (2019-02-17) 354 | 355 | 356 | ### Bug Fixes 357 | 358 | * **module:** handle readJSFiles for string param ([#143](https://github.com/nuxt-community/pwa-module/issues/143)) ([4f06479](https://github.com/nuxt-community/pwa-module/commit/4f06479)) 359 | 360 | 361 | ### Features 362 | 363 | * **workbox:** bump to 4.0.0-rc.2 ([7e278f0](https://github.com/nuxt-community/pwa-module/commit/7e278f0)) 364 | 365 | 366 | 367 | 368 | 369 | # [3.0.0-beta.6](https://github.com/nuxt-community/pwa-module/compare/v3.0.0-beta.5...v3.0.0-beta.6) (2019-02-08) 370 | 371 | 372 | ### Bug Fixes 373 | 374 | * relax pages regex for workbox 4 compatiblity ([04e74a7](https://github.com/nuxt-community/pwa-module/commit/04e74a7)) 375 | 376 | 377 | ### Features 378 | 379 | * cleanupOutdatedCaches ([9167013](https://github.com/nuxt-community/pwa-module/commit/9167013)) 380 | * **workbox:** assetsURLPattern, pagesURLPattern ([5fc3d66](https://github.com/nuxt-community/pwa-module/commit/5fc3d66)) 381 | * **workbox:** preCaching option ([67f1c3d](https://github.com/nuxt-community/pwa-module/commit/67f1c3d)) 382 | * **workbox:** upgrade workboxVersion to 4.0.0-rc.0 ([b364572](https://github.com/nuxt-community/pwa-module/commit/b364572)) 383 | 384 | 385 | 386 | 387 | 388 | # [3.0.0-beta.5](https://github.com/nuxt-community/pwa-module/compare/v3.0.0-beta.3...v3.0.0-beta.5) (2019-02-08) 389 | 390 | 391 | ### Bug Fixes 392 | 393 | * add workboxExtensions to defaults ([#138](https://github.com/nuxt-community/pwa-module/issues/138)) ([ac8ba74](https://github.com/nuxt-community/pwa-module/commit/ac8ba74)) 394 | 395 | 396 | 397 | 398 | 399 | # [3.0.0-beta.3](https://github.com/nuxt-community/pwa-module/compare/v3.0.0-beta.2...v3.0.0-beta.3) (2019-02-07) 400 | 401 | 402 | ### Bug Fixes 403 | 404 | * **onesignal:** add cache query to sw.js ([33f8f61](https://github.com/nuxt-community/pwa-module/commit/33f8f61)) 405 | * **pwa-utils:** ensure joinUrl not modifying scheme part ([09a465a](https://github.com/nuxt-community/pwa-module/commit/09a465a)) 406 | 407 | 408 | ### Features 409 | 410 | * options.dev ([fb0d38c](https://github.com/nuxt-community/pwa-module/commit/fb0d38c)) 411 | 412 | 413 | 414 | 415 | 416 | # [3.0.0-beta.2](https://github.com/nuxt-community/pwa-module/compare/v3.0.0-beta.1...v3.0.0-beta.2) (2019-02-07) 417 | 418 | 419 | ### Features 420 | 421 | * offlineAnalytics ([#55](https://github.com/nuxt-community/pwa-module/issues/55)) ([4c4d3ff](https://github.com/nuxt-community/pwa-module/commit/4c4d3ff)) 422 | * workboxExtensions and extension reading fixes ([5c56484](https://github.com/nuxt-community/pwa-module/commit/5c56484)) 423 | 424 | 425 | 426 | 427 | 428 | # [3.0.0-beta.1](https://github.com/nuxt-community/pwa-module/compare/v3.0.0-beta.0...v3.0.0-beta.1) (2019-02-07) 429 | 430 | 431 | ### Features 432 | 433 | * **icon:** allow reading icon from assetc/icon.png ([#29](https://github.com/nuxt-community/pwa-module/issues/29)) ([9e0fde3](https://github.com/nuxt-community/pwa-module/commit/9e0fde3)) 434 | * add HMR test suit ([ff3d502](https://github.com/nuxt-community/pwa-module/commit/ff3d502)) 435 | * use better regexes ([318228e](https://github.com/nuxt-community/pwa-module/commit/318228e)) 436 | 437 | 438 | 439 | 440 | 441 | # [3.0.0-beta.0](https://github.com/nuxt-community/pwa-module/compare/v2.6.0...v3.0.0-beta.0) (2019-02-04) 442 | 443 | 444 | ### Bug Fixes 445 | 446 | * Handle `ogImage` as url ([#121](https://github.com/nuxt-community/pwa-module/issues/121)) ([d6dc82b](https://github.com/nuxt-community/pwa-module/commit/d6dc82b)) 447 | * Routing order for default offline route `/.*` must be last ([#100](https://github.com/nuxt-community/pwa-module/issues/100)) ([1c829d0](https://github.com/nuxt-community/pwa-module/commit/1c829d0)) 448 | 449 | 450 | ### Code Refactoring 451 | 452 | * Use tapable hooks ([#103](https://github.com/nuxt-community/pwa-module/issues/103)) ([9f27d5c](https://github.com/nuxt-community/pwa-module/commit/9f27d5c)) 453 | * Remove debug ([92ba73e](https://github.com/nuxt-community/pwa-module/commit/92ba73e)) 454 | 455 | ### Features 456 | 457 | * **onesignal:** Use CDN by default ([7c78c67](https://github.com/nuxt-community/pwa-module/commit/7c78c67)) 458 | * **workbox:** Rewrite workbox ([#122](https://github.com/nuxt-community/pwa-module/issues/122)) ([9e49896](https://github.com/nuxt-community/pwa-module/commit/9e49896)) 459 | * **icon:** new options ([#126](https://github.com/nuxt-community/pwa-module/issues/126)) ([12e6576](https://github.com/nuxt-community/pwa-module/commit/12e6576)) 460 | * **workbox:** change the order of default `runtimeCache` ([#106](https://github.com/nuxt-community/pwa-module/issues/106)) ([033b504](https://github.com/nuxt-community/pwa-module/commit/033b504)) 461 | 462 | 463 | ### BREAKING CHANGES 464 | 465 | * Only nuxt 2+ supported ([854d826](https://github.com/nuxt-community/pwa-module/commit/854d826)) 466 | * webpack >= 4 is required 467 | 468 | 469 | 470 | # [2.6.0](https://github.com/nuxt-community/pwa-module/compare/v2.5.0...v2.6.0) (2018-09-21) 471 | 472 | 473 | ### Bug Fixes 474 | 475 | * **workbox:** add missing lodash dependency ([#91](https://github.com/nuxt-community/pwa-module/issues/91)) ([da2c36f](https://github.com/nuxt-community/pwa-module/commit/da2c36f)) 476 | 477 | 478 | ### Features 479 | 480 | * **icon:** update to jimp 0.5.0 ([b071c4b](https://github.com/nuxt-community/pwa-module/commit/b071c4b)) 481 | * **workbox:** support pass config object to `workbox.setConfig` ([#95](https://github.com/nuxt-community/pwa-module/issues/95)) ([b5dab8a](https://github.com/nuxt-community/pwa-module/commit/b5dab8a)) 482 | 483 | 484 | 485 | 486 | 487 | 488 | # [2.5.0](https://github.com/nuxt-community/pwa-module/compare/v2.4.0...v2.5.0) (2018-09-02) 489 | 490 | 491 | ### Features 492 | 493 | * **icon:** make icons accessible ([#51](https://github.com/nuxt-community/pwa-module/issues/51)) ([92bccd3](https://github.com/nuxt-community/pwa-module/commit/92bccd3)) 494 | 495 | 496 | 497 | 498 | 499 | 500 | # [2.4.0](https://github.com/nuxt-community/pwa-module/compare/v2.3.2...v2.4.0) (2018-08-28) 501 | 502 | 503 | ### Bug Fixes 504 | 505 | * **icon:** temporary use jimp@0.3.4 ([#84](https://github.com/nuxt-community/pwa-module/issues/84)) ([3f0e718](https://github.com/nuxt-community/pwa-module/commit/3f0e718)) 506 | * **workbox:** infer default value of globDirectory from webpack config. fixes [#83](https://github.com/nuxt-community/pwa-module/issues/83). ([c7102fd](https://github.com/nuxt-community/pwa-module/commit/c7102fd)) 507 | * **workbox:** more fixes regarding nuxt 2 dist directory changes. fixes [#83](https://github.com/nuxt-community/pwa-module/issues/83). ([7a8bb3b](https://github.com/nuxt-community/pwa-module/commit/7a8bb3b)) 508 | 509 | 510 | ### Features 511 | 512 | * **worbox:** offlineAssets ([#86](https://github.com/nuxt-community/pwa-module/issues/86)) ([27c8fa1](https://github.com/nuxt-community/pwa-module/commit/27c8fa1)) 513 | * **workbox:** offline page assets ([#85](https://github.com/nuxt-community/pwa-module/issues/85)) ([8bc4a3b](https://github.com/nuxt-community/pwa-module/commit/8bc4a3b)) 514 | 515 | 516 | 517 | 518 | 519 | 520 | # 2.3.2 (2018-08-24) 521 | 522 | ### Bug Fixes 523 | 524 | * **workbox:** `staleWhileRevalidate()` -> `networkOnly()` for offline pages ([832d60f](https://github.com/nuxt-community/pwa-module/commit/832d60f)) 525 | 526 | 527 | 528 | # 2.3.1 (2018-08-24) 529 | 530 | ### Bug Fixes 531 | 532 | * **workbox:** `offlinePage` syntax error ([af21d74](https://github.com/nuxt-community/pwa-module/commit/af21d74)) 533 | 534 | 535 | # 2.3.0 (2018-08-24) 536 | 537 | ### Bug Fixes 538 | 539 | * **docs:** add reference to pwa module ([49b7c49](https://github.com/nuxt-community/pwa/commit/49b7c49)) 540 | * **icon:** await on build ([e3c1be2](https://github.com/nuxt-community/pwa/commit/e3c1be2)) 541 | * **icon:** generate only on build ([9d68d70](https://github.com/nuxt-community/pwa/commit/9d68d70)) 542 | * **manifest:** run only on build ([ecaa835](https://github.com/nuxt-community/pwa/commit/ecaa835)) 543 | * **meta:** add unique identifiers to meta fields ([#23](https://github.com/nuxt-community/pwa/issues/23)) ([76a1f89](https://github.com/nuxt-community/pwa/commit/76a1f89)) 544 | * **meta:** generate only on build ([1cace26](https://github.com/nuxt-community/pwa/commit/1cace26)) 545 | * **meta:** only set og:url when it has been defined through ogHost or options ([#44](https://github.com/nuxt-community/pwa/issues/44)) ([354f818](https://github.com/nuxt-community/pwa/commit/354f818)) 546 | * **meta:** remove minimal-ui from default viewport ([cf48b3f](https://github.com/nuxt-community/pwa/commit/cf48b3f)), closes [#10](https://github.com/nuxt-community/pwa/issues/10) 547 | * **pwa:** no more optimize dependency ([a1c149f](https://github.com/nuxt-community/pwa/commit/a1c149f)) 548 | * **workbox:** faster service worker register ([07524a2](https://github.com/nuxt-community/pwa/commit/07524a2)) 549 | * **workbox:** hardcoded `static` dir ([#73](https://github.com/nuxt-community/pwa/issues/73)) ([6d241ec](https://github.com/nuxt-community/pwa/commit/6d241ec)) 550 | * **workbox:** make cacheId independent of npm package version ([b744a27](https://github.com/nuxt-community/pwa/commit/b744a27)) 551 | * **workbox:** use regexp for runtimeCaching. fixes [#14](https://github.com/nuxt-community/pwa/issues/14). ([f384103](https://github.com/nuxt-community/pwa/commit/f384103)) 552 | * don't override title when titleTemplate is provided ([#48](https://github.com/nuxt-community/pwa/issues/48)) ([8c3f319](https://github.com/nuxt-community/pwa/commit/8c3f319)) 553 | * workaround to fill meta with SPA and nuxt start ([a0fb908](https://github.com/nuxt-community/pwa/commit/a0fb908)) 554 | 555 | 556 | ### Features 557 | 558 | * Add compatibility for nuxt 1.0.0 hooks ([c0efb1d](https://github.com/nuxt-community/pwa/commit/c0efb1d)) 559 | * add og:image support ([#30](https://github.com/nuxt-community/pwa/issues/30)) ([afebd96](https://github.com/nuxt-community/pwa/commit/afebd96)) 560 | * add oneSignal module ([bbc7b72](https://github.com/nuxt-community/pwa/commit/bbc7b72)) 561 | * **manifest:** allow overriding publicPath ([#19](https://github.com/nuxt-community/pwa/issues/19)) ([4e6782e](https://github.com/nuxt-community/pwa/commit/4e6782e)) 562 | * add option to register third-party sw ([#12](https://github.com/nuxt-community/pwa/issues/12)) ([9c0b61e](https://github.com/nuxt-community/pwa/commit/9c0b61e)) 563 | * **icon:** add combined option sources ([539430f](https://github.com/nuxt-community/pwa/commit/539430f)) 564 | * **manifest:** support crossorigin option ([#71](https://github.com/nuxt-community/pwa/issues/71)) ([ccb2c33](https://github.com/nuxt-community/pwa/commit/ccb2c33)) 565 | * **meta:** add author property ([#41](https://github.com/nuxt-community/pwa/issues/41)) ([cafcfc4](https://github.com/nuxt-community/pwa/commit/cafcfc4)) 566 | * **meta:** add nativeUI option ([3c7aa7d](https://github.com/nuxt-community/pwa/commit/3c7aa7d)), closes [#10](https://github.com/nuxt-community/pwa/issues/10) 567 | * **meta:** add ogUrl url property ([#42](https://github.com/nuxt-community/pwa/issues/42)) ([3990ddf](https://github.com/nuxt-community/pwa/commit/3990ddf)) 568 | * **meta:** add property attribiture for og tags ([dc39fcb](https://github.com/nuxt-community/pwa/commit/dc39fcb)) 569 | * **meta:** add twitter card, site and creator properties ([#43](https://github.com/nuxt-community/pwa/issues/43)) ([fe11c76](https://github.com/nuxt-community/pwa/commit/fe11c76)) 570 | * **onesignal:** move init options under init ([dd61c18](https://github.com/nuxt-community/pwa/commit/dd61c18)) 571 | * **runtimeCaching:** Support runtimeCaching ([fdcda0f](https://github.com/nuxt-community/pwa/commit/fdcda0f)) 572 | * **worbox:** add offline option for making it optional ([#59](https://github.com/nuxt-community/pwa/issues/59)) ([76de33c](https://github.com/nuxt-community/pwa/commit/76de33c)), closes [#24](https://github.com/nuxt-community/pwa/issues/24) 573 | * **workbox:** add options.autoRegister ([f1e1fe1](https://github.com/nuxt-community/pwa/commit/f1e1fe1)) 574 | * **workbox:** disable caching for sw.js by default ([e7677d8](https://github.com/nuxt-community/pwa/commit/e7677d8)) 575 | * **workbox:** expose registration as window.$sw ([a5ddf59](https://github.com/nuxt-community/pwa/commit/a5ddf59)) 576 | * **workbox:** importScripts option ([7c8644c](https://github.com/nuxt-community/pwa/commit/7c8644c)) 577 | * **workbox:** option to enable `skipWaiting` ([#80](https://github.com/nuxt-community/pwa/issues/80)) ([88cc602](https://github.com/nuxt-community/pwa/commit/88cc602)) 578 | * **workbox:** rewrite with better template support ([b0af84e](https://github.com/nuxt-community/pwa/commit/b0af84e)) 579 | * **workbox:** workbox 3 + offlinePage ([#60](https://github.com/nuxt-community/pwa/issues/60)) ([0fef874](https://github.com/nuxt-community/pwa/commit/0fef874)) 580 | * **workbox, onegisnal:** Use defaultsDeep for options ([5ac89cf](https://github.com/nuxt-community/pwa/commit/5ac89cf)) 581 | * Add support of StrategyOptions to cache ([b17bbd0](https://github.com/nuxt-community/pwa/commit/b17bbd0)) 582 | * ogSiteName ([#50](https://github.com/nuxt-community/pwa/issues/50)) ([0c99ab9](https://github.com/nuxt-community/pwa/commit/0c99ab9)) 583 | 584 | # Older changelogs 585 | 586 | ## Icon 587 | 588 | 589 | # [2.5.0](https://github.com/nuxt-community/pwa-module/compare/v2.4.0...v2.5.0) (2018-09-02) 590 | 591 | 592 | ### Features 593 | 594 | * **icon:** make icons accessible ([#51](https://github.com/nuxt-community/pwa-module/issues/51)) ([92bccd3](https://github.com/nuxt-community/pwa-module/commit/92bccd3)) 595 | 596 | 597 | 598 | 599 | 600 | 601 | # [2.4.0](https://github.com/nuxt-community/pwa-module/compare/v2.3.2...v2.4.0) (2018-08-28) 602 | 603 | 604 | ### Bug Fixes 605 | 606 | * **icon:** temporary use jimp@0.3.4 ([#84](https://github.com/nuxt-community/pwa-module/issues/84)) ([3f0e718](https://github.com/nuxt-community/pwa-module/commit/3f0e718)) 607 | 608 | 609 | 610 | 611 | 612 | 613 | # 2.3.0 (2018-08-24) 614 | 615 | 616 | ### Bug Fixes 617 | 618 | * **icon:** await on build ([e3c1be2](https://github.com/nuxt-community/pwa-module/commit/e3c1be2)) 619 | * **icon:** generate only on build ([9d68d70](https://github.com/nuxt-community/pwa-module/commit/9d68d70)) 620 | * workaround to fill meta with SPA and nuxt start ([a0fb908](https://github.com/nuxt-community/pwa-module/commit/a0fb908)) 621 | 622 | 623 | ### Features 624 | 625 | * Add compatibility for nuxt 1.0.0 hooks ([c0efb1d](https://github.com/nuxt-community/pwa-module/commit/c0efb1d)) 626 | * **icon:** add combined option sources ([539430f](https://github.com/nuxt-community/pwa-module/commit/539430f)) 627 | 628 | 629 | 630 | 631 | 632 | 633 | # [2.1.0](https://github.com/nuxt-community/pwa-module/compare/@nuxtjs/icon@2.0.2...@nuxtjs/icon@2.1.0) (2018-03-05) 634 | 635 | 636 | ### Features 637 | 638 | * **icon:** add combined option sources ([539430f](https://github.com/nuxt-community/pwa-module/commit/539430f)) 639 | 640 | 641 | 642 | 643 | 644 | 645 | ## [2.0.2](https://github.com/nuxt-community/pwa-module/compare/@nuxtjs/icon@2.0.1...@nuxtjs/icon@2.0.2) (2017-12-29) 646 | 647 | 648 | 649 | 650 | **Note:** Version bump only for package @nuxtjs/icon 651 | 652 | 653 | ## [2.0.1](https://github.com/nuxt-community/pwa-module/compare/@nuxtjs/icon@2.0.0...@nuxtjs/icon@2.0.1) (2017-11-17) 654 | 655 | 656 | ### Bug Fixes 657 | 658 | * workaround to fill meta with SPA and nuxt start ([a0fb908](https://github.com/nuxt-community/pwa-module/commit/a0fb908)) 659 | 660 | 661 | 662 | 663 | 664 | # [2.0.0](https://github.com/nuxt-community/pwa-module/compare/@nuxtjs/icon@1.1.2...@nuxtjs/icon@2.0.0) (2017-11-16) 665 | 666 | 667 | ### Bug Fixes 668 | 669 | * **icon:** await on build ([e3c1be2](https://github.com/nuxt-community/pwa-module/commit/e3c1be2)) 670 | * **icon:** generate only on build ([9d68d70](https://github.com/nuxt-community/pwa-module/commit/9d68d70)) 671 | 672 | 673 | ### Features 674 | 675 | * Add compatibility for nuxt 1.0.0 hooks ([c0efb1d](https://github.com/nuxt-community/pwa-module/commit/c0efb1d)) 676 | 677 | 678 | 679 | 680 | 681 | ## 1.1.2 (2017-10-04) 682 | 683 | 684 | 685 | 686 | **Note:** Version bump only for package @nuxtjs/icon 687 | 688 | 689 | ## 1.1.1 (2017-10-04) 690 | 691 | 692 | 693 | 694 | **Note:** Version bump only for package @nuxtjs/icon 695 | 696 | 697 | # [1.1.0](https://github.com/nuxt/modules/compare/@nuxtjs/icon@1.0.1...@nuxtjs/icon@1.1.0) (2017-09-21) 698 | 699 | 700 | ### Features 701 | 702 | * **icon:** set minimum size to 64 ([5bd9460](https://github.com/nuxt/modules/commit/5bd9460)) 703 | 704 | 705 | 706 | 707 | 708 | ## [1.0.1](https://github.com/nuxt/modules/compare/@nuxtjs/icon@1.0.0...@nuxtjs/icon@1.0.1) (2017-08-02) 709 | 710 | 711 | 712 | 713 | 714 | # 0.1.0 (2017-06-06) 715 | 716 | 717 | ### Bug Fixes 718 | 719 | * **icon:** fix iconSrc type ([9aaaba7](https://github.com/nuxt/modules/commit/9aaaba7)) 720 | 721 | 722 | ### Features 723 | 724 | * 🖼️ icon module ([6201d2a](https://github.com/nuxt/modules/commit/6201d2a)) 725 | 726 | ## Manifest 727 | 728 | 729 | # [2.4.0](https://github.com/nuxt-community/pwa-module/compare/v2.3.2...v2.4.0) (2018-08-28) 730 | 731 | **Note:** Version bump only for package @nuxtjs/manifest 732 | 733 | 734 | 735 | 736 | 737 | 738 | # 2.3.0 (2018-08-24) 739 | 740 | 741 | ### Bug Fixes 742 | 743 | * **docs:** add reference to pwa module ([49b7c49](https://github.com/nuxt-community/pwa-module/commit/49b7c49)) 744 | * **manifest:** run only on build ([ecaa835](https://github.com/nuxt-community/pwa-module/commit/ecaa835)) 745 | * workaround to fill meta with SPA and nuxt start ([a0fb908](https://github.com/nuxt-community/pwa-module/commit/a0fb908)) 746 | 747 | 748 | ### Features 749 | 750 | * Add compatibility for nuxt 1.0.0 hooks ([c0efb1d](https://github.com/nuxt-community/pwa-module/commit/c0efb1d)) 751 | * **manifest:** allow overriding publicPath ([#19](https://github.com/nuxt-community/pwa-module/issues/19)) ([4e6782e](https://github.com/nuxt-community/pwa-module/commit/4e6782e)) 752 | * **manifest:** support crossorigin option ([#71](https://github.com/nuxt-community/pwa-module/issues/71)) ([ccb2c33](https://github.com/nuxt-community/pwa-module/commit/ccb2c33)) 753 | 754 | 755 | 756 | 757 | 758 | 759 | # [2.1.0](https://github.com/nuxt-community/pwa-module/compare/@nuxtjs/manifest@2.0.1...@nuxtjs/manifest@2.1.0) (2017-12-07) 760 | 761 | 762 | ### Features 763 | 764 | * **manifest:** allow overriding publicPath ([#19](https://github.com/nuxt-community/pwa-module/issues/19)) ([4e6782e](https://github.com/nuxt-community/pwa-module/commit/4e6782e)) 765 | 766 | 767 | 768 | 769 | 770 | ## [2.0.1](https://github.com/nuxt-community/pwa-module/compare/@nuxtjs/manifest@2.0.0...@nuxtjs/manifest@2.0.1) (2017-11-17) 771 | 772 | 773 | ### Bug Fixes 774 | 775 | * workaround to fill meta with SPA and nuxt start ([a0fb908](https://github.com/nuxt-community/pwa-module/commit/a0fb908)) 776 | 777 | 778 | 779 | 780 | 781 | # [2.0.0](https://github.com/nuxt-community/pwa-module/compare/@nuxtjs/manifest@1.7.2...@nuxtjs/manifest@2.0.0) (2017-11-16) 782 | 783 | 784 | ### Bug Fixes 785 | 786 | * **manifest:** run only on build ([ecaa835](https://github.com/nuxt-community/pwa-module/commit/ecaa835)) 787 | 788 | 789 | ### Features 790 | 791 | * Add compatibility for nuxt 1.0.0 hooks ([c0efb1d](https://github.com/nuxt-community/pwa-module/commit/c0efb1d)) 792 | 793 | 794 | 795 | 796 | 797 | ## 1.7.2 (2017-10-04) 798 | 799 | 800 | ### Bug Fixes 801 | 802 | * **docs:** add reference to pwa module ([49b7c49](https://github.com/nuxt-community/pwa/commit/49b7c49)) 803 | 804 | 805 | 806 | 807 | 808 | ## 1.7.1 (2017-10-04) 809 | 810 | 811 | 812 | 813 | **Note:** Version bump only for package @nuxtjs/manifest 814 | 815 | 816 | # [1.7.0](https://github.com/nuxt/modules/compare/@nuxtjs/manifest@1.6.1...@nuxtjs/manifest@1.7.0) (2017-09-22) 817 | 818 | 819 | ### Features 820 | 821 | * **manifest:** add standalone to start_url ([81dbe9c](https://github.com/nuxt/modules/commit/81dbe9c)) 822 | 823 | 824 | 825 | 826 | 827 | # [1.6.0](https://github.com/nuxt/modules/compare/@nuxtjs/manifest@1.5.0...@nuxtjs/manifest@1.6.0) (2017-06-06) 828 | 829 | 830 | ### Bug Fixes 831 | 832 | * **manifest:** correctly omit internal options ([47559b0](https://github.com/nuxt/modules/commit/47559b0)) 833 | 834 | 835 | ### Features 836 | 837 | * **manifest:** meta module compatibility ([8a41fda](https://github.com/nuxt/modules/commit/8a41fda)) 838 | * **manifest:** refactor & openGraph support ([0768246](https://github.com/nuxt/modules/commit/0768246)) 839 | * **manifest:** rewrite module ([352b4bf](https://github.com/nuxt/modules/commit/352b4bf)) 840 | 841 | 842 | 843 | 844 | 845 | # [1.5.0](https://github.com/nuxt/modules/compare/@nuxtjs/manifest@1.4.2...@nuxtjs/manifest@1.5.0) (2017-06-05) 846 | 847 | 848 | ### Features 849 | 850 | * **manifest:** defaultIcon option ([1086962](https://github.com/nuxt/modules/commit/1086962)) 851 | 852 | 853 | 854 | 855 | 856 | ## [1.4.2](https://github.com/nuxt/modules/compare/@nuxtjs/manifest@1.4.1...@nuxtjs/manifest@1.4.2) (2017-06-04) 857 | 858 | 859 | ### Bug Fixes 860 | 861 | * prevent invalid url when router base is / ([f0fd863](https://github.com/nuxt/modules/commit/f0fd863)) 862 | 863 | 864 | 865 | 866 | 867 | ## [1.4.1](https://github.com/nuxt/modules/compare/@nuxtjs/manifest@1.4.0...@nuxtjs/manifest@1.4.1) (2017-06-04) 868 | 869 | 870 | ### Bug Fixes 871 | 872 | * **manifest:** sanetize options ([b8497a0](https://github.com/nuxt/modules/commit/b8497a0)) 873 | * **manifest:** typo in manifest.json filename ([c2cabb6](https://github.com/nuxt/modules/commit/c2cabb6)) 874 | 875 | 876 | 877 | 878 | 879 | # [1.4.0](https://github.com/nuxt/modules/compare/@nuxtjs/manifest@1.3.1...@nuxtjs/manifest@1.4.0) (2017-06-04) 880 | 881 | 882 | ### Features 883 | 884 | * **manifest:** improvements ([cac9b4e](https://github.com/nuxt/modules/commit/cac9b4e)) 885 | 886 | 887 | 888 | 889 | 890 | ## [1.3.1](https://github.com/nuxt/modules/compare/@nuxtjs/manifest@1.3.0...@nuxtjs/manifest@1.3.1) (2017-06-02) 891 | 892 | 893 | ### Bug Fixes 894 | 895 | * **manifest:** write manifest file once ([18aa015](https://github.com/nuxt/modules/commit/18aa015)) 896 | 897 | 898 | 899 | 900 | 901 | # [1.3.0](https://github.com/nuxt/modules/compare/@nuxtjs/manifest@1.2.0...@nuxtjs/manifest@1.3.0) (2017-06-02) 902 | 903 | 904 | ### Features 905 | 906 | * **manifest:** add lang ([bfdb96e](https://github.com/nuxt/modules/commit/bfdb96e)) 907 | * **manifest:** improve default short_name ([45b2bb2](https://github.com/nuxt/modules/commit/45b2bb2)) 908 | 909 | 910 | 911 | 912 | 913 | # [1.2.0](https://github.com/nuxt/modules/compare/@nuxtjs/manifest@1.1.1...@nuxtjs/manifest@1.2.0) (2017-06-02) 914 | 915 | 916 | ### Features 917 | 918 | * **meta:** add apple-touch-icon ([c74ffa4](https://github.com/nuxt/modules/commit/c74ffa4)) 919 | 920 | 921 | 922 | 923 | 924 | ## [1.1.1](https://github.com/nuxt/modules/compare/@nuxtjs/manifest@1.1.0...@nuxtjs/manifest@1.1.1) (2017-05-31) 925 | 926 | 927 | 928 | 929 | 930 | # [1.1.0](https://github.com/nuxt/modules/compare/@nuxtjs/manifest@1.0.1...@nuxtjs/manifest@1.1.0) (2017-05-30) 931 | 932 | 933 | ### Features 934 | 935 | * **manifest:** Use loading as theme color as default ([cae4329](https://github.com/nuxt/modules/commit/cae4329)) 936 | 937 | 938 | 939 | 940 | 941 | ## [1.0.1](https://github.com/nuxt/modules/compare/@nuxtjs/manifest@1.0.0...@nuxtjs/manifest@1.0.1) (2017-05-29) 942 | 943 | 944 | 945 | 946 | 947 | # 1.0.0 (2017-05-26) 948 | 949 | 950 | ### Features 951 | 952 | * initial migration to 1.0.0-alpha1 ([05c1b7a](https://github.com/nuxt/modules/commit/05c1b7a)) 953 | 954 | 955 | ### BREAKING CHANGES 956 | 957 | * New modules system is backward incompatible with nuxt-helpers style modules 958 | 959 | 960 | 961 | 962 | 963 | ## 0.0.1 (2017-05-10) 964 | 965 | 966 | ## Meta 967 | 968 | 969 | # [2.4.0](https://github.com/nuxt-community/pwa-module/compare/v2.3.2...v2.4.0) (2018-08-28) 970 | 971 | **Note:** Version bump only for package @nuxtjs/meta 972 | 973 | 974 | 975 | 976 | 977 | 978 | # 2.3.0 (2018-08-24) 979 | 980 | 981 | ### Bug Fixes 982 | 983 | * **docs:** add reference to pwa module ([49b7c49](https://github.com/nuxt-community/pwa-module/commit/49b7c49)) 984 | * **meta:** add unique identifiers to meta fields ([#23](https://github.com/nuxt-community/pwa-module/issues/23)) ([76a1f89](https://github.com/nuxt-community/pwa-module/commit/76a1f89)) 985 | * **meta:** generate only on build ([1cace26](https://github.com/nuxt-community/pwa-module/commit/1cace26)) 986 | * **meta:** only set og:url when it has been defined through ogHost or options ([#44](https://github.com/nuxt-community/pwa-module/issues/44)) ([354f818](https://github.com/nuxt-community/pwa-module/commit/354f818)) 987 | * **meta:** remove minimal-ui from default viewport ([cf48b3f](https://github.com/nuxt-community/pwa-module/commit/cf48b3f)), closes [#10](https://github.com/nuxt-community/pwa-module/issues/10) 988 | * don't override title when titleTemplate is provided ([#48](https://github.com/nuxt-community/pwa-module/issues/48)) ([8c3f319](https://github.com/nuxt-community/pwa-module/commit/8c3f319)) 989 | * workaround to fill meta with SPA and nuxt start ([a0fb908](https://github.com/nuxt-community/pwa-module/commit/a0fb908)) 990 | 991 | 992 | ### Features 993 | 994 | * Add compatibility for nuxt 1.0.0 hooks ([c0efb1d](https://github.com/nuxt-community/pwa-module/commit/c0efb1d)) 995 | * add og:image support ([#30](https://github.com/nuxt-community/pwa-module/issues/30)) ([afebd96](https://github.com/nuxt-community/pwa-module/commit/afebd96)) 996 | * **meta:** add author property ([#41](https://github.com/nuxt-community/pwa-module/issues/41)) ([cafcfc4](https://github.com/nuxt-community/pwa-module/commit/cafcfc4)) 997 | * **meta:** add nativeUI option ([3c7aa7d](https://github.com/nuxt-community/pwa-module/commit/3c7aa7d)), closes [#10](https://github.com/nuxt-community/pwa-module/issues/10) 998 | * **meta:** add ogUrl url property ([#42](https://github.com/nuxt-community/pwa-module/issues/42)) ([3990ddf](https://github.com/nuxt-community/pwa-module/commit/3990ddf)) 999 | * **meta:** add property attribiture for og tags ([dc39fcb](https://github.com/nuxt-community/pwa-module/commit/dc39fcb)) 1000 | * **meta:** add twitter card, site and creator properties ([#43](https://github.com/nuxt-community/pwa-module/issues/43)) ([fe11c76](https://github.com/nuxt-community/pwa-module/commit/fe11c76)) 1001 | * ogSiteName ([#50](https://github.com/nuxt-community/pwa-module/issues/50)) ([0c99ab9](https://github.com/nuxt-community/pwa-module/commit/0c99ab9)) 1002 | * **workbox:** workbox 3 + offlinePage ([#60](https://github.com/nuxt-community/pwa-module/issues/60)) ([0fef874](https://github.com/nuxt-community/pwa-module/commit/0fef874)) 1003 | 1004 | 1005 | 1006 | 1007 | 1008 | 1009 | ## [2.2.1](https://github.com/nuxt-community/pwa-module/compare/@nuxtjs/meta@2.2.0...@nuxtjs/meta@2.2.1) (2018-03-08) 1010 | 1011 | 1012 | ### Bug Fixes 1013 | 1014 | * **meta:** only set og:url when it has been defined through ogHost or options ([#44](https://github.com/nuxt-community/pwa-module/issues/44)) ([354f818](https://github.com/nuxt-community/pwa-module/commit/354f818)) 1015 | 1016 | 1017 | 1018 | 1019 | 1020 | 1021 | # [2.2.0](https://github.com/nuxt-community/pwa-module/compare/@nuxtjs/meta@2.1.0...@nuxtjs/meta@2.2.0) (2018-03-08) 1022 | 1023 | 1024 | ### Features 1025 | 1026 | * **meta:** add author property ([#41](https://github.com/nuxt-community/pwa-module/issues/41)) ([cafcfc4](https://github.com/nuxt-community/pwa-module/commit/cafcfc4)) 1027 | * **meta:** add ogUrl url property ([#42](https://github.com/nuxt-community/pwa-module/issues/42)) ([3990ddf](https://github.com/nuxt-community/pwa-module/commit/3990ddf)) 1028 | * **meta:** add twitter card, site and creator properties ([#43](https://github.com/nuxt-community/pwa-module/issues/43)) ([fe11c76](https://github.com/nuxt-community/pwa-module/commit/fe11c76)) 1029 | 1030 | 1031 | 1032 | 1033 | 1034 | 1035 | # [2.1.0](https://github.com/nuxt-community/pwa-module/compare/@nuxtjs/meta@2.0.2...@nuxtjs/meta@2.1.0) (2018-03-05) 1036 | 1037 | 1038 | ### Features 1039 | 1040 | * add og:image support ([#30](https://github.com/nuxt-community/pwa-module/issues/30)) ([afebd96](https://github.com/nuxt-community/pwa-module/commit/afebd96)) 1041 | 1042 | 1043 | 1044 | 1045 | 1046 | 1047 | ## [2.0.2](https://github.com/nuxt-community/pwa-module/compare/@nuxtjs/meta@2.0.1...@nuxtjs/meta@2.0.2) (2017-12-29) 1048 | 1049 | 1050 | ### Bug Fixes 1051 | 1052 | * **meta:** add unique identifiers to meta fields ([#23](https://github.com/nuxt-community/pwa-module/issues/23)) ([76a1f89](https://github.com/nuxt-community/pwa-module/commit/76a1f89)) 1053 | 1054 | 1055 | 1056 | 1057 | 1058 | ## [2.0.1](https://github.com/nuxt-community/pwa-module/compare/@nuxtjs/meta@2.0.0...@nuxtjs/meta@2.0.1) (2017-11-17) 1059 | 1060 | 1061 | ### Bug Fixes 1062 | 1063 | * workaround to fill meta with SPA and nuxt start ([a0fb908](https://github.com/nuxt-community/pwa-module/commit/a0fb908)) 1064 | 1065 | 1066 | 1067 | 1068 | 1069 | # [2.0.0](https://github.com/nuxt-community/pwa-module/compare/@nuxtjs/meta@1.5.3...@nuxtjs/meta@2.0.0) (2017-11-16) 1070 | 1071 | 1072 | ### Bug Fixes 1073 | 1074 | * **meta:** generate only on build ([1cace26](https://github.com/nuxt-community/pwa-module/commit/1cace26)) 1075 | * **meta:** remove minimal-ui from default viewport ([cf48b3f](https://github.com/nuxt-community/pwa-module/commit/cf48b3f)) 1076 | 1077 | 1078 | ### Features 1079 | 1080 | * **meta:** add nativeUI option ([3c7aa7d](https://github.com/nuxt-community/pwa-module/commit/3c7aa7d)) 1081 | * Add compatibility for nuxt 1.0.0 hooks ([c0efb1d](https://github.com/nuxt-community/pwa-module/commit/c0efb1d)) 1082 | * **meta:** add property attribiture for og tags ([dc39fcb](https://github.com/nuxt-community/pwa-module/commit/dc39fcb)) 1083 | 1084 | 1085 | 1086 | 1087 | 1088 | ## 1.5.3 (2017-10-04) 1089 | 1090 | 1091 | ### Bug Fixes 1092 | 1093 | * **docs:** add reference to pwa module ([49b7c49](https://github.com/nuxt-community/pwa/commit/49b7c49)) 1094 | 1095 | 1096 | 1097 | 1098 | 1099 | ## 1.5.2 (2017-10-04) 1100 | 1101 | 1102 | 1103 | 1104 | **Note:** Version bump only for package @nuxtjs/meta 1105 | 1106 | 1107 | ## [1.5.1](https://github.com/nuxt/modules/compare/@nuxtjs/meta@1.5.0...@nuxtjs/meta@1.5.1) (2017-09-22) 1108 | 1109 | 1110 | ### Bug Fixes 1111 | 1112 | * **meta:** default apple-mobile-web-app-status-bar-style to default ([2535e08](https://github.com/nuxt/modules/commit/2535e08)) 1113 | 1114 | 1115 | 1116 | 1117 | 1118 | # [1.5.0](https://github.com/nuxt/modules/compare/@nuxtjs/meta@1.4.0...@nuxtjs/meta@1.5.0) (2017-09-21) 1119 | 1120 | 1121 | ### Bug Fixes 1122 | 1123 | * **meta:** default appleStatusBarStyle to black ([756d5cb](https://github.com/nuxt/modules/commit/756d5cb)) 1124 | 1125 | 1126 | ### Features 1127 | 1128 | * **meta:** apple-touch-startup-image ([b98106c](https://github.com/nuxt/modules/commit/b98106c)) 1129 | * **meta:** better IOS icons ([d76db2d](https://github.com/nuxt/modules/commit/d76db2d)) 1130 | * **meta:** ios launch icon title ([e94e011](https://github.com/nuxt/modules/commit/e94e011)) 1131 | 1132 | 1133 | 1134 | 1135 | 1136 | # [1.4.0](https://github.com/nuxt/modules/compare/@nuxtjs/meta@1.3.0...@nuxtjs/meta@1.4.0) (2017-09-21) 1137 | 1138 | 1139 | ### Features 1140 | 1141 | * **meta:** ios specific options ([54a1435](https://github.com/nuxt/modules/commit/54a1435)) 1142 | 1143 | 1144 | 1145 | 1146 | 1147 | # [1.3.0](https://github.com/nuxt/modules/compare/@nuxtjs/meta@1.2.1...@nuxtjs/meta@1.3.0) (2017-07-20) 1148 | 1149 | 1150 | ### Features 1151 | 1152 | * **icon:** applefavicon option (#76) ([280b416](https://github.com/nuxt/modules/commit/280b416)) 1153 | 1154 | 1155 | 1156 | 1157 | 1158 | # [1.2.0](https://github.com/nuxt/modules/compare/@nuxtjs/meta@1.1.0...@nuxtjs/meta@1.2.0) (2017-06-06) 1159 | 1160 | 1161 | ### Features 1162 | 1163 | * **meta:** Support manifest meta & openGraph ([17b7db1](https://github.com/nuxt/modules/commit/17b7db1)) 1164 | 1165 | 1166 | 1167 | 1168 | 1169 | # [1.1.0](https://github.com/nuxt/modules/compare/@nuxtjs/meta@1.0.1...@nuxtjs/meta@1.1.0) (2017-06-02) 1170 | 1171 | 1172 | ### Features 1173 | 1174 | * **meta:** more meta tags ([a4e3a04](https://github.com/nuxt/modules/commit/a4e3a04)) 1175 | 1176 | 1177 | 1178 | 1179 | 1180 | ## [1.0.1](https://github.com/nuxt/modules/compare/@nuxtjs/meta@1.0.0...@nuxtjs/meta@1.0.1) (2017-05-29) 1181 | 1182 | 1183 | ### Bug Fixes 1184 | 1185 | * **meta:** add missing head keyword ([758cccd](https://github.com/nuxt/modules/commit/758cccd)) 1186 | * **meta:** fix package.json ([4e395cf](https://github.com/nuxt/modules/commit/4e395cf)) 1187 | 1188 | 1189 | 1190 | 1191 | 1192 | # 1.0.0 (2017-05-26) 1193 | 1194 | 1195 | ### Features 1196 | 1197 | * initial migration to 1.0.0-alpha1 ([05c1b7a](https://github.com/nuxt/modules/commit/05c1b7a)) 1198 | 1199 | 1200 | ### BREAKING CHANGES 1201 | 1202 | * New modules system is backward incompatible with nuxt-helpers style modules 1203 | 1204 | 1205 | 1206 | 1207 | 1208 | ## 0.0.1 (2017-05-10) 1209 | 1210 | ## One signal 1211 | 1212 | 1213 | # [2.4.0](https://github.com/nuxt-community/pwa-module/compare/v2.3.2...v2.4.0) (2018-08-28) 1214 | 1215 | **Note:** Version bump only for package @nuxtjs/onesignal 1216 | 1217 | 1218 | 1219 | 1220 | 1221 | 1222 | # 2.0.0 (2017-11-17) 1223 | 1224 | 1225 | ### Features 1226 | 1227 | * add oneSignal module ([bbc7b72](https://github.com/nuxt-community/pwa-module/commit/bbc7b72)) 1228 | * **onesignal:** move init options under init ([dd61c18](https://github.com/nuxt-community/pwa-module/commit/dd61c18)) 1229 | * **workbox, onegisnal:** Use defaultsDeep for options ([5ac89cf](https://github.com/nuxt-community/pwa-module/commit/5ac89cf)) 1230 | 1231 | ## Workbox 1232 | 1233 | 1234 | # [2.4.0](https://github.com/nuxt-community/pwa-module/compare/v2.3.2...v2.4.0) (2018-08-28) 1235 | 1236 | 1237 | ### Bug Fixes 1238 | 1239 | * **workbox:** infer default value of globDirectory from webpack config. fixes [#83](https://github.com/nuxt-community/pwa-module/issues/83). ([c7102fd](https://github.com/nuxt-community/pwa-module/commit/c7102fd)) 1240 | * **workbox:** more fixes regarding nuxt 2 dist directory changes. fixes [#83](https://github.com/nuxt-community/pwa-module/issues/83). ([7a8bb3b](https://github.com/nuxt-community/pwa-module/commit/7a8bb3b)) 1241 | 1242 | 1243 | ### Features 1244 | 1245 | * **worbox:** offlineAssets ([#86](https://github.com/nuxt-community/pwa-module/issues/86)) ([27c8fa1](https://github.com/nuxt-community/pwa-module/commit/27c8fa1)) 1246 | * **workbox:** offline page assets ([#85](https://github.com/nuxt-community/pwa-module/issues/85)) ([8bc4a3b](https://github.com/nuxt-community/pwa-module/commit/8bc4a3b)) 1247 | 1248 | 1249 | 1250 | 1251 | 1252 | 1253 | # 2.3.2 (2018-08-24) 1254 | 1255 | ### Bug Fixes 1256 | 1257 | * **workbox:** `staleWhileRevalidate()` -> `networkOnly()` for offline pages ([832d60f](https://github.com/nuxt-community/pwa-module/commit/832d60f)) 1258 | 1259 | 1260 | 1261 | # 2.3.1 (2018-08-24) 1262 | 1263 | ### Bug Fixes 1264 | 1265 | * **workbox:** `offlinePage` syntax error ([af21d74](https://github.com/nuxt-community/pwa-module/commit/af21d74)) 1266 | 1267 | 1268 | 1269 | # 2.3.0 (2018-08-24) 1270 | 1271 | 1272 | ### Bug Fixes 1273 | 1274 | * **docs:** add reference to pwa module ([49b7c49](https://github.com/nuxt-community/pwa-module/commit/49b7c49)) 1275 | * **workbox:** faster service worker register ([07524a2](https://github.com/nuxt-community/pwa-module/commit/07524a2)) 1276 | * **workbox:** hardcoded `static` dir ([#73](https://github.com/nuxt-community/pwa-module/issues/73)) ([6d241ec](https://github.com/nuxt-community/pwa-module/commit/6d241ec)) 1277 | * **workbox:** make cacheId independent of npm package version ([b744a27](https://github.com/nuxt-community/pwa-module/commit/b744a27)) 1278 | * **workbox:** use regexp for runtimeCaching. fixes [#14](https://github.com/nuxt-community/pwa-module/issues/14). ([f384103](https://github.com/nuxt-community/pwa-module/commit/f384103)) 1279 | 1280 | 1281 | ### Features 1282 | 1283 | * Add compatibility for nuxt 1.0.0 hooks ([c0efb1d](https://github.com/nuxt-community/pwa-module/commit/c0efb1d)) 1284 | * **workbox, onegisnal:** Use defaultsDeep for options ([5ac89cf](https://github.com/nuxt-community/pwa-module/commit/5ac89cf)) 1285 | * add option to register third-party sw ([#12](https://github.com/nuxt-community/pwa-module/issues/12)) ([9c0b61e](https://github.com/nuxt-community/pwa-module/commit/9c0b61e)) 1286 | * **runtimeCaching:** Support runtimeCaching ([fdcda0f](https://github.com/nuxt-community/pwa-module/commit/fdcda0f)) 1287 | * Add support of StrategyOptions to cache ([b17bbd0](https://github.com/nuxt-community/pwa-module/commit/b17bbd0)) 1288 | * **worbox:** add offline option for making it optional ([#59](https://github.com/nuxt-community/pwa-module/issues/59)) ([76de33c](https://github.com/nuxt-community/pwa-module/commit/76de33c)), closes [#24](https://github.com/nuxt-community/pwa-module/issues/24) 1289 | * **workbox:** add options.autoRegister ([f1e1fe1](https://github.com/nuxt-community/pwa-module/commit/f1e1fe1)) 1290 | * **workbox:** disable caching for sw.js by default ([e7677d8](https://github.com/nuxt-community/pwa-module/commit/e7677d8)) 1291 | * **workbox:** expose registration as window.$sw ([a5ddf59](https://github.com/nuxt-community/pwa-module/commit/a5ddf59)) 1292 | * **workbox:** importScripts option ([7c8644c](https://github.com/nuxt-community/pwa-module/commit/7c8644c)) 1293 | * **workbox:** option to enable `skipWaiting` ([#80](https://github.com/nuxt-community/pwa-module/issues/80)) ([88cc602](https://github.com/nuxt-community/pwa-module/commit/88cc602)) 1294 | * **workbox:** rewrite with better template support ([b0af84e](https://github.com/nuxt-community/pwa-module/commit/b0af84e)) 1295 | * **workbox:** workbox 3 + offlinePage ([#60](https://github.com/nuxt-community/pwa-module/issues/60)) ([0fef874](https://github.com/nuxt-community/pwa-module/commit/0fef874)) 1296 | 1297 | 1298 | 1299 | 1300 | 1301 | 1302 | # [2.2.0](https://github.com/nuxt-community/pwa-module/compare/@nuxtjs/workbox@2.1.1...@nuxtjs/workbox@2.2.0) (2018-03-05) 1303 | 1304 | 1305 | ### Features 1306 | 1307 | * Add support of StrategyOptions to cache ([b17bbd0](https://github.com/nuxt-community/pwa-module/commit/b17bbd0)) 1308 | 1309 | 1310 | 1311 | 1312 | 1313 | 1314 | ## [2.1.1](https://github.com/nuxt-community/pwa-module/compare/@nuxtjs/workbox@2.1.0...@nuxtjs/workbox@2.1.1) (2017-11-27) 1315 | 1316 | 1317 | 1318 | 1319 | **Note:** Version bump only for package @nuxtjs/workbox 1320 | 1321 | 1322 | # [2.1.0](https://github.com/nuxt-community/pwa-module/compare/@nuxtjs/workbox@2.0.1...@nuxtjs/workbox@2.1.0) (2017-11-17) 1323 | 1324 | 1325 | ### Bug Fixes 1326 | 1327 | * **workbox:** faster service worker register ([07524a2](https://github.com/nuxt-community/pwa-module/commit/07524a2)) 1328 | 1329 | 1330 | ### Features 1331 | 1332 | * **runtimeCaching:** Support runtimeCaching ([fdcda0f](https://github.com/nuxt-community/pwa-module/commit/fdcda0f)) 1333 | * **workbox:** add options.autoRegister ([f1e1fe1](https://github.com/nuxt-community/pwa-module/commit/f1e1fe1)) 1334 | * **workbox, onegisnal:** Use defaultsDeep for options ([5ac89cf](https://github.com/nuxt-community/pwa-module/commit/5ac89cf)) 1335 | 1336 | 1337 | 1338 | 1339 | 1340 | ## [2.0.1](https://github.com/nuxt-community/pwa-module/compare/@nuxtjs/workbox@2.0.0...@nuxtjs/workbox@2.0.1) (2017-11-17) 1341 | 1342 | 1343 | ### Bug Fixes 1344 | 1345 | * **workbox:** make cacheId independent of npm package version ([b744a27](https://github.com/nuxt-community/pwa-module/commit/b744a27)) 1346 | * **workbox:** use regexp for runtimeCaching. fixes [#14](https://github.com/nuxt-community/pwa-module/issues/14). ([f384103](https://github.com/nuxt-community/pwa-module/commit/f384103)) 1347 | 1348 | 1349 | 1350 | 1351 | 1352 | # [2.0.0](https://github.com/nuxt-community/pwa-module/compare/@nuxtjs/workbox@1.2.2...@nuxtjs/workbox@2.0.0) (2017-11-16) 1353 | 1354 | 1355 | ### Features 1356 | 1357 | * Add compatibility for nuxt 1.0.0 hooks ([c0efb1d](https://github.com/nuxt-community/pwa-module/commit/c0efb1d)) 1358 | * add option to register third-party sw ([#12](https://github.com/nuxt-community/pwa-module/issues/12)) ([9c0b61e](https://github.com/nuxt-community/pwa-module/commit/9c0b61e)) 1359 | * **workbox:** expose registration as window.$sw ([a5ddf59](https://github.com/nuxt-community/pwa-module/commit/a5ddf59)) 1360 | * **workbox:** importScripts option ([7c8644c](https://github.com/nuxt-community/pwa-module/commit/7c8644c)) 1361 | * **workbox:** rewrite with better template support ([b0af84e](https://github.com/nuxt-community/pwa-module/commit/b0af84e)) 1362 | 1363 | 1364 | 1365 | 1366 | 1367 | ## 1.2.2 (2017-10-04) 1368 | 1369 | 1370 | ### Bug Fixes 1371 | 1372 | * **docs:** add reference to pwa module ([49b7c49](https://github.com/nuxt-community/pwa/commit/49b7c49)) 1373 | 1374 | 1375 | 1376 | 1377 | 1378 | ## 1.2.1 (2017-10-04) 1379 | 1380 | 1381 | 1382 | 1383 | **Note:** Version bump only for package @nuxtjs/workbox 1384 | 1385 | 1386 | # [1.2.0](https://github.com/nuxt/modules/compare/@nuxtjs/workbox@1.1.6...@nuxtjs/workbox@1.2.0) (2017-08-16) 1387 | 1388 | 1389 | ### Features 1390 | 1391 | * **workbox:** use nuxt tapables ([4c52955](https://github.com/nuxt/modules/commit/4c52955)) 1392 | 1393 | 1394 | 1395 | 1396 | 1397 | ## [1.1.6](https://github.com/nuxt/modules/compare/@nuxtjs/workbox@1.1.5...@nuxtjs/workbox@1.1.6) (2017-08-11) 1398 | 1399 | 1400 | ### Bug Fixes 1401 | 1402 | * **workbox:** fix globDirectory ([db6588f](https://github.com/nuxt/modules/commit/db6588f)) 1403 | 1404 | 1405 | 1406 | 1407 | 1408 | ## [1.1.5](https://github.com/nuxt/modules/compare/@nuxtjs/workbox@1.1.4...@nuxtjs/workbox@1.1.5) (2017-08-11) 1409 | 1410 | 1411 | ### Bug Fixes 1412 | 1413 | * **workbox:** explicitly provide globDirectory ([6c4f984](https://github.com/nuxt/modules/commit/6c4f984)) 1414 | 1415 | 1416 | 1417 | 1418 | 1419 | ## [1.1.4](https://github.com/nuxt/modules/compare/@nuxtjs/workbox@1.1.3...@nuxtjs/workbox@1.1.4) (2017-08-06) 1420 | 1421 | 1422 | ### Bug Fixes 1423 | 1424 | * **workbox:** correct serviceworker check (#109) ([53897f1](https://github.com/nuxt/modules/commit/53897f1)) 1425 | 1426 | 1427 | 1428 | 1429 | 1430 | ## [1.1.3](https://github.com/nuxt/modules/compare/@nuxtjs/workbox@1.1.2...@nuxtjs/workbox@1.1.3) (2017-08-02) 1431 | 1432 | 1433 | ### Bug Fixes 1434 | 1435 | * **workbox:** only cach css and js files ([42e3edb](https://github.com/nuxt/modules/commit/42e3edb)) 1436 | 1437 | 1438 | 1439 | 1440 | 1441 | ## [1.1.2](https://github.com/nuxt/modules/compare/@nuxtjs/workbox@1.1.1...@nuxtjs/workbox@1.1.2) (2017-07-31) 1442 | 1443 | 1444 | 1445 | 1446 | 1447 | ## [1.1.1](https://github.com/nuxt/modules/compare/@nuxtjs/workbox@1.1.0...@nuxtjs/workbox@1.1.1) (2017-07-19) 1448 | 1449 | 1450 | ### Bug Fixes 1451 | 1452 | * **workbox:** don't use regexs ([19502d9](https://github.com/nuxt/modules/commit/19502d9)) 1453 | 1454 | 1455 | 1456 | 1457 | 1458 | # [1.1.0](https://github.com/nuxt/modules/compare/@nuxtjs/workbox@1.0.1...@nuxtjs/workbox@1.1.0) (2017-07-19) 1459 | 1460 | 1461 | ### Features 1462 | 1463 | * **workbox:** enable clientsClaim by default ([f7001ad](https://github.com/nuxt/modules/commit/f7001ad)) 1464 | 1465 | 1466 | 1467 | 1468 | 1469 | ## [1.0.1](https://github.com/nuxt/modules/compare/@nuxtjs/workbox@1.0.0...@nuxtjs/workbox@1.0.1) (2017-07-19) 1470 | 1471 | 1472 | ### Bug Fixes 1473 | 1474 | * **workbox:** update modifyUrlPrefix for latest workbox (#75) ([93e3b66](https://github.com/nuxt/modules/commit/93e3b66)), closes [#75](https://github.com/nuxt/modules/issues/75) 1475 | 1476 | 1477 | 1478 | 1479 | 1480 | # [0.4.0](https://github.com/nuxt/modules/compare/@nuxtjs/workbox@0.3.4...@nuxtjs/workbox@0.4.0) (2017-06-06) 1481 | 1482 | 1483 | ### Features 1484 | 1485 | * **workbox:** simplify publicPath & routerBase ([ab1cb77](https://github.com/nuxt/modules/commit/ab1cb77)) 1486 | 1487 | 1488 | 1489 | 1490 | 1491 | ## [0.3.4](https://github.com/nuxt/modules/compare/@nuxtjs/workbox@0.3.3...@nuxtjs/workbox@0.3.4) (2017-06-05) 1492 | 1493 | 1494 | ### Bug Fixes 1495 | 1496 | * **workbox:** incorrect swURL when routerBase is / ([efbd90e](https://github.com/nuxt/modules/commit/efbd90e)) 1497 | 1498 | 1499 | 1500 | 1501 | 1502 | ## [0.3.3](https://github.com/nuxt/modules/compare/@nuxtjs/workbox@0.3.2...@nuxtjs/workbox@0.3.3) (2017-06-04) 1503 | 1504 | 1505 | ### Performance Improvements 1506 | 1507 | * **workbox:** use default options ([946546f](https://github.com/nuxt/modules/commit/946546f)) 1508 | 1509 | 1510 | 1511 | 1512 | 1513 | ## [0.3.2](https://github.com/nuxt/modules/compare/@nuxtjs/workbox@0.3.1...@nuxtjs/workbox@0.3.2) (2017-06-04) 1514 | 1515 | 1516 | ### Bug Fixes 1517 | 1518 | * **workbox:** empty scope ([50326e9](https://github.com/nuxt/modules/commit/50326e9)) 1519 | 1520 | 1521 | 1522 | 1523 | 1524 | ## [0.3.1](https://github.com/nuxt/modules/compare/@nuxtjs/workbox@0.3.0...@nuxtjs/workbox@0.3.1) (2017-06-04) 1525 | 1526 | 1527 | ### Bug Fixes 1528 | 1529 | * prevent invalid url when router base is / ([f0fd863](https://github.com/nuxt/modules/commit/f0fd863)) 1530 | 1531 | 1532 | 1533 | 1534 | 1535 | # [0.3.0](https://github.com/nuxt/modules/compare/@nuxtjs/workbox@0.2.0...@nuxtjs/workbox@0.3.0) (2017-06-04) 1536 | 1537 | 1538 | ### Features 1539 | 1540 | * **workbox:** full offline support ([9ee7f8f](https://github.com/nuxt/modules/commit/9ee7f8f)) 1541 | 1542 | 1543 | 1544 | 1545 | 1546 | # [0.2.0](https://github.com/nuxt/modules/compare/@nuxtjs/workbox@0.1.0...@nuxtjs/workbox@0.2.0) (2017-06-02) 1547 | 1548 | 1549 | ### Features 1550 | 1551 | * **workbox:** improve service worker ([445a1c2](https://github.com/nuxt/modules/commit/445a1c2)) 1552 | 1553 | 1554 | 1555 | 1556 | 1557 | # 0.1.0 (2017-06-02) 1558 | 1559 | 1560 | ### Features 1561 | 1562 | * workbox ([3d919c3](https://github.com/nuxt/modules/commit/3d919c3)) 1563 | --------------------------------------------------------------------------------