@vite-pwa/nuxt 0.1.2 → 0.2.0

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.
@@ -0,0 +1,5 @@
1
+ declare module 'virtual:nuxt-pwa-configuration' {
2
+ export const enabled: boolean
3
+ export const installPrompt: string | undefined
4
+ export const periodicSyncForUpdates: number
5
+ }
package/dist/module.d.ts CHANGED
@@ -1,30 +1,6 @@
1
1
  import * as _nuxt_schema from '@nuxt/schema';
2
2
  import { VitePWAOptions } from 'vite-plugin-pwa';
3
- import { UnwrapNestedRefs, Ref } from 'vue';
4
3
 
5
- interface PwaInjection {
6
- isInstalled: boolean;
7
- showInstallPrompt: Ref<boolean>;
8
- cancelInstall: () => void;
9
- install: () => Promise<void>;
10
- swActivated: Ref<boolean>;
11
- registrationError: Ref<boolean>;
12
- offlineReady: Ref<boolean>;
13
- needRefresh: Ref<boolean>;
14
- updateServiceWorker: (reloadPage?: boolean | undefined) => Promise<void>;
15
- cancelPrompt: () => Promise<void>;
16
- getSWRegistration: () => ServiceWorkerRegistration | undefined;
17
- }
18
- declare module '#app/nuxt' {
19
- interface NuxtApp {
20
- $pwa: UnwrapNestedRefs<PwaInjection>;
21
- }
22
- }
23
- declare module '@vue/runtime-core' {
24
- interface ComponentCustomProperties {
25
- $pwa: UnwrapNestedRefs<PwaInjection>;
26
- }
27
- }
28
4
  interface ClientOptions {
29
5
  /**
30
6
  * Exposes the plugin: defaults to true.
@@ -59,4 +35,4 @@ interface ModuleOptions extends Partial<VitePWAOptions> {
59
35
 
60
36
  declare const _default: _nuxt_schema.NuxtModule<ModuleOptions>;
61
37
 
62
- export { ClientOptions, ModuleOptions, PwaInjection, _default as default };
38
+ export { ClientOptions, ModuleOptions, _default as default };
package/dist/module.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "name": "pwa",
3
3
  "configKey": "pwa",
4
- "version": "0.1.2"
4
+ "version": "0.2.0"
5
5
  }
package/dist/module.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  import { join } from 'node:path';
2
2
  import { writeFile, mkdir } from 'node:fs/promises';
3
- import { defineNuxtModule, createResolver, addPluginTemplate, addComponent, extendWebpackConfig } from '@nuxt/kit';
3
+ import { defineNuxtModule, createResolver, addPlugin, addComponent, extendWebpackConfig } from '@nuxt/kit';
4
4
  import { VitePWA } from 'vite-plugin-pwa';
5
5
  import { resolve } from 'pathe';
6
6
 
@@ -85,21 +85,26 @@ const module = defineNuxtModule({
85
85
  return vitePwaClientPlugin?.api;
86
86
  };
87
87
  const client = options.client ?? { registerPlugin: true, installPrompt: false, periodicSyncForUpdates: 0 };
88
+ const runtimeDir = resolver.resolve("./runtime");
89
+ if (!nuxt.options.ssr)
90
+ nuxt.options.build.transpile.push(runtimeDir);
88
91
  if (client.registerPlugin) {
89
- addPluginTemplate({
90
- src: resolver.resolve("../templates/pwa.client.ts"),
91
- write: nuxt.options.dev || options.writePlugin,
92
- options: {
93
- periodicSyncForUpdates: typeof client.periodicSyncForUpdates === "number" ? client.periodicSyncForUpdates : 0,
94
- installPrompt: typeof client.installPrompt === "undefined" || client.installPrompt === false ? void 0 : client.installPrompt === true || client.installPrompt.trim() === "" ? "vite-pwa:hide-install" : client.installPrompt.trim()
95
- }
92
+ addPlugin({
93
+ src: resolver.resolve(runtimeDir, "plugins/pwa.client"),
94
+ mode: "client"
95
+ });
96
+ } else {
97
+ addPlugin({
98
+ src: resolver.resolve(runtimeDir, "plugins/pwa.client.stub"),
99
+ mode: "client"
96
100
  });
97
101
  }
98
102
  await addComponent({
99
103
  name: "VitePwaManifest",
100
- filePath: resolver.resolve("./runtime/VitePwaManifest")
104
+ filePath: resolver.resolve(runtimeDir, "components/VitePwaManifest")
101
105
  });
102
106
  nuxt.hook("prepare:types", ({ references }) => {
107
+ references.push({ types: "@vite-pwa/nuxt/configuration" });
103
108
  references.push({ types: "vite-plugin-pwa/vue" });
104
109
  references.push({ types: "vite-plugin-pwa/info" });
105
110
  });
@@ -123,6 +128,8 @@ const module = defineNuxtModule({
123
128
  if (plugin)
124
129
  throw new Error("Remove vite-plugin-pwa plugin from Vite Plugins entry in Nuxt config file!");
125
130
  if (options.manifest && isClient) {
131
+ const configuration = "virtual:nuxt-pwa-configuration";
132
+ const resolvedConfiguration = `\0${configuration}`;
126
133
  viteInlineConfig.plugins.push({
127
134
  name: "vite-pwa-nuxt:webmanifest:build",
128
135
  apply: "build",
@@ -135,6 +142,22 @@ const module = defineNuxtModule({
135
142
  await writeWebManifest(manifestDir, options.manifestFilename || "manifest.webmanifest", api);
136
143
  }
137
144
  }
145
+ }, {
146
+ name: "vite-pwa-nuxt:configuration",
147
+ enforce: "pre",
148
+ resolveId(id) {
149
+ if (id === configuration)
150
+ return resolvedConfiguration;
151
+ },
152
+ load(id) {
153
+ if (id === resolvedConfiguration) {
154
+ const installPrompt = typeof client.installPrompt === "undefined" || client.installPrompt === false ? void 0 : client.installPrompt === true || client.installPrompt.trim() === "" ? "vite-pwa:hide-install" : client.installPrompt.trim();
155
+ return `export const enabled = ${client.registerPlugin}
156
+ export const installPrompt = ${JSON.stringify(installPrompt)}
157
+ export const periodicSyncForUpdates = ${typeof client.periodicSyncForUpdates === "number" ? client.periodicSyncForUpdates : 0}
158
+ `;
159
+ }
160
+ }
138
161
  });
139
162
  }
140
163
  const plugins = [...VitePWA(options).filter((p) => p.name !== "vite-plugin-pwa:build")];
@@ -0,0 +1,2 @@
1
+ declare const _default: any;
2
+ export default _default;
@@ -0,0 +1,112 @@
1
+ import { nextTick, reactive, ref } from "vue";
2
+ import { useRegisterSW } from "virtual:pwa-register/vue";
3
+ import { installPrompt, periodicSyncForUpdates } from "virtual:nuxt-pwa-configuration";
4
+ import { defineNuxtPlugin } from "#imports";
5
+ export default defineNuxtPlugin(() => {
6
+ const registrationError = ref(false);
7
+ const swActivated = ref(false);
8
+ const showInstallPrompt = ref(false);
9
+ const hideInstall = ref(!installPrompt ? true : localStorage.getItem(installPrompt) === "true");
10
+ const ua = navigator.userAgent;
11
+ const ios = ua.match(/iPhone|iPad|iPod/);
12
+ const standalone = window.matchMedia("(display-mode: standalone)").matches;
13
+ const isInstalled = !!(standalone || ios && !ua.match(/Safari/));
14
+ let swRegistration;
15
+ const getSWRegistration = () => swRegistration;
16
+ const registerPeriodicSync = (swUrl, r, timeout) => {
17
+ setInterval(async () => {
18
+ if ("connection" in navigator && !navigator.onLine)
19
+ return;
20
+ const resp = await fetch(swUrl, {
21
+ cache: "no-store",
22
+ headers: {
23
+ "cache": "no-store",
24
+ "cache-control": "no-cache"
25
+ }
26
+ });
27
+ if (resp?.status === 200)
28
+ await r.update();
29
+ }, timeout);
30
+ };
31
+ const {
32
+ offlineReady,
33
+ needRefresh,
34
+ updateServiceWorker
35
+ } = useRegisterSW({
36
+ immediate: true,
37
+ onRegisterError() {
38
+ registrationError.value = true;
39
+ },
40
+ onRegisteredSW(swUrl, r) {
41
+ swRegistration = r;
42
+ const timeout = periodicSyncForUpdates;
43
+ if (timeout > 0) {
44
+ if (r?.active?.state === "activated") {
45
+ swActivated.value = true;
46
+ registerPeriodicSync(swUrl, r, timeout * 1e3);
47
+ } else if (r?.installing) {
48
+ r.installing.addEventListener("statechange", (e) => {
49
+ const sw = e.target;
50
+ swActivated.value = sw.state === "activated";
51
+ if (swActivated.value)
52
+ registerPeriodicSync(swUrl, r, timeout * 1e3);
53
+ });
54
+ }
55
+ }
56
+ }
57
+ });
58
+ const cancelPrompt = async () => {
59
+ offlineReady.value = false;
60
+ needRefresh.value = false;
61
+ };
62
+ let install = () => Promise.resolve();
63
+ let cancelInstall = () => {
64
+ };
65
+ if (!hideInstall.value) {
66
+ let deferredPrompt;
67
+ const beforeInstallPrompt = (e) => {
68
+ e.preventDefault();
69
+ deferredPrompt = e;
70
+ showInstallPrompt.value = true;
71
+ };
72
+ window.addEventListener("beforeinstallprompt", beforeInstallPrompt);
73
+ window.addEventListener("appinstalled", () => {
74
+ deferredPrompt = void 0;
75
+ showInstallPrompt.value = false;
76
+ });
77
+ cancelInstall = () => {
78
+ deferredPrompt = void 0;
79
+ showInstallPrompt.value = false;
80
+ window.removeEventListener("beforeinstallprompt", beforeInstallPrompt);
81
+ hideInstall.value = true;
82
+ localStorage.setItem(installPrompt, "true");
83
+ };
84
+ install = async () => {
85
+ if (!showInstallPrompt.value || !deferredPrompt) {
86
+ showInstallPrompt.value = false;
87
+ return;
88
+ }
89
+ showInstallPrompt.value = false;
90
+ await nextTick();
91
+ deferredPrompt.prompt();
92
+ await deferredPrompt.userChoice;
93
+ };
94
+ }
95
+ return {
96
+ provide: {
97
+ pwa: reactive({
98
+ isInstalled,
99
+ showInstallPrompt,
100
+ cancelInstall,
101
+ install,
102
+ swActivated,
103
+ registrationError,
104
+ offlineReady,
105
+ needRefresh,
106
+ updateServiceWorker,
107
+ cancelPrompt,
108
+ getSWRegistration
109
+ })
110
+ }
111
+ };
112
+ });
@@ -0,0 +1,2 @@
1
+ declare const _default: any;
2
+ export default _default;
@@ -0,0 +1,8 @@
1
+ import { defineNuxtPlugin } from "#imports";
2
+ export default defineNuxtPlugin(() => {
3
+ return {
4
+ provide: {
5
+ pwa: void 0
6
+ }
7
+ };
8
+ });
@@ -0,0 +1,14 @@
1
+ import type { Ref } from 'vue';
2
+ export interface PwaInjection {
3
+ isInstalled: boolean;
4
+ showInstallPrompt: Ref<boolean>;
5
+ cancelInstall: () => void;
6
+ install: () => Promise<void>;
7
+ swActivated: Ref<boolean>;
8
+ registrationError: Ref<boolean>;
9
+ offlineReady: Ref<boolean>;
10
+ needRefresh: Ref<boolean>;
11
+ updateServiceWorker: (reloadPage?: boolean | undefined) => Promise<void>;
12
+ cancelPrompt: () => Promise<void>;
13
+ getSWRegistration: () => ServiceWorkerRegistration | undefined;
14
+ }
File without changes
package/dist/types.d.ts CHANGED
@@ -12,4 +12,4 @@ declare module 'nuxt/schema' {
12
12
  }
13
13
 
14
14
 
15
- export { ClientOptions, ModuleOptions, PwaInjection, default } from './module'
15
+ export { ClientOptions, ModuleOptions, default } from './module'
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@vite-pwa/nuxt",
3
3
  "type": "module",
4
- "version": "0.1.2",
4
+ "version": "0.2.0",
5
5
  "packageManager": "pnpm@8.10.2",
6
6
  "description": "Zero-config PWA for Nuxt 3",
7
7
  "author": "antfu <anthonyfu117@hotmail.com>",
@@ -23,15 +23,18 @@
23
23
  "exports": {
24
24
  ".": {
25
25
  "types": "./dist/types.d.ts",
26
- "require": "./dist/module.cjs",
27
- "import": "./dist/module.mjs"
26
+ "import": "./dist/module.mjs",
27
+ "require": "./dist/module.cjs"
28
+ },
29
+ "./configuration": {
30
+ "types": "./configuration.d.ts"
28
31
  }
29
32
  },
30
33
  "main": "./dist/module.cjs",
31
34
  "types": "./dist/types.d.ts",
32
35
  "files": [
33
36
  "dist",
34
- "templates"
37
+ "*.d.ts"
35
38
  ],
36
39
  "scripts": {
37
40
  "prepack": "nuxt-module-build prepare && nuxt-module-build",
@@ -54,23 +57,27 @@
54
57
  "test:with-build": "nr dev:prepare && nr prepack && nr test"
55
58
  },
56
59
  "peerDependencies": {
57
- "@nuxt/kit": "^3.5.3",
60
+ "@nuxt/kit": "^3.6.2",
58
61
  "vite-plugin-pwa": ">=0.16.5 <1"
59
62
  },
60
63
  "dependencies": {
61
- "@nuxt/kit": "^3.5.3",
64
+ "@nuxt/kit": "^3.6.2",
65
+ "pathe": "^1.1.1",
66
+ "ufo": "^1.3.1",
62
67
  "vite-plugin-pwa": ">=0.16.5 <1"
63
68
  },
64
69
  "devDependencies": {
65
70
  "@antfu/eslint-config": "^0.41.0",
66
71
  "@antfu/ni": "^0.21.8",
67
72
  "@nuxt/module-builder": "^0.4.0",
68
- "@nuxt/schema": "^3.5.3",
73
+ "@nuxt/schema": "^3.6.5",
69
74
  "@nuxt/test-utils": "^3.5.3",
70
75
  "@playwright/test": "^1.37.1",
76
+ "@types/node": "^18",
71
77
  "bumpp": "^9.2.0",
72
78
  "eslint": "^8.49.0",
73
- "nuxt": "^3.5.3",
79
+ "node-fetch-native": "^1.4.1",
80
+ "nuxt": "^3.6.5",
74
81
  "serve": "^14.2.1",
75
82
  "typescript": "^5.2.2",
76
83
  "vitest": "^0.34.4"
@@ -80,8 +87,12 @@
80
87
  "node:child_process",
81
88
  "node:fs",
82
89
  "consola",
90
+ "esbuild",
83
91
  "pathe",
84
- "ufo"
92
+ "rollup",
93
+ "ufo",
94
+ "vite",
95
+ "vite-plugin-pwa"
85
96
  ]
86
97
  }
87
98
  }
@@ -1,136 +0,0 @@
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
- })