@serwist/nuxt 9.5.7 → 9.5.9
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/dist/module.json +2 -2
- package/dist/module.mjs +3 -2
- package/dist/module.mjs.map +1 -0
- package/package.json +11 -10
- package/src/config.ts +111 -0
- package/src/module.ts +125 -0
- package/src/runtime/plugins/augmentation.d.ts +19 -0
- package/src/runtime/plugins/client.ts +15 -0
- package/src/types.ts +22 -0
- package/src/utils.ts +33 -0
- package/src/virtual-configuration.d.ts +3 -0
package/dist/module.json
CHANGED
package/dist/module.mjs
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import path from 'node:path';
|
|
2
1
|
import { defineNuxtModule, createResolver, addPlugin, extendWebpackConfig } from '@nuxt/kit';
|
|
3
2
|
import { createContext, createApi, main, dev, resolveEntry } from '@serwist/vite';
|
|
3
|
+
import path from 'node:path';
|
|
4
4
|
import { createHash } from 'node:crypto';
|
|
5
5
|
import { createReadStream } from 'node:fs';
|
|
6
6
|
import fsp from 'node:fs/promises';
|
|
7
7
|
import { DEFAULT_GLOB_PATTERNS } from '@serwist/build';
|
|
8
8
|
|
|
9
|
-
const version = "9.5.
|
|
9
|
+
const version = "9.5.9";
|
|
10
10
|
|
|
11
11
|
const configureSerwistOptions = (options, nuxt, nitroConfig) => {
|
|
12
12
|
let buildAssetsDir = nuxt.options.app.buildAssetsDir ?? "_nuxt/";
|
|
@@ -177,3 +177,4 @@ const module$1 = defineNuxtModule().with({
|
|
|
177
177
|
});
|
|
178
178
|
|
|
179
179
|
export { module$1 as default };
|
|
180
|
+
//# sourceMappingURL=module.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"module.mjs","sources":["../src/config.ts","../src/module.ts"],"sourcesContent":["import { createHash } from \"node:crypto\";\nimport { createReadStream } from \"node:fs\";\nimport fsp from \"node:fs/promises\";\nimport path from \"node:path\";\nimport type { Nuxt } from \"@nuxt/schema\";\nimport type { ManifestTransform } from \"@serwist/build\";\nimport { DEFAULT_GLOB_PATTERNS } from \"@serwist/build\";\nimport type { PluginOptions } from \"@serwist/vite\";\nimport type { NitroConfig } from \"nitropack\";\n\nexport const configureSerwistOptions = (options: PluginOptions, nuxt: Nuxt, nitroConfig: NitroConfig) => {\n let buildAssetsDir = nuxt.options.app.buildAssetsDir ?? \"_nuxt/\";\n if (buildAssetsDir[0] === \"/\") buildAssetsDir = buildAssetsDir.slice(1);\n if (buildAssetsDir[buildAssetsDir.length - 1] !== \"/\") buildAssetsDir += \"/\";\n\n // Vite 5 support: allow override dontCacheBustURLsMatching\n if (!(\"dontCacheBustURLsMatching\" in options)) {\n options.dontCacheBustURLsMatching = new RegExp(buildAssetsDir);\n }\n\n options.globPatterns = options.globPatterns ?? DEFAULT_GLOB_PATTERNS;\n\n // Handle `payloadExtraction`.\n if (\n nuxt.options.experimental.payloadExtraction &&\n // Has prerendered routes\n (nuxt.options.nitro.static ||\n (nuxt.options as any)._generate /* TODO(v10): remove in future */ ||\n !!nitroConfig.prerender?.routes?.length ||\n Object.values(nitroConfig.routeRules ?? {}).some((r: any) => r.prerender))\n ) {\n options.globPatterns.push(\"**/_payload.json\");\n }\n\n // Handle Nuxt's App Manifest\n let appManifestFolder: string | undefined;\n if (nuxt.options.experimental.appManifest) {\n appManifestFolder = `${buildAssetsDir}builds/`;\n options.globPatterns.push(`${appManifestFolder}**/*.json`);\n }\n\n const _public = nitroConfig.output?.publicDir ?? nuxt.options.nitro?.output?.publicDir;\n\n const publicDir = _public ? path.resolve(_public) : path.resolve(nuxt.options.rootDir, \".output/public\");\n\n options.swDest = options.swDest\n ? path.isAbsolute(options.swDest)\n ? options.swDest\n : path.resolve(publicDir, options.swDest)\n : path.resolve(publicDir, \"sw.js\");\n options.globDirectory = options.globDirectory || publicDir;\n\n // allow override manifestTransforms\n if (!nuxt.options.dev && !options.manifestTransforms) {\n options.manifestTransforms = [createManifestTransform(nuxt.options.app.baseURL ?? \"/\", publicDir, appManifestFolder)];\n }\n};\n\nfunction createManifestTransform(base: string, publicDir: string, appManifestFolder?: string): ManifestTransform {\n return async (entries) => {\n entries\n .filter((e) => e.url.endsWith(\".html\"))\n .forEach((e) => {\n const url = e.url.startsWith(\"/\") ? e.url.slice(1) : e.url;\n if (url === \"index.html\") {\n e.url = base;\n } else {\n const parts = url.split(\"/\");\n parts[parts.length - 1] = parts[parts.length - 1]!.replace(/\\.html$/, \"\");\n e.url = parts.length > 1 ? parts.slice(0, parts.length - 1).join(\"/\") : parts[0]!;\n }\n });\n\n if (appManifestFolder) {\n // this shouldn't be necessary, since we are using dontCacheBustURLsMatching\n 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;\n // we need to remove the revision from the sw prechaing manifest, UUID is enough:\n // we don't use dontCacheBustURLsMatching, single regex\n entries\n .filter((e) => e.url.startsWith(appManifestFolder) && regExp.test(e.url))\n .forEach((e) => {\n e.revision = null;\n });\n // add revision to latest.json file: we are excluding `_nuxt/` assets from dontCacheBustURLsMatching\n const latest = `${appManifestFolder}latest.json`;\n const latestJson = path.resolve(publicDir, latest);\n const data = await fsp.lstat(latestJson).catch(() => undefined);\n if (data?.isFile()) {\n const revision = await new Promise<string>((resolve, reject) => {\n const cHash = createHash(\"MD5\");\n const stream = createReadStream(latestJson);\n stream.on(\"error\", (err) => {\n reject(err);\n });\n stream.on(\"data\", (chunk) => cHash.update(chunk));\n stream.on(\"end\", () => {\n resolve(cHash.digest(\"hex\"));\n });\n });\n\n const latestEntry = entries.find((e) => e.url === latest);\n if (latestEntry) latestEntry.revision = revision;\n else entries.push({ url: latest, revision, size: data.size });\n } else {\n entries = entries.filter((e) => e.url !== latest);\n }\n }\n\n return { manifest: entries, warnings: [] };\n };\n}\n","import { addPlugin, createResolver, defineNuxtModule, extendWebpackConfig } from \"@nuxt/kit\";\nimport type { SerwistViteApi, SerwistViteContext } from \"@serwist/vite\";\nimport { createApi, createContext, dev as devPlugin, main as mainPlugin, resolveEntry } from \"@serwist/vite\";\nimport path from \"node:path\";\nimport type { ViteConfig } from \"nuxt/schema\";\nimport { version } from \"../package.json\";\nimport { configureSerwistOptions } from \"./config.js\";\nimport type { ClientOptions, DefaultModuleOptions, ModuleOptions } from \"./types.js\";\n\nexport * from \"./types.js\";\n\nexport default defineNuxtModule<ModuleOptions>().with<DefaultModuleOptions>({\n meta: {\n name: \"@serwist/nuxt\",\n configKey: \"serwist\",\n compatibility: {\n nuxt: \"^3.8.0 || ^4.0.0\",\n },\n version,\n },\n defaults(nuxt) {\n return {\n base: nuxt.options.app.baseURL,\n scope: nuxt.options.app.baseURL,\n client: {\n registerPlugin: true,\n },\n // Try to find `service-worker.{ts,js}` or `service-worker/index.{ts,js}`. If not found,\n // force the user to provide a `swSrc` themself.\n swSrc: resolveEntry(path.resolve(nuxt.options.rootDir, \"service-worker\")) || undefined!,\n // If `swDest` is not set by `configureSerwistOptions`, something is wrong.\n swDest: \"\",\n swUrl: \"/sw.js\",\n // If `globDirectory` is not set by `configureSerwistOptions`, something is wrong.\n globDirectory: \"\",\n injectionPoint: \"self.__SW_MANIFEST\",\n };\n },\n async setup(_options, nuxt) {\n const resolver = createResolver(import.meta.url);\n\n let ctx: SerwistViteContext | undefined;\n let api: SerwistViteApi | undefined;\n\n const { client: _client, ...options } = _options;\n\n const client = { registerPlugin: true, ..._client } satisfies ClientOptions;\n\n const runtimeDir = resolver.resolve(\"./runtime\");\n\n if (!nuxt.options.ssr) nuxt.options.build.transpile.push(runtimeDir);\n\n if (client.registerPlugin) {\n addPlugin({\n src: resolver.resolve(runtimeDir, \"plugins/client\"),\n mode: \"client\",\n });\n }\n\n nuxt.hook(\"prepare:types\", ({ references }) => {\n references.push({ path: resolver.resolve(runtimeDir, \"plugins/augmentation.d.ts\") });\n });\n\n nuxt.hook(\"nitro:init\", (nitro) => {\n configureSerwistOptions(options, nuxt, nitro.options);\n });\n\n nuxt.hook(\"vite:extend\", ({ config }) => {\n const plugin = config.plugins?.find((p) => p && typeof p === \"object\" && \"name\" in p && p.name === \"@serwist/vite\");\n if (plugin) {\n throw new Error(\"Remove '@serwist/vite' from your Vite configuration! Do not use it alongside '@serwist/nuxt'.\");\n }\n });\n\n nuxt.hook(\"vite:extendConfig\", async (viteInlineConfig: ViteConfig, { isClient }) => {\n if (!viteInlineConfig.plugins) {\n viteInlineConfig.plugins = [];\n }\n const plugin = viteInlineConfig.plugins.find((p) => p && typeof p === \"object\" && \"name\" in p && p.name === \"@serwist/vite\");\n if (plugin) {\n throw new Error(\"Remove '@serwist/vite' from your Vite configuration! Do not use it alongside '@serwist/nuxt'.\");\n }\n\n if (isClient) {\n const configuration = \"virtual:serwist-nuxt-configuration\";\n const resolvedConfiguration = `\\0${configuration}`;\n viteInlineConfig.plugins.push({\n name: \"@serwist/nuxt:configuration\",\n enforce: \"pre\",\n resolveId(id) {\n if (id === configuration) {\n return resolvedConfiguration;\n }\n return undefined;\n },\n async load(id) {\n if (id === resolvedConfiguration) {\n return `export const enabled = ${client.registerPlugin};`;\n }\n\n return undefined;\n },\n });\n }\n\n ctx = createContext(options, \"nuxt\");\n api = createApi(ctx);\n const plugins = [mainPlugin(ctx, api), devPlugin(ctx, api)];\n viteInlineConfig.plugins.push(plugins);\n });\n\n extendWebpackConfig(() => {\n throw new Error(\"Webpack is not supported: '@serwist/nuxt' can only be used with Vite!\");\n });\n\n if (!nuxt.options.dev) {\n nuxt.hook(\"nitro:build:public-assets\", () => {\n if (!api || api.disabled) {\n return;\n }\n void api.generateSW();\n });\n }\n },\n});\n"],"names":["mainPlugin","devPlugin"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@serwist/nuxt",
|
|
3
|
-
"version": "9.5.
|
|
3
|
+
"version": "9.5.9",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "A Nuxt module that integrates Serwist into your application.",
|
|
6
6
|
"files": [
|
|
7
|
+
"src",
|
|
7
8
|
"dist"
|
|
8
9
|
],
|
|
9
10
|
"keywords": [
|
|
@@ -51,22 +52,22 @@
|
|
|
51
52
|
},
|
|
52
53
|
"dependencies": {
|
|
53
54
|
"@nuxt/kit": "4.4.2",
|
|
54
|
-
"@serwist/build": "9.5.
|
|
55
|
-
"@serwist/utils": "9.5.
|
|
56
|
-
"@serwist/vite": "9.5.
|
|
57
|
-
"@serwist/window": "9.5.
|
|
55
|
+
"@serwist/build": "9.5.9",
|
|
56
|
+
"@serwist/utils": "9.5.9",
|
|
57
|
+
"@serwist/vite": "9.5.9",
|
|
58
|
+
"@serwist/window": "9.5.9"
|
|
58
59
|
},
|
|
59
60
|
"devDependencies": {
|
|
60
61
|
"@nuxt/module-builder": "1.0.2",
|
|
61
62
|
"@nuxt/schema": "4.4.2",
|
|
62
|
-
"@types/node": "25.
|
|
63
|
+
"@types/node": "25.6.0",
|
|
63
64
|
"nuxt": "4.4.2",
|
|
64
65
|
"rimraf": "5.0.10",
|
|
65
66
|
"serve": "14.2.6",
|
|
66
|
-
"typescript": "
|
|
67
|
-
"
|
|
68
|
-
"
|
|
69
|
-
"
|
|
67
|
+
"typescript": "6.0.3",
|
|
68
|
+
"unbuild": "3.6.1",
|
|
69
|
+
"vite": "8.0.10",
|
|
70
|
+
"vue-tsc": "3.2.7"
|
|
70
71
|
},
|
|
71
72
|
"peerDependencies": {
|
|
72
73
|
"typescript": ">=5.0.0",
|
package/src/config.ts
ADDED
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { createReadStream } from "node:fs";
|
|
3
|
+
import fsp from "node:fs/promises";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
import type { Nuxt } from "@nuxt/schema";
|
|
6
|
+
import type { ManifestTransform } from "@serwist/build";
|
|
7
|
+
import { DEFAULT_GLOB_PATTERNS } from "@serwist/build";
|
|
8
|
+
import type { PluginOptions } from "@serwist/vite";
|
|
9
|
+
import type { NitroConfig } from "nitropack";
|
|
10
|
+
|
|
11
|
+
export const configureSerwistOptions = (options: PluginOptions, nuxt: Nuxt, nitroConfig: NitroConfig) => {
|
|
12
|
+
let buildAssetsDir = nuxt.options.app.buildAssetsDir ?? "_nuxt/";
|
|
13
|
+
if (buildAssetsDir[0] === "/") buildAssetsDir = buildAssetsDir.slice(1);
|
|
14
|
+
if (buildAssetsDir[buildAssetsDir.length - 1] !== "/") buildAssetsDir += "/";
|
|
15
|
+
|
|
16
|
+
// Vite 5 support: allow override dontCacheBustURLsMatching
|
|
17
|
+
if (!("dontCacheBustURLsMatching" in options)) {
|
|
18
|
+
options.dontCacheBustURLsMatching = new RegExp(buildAssetsDir);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
options.globPatterns = options.globPatterns ?? DEFAULT_GLOB_PATTERNS;
|
|
22
|
+
|
|
23
|
+
// Handle `payloadExtraction`.
|
|
24
|
+
if (
|
|
25
|
+
nuxt.options.experimental.payloadExtraction &&
|
|
26
|
+
// Has prerendered routes
|
|
27
|
+
(nuxt.options.nitro.static ||
|
|
28
|
+
(nuxt.options as any)._generate /* TODO(v10): remove in future */ ||
|
|
29
|
+
!!nitroConfig.prerender?.routes?.length ||
|
|
30
|
+
Object.values(nitroConfig.routeRules ?? {}).some((r: any) => r.prerender))
|
|
31
|
+
) {
|
|
32
|
+
options.globPatterns.push("**/_payload.json");
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Handle Nuxt's App Manifest
|
|
36
|
+
let appManifestFolder: string | undefined;
|
|
37
|
+
if (nuxt.options.experimental.appManifest) {
|
|
38
|
+
appManifestFolder = `${buildAssetsDir}builds/`;
|
|
39
|
+
options.globPatterns.push(`${appManifestFolder}**/*.json`);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const _public = nitroConfig.output?.publicDir ?? nuxt.options.nitro?.output?.publicDir;
|
|
43
|
+
|
|
44
|
+
const publicDir = _public ? path.resolve(_public) : path.resolve(nuxt.options.rootDir, ".output/public");
|
|
45
|
+
|
|
46
|
+
options.swDest = options.swDest
|
|
47
|
+
? path.isAbsolute(options.swDest)
|
|
48
|
+
? options.swDest
|
|
49
|
+
: path.resolve(publicDir, options.swDest)
|
|
50
|
+
: path.resolve(publicDir, "sw.js");
|
|
51
|
+
options.globDirectory = options.globDirectory || publicDir;
|
|
52
|
+
|
|
53
|
+
// allow override manifestTransforms
|
|
54
|
+
if (!nuxt.options.dev && !options.manifestTransforms) {
|
|
55
|
+
options.manifestTransforms = [createManifestTransform(nuxt.options.app.baseURL ?? "/", publicDir, appManifestFolder)];
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
function createManifestTransform(base: string, publicDir: string, appManifestFolder?: string): ManifestTransform {
|
|
60
|
+
return async (entries) => {
|
|
61
|
+
entries
|
|
62
|
+
.filter((e) => e.url.endsWith(".html"))
|
|
63
|
+
.forEach((e) => {
|
|
64
|
+
const url = e.url.startsWith("/") ? e.url.slice(1) : e.url;
|
|
65
|
+
if (url === "index.html") {
|
|
66
|
+
e.url = base;
|
|
67
|
+
} else {
|
|
68
|
+
const parts = url.split("/");
|
|
69
|
+
parts[parts.length - 1] = parts[parts.length - 1]!.replace(/\.html$/, "");
|
|
70
|
+
e.url = parts.length > 1 ? parts.slice(0, parts.length - 1).join("/") : parts[0]!;
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
if (appManifestFolder) {
|
|
75
|
+
// this shouldn't be necessary, since we are using dontCacheBustURLsMatching
|
|
76
|
+
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;
|
|
77
|
+
// we need to remove the revision from the sw prechaing manifest, UUID is enough:
|
|
78
|
+
// we don't use dontCacheBustURLsMatching, single regex
|
|
79
|
+
entries
|
|
80
|
+
.filter((e) => e.url.startsWith(appManifestFolder) && regExp.test(e.url))
|
|
81
|
+
.forEach((e) => {
|
|
82
|
+
e.revision = null;
|
|
83
|
+
});
|
|
84
|
+
// add revision to latest.json file: we are excluding `_nuxt/` assets from dontCacheBustURLsMatching
|
|
85
|
+
const latest = `${appManifestFolder}latest.json`;
|
|
86
|
+
const latestJson = path.resolve(publicDir, latest);
|
|
87
|
+
const data = await fsp.lstat(latestJson).catch(() => undefined);
|
|
88
|
+
if (data?.isFile()) {
|
|
89
|
+
const revision = await new Promise<string>((resolve, reject) => {
|
|
90
|
+
const cHash = createHash("MD5");
|
|
91
|
+
const stream = createReadStream(latestJson);
|
|
92
|
+
stream.on("error", (err) => {
|
|
93
|
+
reject(err);
|
|
94
|
+
});
|
|
95
|
+
stream.on("data", (chunk) => cHash.update(chunk));
|
|
96
|
+
stream.on("end", () => {
|
|
97
|
+
resolve(cHash.digest("hex"));
|
|
98
|
+
});
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
const latestEntry = entries.find((e) => e.url === latest);
|
|
102
|
+
if (latestEntry) latestEntry.revision = revision;
|
|
103
|
+
else entries.push({ url: latest, revision, size: data.size });
|
|
104
|
+
} else {
|
|
105
|
+
entries = entries.filter((e) => e.url !== latest);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
return { manifest: entries, warnings: [] };
|
|
110
|
+
};
|
|
111
|
+
}
|
package/src/module.ts
ADDED
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import { addPlugin, createResolver, defineNuxtModule, extendWebpackConfig } from "@nuxt/kit";
|
|
2
|
+
import type { SerwistViteApi, SerwistViteContext } from "@serwist/vite";
|
|
3
|
+
import { createApi, createContext, dev as devPlugin, main as mainPlugin, resolveEntry } from "@serwist/vite";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
import type { ViteConfig } from "nuxt/schema";
|
|
6
|
+
import { version } from "../package.json";
|
|
7
|
+
import { configureSerwistOptions } from "./config.js";
|
|
8
|
+
import type { ClientOptions, DefaultModuleOptions, ModuleOptions } from "./types.js";
|
|
9
|
+
|
|
10
|
+
export * from "./types.js";
|
|
11
|
+
|
|
12
|
+
export default defineNuxtModule<ModuleOptions>().with<DefaultModuleOptions>({
|
|
13
|
+
meta: {
|
|
14
|
+
name: "@serwist/nuxt",
|
|
15
|
+
configKey: "serwist",
|
|
16
|
+
compatibility: {
|
|
17
|
+
nuxt: "^3.8.0 || ^4.0.0",
|
|
18
|
+
},
|
|
19
|
+
version,
|
|
20
|
+
},
|
|
21
|
+
defaults(nuxt) {
|
|
22
|
+
return {
|
|
23
|
+
base: nuxt.options.app.baseURL,
|
|
24
|
+
scope: nuxt.options.app.baseURL,
|
|
25
|
+
client: {
|
|
26
|
+
registerPlugin: true,
|
|
27
|
+
},
|
|
28
|
+
// Try to find `service-worker.{ts,js}` or `service-worker/index.{ts,js}`. If not found,
|
|
29
|
+
// force the user to provide a `swSrc` themself.
|
|
30
|
+
swSrc: resolveEntry(path.resolve(nuxt.options.rootDir, "service-worker")) || undefined!,
|
|
31
|
+
// If `swDest` is not set by `configureSerwistOptions`, something is wrong.
|
|
32
|
+
swDest: "",
|
|
33
|
+
swUrl: "/sw.js",
|
|
34
|
+
// If `globDirectory` is not set by `configureSerwistOptions`, something is wrong.
|
|
35
|
+
globDirectory: "",
|
|
36
|
+
injectionPoint: "self.__SW_MANIFEST",
|
|
37
|
+
};
|
|
38
|
+
},
|
|
39
|
+
async setup(_options, nuxt) {
|
|
40
|
+
const resolver = createResolver(import.meta.url);
|
|
41
|
+
|
|
42
|
+
let ctx: SerwistViteContext | undefined;
|
|
43
|
+
let api: SerwistViteApi | undefined;
|
|
44
|
+
|
|
45
|
+
const { client: _client, ...options } = _options;
|
|
46
|
+
|
|
47
|
+
const client = { registerPlugin: true, ..._client } satisfies ClientOptions;
|
|
48
|
+
|
|
49
|
+
const runtimeDir = resolver.resolve("./runtime");
|
|
50
|
+
|
|
51
|
+
if (!nuxt.options.ssr) nuxt.options.build.transpile.push(runtimeDir);
|
|
52
|
+
|
|
53
|
+
if (client.registerPlugin) {
|
|
54
|
+
addPlugin({
|
|
55
|
+
src: resolver.resolve(runtimeDir, "plugins/client"),
|
|
56
|
+
mode: "client",
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
nuxt.hook("prepare:types", ({ references }) => {
|
|
61
|
+
references.push({ path: resolver.resolve(runtimeDir, "plugins/augmentation.d.ts") });
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
nuxt.hook("nitro:init", (nitro) => {
|
|
65
|
+
configureSerwistOptions(options, nuxt, nitro.options);
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
nuxt.hook("vite:extend", ({ config }) => {
|
|
69
|
+
const plugin = config.plugins?.find((p) => p && typeof p === "object" && "name" in p && p.name === "@serwist/vite");
|
|
70
|
+
if (plugin) {
|
|
71
|
+
throw new Error("Remove '@serwist/vite' from your Vite configuration! Do not use it alongside '@serwist/nuxt'.");
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
nuxt.hook("vite:extendConfig", async (viteInlineConfig: ViteConfig, { isClient }) => {
|
|
76
|
+
if (!viteInlineConfig.plugins) {
|
|
77
|
+
viteInlineConfig.plugins = [];
|
|
78
|
+
}
|
|
79
|
+
const plugin = viteInlineConfig.plugins.find((p) => p && typeof p === "object" && "name" in p && p.name === "@serwist/vite");
|
|
80
|
+
if (plugin) {
|
|
81
|
+
throw new Error("Remove '@serwist/vite' from your Vite configuration! Do not use it alongside '@serwist/nuxt'.");
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
if (isClient) {
|
|
85
|
+
const configuration = "virtual:serwist-nuxt-configuration";
|
|
86
|
+
const resolvedConfiguration = `\0${configuration}`;
|
|
87
|
+
viteInlineConfig.plugins.push({
|
|
88
|
+
name: "@serwist/nuxt:configuration",
|
|
89
|
+
enforce: "pre",
|
|
90
|
+
resolveId(id) {
|
|
91
|
+
if (id === configuration) {
|
|
92
|
+
return resolvedConfiguration;
|
|
93
|
+
}
|
|
94
|
+
return undefined;
|
|
95
|
+
},
|
|
96
|
+
async load(id) {
|
|
97
|
+
if (id === resolvedConfiguration) {
|
|
98
|
+
return `export const enabled = ${client.registerPlugin};`;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
return undefined;
|
|
102
|
+
},
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
ctx = createContext(options, "nuxt");
|
|
107
|
+
api = createApi(ctx);
|
|
108
|
+
const plugins = [mainPlugin(ctx, api), devPlugin(ctx, api)];
|
|
109
|
+
viteInlineConfig.plugins.push(plugins);
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
extendWebpackConfig(() => {
|
|
113
|
+
throw new Error("Webpack is not supported: '@serwist/nuxt' can only be used with Vite!");
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
if (!nuxt.options.dev) {
|
|
117
|
+
nuxt.hook("nitro:build:public-assets", () => {
|
|
118
|
+
if (!api || api.disabled) {
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
void api.generateSW();
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
},
|
|
125
|
+
});
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { Serwist } from "@serwist/window";
|
|
2
|
+
|
|
3
|
+
declare module "#app" {
|
|
4
|
+
interface NuxtApp {
|
|
5
|
+
$serwist: Serwist | undefined;
|
|
6
|
+
}
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
declare module "vue" {
|
|
10
|
+
interface ComponentCustomProperties {
|
|
11
|
+
$serwist: Serwist | undefined;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
declare module "@vue/runtime-core" {
|
|
16
|
+
interface ComponentCustomProperties {
|
|
17
|
+
$serwist: Serwist | undefined;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { getSerwist } from "virtual:serwist";
|
|
2
|
+
import type { Serwist } from "@serwist/window";
|
|
3
|
+
import type { Plugin } from "#app";
|
|
4
|
+
import { defineNuxtPlugin } from "#imports";
|
|
5
|
+
|
|
6
|
+
const plugin: Plugin<{ serwist: Serwist | undefined }> = defineNuxtPlugin(async () => {
|
|
7
|
+
const serwist = await getSerwist();
|
|
8
|
+
return {
|
|
9
|
+
provide: {
|
|
10
|
+
serwist,
|
|
11
|
+
},
|
|
12
|
+
};
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
export default plugin;
|
package/src/types.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { PluginOptions } from "@serwist/vite";
|
|
2
|
+
import type { Optional, Require } from "./utils";
|
|
3
|
+
|
|
4
|
+
export interface ClientOptions {
|
|
5
|
+
/**
|
|
6
|
+
* Whether this plugin should be registered.
|
|
7
|
+
*/
|
|
8
|
+
registerPlugin?: boolean;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export interface ModuleOptions extends Optional<PluginOptions, "swSrc" | "swDest" | "globDirectory"> {
|
|
12
|
+
/**
|
|
13
|
+
* Options for plugin.
|
|
14
|
+
*/
|
|
15
|
+
client?: ClientOptions;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export type DefaultModuleKeys = "base" | "scope" | "client" | "swSrc" | "swDest" | "swUrl" | "globDirectory" | "injectionPoint";
|
|
19
|
+
|
|
20
|
+
export type DefaultModuleOptions = Required<Pick<ModuleOptions, DefaultModuleKeys>>;
|
|
21
|
+
|
|
22
|
+
export type ResolvedModuleOptions = Require<ModuleOptions, DefaultModuleKeys>;
|
package/src/utils.ts
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Make certain fields in a object type required
|
|
3
|
+
*
|
|
4
|
+
* @example
|
|
5
|
+
* interface A {
|
|
6
|
+
* a?: string;
|
|
7
|
+
* b?: string;
|
|
8
|
+
* c?: string;
|
|
9
|
+
* }
|
|
10
|
+
* type B = RequiredFields<A, "b" | "c">;
|
|
11
|
+
* const b: B = {
|
|
12
|
+
* b: "hehe",
|
|
13
|
+
* c: "hehe",
|
|
14
|
+
* }; //valid
|
|
15
|
+
* const b: B = { a: "hehe" }; //invalid
|
|
16
|
+
* const c: B = { a: "hehe", b: "hehe" }; //invalid
|
|
17
|
+
*/
|
|
18
|
+
export type Require<T, U extends keyof T> = T & Required<Pick<T, U>>;
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Make certain fields in a object type optional
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* interface A {
|
|
25
|
+
* a: string;
|
|
26
|
+
* b: string;
|
|
27
|
+
* c: string;
|
|
28
|
+
* }
|
|
29
|
+
* type B = Optional<A, "b" | "c">;
|
|
30
|
+
* const b: B = { a: "hehe" }; //valid
|
|
31
|
+
* const b: B = {}; //invalid
|
|
32
|
+
*/
|
|
33
|
+
export type Optional<T, U extends keyof T> = Omit<T, U> & Partial<Pick<T, U>>;
|