@vite-pwa/nuxt 1.1.0 → 2.0.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.
Files changed (50) hide show
  1. package/README.md +28 -59
  2. package/config/index.d.mts +1 -0
  3. package/config/index.mjs +3 -0
  4. package/configuration.d.ts +3 -0
  5. package/dist/chunks/create-nuxt-pwa-context.mjs +27 -0
  6. package/dist/chunks/prepare-module.mjs +871 -0
  7. package/dist/chunks/prepare-pwa-icons.mjs +161 -0
  8. package/dist/module.d.mts +42 -89
  9. package/dist/module.json +5 -5
  10. package/dist/module.mjs +40 -8
  11. package/dist/runtime/components/NuxtPwaAssets.d.ts +1 -1
  12. package/dist/runtime/components/NuxtPwaAssets.js +8 -4
  13. package/dist/runtime/components/{VitePwaManifest.d.ts → NuxtPwaManifest.d.ts} +1 -1
  14. package/dist/runtime/components/{VitePwaManifest.js → NuxtPwaManifest.js} +2 -2
  15. package/dist/runtime/{composables/index.d.ts → composables.d.ts} +12 -28
  16. package/dist/runtime/{composables/index.js → composables.js} +1 -11
  17. package/dist/runtime/plugins/pwa-install.client.d.ts +6 -0
  18. package/dist/runtime/plugins/pwa-install.client.js +70 -0
  19. package/dist/runtime/plugins/pwa.client.d.ts +1 -1
  20. package/dist/runtime/plugins/pwa.client.js +90 -77
  21. package/dist/runtime/plugins/types.d.ts +70 -129
  22. package/dist/runtime/plugins/types.js +0 -0
  23. package/dist/types.d.mts +5 -5
  24. package/package.json +40 -59
  25. package/dist/chunks/dev.mjs +0 -37
  26. package/dist/chunks/pwa-icons.mjs +0 -155
  27. package/dist/module.cjs +0 -5
  28. package/dist/module.d.ts +0 -110
  29. package/dist/runtime/components/PwaAppleImage.vue +0 -12
  30. package/dist/runtime/components/PwaAppleImage.vue.d.ts +0 -2
  31. package/dist/runtime/components/PwaAppleSplashScreenImage.vue +0 -12
  32. package/dist/runtime/components/PwaAppleSplashScreenImage.vue.d.ts +0 -2
  33. package/dist/runtime/components/PwaFaviconImage.vue +0 -12
  34. package/dist/runtime/components/PwaFaviconImage.vue.d.ts +0 -2
  35. package/dist/runtime/components/PwaMaskableImage.vue +0 -12
  36. package/dist/runtime/components/PwaMaskableImage.vue.d.ts +0 -2
  37. package/dist/runtime/components/PwaTransparentImage.vue +0 -12
  38. package/dist/runtime/components/PwaTransparentImage.vue.d.ts +0 -2
  39. package/dist/runtime/components/nuxt4/PwaAppleImage.d.ts +0 -4
  40. package/dist/runtime/components/nuxt4/PwaAppleImage.js +0 -15
  41. package/dist/runtime/components/nuxt4/PwaAppleSplashScreenImage.d.ts +0 -4
  42. package/dist/runtime/components/nuxt4/PwaAppleSplashScreenImage.js +0 -15
  43. package/dist/runtime/components/nuxt4/PwaFaviconImage.d.ts +0 -4
  44. package/dist/runtime/components/nuxt4/PwaFaviconImage.js +0 -15
  45. package/dist/runtime/components/nuxt4/PwaMaskableImage.d.ts +0 -4
  46. package/dist/runtime/components/nuxt4/PwaMaskableImage.js +0 -15
  47. package/dist/runtime/components/nuxt4/PwaTransparentImage.d.ts +0 -4
  48. package/dist/runtime/components/nuxt4/PwaTransparentImage.js +0 -15
  49. package/dist/shared/nuxt.00c26fe8.mjs +0 -734
  50. package/dist/types.d.ts +0 -15
