@sovereignbase/pwa 0.0.2 → 1.0.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.
- package/LICENSE +200 -200
- package/README.md +109 -0
- package/dist/{htmlDocument-Cx-dprM5.cjs → htmlDocument-C3k13Sjr.cjs} +3 -10
- package/dist/htmlDocument-C3k13Sjr.cjs.map +1 -0
- package/dist/{htmlDocument-DABSNDvf.js → htmlDocument-C533Sj5O.js} +3 -10
- package/dist/htmlDocument-C533Sj5O.js.map +1 -0
- package/dist/index.cjs +216 -38
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +60 -109
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.ts +60 -109
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +218 -40
- package/dist/index.js.map +1 -1
- package/dist/serviceWorker/entrypoint.cjs +13 -12
- package/dist/serviceWorker/entrypoint.cjs.map +1 -1
- package/dist/serviceWorker/entrypoint.js +13 -12
- package/dist/serviceWorker/entrypoint.js.map +1 -1
- package/package.json +1 -1
- package/dist/htmlDocument-Cx-dprM5.cjs.map +0 -1
- package/dist/htmlDocument-DABSNDvf.js.map +0 -1
package/dist/index.js
CHANGED
|
@@ -14,16 +14,18 @@
|
|
|
14
14
|
* limitations under the License.
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
|
-
import { t as documentMarkup } from "./htmlDocument-
|
|
17
|
+
import { t as documentMarkup } from "./htmlDocument-C533Sj5O.js";
|
|
18
|
+
import { createHash } from "node:crypto";
|
|
18
19
|
import { existsSync } from "node:fs";
|
|
19
|
-
import { cp, mkdir, readdir, writeFile } from "node:fs/promises";
|
|
20
|
-
import { basename, join, relative, sep } from "node:path";
|
|
20
|
+
import { cp, mkdir, readFile, readdir, writeFile } from "node:fs/promises";
|
|
21
|
+
import { basename, dirname, extname, join, relative, sep } from "node:path";
|
|
21
22
|
import { build } from "esbuild";
|
|
22
23
|
import { transform } from "lightningcss";
|
|
23
24
|
import { minify } from "html-minifier-terser";
|
|
24
25
|
import { fileURLToPath } from "node:url";
|
|
25
26
|
import { minify as minify$1 } from "terser";
|
|
26
27
|
//#region src/minifyCss/index.ts
|
|
28
|
+
const minifiedOutputs$2 = /* @__PURE__ */ new Map();
|
|
27
29
|
/** Bundles and minifies a CSS entrypoint into a dense string. */
|
|
28
30
|
async function minifyCss(entrypoint) {
|
|
29
31
|
const bundled = await build({
|
|
@@ -35,18 +37,26 @@ async function minifyCss(entrypoint) {
|
|
|
35
37
|
write: false,
|
|
36
38
|
external: ["/assets/*"]
|
|
37
39
|
});
|
|
40
|
+
const source = bundled.outputFiles[0].text;
|
|
41
|
+
const cached = minifiedOutputs$2.get(source);
|
|
42
|
+
if (cached !== void 0) return cached;
|
|
38
43
|
const { code } = transform({
|
|
39
44
|
code: bundled.outputFiles[0].contents,
|
|
40
45
|
filename: entrypoint.toString(),
|
|
41
46
|
minify: true
|
|
42
47
|
});
|
|
43
|
-
|
|
48
|
+
const output = new TextDecoder().decode(code).trim();
|
|
49
|
+
minifiedOutputs$2.set(source, output);
|
|
50
|
+
return output;
|
|
44
51
|
}
|
|
45
52
|
//#endregion
|
|
46
53
|
//#region src/minifyHtml/index.ts
|
|
54
|
+
const minifiedOutputs$1 = /* @__PURE__ */ new Map();
|
|
47
55
|
/** Minifies a complete HTML document, including inline CSS and JavaScript. */
|
|
48
56
|
async function minifyHtml(source) {
|
|
49
|
-
|
|
57
|
+
const cached = minifiedOutputs$1.get(source);
|
|
58
|
+
if (cached !== void 0) return cached;
|
|
59
|
+
const output = await minify(source, {
|
|
50
60
|
collapseBooleanAttributes: true,
|
|
51
61
|
collapseInlineTagWhitespace: true,
|
|
52
62
|
collapseWhitespace: true,
|
|
@@ -72,17 +82,21 @@ async function minifyHtml(source) {
|
|
|
72
82
|
sortClassName: true,
|
|
73
83
|
useShortDoctype: true
|
|
74
84
|
});
|
|
85
|
+
minifiedOutputs$1.set(source, output);
|
|
86
|
+
return output;
|
|
75
87
|
}
|
|
76
88
|
//#endregion
|
|
77
89
|
//#region src/minifyJs/index.ts
|
|
90
|
+
const minifiedOutputs = /* @__PURE__ */ new Map();
|
|
78
91
|
/** Bundles, tree-shakes, mangles, and repeatedly minifies JavaScript. */
|
|
79
|
-
async function minifyJs(input, { define, passes = 3 } = {}) {
|
|
80
|
-
|
|
92
|
+
async function minifyJs(input, { banner, define, passes = 3 } = {}) {
|
|
93
|
+
const output = (await build({
|
|
81
94
|
...typeof input === "object" && "source" in input ? { stdin: {
|
|
82
95
|
contents: input.source,
|
|
83
96
|
resolveDir: process.cwd()
|
|
84
97
|
} } : { entryPoints: [input instanceof URL ? fileURLToPath(input) : input.toString()] },
|
|
85
98
|
bundle: true,
|
|
99
|
+
banner: banner === void 0 ? void 0 : { js: banner },
|
|
86
100
|
define,
|
|
87
101
|
format: "esm",
|
|
88
102
|
legalComments: "none",
|
|
@@ -91,6 +105,15 @@ async function minifyJs(input, { define, passes = 3 } = {}) {
|
|
|
91
105
|
treeShaking: true,
|
|
92
106
|
write: false
|
|
93
107
|
})).outputFiles[0].text;
|
|
108
|
+
const cacheKey = `${passes}\0${output}`;
|
|
109
|
+
const cached = minifiedOutputs.get(cacheKey);
|
|
110
|
+
if (cached !== void 0) return cached;
|
|
111
|
+
const result = await repeatedlyMinify(output, passes);
|
|
112
|
+
minifiedOutputs.set(cacheKey, result);
|
|
113
|
+
return result;
|
|
114
|
+
}
|
|
115
|
+
async function repeatedlyMinify(source, passes) {
|
|
116
|
+
let output = source;
|
|
94
117
|
for (let round = 0; round < passes; round += 1) {
|
|
95
118
|
const result = await minify$1(output, {
|
|
96
119
|
compress: {
|
|
@@ -108,6 +131,7 @@ async function minifyJs(input, { define, passes = 3 } = {}) {
|
|
|
108
131
|
module: true,
|
|
109
132
|
toplevel: true
|
|
110
133
|
});
|
|
134
|
+
/* v8 ignore next 3 -- Terser returns code or rejects for this input form. */
|
|
111
135
|
if (result.code === void 0) throw new Error("Terser did not produce JavaScript output");
|
|
112
136
|
output = result.code;
|
|
113
137
|
}
|
|
@@ -158,35 +182,34 @@ const webManifest = ({ name, shortName, description, startUrl, themeColor, icon1
|
|
|
158
182
|
//#region src/index.ts
|
|
159
183
|
async function pwaize(config) {
|
|
160
184
|
const outputDirectory = join(config.outDir.toString(), "web");
|
|
161
|
-
const
|
|
185
|
+
const languages = [.../* @__PURE__ */ new Set([config.defaultLanguage, ...config.alternateLanguages])];
|
|
162
186
|
const minifyPasses = config.minifyPasses ?? 3;
|
|
163
187
|
const serviceWorkerPath = "/ServiceWorker";
|
|
164
188
|
await mkdir(outputDirectory, { recursive: true });
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
const sourceDirectory = directory.toString();
|
|
189
|
+
if (config.assetsDir !== void 0) {
|
|
190
|
+
const sourceDirectory = config.assetsDir.toString();
|
|
168
191
|
await cp(sourceDirectory, join(outputDirectory, basename(sourceDirectory)), { recursive: true });
|
|
169
192
|
}
|
|
193
|
+
if (config.i18nDir !== void 0) {
|
|
194
|
+
const sourceDirectory = config.i18nDir.toString();
|
|
195
|
+
await buildScriptDirectory(sourceDirectory, join(outputDirectory, basename(sourceDirectory)), minifyPasses);
|
|
196
|
+
}
|
|
170
197
|
const stylesheet = await minifyCss(config.stylesheet);
|
|
171
198
|
const entrypoint = await minifyJs(config.entrypoint, { passes: minifyPasses });
|
|
172
|
-
const installer = await minifyJs({ source: `
|
|
173
|
-
const
|
|
199
|
+
const installer = await minifyJs({ source: `await navigator.serviceWorker.register(${JSON.stringify(serviceWorkerPath)},{scope:"/",type:"module"});await navigator.serviceWorker.ready;location.reload();` }, { passes: minifyPasses });
|
|
200
|
+
const documentOptions = {};
|
|
174
201
|
for (const language of languages) {
|
|
175
|
-
const localized = config
|
|
176
|
-
if (localized === void 0) throw new Error(`Missing PWA configuration for language "${language}"`);
|
|
202
|
+
const localized = localizeConfig(config, language, languages);
|
|
177
203
|
const languageDirectory = join(outputDirectory, language);
|
|
178
204
|
const manifestPath = `/${language}/manifest.webmanifest`;
|
|
179
|
-
const manifest = webManifest(
|
|
180
|
-
|
|
181
|
-
lang: language
|
|
182
|
-
});
|
|
205
|
+
const manifest = webManifest(localized.manifest);
|
|
206
|
+
documentOptions[language] = localized.document;
|
|
183
207
|
await mkdir(languageDirectory, { recursive: true });
|
|
184
208
|
await writeFile(join(languageDirectory, "manifest.webmanifest"), manifest);
|
|
185
209
|
const installerDocument = await minifyHtml(await documentMarkup({
|
|
186
210
|
...localized.document,
|
|
187
|
-
language,
|
|
188
|
-
stylesheet: "",
|
|
189
211
|
entrypoint: installer,
|
|
212
|
+
language,
|
|
190
213
|
manifestUrl: manifestPath
|
|
191
214
|
}));
|
|
192
215
|
await writeFile(join(languageDirectory, "index.html"), installerDocument);
|
|
@@ -195,30 +218,73 @@ async function pwaize(config) {
|
|
|
195
218
|
await writeFile(join(outputDirectory, "manifest.webmanifest"), manifest);
|
|
196
219
|
}
|
|
197
220
|
}
|
|
198
|
-
const buildIdPath = join(outputDirectory, "@sovereignbase", "pwa", "pwaize-build-id.txt");
|
|
199
|
-
await mkdir(join(outputDirectory, "@sovereignbase", "pwa"), { recursive: true });
|
|
200
|
-
await writeFile(buildIdPath, buildId);
|
|
201
221
|
if (config._headersFile === true) await writeFile(join(outputDirectory, "_headers"), `/${serviceWorkerPath.slice(1)}\n Cache-Control: no-cache\n Content-Type: text/javascript;charset=UTF-8\n\n/*\n X-Content-Type-Options: nosniff\n`);
|
|
202
|
-
const
|
|
222
|
+
const buildIdUrl = "/@sovereignbase/pwa/pwaize-build-id.txt";
|
|
223
|
+
const generatedFiles = (await publicFiles(outputDirectory)).filter((url) => url !== serviceWorkerPath && url !== buildIdUrl);
|
|
224
|
+
const precache = [.../* @__PURE__ */ new Set([...generatedFiles, ...config.serviceWorker?.precache ?? []])].sort();
|
|
203
225
|
const bypassRules = (config.serviceWorker?.bypass ?? []).map(globRule);
|
|
204
|
-
const
|
|
205
|
-
const
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
entrypoint: JSON.stringify(entrypoint),
|
|
215
|
-
precache: JSON.stringify(precache),
|
|
216
|
-
stylesheet: JSON.stringify(stylesheet)
|
|
217
|
-
},
|
|
218
|
-
passes: minifyPasses
|
|
226
|
+
const initialize = config.serviceWorker?.initialize === void 0 ? "undefined" : functionExpression(config.serviceWorker.initialize);
|
|
227
|
+
const waitUntil = config.serviceWorker?.waitUntil === void 0 ? "undefined" : functionExpression(config.serviceWorker.waitUntil);
|
|
228
|
+
const buildId = await contentBuildId(outputDirectory, generatedFiles, {
|
|
229
|
+
bypassRules,
|
|
230
|
+
documentOptions,
|
|
231
|
+
entrypoint,
|
|
232
|
+
initialize,
|
|
233
|
+
precache,
|
|
234
|
+
stylesheet,
|
|
235
|
+
waitUntil
|
|
219
236
|
});
|
|
237
|
+
const buildIdDirectory = join(outputDirectory, "@sovereignbase", "pwa");
|
|
238
|
+
await mkdir(buildIdDirectory, { recursive: true });
|
|
239
|
+
await writeFile(join(buildIdDirectory, "pwaize-build-id.txt"), buildId);
|
|
240
|
+
const compiledServiceWorker = new URL("./serviceWorker/entrypoint.js", import.meta.url);
|
|
241
|
+
const serviceWorker = await minifyJs(
|
|
242
|
+
/* v8 ignore next -- the packaged .js path is exercised by runtime tests */
|
|
243
|
+
existsSync(compiledServiceWorker) ? compiledServiceWorker : new URL("./serviceWorker/entrypoint.ts", import.meta.url),
|
|
244
|
+
{
|
|
245
|
+
banner: `const __pwaInitialize=${initialize},__pwaWaitUntil=${waitUntil};`,
|
|
246
|
+
define: {
|
|
247
|
+
buildId: JSON.stringify(buildId),
|
|
248
|
+
buildIdUrl: JSON.stringify(buildIdUrl),
|
|
249
|
+
bypassRules: JSON.stringify(bypassRules),
|
|
250
|
+
customInitialize: "__pwaInitialize",
|
|
251
|
+
customWaitUntil: "__pwaWaitUntil",
|
|
252
|
+
defaultLanguage: JSON.stringify(config.defaultLanguage),
|
|
253
|
+
documentOptions: JSON.stringify(documentOptions),
|
|
254
|
+
entrypoint: JSON.stringify(entrypoint),
|
|
255
|
+
precache: JSON.stringify(precache),
|
|
256
|
+
stylesheet: JSON.stringify(stylesheet)
|
|
257
|
+
},
|
|
258
|
+
passes: minifyPasses
|
|
259
|
+
}
|
|
260
|
+
);
|
|
220
261
|
await writeFile(join(outputDirectory, serviceWorkerPath.slice(1)), serviceWorker);
|
|
221
262
|
}
|
|
263
|
+
async function buildScriptDirectory(sourceDirectory, outputDirectory, passes, root = sourceDirectory) {
|
|
264
|
+
for (const entry of await readdir(sourceDirectory, { withFileTypes: true })) {
|
|
265
|
+
const source = join(sourceDirectory, entry.name);
|
|
266
|
+
if (entry.isDirectory()) {
|
|
267
|
+
await buildScriptDirectory(source, outputDirectory, passes, root);
|
|
268
|
+
continue;
|
|
269
|
+
}
|
|
270
|
+
if (!entry.isFile() || entry.name.endsWith(".d.ts")) continue;
|
|
271
|
+
const relativePath = relative(root, source);
|
|
272
|
+
const extension = extname(relativePath);
|
|
273
|
+
const output = join(outputDirectory, /\.[cm]?[jt]sx?$/.test(extension) ? `${relativePath.slice(0, -extension.length)}.js` : relativePath);
|
|
274
|
+
await mkdir(dirname(output), { recursive: true });
|
|
275
|
+
if (/\.[cm]?[jt]sx?$/.test(extension)) await writeFile(output, await minifyJs(source, { passes }));
|
|
276
|
+
else await cp(source, output);
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
async function contentBuildId(outputDirectory, files, configuration) {
|
|
280
|
+
const hash = createHash("sha256");
|
|
281
|
+
hash.update(JSON.stringify(configuration));
|
|
282
|
+
for (const file of files) {
|
|
283
|
+
hash.update(file);
|
|
284
|
+
hash.update(await readFile(join(outputDirectory, ...file.slice(1).split("/"))));
|
|
285
|
+
}
|
|
286
|
+
return hash.digest("hex");
|
|
287
|
+
}
|
|
222
288
|
async function publicFiles(directory, root = directory) {
|
|
223
289
|
const entries = await readdir(directory, { withFileTypes: true });
|
|
224
290
|
const files = [];
|
|
@@ -252,6 +318,118 @@ function globRule(pattern) {
|
|
|
252
318
|
source: `${source}$`
|
|
253
319
|
};
|
|
254
320
|
}
|
|
321
|
+
function functionExpression(callback) {
|
|
322
|
+
const source = callback.toString();
|
|
323
|
+
if (/^(?:async\s+)?function\b|^(?:async\s+)?\(/.test(source)) return `(${source})`;
|
|
324
|
+
if (source.startsWith("async ")) return `(async function ${source.slice(6)})`;
|
|
325
|
+
return `(function ${source})`;
|
|
326
|
+
}
|
|
327
|
+
function localizeConfig(config, language, languages) {
|
|
328
|
+
const get = (value, empty) => localizedValue(value, language, config.defaultLanguage, empty);
|
|
329
|
+
const applicationName = get(config.applicationName, "");
|
|
330
|
+
const description = get(config.description, "");
|
|
331
|
+
const icon192 = get(config.icons.icon192, "");
|
|
332
|
+
const icon512 = get(config.icons.icon512, "");
|
|
333
|
+
const origin = get(config.origin, "");
|
|
334
|
+
const pageUrl = origin === "" ? "" : new URL(`/${language}`, origin).href;
|
|
335
|
+
const organizationLogo = origin === "" || icon512 === "" ? "" : new URL(icon512, origin).href;
|
|
336
|
+
const themeColor = get(config.themeColor, "");
|
|
337
|
+
const title = get(config.title, "");
|
|
338
|
+
return {
|
|
339
|
+
document: {
|
|
340
|
+
applicationName,
|
|
341
|
+
appleStatusBarStyle: get(config.appleStatusBarStyle, "black-translucent"),
|
|
342
|
+
appleTouchIconUrl: get(config.icons.appleTouchIconUrl, icon192),
|
|
343
|
+
bodyMarkup: get(config.bodyMarkup, ""),
|
|
344
|
+
colorScheme: get(config.colorScheme, "light dark"),
|
|
345
|
+
headMarkup: get(config.headMarkup, ""),
|
|
346
|
+
iconUrl: get(config.icons.iconUrl, icon512),
|
|
347
|
+
maskIconColor: themeColor,
|
|
348
|
+
maskIconUrl: get(config.icons.maskIconUrl, ""),
|
|
349
|
+
seo: {
|
|
350
|
+
jsonLD: {
|
|
351
|
+
application: {
|
|
352
|
+
applicationCategory: get(config.application?.category, ""),
|
|
353
|
+
browserRequirements: get(config.application?.browserRequirements, ""),
|
|
354
|
+
featureList: get(config.application?.featureList, []),
|
|
355
|
+
inLanguage: languages,
|
|
356
|
+
name: applicationName,
|
|
357
|
+
operatingSystem: get(config.application?.operatingSystem, ""),
|
|
358
|
+
url: origin
|
|
359
|
+
},
|
|
360
|
+
organization: {
|
|
361
|
+
logo: get(config.organization?.logoUrl, organizationLogo),
|
|
362
|
+
name: get(config.organization?.name, applicationName),
|
|
363
|
+
url: get(config.organization?.url, origin)
|
|
364
|
+
},
|
|
365
|
+
page: {
|
|
366
|
+
description,
|
|
367
|
+
inLanguage: language,
|
|
368
|
+
name: title,
|
|
369
|
+
url: pageUrl
|
|
370
|
+
},
|
|
371
|
+
site: {
|
|
372
|
+
name: applicationName,
|
|
373
|
+
url: origin
|
|
374
|
+
}
|
|
375
|
+
},
|
|
376
|
+
languageLinks: {
|
|
377
|
+
alternateLanguages: languages,
|
|
378
|
+
canonicalLanguage: config.canonicalLanguage,
|
|
379
|
+
defaultLanguage: config.defaultLanguage,
|
|
380
|
+
host: origin === "" ? "" : new URL(origin).host
|
|
381
|
+
},
|
|
382
|
+
openGraph: {
|
|
383
|
+
description,
|
|
384
|
+
imageAlt: get(config.socialImage.alt, ""),
|
|
385
|
+
imageHeight: get(config.socialImage.height, 630),
|
|
386
|
+
imageUrl: get(config.socialImage.url, ""),
|
|
387
|
+
imageWidth: get(config.socialImage.width, 1200),
|
|
388
|
+
locale: get(config.openGraphLocale, ""),
|
|
389
|
+
siteName: applicationName,
|
|
390
|
+
title,
|
|
391
|
+
url: pageUrl
|
|
392
|
+
},
|
|
393
|
+
twitter: {
|
|
394
|
+
creator: get(config.twitter.creator, ""),
|
|
395
|
+
description,
|
|
396
|
+
imageAlt: get(config.socialImage.alt, ""),
|
|
397
|
+
imageUrl: get(config.socialImage.url, ""),
|
|
398
|
+
site: get(config.twitter.site, ""),
|
|
399
|
+
title,
|
|
400
|
+
url: pageUrl
|
|
401
|
+
}
|
|
402
|
+
},
|
|
403
|
+
themeColor,
|
|
404
|
+
title
|
|
405
|
+
},
|
|
406
|
+
manifest: {
|
|
407
|
+
backgroundColor: get(config.backgroundColor, themeColor),
|
|
408
|
+
categories: get(config.manifest?.categories, []),
|
|
409
|
+
description,
|
|
410
|
+
display: get(config.manifest?.display, "standalone"),
|
|
411
|
+
icon192,
|
|
412
|
+
icon512,
|
|
413
|
+
id: get(config.manifest?.id, "/"),
|
|
414
|
+
lang: language,
|
|
415
|
+
maskableIcon512: get(config.icons.maskableIcon512, icon512),
|
|
416
|
+
name: applicationName,
|
|
417
|
+
orientation: get(config.manifest?.orientation, "any"),
|
|
418
|
+
scope: get(config.manifest?.scope, "/"),
|
|
419
|
+
screenshots: get(config.manifest?.screenshots, []),
|
|
420
|
+
shortName: get(config.shortName, applicationName),
|
|
421
|
+
shortcuts: get(config.manifest?.shortcuts, []),
|
|
422
|
+
startUrl: `/${language}`,
|
|
423
|
+
themeColor
|
|
424
|
+
}
|
|
425
|
+
};
|
|
426
|
+
}
|
|
427
|
+
function localizedValue(value, language, defaultLanguage, empty) {
|
|
428
|
+
if (value === void 0) return empty;
|
|
429
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) return value;
|
|
430
|
+
const values = value;
|
|
431
|
+
return values[language] ?? values[defaultLanguage] ?? empty;
|
|
432
|
+
}
|
|
255
433
|
//#endregion
|
|
256
434
|
export { pwaize };
|
|
257
435
|
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["minify"],"sources":["../src/minifyCss/index.ts","../src/minifyHtml/index.ts","../src/minifyJs/index.ts","../src/webManifest/index.ts","../src/index.ts"],"sourcesContent":["import type { PathLike } from 'node:fs'\nimport { build } from 'esbuild'\nimport { transform } from 'lightningcss'\n\n/** Bundles and minifies a CSS entrypoint into a dense string. */\nexport default async function minifyCss(entrypoint: PathLike): Promise<string> {\n const bundled = await build({\n entryPoints: [entrypoint.toString()],\n bundle: true,\n legalComments: 'none',\n minify: true,\n treeShaking: true,\n write: false,\n external: ['/assets/*'],\n })\n const { code } = transform({\n code: bundled.outputFiles[0].contents,\n filename: entrypoint.toString(),\n minify: true,\n })\n\n return new TextDecoder().decode(code).trim()\n}\n","import { minify } from 'html-minifier-terser'\n\n/** Minifies a complete HTML document, including inline CSS and JavaScript. */\nexport default async function minifyHtml(source: string): Promise<string> {\n return minify(source, {\n collapseBooleanAttributes: true,\n collapseInlineTagWhitespace: true,\n collapseWhitespace: true,\n decodeEntities: true,\n html5: true,\n minifyCSS: true,\n minifyJS: {\n compress: {\n dead_code: true,\n passes: 3,\n toplevel: true,\n unused: true,\n },\n mangle: {\n toplevel: true,\n },\n module: true,\n toplevel: true,\n },\n removeAttributeQuotes: true,\n removeComments: true,\n removeEmptyAttributes: true,\n removeRedundantAttributes: true,\n sortAttributes: true,\n sortClassName: true,\n useShortDoctype: true,\n })\n}\n","import type { PathLike } from 'node:fs'\nimport { fileURLToPath } from 'node:url'\nimport { build } from 'esbuild'\nimport { minify } from 'terser'\n\ntype JavaScriptInput = PathLike | { source: string }\n\ntype MinifyJsOptions = {\n define?: Record<string, string>\n passes?: number\n}\n\n/** Bundles, tree-shakes, mangles, and repeatedly minifies JavaScript. */\nexport default async function minifyJs(\n input: JavaScriptInput,\n { define, passes = 3 }: MinifyJsOptions = {}\n): Promise<string> {\n const bundled = await build({\n ...(typeof input === 'object' && 'source' in input\n ? { stdin: { contents: input.source, resolveDir: process.cwd() } }\n : {\n entryPoints: [\n input instanceof URL ? fileURLToPath(input) : input.toString(),\n ],\n }),\n bundle: true,\n define,\n format: 'esm',\n legalComments: 'none',\n minify: true,\n platform: 'browser',\n treeShaking: true,\n write: false,\n })\n\n let output = bundled.outputFiles[0].text\n\n for (let round = 0; round < passes; round += 1) {\n const result = await minify(output, {\n compress: {\n dead_code: true,\n passes,\n toplevel: true,\n unused: true,\n },\n ecma: 2024,\n format: {\n beautify: false,\n comments: false,\n },\n mangle: {\n toplevel: true,\n },\n module: true,\n toplevel: true,\n })\n\n if (result.code === undefined) {\n throw new Error('Terser did not produce JavaScript output')\n }\n\n output = result.code\n }\n\n return output\n}\n","import type { BCP47LanguageTag } from '@sovereignbase/utils'\n\ntype Path = `/${string}`\ntype ImageURL = Path | `https://${string}`\n\nexport interface WebManifestScreenshot {\n src: ImageURL\n sizes: `${number}x${number}`\n type?: `image/${string}`\n form_factor?: 'narrow' | 'wide'\n label?: string\n}\n\nexport interface WebManifestShortcut {\n name: string\n url: Path\n description?: string\n icons?: {\n src: ImageURL\n sizes: `${number}x${number}` | 'any'\n type?: `image/${string}`\n }[]\n}\n\nexport interface WebManifestOptions {\n name: string\n shortName: string\n description: string\n startUrl: Path\n themeColor: string\n icon192: ImageURL\n icon512: ImageURL\n maskableIcon512: ImageURL\n id?: Path\n scope?: Path\n backgroundColor?: string\n lang?: BCP47LanguageTag\n display?: 'standalone' | 'fullscreen' | 'minimal-ui' | 'browser'\n orientation?:\n | 'any'\n | 'natural'\n | 'portrait'\n | 'portrait-primary'\n | 'portrait-secondary'\n | 'landscape'\n | 'landscape-primary'\n | 'landscape-secondary'\n categories?: string[]\n screenshots?: WebManifestScreenshot[]\n shortcuts?: WebManifestShortcut[]\n}\n\n/**\n * Generates a standards-based Web App Manifest JSON string.\n */\nexport const webManifest = ({\n name,\n shortName,\n description,\n startUrl,\n themeColor,\n icon192,\n icon512,\n maskableIcon512,\n id = '/',\n scope = '/',\n backgroundColor = themeColor,\n lang,\n display = 'standalone',\n orientation,\n categories,\n screenshots,\n shortcuts,\n}: WebManifestOptions): string =>\n JSON.stringify({\n id,\n name,\n short_name: shortName,\n description,\n start_url: startUrl,\n scope,\n display,\n theme_color: themeColor,\n background_color: backgroundColor,\n ...(lang ? { lang } : {}),\n ...(orientation ? { orientation } : {}),\n ...(categories?.length ? { categories } : {}),\n ...(screenshots?.length ? { screenshots } : {}),\n ...(shortcuts?.length ? { shortcuts } : {}),\n icons: [\n {\n src: icon192,\n sizes: '192x192',\n type: 'image/png',\n purpose: 'any',\n },\n {\n src: icon512,\n sizes: '512x512',\n type: 'image/png',\n purpose: 'any',\n },\n {\n src: maskableIcon512,\n sizes: '512x512',\n type: 'image/png',\n purpose: 'maskable',\n },\n ],\n })\n","import { existsSync, type PathLike } from 'node:fs'\nimport { cp, mkdir, readdir, writeFile } from 'node:fs/promises'\nimport { basename, join, relative, sep } from 'node:path'\nimport type { BCP47LanguageTag } from '@sovereignbase/utils'\nimport type { DocumentMarkupOptions } from './.types/index.js'\nimport { documentMarkup } from './htmlDocument/index.js'\nimport minifyCss from './minifyCss/index.js'\nimport minifyHtml from './minifyHtml/index.js'\nimport minifyJs from './minifyJs/index.js'\nimport { webManifest, type WebManifestOptions } from './webManifest/index.js'\n\nexport async function pwaize(config: PWAizeConfig): Promise<void> {\n const outputDirectory = join(config.outDir.toString(), 'web')\n const buildId = crypto.randomUUID()\n const minifyPasses = config.minifyPasses ?? 3\n const serviceWorkerPath = '/ServiceWorker'\n\n await mkdir(outputDirectory, { recursive: true })\n\n for (const directory of [config.assetsDir, config.i18nDir]) {\n if (directory === undefined) continue\n\n const sourceDirectory = directory.toString()\n await cp(\n sourceDirectory,\n join(outputDirectory, basename(sourceDirectory)),\n {\n recursive: true,\n }\n )\n }\n\n const stylesheet = await minifyCss(config.stylesheet)\n const entrypoint = await minifyJs(config.entrypoint, {\n passes: minifyPasses,\n })\n const installer = await minifyJs(\n {\n source: `const registration=await navigator.serviceWorker.register(${JSON.stringify(serviceWorkerPath)},{scope:\"/\",type:\"module\"});await navigator.serviceWorker.ready;if(!navigator.serviceWorker.controller)location.reload();`,\n },\n { passes: minifyPasses }\n )\n const languages = [config.defaultLanguage, ...config.alternateLanguages]\n\n for (const language of languages) {\n const localized = config.languages[language]\n if (localized === undefined) {\n throw new Error(`Missing PWA configuration for language \"${language}\"`)\n }\n\n const languageDirectory = join(outputDirectory, language)\n const manifestPath = `/${language}/manifest.webmanifest` as const\n const manifest = webManifest({\n ...localized.manifest,\n lang: language,\n })\n\n await mkdir(languageDirectory, { recursive: true })\n await writeFile(join(languageDirectory, 'manifest.webmanifest'), manifest)\n\n const installerDocument = await minifyHtml(\n await documentMarkup({\n ...localized.document,\n language,\n stylesheet: '',\n entrypoint: installer,\n manifestUrl: manifestPath,\n })\n )\n\n await writeFile(join(languageDirectory, 'index.html'), installerDocument)\n\n if (language === config.defaultLanguage) {\n await writeFile(join(outputDirectory, 'index.html'), installerDocument)\n await writeFile(join(outputDirectory, 'manifest.webmanifest'), manifest)\n }\n }\n\n const buildIdPath = join(\n outputDirectory,\n '@sovereignbase',\n 'pwa',\n 'pwaize-build-id.txt'\n )\n await mkdir(join(outputDirectory, '@sovereignbase', 'pwa'), {\n recursive: true,\n })\n await writeFile(buildIdPath, buildId)\n\n if (config._headersFile === true) {\n await writeFile(\n join(outputDirectory, '_headers'),\n `/${serviceWorkerPath.slice(1)}\\n Cache-Control: no-cache\\n Content-Type: text/javascript;charset=UTF-8\\n\\n/*\\n X-Content-Type-Options: nosniff\\n`\n )\n }\n\n const precache = [\n ...(await publicFiles(outputDirectory)),\n ...(config.serviceWorker?.precache ?? []),\n ]\n const bypassRules = (config.serviceWorker?.bypass ?? []).map(globRule)\n const compiledServiceWorker = new URL(\n './serviceWorker/entrypoint.js',\n import.meta.url\n )\n const serviceWorker = await minifyJs(\n existsSync(compiledServiceWorker)\n ? compiledServiceWorker\n : new URL('./serviceWorker/entrypoint.ts', import.meta.url),\n {\n define: {\n buildId: JSON.stringify(buildId),\n buildIdUrl: JSON.stringify('/@sovereignbase/pwa/pwaize-build-id.txt'),\n bypassRules: JSON.stringify(bypassRules),\n customInitialize:\n config.serviceWorker?.initialize === undefined\n ? 'undefined'\n : `(${config.serviceWorker.initialize.toString()})`,\n customWaitUntil:\n config.serviceWorker?.waitUntil === undefined\n ? 'undefined'\n : `(${config.serviceWorker.waitUntil.toString()})`,\n defaultLanguage: JSON.stringify(config.defaultLanguage),\n documentOptions: JSON.stringify(\n Object.fromEntries(\n languages.map((language) => [\n language,\n config.languages[language].document,\n ])\n )\n ),\n entrypoint: JSON.stringify(entrypoint),\n precache: JSON.stringify(precache),\n stylesheet: JSON.stringify(stylesheet),\n },\n passes: minifyPasses,\n }\n )\n\n await writeFile(\n join(outputDirectory, serviceWorkerPath.slice(1)),\n serviceWorker\n )\n}\n\nasync function publicFiles(\n directory: string,\n root = directory\n): Promise<string[]> {\n const entries = await readdir(directory, { withFileTypes: true })\n const files: string[] = []\n\n for (const entry of entries) {\n const path = join(directory, entry.name)\n if (entry.isDirectory()) {\n files.push(...(await publicFiles(path, root)))\n } else if (entry.isFile() && entry.name !== '_headers') {\n files.push(`/${relative(root, path).split(sep).join('/')}`)\n }\n }\n\n return files.sort()\n}\n\nfunction globRule(pattern: string | RegExp): {\n absolute: boolean\n flags: string\n source: string\n} {\n if (pattern instanceof RegExp) {\n return {\n absolute: true,\n flags: pattern.flags,\n source: pattern.source,\n }\n }\n\n let source = '^'\n for (let index = 0; index < pattern.length; index += 1) {\n const character = pattern[index]\n\n if (character === '*') {\n if (pattern[index + 1] === '*') {\n source += '.*'\n index += 1\n } else {\n source += '[^/]*'\n }\n } else if (character === '?') {\n source += '.'\n } else {\n source += character.replace(/[|\\\\{}()[\\]^$+?.]/g, '\\\\$&')\n }\n }\n\n return {\n absolute: pattern.includes('://'),\n flags: '',\n source: `${source}$`,\n }\n}\n\nexport type PWAizeConfig = {\n defaultLanguage: BCP47LanguageTag\n canonicalLanguage: BCP47LanguageTag\n alternateLanguages: BCP47LanguageTag[]\n\n languages: Record<\n string,\n {\n document: Omit<\n DocumentMarkupOptions,\n 'entrypoint' | 'language' | 'manifestUrl' | 'stylesheet'\n >\n manifest: Omit<WebManifestOptions, 'lang'>\n }\n >\n\n stylesheet: PathLike\n entrypoint: PathLike\n outDir: PathLike\n\n assetsDir?: PathLike\n i18nDir?: PathLike\n minifyPasses?: number\n\n serviceWorker?: {\n bypass?: Array<string | RegExp>\n precache?: `/${string}`[]\n initialize?: () => void\n waitUntil?: () => Promise<void>\n }\n\n _headersFile?: boolean\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["minifiedOutputs","minifiedOutputs","minify"],"sources":["../src/minifyCss/index.ts","../src/minifyHtml/index.ts","../src/minifyJs/index.ts","../src/webManifest/index.ts","../src/index.ts"],"sourcesContent":["import type { PathLike } from 'node:fs'\nimport { build } from 'esbuild'\nimport { transform } from 'lightningcss'\n\nconst minifiedOutputs = new Map<string, string>()\n\n/** Bundles and minifies a CSS entrypoint into a dense string. */\nexport default async function minifyCss(entrypoint: PathLike): Promise<string> {\n const bundled = await build({\n entryPoints: [entrypoint.toString()],\n bundle: true,\n legalComments: 'none',\n minify: true,\n treeShaking: true,\n write: false,\n external: ['/assets/*'],\n })\n const source = bundled.outputFiles[0].text\n const cached = minifiedOutputs.get(source)\n if (cached !== undefined) return cached\n\n const { code } = transform({\n code: bundled.outputFiles[0].contents,\n filename: entrypoint.toString(),\n minify: true,\n })\n\n const output = new TextDecoder().decode(code).trim()\n minifiedOutputs.set(source, output)\n return output\n}\n","import { minify } from 'html-minifier-terser'\n\nconst minifiedOutputs = new Map<string, string>()\n\n/** Minifies a complete HTML document, including inline CSS and JavaScript. */\nexport default async function minifyHtml(source: string): Promise<string> {\n const cached = minifiedOutputs.get(source)\n if (cached !== undefined) return cached\n\n const output = await minify(source, {\n collapseBooleanAttributes: true,\n collapseInlineTagWhitespace: true,\n collapseWhitespace: true,\n decodeEntities: true,\n html5: true,\n minifyCSS: true,\n minifyJS: {\n compress: {\n dead_code: true,\n passes: 3,\n toplevel: true,\n unused: true,\n },\n mangle: {\n toplevel: true,\n },\n module: true,\n toplevel: true,\n },\n removeAttributeQuotes: true,\n removeComments: true,\n removeEmptyAttributes: true,\n removeRedundantAttributes: true,\n sortAttributes: true,\n sortClassName: true,\n useShortDoctype: true,\n })\n minifiedOutputs.set(source, output)\n return output\n}\n","import type { PathLike } from 'node:fs'\nimport { fileURLToPath } from 'node:url'\nimport { build } from 'esbuild'\nimport { minify } from 'terser'\n\nconst minifiedOutputs = new Map<string, string>()\n\ntype JavaScriptInput = PathLike | { source: string }\n\ntype MinifyJsOptions = {\n banner?: string\n define?: Record<string, string>\n passes?: number\n}\n\n/** Bundles, tree-shakes, mangles, and repeatedly minifies JavaScript. */\nexport default async function minifyJs(\n input: JavaScriptInput,\n { banner, define, passes = 3 }: MinifyJsOptions = {}\n): Promise<string> {\n const bundled = await build({\n ...(typeof input === 'object' && 'source' in input\n ? { stdin: { contents: input.source, resolveDir: process.cwd() } }\n : {\n entryPoints: [\n input instanceof URL ? fileURLToPath(input) : input.toString(),\n ],\n }),\n bundle: true,\n banner: banner === undefined ? undefined : { js: banner },\n define,\n format: 'esm',\n legalComments: 'none',\n minify: true,\n platform: 'browser',\n treeShaking: true,\n write: false,\n })\n\n const output = bundled.outputFiles[0].text\n const cacheKey = `${passes}\\0${output}`\n const cached = minifiedOutputs.get(cacheKey)\n if (cached !== undefined) return cached\n\n const result = await repeatedlyMinify(output, passes)\n minifiedOutputs.set(cacheKey, result)\n return result\n}\n\nasync function repeatedlyMinify(\n source: string,\n passes: number\n): Promise<string> {\n let output = source\n\n for (let round = 0; round < passes; round += 1) {\n const result = await minify(output, {\n compress: {\n dead_code: true,\n passes,\n toplevel: true,\n unused: true,\n },\n ecma: 2024,\n format: {\n beautify: false,\n comments: false,\n },\n mangle: {\n toplevel: true,\n },\n module: true,\n toplevel: true,\n })\n\n /* v8 ignore next 3 -- Terser returns code or rejects for this input form. */\n if (result.code === undefined) {\n throw new Error('Terser did not produce JavaScript output')\n }\n\n output = result.code\n }\n\n return output\n}\n","import type { BCP47LanguageTag } from '@sovereignbase/utils'\n\ntype Path = `/${string}`\ntype ImageURL = Path | `https://${string}`\n\nexport interface WebManifestScreenshot {\n src: ImageURL\n sizes: `${number}x${number}`\n type?: `image/${string}`\n form_factor?: 'narrow' | 'wide'\n label?: string\n}\n\nexport interface WebManifestShortcut {\n name: string\n url: Path\n description?: string\n icons?: {\n src: ImageURL\n sizes: `${number}x${number}` | 'any'\n type?: `image/${string}`\n }[]\n}\n\nexport interface WebManifestOptions {\n name: string\n shortName: string\n description: string\n startUrl: Path\n themeColor: string\n icon192: ImageURL\n icon512: ImageURL\n maskableIcon512: ImageURL\n id?: Path\n scope?: Path\n backgroundColor?: string\n lang?: BCP47LanguageTag\n display?: 'standalone' | 'fullscreen' | 'minimal-ui' | 'browser'\n orientation?:\n | 'any'\n | 'natural'\n | 'portrait'\n | 'portrait-primary'\n | 'portrait-secondary'\n | 'landscape'\n | 'landscape-primary'\n | 'landscape-secondary'\n categories?: string[]\n screenshots?: WebManifestScreenshot[]\n shortcuts?: WebManifestShortcut[]\n}\n\n/**\n * Generates a standards-based Web App Manifest JSON string.\n */\nexport const webManifest = ({\n name,\n shortName,\n description,\n startUrl,\n themeColor,\n icon192,\n icon512,\n maskableIcon512,\n id = '/',\n scope = '/',\n backgroundColor = themeColor,\n lang,\n display = 'standalone',\n orientation,\n categories,\n screenshots,\n shortcuts,\n}: WebManifestOptions): string =>\n JSON.stringify({\n id,\n name,\n short_name: shortName,\n description,\n start_url: startUrl,\n scope,\n display,\n theme_color: themeColor,\n background_color: backgroundColor,\n ...(lang ? { lang } : {}),\n ...(orientation ? { orientation } : {}),\n ...(categories?.length ? { categories } : {}),\n ...(screenshots?.length ? { screenshots } : {}),\n ...(shortcuts?.length ? { shortcuts } : {}),\n icons: [\n {\n src: icon192,\n sizes: '192x192',\n type: 'image/png',\n purpose: 'any',\n },\n {\n src: icon512,\n sizes: '512x512',\n type: 'image/png',\n purpose: 'any',\n },\n {\n src: maskableIcon512,\n sizes: '512x512',\n type: 'image/png',\n purpose: 'maskable',\n },\n ],\n })\n","import { createHash } from 'node:crypto'\nimport { existsSync, type PathLike } from 'node:fs'\nimport { cp, mkdir, readFile, readdir, writeFile } from 'node:fs/promises'\nimport { basename, dirname, extname, join, relative, sep } from 'node:path'\nimport type { BCP47LanguageTag, OpenGraphLocale } from '@sovereignbase/utils'\nimport type {\n DocumentMarkupOptions,\n HTTPSUrl,\n URLPath,\n} from './.types/index.js'\nimport { documentMarkup } from './htmlDocument/index.js'\nimport minifyCss from './minifyCss/index.js'\nimport minifyHtml from './minifyHtml/index.js'\nimport minifyJs from './minifyJs/index.js'\nimport {\n webManifest,\n type WebManifestOptions,\n type WebManifestScreenshot,\n type WebManifestShortcut,\n} from './webManifest/index.js'\n\nexport async function pwaize(config: PWAizeConfig): Promise<void> {\n const outputDirectory = join(config.outDir.toString(), 'web')\n const languages = [\n ...new Set([config.defaultLanguage, ...config.alternateLanguages]),\n ]\n const minifyPasses = config.minifyPasses ?? 3\n const serviceWorkerPath = '/ServiceWorker'\n\n await mkdir(outputDirectory, { recursive: true })\n\n if (config.assetsDir !== undefined) {\n const sourceDirectory = config.assetsDir.toString()\n await cp(\n sourceDirectory,\n join(outputDirectory, basename(sourceDirectory)),\n { recursive: true }\n )\n }\n\n if (config.i18nDir !== undefined) {\n const sourceDirectory = config.i18nDir.toString()\n await buildScriptDirectory(\n sourceDirectory,\n join(outputDirectory, basename(sourceDirectory)),\n minifyPasses\n )\n }\n\n const stylesheet = await minifyCss(config.stylesheet)\n const entrypoint = await minifyJs(config.entrypoint, {\n passes: minifyPasses,\n })\n const installer = await minifyJs(\n {\n source: `await navigator.serviceWorker.register(${JSON.stringify(serviceWorkerPath)},{scope:\"/\",type:\"module\"});await navigator.serviceWorker.ready;location.reload();`,\n },\n { passes: minifyPasses }\n )\n const documentOptions: Record<\n string,\n Omit<\n DocumentMarkupOptions,\n 'entrypoint' | 'language' | 'manifestUrl' | 'stylesheet'\n >\n > = {}\n\n for (const language of languages) {\n const localized = localizeConfig(config, language, languages)\n const languageDirectory = join(outputDirectory, language)\n const manifestPath = `/${language}/manifest.webmanifest` as const\n const manifest = webManifest(localized.manifest)\n documentOptions[language] = localized.document\n\n await mkdir(languageDirectory, { recursive: true })\n await writeFile(join(languageDirectory, 'manifest.webmanifest'), manifest)\n\n const installerDocument = await minifyHtml(\n await documentMarkup({\n ...localized.document,\n entrypoint: installer,\n language,\n manifestUrl: manifestPath,\n })\n )\n await writeFile(join(languageDirectory, 'index.html'), installerDocument)\n\n if (language === config.defaultLanguage) {\n await writeFile(join(outputDirectory, 'index.html'), installerDocument)\n await writeFile(join(outputDirectory, 'manifest.webmanifest'), manifest)\n }\n }\n\n if (config._headersFile === true) {\n await writeFile(\n join(outputDirectory, '_headers'),\n `/${serviceWorkerPath.slice(1)}\\n Cache-Control: no-cache\\n Content-Type: text/javascript;charset=UTF-8\\n\\n/*\\n X-Content-Type-Options: nosniff\\n`\n )\n }\n\n const buildIdUrl = '/@sovereignbase/pwa/pwaize-build-id.txt'\n const generatedFiles = (await publicFiles(outputDirectory)).filter(\n (url) => url !== serviceWorkerPath && url !== buildIdUrl\n )\n const precache = [\n ...new Set([...generatedFiles, ...(config.serviceWorker?.precache ?? [])]),\n ].sort()\n const bypassRules = (config.serviceWorker?.bypass ?? []).map(globRule)\n const initialize =\n config.serviceWorker?.initialize === undefined\n ? 'undefined'\n : functionExpression(config.serviceWorker.initialize)\n const waitUntil =\n config.serviceWorker?.waitUntil === undefined\n ? 'undefined'\n : functionExpression(config.serviceWorker.waitUntil)\n const buildId = await contentBuildId(outputDirectory, generatedFiles, {\n bypassRules,\n documentOptions,\n entrypoint,\n initialize,\n precache,\n stylesheet,\n waitUntil,\n })\n const buildIdDirectory = join(outputDirectory, '@sovereignbase', 'pwa')\n await mkdir(buildIdDirectory, { recursive: true })\n await writeFile(join(buildIdDirectory, 'pwaize-build-id.txt'), buildId)\n const compiledServiceWorker = new URL(\n './serviceWorker/entrypoint.js',\n import.meta.url\n )\n const serviceWorker = await minifyJs(\n /* v8 ignore next -- the packaged .js path is exercised by runtime tests */\n existsSync(compiledServiceWorker)\n ? compiledServiceWorker\n : new URL('./serviceWorker/entrypoint.ts', import.meta.url),\n {\n banner: `const __pwaInitialize=${initialize},__pwaWaitUntil=${waitUntil};`,\n define: {\n buildId: JSON.stringify(buildId),\n buildIdUrl: JSON.stringify(buildIdUrl),\n bypassRules: JSON.stringify(bypassRules),\n customInitialize: '__pwaInitialize',\n customWaitUntil: '__pwaWaitUntil',\n defaultLanguage: JSON.stringify(config.defaultLanguage),\n documentOptions: JSON.stringify(documentOptions),\n entrypoint: JSON.stringify(entrypoint),\n precache: JSON.stringify(precache),\n stylesheet: JSON.stringify(stylesheet),\n },\n passes: minifyPasses,\n }\n )\n\n await writeFile(\n join(outputDirectory, serviceWorkerPath.slice(1)),\n serviceWorker\n )\n}\n\nasync function buildScriptDirectory(\n sourceDirectory: string,\n outputDirectory: string,\n passes: number,\n root = sourceDirectory\n): Promise<void> {\n for (const entry of await readdir(sourceDirectory, { withFileTypes: true })) {\n const source = join(sourceDirectory, entry.name)\n if (entry.isDirectory()) {\n await buildScriptDirectory(source, outputDirectory, passes, root)\n continue\n }\n if (!entry.isFile() || entry.name.endsWith('.d.ts')) continue\n\n const relativePath = relative(root, source)\n const extension = extname(relativePath)\n const output = join(\n outputDirectory,\n /\\.[cm]?[jt]sx?$/.test(extension)\n ? `${relativePath.slice(0, -extension.length)}.js`\n : relativePath\n )\n await mkdir(dirname(output), { recursive: true })\n if (/\\.[cm]?[jt]sx?$/.test(extension)) {\n await writeFile(output, await minifyJs(source, { passes }))\n } else {\n await cp(source, output)\n }\n }\n}\n\nasync function contentBuildId(\n outputDirectory: string,\n files: string[],\n configuration: unknown\n): Promise<string> {\n const hash = createHash('sha256')\n hash.update(JSON.stringify(configuration))\n for (const file of files) {\n hash.update(file)\n hash.update(\n await readFile(join(outputDirectory, ...file.slice(1).split('/')))\n )\n }\n return hash.digest('hex')\n}\n\nasync function publicFiles(\n directory: string,\n root = directory\n): Promise<string[]> {\n const entries = await readdir(directory, { withFileTypes: true })\n const files: string[] = []\n\n for (const entry of entries) {\n const path = join(directory, entry.name)\n if (entry.isDirectory()) {\n files.push(...(await publicFiles(path, root)))\n } else if (entry.isFile() && entry.name !== '_headers') {\n files.push(`/${relative(root, path).split(sep).join('/')}`)\n }\n }\n\n return files.sort()\n}\n\nfunction globRule(pattern: string | RegExp): {\n absolute: boolean\n flags: string\n source: string\n} {\n if (pattern instanceof RegExp) {\n return { absolute: true, flags: pattern.flags, source: pattern.source }\n }\n\n let source = '^'\n for (let index = 0; index < pattern.length; index += 1) {\n const character = pattern[index]\n if (character === '*') {\n if (pattern[index + 1] === '*') {\n source += '.*'\n index += 1\n } else {\n source += '[^/]*'\n }\n } else if (character === '?') {\n source += '.'\n } else {\n source += character.replace(/[|\\\\{}()[\\]^$+?.]/g, '\\\\$&')\n }\n }\n\n return {\n absolute: pattern.includes('://'),\n flags: '',\n source: `${source}$`,\n }\n}\n\nfunction functionExpression(\n callback: (...arguments_: never[]) => unknown\n): string {\n const source = callback.toString()\n if (/^(?:async\\s+)?function\\b|^(?:async\\s+)?\\(/.test(source)) {\n return `(${source})`\n }\n if (source.startsWith('async ')) {\n return `(async function ${source.slice('async '.length)})`\n }\n return `(function ${source})`\n}\n\nfunction localizeConfig(\n config: PWAizeConfig,\n language: BCP47LanguageTag,\n languages: BCP47LanguageTag[]\n): {\n document: Omit<\n DocumentMarkupOptions,\n 'entrypoint' | 'language' | 'manifestUrl' | 'stylesheet'\n >\n manifest: WebManifestOptions\n} {\n const get = <T>(value: Localized<T> | undefined, empty: T): T =>\n localizedValue(value, language, config.defaultLanguage, empty)\n const applicationName = get(config.applicationName, '')\n const description = get(config.description, '')\n const icon192 = get<string>(config.icons.icon192, '')\n const icon512 = get<string>(config.icons.icon512, '')\n const origin = get<string>(config.origin, '')\n const pageUrl = (\n origin === '' ? '' : new URL(`/${language}`, origin).href\n ) as HTTPSUrl\n const organizationLogo = (\n origin === '' || icon512 === '' ? '' : new URL(icon512, origin).href\n ) as HTTPSUrl\n const themeColor = get(config.themeColor, '')\n const title = get(config.title, '')\n\n return {\n document: {\n applicationName,\n appleStatusBarStyle: get(config.appleStatusBarStyle, 'black-translucent'),\n appleTouchIconUrl: get(\n config.icons.appleTouchIconUrl,\n icon192 as URLPath\n ),\n bodyMarkup: get(config.bodyMarkup, ''),\n colorScheme: get(config.colorScheme, 'light dark'),\n headMarkup: get(config.headMarkup, ''),\n iconUrl: get(config.icons.iconUrl, icon512 as URLPath),\n maskIconColor: themeColor,\n maskIconUrl: get(config.icons.maskIconUrl, '' as URLPath),\n seo: {\n jsonLD: {\n application: {\n applicationCategory: get(config.application?.category, ''),\n browserRequirements: get(\n config.application?.browserRequirements,\n ''\n ),\n featureList: get(config.application?.featureList, []),\n inLanguage: languages,\n name: applicationName,\n operatingSystem: get(config.application?.operatingSystem, ''),\n url: origin as HTTPSUrl,\n },\n organization: {\n logo: get(config.organization?.logoUrl, organizationLogo),\n name: get(config.organization?.name, applicationName),\n url: get<string>(config.organization?.url, origin) as HTTPSUrl,\n },\n page: {\n description,\n inLanguage: language,\n name: title,\n url: pageUrl,\n },\n site: { name: applicationName, url: origin as HTTPSUrl },\n },\n languageLinks: {\n alternateLanguages: languages,\n canonicalLanguage: config.canonicalLanguage,\n defaultLanguage: config.defaultLanguage,\n host: (origin === ''\n ? ''\n : new URL(origin).host) as `${string}.${string}`,\n },\n openGraph: {\n description,\n imageAlt: get(config.socialImage.alt, ''),\n imageHeight: get(config.socialImage.height, 630),\n imageUrl: get(config.socialImage.url, '' as HTTPSUrl),\n imageWidth: get(config.socialImage.width, 1200),\n locale: get(config.openGraphLocale, '' as OpenGraphLocale),\n siteName: applicationName,\n title,\n url: pageUrl,\n },\n twitter: {\n creator: get(config.twitter.creator, '' as `@${string}`),\n description,\n imageAlt: get(config.socialImage.alt, ''),\n imageUrl: get(config.socialImage.url, '' as HTTPSUrl),\n site: get(config.twitter.site, '' as `@${string}`),\n title,\n url: pageUrl,\n },\n },\n themeColor,\n title,\n },\n manifest: {\n backgroundColor: get(config.backgroundColor, themeColor),\n categories: get(config.manifest?.categories, []),\n description,\n display: get(config.manifest?.display, 'standalone'),\n icon192: icon192 as URLPath,\n icon512: icon512 as URLPath,\n id: get(config.manifest?.id, '/' as URLPath),\n lang: language,\n maskableIcon512: get(config.icons.maskableIcon512, icon512 as URLPath),\n name: applicationName,\n orientation: get(config.manifest?.orientation, 'any'),\n scope: get(config.manifest?.scope, '/' as URLPath),\n screenshots: get(config.manifest?.screenshots, []),\n shortName: get(config.shortName, applicationName),\n shortcuts: get(config.manifest?.shortcuts, []),\n startUrl: `/${language}`,\n themeColor,\n },\n }\n}\n\nfunction localizedValue<T>(\n value: Localized<T> | undefined,\n language: BCP47LanguageTag,\n defaultLanguage: BCP47LanguageTag,\n empty: T\n): T {\n if (value === undefined) return empty\n if (typeof value !== 'object' || value === null || Array.isArray(value)) {\n return value as T\n }\n\n const values = value as Partial<Record<BCP47LanguageTag, T>>\n return values[language] ?? values[defaultLanguage] ?? empty\n}\n\nexport type Localized<T> = T | Partial<Record<BCP47LanguageTag, T>>\n\nexport type PWAizeConfig = {\n _headersFile?: boolean\n alternateLanguages: BCP47LanguageTag[]\n application?: {\n browserRequirements?: Localized<string>\n category?: Localized<string>\n featureList?: Localized<string[]>\n operatingSystem?: Localized<string>\n }\n applicationName: Localized<string>\n appleStatusBarStyle?: Localized<'black' | 'black-translucent' | 'default'>\n assetsDir?: PathLike\n backgroundColor?: Localized<string>\n bodyMarkup?: Localized<string>\n canonicalLanguage: BCP47LanguageTag\n colorScheme?: Localized<'dark' | 'dark light' | 'light' | 'light dark'>\n defaultLanguage: BCP47LanguageTag\n description: Localized<string>\n entrypoint: PathLike\n headMarkup?: Localized<string>\n i18nDir?: PathLike\n icons: {\n appleTouchIconUrl?: Localized<URLPath>\n icon192: Localized<URLPath>\n icon512: Localized<URLPath>\n iconUrl?: Localized<URLPath>\n maskableIcon512: Localized<URLPath>\n maskIconUrl?: Localized<URLPath>\n }\n manifest?: {\n categories?: Localized<string[]>\n display?: Localized<'browser' | 'fullscreen' | 'minimal-ui' | 'standalone'>\n id?: Localized<URLPath>\n orientation?: Localized<WebManifestOptions['orientation']>\n scope?: Localized<URLPath>\n screenshots?: Localized<WebManifestScreenshot[]>\n shortcuts?: Localized<WebManifestShortcut[]>\n }\n minifyPasses?: number\n openGraphLocale: Localized<OpenGraphLocale>\n organization?: {\n logoUrl?: Localized<HTTPSUrl>\n name?: Localized<string>\n url?: Localized<HTTPSUrl>\n }\n origin: Localized<HTTPSUrl>\n outDir: PathLike\n serviceWorker?: {\n bypass?: Array<string | RegExp>\n initialize?: () => void\n precache?: URLPath[]\n waitUntil?: () => Promise<void>\n }\n shortName?: Localized<string>\n socialImage: {\n alt: Localized<string>\n height?: Localized<number>\n url: Localized<HTTPSUrl>\n width?: Localized<number>\n }\n stylesheet: PathLike\n themeColor: Localized<string>\n title: Localized<string>\n twitter: {\n creator: Localized<`@${string}`>\n site: Localized<`@${string}`>\n }\n}\n"],"mappings":"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"}
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
* limitations under the License.
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
|
-
const require_htmlDocument = require("../htmlDocument-
|
|
17
|
+
const require_htmlDocument = require("../htmlDocument-C3k13Sjr.cjs");
|
|
18
18
|
//#region src/serviceWorker/entrypoint.ts
|
|
19
19
|
const worker = self;
|
|
20
20
|
const cachePrefix = "@sovereignbase/pwa:";
|
|
@@ -45,10 +45,12 @@ worker.addEventListener("message", (event) => {
|
|
|
45
45
|
if (event.data === "SKIP_WAITING") event.waitUntil(worker.skipWaiting());
|
|
46
46
|
});
|
|
47
47
|
async function buildDocumentResponse(event) {
|
|
48
|
+
const language = documentLanguage(event.request);
|
|
48
49
|
const cache = await caches.open(cacheName);
|
|
49
|
-
const
|
|
50
|
-
const
|
|
51
|
-
|
|
50
|
+
const cacheKey = documentCacheKey(event.request, language);
|
|
51
|
+
const cached = await cache.match(cacheKey);
|
|
52
|
+
const rendered = renderDocument(language).then(async (response) => {
|
|
53
|
+
await cache.put(cacheKey, response.clone());
|
|
52
54
|
return response;
|
|
53
55
|
});
|
|
54
56
|
if (cached === void 0) return rendered;
|
|
@@ -65,9 +67,8 @@ async function negotiateCache(event) {
|
|
|
65
67
|
event.waitUntil(updated);
|
|
66
68
|
return cached;
|
|
67
69
|
}
|
|
68
|
-
async function renderDocument(
|
|
69
|
-
const
|
|
70
|
-
const options = documentOptions[language] ?? documentOptions[defaultLanguage];
|
|
70
|
+
async function renderDocument(language) {
|
|
71
|
+
const options = documentOptions[language];
|
|
71
72
|
const markup = await require_htmlDocument.documentMarkup({
|
|
72
73
|
...options,
|
|
73
74
|
entrypoint,
|
|
@@ -80,6 +81,11 @@ async function renderDocument(request) {
|
|
|
80
81
|
"x-pwaize-build-id": buildId
|
|
81
82
|
} });
|
|
82
83
|
}
|
|
84
|
+
function documentCacheKey(request, language) {
|
|
85
|
+
const url = new URL(request.url);
|
|
86
|
+
url.searchParams.set("__pwaize_language", language);
|
|
87
|
+
return new Request(url);
|
|
88
|
+
}
|
|
83
89
|
function documentLanguage(request) {
|
|
84
90
|
const pathLanguage = new URL(request.url).pathname.split("/").filter(Boolean)[0];
|
|
85
91
|
if (pathLanguage in documentOptions) return pathLanguage;
|
|
@@ -113,11 +119,6 @@ async function activateServiceWorker() {
|
|
|
113
119
|
worker.clients.claim(),
|
|
114
120
|
backgroundStartup
|
|
115
121
|
]);
|
|
116
|
-
const clients = await worker.clients.matchAll({
|
|
117
|
-
includeUncontrolled: true,
|
|
118
|
-
type: "window"
|
|
119
|
-
});
|
|
120
|
-
await Promise.all(clients.map((client) => client.navigate(client.url)));
|
|
121
122
|
}
|
|
122
123
|
async function deleteOldCaches() {
|
|
123
124
|
const names = await caches.keys();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"entrypoint.cjs","names":["documentMarkup"],"sources":["../../src/serviceWorker/entrypoint.ts"],"sourcesContent":["import type { DocumentMarkupOptions } from '../.types/index.js'\nimport { documentMarkup } from '../htmlDocument/index.js'\n\ndeclare const buildId: string\ndeclare const buildIdUrl: string\ndeclare const bypassRules: ReadonlyArray<{\n absolute: boolean\n flags: string\n source: string\n}>\ndeclare const customInitialize: (() => void) | undefined\ndeclare const customWaitUntil: (() => Promise<void>) | undefined\ndeclare const defaultLanguage: DocumentMarkupOptions['language']\ndeclare const documentOptions: Readonly<\n Record<\n string,\n Omit<\n DocumentMarkupOptions,\n 'entrypoint' | 'language' | 'manifestUrl' | 'stylesheet'\n >\n >\n>\ndeclare const entrypoint: string\ndeclare const precache: readonly string[]\ndeclare const stylesheet: string\n\nconst worker = self as unknown as ServiceWorkerGlobalScope\nconst cachePrefix = '@sovereignbase/pwa:'\nconst cacheName = `${cachePrefix}${buildId}`\nconst backgroundStartup = Promise.resolve(customWaitUntil?.())\n\ncustomInitialize?.()\n\nconst routes = Object.freeze({\n document: buildDocumentResponse,\n static: negotiateCache,\n})\n\nworker.addEventListener('fetch', (event) => {\n event.waitUntil(Promise.all([backgroundStartup, checkForUpdate()]))\n\n if (event.request.method !== 'GET' || bypassesServiceWorker(event.request)) {\n return\n }\n\n const route =\n event.request.mode === 'navigate' ? routes.document : routes.static\n event.respondWith(route(event))\n})\n\nworker.addEventListener('install', (event) => {\n event.waitUntil(\n Promise.all([\n caches.open(cacheName).then((cache) => cache.addAll(precache)),\n worker.skipWaiting(),\n backgroundStartup,\n ])\n )\n})\n\nworker.addEventListener('activate', (event) => {\n event.waitUntil(activateServiceWorker())\n})\n\nworker.addEventListener('message', (event) => {\n if (event.data === 'SKIP_WAITING') {\n event.waitUntil(worker.skipWaiting())\n }\n})\n\nasync function buildDocumentResponse(event: FetchEvent): Promise<Response> {\n const cache = await caches.open(cacheName)\n const cached = await cache.match(
|
|
1
|
+
{"version":3,"file":"entrypoint.cjs","names":["documentMarkup"],"sources":["../../src/serviceWorker/entrypoint.ts"],"sourcesContent":["import type { DocumentMarkupOptions } from '../.types/index.js'\nimport { documentMarkup } from '../htmlDocument/index.js'\n\ndeclare const buildId: string\ndeclare const buildIdUrl: string\ndeclare const bypassRules: ReadonlyArray<{\n absolute: boolean\n flags: string\n source: string\n}>\ndeclare const customInitialize: (() => void) | undefined\ndeclare const customWaitUntil: (() => Promise<void>) | undefined\ndeclare const defaultLanguage: DocumentMarkupOptions['language']\ndeclare const documentOptions: Readonly<\n Record<\n string,\n Omit<\n DocumentMarkupOptions,\n 'entrypoint' | 'language' | 'manifestUrl' | 'stylesheet'\n >\n >\n>\ndeclare const entrypoint: string\ndeclare const precache: readonly string[]\ndeclare const stylesheet: string\n\nconst worker = self as unknown as ServiceWorkerGlobalScope\nconst cachePrefix = '@sovereignbase/pwa:'\nconst cacheName = `${cachePrefix}${buildId}`\nconst backgroundStartup = Promise.resolve(customWaitUntil?.())\n\ncustomInitialize?.()\n\nconst routes = Object.freeze({\n document: buildDocumentResponse,\n static: negotiateCache,\n})\n\nworker.addEventListener('fetch', (event) => {\n event.waitUntil(Promise.all([backgroundStartup, checkForUpdate()]))\n\n if (event.request.method !== 'GET' || bypassesServiceWorker(event.request)) {\n return\n }\n\n const route =\n event.request.mode === 'navigate' ? routes.document : routes.static\n event.respondWith(route(event))\n})\n\nworker.addEventListener('install', (event) => {\n event.waitUntil(\n Promise.all([\n caches.open(cacheName).then((cache) => cache.addAll(precache)),\n worker.skipWaiting(),\n backgroundStartup,\n ])\n )\n})\n\nworker.addEventListener('activate', (event) => {\n event.waitUntil(activateServiceWorker())\n})\n\nworker.addEventListener('message', (event) => {\n if (event.data === 'SKIP_WAITING') {\n event.waitUntil(worker.skipWaiting())\n }\n})\n\nasync function buildDocumentResponse(event: FetchEvent): Promise<Response> {\n const language = documentLanguage(event.request)\n const cache = await caches.open(cacheName)\n const cacheKey = documentCacheKey(event.request, language)\n const cached = await cache.match(cacheKey)\n const rendered = renderDocument(language).then(async (response) => {\n await cache.put(cacheKey, response.clone())\n return response\n })\n\n if (cached === undefined) return rendered\n\n event.waitUntil(rendered)\n return cached\n}\n\nasync function negotiateCache(event: FetchEvent): Promise<Response> {\n const cached = await caches.match(event.request)\n const updated = fetch(event.request).then(async (response) => {\n if (response.ok) {\n const cache = await caches.open(cacheName)\n await cache.put(event.request, response.clone())\n }\n return response\n })\n\n if (cached === undefined) return updated\n\n event.waitUntil(updated)\n return cached\n}\n\nasync function renderDocument(\n language: DocumentMarkupOptions['language']\n): Promise<Response> {\n const options = documentOptions[language]\n const markup = await documentMarkup({\n ...options,\n entrypoint,\n language,\n manifestUrl: `/${language}/manifest.webmanifest`,\n stylesheet,\n })\n\n return new Response(markup, {\n headers: {\n 'content-type': 'text/html;charset=UTF-8',\n 'x-pwaize-build-id': buildId,\n },\n })\n}\n\nfunction documentCacheKey(\n request: Request,\n language: DocumentMarkupOptions['language']\n): Request {\n const url = new URL(request.url)\n url.searchParams.set('__pwaize_language', language)\n return new Request(url)\n}\n\nfunction documentLanguage(request: Request): DocumentMarkupOptions['language'] {\n const pathLanguage = new URL(request.url).pathname\n .split('/')\n .filter(Boolean)[0]\n if (pathLanguage in documentOptions) {\n return pathLanguage as DocumentMarkupOptions['language']\n }\n\n const accepted = request.headers.get('accept-language') ?? ''\n for (const preference of accepted.split(',')) {\n const language = preference.split(';')[0].trim()\n if (language in documentOptions) {\n return language as DocumentMarkupOptions['language']\n }\n\n const baseLanguage = language.split('-')[0]\n if (baseLanguage in documentOptions) {\n return baseLanguage as DocumentMarkupOptions['language']\n }\n }\n\n return defaultLanguage\n}\n\nfunction bypassesServiceWorker(request: Request): boolean {\n const url = new URL(request.url)\n\n for (const rule of bypassRules) {\n const value = rule.absolute ? url.href : `${url.pathname}${url.search}`\n if (new RegExp(rule.source, rule.flags).test(value)) return true\n }\n\n return false\n}\n\nasync function checkForUpdate(): Promise<void> {\n try {\n const response = await fetch(buildIdUrl, { cache: 'no-store' })\n if (!response.ok || (await response.text()).trim() === buildId) return\n\n await worker.registration.update()\n } catch {\n // Offline version checks must not prevent offline responses.\n }\n}\n\nasync function activateServiceWorker(): Promise<void> {\n await Promise.all([\n deleteOldCaches(),\n worker.clients.claim(),\n backgroundStartup,\n ])\n}\n\nasync function deleteOldCaches(): Promise<void> {\n const names = await caches.keys()\n await Promise.all(\n names\n .filter((name) => name.startsWith(cachePrefix) && name !== cacheName)\n .map((name) => caches.delete(name))\n )\n}\n"],"mappings":"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"}
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
* limitations under the License.
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
|
-
import { t as documentMarkup } from "../htmlDocument-
|
|
17
|
+
import { t as documentMarkup } from "../htmlDocument-C533Sj5O.js";
|
|
18
18
|
//#region src/serviceWorker/entrypoint.ts
|
|
19
19
|
const worker = self;
|
|
20
20
|
const cachePrefix = "@sovereignbase/pwa:";
|
|
@@ -45,10 +45,12 @@ worker.addEventListener("message", (event) => {
|
|
|
45
45
|
if (event.data === "SKIP_WAITING") event.waitUntil(worker.skipWaiting());
|
|
46
46
|
});
|
|
47
47
|
async function buildDocumentResponse(event) {
|
|
48
|
+
const language = documentLanguage(event.request);
|
|
48
49
|
const cache = await caches.open(cacheName);
|
|
49
|
-
const
|
|
50
|
-
const
|
|
51
|
-
|
|
50
|
+
const cacheKey = documentCacheKey(event.request, language);
|
|
51
|
+
const cached = await cache.match(cacheKey);
|
|
52
|
+
const rendered = renderDocument(language).then(async (response) => {
|
|
53
|
+
await cache.put(cacheKey, response.clone());
|
|
52
54
|
return response;
|
|
53
55
|
});
|
|
54
56
|
if (cached === void 0) return rendered;
|
|
@@ -65,9 +67,8 @@ async function negotiateCache(event) {
|
|
|
65
67
|
event.waitUntil(updated);
|
|
66
68
|
return cached;
|
|
67
69
|
}
|
|
68
|
-
async function renderDocument(
|
|
69
|
-
const
|
|
70
|
-
const options = documentOptions[language] ?? documentOptions[defaultLanguage];
|
|
70
|
+
async function renderDocument(language) {
|
|
71
|
+
const options = documentOptions[language];
|
|
71
72
|
const markup = await documentMarkup({
|
|
72
73
|
...options,
|
|
73
74
|
entrypoint,
|
|
@@ -80,6 +81,11 @@ async function renderDocument(request) {
|
|
|
80
81
|
"x-pwaize-build-id": buildId
|
|
81
82
|
} });
|
|
82
83
|
}
|
|
84
|
+
function documentCacheKey(request, language) {
|
|
85
|
+
const url = new URL(request.url);
|
|
86
|
+
url.searchParams.set("__pwaize_language", language);
|
|
87
|
+
return new Request(url);
|
|
88
|
+
}
|
|
83
89
|
function documentLanguage(request) {
|
|
84
90
|
const pathLanguage = new URL(request.url).pathname.split("/").filter(Boolean)[0];
|
|
85
91
|
if (pathLanguage in documentOptions) return pathLanguage;
|
|
@@ -113,11 +119,6 @@ async function activateServiceWorker() {
|
|
|
113
119
|
worker.clients.claim(),
|
|
114
120
|
backgroundStartup
|
|
115
121
|
]);
|
|
116
|
-
const clients = await worker.clients.matchAll({
|
|
117
|
-
includeUncontrolled: true,
|
|
118
|
-
type: "window"
|
|
119
|
-
});
|
|
120
|
-
await Promise.all(clients.map((client) => client.navigate(client.url)));
|
|
121
122
|
}
|
|
122
123
|
async function deleteOldCaches() {
|
|
123
124
|
const names = await caches.keys();
|