diff --git a/.eslintrc.json b/.eslintrc.json
index 0909a15..ccdc4a8 100644
--- a/.eslintrc.json
+++ b/.eslintrc.json
@@ -67,5 +67,16 @@
"alphabetize": { "order": "asc", "caseInsensitive": true }
}
]
- }
+ },
+ "overrides": [
+ {
+ "files": ["service-worker.js"],
+ "rules": {
+ "no-restricted-globals": "off"
+ },
+ "env": {
+ "serviceworker": true
+ }
+ }
+ ]
}
diff --git a/mamar-web/package.json b/mamar-web/package.json
index 81cebb8..b8b3a3f 100644
--- a/mamar-web/package.json
+++ b/mamar-web/package.json
@@ -12,6 +12,7 @@
},
"dependencies": {
"@adobe/react-spectrum": "^3.21.2",
+ "@parcel/service-worker": "^2.7.0",
"@react-hook/resize-observer": "^1.2.6",
"@spectrum-icons/workflow": "^4.0.2",
"@types/stats.js": "^0.17.0",
diff --git a/mamar-web/src/app/index.tsx b/mamar-web/src/app/index.tsx
index 8de9174..df03a66 100644
--- a/mamar-web/src/app/index.tsx
+++ b/mamar-web/src/app/index.tsx
@@ -2,6 +2,7 @@ import * as WasmBridge from "mamar-wasm-bridge"
import * as React from "react"
import * as ReactDOM from "react-dom/client"
+import "../service-worker-load.js"
import report from "./analytics"
import App from "./App"
diff --git a/mamar-web/src/index.html b/mamar-web/src/index.html
index 7f99439..ed99253 100644
--- a/mamar-web/src/index.html
+++ b/mamar-web/src/index.html
@@ -86,6 +86,7 @@
Contributing
diff --git a/mamar-web/src/service-worker-load.js b/mamar-web/src/service-worker-load.js
new file mode 100644
index 0000000..e8f8f0f
--- /dev/null
+++ b/mamar-web/src/service-worker-load.js
@@ -0,0 +1 @@
+navigator.serviceWorker.register(new URL("./service-worker.js", import.meta.url), { type: "module" })
diff --git a/mamar-web/src/service-worker.js b/mamar-web/src/service-worker.js
new file mode 100644
index 0000000..14afc0e
--- /dev/null
+++ b/mamar-web/src/service-worker.js
@@ -0,0 +1,33 @@
+import { manifest, version } from "@parcel/service-worker"
+
+async function install() {
+ const cache = await caches.open(version)
+ await cache.addAll(Array.from(new Set(manifest)))
+}
+addEventListener("install", evt => evt.waitUntil(install()))
+
+async function activate() {
+ const keys = await caches.keys()
+ await Promise.all(
+ keys.map(key => key !== version && caches.delete(key)),
+ )
+}
+addEventListener("activate", evt => evt.waitUntil(activate()))
+
+addEventListener("fetch", evt => {
+ evt.respondWith((async () => {
+ const r = await caches.match(evt.request)
+ if (r) {
+ console.log("[service worker] Cache hit", evt.request.url)
+ return r
+ }
+
+ console.error("[service worker] Cache miss", evt.request.url)
+
+ const response = await fetch(evt.request)
+ const cache = await caches.open(version)
+ console.log(`[service worker] Caching new resource: ${evt.request.url}`)
+ cache.put(evt.request, response.clone())
+ return response
+ })())
+})
diff --git a/yarn.lock b/yarn.lock
index 376875c..6834668 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1862,6 +1862,11 @@
"@parcel/utils" "2.7.0"
nullthrows "^1.1.1"
+"@parcel/service-worker@^2.7.0":
+ version "2.7.0"
+ resolved "https://registry.yarnpkg.com/@parcel/service-worker/-/service-worker-2.7.0.tgz#b8525b2129cc21e33bc870c398a25cf9f5c31a12"
+ integrity sha512-EUMQcBtRQagZ4yVH2BxtToDpplLtfhjYqtvcgwVQIk3WkvMvKsTVCQZb9GHWKMBz7RKGdeQhbtZLPO3ywI0lfA==
+
"@parcel/source-map@^2.0.0":
version "2.1.1"
resolved "https://registry.yarnpkg.com/@parcel/source-map/-/source-map-2.1.1.tgz#fb193b82dba6dd62cc7a76b326f57bb35000a782"