@@ -0,0 +1,871 @@
1
+ import fs, { promises, existsSync } from 'node:fs';
2
+ import { addTemplate, addPluginTemplate, useLogger, addPlugin, addComponent, addImports } from '@nuxt/kit';
3
+ import { resolveDefaultConfig } from '@unplugin-pwa/core/config';
4
+ import { preparePWAAssetsGenerator, normalizeManifest, normalizePath as normalizePath$1, preparePWAStrategy } from '@unplugin-pwa/core/helpers';
5
+ import { loadPwaConfiguration } from '@vite-pwa/nuxt-core';
6
+ import path from 'node:path';
7
+ import { generateWebManifest } from '@unplugin-pwa/core/generate-web-manifest';
8
+ import { INSPECTOR_BASE_PATH_URL, INSPECTOR_BASE_PATH } from '@unplugin-pwa/core/constants';
9
+ import { defu } from 'defu';
10
+ import { access, lstat } from 'node:fs/promises';
11
+ import { prepareSwNamesAndGlobDirectory } from '@unplugin-pwa/core/dev/prepare-sw-names-and-glob-directory';
12
+ import process from 'node:process';
13
+ import { resolveSWNames, normalizePath, extractSwDestNameFromSource } from '@vite-pwa/workbox-build/utils/resolve-sw-names';
14
+ import { hash } from 'node:crypto';
15
+ import { getMajor } from 'verkit';
16
+ import { createRequire } from 'node:module';
17
+
18
+ async function buildPwaAssets(ctx, nuxt) {
19
+ const pwaAssetsGenerator = await ctx.pwaAssetsGenerator;
20
+ if (pwaAssetsGenerator) {
21
+ await pwaAssetsGenerator.generate();
22
+ pwaAssetsGenerator.injectManifestIcons();
23
+ }
24
+ if (ctx.resolvedOptions.manifest) {
25
+ const webManifest = generateWebManifest(ctx);
26
+ await promises.writeFile(
27
+ path.resolve(ctx.outDir, ctx.resolvedOptions.manifestFilename || "manifest.webmanifest"),
28
+ webManifest,
29
+ "utf-8"
30
+ );
31
+ }
32
+ if (!ctx.resolvedOptions.disable) {
33
+ await nuxt.callHook("pwa:beforeBuildServiceWorker", ctx.resolvedOptions);
34
+ await ctx.runBuild();
35
+ }
36
+ }
37
+
38
+ function buildBeforeHook(ctx) {
39
+ return async () => {
40
+ await ctx.nuxt.prepareNuxtOptions();
41
+ };
42
+ }
43
+
44
+ function devtoolsCustomTabsHook(ctx) {
45
+ return (tabs) => {
46
+ if (ctx.resolvedOptions.devOptions?.inspector) {
47
+ tabs.push({
48
+ title: "Unplugin PWA Inspector",
49
+ name: "vite-pwa:nuxt:inspector",
50
+ icon: `${INSPECTOR_BASE_PATH}/icon_gray.svg`,
51
+ view: {
52
+ type: "iframe",
53
+ src: INSPECTOR_BASE_PATH_URL
54
+ }
55
+ });
56
+ }
57
+ };
58
+ }
59
+
60
+ function nitroConfigHook(ctx, nuxt) {
61
+ return (nitroConfig) => {
62
+ if (nuxt.options.experimental.payloadExtraction) {
63
+ ctx.nuxt.enableGlobPatterns = !!nuxt.options.nitro.static || !!nitroConfig.prerender?.routes?.length || Object.values(nitroConfig.routeRules ?? {}).some((r) => r.prerender);
64
+ }
65
+ };
66
+ }
67
+
68
+ async function initPwaAssetsGenerator(ctx, nuxt) {
69
+ if (ctx.resolvedOptions.pwaAssets) {
70
+ const config = ctx.resolvedOptions.pwaAssets.config;
71
+ if (typeof config === "string") {
72
+ ctx.resolvedOptions.pwaAssets.config = await ctx.nuxt.moduleResolver.resolvePath(
73
+ config,
74
+ {
75
+ cwd: nuxt.options.rootDir,
76
+ alias: nuxt.options.alias
77
+ }
78
+ );
79
+ }
80
+ ctx.resolvedOptions.pwaAssets.integration = {
81
+ baseUrl: ctx.base,
82
+ publicDir: ctx.publicDir,
83
+ outDir: ctx.outDir,
84
+ resolveImage: resolveImageFactory(ctx, nuxt)
85
+ };
86
+ preparePWAAssetsGenerator(ctx);
87
+ }
88
+ }
89
+ async function checkFileExists(pathname) {
90
+ try {
91
+ await access(pathname, fs.constants.R_OK);
92
+ } catch {
93
+ return false;
94
+ }
95
+ return true;
96
+ }
97
+ function* preparePaths(nuxt, imageName, layers = false) {
98
+ if (layers) {
99
+ for (const [idx, layer] of nuxt.options._layers.entries()) {
100
+ if (idx === 0) {
101
+ continue;
102
+ }
103
+ yield path.resolve(layer.config.rootDir, imageName);
104
+ yield path.resolve(layer.config.srcDir, imageName);
105
+ }
106
+ return;
107
+ }
108
+ if (nuxt.options.nitro.publicAssets) {
109
+ for (const publicAsset of nuxt.options.nitro.publicAssets) {
110
+ if (publicAsset?.dir) {
111
+ yield path.resolve(publicAsset.dir, imageName);
112
+ }
113
+ }
114
+ }
115
+ yield path.resolve(nuxt.options.rootDir, imageName);
116
+ yield path.resolve(nuxt.options.srcDir, imageName);
117
+ }
118
+ async function* tryToResolveImage(ctx, nuxt, imageName) {
119
+ for (const imagePath of preparePaths(nuxt, imageName)) {
120
+ if (await checkFileExists(imagePath)) {
121
+ yield imagePath;
122
+ }
123
+ }
124
+ try {
125
+ const imagePath = await ctx.nuxt.moduleResolver.resolvePath(imageName, {
126
+ cwd: nuxt.options.rootDir,
127
+ alias: nuxt.options.alias
128
+ });
129
+ if (await checkFileExists(imagePath)) {
130
+ yield imagePath;
131
+ }
132
+ } catch {
133
+ }
134
+ for (const imagePath of preparePaths(nuxt, imageName, true)) {
135
+ if (await checkFileExists(imagePath)) {
136
+ yield imagePath;
137
+ }
138
+ }
139
+ }
140
+ function resolveImageFactory(ctx, nuxt) {
141
+ return async (image) => {
142
+ for await (const imagePath of tryToResolveImage(ctx, nuxt, image)) {
143
+ if (imagePath) {
144
+ return imagePath;
145
+ }
146
+ }
147
+ throw new Error(`PWA Assets image '${image}' cannot be resolved!`);
148
+ };
149
+ }
150
+
151
+ function prepareBuildSwNames(ctx, nitroPublicDir) {
152
+ let swSrc;
153
+ let options;
154
+ switch (ctx.strategy) {
155
+ case "generate-sw":
156
+ swSrc = "x";
157
+ options = ctx.resolvedOptions.generateSW;
158
+ break;
159
+ case "inject-manifest":
160
+ swSrc = ctx.resolvedOptions.injectManifest.swSrc;
161
+ options = ctx.resolvedOptions.injectManifest;
162
+ break;
163
+ case "build-sw":
164
+ swSrc = ctx.resolvedOptions.buildSW.swSrc;
165
+ options = ctx.resolvedOptions.buildSW;
166
+ break;
167
+ }
168
+ if (options) {
169
+ const {
170
+ swDest,
171
+ classicSWDest,
172
+ moduleSWDest
173
+ } = resolveSWNames(
174
+ normalizePath(path.relative(process.cwd(), path.resolve(nitroPublicDir, options.swDest))),
175
+ swSrc,
176
+ ctx.strategy === "generate-sw"
177
+ );
178
+ ctx.swNames = {
179
+ hasNames: true,
180
+ name: swDest,
181
+ classic: classicSWDest,
182
+ module: moduleSWDest
183
+ };
184
+ }
185
+ }
186
+
187
+ async function prepareNitroRoutes(ctx, nuxt) {
188
+ const isDev = nuxt.options.dev;
189
+ let swDisabled = false;
190
+ if (isDev) {
191
+ ctx.devEnvironment = true;
192
+ if (ctx.resolvedOptions.disable) {
193
+ swDisabled = true;
194
+ } else {
195
+ const devOptions = ctx.resolvedOptions.devOptions;
196
+ if (devOptions) {
197
+ swDisabled = !(devOptions.enabled === true);
198
+ } else {
199
+ swDisabled = true;
200
+ }
201
+ }
202
+ } else {
203
+ if (ctx.resolvedOptions.disable) {
204
+ swDisabled = true;
205
+ }
206
+ if (!swDisabled) {
207
+ prepareBuildSwNames(
208
+ ctx,
209
+ ctx.outDir
210
+ );
211
+ }
212
+ }
213
+ const webManifest = ctx.resolvedOptions.manifest;
214
+ let swNames;
215
+ if (isDev) {
216
+ if (!swDisabled) {
217
+ await prepareSwNamesAndGlobDirectory(ctx);
218
+ swNames = ctx.dev.options.swNames;
219
+ await promises.mkdir(ctx.outDir, { recursive: true });
220
+ }
221
+ } else {
222
+ swNames = ctx.swNames;
223
+ }
224
+ const routeRules = ctx.nuxt.nitroPWAOptions.routeRules;
225
+ if (swNames?.hasNames) {
226
+ if (ctx.resolvedOptions.swType === "classic-and-module") {
227
+ routeRules[`${ctx.base}${path.basename(swNames.classic)}`] = {
228
+ headers: {
229
+ "Cache-Control": "public, max-age=0, must-revalidate"
230
+ }
231
+ };
232
+ routeRules[`${ctx.base}${path.basename(swNames.module)}`] = {
233
+ headers: {
234
+ "Cache-Control": "public, max-age=0, must-revalidate"
235
+ }
236
+ };
237
+ } else {
238
+ routeRules[`${ctx.base}${path.basename(swNames.name)}`] = {
239
+ headers: {
240
+ "Cache-Control": "public, max-age=0, must-revalidate"
241
+ }
242
+ };
243
+ }
244
+ }
245
+ if ((nuxt.options.dev || ctx.nuxt.registerWebManifestInRouteRules) && webManifest) {
246
+ routeRules[`${ctx.base}${ctx.resolvedOptions.manifestFilename ?? "manifest.webmanifest"}`] = {
247
+ headers: {
248
+ "Content-Type": "application/manifest+json",
249
+ "Cache-Control": "public, max-age=0, must-revalidate"
250
+ }
251
+ };
252
+ }
253
+ }
254
+
255
+ async function prepareResolvedPwaOptions(ctx, nuxt, outDir) {
256
+ normalizeManifest(ctx);
257
+ let config;
258
+ if (ctx.strategy === "build-sw") {
259
+ ctx.resolvedOptions.buildSW.swSrc = await ctx.nuxt.moduleResolver.resolvePath(
260
+ ctx.resolvedOptions.buildSW.swSrc,
261
+ {
262
+ cwd: nuxt.options.rootDir,
263
+ alias: nuxt.options.alias
264
+ }
265
+ );
266
+ ctx.consumerOptions.filename = ctx.consumerOptions.filename ?? normalizePath$1(
267
+ path.resolve(ctx.outDir, extractSwDestNameFromSource(ctx.resolvedOptions.buildSW.swSrc))
268
+ );
269
+ ctx.resolvedOptions.buildSW.swDest = ctx.consumerOptions.filename;
270
+ ctx.resolvedOptions.buildSW.alias = nuxt.options.alias;
271
+ config = ctx.resolvedOptions.buildSW;
272
+ } else if (ctx.strategy === "generate-sw") {
273
+ ctx.resolvedOptions.generateSW ??= {};
274
+ const generateSW = ctx.resolvedOptions.generateSW;
275
+ if (ctx.resolvedOptions.registerType === "autoUpdate" && (ctx.nuxt.client.registerPlugin || ctx.resolvedOptions.injectRegister === "script" || ctx.resolvedOptions.injectRegister === "inline")) {
276
+ generateSW.clientsClaim = true;
277
+ generateSW.skipWaiting = true;
278
+ }
279
+ if (nuxt.options.dev) {
280
+ generateSW.navigateFallback = generateSW.navigateFallback ?? nuxt.options.app.baseURL ?? "/";
281
+ const devOptions = ctx.resolvedOptions.devOptions;
282
+ if (devOptions?.enabled && !devOptions.navigateFallbackAllowlist) {
283
+ const baseURL = nuxt.options.app.baseURL;
284
+ devOptions.navigateFallbackAllowlist = [
285
+ baseURL ? new RegExp(`^${baseURL.replace(/[-/\\^$*+?.()|[\]{}]/g, "\\$&")}$`) : /^\/$/
286
+ ];
287
+ }
288
+ }
289
+ if (!("navigateFallback" in generateSW)) {
290
+ generateSW.navigateFallback = ctx.base;
291
+ }
292
+ config = generateSW;
293
+ } else if (ctx.strategy === "inject-manifest") {
294
+ ctx.resolvedOptions.injectManifest ??= {};
295
+ ctx.resolvedOptions.injectManifest.swSrc = await ctx.nuxt.moduleResolver.resolvePath(
296
+ ctx.resolvedOptions.injectManifest.swSrc,
297
+ {
298
+ cwd: nuxt.options.rootDir,
299
+ alias: nuxt.options.alias
300
+ }
301
+ );
302
+ ctx.consumerOptions.filename = ctx.consumerOptions.filename ?? normalizePath$1(
303
+ path.resolve(ctx.outDir, extractSwDestNameFromSource(ctx.resolvedOptions.injectManifest.swSrc))
304
+ );
305
+ ctx.resolvedOptions.injectManifest.swDest = ctx.consumerOptions.filename;
306
+ config = ctx.resolvedOptions.injectManifest;
307
+ }
308
+ if (!config) {
309
+ return;
310
+ }
311
+ if (!nuxt.options.dev) {
312
+ config.globDirectory = outDir;
313
+ }
314
+ if (!("globPatterns" in config)) {
315
+ config.globPatterns = ["**/*.{js,css,html}"];
316
+ }
317
+ const buildAssetsDir = ctx.nuxt.buildAssetsDir;
318
+ if (!("dontCacheBustURLsMatching" in config)) {
319
+ config.dontCacheBustURLsMatching = new RegExp(`^${buildAssetsDir.replace(/^\.*\//, "")}`);
320
+ }
321
+ if (ctx.nuxt.enableGlobPatterns) {
322
+ config.globPatterns = config.globPatterns ?? [];
323
+ config.globPatterns.push("**/_payload.json");
324
+ if (ctx.resolvedOptions.strategy === "generate-sw" && (ctx.nuxt.experimental?.enableWorkboxPayloadQueryParams === true || ctx.nuxt.experimental?.enableGenerateSWPayloadQueryParams === true)) {
325
+ const generateSW = ctx.resolvedOptions.generateSW;
326
+ generateSW.runtimeCaching = generateSW.runtimeCaching ?? [];
327
+ generateSW.runtimeCaching.push({
328
+ urlPattern: /\/_payload\.json\?/,
329
+ handler: "NetworkOnly",
330
+ options: {
331
+ plugins: [
332
+ {
333
+ /* this callback will be called when the fetch call fails */
334
+ handlerDidError: async ({ request }) => {
335
+ const url = new URL(request.url);
336
+ url.search = "";
337
+ return Response.redirect(url.href, 302);
338
+ },
339
+ /* this callback will prevent caching the response */
340
+ cacheWillUpdate: async () => null
341
+ }
342
+ ]
343
+ }
344
+ });
345
+ }
346
+ }
347
+ let appManifestFolder;
348
+ if (nuxt.options.experimental.appManifest) {
349
+ config.globPatterns = config.globPatterns ?? [];
350
+ appManifestFolder = `${buildAssetsDir}builds/`;
351
+ config.globPatterns.push(`${appManifestFolder}**/*.json`);
352
+ }
353
+ if (!nuxt.options.dev && !config.manifestTransforms) {
354
+ config.manifestTransforms = [
355
+ createManifestTransform(ctx.base ?? "/", outDir, appManifestFolder)
356
+ ];
357
+ }
358
+ await preparePWAStrategy(
359
+ ctx,
360
+ nuxt.options.rootDir,
361
+ ctx.outDir,
362
+ buildAssetsDir
363
+ );
364
+ }
365
+ function createManifestTransform(base, publicFolder, appManifestFolder) {
366
+ return async (entries) => {
367
+ const regexp = /\.html$/;
368
+ for (const e of entries) {
369
+ if (!e.url.endsWith(".html")) {
370
+ continue;
371
+ }
372
+ const url = e.url.startsWith("/") ? e.url.slice(1) : e.url;
373
+ if (url === "index.html") {
374
+ e.url = base;
375
+ } else {
376
+ const parts = url.split("/");
377
+ parts[parts.length - 1] = parts[parts.length - 1].replace(regexp, "");
378
+ e.url = parts.length > 1 ? parts.slice(0, parts.length - 1).join("/") : parts[0];
379
+ }
380
+ }
381
+ if (appManifestFolder) {
382
+ const regExp = /(\/)?[0-9a-f]{8}\b-[0-9a-f]{4}\b-[0-9a-f]{4}\b-[0-9a-f]{4}\b-[0-9a-f]{12}\.json$/i;
383
+ entries.filter((e) => e.url.startsWith(appManifestFolder) && regExp.test(e.url)).forEach((e) => {
384
+ e.revision = null;
385
+ });
386
+ const latest = `${appManifestFolder}latest.json`;
387
+ const latestJson = path.resolve(publicFolder, latest);
388
+ const data = await lstat(latestJson).catch(() => void 0);
389
+ if (data?.isFile()) {
390
+ const revision = hash("md5", await promises.readFile(latestJson, "utf-8"), "hex");
391
+ const latestEntry = entries.find((e) => e.url === latest);
392
+ if (latestEntry)
393
+ latestEntry.revision = revision;
394
+ else
395
+ entries.push({ url: latest, revision, size: data.size });
396
+ } else {
397
+ entries = entries.filter((e) => e.url !== latest);
398
+ }
399
+ }
400
+ return { manifest: entries, warnings: [] };
401
+ };
402
+ }
403
+
404
+ function addPwaTemplate(filename, content) {
405
+ if (content?.length) {
406
+ return addTemplate({
407
+ write: true,
408
+ filename: `pwa-icons/${filename}.d.ts`,
409
+ getContents: () => content
410
+ }).filename;
411
+ } else {
412
+ return addTemplate({
413
+ write: true,
414
+ filename: `pwa-icons/${filename}.d.ts`,
415
+ getContents: () => generatePwaImageType(filename)
416
+ }).filename;
417
+ }
418
+ }
419
+ function pwaIcons(types) {
420
+ return `// Generated by @vite-pwa/nuxt
421
+ import type { AppleSplashScreenLink, FaviconLink, HtmlLink, IconAsset } from '@vite-pwa/assets-generator/api'
422
+
423
+ export interface PWAAssetIconImage {
424
+ width?: number | string
425
+ height?: number | string
426
+ key: string
427
+ src: string
428
+ }
429
+ export type PWAAssetIcon<T extends HtmlLink> = Omit<IconAsset<T>, 'buffer'> & {
430
+ asImage: PWAAssetIconImage
431
+ }
432
+ export interface PWAIcons {
433
+ transparent: Record<${generateTypes(types?.transparent)}, PWAAssetIcon<HtmlLink>>
434
+ maskable: Record<${generateTypes(types?.maskable)}, PWAAssetIcon<HtmlLink>>
435
+ favicon: Record<${generateTypes(types?.favicon)}, PWAAssetIcon<FaviconLink>>
436
+ apple: Record<${generateTypes(types?.apple)}, PWAAssetIcon<HtmlLink>>
437
+ appleSplashScreen: Record<${generateTypes(types?.appleSplashScreen)}, PWAAssetIcon<AppleSplashScreenLink>>
438
+ }
439
+ `;
440
+ }
441
+ function generatePwaImageType(propsName, names) {
442
+ return `// Generated by @vite-pwa/nuxt
443
+ import type { ImgHTMLAttributes } from 'vue'
444
+
445
+ export type PWAVueImageType = Omit<ImgHTMLAttributes, 'src'>
446
+
447
+ export type ${propsName} = PWAVueImageType & {
448
+ /**
449
+ * Name of the PWA icon to render.
450
+ * @type {${generateTypes(names)}}
451
+ */
452
+ image: ${generateTypes(names)}
453
+ }
454
+ `;
455
+ }
456
+ function generateTypes(types) {
457
+ return types?.length ? types.map((name) => `'${name}'`).join(" | ") : "string";
458
+ }
459
+ function addPWAIconsPluginTemplate(ctx, nuxt, nuxt4, pwaAssetsEnabled) {
460
+ const buildDir = ctx.nuxt.moduleResolver.resolve(nuxt.options.buildDir, "pwa-icons");
461
+ const resolvePluginJsPath = (name) => ctx.nuxt.moduleResolver.resolve(
462
+ buildDir,
463
+ name
464
+ );
465
+ if (nuxt4) {
466
+ addTemplate({
467
+ filename: resolvePluginJsPath("plugin.d.ts"),
468
+ write: true,
469
+ getContents: () => `// Generated by @vite-pwa/nuxt
470
+ import type { Plugin } from '#app';
471
+ import type { PWAIcons } from '#build/pwa-icons';
472
+ declare const plugin: Plugin<{
473
+ pwaIcons?: PWAIcons;
474
+ }>;
475
+ export default plugin;
476
+ `
477
+ });
478
+ addPWAIconPluginTemplate(
479
+ resolvePluginJsPath,
480
+ pwaAssetsEnabled,
481
+ "all"
482
+ );
483
+ } else {
484
+ addPWAIconPluginTemplate(
485
+ resolvePluginJsPath,
486
+ pwaAssetsEnabled,
487
+ "client"
488
+ );
489
+ addPWAIconPluginTemplate(
490
+ resolvePluginJsPath,
491
+ pwaAssetsEnabled,
492
+ "server"
493
+ );
494
+ }
495
+ }
496
+ function addPWAIconPluginTemplate(resolvePluginJsPath, pwaAssetsEnabled, mode) {
497
+ const suffix = mode === "all" ? "" : `:${mode}`;
498
+ const filename = mode === "all" ? "plugin" : `plugin.${mode}`;
499
+ if (mode !== "all") {
500
+ addTemplate({
501
+ filename: resolvePluginJsPath(`plugin.${mode}.d.ts`),
502
+ write: true,
503
+ getContents: () => `// Generated by @vite-pwa/nuxt
504
+ import type { Plugin } from '#app';
505
+ import type { PWAIcons } from '#build/pwa-icons';
506
+
507
+ declare const plugin: Plugin<{
508
+ pwaIcons?: PWAIcons;
509
+ }>;
510
+ export default plugin;
511
+ `
512
+ });
513
+ }
514
+ if (pwaAssetsEnabled) {
515
+ addPluginTemplate({
516
+ filename: resolvePluginJsPath(`${filename}.js`),
517
+ name: `vite-pwa:nuxt:pwa-icons${suffix}:plugin`,
518
+ write: true,
519
+ mode,
520
+ getContents: () => `// Generated by @vite-pwa/nuxt
521
+ import { pwaAssetsIcons } from 'virtual:pwa-assets/icons';
522
+ import { defineNuxtPlugin } from '#imports';
523
+
524
+ export default defineNuxtPlugin(() => ({
525
+ provide: {
526
+ pwaIcons: {
527
+ transparent: configureEntry("transparent"),
528
+ maskable: configureEntry("maskable"),
529
+ favicon: configureEntry("favicon"),
530
+ apple: configureEntry("apple"),
531
+ appleSplashScreen: configureEntry("appleSplashScreen")
532
+ }
533
+ }
534
+ }))
535
+
536
+ function configureEntry(key) {
537
+ return Object.values(pwaAssetsIcons[key] ?? {}).reduce((acc, icon) => {
538
+ const entry = Object.assign({}, icon, {
539
+ asImage: {
540
+ src: icon.url,
541
+ key: \`\${key}-\${icon.name}\`
542
+ }
543
+ });
544
+ if (icon.width && icon.height) {
545
+ entry.asImage.width = icon.width;
546
+ entry.asImage.height = icon.height;
547
+ }
548
+ acc[icon.name] = entry;
549
+ return acc;
550
+ }, {});
551
+ }
552
+ `
553
+ });
554
+ } else {
555
+ addPluginTemplate({
556
+ filename: resolvePluginJsPath(`${filename}.js`),
557
+ name: `vite-pwa:nuxt:pwa-icons${suffix}:plugin`,
558
+ write: true,
559
+ mode,
560
+ getContents: () => `// Generated by @vite-pwa/nuxt
561
+ import { defineNuxtPlugin } from '#imports'
562
+
563
+ export default defineNuxtPlugin(() => ({
564
+ provide: {
565
+ pwaIcons: {
566
+ transparent: {},
567
+ maskable: {},
568
+ favicon: {},
569
+ apple: {},
570
+ appleSplashScreen: {}
571
+ }
572
+ }
573
+ }))
574
+ `
575
+ });
576
+ }
577
+ }
578
+
579
+ async function registerPwaIconsTypes(ctx, nuxt) {
580
+ const options = ctx.resolvedOptions;
581
+ const pwaAssets = options.pwaAssets && !options.pwaAssets.disabled;
582
+ let dts;
583
+ if (pwaAssets) {
584
+ try {
585
+ const { preparePWAIcons } = await import('./prepare-pwa-icons.mjs');
586
+ dts = await preparePWAIcons(nuxt, ctx);
587
+ } catch (error) {
588
+ useLogger("@vite-pwa/nuxt").warn("Unable to generate PWA icons types.", error);
589
+ dts = void 0;
590
+ }
591
+ }
592
+ const templates = [];
593
+ const dtsContent = dts?.dts;
594
+ if (dtsContent) {
595
+ templates.push(addTemplate({
596
+ write: true,
597
+ filename: "pwa-icons/index.d.ts",
598
+ getContents: () => dtsContent
599
+ }).filename);
600
+ } else {
601
+ templates.push(addTemplate({
602
+ write: true,
603
+ filename: "pwa-icons/index.d.ts",
604
+ getContents: () => pwaIcons()
605
+ }).filename);
606
+ }
607
+ templates.push(addPwaTemplate("PwaTransparentImageProps", dts?.transparent));
608
+ templates.push(addPwaTemplate("PwaMaskableImageProps", dts?.maskable));
609
+ templates.push(addPwaTemplate("PwaFaviconImageProps", dts?.favicon));
610
+ templates.push(addPwaTemplate("PwaAppleImageProps", dts?.apple));
611
+ templates.push(addPwaTemplate("PwaAppleSplashScreenImageProps", dts?.appleSplashScreen));
612
+ addPWAIconsPluginTemplate(
613
+ ctx,
614
+ nuxt,
615
+ getMajor(ctx.nuxt.nuxtVersion) >= 4,
616
+ pwaAssets === true
617
+ );
618
+ const pwaInjectionPath = normalizePath$1(path.relative(
619
+ ctx.nuxt.moduleResolver.resolve(nuxt.options.buildDir, "types"),
620
+ ctx.nuxt.moduleResolver.resolve("runtime/plugins/types")
621
+ ));
622
+ const nuxt5 = getMajor(ctx.nuxt.nuxtVersion) > 4;
623
+ addTemplate({
624
+ write: true,
625
+ filename: "types/pwa-augments.d.ts",
626
+ getContents: () => prepareVueModuleAugmentation(
627
+ pwaInjectionPath,
628
+ nuxt5
629
+ )
630
+ });
631
+ const pwaPath = addTemplate({
632
+ filename: "types/pwa.d.ts",
633
+ write: true,
634
+ getContents: () => templates.map(
635
+ (t) => `/// <reference path="../${t}" />`
636
+ ).join("\n")
637
+ }).dst;
638
+ nuxt.hook("prepare:types", (context) => {
639
+ context.references.push({ path: pwaPath });
640
+ if (getMajor(ctx.nuxt.nuxtVersion) >= 4) {
641
+ context.nodeReferences.push({ path: pwaPath });
642
+ }
643
+ });
644
+ }
645
+ function prepareVueModuleAugmentation(pwaInjectionPath, nuxt5) {
646
+ const footer = nuxt5 ? "" : `
647
+ export {}
648
+ `;
649
+ return `// Generated by @vite-pwa/nuxt
650
+ import { UnwrapNestedRefs } from 'vue'
651
+ import { PWAIcons } from '#build/pwa-icons'
652
+ import { PwaInjection, PwaInstallPromptInjection } from '${pwaInjectionPath}'
653
+
654
+ declare module '#app' {
655
+ interface NuxtApp {
656
+ /**
657
+ * Reactive PWA state and controls provided by \`@vite-pwa/nuxt\`.
658
+ *
659
+ * @example
660
+ * \`\`\`ts
661
+ * const { $pwa } = useNuxtApp()
662
+ * if ($pwa?.needRefresh) await $pwa.updateServiceWorker()
663
+ * \`\`\`
664
+ */
665
+ $pwa?: UnwrapNestedRefs<PwaInjection>
666
+ /**
667
+ * Internal usage, use \`$pwa\` instead.
668
+ */
669
+ $pwaInstallPrompt: PwaInstallPromptInjection
670
+ /**
671
+ * Available PWA icons.
672
+ */
673
+ $pwaIcons?: PWAIcons
674
+ }
675
+ }
676
+
677
+ declare module 'vue' {
678
+ interface ComponentCustomProperties {
679
+ /**
680
+ * Reactive PWA state and controls provided by \`@vite-pwa/nuxt\`.
681
+ *
682
+ * @example
683
+ * \`\`\`ts
684
+ * const { $pwa } = useNuxtApp()
685
+ * if ($pwa?.needRefresh) await $pwa.updateServiceWorker()
686
+ * \`\`\`
687
+ */
688
+ $pwa?: UnwrapNestedRefs<PwaInjection>
689
+ /**
690
+ * Internal usage, use \`$pwa\` instead.
691
+ */
692
+ $pwaInstallPrompt: PwaInstallPromptInjection
693
+ /**
694
+ * Available PWA icons.
695
+ */
696
+ $pwaIcons?: PWAIcons
697
+ }
698
+ }
699
+ ${footer}
700
+ `;
701
+ }
702
+
703
+ function nitroInitHook(ctx, nuxt) {
704
+ return async (nitro) => {
705
+ ctx.resolvedOptions.includeManifestIcons = false;
706
+ ctx.resolvedOptions.includeManifestScreenshots = false;
707
+ ctx.resolvedOptions.includeManifestShortcutIcons = false;
708
+ ctx.publicDir = nuxt.options.dir.public;
709
+ ctx.rootDir = nuxt.options.rootDir;
710
+ if (nuxt.options.dev) {
711
+ ctx.devEnvironment = true;
712
+ const internalDevOptions = ctx.dev.options;
713
+ internalDevOptions.tempFolder = path.resolve(nuxt.options.buildDir, "pwa-dev/.dev-dist");
714
+ ctx.outDir = internalDevOptions.tempFolder;
715
+ } else {
716
+ ctx.outDir = normalizePath$1(nitro.options.output.publicDir);
717
+ }
718
+ ctx.resolvedOptions.outDir = ctx.outDir;
719
+ ctx.strategy = ctx.resolvedOptions.strategy;
720
+ ctx.resolvedOptions.base ??= ctx.base;
721
+ ctx.resolvedOptions.buildBase ??= ctx.base;
722
+ ctx.resolvedOptions.scope ??= ctx.base;
723
+ await prepareResolvedPwaOptions(ctx, nuxt, ctx.outDir);
724
+ await ctx.nuxt.preparePwaConfiguration?.();
725
+ await initPwaAssetsGenerator(ctx, nuxt);
726
+ await registerPwaIconsTypes(ctx, nuxt);
727
+ await prepareNitroRoutes(ctx, nuxt);
728
+ const routeRules = ctx.nuxt.nitroPWAOptions.routeRules;
729
+ if (Object.keys(routeRules).length > 0) {
730
+ for (const [route, rules] of Object.entries(routeRules)) {
731
+ nitro.options.routeRules[route] = defu(nitro.options.routeRules[route], rules);
732
+ }
733
+ nitro.routing?.sync();
734
+ }
735
+ };
736
+ }
737
+
738
+ function prepareTypesHook(ctx) {
739
+ return (context) => {
740
+ const unpluginPwaCoreDir = path.dirname(
741
+ createRequire(import.meta.url).resolve("@unplugin-pwa/core/package.json")
742
+ );
743
+ const references = [
744
+ {
745
+ path: ctx.nuxt.moduleResolver.resolve("../configuration.d.ts")
746
+ },
747
+ ...["vue.d.ts", "info.d.ts", "pwa-assets.d.ts"].map((file) => ({
748
+ path: path.join(unpluginPwaCoreDir, file)
749
+ })),
750
+ { path: "types/pwa-augments.d.ts" }
751
+ ];
752
+ context.references.push(...references);
753
+ if (getMajor(ctx.nuxt.nuxtVersion) >= 4) {
754
+ context.nodeReferences.push(...references);
755
+ }
756
+ };
757
+ }
758
+
759
+ function serverDevHandlerHook(ctx, nuxt) {
760
+ return async () => {
761
+ const devOptions = ctx.resolvedOptions.devOptions;
762
+ if (nuxt.options.dev && devOptions && devOptions.inspector) {
763
+ await ctx.hooks.callHook("context:ready");
764
+ }
765
+ };
766
+ }
767
+
768
+ async function prepareModule(ctx, nuxt) {
769
+ const resolver = ctx.nuxt.moduleResolver;
770
+ const consumerOptions = ctx.consumerOptions;
771
+ if (consumerOptions.path) {
772
+ consumerOptions.path = await resolver.resolvePath(
773
+ consumerOptions.path,
774
+ {
775
+ cwd: nuxt.options.rootDir,
776
+ alias: nuxt.options.alias
777
+ }
778
+ );
779
+ } else {
780
+ for (const dir of [nuxt.options.srcDir, nuxt.options.rootDir]) {
781
+ const resolvedPath = resolveDefaultConfig(dir);
782
+ if (resolvedPath) {
783
+ consumerOptions.path = normalizePath$1(resolvedPath);
784
+ break;
785
+ }
786
+ }
787
+ }
788
+ ctx.externalConfigurationLoader = true;
789
+ ctx.base ??= consumerOptions.base || "/";
790
+ consumerOptions.base ??= ctx.base;
791
+ consumerOptions.scope ??= ctx.base;
792
+ const publicDirs = /* @__PURE__ */ new Set();
793
+ for (const layer of nuxt.options._layers) {
794
+ publicDirs.add(normalizePath$1(resolver.resolve(layer.config.rootDir, layer.config.dir?.public || "public")));
795
+ }
796
+ ctx.nuxt.publicDirs = [...publicDirs].filter((dir) => existsSync(dir));
797
+ await loadPwaConfiguration(ctx, nuxt);
798
+ if (ctx.resolvedOptions.path) {
799
+ nuxt.options.watch.push(ctx.resolvedOptions.path);
800
+ applyExternalNuxtOptions(ctx);
801
+ }
802
+ const runtimeDir = resolver.resolve("./runtime");
803
+ nuxt.options.build.transpile.push(runtimeDir);
804
+ nuxt.options.alias["#pwa"] = resolver.resolve(runtimeDir, "composables");
805
+ if (ctx.nuxt.client.registerPlugin) {
806
+ addPlugin({
807
+ src: resolver.resolve(runtimeDir, "plugins/pwa.client"),
808
+ mode: "client"
809
+ });
810
+ addPlugin({
811
+ src: resolver.resolve(runtimeDir, "plugins/pwa-install.client"),
812
+ mode: "client"
813
+ });
814
+ }
815
+ nuxt.hook("nitro:config", nitroConfigHook(ctx, nuxt));
816
+ nuxt.hook("nitro:init", nitroInitHook(ctx, nuxt));
817
+ nuxt.hook("prepare:types", prepareTypesHook(ctx));
818
+ nuxt.hook("devtools:customTabs", devtoolsCustomTabsHook(ctx));
819
+ for (const name of ["NuxtPwaAssets", "NuxtPwaManifest"]) {
820
+ addComponent({
821
+ name,
822
+ global: !nuxt.options.imports.autoImport,
823
+ filePath: resolver.resolve(runtimeDir, `components/${name}`)
824
+ });
825
+ }
826
+ addImports([
827
+ "usePWA",
828
+ "useTransparentPwaIcon",
829
+ "useMaskablePwaIcon",
830
+ "useFaviconPwaIcon",
831
+ "useApplePwaIcon",
832
+ "useAppleSplashScreenPwaIcon"
833
+ ].map((name) => ({
834
+ name,
835
+ from: resolver.resolve(runtimeDir, "composables")
836
+ })));
837
+ nuxt.hook("server:devHandler", serverDevHandlerHook(ctx, nuxt));
838
+ nuxt.hook("build:before", buildBeforeHook(ctx));
839
+ if (!nuxt.options.dev) {
840
+ nuxt.hook("nitro:build:public-assets", async () => {
841
+ await buildPwaAssets(ctx, nuxt);
842
+ });
843
+ }
844
+ }
845
+ function applyExternalNuxtOptions(ctx) {
846
+ const {
847
+ client,
848
+ experimental,
849
+ registerWebManifestInRouteRules,
850
+ writePlugin
851
+ } = ctx.resolvedOptions;
852
+ if (client) {
853
+ Object.assign(ctx.nuxt.client, client);
854
+ }
855
+ if (experimental) {
856
+ ctx.nuxt.experimental = experimental;
857
+ }
858
+ if (registerWebManifestInRouteRules !== void 0) {
859
+ ctx.nuxt.registerWebManifestInRouteRules = registerWebManifestInRouteRules;
860
+ }
861
+ if (writePlugin !== void 0) {
862
+ ctx.nuxt.writePlugin = writePlugin;
863
+ }
864
+ }
865
+
866
+ const prepareModule$1 = {
867
+ __proto__: null,
868
+ prepareModule: prepareModule
869
+ };
870
+
871
+ export { prepareModule$1 as a, generatePwaImageType as g, pwaIcons as p };