@vite-pwa/nuxt 0.0.10 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -1
- package/dist/module.json +1 -1
- package/dist/module.mjs +9 -1
- package/package.json +17 -17
- package/templates/pwa.client.ts +136 -136
package/README.md
CHANGED
|
@@ -40,7 +40,8 @@ Zero-config PWA Plugin for Nuxt 3
|
|
|
40
40
|
- ⚙️ **Stale-while-revalidate**: automatic reload when new content is available
|
|
41
41
|
- ✨ **Static assets handling**: configure static assets for offline support
|
|
42
42
|
- 🐞 **Development Support**: debug your custom service worker logic as you develop your application
|
|
43
|
-
- 🛠️ **Versatile**: integration with meta frameworks:
|
|
43
|
+
- 🛠️ **Versatile**: integration with meta frameworks: [îles](https://github.com/ElMassimo/iles), [SvelteKit](https://github.com/sveltejs/kit), [VitePress](https://github.com/vuejs/vitepress), [Astro](https://github.com/withastro/astro), and [Nuxt 3](https://github.com/nuxt/nuxt)
|
|
44
|
+
- 💥 PWA Assets Generator: generate all the PWA assets from a single command and a single source image
|
|
44
45
|
|
|
45
46
|
## 📦 Install
|
|
46
47
|
|
package/dist/module.json
CHANGED
package/dist/module.mjs
CHANGED
|
@@ -98,7 +98,7 @@ const module = defineNuxtModule({
|
|
|
98
98
|
filePath: resolver.resolve("./runtime/VitePwaManifest")
|
|
99
99
|
});
|
|
100
100
|
nuxt.hook("prepare:types", ({ references }) => {
|
|
101
|
-
references.push({ types: "vite-plugin-pwa/
|
|
101
|
+
references.push({ types: "vite-plugin-pwa/vue" });
|
|
102
102
|
references.push({ types: "vite-plugin-pwa/info" });
|
|
103
103
|
});
|
|
104
104
|
const manifestDir = join(nuxt.options.buildDir, "manifests");
|
|
@@ -162,6 +162,14 @@ const module = defineNuxtModule({
|
|
|
162
162
|
return;
|
|
163
163
|
viteServer.middlewares.stack.push({ route: workbox, handle: emptyHandle });
|
|
164
164
|
});
|
|
165
|
+
if (options.devOptions?.suppressWarnings) {
|
|
166
|
+
const suppressWarnings = `${nuxt.options.app.baseURL}suppress-warnings.js`;
|
|
167
|
+
nuxt.hook("vite:serverCreated", (viteServer, { isServer }) => {
|
|
168
|
+
if (isServer)
|
|
169
|
+
return;
|
|
170
|
+
viteServer.middlewares.stack.push({ route: suppressWarnings, handle: emptyHandle });
|
|
171
|
+
});
|
|
172
|
+
}
|
|
165
173
|
}
|
|
166
174
|
} else {
|
|
167
175
|
if (!options.disable && options.registerWebManifestInRouteRules) {
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vite-pwa/nuxt",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.
|
|
5
|
-
"packageManager": "pnpm@8.
|
|
4
|
+
"version": "0.1.1",
|
|
5
|
+
"packageManager": "pnpm@8.7.4",
|
|
6
6
|
"description": "Zero-config PWA for Nuxt 3",
|
|
7
7
|
"author": "antfu <anthonyfu117@hotmail.com>",
|
|
8
8
|
"license": "MIT",
|
|
@@ -55,26 +55,26 @@
|
|
|
55
55
|
"test:with-build": "nr dev:prepare && nr prepack && nr test"
|
|
56
56
|
},
|
|
57
57
|
"peerDependencies": {
|
|
58
|
-
"@nuxt/kit": "^3.
|
|
59
|
-
"vite-plugin-pwa": "
|
|
58
|
+
"@nuxt/kit": "^3.5.3",
|
|
59
|
+
"vite-plugin-pwa": ">=0.16.5 <1"
|
|
60
60
|
},
|
|
61
61
|
"dependencies": {
|
|
62
|
-
"@nuxt/kit": "^3.5.
|
|
63
|
-
"vite-plugin-pwa": "
|
|
62
|
+
"@nuxt/kit": "^3.5.3",
|
|
63
|
+
"vite-plugin-pwa": ">=0.16.5 <1"
|
|
64
64
|
},
|
|
65
65
|
"devDependencies": {
|
|
66
|
-
"@antfu/eslint-config": "^0.
|
|
67
|
-
"@antfu/ni": "^0.21.
|
|
66
|
+
"@antfu/eslint-config": "^0.41.0",
|
|
67
|
+
"@antfu/ni": "^0.21.8",
|
|
68
68
|
"@nuxt/module-builder": "^0.4.0",
|
|
69
|
-
"@nuxt/schema": "^3.5.
|
|
70
|
-
"@nuxt/test-utils": "^3.5.
|
|
71
|
-
"@playwright/test": "^1.
|
|
72
|
-
"bumpp": "^
|
|
73
|
-
"eslint": "^8.
|
|
74
|
-
"nuxt": "^3.5.
|
|
75
|
-
"serve": "^14.2.
|
|
76
|
-
"typescript": "^5.
|
|
77
|
-
"vitest": "^0.
|
|
69
|
+
"@nuxt/schema": "^3.5.3",
|
|
70
|
+
"@nuxt/test-utils": "^3.5.3",
|
|
71
|
+
"@playwright/test": "^1.37.1",
|
|
72
|
+
"bumpp": "^9.2.0",
|
|
73
|
+
"eslint": "^8.49.0",
|
|
74
|
+
"nuxt": "^3.5.3",
|
|
75
|
+
"serve": "^14.2.1",
|
|
76
|
+
"typescript": "^5.2.2",
|
|
77
|
+
"vitest": "^0.34.4"
|
|
78
78
|
},
|
|
79
79
|
"build": {
|
|
80
80
|
"externals": [
|
package/templates/pwa.client.ts
CHANGED
|
@@ -1,136 +1,136 @@
|
|
|
1
|
-
import { ref, reactive, nextTick, type UnwrapNestedRefs } from 'vue'
|
|
2
|
-
import { useRegisterSW } from 'virtual:pwa-register/vue'
|
|
3
|
-
import { defineNuxtPlugin } from '#imports'
|
|
4
|
-
|
|
5
|
-
import { type PwaInjection } from '@vite-pwa/nuxt'
|
|
6
|
-
|
|
7
|
-
const options: { periodicSyncForUpdates: number; installPrompt?: string } = <%= JSON.stringify(options) %>
|
|
8
|
-
|
|
9
|
-
export default defineNuxtPlugin(() => {
|
|
10
|
-
const registrationError = ref(false)
|
|
11
|
-
const swActivated = ref(false)
|
|
12
|
-
const showInstallPrompt = ref(false)
|
|
13
|
-
const hideInstall = ref(!options.installPrompt ? true : localStorage.getItem(options.installPrompt) === 'true')
|
|
14
|
-
|
|
15
|
-
// https://thomashunter.name/posts/2021-12-11-detecting-if-pwa-twa-is-installed
|
|
16
|
-
const ua = navigator.userAgent
|
|
17
|
-
const ios = ua.match(/iPhone|iPad|iPod/)
|
|
18
|
-
const standalone = window.matchMedia('(display-mode: standalone)').matches
|
|
19
|
-
const isInstalled = !!(standalone || (ios && !ua.match(/Safari/)))
|
|
20
|
-
|
|
21
|
-
let swRegistration: ServiceWorkerRegistration | undefined
|
|
22
|
-
|
|
23
|
-
const getSWRegistration = () => swRegistration
|
|
24
|
-
|
|
25
|
-
const registerPeriodicSync = (swUrl: string, r: ServiceWorkerRegistration, timeout: number) => {
|
|
26
|
-
setInterval(async () => {
|
|
27
|
-
if (('connection' in navigator) && !navigator.onLine)
|
|
28
|
-
return
|
|
29
|
-
|
|
30
|
-
const resp = await fetch(swUrl, {
|
|
31
|
-
cache: 'no-store',
|
|
32
|
-
headers: {
|
|
33
|
-
'cache': 'no-store',
|
|
34
|
-
'cache-control': 'no-cache',
|
|
35
|
-
},
|
|
36
|
-
})
|
|
37
|
-
|
|
38
|
-
if (resp?.status === 200)
|
|
39
|
-
await r.update()
|
|
40
|
-
}, timeout)
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
const {
|
|
44
|
-
offlineReady, needRefresh, updateServiceWorker,
|
|
45
|
-
} = useRegisterSW({
|
|
46
|
-
immediate: true,
|
|
47
|
-
onRegisterError() {
|
|
48
|
-
registrationError.value = true
|
|
49
|
-
},
|
|
50
|
-
onRegisteredSW(swUrl, r) {
|
|
51
|
-
swRegistration = r
|
|
52
|
-
const timeout = options.periodicSyncForUpdates
|
|
53
|
-
if (timeout > 0) {
|
|
54
|
-
// should add support in pwa plugin
|
|
55
|
-
if (r?.active?.state === 'activated') {
|
|
56
|
-
swActivated.value = true
|
|
57
|
-
registerPeriodicSync(swUrl, r, timeout * 1000)
|
|
58
|
-
}
|
|
59
|
-
else if (r?.installing) {
|
|
60
|
-
r.installing.addEventListener('statechange', (e) => {
|
|
61
|
-
const sw = e.target as ServiceWorker
|
|
62
|
-
swActivated.value = sw.state === 'activated'
|
|
63
|
-
if (swActivated.value)
|
|
64
|
-
registerPeriodicSync(swUrl, r, timeout * 1000)
|
|
65
|
-
})
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
},
|
|
69
|
-
})
|
|
70
|
-
|
|
71
|
-
const cancelPrompt = async () => {
|
|
72
|
-
offlineReady.value = false
|
|
73
|
-
needRefresh.value = false
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
let install: () => Promise<void> = () => Promise.resolve()
|
|
77
|
-
let cancelInstall: () => void = () => {}
|
|
78
|
-
|
|
79
|
-
if (!hideInstall.value) {
|
|
80
|
-
type InstallPromptEvent = Event & {
|
|
81
|
-
prompt: () => void
|
|
82
|
-
userChoice: Promise<{ outcome: 'dismissed' | 'accepted' }>
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
let deferredPrompt: InstallPromptEvent | undefined
|
|
86
|
-
|
|
87
|
-
const beforeInstallPrompt = (e: Event) => {
|
|
88
|
-
e.preventDefault()
|
|
89
|
-
deferredPrompt = e as InstallPromptEvent
|
|
90
|
-
showInstallPrompt.value = true
|
|
91
|
-
}
|
|
92
|
-
window.addEventListener('beforeinstallprompt', beforeInstallPrompt)
|
|
93
|
-
window.addEventListener('appinstalled', () => {
|
|
94
|
-
deferredPrompt = undefined
|
|
95
|
-
showInstallPrompt.value = false
|
|
96
|
-
})
|
|
97
|
-
|
|
98
|
-
cancelInstall = () => {
|
|
99
|
-
deferredPrompt = undefined
|
|
100
|
-
showInstallPrompt.value = false
|
|
101
|
-
window.removeEventListener('beforeinstallprompt', beforeInstallPrompt)
|
|
102
|
-
hideInstall.value = true
|
|
103
|
-
localStorage.setItem(options.installPrompt!, 'true')
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
install = async () => {
|
|
107
|
-
if (!showInstallPrompt.value || !deferredPrompt) {
|
|
108
|
-
showInstallPrompt.value = false
|
|
109
|
-
return
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
showInstallPrompt.value = false
|
|
113
|
-
await nextTick()
|
|
114
|
-
deferredPrompt.prompt()
|
|
115
|
-
await deferredPrompt.userChoice
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
return {
|
|
120
|
-
provide: {
|
|
121
|
-
pwa: reactive({
|
|
122
|
-
isInstalled,
|
|
123
|
-
showInstallPrompt,
|
|
124
|
-
cancelInstall,
|
|
125
|
-
install,
|
|
126
|
-
swActivated,
|
|
127
|
-
registrationError,
|
|
128
|
-
offlineReady,
|
|
129
|
-
needRefresh,
|
|
130
|
-
updateServiceWorker,
|
|
131
|
-
cancelPrompt,
|
|
132
|
-
getSWRegistration,
|
|
133
|
-
}) satisfies UnwrapNestedRefs<PwaInjection>,
|
|
134
|
-
},
|
|
135
|
-
}
|
|
136
|
-
})
|
|
1
|
+
import { ref, reactive, nextTick, type UnwrapNestedRefs } from 'vue'
|
|
2
|
+
import { useRegisterSW } from 'virtual:pwa-register/vue'
|
|
3
|
+
import { defineNuxtPlugin } from '#imports'
|
|
4
|
+
|
|
5
|
+
import { type PwaInjection } from '@vite-pwa/nuxt'
|
|
6
|
+
|
|
7
|
+
const options: { periodicSyncForUpdates: number; installPrompt?: string } = <%= JSON.stringify(options) %>
|
|
8
|
+
|
|
9
|
+
export default defineNuxtPlugin(() => {
|
|
10
|
+
const registrationError = ref(false)
|
|
11
|
+
const swActivated = ref(false)
|
|
12
|
+
const showInstallPrompt = ref(false)
|
|
13
|
+
const hideInstall = ref(!options.installPrompt ? true : localStorage.getItem(options.installPrompt) === 'true')
|
|
14
|
+
|
|
15
|
+
// https://thomashunter.name/posts/2021-12-11-detecting-if-pwa-twa-is-installed
|
|
16
|
+
const ua = navigator.userAgent
|
|
17
|
+
const ios = ua.match(/iPhone|iPad|iPod/)
|
|
18
|
+
const standalone = window.matchMedia('(display-mode: standalone)').matches
|
|
19
|
+
const isInstalled = !!(standalone || (ios && !ua.match(/Safari/)))
|
|
20
|
+
|
|
21
|
+
let swRegistration: ServiceWorkerRegistration | undefined
|
|
22
|
+
|
|
23
|
+
const getSWRegistration = () => swRegistration
|
|
24
|
+
|
|
25
|
+
const registerPeriodicSync = (swUrl: string, r: ServiceWorkerRegistration, timeout: number) => {
|
|
26
|
+
setInterval(async () => {
|
|
27
|
+
if (('connection' in navigator) && !navigator.onLine)
|
|
28
|
+
return
|
|
29
|
+
|
|
30
|
+
const resp = await fetch(swUrl, {
|
|
31
|
+
cache: 'no-store',
|
|
32
|
+
headers: {
|
|
33
|
+
'cache': 'no-store',
|
|
34
|
+
'cache-control': 'no-cache',
|
|
35
|
+
},
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
if (resp?.status === 200)
|
|
39
|
+
await r.update()
|
|
40
|
+
}, timeout)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const {
|
|
44
|
+
offlineReady, needRefresh, updateServiceWorker,
|
|
45
|
+
} = useRegisterSW({
|
|
46
|
+
immediate: true,
|
|
47
|
+
onRegisterError() {
|
|
48
|
+
registrationError.value = true
|
|
49
|
+
},
|
|
50
|
+
onRegisteredSW(swUrl, r) {
|
|
51
|
+
swRegistration = r
|
|
52
|
+
const timeout = options.periodicSyncForUpdates
|
|
53
|
+
if (timeout > 0) {
|
|
54
|
+
// should add support in pwa plugin
|
|
55
|
+
if (r?.active?.state === 'activated') {
|
|
56
|
+
swActivated.value = true
|
|
57
|
+
registerPeriodicSync(swUrl, r, timeout * 1000)
|
|
58
|
+
}
|
|
59
|
+
else if (r?.installing) {
|
|
60
|
+
r.installing.addEventListener('statechange', (e) => {
|
|
61
|
+
const sw = e.target as ServiceWorker
|
|
62
|
+
swActivated.value = sw.state === 'activated'
|
|
63
|
+
if (swActivated.value)
|
|
64
|
+
registerPeriodicSync(swUrl, r, timeout * 1000)
|
|
65
|
+
})
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
})
|
|
70
|
+
|
|
71
|
+
const cancelPrompt = async () => {
|
|
72
|
+
offlineReady.value = false
|
|
73
|
+
needRefresh.value = false
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
let install: () => Promise<void> = () => Promise.resolve()
|
|
77
|
+
let cancelInstall: () => void = () => {}
|
|
78
|
+
|
|
79
|
+
if (!hideInstall.value) {
|
|
80
|
+
type InstallPromptEvent = Event & {
|
|
81
|
+
prompt: () => void
|
|
82
|
+
userChoice: Promise<{ outcome: 'dismissed' | 'accepted' }>
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
let deferredPrompt: InstallPromptEvent | undefined
|
|
86
|
+
|
|
87
|
+
const beforeInstallPrompt = (e: Event) => {
|
|
88
|
+
e.preventDefault()
|
|
89
|
+
deferredPrompt = e as InstallPromptEvent
|
|
90
|
+
showInstallPrompt.value = true
|
|
91
|
+
}
|
|
92
|
+
window.addEventListener('beforeinstallprompt', beforeInstallPrompt)
|
|
93
|
+
window.addEventListener('appinstalled', () => {
|
|
94
|
+
deferredPrompt = undefined
|
|
95
|
+
showInstallPrompt.value = false
|
|
96
|
+
})
|
|
97
|
+
|
|
98
|
+
cancelInstall = () => {
|
|
99
|
+
deferredPrompt = undefined
|
|
100
|
+
showInstallPrompt.value = false
|
|
101
|
+
window.removeEventListener('beforeinstallprompt', beforeInstallPrompt)
|
|
102
|
+
hideInstall.value = true
|
|
103
|
+
localStorage.setItem(options.installPrompt!, 'true')
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
install = async () => {
|
|
107
|
+
if (!showInstallPrompt.value || !deferredPrompt) {
|
|
108
|
+
showInstallPrompt.value = false
|
|
109
|
+
return
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
showInstallPrompt.value = false
|
|
113
|
+
await nextTick()
|
|
114
|
+
deferredPrompt.prompt()
|
|
115
|
+
await deferredPrompt.userChoice
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
return {
|
|
120
|
+
provide: {
|
|
121
|
+
pwa: reactive({
|
|
122
|
+
isInstalled,
|
|
123
|
+
showInstallPrompt,
|
|
124
|
+
cancelInstall,
|
|
125
|
+
install,
|
|
126
|
+
swActivated,
|
|
127
|
+
registrationError,
|
|
128
|
+
offlineReady,
|
|
129
|
+
needRefresh,
|
|
130
|
+
updateServiceWorker,
|
|
131
|
+
cancelPrompt,
|
|
132
|
+
getSWRegistration,
|
|
133
|
+
}) satisfies UnwrapNestedRefs<PwaInjection>,
|
|
134
|
+
},
|
|
135
|
+
}
|
|
136
|
+
})
|