mirror of
https://github.com/CharaChorder/DeviceManager.git
synced 2026-01-19 16:32:58 +00:00
1165 lines
36 KiB
JavaScript
1165 lines
36 KiB
JavaScript
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
}) : x)(function(x) {
|
|
if (typeof require !== "undefined")
|
|
return require.apply(this, arguments);
|
|
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
});
|
|
|
|
// src/context.ts
|
|
function createContext(userOptions) {
|
|
return {
|
|
userOptions,
|
|
options: void 0,
|
|
viteConfig: void 0,
|
|
useImportRegister: false,
|
|
devEnvironment: false
|
|
};
|
|
}
|
|
|
|
// src/constants.ts
|
|
var FILE_SW_REGISTER = "registerSW.js";
|
|
var VIRTUAL_MODULES_MAP = {
|
|
"virtual:pwa-register": "register",
|
|
"virtual:pwa-register/vue": "vue",
|
|
"virtual:pwa-register/svelte": "svelte",
|
|
"virtual:pwa-register/react": "react",
|
|
"virtual:pwa-register/preact": "preact",
|
|
"virtual:pwa-register/solid": "solid"
|
|
};
|
|
var VIRTUAL_MODULES_RESOLVE_PREFIX = "/@vite-plugin-pwa/";
|
|
var VIRTUAL_MODULES = Object.keys(VIRTUAL_MODULES_MAP);
|
|
var defaultInjectManifestVitePlugins = [
|
|
"alias",
|
|
"commonjs",
|
|
"vite:resolve",
|
|
"vite:esbuild",
|
|
"replace",
|
|
"vite:define",
|
|
"rollup-plugin-dynamic-import-variables",
|
|
"vite:esbuild-transpile",
|
|
"vite:json",
|
|
"vite:terser"
|
|
];
|
|
var PWA_INFO_VIRTUAL = "virtual:pwa-info";
|
|
var RESOLVED_PWA_INFO_VIRTUAL = `\0${PWA_INFO_VIRTUAL}`;
|
|
var DEV_SW_NAME = "dev-sw.js?dev-sw";
|
|
var DEV_SW_VIRTUAL = `${VIRTUAL_MODULES_RESOLVE_PREFIX}pwa-entry-point-loaded`;
|
|
var RESOLVED_DEV_SW_VIRTUAL = `\0${DEV_SW_VIRTUAL}`;
|
|
var DEV_READY_NAME = "vite-pwa-plugin:dev-ready";
|
|
var DEV_REGISTER_SW_NAME = "vite-plugin-pwa:register-sw";
|
|
|
|
// src/html.ts
|
|
function generateSimpleSWRegister(options2, dev) {
|
|
const path = dev ? `${options2.base}${DEV_SW_NAME}` : `${options2.buildBase}${options2.filename}`;
|
|
if (dev) {
|
|
const swType = options2.devOptions.type ?? "classic";
|
|
return `if('serviceWorker' in navigator) navigator.serviceWorker.register('${path}', { scope: '${options2.scope}', type: '${swType}' })`;
|
|
}
|
|
return `
|
|
if('serviceWorker' in navigator) {
|
|
window.addEventListener('load', () => {
|
|
navigator.serviceWorker.register('${path}', { scope: '${options2.scope}' })
|
|
})
|
|
}`.replace(/\n/g, "");
|
|
}
|
|
function injectServiceWorker(html, options2, dev) {
|
|
const manifest = generateWebManifest(options2, dev);
|
|
if (!dev) {
|
|
const script = generateRegisterSW(options2, dev);
|
|
if (script) {
|
|
return html.replace(
|
|
"</head>",
|
|
`${manifest}${script}</head>`
|
|
);
|
|
}
|
|
}
|
|
return html.replace(
|
|
"</head>",
|
|
`${manifest}</head>`
|
|
);
|
|
}
|
|
function generateWebManifest(options2, dev) {
|
|
const crossorigin = options2.useCredentials ? ' crossorigin="use-credentials"' : "";
|
|
if (dev) {
|
|
const name = options2.devOptions.webManifestUrl ?? `${options2.base}${options2.manifestFilename}`;
|
|
return options2.manifest ? `<link rel="manifest" href="${name}"${crossorigin}>` : "";
|
|
} else {
|
|
return options2.manifest ? `<link rel="manifest" href="${options2.buildBase}${options2.manifestFilename}"${crossorigin}>` : "";
|
|
}
|
|
}
|
|
function generateRegisterSW(options2, dev) {
|
|
if (options2.injectRegister === "inline")
|
|
return `<script id="vite-plugin-pwa:inline-sw">${generateSimpleSWRegister(options2, dev)}</script>`;
|
|
else if (options2.injectRegister === "script")
|
|
return `<script id="vite-plugin-pwa:register-sw" src="${dev ? options2.base : options2.buildBase}${FILE_SW_REGISTER}"></script>`;
|
|
return void 0;
|
|
}
|
|
function generateRegisterDevSW(base) {
|
|
const path = `${base.endsWith("/") ? base : `${base}/`}${DEV_SW_VIRTUAL.slice(1)}`;
|
|
return `<script id="vite-plugin-pwa:register-dev-sw" type="module">
|
|
import registerDevSW from '${path}';
|
|
registerDevSW();
|
|
</script>`;
|
|
}
|
|
function generateSWHMR() {
|
|
return `
|
|
import.meta.hot.on('${DEV_REGISTER_SW_NAME}', ({ inline, inlinePath, registerPath, scope, swType = 'classic' }) => {
|
|
if (inline) {
|
|
if('serviceWorker' in navigator) {
|
|
navigator.serviceWorker.register(inlinePath, { scope, type: swType });
|
|
}
|
|
}
|
|
else {
|
|
const registerSW = document.createElement('script');
|
|
registerSW.setAttribute('id', 'vite-plugin-pwa:register-sw');
|
|
registerSW.setAttribute('src', registerPath);
|
|
document.head.appendChild(registerSW);
|
|
}
|
|
});
|
|
function registerDevSW() {
|
|
try {
|
|
import.meta.hot.send('${DEV_READY_NAME}');
|
|
} catch (e) {
|
|
console.error('unable to send ${DEV_READY_NAME} message to register service worker in dev mode!', e);
|
|
}
|
|
}
|
|
export default registerDevSW;
|
|
`;
|
|
}
|
|
|
|
// src/api.ts
|
|
import { resolve as resolve2 } from "node:path";
|
|
import { existsSync } from "node:fs";
|
|
|
|
// src/modules.ts
|
|
import { dirname, resolve } from "node:path";
|
|
import { promises as fs } from "node:fs";
|
|
import { fileURLToPath } from "node:url";
|
|
|
|
// src/log.ts
|
|
import { relative } from "node:path";
|
|
|
|
// node_modules/.pnpm/kolorist@1.8.0/node_modules/kolorist/dist/esm/index.mjs
|
|
var enabled = true;
|
|
var globalVar = typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : typeof global !== "undefined" ? global : {};
|
|
var supportLevel = 0;
|
|
if (globalVar.process && globalVar.process.env && globalVar.process.stdout) {
|
|
const { FORCE_COLOR, NODE_DISABLE_COLORS, NO_COLOR, TERM, COLORTERM } = globalVar.process.env;
|
|
if (NODE_DISABLE_COLORS || NO_COLOR || FORCE_COLOR === "0") {
|
|
enabled = false;
|
|
} else if (FORCE_COLOR === "1" || FORCE_COLOR === "2" || FORCE_COLOR === "3") {
|
|
enabled = true;
|
|
} else if (TERM === "dumb") {
|
|
enabled = false;
|
|
} else if ("CI" in globalVar.process.env && [
|
|
"TRAVIS",
|
|
"CIRCLECI",
|
|
"APPVEYOR",
|
|
"GITLAB_CI",
|
|
"GITHUB_ACTIONS",
|
|
"BUILDKITE",
|
|
"DRONE"
|
|
].some((vendor) => vendor in globalVar.process.env)) {
|
|
enabled = true;
|
|
} else {
|
|
enabled = process.stdout.isTTY;
|
|
}
|
|
if (enabled) {
|
|
if (process.platform === "win32") {
|
|
supportLevel = 3;
|
|
} else {
|
|
if (COLORTERM && (COLORTERM === "truecolor" || COLORTERM === "24bit")) {
|
|
supportLevel = 3;
|
|
} else if (TERM && (TERM.endsWith("-256color") || TERM.endsWith("256"))) {
|
|
supportLevel = 2;
|
|
} else {
|
|
supportLevel = 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
var options = {
|
|
enabled,
|
|
supportLevel
|
|
};
|
|
function kolorist(start, end, level = 1) {
|
|
const open = `\x1B[${start}m`;
|
|
const close = `\x1B[${end}m`;
|
|
const regex = new RegExp(`\\x1b\\[${end}m`, "g");
|
|
return (str) => {
|
|
return options.enabled && options.supportLevel >= level ? open + ("" + str).replace(regex, open) + close : "" + str;
|
|
};
|
|
}
|
|
var reset = kolorist(0, 0);
|
|
var bold = kolorist(1, 22);
|
|
var dim = kolorist(2, 22);
|
|
var italic = kolorist(3, 23);
|
|
var underline = kolorist(4, 24);
|
|
var inverse = kolorist(7, 27);
|
|
var hidden = kolorist(8, 28);
|
|
var strikethrough = kolorist(9, 29);
|
|
var black = kolorist(30, 39);
|
|
var red = kolorist(31, 39);
|
|
var green = kolorist(32, 39);
|
|
var yellow = kolorist(33, 39);
|
|
var blue = kolorist(34, 39);
|
|
var magenta = kolorist(35, 39);
|
|
var cyan = kolorist(36, 39);
|
|
var white = kolorist(97, 39);
|
|
var gray = kolorist(90, 39);
|
|
var lightGray = kolorist(37, 39);
|
|
var lightRed = kolorist(91, 39);
|
|
var lightGreen = kolorist(92, 39);
|
|
var lightYellow = kolorist(93, 39);
|
|
var lightBlue = kolorist(94, 39);
|
|
var lightMagenta = kolorist(95, 39);
|
|
var lightCyan = kolorist(96, 39);
|
|
var bgBlack = kolorist(40, 49);
|
|
var bgRed = kolorist(41, 49);
|
|
var bgGreen = kolorist(42, 49);
|
|
var bgYellow = kolorist(43, 49);
|
|
var bgBlue = kolorist(44, 49);
|
|
var bgMagenta = kolorist(45, 49);
|
|
var bgCyan = kolorist(46, 49);
|
|
var bgWhite = kolorist(107, 49);
|
|
var bgGray = kolorist(100, 49);
|
|
var bgLightRed = kolorist(101, 49);
|
|
var bgLightGreen = kolorist(102, 49);
|
|
var bgLightYellow = kolorist(103, 49);
|
|
var bgLightBlue = kolorist(104, 49);
|
|
var bgLightMagenta = kolorist(105, 49);
|
|
var bgLightCyan = kolorist(106, 49);
|
|
var bgLightGray = kolorist(47, 49);
|
|
|
|
// package.json
|
|
var version = "0.16.5";
|
|
|
|
// src/log.ts
|
|
function logWorkboxResult(strategy, buildResult, viteOptions) {
|
|
const { root, logLevel = "info" } = viteOptions;
|
|
if (logLevel === "silent")
|
|
return;
|
|
const { count, size, filePaths, warnings } = buildResult;
|
|
if (logLevel === "info") {
|
|
console.info([
|
|
"",
|
|
`${cyan(`PWA v${version}`)}`,
|
|
`mode ${magenta(strategy)}`,
|
|
`precache ${green(`${count} entries`)} ${dim(`(${(size / 1024).toFixed(2)} KiB)`)}`,
|
|
"files generated",
|
|
...filePaths.map((p) => ` ${dim(relative(root, p))}`)
|
|
].join("\n"));
|
|
}
|
|
warnings && warnings.length > 0 && console.warn(yellow([
|
|
"warnings",
|
|
...warnings.map((w) => ` ${w}`),
|
|
""
|
|
].join("\n")));
|
|
}
|
|
|
|
// src/modules.ts
|
|
var _dirname = typeof __dirname !== "undefined" ? __dirname : dirname(fileURLToPath(import.meta.url));
|
|
async function loadWorkboxBuild() {
|
|
try {
|
|
const workbox = await import("workbox-build");
|
|
return workbox.default ?? workbox;
|
|
} catch (_) {
|
|
return __require("workbox-build");
|
|
}
|
|
}
|
|
async function generateRegisterSW2(options2, mode, source = "register") {
|
|
const sw = options2.buildBase + options2.filename;
|
|
const scope = options2.scope;
|
|
const content = await fs.readFile(resolve(_dirname, `client/${mode}/${source}.js`), "utf-8");
|
|
return content.replace(/__SW__/g, sw).replace("__SCOPE__", scope).replace("__SW_AUTO_UPDATE__", `${options2.registerType === "autoUpdate"}`).replace("__SW_SELF_DESTROYING__", `${options2.selfDestroying}`).replace("__TYPE__", `${options2.devOptions.enabled ? options2.devOptions.type : "classic"}`);
|
|
}
|
|
async function generateServiceWorker(options2, viteOptions) {
|
|
if (options2.selfDestroying) {
|
|
const selfDestroyingSW = `
|
|
self.addEventListener('install', function(e) {
|
|
self.skipWaiting();
|
|
});
|
|
self.addEventListener('activate', function(e) {
|
|
self.registration.unregister()
|
|
.then(function() {
|
|
return self.clients.matchAll();
|
|
})
|
|
.then(function(clients) {
|
|
clients.forEach(client => client.navigate(client.url))
|
|
});
|
|
});
|
|
`;
|
|
await fs.writeFile(options2.swDest.replace(/\\/g, "/"), selfDestroyingSW, { encoding: "utf8" });
|
|
return {
|
|
count: 1,
|
|
size: selfDestroyingSW.length,
|
|
warnings: [],
|
|
filePaths: [options2.filename]
|
|
};
|
|
}
|
|
const { generateSW } = await loadWorkboxBuild();
|
|
const buildResult = await generateSW(options2.workbox);
|
|
logWorkboxResult("generateSW", buildResult, viteOptions);
|
|
return buildResult;
|
|
}
|
|
async function generateInjectManifest(options2, viteOptions) {
|
|
const { selfDestroying } = options2;
|
|
if (selfDestroying) {
|
|
await generateServiceWorker(options2, viteOptions);
|
|
return;
|
|
}
|
|
const { build } = await import("vite");
|
|
const define = { ...viteOptions.define ?? {} };
|
|
define["process.env.NODE_ENV"] = JSON.stringify(options2.mode);
|
|
const { format, plugins, rollupOptions } = options2.injectManifestRollupOptions;
|
|
await build({
|
|
root: viteOptions.root,
|
|
base: viteOptions.base,
|
|
resolve: viteOptions.resolve,
|
|
// don't copy anything from public folder
|
|
publicDir: false,
|
|
build: {
|
|
sourcemap: viteOptions.build.sourcemap,
|
|
lib: {
|
|
entry: options2.swSrc,
|
|
name: "app",
|
|
formats: [format]
|
|
},
|
|
rollupOptions: {
|
|
...rollupOptions,
|
|
plugins,
|
|
output: {
|
|
entryFileNames: options2.filename
|
|
}
|
|
},
|
|
outDir: options2.outDir,
|
|
emptyOutDir: false
|
|
},
|
|
configFile: false,
|
|
define
|
|
});
|
|
if (!options2.injectManifest.injectionPoint)
|
|
return;
|
|
const injectManifestOptions = {
|
|
...options2.injectManifest,
|
|
// this will not fail since there is an injectionPoint
|
|
swSrc: options2.injectManifest.swDest
|
|
};
|
|
const { injectManifest } = await loadWorkboxBuild();
|
|
const buildResult = await injectManifest(injectManifestOptions);
|
|
logWorkboxResult("injectManifest", buildResult, viteOptions);
|
|
}
|
|
|
|
// src/assets.ts
|
|
import { resolve as resolveFs } from "node:path";
|
|
import fs2 from "node:fs";
|
|
import crypto from "node:crypto";
|
|
import fg from "fast-glob";
|
|
function buildManifestEntry(publicDir, url) {
|
|
return new Promise((resolve5, reject) => {
|
|
const cHash = crypto.createHash("MD5");
|
|
const stream = fs2.createReadStream(resolveFs(publicDir, url));
|
|
stream.on("error", (err) => {
|
|
reject(err);
|
|
});
|
|
stream.on("data", (chunk) => {
|
|
cHash.update(chunk);
|
|
});
|
|
stream.on("end", () => {
|
|
return resolve5({
|
|
url,
|
|
revision: `${cHash.digest("hex")}`
|
|
});
|
|
});
|
|
});
|
|
}
|
|
function lookupAdditionalManifestEntries(useInjectManifest, injectManifest, workbox) {
|
|
return useInjectManifest ? injectManifest.additionalManifestEntries || [] : workbox.additionalManifestEntries || [];
|
|
}
|
|
function normalizeIconPath(path) {
|
|
return path.startsWith("/") ? path.substring(1) : path;
|
|
}
|
|
function includeIcons(icons, globs) {
|
|
Object.keys(icons).forEach((key) => {
|
|
const icon = icons[key];
|
|
const src = normalizeIconPath(icon.src);
|
|
if (!globs.includes(src))
|
|
globs.push(src);
|
|
});
|
|
}
|
|
async function configureStaticAssets(resolvedVitePWAOptions, viteConfig) {
|
|
const {
|
|
manifest,
|
|
strategies,
|
|
injectManifest,
|
|
workbox,
|
|
includeAssets,
|
|
includeManifestIcons,
|
|
manifestFilename
|
|
} = resolvedVitePWAOptions;
|
|
const useInjectManifest = strategies === "injectManifest";
|
|
const { publicDir } = viteConfig;
|
|
const globs = [];
|
|
const manifestEntries = lookupAdditionalManifestEntries(
|
|
useInjectManifest,
|
|
injectManifest,
|
|
workbox
|
|
);
|
|
if (includeAssets) {
|
|
if (Array.isArray(includeAssets))
|
|
globs.push(...includeAssets.map(normalizeIconPath));
|
|
else
|
|
globs.push(normalizeIconPath(includeAssets));
|
|
}
|
|
if (includeManifestIcons && manifest) {
|
|
manifest.icons && includeIcons(manifest.icons, globs);
|
|
manifest.shortcuts && manifest.shortcuts.forEach((s) => {
|
|
s.icons && includeIcons(s.icons, globs);
|
|
});
|
|
}
|
|
if (globs.length > 0) {
|
|
let assets = await fg(
|
|
globs,
|
|
{
|
|
cwd: publicDir,
|
|
onlyFiles: true,
|
|
unique: true
|
|
}
|
|
);
|
|
if (manifestEntries.length > 0) {
|
|
const included = manifestEntries.map((me) => {
|
|
if (typeof me === "string")
|
|
return me;
|
|
else
|
|
return me.url;
|
|
});
|
|
assets = assets.filter((a) => !included.includes(a));
|
|
}
|
|
const assetsEntries = await Promise.all(assets.map((a) => {
|
|
return buildManifestEntry(publicDir, a);
|
|
}));
|
|
manifestEntries.push(...assetsEntries);
|
|
}
|
|
if (manifest) {
|
|
const cHash = crypto.createHash("MD5");
|
|
cHash.update(generateWebManifestFile(resolvedVitePWAOptions));
|
|
manifestEntries.push({
|
|
url: manifestFilename,
|
|
revision: `${cHash.digest("hex")}`
|
|
});
|
|
}
|
|
if (manifestEntries.length > 0) {
|
|
if (useInjectManifest)
|
|
injectManifest.additionalManifestEntries = manifestEntries;
|
|
else
|
|
workbox.additionalManifestEntries = manifestEntries;
|
|
}
|
|
}
|
|
function generateWebManifestFile(options2) {
|
|
return `${JSON.stringify(options2.manifest, null, options2.minify ? 0 : 2)}
|
|
`;
|
|
}
|
|
|
|
// src/api.ts
|
|
async function _generateSW({ options: options2, viteConfig }) {
|
|
if (options2.disable)
|
|
return;
|
|
if (options2.strategies === "injectManifest")
|
|
await generateInjectManifest(options2, viteConfig);
|
|
else
|
|
await generateServiceWorker(options2, viteConfig);
|
|
}
|
|
function _generateBundle({ options: options2, viteConfig, useImportRegister }, bundle) {
|
|
if (options2.disable || !bundle)
|
|
return;
|
|
if (options2.manifest) {
|
|
bundle[options2.manifestFilename] = {
|
|
// @ts-expect-error: for Vite 3 support, Vite 4 has removed `isAsset` property
|
|
isAsset: true,
|
|
type: "asset",
|
|
name: void 0,
|
|
source: generateWebManifestFile(options2),
|
|
fileName: options2.manifestFilename
|
|
};
|
|
}
|
|
if (options2.injectRegister === "auto")
|
|
options2.injectRegister = useImportRegister ? null : "script";
|
|
if (options2.injectRegister === "script" && !existsSync(resolve2(viteConfig.publicDir, FILE_SW_REGISTER))) {
|
|
bundle[FILE_SW_REGISTER] = {
|
|
// @ts-expect-error: for Vite 3 support, Vite 4 has removed `isAsset` property
|
|
isAsset: true,
|
|
type: "asset",
|
|
name: void 0,
|
|
source: generateSimpleSWRegister(options2, false),
|
|
fileName: FILE_SW_REGISTER
|
|
};
|
|
}
|
|
return bundle;
|
|
}
|
|
function createAPI(ctx) {
|
|
return {
|
|
get disabled() {
|
|
return ctx?.options?.disable;
|
|
},
|
|
get pwaInDevEnvironment() {
|
|
return ctx?.devEnvironment === true;
|
|
},
|
|
webManifestData() {
|
|
const options2 = ctx?.options;
|
|
if (!options2 || options2.disable || !options2.manifest || ctx.devEnvironment && !ctx.options.devOptions.enabled)
|
|
return void 0;
|
|
let url = options2.manifestFilename;
|
|
let manifest;
|
|
if (ctx.devEnvironment && ctx.options.devOptions.enabled === true) {
|
|
url = ctx.options.devOptions.webManifestUrl ?? options2.manifestFilename;
|
|
manifest = generateWebManifest(options2, true);
|
|
} else {
|
|
manifest = generateWebManifest(options2, false);
|
|
}
|
|
return {
|
|
href: `${ctx.devEnvironment ? options2.base : options2.buildBase}${url}`,
|
|
useCredentials: ctx.options.useCredentials,
|
|
toLinkTag() {
|
|
return manifest;
|
|
}
|
|
};
|
|
},
|
|
registerSWData() {
|
|
const options2 = ctx?.options;
|
|
if (!options2 || options2.disable || ctx.devEnvironment && !ctx.options.devOptions.enabled)
|
|
return void 0;
|
|
const mode = options2.injectRegister;
|
|
if (!mode || ctx.useImportRegister)
|
|
return void 0;
|
|
let type = "classic";
|
|
let script;
|
|
let shouldRegisterSW = options2.injectRegister === "inline" || options2.injectRegister === "script";
|
|
if (ctx.devEnvironment && ctx.options.devOptions.enabled === true) {
|
|
type = ctx.options.devOptions.type ?? "classic";
|
|
script = generateRegisterDevSW(ctx.options.base);
|
|
shouldRegisterSW = true;
|
|
} else if (shouldRegisterSW) {
|
|
script = generateRegisterSW(options2, false);
|
|
}
|
|
const base = ctx.devEnvironment ? options2.base : options2.buildBase;
|
|
return {
|
|
// hint when required
|
|
shouldRegisterSW,
|
|
inline: options2.injectRegister === "inline",
|
|
scope: options2.scope,
|
|
inlinePath: `${base}${ctx.devEnvironment ? DEV_SW_NAME : options2.filename}`,
|
|
registerPath: `${base}${FILE_SW_REGISTER}`,
|
|
type,
|
|
toScriptTag() {
|
|
return script;
|
|
}
|
|
};
|
|
},
|
|
generateBundle(bundle) {
|
|
return _generateBundle(ctx, bundle);
|
|
},
|
|
async generateSW() {
|
|
return await _generateSW(ctx);
|
|
},
|
|
extendManifestEntries(fn) {
|
|
const { options: options2 } = ctx;
|
|
if (options2.disable)
|
|
return;
|
|
const configField = options2.strategies === "generateSW" ? "workbox" : "injectManifest";
|
|
const result = fn(options2[configField].additionalManifestEntries || []);
|
|
if (result != null)
|
|
options2[configField].additionalManifestEntries = result;
|
|
}
|
|
};
|
|
}
|
|
|
|
// src/plugins/build.ts
|
|
function BuildPlugin(ctx) {
|
|
return {
|
|
name: "vite-plugin-pwa:build",
|
|
enforce: "post",
|
|
apply: "build",
|
|
transformIndexHtml: {
|
|
enforce: "post",
|
|
transform(html) {
|
|
const { options: options2, useImportRegister } = ctx;
|
|
if (options2.disable)
|
|
return html;
|
|
if (options2.injectRegister === "auto")
|
|
options2.injectRegister = useImportRegister ? null : "script";
|
|
return injectServiceWorker(html, options2, false);
|
|
}
|
|
},
|
|
generateBundle(_, bundle) {
|
|
return _generateBundle(ctx, bundle);
|
|
},
|
|
closeBundle: {
|
|
sequential: true,
|
|
order: ctx.userOptions?.integration?.closeBundleOrder,
|
|
async handler() {
|
|
if (!ctx.viteConfig.build.ssr && !ctx.options.disable)
|
|
await _generateSW(ctx);
|
|
}
|
|
},
|
|
async buildEnd(error) {
|
|
if (error)
|
|
throw error;
|
|
}
|
|
};
|
|
}
|
|
|
|
// src/plugins/dev.ts
|
|
import { basename, resolve as resolve3 } from "node:path";
|
|
import { existsSync as existsSync2, promises as fs3, mkdirSync } from "node:fs";
|
|
|
|
// src/utils.ts
|
|
function resolveBasePath(base) {
|
|
if (isAbsolute(base))
|
|
return base;
|
|
return !base.startsWith("/") && !base.startsWith("./") ? `/${base}` : base;
|
|
}
|
|
function isAbsolute(url) {
|
|
return url.match(/^(?:[a-z]+:)?\/\//i);
|
|
}
|
|
function normalizePath(path) {
|
|
return path.replace(/\\/g, "/");
|
|
}
|
|
|
|
// src/plugins/dev.ts
|
|
var swDevOptions = {
|
|
swUrl: DEV_SW_NAME,
|
|
swDevGenerated: false,
|
|
workboxPaths: /* @__PURE__ */ new Map()
|
|
};
|
|
function DevPlugin(ctx) {
|
|
return {
|
|
name: "vite-plugin-pwa:dev-sw",
|
|
apply: "serve",
|
|
transformIndexHtml: {
|
|
enforce: "post",
|
|
async transform(html) {
|
|
const { options: options2 } = ctx;
|
|
if (options2.disable || !options2.manifest || !options2.devOptions.enabled)
|
|
return html;
|
|
html = injectServiceWorker(html, options2, true);
|
|
return html.replace(
|
|
"</body>",
|
|
`${generateRegisterDevSW(options2.base)}
|
|
</body>`
|
|
);
|
|
}
|
|
},
|
|
configureServer(server) {
|
|
ctx.devEnvironment = true;
|
|
const { options: options2 } = ctx;
|
|
if (!options2.disable && options2.manifest && options2.devOptions.enabled) {
|
|
server.ws.on(DEV_READY_NAME, createSWResponseHandler(server, ctx));
|
|
const name = options2.devOptions.webManifestUrl ?? `${options2.base}${options2.manifestFilename}`;
|
|
server.middlewares.use((req, res, next) => {
|
|
if (req.url === name) {
|
|
res.statusCode = 200;
|
|
res.setHeader("Content-Type", "application/manifest+json");
|
|
res.write(generateWebManifestFile(options2), "utf-8");
|
|
res.end();
|
|
} else {
|
|
next();
|
|
}
|
|
});
|
|
}
|
|
},
|
|
resolveId(id) {
|
|
if (id === DEV_SW_VIRTUAL)
|
|
return RESOLVED_DEV_SW_VIRTUAL;
|
|
const { options: options2 } = ctx;
|
|
if (!options2.disable && options2.devOptions.enabled && options2.strategies === "injectManifest" && !options2.selfDestroying) {
|
|
const name = id.startsWith("/") ? id.slice(1) : id;
|
|
return name === swDevOptions.swUrl || name === options2.injectManifest.swSrc ? options2.injectManifest.swSrc : void 0;
|
|
}
|
|
return void 0;
|
|
},
|
|
async load(id) {
|
|
if (id === RESOLVED_DEV_SW_VIRTUAL)
|
|
return generateSWHMR();
|
|
const { options: options2, viteConfig } = ctx;
|
|
if (!options2.disable && options2.devOptions.enabled) {
|
|
if (options2.strategies === "injectManifest" && !options2.selfDestroying) {
|
|
const swSrc = normalizePath(options2.injectManifest.swSrc);
|
|
if (id === swSrc) {
|
|
let content = await fs3.readFile(options2.injectManifest.swSrc, "utf-8");
|
|
const resolvedIP = options2.injectManifest.injectionPoint;
|
|
if (resolvedIP) {
|
|
const ip = new RegExp(resolvedIP, "g");
|
|
const navigateFallback = options2.devOptions.navigateFallback;
|
|
if (navigateFallback)
|
|
content = content.replace(ip, `[{ url: '${navigateFallback}' }]`);
|
|
else
|
|
content = content.replace(ip, "[]");
|
|
}
|
|
return content;
|
|
}
|
|
if (swDevOptions.workboxPaths.has(id))
|
|
return await fs3.readFile(swDevOptions.workboxPaths.get(id), "utf-8");
|
|
return void 0;
|
|
}
|
|
if (id.endsWith(swDevOptions.swUrl)) {
|
|
const globDirectory = await resolveDevDistFolder(options2, viteConfig);
|
|
if (!existsSync2(globDirectory))
|
|
mkdirSync(globDirectory, { recursive: true });
|
|
const swDest = resolve3(globDirectory, "sw.js");
|
|
if (!swDevOptions.swDevGenerated || !existsSync2(swDest)) {
|
|
let suppressWarnings;
|
|
if (options2.devOptions.suppressWarnings === true) {
|
|
suppressWarnings = normalizePath(resolve3(globDirectory, "suppress-warnings.js"));
|
|
await fs3.writeFile(suppressWarnings, "", "utf-8");
|
|
}
|
|
const globPatterns = options2.devOptions.suppressWarnings === true ? ["*.js"] : options2.workbox.globPatterns;
|
|
const navigateFallback = options2.workbox.navigateFallback;
|
|
const { filePaths } = await generateServiceWorker(
|
|
Object.assign(
|
|
{},
|
|
options2,
|
|
{
|
|
swDest: options2.selfDestroying ? swDest : options2.swDest,
|
|
workbox: {
|
|
...options2.workbox,
|
|
navigateFallbackAllowlist: options2.devOptions.navigateFallbackAllowlist ?? [/^\/$/],
|
|
runtimeCaching: options2.devOptions.disableRuntimeConfig ? void 0 : options2.workbox.runtimeCaching,
|
|
// we only include navigateFallback: add revision to remove workbox-build warning
|
|
additionalManifestEntries: navigateFallback ? [{
|
|
url: navigateFallback,
|
|
revision: Math.random().toString(32)
|
|
}] : void 0,
|
|
cleanupOutdatedCaches: true,
|
|
globDirectory: normalizePath(globDirectory),
|
|
globPatterns,
|
|
swDest: normalizePath(swDest)
|
|
}
|
|
}
|
|
),
|
|
viteConfig
|
|
);
|
|
filePaths.forEach((we) => {
|
|
const name = basename(we);
|
|
if (name !== "sw.js")
|
|
swDevOptions.workboxPaths.set(normalizePath(`${options2.base}${name}`), we);
|
|
});
|
|
if (suppressWarnings) {
|
|
swDevOptions.workboxPaths.set(
|
|
normalizePath(`${options2.base}${basename(suppressWarnings)}`),
|
|
suppressWarnings
|
|
);
|
|
}
|
|
swDevOptions.swDevGenerated = true;
|
|
}
|
|
return await fs3.readFile(swDest, "utf-8");
|
|
}
|
|
if (id.startsWith(options2.base)) {
|
|
const key = normalizePath(id);
|
|
if (swDevOptions.workboxPaths.has(key))
|
|
return await fs3.readFile(swDevOptions.workboxPaths.get(key), "utf-8");
|
|
}
|
|
}
|
|
}
|
|
};
|
|
}
|
|
async function resolveDevDistFolder(options2, viteConfig) {
|
|
return options2.devOptions.resolveTempFolder ? await options2.devOptions.resolveTempFolder() : resolve3(viteConfig.root, "dev-dist");
|
|
}
|
|
async function createDevRegisterSW(options2, viteConfig) {
|
|
if (options2.injectRegister === "script") {
|
|
const devDist = await resolveDevDistFolder(options2, viteConfig);
|
|
if (!existsSync2(devDist))
|
|
mkdirSync(devDist);
|
|
const registerSW = resolve3(devDist, FILE_SW_REGISTER);
|
|
if (existsSync2(registerSW)) {
|
|
if (!swDevOptions.workboxPaths.has(registerSW))
|
|
swDevOptions.workboxPaths.set(normalizePath(`${options2.base}${FILE_SW_REGISTER}`), registerSW);
|
|
return;
|
|
}
|
|
await fs3.writeFile(registerSW, generateSimpleSWRegister(options2, true), { encoding: "utf8" });
|
|
swDevOptions.workboxPaths.set(normalizePath(`${options2.base}${FILE_SW_REGISTER}`), registerSW);
|
|
}
|
|
}
|
|
function createSWResponseHandler(server, ctx) {
|
|
return async () => {
|
|
const { options: options2, useImportRegister } = ctx;
|
|
const { injectRegister, scope, base } = options2;
|
|
if (!useImportRegister && injectRegister) {
|
|
if (injectRegister === "auto")
|
|
options2.injectRegister = "script";
|
|
await createDevRegisterSW(options2, ctx.viteConfig);
|
|
server.ws.send({
|
|
type: "custom",
|
|
event: DEV_REGISTER_SW_NAME,
|
|
data: {
|
|
inline: options2.injectRegister === "inline",
|
|
scope,
|
|
inlinePath: `${base}${DEV_SW_NAME}`,
|
|
registerPath: `${base}${FILE_SW_REGISTER}`,
|
|
swType: options2.devOptions.type
|
|
}
|
|
});
|
|
}
|
|
};
|
|
}
|
|
|
|
// src/options.ts
|
|
import fs4 from "node:fs";
|
|
import { extname, resolve as resolve4 } from "node:path";
|
|
import process2 from "node:process";
|
|
function resolveSwPaths(injectManifest, root, srcDir, outDir, filename) {
|
|
const swSrc = resolve4(root, srcDir, filename);
|
|
if (injectManifest && extname(filename) === ".ts" && fs4.existsSync(swSrc)) {
|
|
const useFilename = `${filename.substring(0, filename.lastIndexOf("."))}.js`;
|
|
return {
|
|
swSrc,
|
|
swDest: resolve4(root, outDir, useFilename),
|
|
useFilename
|
|
};
|
|
}
|
|
return {
|
|
swSrc,
|
|
swDest: resolve4(root, outDir, filename)
|
|
};
|
|
}
|
|
async function resolveOptions(options2, viteConfig) {
|
|
const root = viteConfig.root;
|
|
const pkg = fs4.existsSync("package.json") ? JSON.parse(fs4.readFileSync("package.json", "utf-8")) : {};
|
|
const {
|
|
// prevent tsup replacing `process.env`
|
|
// eslint-disable-next-line dot-notation
|
|
mode = process2["env"]["NODE_ENV"] || "production",
|
|
srcDir = "public",
|
|
outDir = viteConfig.build.outDir || "dist",
|
|
injectRegister = "auto",
|
|
registerType = "prompt",
|
|
filename = "sw.js",
|
|
manifestFilename = "manifest.webmanifest",
|
|
strategies = "generateSW",
|
|
minify = true,
|
|
base = viteConfig.base,
|
|
includeAssets = void 0,
|
|
includeManifestIcons = true,
|
|
useCredentials = false,
|
|
disable = false,
|
|
devOptions = { enabled: false, type: "classic", suppressWarnings: false },
|
|
selfDestroying = false,
|
|
integration = {},
|
|
buildBase
|
|
} = options2;
|
|
const basePath = resolveBasePath(base);
|
|
const { swSrc, swDest, useFilename } = resolveSwPaths(
|
|
strategies === "injectManifest",
|
|
root,
|
|
srcDir,
|
|
outDir,
|
|
filename
|
|
);
|
|
const outDirRoot = resolve4(root, outDir);
|
|
const scope = options2.scope || basePath;
|
|
const defaultWorkbox = {
|
|
swDest,
|
|
globDirectory: outDirRoot,
|
|
offlineGoogleAnalytics: false,
|
|
cleanupOutdatedCaches: true,
|
|
dontCacheBustURLsMatching: /[.-][a-f0-9]{8}\./,
|
|
mode,
|
|
navigateFallback: "index.html"
|
|
};
|
|
const defaultInjectManifest = {
|
|
swSrc,
|
|
swDest,
|
|
globDirectory: outDirRoot,
|
|
dontCacheBustURLsMatching: /[.-][a-f0-9]{8}\./,
|
|
injectionPoint: "self.__WB_MANIFEST"
|
|
};
|
|
const defaultManifest = {
|
|
name: pkg.name,
|
|
short_name: pkg.name,
|
|
start_url: basePath,
|
|
display: "standalone",
|
|
background_color: "#ffffff",
|
|
lang: "en",
|
|
scope
|
|
};
|
|
const workbox = Object.assign({}, defaultWorkbox, options2.workbox || {});
|
|
const manifest = typeof options2.manifest === "boolean" && !options2.manifest ? false : Object.assign({}, defaultManifest, options2.manifest || {});
|
|
const {
|
|
vitePlugins = defaultInjectManifestVitePlugins,
|
|
plugins = [],
|
|
rollupOptions = {},
|
|
rollupFormat = "es",
|
|
...userInjectManifest
|
|
} = options2.injectManifest || {};
|
|
const injectManifest = Object.assign({}, defaultInjectManifest, userInjectManifest);
|
|
if ((injectRegister === "auto" || injectRegister == null) && registerType === "autoUpdate") {
|
|
workbox.skipWaiting = true;
|
|
workbox.clientsClaim = true;
|
|
}
|
|
if (strategies === "generateSW" && workbox.sourcemap === void 0) {
|
|
const sourcemap = viteConfig.build?.sourcemap;
|
|
workbox.sourcemap = sourcemap === true || sourcemap === "inline" || sourcemap === "hidden";
|
|
}
|
|
if (devOptions.enabled && viteConfig.command === "serve") {
|
|
if (strategies === "generateSW")
|
|
devOptions.type = "classic";
|
|
} else {
|
|
devOptions.enabled = false;
|
|
devOptions.type = "classic";
|
|
}
|
|
const resolvedVitePWAOptions = {
|
|
base: basePath,
|
|
mode,
|
|
swSrc,
|
|
swDest,
|
|
srcDir,
|
|
outDir,
|
|
injectRegister,
|
|
registerType,
|
|
filename: useFilename || filename,
|
|
manifestFilename,
|
|
strategies,
|
|
workbox,
|
|
manifest,
|
|
useCredentials,
|
|
injectManifest,
|
|
scope,
|
|
minify,
|
|
includeAssets,
|
|
includeManifestIcons,
|
|
disable,
|
|
integration,
|
|
devOptions,
|
|
rollupFormat,
|
|
vitePlugins,
|
|
selfDestroying,
|
|
buildBase: buildBase ?? basePath,
|
|
injectManifestRollupOptions: {
|
|
plugins,
|
|
rollupOptions,
|
|
format: rollupFormat
|
|
}
|
|
};
|
|
const calculateHash = !resolvedVitePWAOptions.disable && resolvedVitePWAOptions.manifest && (viteConfig.command === "build" || resolvedVitePWAOptions.devOptions.enabled);
|
|
if (calculateHash)
|
|
await configureStaticAssets(resolvedVitePWAOptions, viteConfig);
|
|
return resolvedVitePWAOptions;
|
|
}
|
|
|
|
// src/plugins/main.ts
|
|
function MainPlugin(ctx, api) {
|
|
return {
|
|
name: "vite-plugin-pwa",
|
|
enforce: "pre",
|
|
config() {
|
|
return {
|
|
ssr: {
|
|
// TODO: remove until workbox-window support native ESM
|
|
noExternal: ["workbox-window"]
|
|
}
|
|
};
|
|
},
|
|
async configResolved(config) {
|
|
ctx.useImportRegister = false;
|
|
ctx.viteConfig = config;
|
|
ctx.userOptions?.integration?.configureOptions?.(config, ctx.userOptions);
|
|
ctx.options = await resolveOptions(ctx.userOptions, config);
|
|
},
|
|
resolveId(id) {
|
|
return VIRTUAL_MODULES.includes(id) ? VIRTUAL_MODULES_RESOLVE_PREFIX + id : void 0;
|
|
},
|
|
load(id) {
|
|
if (id.startsWith(VIRTUAL_MODULES_RESOLVE_PREFIX))
|
|
id = id.slice(VIRTUAL_MODULES_RESOLVE_PREFIX.length);
|
|
else
|
|
return;
|
|
if (VIRTUAL_MODULES.includes(id)) {
|
|
ctx.useImportRegister = true;
|
|
if (ctx.viteConfig.command === "serve" && ctx.options.devOptions.enabled) {
|
|
return generateRegisterSW2(
|
|
{ ...ctx.options, filename: swDevOptions.swUrl },
|
|
"build",
|
|
VIRTUAL_MODULES_MAP[id]
|
|
);
|
|
} else {
|
|
return generateRegisterSW2(
|
|
ctx.options,
|
|
!ctx.options.disable && ctx.viteConfig.command === "build" ? "build" : "dev",
|
|
VIRTUAL_MODULES_MAP[id]
|
|
);
|
|
}
|
|
}
|
|
},
|
|
api
|
|
};
|
|
}
|
|
|
|
// src/plugins/info.ts
|
|
function InfoPlugin(ctx, api) {
|
|
return {
|
|
name: "vite-plugin-pwa:info",
|
|
enforce: "post",
|
|
resolveId(id) {
|
|
if (id === PWA_INFO_VIRTUAL)
|
|
return RESOLVED_PWA_INFO_VIRTUAL;
|
|
return void 0;
|
|
},
|
|
load(id) {
|
|
if (id === RESOLVED_PWA_INFO_VIRTUAL)
|
|
return generatePwaInfo(ctx, api);
|
|
}
|
|
};
|
|
}
|
|
function generatePwaInfo(ctx, api) {
|
|
const webManifestData = api.webManifestData();
|
|
if (!webManifestData)
|
|
return "export const pwaInfo = undefined;";
|
|
const { href, useCredentials, toLinkTag } = webManifestData;
|
|
const registerSWData = api.registerSWData();
|
|
const entry = {
|
|
pwaInDevEnvironment: api.pwaInDevEnvironment,
|
|
webManifest: {
|
|
href,
|
|
useCredentials,
|
|
linkTag: toLinkTag()
|
|
}
|
|
};
|
|
if (registerSWData) {
|
|
const scriptTag = registerSWData.toScriptTag();
|
|
if (scriptTag) {
|
|
const { inline, inlinePath, registerPath, type, scope } = registerSWData;
|
|
entry.registerSW = {
|
|
inline,
|
|
inlinePath,
|
|
registerPath,
|
|
type,
|
|
scope,
|
|
scriptTag
|
|
};
|
|
}
|
|
}
|
|
return `export const pwaInfo = ${JSON.stringify(entry)};`;
|
|
}
|
|
|
|
// src/cache.ts
|
|
var cachePreset = [
|
|
{
|
|
urlPattern: /^https:\/\/fonts\.(?:googleapis|gstatic)\.com\/.*/i,
|
|
handler: "CacheFirst",
|
|
options: {
|
|
cacheName: "google-fonts",
|
|
expiration: {
|
|
maxEntries: 4,
|
|
maxAgeSeconds: 365 * 24 * 60 * 60
|
|
// 365 days
|
|
}
|
|
}
|
|
},
|
|
{
|
|
urlPattern: /\.(?:eot|otf|ttc|ttf|woff|woff2|font.css)$/i,
|
|
handler: "StaleWhileRevalidate",
|
|
options: {
|
|
cacheName: "static-font-assets",
|
|
expiration: {
|
|
maxEntries: 4,
|
|
maxAgeSeconds: 7 * 24 * 60 * 60
|
|
// 7 days
|
|
}
|
|
}
|
|
},
|
|
{
|
|
urlPattern: /\.(?:jpg|jpeg|gif|png|svg|ico|webp)$/i,
|
|
handler: "StaleWhileRevalidate",
|
|
options: {
|
|
cacheName: "static-image-assets",
|
|
expiration: {
|
|
maxEntries: 64,
|
|
maxAgeSeconds: 24 * 60 * 60
|
|
// 24 hours
|
|
}
|
|
}
|
|
},
|
|
{
|
|
urlPattern: /\.(?:js)$/i,
|
|
handler: "StaleWhileRevalidate",
|
|
options: {
|
|
cacheName: "static-js-assets",
|
|
expiration: {
|
|
maxEntries: 32,
|
|
maxAgeSeconds: 24 * 60 * 60
|
|
// 24 hours
|
|
}
|
|
}
|
|
},
|
|
{
|
|
urlPattern: /\.(?:css|less)$/i,
|
|
handler: "StaleWhileRevalidate",
|
|
options: {
|
|
cacheName: "static-style-assets",
|
|
expiration: {
|
|
maxEntries: 32,
|
|
maxAgeSeconds: 24 * 60 * 60
|
|
// 24 hours
|
|
}
|
|
}
|
|
},
|
|
{
|
|
urlPattern: /\.(?:json|xml|csv)$/i,
|
|
handler: "NetworkFirst",
|
|
options: {
|
|
cacheName: "static-data-assets",
|
|
expiration: {
|
|
maxEntries: 32,
|
|
maxAgeSeconds: 24 * 60 * 60
|
|
// 24 hours
|
|
}
|
|
}
|
|
},
|
|
{
|
|
urlPattern: /\/api\/.*$/i,
|
|
handler: "NetworkFirst",
|
|
method: "GET",
|
|
options: {
|
|
cacheName: "apis",
|
|
expiration: {
|
|
maxEntries: 16,
|
|
maxAgeSeconds: 24 * 60 * 60
|
|
// 24 hours
|
|
},
|
|
networkTimeoutSeconds: 10
|
|
// fall back to cache if api does not response within 10 seconds
|
|
}
|
|
},
|
|
{
|
|
urlPattern: /.*/i,
|
|
handler: "NetworkFirst",
|
|
options: {
|
|
cacheName: "others",
|
|
expiration: {
|
|
maxEntries: 32,
|
|
maxAgeSeconds: 24 * 60 * 60
|
|
// 24 hours
|
|
},
|
|
networkTimeoutSeconds: 10
|
|
}
|
|
}
|
|
];
|
|
|
|
// src/index.ts
|
|
function VitePWA(userOptions = {}) {
|
|
const ctx = createContext(userOptions);
|
|
const api = createAPI(ctx);
|
|
return [
|
|
MainPlugin(ctx, api),
|
|
InfoPlugin(ctx, api),
|
|
BuildPlugin(ctx),
|
|
DevPlugin(ctx)
|
|
];
|
|
}
|
|
export {
|
|
VitePWA,
|
|
cachePreset,
|
|
defaultInjectManifestVitePlugins
|
|
};
|