@necrolab/dashboard 0.5.31 → 0.5.32
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/index.html +5 -6
- package/package.json +5 -5
- package/postinstall.js +86 -101
- package/public/manifest.json +4 -4
- package/scripts/build.mjs +40 -0
- package/scripts/generate-sw.mjs +43 -0
- package/src/registerServiceWorker.js +40 -27
- package/workbox-config.cjs +27 -22
- package/public/reconnect-logo.png +0 -0
- /package/public/{android-chrome-192x192.png → img/pwa/android-chrome-192x192.png} +0 -0
- /package/public/{android-chrome-512x512.png → img/pwa/android-chrome-512x512.png} +0 -0
- /package/public/{apple-touch-icon.png → img/pwa/apple-touch-icon.png} +0 -0
package/index.html
CHANGED
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
<head>
|
|
4
4
|
<meta charset="UTF-8" />
|
|
5
5
|
<link rel="icon" href="/favicon.ico" />
|
|
6
|
+
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png" />
|
|
7
|
+
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png" />
|
|
6
8
|
<meta
|
|
7
9
|
name="viewport"
|
|
8
10
|
content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover" />
|
|
@@ -97,14 +99,11 @@
|
|
|
97
99
|
<link rel="prefetch" as="image" href="/flags/ae.svg" />
|
|
98
100
|
|
|
99
101
|
<!-- Prefetch other logo variants -->
|
|
100
|
-
<link rel="prefetch" as="image" href="/android-chrome-192x192.png" />
|
|
102
|
+
<link rel="prefetch" as="image" href="/img/pwa/android-chrome-192x192.png" />
|
|
101
103
|
|
|
102
|
-
|
|
103
|
-
<link rel="prefetch" as="script" href="/sw.js" />
|
|
104
|
-
|
|
105
|
-
<link rel="manifest" href="/manifest.json?v=3" crossorigin />
|
|
104
|
+
<link rel="manifest" href="/manifest.json" crossorigin />
|
|
106
105
|
<meta name="theme-color" content="#1a1b1e" />
|
|
107
|
-
<link rel="apple-touch-icon" href="/apple-touch-icon.png
|
|
106
|
+
<link rel="apple-touch-icon" href="/img/pwa/apple-touch-icon.png" />
|
|
108
107
|
|
|
109
108
|
<!-- Prism.js for syntax highlighting -->
|
|
110
109
|
<link
|
package/package.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@necrolab/dashboard",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.32",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"scripts": {
|
|
6
|
-
"build": "
|
|
6
|
+
"build": "node scripts/build.mjs",
|
|
7
7
|
"dev": "node dev-server.js",
|
|
8
8
|
"bot": "node dev-server.js",
|
|
9
9
|
"expose": "node dev-server.js",
|
|
@@ -38,7 +38,8 @@
|
|
|
38
38
|
"vue-virtual-scroller": "^2.0.0-beta.8",
|
|
39
39
|
"vue3-toastify": "^0.0.4",
|
|
40
40
|
"vuedraggable": "^4.1.0",
|
|
41
|
-
"websocket-heartbeat-js": "^1.1.3"
|
|
41
|
+
"websocket-heartbeat-js": "^1.1.3",
|
|
42
|
+
"workbox-build": "^7.3.0"
|
|
42
43
|
},
|
|
43
44
|
"main": "index.js",
|
|
44
45
|
"devDependencies": {
|
|
@@ -46,8 +47,7 @@
|
|
|
46
47
|
"@eslint/js": "^9.39.2",
|
|
47
48
|
"eslint": "^9.17.0",
|
|
48
49
|
"eslint-plugin-vue": "^9.32.0",
|
|
49
|
-
"globals": "^17.3.0"
|
|
50
|
-
"workbox-cli": "^7.3.0"
|
|
50
|
+
"globals": "^17.3.0"
|
|
51
51
|
},
|
|
52
52
|
"overrides": {
|
|
53
53
|
"glob": "^11.0.0",
|
package/postinstall.js
CHANGED
|
@@ -1,124 +1,109 @@
|
|
|
1
1
|
import fs from "node:fs";
|
|
2
|
-
import { execSync } from "node:child_process";
|
|
3
2
|
import path from "node:path";
|
|
3
|
+
import { execFileSync } from "node:child_process";
|
|
4
4
|
import { fileURLToPath } from "node:url";
|
|
5
5
|
|
|
6
|
-
const
|
|
6
|
+
const packageRoot = path.dirname(fileURLToPath(import.meta.url));
|
|
7
|
+
const buildScriptPath = path.join(packageRoot, "scripts", "build.mjs");
|
|
7
8
|
|
|
8
|
-
|
|
9
|
-
const packageJsonPath = path.join(
|
|
10
|
-
let currentVersion = "0.0.0";
|
|
11
|
-
try {
|
|
9
|
+
function readPackageVersion() {
|
|
10
|
+
const packageJsonPath = path.join(packageRoot, "package.json");
|
|
12
11
|
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf-8"));
|
|
13
|
-
|
|
14
|
-
} catch (e) {
|
|
15
|
-
console.error(`Failed to read package.json version: ${e.message}`);
|
|
12
|
+
return packageJson.version || "0.0.0";
|
|
16
13
|
}
|
|
17
14
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
} else {
|
|
29
|
-
// Running as a dependency - build to parent project's dashboard/dist
|
|
30
|
-
const projectRoot = path.resolve(__dirname, "../../..");
|
|
31
|
-
const dashboardDir = path.join(projectRoot, "dashboard");
|
|
32
|
-
distPath = path.join(dashboardDir, "dist");
|
|
33
|
-
versionFilePath = path.join(distPath, "version.txt");
|
|
15
|
+
function isDependencyInstall() {
|
|
16
|
+
return packageRoot.includes(`${path.sep}node_modules${path.sep}`);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function getHostProjectRoot() {
|
|
20
|
+
const marker = `${path.sep}node_modules${path.sep}`;
|
|
21
|
+
const markerIndex = packageRoot.lastIndexOf(marker);
|
|
22
|
+
|
|
23
|
+
if (markerIndex === -1) {
|
|
24
|
+
return packageRoot;
|
|
34
25
|
}
|
|
35
26
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
console.log(`Version ${currentVersion} is already installed at ${distPath}. Skipping build.`);
|
|
43
|
-
process.exit(0);
|
|
44
|
-
} else {
|
|
45
|
-
console.log(
|
|
46
|
-
`Version mismatch (Installed: ${installedVersion}, Target: ${currentVersion}). Proceeding with build.`
|
|
47
|
-
);
|
|
48
|
-
}
|
|
49
|
-
} catch {
|
|
50
|
-
console.log("Could not read version file. Proceeding with build.");
|
|
51
|
-
}
|
|
52
|
-
} else {
|
|
53
|
-
console.log("No version file found. Proceeding with build.");
|
|
27
|
+
return packageRoot.slice(0, markerIndex);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function resolveTargetDistPath() {
|
|
31
|
+
if (!isDependencyInstall()) {
|
|
32
|
+
return path.join(packageRoot, "dist");
|
|
54
33
|
}
|
|
55
34
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
cwd: __dirname,
|
|
63
|
-
stdio: "inherit"
|
|
64
|
-
});
|
|
65
|
-
} catch (error) {
|
|
66
|
-
console.error("Failed to generate service worker.");
|
|
67
|
-
throw error;
|
|
35
|
+
return path.join(getHostProjectRoot(), "dashboard", "dist");
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function readInstalledVersion(versionFilePath) {
|
|
39
|
+
if (!fs.existsSync(versionFilePath)) {
|
|
40
|
+
return null;
|
|
68
41
|
}
|
|
69
42
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
|
|
43
|
+
return fs.readFileSync(versionFilePath, "utf-8").trim() || null;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function runBuildPipeline() {
|
|
47
|
+
execFileSync(process.execPath, [buildScriptPath], {
|
|
48
|
+
cwd: packageRoot,
|
|
49
|
+
stdio: "inherit"
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function ensureDirectory(directoryPath) {
|
|
54
|
+
if (!fs.existsSync(directoryPath)) {
|
|
55
|
+
fs.mkdirSync(directoryPath, { recursive: true });
|
|
80
56
|
}
|
|
57
|
+
}
|
|
81
58
|
|
|
82
|
-
|
|
59
|
+
function copyBuiltDistToTarget(targetDistPath) {
|
|
60
|
+
const sourceDistPath = path.join(packageRoot, "dist");
|
|
61
|
+
if (!fs.existsSync(sourceDistPath)) {
|
|
62
|
+
throw new Error(`Build failed: ${sourceDistPath} does not exist.`);
|
|
63
|
+
}
|
|
83
64
|
|
|
84
|
-
if (
|
|
85
|
-
|
|
65
|
+
if (path.resolve(sourceDistPath) === path.resolve(targetDistPath)) {
|
|
66
|
+
return;
|
|
86
67
|
}
|
|
87
68
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
// Running as dependency - move dist to parent project
|
|
95
|
-
console.log("Moving build artifacts...");
|
|
96
|
-
|
|
97
|
-
// Ensure target directory exists
|
|
98
|
-
const dashboardDir = path.dirname(distPath);
|
|
99
|
-
if (!fs.existsSync(dashboardDir)) {
|
|
100
|
-
console.log(`Creating target directory: ${dashboardDir}`);
|
|
101
|
-
fs.mkdirSync(dashboardDir, { recursive: true });
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
// Clean destination
|
|
105
|
-
if (fs.existsSync(distPath)) {
|
|
106
|
-
fs.rmSync(distPath, { recursive: true, force: true });
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
// Copy
|
|
110
|
-
fs.cpSync(buildPath, distPath, { recursive: true });
|
|
111
|
-
|
|
112
|
-
// Write version file
|
|
113
|
-
fs.writeFileSync(versionFilePath, currentVersion);
|
|
114
|
-
console.log(`Written version ${currentVersion} to ${versionFilePath}`);
|
|
115
|
-
|
|
116
|
-
// Cleanup source dist
|
|
117
|
-
fs.rmSync(buildPath, { recursive: true, force: true });
|
|
69
|
+
ensureDirectory(path.dirname(targetDistPath));
|
|
70
|
+
fs.rmSync(targetDistPath, { recursive: true, force: true });
|
|
71
|
+
fs.cpSync(sourceDistPath, targetDistPath, { recursive: true });
|
|
72
|
+
|
|
73
|
+
if (isDependencyInstall()) {
|
|
74
|
+
fs.rmSync(sourceDistPath, { recursive: true, force: true });
|
|
118
75
|
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function writeVersionFile(versionFilePath, version) {
|
|
79
|
+
ensureDirectory(path.dirname(versionFilePath));
|
|
80
|
+
fs.writeFileSync(versionFilePath, version);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function runPostinstall() {
|
|
84
|
+
const targetDistPath = resolveTargetDistPath();
|
|
85
|
+
const versionFilePath = path.join(targetDistPath, "version.txt");
|
|
86
|
+
const currentVersion = readPackageVersion();
|
|
87
|
+
const installedVersion = readInstalledVersion(versionFilePath);
|
|
88
|
+
|
|
89
|
+
console.log(`[postinstall] Target dist: ${targetDistPath}`);
|
|
90
|
+
console.log(`[postinstall] Package version: ${currentVersion}`);
|
|
119
91
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
92
|
+
if (installedVersion === currentVersion) {
|
|
93
|
+
console.log("[postinstall] Dashboard bundle is already up to date. Skipping build.");
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
runBuildPipeline();
|
|
98
|
+
copyBuiltDistToTarget(targetDistPath);
|
|
99
|
+
writeVersionFile(versionFilePath, currentVersion);
|
|
100
|
+
|
|
101
|
+
console.log("[postinstall] Dashboard bundle is ready.");
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
try {
|
|
105
|
+
runPostinstall();
|
|
106
|
+
} catch (error) {
|
|
107
|
+
console.error(`[postinstall] Failed: ${error.message}`);
|
|
123
108
|
process.exit(1);
|
|
124
109
|
}
|
package/public/manifest.json
CHANGED
|
@@ -3,24 +3,24 @@
|
|
|
3
3
|
"name": "Necro Dashboard",
|
|
4
4
|
"icons": [
|
|
5
5
|
{
|
|
6
|
-
"src": "/android-chrome-192x192.png
|
|
6
|
+
"src": "/img/pwa/android-chrome-192x192.png",
|
|
7
7
|
"type": "image/png",
|
|
8
8
|
"sizes": "192x192",
|
|
9
9
|
"purpose": "any"
|
|
10
10
|
},
|
|
11
11
|
{
|
|
12
|
-
"src": "/android-chrome-512x512.png
|
|
12
|
+
"src": "/img/pwa/android-chrome-512x512.png",
|
|
13
13
|
"type": "image/png",
|
|
14
14
|
"sizes": "512x512",
|
|
15
15
|
"purpose": "maskable"
|
|
16
16
|
},
|
|
17
17
|
{
|
|
18
|
-
"src": "/android-chrome-512x512.png
|
|
18
|
+
"src": "/img/pwa/android-chrome-512x512.png",
|
|
19
19
|
"type": "image/png",
|
|
20
20
|
"sizes": "512x512"
|
|
21
21
|
},
|
|
22
22
|
{
|
|
23
|
-
"src": "/apple-touch-icon.png
|
|
23
|
+
"src": "/img/pwa/apple-touch-icon.png",
|
|
24
24
|
"type": "image/png",
|
|
25
25
|
"sizes": "180x180"
|
|
26
26
|
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { spawnSync } from "node:child_process";
|
|
4
|
+
import { createRequire } from "node:module";
|
|
5
|
+
import { fileURLToPath } from "node:url";
|
|
6
|
+
import { generateServiceWorker } from "./generate-sw.mjs";
|
|
7
|
+
|
|
8
|
+
const require = createRequire(import.meta.url);
|
|
9
|
+
const scriptsDirectory = path.dirname(fileURLToPath(import.meta.url));
|
|
10
|
+
const projectRoot = path.resolve(scriptsDirectory, "..");
|
|
11
|
+
const distDirectory = path.join(projectRoot, "dist");
|
|
12
|
+
|
|
13
|
+
function runNodeScript(scriptPath, args = []) {
|
|
14
|
+
const commandResult = spawnSync(process.execPath, [scriptPath, ...args], {
|
|
15
|
+
cwd: projectRoot,
|
|
16
|
+
stdio: "inherit"
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
if (commandResult.status !== 0) {
|
|
20
|
+
const exitCode = commandResult.status ?? 1;
|
|
21
|
+
throw new Error(`Command failed (${path.basename(scriptPath)}) with exit code ${exitCode}.`);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function runViteBuild() {
|
|
26
|
+
const vitePackageJsonPath = require.resolve("vite/package.json");
|
|
27
|
+
const viteBinPath = path.join(path.dirname(vitePackageJsonPath), "bin", "vite.js");
|
|
28
|
+
runNodeScript(viteBinPath, ["build"]);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
async function runBuild() {
|
|
32
|
+
fs.rmSync(distDirectory, { recursive: true, force: true });
|
|
33
|
+
runViteBuild();
|
|
34
|
+
await generateServiceWorker(projectRoot);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
runBuild().catch((error) => {
|
|
38
|
+
console.error(`[build] Failed: ${error.message}`);
|
|
39
|
+
process.exit(1);
|
|
40
|
+
});
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { createRequire } from "node:module";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
5
|
+
|
|
6
|
+
const require = createRequire(import.meta.url);
|
|
7
|
+
const currentFilePath = fileURLToPath(import.meta.url);
|
|
8
|
+
|
|
9
|
+
export async function generateServiceWorker(projectRoot) {
|
|
10
|
+
const rootPath = projectRoot ?? path.resolve(path.dirname(currentFilePath), "..");
|
|
11
|
+
const configPath = path.join(rootPath, "workbox-config.cjs");
|
|
12
|
+
|
|
13
|
+
if (!fs.existsSync(configPath)) {
|
|
14
|
+
throw new Error(`Missing Workbox config: ${configPath}`);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const baseConfig = require(configPath);
|
|
18
|
+
const { generateSW } = require("workbox-build");
|
|
19
|
+
|
|
20
|
+
const normalizedConfig = {
|
|
21
|
+
...baseConfig,
|
|
22
|
+
globDirectory: path.resolve(rootPath, baseConfig.globDirectory ?? "dist"),
|
|
23
|
+
swDest: path.resolve(rootPath, baseConfig.swDest ?? "dist/sw.js")
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
const { count, size, warnings } = await generateSW(normalizedConfig);
|
|
27
|
+
|
|
28
|
+
if (warnings?.length) {
|
|
29
|
+
for (const warning of warnings) {
|
|
30
|
+
console.warn(`[workbox] ${warning}`);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const totalKilobytes = (size / 1024).toFixed(2);
|
|
35
|
+
console.log(`[workbox] Generated service worker with ${count} entries (${totalKilobytes} KiB).`);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (process.argv[1] && path.resolve(process.argv[1]) === currentFilePath) {
|
|
39
|
+
generateServiceWorker().catch((error) => {
|
|
40
|
+
console.error(`[workbox] Failed: ${error.message}`);
|
|
41
|
+
process.exit(1);
|
|
42
|
+
});
|
|
43
|
+
}
|
|
@@ -2,31 +2,44 @@
|
|
|
2
2
|
|
|
3
3
|
import { register } from "register-service-worker";
|
|
4
4
|
|
|
5
|
-
if (
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
"
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
5
|
+
if ("serviceWorker" in navigator) {
|
|
6
|
+
if (import.meta.env.PROD) {
|
|
7
|
+
register("/sw.js", {
|
|
8
|
+
ready() {
|
|
9
|
+
console.log(
|
|
10
|
+
"App is being served from cache by a service worker.\n" +
|
|
11
|
+
"For more details, visit https://goo.gl/AFskqB"
|
|
12
|
+
);
|
|
13
|
+
},
|
|
14
|
+
registered() {
|
|
15
|
+
console.log("Service worker has been registered.");
|
|
16
|
+
},
|
|
17
|
+
cached() {
|
|
18
|
+
console.log("Content has been cached for offline use.");
|
|
19
|
+
},
|
|
20
|
+
updatefound() {
|
|
21
|
+
console.log("New content is downloading.");
|
|
22
|
+
},
|
|
23
|
+
updated() {
|
|
24
|
+
console.log("New content is available; please refresh.");
|
|
25
|
+
},
|
|
26
|
+
offline() {
|
|
27
|
+
console.log("No internet connection found. App is running in offline mode.");
|
|
28
|
+
},
|
|
29
|
+
error(error) {
|
|
30
|
+
console.error("Error during service worker registration:", error);
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
} else {
|
|
34
|
+
window.addEventListener("load", () => {
|
|
35
|
+
navigator.serviceWorker
|
|
36
|
+
.getRegistrations()
|
|
37
|
+
.then((registrations) => {
|
|
38
|
+
for (const registration of registrations) {
|
|
39
|
+
registration.unregister();
|
|
40
|
+
}
|
|
41
|
+
})
|
|
42
|
+
.catch(() => {});
|
|
43
|
+
});
|
|
44
|
+
}
|
|
32
45
|
}
|
package/workbox-config.cjs
CHANGED
|
@@ -1,20 +1,25 @@
|
|
|
1
1
|
module.exports = {
|
|
2
2
|
globDirectory: "dist/",
|
|
3
3
|
globPatterns: [
|
|
4
|
-
//
|
|
5
|
-
"
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
"
|
|
10
|
-
// Manifest and other static files
|
|
4
|
+
// App shell + bundled assets
|
|
5
|
+
"index.html",
|
|
6
|
+
"assets/**/*.{js,css,woff2,woff,ttf,eot,png,ico,svg,jpg,jpeg,webp,gif}",
|
|
7
|
+
// Public static assets
|
|
8
|
+
"img/**/*.{png,ico,svg,jpg,jpeg,webp,gif}",
|
|
9
|
+
"flags/**/*.svg",
|
|
11
10
|
"manifest.json",
|
|
12
|
-
"
|
|
11
|
+
"favicon.ico",
|
|
12
|
+
"favicon-16x16.png",
|
|
13
|
+
"favicon-32x32.png",
|
|
14
|
+
"robots.txt"
|
|
13
15
|
],
|
|
16
|
+
globIgnores: ["sw.js", "workbox-*.js"],
|
|
14
17
|
swDest: "dist/sw.js",
|
|
18
|
+
mode: "production",
|
|
15
19
|
sourcemap: false,
|
|
16
20
|
skipWaiting: true,
|
|
17
21
|
clientsClaim: true,
|
|
22
|
+
navigateFallback: "/index.html",
|
|
18
23
|
ignoreURLParametersMatching: [/^utm_/, /^fbclid$/],
|
|
19
24
|
cleanupOutdatedCaches: true,
|
|
20
25
|
// Increase max size to handle larger bundles
|
|
@@ -33,6 +38,18 @@ module.exports = {
|
|
|
33
38
|
}
|
|
34
39
|
}
|
|
35
40
|
},
|
|
41
|
+
// Country flags
|
|
42
|
+
{
|
|
43
|
+
urlPattern: /\/flags\//,
|
|
44
|
+
handler: "CacheFirst",
|
|
45
|
+
options: {
|
|
46
|
+
cacheName: "country-flags",
|
|
47
|
+
expiration: {
|
|
48
|
+
maxEntries: 50,
|
|
49
|
+
maxAgeSeconds: 60 * 60 * 24 * 90 // 90 days
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
},
|
|
36
53
|
// Images - Cache first for best performance
|
|
37
54
|
{
|
|
38
55
|
urlPattern: /\.(?:png|jpg|jpeg|svg|gif|webp|ico)$/,
|
|
@@ -52,8 +69,8 @@ module.exports = {
|
|
|
52
69
|
options: {
|
|
53
70
|
cacheName: "static-resources",
|
|
54
71
|
expiration: {
|
|
55
|
-
maxEntries: 100,
|
|
56
|
-
maxAgeSeconds: 60 * 60 * 24 * 30
|
|
72
|
+
maxEntries: 100,
|
|
73
|
+
maxAgeSeconds: 60 * 60 * 24 * 30
|
|
57
74
|
}
|
|
58
75
|
}
|
|
59
76
|
},
|
|
@@ -77,18 +94,6 @@ module.exports = {
|
|
|
77
94
|
}
|
|
78
95
|
}
|
|
79
96
|
},
|
|
80
|
-
// Country flags
|
|
81
|
-
{
|
|
82
|
-
urlPattern: /\/flags\//,
|
|
83
|
-
handler: "CacheFirst",
|
|
84
|
-
options: {
|
|
85
|
-
cacheName: "country-flags",
|
|
86
|
-
expiration: {
|
|
87
|
-
maxEntries: 50,
|
|
88
|
-
maxAgeSeconds: 60 * 60 * 24 * 90 // 90 days
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
},
|
|
92
97
|
// Prism.js CDN resources
|
|
93
98
|
{
|
|
94
99
|
urlPattern: /^https:\/\/cdnjs\.cloudflare\.com\/ajax\/libs\/prism\//,
|
|
Binary file
|
|
File without changes
|
|
File without changes
|
|
File without changes
|