From 4eaaaa0b8f21417ca65330259551f69acb3684ff Mon Sep 17 00:00:00 2001 From: JovannMC Date: Tue, 11 Feb 2025 12:32:23 +0300 Subject: [PATCH 01/13] fix: netlify serve HTTP headers for libvips --- _headers | 4 ++++ src/routes/+layout.svelte | 1 - static/coi-serviceworker.min.js | 2 -- 3 files changed, 4 insertions(+), 3 deletions(-) create mode 100644 _headers delete mode 100644 static/coi-serviceworker.min.js diff --git a/_headers b/_headers new file mode 100644 index 0000000..2568767 --- /dev/null +++ b/_headers @@ -0,0 +1,4 @@ +# For libvips/wasm-vips converter (images) +/* + Cross-Origin-Embedder-Policy: require-corp + Cross-Origin-Opener-Policy: same-origin \ No newline at end of file diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte index d9fdda6..0b56b9e 100644 --- a/src/routes/+layout.svelte +++ b/src/routes/+layout.svelte @@ -91,7 +91,6 @@ data-domain={PUB_HOSTNAME || "vert.sh"} src="{PUB_PLAUSIBLE_URL}/js/script.pageview-props.tagged-events.js" >{/if} - diff --git a/static/coi-serviceworker.min.js b/static/coi-serviceworker.min.js deleted file mode 100644 index 117f9f8..0000000 --- a/static/coi-serviceworker.min.js +++ /dev/null @@ -1,2 +0,0 @@ -/*! coi-serviceworker v0.1.7 - Guido Zuidhof and contributors, licensed under MIT */ -let coepCredentialless=!1;"undefined"==typeof window?(self.addEventListener("install",(()=>self.skipWaiting())),self.addEventListener("activate",(e=>e.waitUntil(self.clients.claim()))),self.addEventListener("message",(e=>{e.data&&("deregister"===e.data.type?self.registration.unregister().then((()=>self.clients.matchAll())).then((e=>{e.forEach((e=>e.navigate(e.url)))})):"coepCredentialless"===e.data.type&&(coepCredentialless=e.data.value))})),self.addEventListener("fetch",(function(e){const o=e.request;if("only-if-cached"===o.cache&&"same-origin"!==o.mode)return;const s=coepCredentialless&&"no-cors"===o.mode?new Request(o,{credentials:"omit"}):o;e.respondWith(fetch(s).then((e=>{if(0===e.status)return e;const o=new Headers(e.headers);return o.set("Cross-Origin-Embedder-Policy",coepCredentialless?"credentialless":"require-corp"),coepCredentialless||o.set("Cross-Origin-Resource-Policy","cross-origin"),o.set("Cross-Origin-Opener-Policy","same-origin"),new Response(e.body,{status:e.status,statusText:e.statusText,headers:o})})).catch((e=>console.error(e))))}))):(()=>{const e=window.sessionStorage.getItem("coiReloadedBySelf");window.sessionStorage.removeItem("coiReloadedBySelf");const o="coepdegrade"==e,s={shouldRegister:()=>!e,shouldDeregister:()=>!1,coepCredentialless:()=>!0,coepDegrade:()=>!0,doReload:()=>window.location.reload(),quiet:!1,...window.coi},r=navigator,t=r.serviceWorker&&r.serviceWorker.controller;t&&!window.crossOriginIsolated&&window.sessionStorage.setItem("coiCoepHasFailed","true");const i=window.sessionStorage.getItem("coiCoepHasFailed");if(t){const e=s.coepDegrade()&&!(o||window.crossOriginIsolated);r.serviceWorker.controller.postMessage({type:"coepCredentialless",value:!(e||i&&s.coepDegrade())&&s.coepCredentialless()}),e&&(!s.quiet&&console.log("Reloading page to degrade COEP."),window.sessionStorage.setItem("coiReloadedBySelf","coepdegrade"),s.doReload("coepdegrade")),s.shouldDeregister()&&r.serviceWorker.controller.postMessage({type:"deregister"})}!1===window.crossOriginIsolated&&s.shouldRegister()&&(window.isSecureContext?r.serviceWorker?r.serviceWorker.register(window.document.currentScript.src).then((e=>{!s.quiet&&console.log("COOP/COEP Service Worker registered",e.scope),e.addEventListener("updatefound",(()=>{!s.quiet&&console.log("Reloading page to make use of updated COOP/COEP Service Worker."),window.sessionStorage.setItem("coiReloadedBySelf","updatefound"),s.doReload()})),e.active&&!r.serviceWorker.controller&&(!s.quiet&&console.log("Reloading page to make use of COOP/COEP Service Worker."),window.sessionStorage.setItem("coiReloadedBySelf","notcontrolling"),s.doReload())}),(e=>{!s.quiet&&console.error("COOP/COEP Service Worker failed to register:",e)})):!s.quiet&&console.error("COOP/COEP Service Worker not registered, perhaps due to private mode."):!s.quiet&&console.log("COOP/COEP Service Worker not registered, a secure context is required."))})(); \ No newline at end of file From bc1dbedbecdb0132a432b70355ee8eeaa25aa936 Mon Sep 17 00:00:00 2001 From: JovannMC Date: Tue, 11 Feb 2025 12:39:23 +0300 Subject: [PATCH 02/13] fix: _headers not included in build folder --- bun.lock | 19 +++++++++++++++++++ package.json | 1 + vite.config.ts | 22 +++++++++------------- 3 files changed, 29 insertions(+), 13 deletions(-) diff --git a/bun.lock b/bun.lock index 7c99eeb..c8a3696 100644 --- a/bun.lock +++ b/bun.lock @@ -14,6 +14,7 @@ "clsx": "^2.1.1", "jsmediatags": "^3.9.7", "lucide-svelte": "^0.475.0", + "vite-plugin-static-copy": "^2.2.0", "wasm-vips": "^0.0.11", }, "devDependencies": { @@ -425,6 +426,8 @@ "fraction.js": ["fraction.js@4.3.7", "", {}, "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew=="], + "fs-extra": ["fs-extra@11.3.0", "", { "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" } }, "sha512-Z4XaCL6dUDHfP/jT25jJKMmtxvuwbkrD1vNSMFlo9lNLY2c5FHYSQgHPRZUjAB26TpDEoW9HCOgplrdbaPV/ew=="], + "fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="], "function-bind": ["function-bind@1.1.2", "", {}, "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA=="], @@ -435,6 +438,8 @@ "globals": ["globals@15.14.0", "", {}, "sha512-OkToC372DtlQeje9/zHIo5CT8lRP/FUgEOKBEhU4e0abL7J7CD24fD9ohiLN5hagG/kWCYj4K5oaxxtj2Z0Dig=="], + "graceful-fs": ["graceful-fs@4.2.11", "", {}, "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="], + "graphemer": ["graphemer@1.4.0", "", {}, "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag=="], "has-flag": ["has-flag@4.0.0", "", {}, "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="], @@ -481,6 +486,8 @@ "json-stable-stringify-without-jsonify": ["json-stable-stringify-without-jsonify@1.0.1", "", {}, "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw=="], + "jsonfile": ["jsonfile@6.1.0", "", { "dependencies": { "universalify": "^2.0.0" }, "optionalDependencies": { "graceful-fs": "^4.1.6" } }, "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ=="], + "keyv": ["keyv@4.5.4", "", { "dependencies": { "json-buffer": "3.0.1" } }, "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw=="], "kleur": ["kleur@4.1.5", "", {}, "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ=="], @@ -673,6 +680,8 @@ "typescript-eslint": ["typescript-eslint@8.23.0", "", { "dependencies": { "@typescript-eslint/eslint-plugin": "8.23.0", "@typescript-eslint/parser": "8.23.0", "@typescript-eslint/utils": "8.23.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <5.8.0" } }, "sha512-/LBRo3HrXr5LxmrdYSOCvoAMm7p2jNizNfbIpCgvG4HMsnoprRUOce/+8VJ9BDYWW68rqIENE/haVLWPeFZBVQ=="], + "universalify": ["universalify@2.0.1", "", {}, "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw=="], + "update-browserslist-db": ["update-browserslist-db@1.1.2", "", { "dependencies": { "escalade": "^3.2.0", "picocolors": "^1.1.1" }, "peerDependencies": { "browserslist": ">= 4.21.0" }, "bin": { "update-browserslist-db": "cli.js" } }, "sha512-PPypAm5qvlD7XMZC3BujecnaOxwhrtoFR+Dqkk5Aa/6DssiH0ibKoketaj9w8LP7Bont1rYeoV5plxD7RTEPRg=="], "uri-js": ["uri-js@4.4.1", "", { "dependencies": { "punycode": "^2.1.0" } }, "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg=="], @@ -681,6 +690,8 @@ "vite": ["vite@5.4.14", "", { "dependencies": { "esbuild": "^0.21.3", "postcss": "^8.4.43", "rollup": "^4.20.0" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^18.0.0 || >=20.0.0", "less": "*", "lightningcss": "^1.21.0", "sass": "*", "sass-embedded": "*", "stylus": "*", "sugarss": "*", "terser": "^5.4.0" }, "optionalPeers": ["@types/node", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser"], "bin": { "vite": "bin/vite.js" } }, "sha512-EK5cY7Q1D8JNhSaPKVK4pwBFvaTmZxEnoKXLG/U9gmdDcihQGNzFlgIvaxezFR4glP1LsuiedwMBqCXH3wZccA=="], + "vite-plugin-static-copy": ["vite-plugin-static-copy@2.2.0", "", { "dependencies": { "chokidar": "^3.5.3", "fast-glob": "^3.2.11", "fs-extra": "^11.1.0", "picocolors": "^1.0.0" }, "peerDependencies": { "vite": "^5.0.0 || ^6.0.0" } }, "sha512-ytMrKdR9iWEYHbUxs6x53m+MRl4SJsOSoMu1U1+Pfg0DjPeMlsRVx3RR5jvoonineDquIue83Oq69JvNsFSU5w=="], + "vitefu": ["vitefu@1.0.5", "", { "peerDependencies": { "vite": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0" }, "optionalPeers": ["vite"] }, "sha512-h4Vflt9gxODPFNGPwp4zAMZRpZR7eslzwH2c5hn5kNZ5rhnKyRJ50U+yGCdc2IRaBs8O4haIgLNGrV5CrpMsCA=="], "wasm-vips": ["wasm-vips@0.0.11", "", {}, "sha512-bzFU7WcimMY4WeqnZk7whKVpSXxpagISXPJwsk2VHF4lgIN9rl4uUo5sF9x6jOlACuCH6ITZUJ7QPTYmy60NCQ=="], @@ -741,6 +752,8 @@ "tailwindcss/postcss-load-config": ["postcss-load-config@4.0.2", "", { "dependencies": { "lilconfig": "^3.0.0", "yaml": "^2.3.4" }, "peerDependencies": { "postcss": ">=8.0.9", "ts-node": ">=9.0.0" }, "optionalPeers": ["postcss", "ts-node"] }, "sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ=="], + "vite-plugin-static-copy/chokidar": ["chokidar@3.6.0", "", { "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", "glob-parent": "~5.1.2", "is-binary-path": "~2.1.0", "is-glob": "~4.0.1", "normalize-path": "~3.0.0", "readdirp": "~3.6.0" }, "optionalDependencies": { "fsevents": "~2.3.2" } }, "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw=="], + "wrap-ansi/ansi-styles": ["ansi-styles@6.2.1", "", {}, "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug=="], "wrap-ansi-cjs/string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], @@ -761,10 +774,16 @@ "tailwindcss/postcss-load-config/yaml": ["yaml@2.7.0", "", { "bin": { "yaml": "bin.mjs" } }, "sha512-+hSoy/QHluxmC9kCIJyL/uyFmLmc+e5CFR5Wa+bpIhIj85LVb9ZH2nVnqrHoSvKogwODv0ClqZkmiSSaIH5LTA=="], + "vite-plugin-static-copy/chokidar/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="], + + "vite-plugin-static-copy/chokidar/readdirp": ["readdirp@3.6.0", "", { "dependencies": { "picomatch": "^2.2.1" } }, "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA=="], + "wrap-ansi-cjs/string-width/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="], "wrap-ansi-cjs/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], "tailwindcss/chokidar/readdirp/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], + + "vite-plugin-static-copy/chokidar/readdirp/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], } } diff --git a/package.json b/package.json index 56999cf..6a5d424 100644 --- a/package.json +++ b/package.json @@ -45,6 +45,7 @@ "clsx": "^2.1.1", "jsmediatags": "^3.9.7", "lucide-svelte": "^0.475.0", + "vite-plugin-static-copy": "^2.2.0", "wasm-vips": "^0.0.11" }, "patchedDependencies": { diff --git a/vite.config.ts b/vite.config.ts index 56a46a8..733c29c 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -1,23 +1,11 @@ import { sveltekit } from "@sveltejs/kit/vite"; import { defineConfig } from "vite"; +import { viteStaticCopy } from "vite-plugin-static-copy"; import svg from "@poppanator/sveltekit-svg"; export default defineConfig({ plugins: [ sveltekit(), - { - name: "vips-request-middleware", - configureServer(server) { - server.middlewares.use((req, res, next) => { - res.setHeader( - "Cross-Origin-Embedder-Policy", - "require-corp", - ); - res.setHeader("Cross-Origin-Opener-Policy", "same-origin"); - next(); - }); - }, - }, svg({ includePaths: ["./src/lib/assets"], svgoOptions: { @@ -31,6 +19,14 @@ export default defineConfig({ ], }, }), + viteStaticCopy({ + targets: [ + { + src: '_headers', + dest: '' + } + ] + }) ], optimizeDeps: { exclude: [ From 70b6c4e680d406f7d09d428768730a7d7e3aa844 Mon Sep 17 00:00:00 2001 From: JovannMC Date: Tue, 11 Feb 2025 15:24:19 +0300 Subject: [PATCH 03/13] fix: VIPS on dev oops --- vite.config.ts | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/vite.config.ts b/vite.config.ts index 733c29c..ff6c6d7 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -6,6 +6,19 @@ import svg from "@poppanator/sveltekit-svg"; export default defineConfig({ plugins: [ sveltekit(), + { + name: "vips-request-middleware", + configureServer(server) { + server.middlewares.use((req, res, next) => { + res.setHeader( + "Cross-Origin-Embedder-Policy", + "require-corp", + ); + res.setHeader("Cross-Origin-Opener-Policy", "same-origin"); + next(); + }); + }, + }, svg({ includePaths: ["./src/lib/assets"], svgoOptions: { @@ -20,13 +33,13 @@ export default defineConfig({ }, }), viteStaticCopy({ - targets: [ - { - src: '_headers', - dest: '' - } - ] - }) + targets: [ + { + src: "_headers", + dest: "", + }, + ], + }), ], optimizeDeps: { exclude: [ From 892dbfcc098506e51834650774a30896d4291eab Mon Sep 17 00:00:00 2001 From: JovannMC Date: Tue, 11 Feb 2025 15:24:29 +0300 Subject: [PATCH 04/13] feat: start PWA support --- src/routes/+layout.svelte | 19 +++++++++++++++++++ static/lettermark.jpg | Bin 0 -> 34053 bytes static/manifest.json | 21 +++++++++++++++++++++ static/service-worker.js | 19 +++++++++++++++++++ 4 files changed, 59 insertions(+) create mode 100644 static/lettermark.jpg create mode 100644 static/manifest.json create mode 100644 static/service-worker.js diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte index 0b56b9e..a49ccf8 100644 --- a/src/routes/+layout.svelte +++ b/src/routes/+layout.svelte @@ -18,6 +18,7 @@ dropping, } from "$lib/store/index.svelte"; import "../app.scss"; + import { log, error } from "$lib/logger"; let { children } = $props(); @@ -52,6 +53,23 @@ ); Settings.instance.load(); + + if ("serviceWorker" in navigator) { + navigator.serviceWorker + .register("/service-worker.js") + .then((registration) => { + log( + ["PWA"], + `Service Worker registration successful with scope: ${registration.scope}`, + ); + }) + .catch((err) => { + error( + ["PWA"], + `Service Worker registration failed: ${err}`, + ); + }); + } }); @@ -86,6 +104,7 @@ content="With VERT you can convert image and audio files to and from PNG, JPG, WEBP, MP3, WAV, FLAC, and more. No ads, no tracking, open source, and all processing is done on your device." /> + {#if PUB_PLAUSIBLE_URL} diff --git a/src/service-worker.js b/src/service-worker.js new file mode 100644 index 0000000..c731472 --- /dev/null +++ b/src/service-worker.js @@ -0,0 +1,84 @@ +/// +import { build, files, version } from '$service-worker'; + +// Create a unique cache name for this deployment +const CACHE = `cache-${version}`; + +const ASSETS = [ + ...build, // the app itself + ...files, // everything in `static` +]; + +self.addEventListener('install', (event) => { + // Create a new cache and add all files to it + async function addFilesToCache() { + const cache = await caches.open(CACHE); + await cache.addAll(ASSETS); + } + + console.log('installing service worker for version', version); + console.log('caching assets', ASSETS); + + event.waitUntil(addFilesToCache()); +}); + +self.addEventListener('activate', (event) => { + // Remove previous cached data from disk + async function deleteOldCaches() { + for (const key of await caches.keys()) { + if (key !== CACHE) await caches.delete(key); + } + } + + event.waitUntil(deleteOldCaches()); +}); + +self.addEventListener('fetch', (event) => { + // ignore POST requests etc + if (event.request.method !== 'GET') return; + + async function respond() { + const url = new URL(event.request.url); + const cache = await caches.open(CACHE); + + // `build`/`files` can always be served from the cache + if (ASSETS.includes(url.pathname)) { + const response = await cache.match(url.pathname); + + if (response) { + return response; + } + } + + // for everything else, try the network first, but + // fall back to the cache if we're offline + try { + const response = await fetch(event.request); + + // if we're offline, fetch can return a value that is not a Response + // instead of throwing - and we can't pass this non-Response to respondWith + if (!(response instanceof Response)) { + throw new Error('invalid response from fetch'); + } + + if (response.status === 200) { + cache.put(event.request, response.clone()); + } + + return response; + } catch (err) { + const response = await cache.match(event.request); + + if (response) { + console.log(`Returning from Cache`, event.request.url); + return response; + } + + // if there's no cache, then just error out + // as there is nothing we can do to respond to this request + throw err; + } + } + + event.respondWith(respond()); +}); diff --git a/static/service-worker.js b/static/service-worker.js deleted file mode 100644 index 4c80564..0000000 --- a/static/service-worker.js +++ /dev/null @@ -1,19 +0,0 @@ -self.addEventListener('install', (event) => { - event.waitUntil( - caches.open('vert-cache').then((cache) => { - return cache.addAll([ - '/', - '/manifest.json', - '/lettermark.jpg', - ]); - }) - ); -}); - -self.addEventListener('fetch', (event) => { - event.respondWith( - caches.match(event.request).then((response) => { - return response || fetch(event.request); - }) - ); -}); \ No newline at end of file diff --git a/vite.config.ts b/vite.config.ts index ff6c6d7..07f3d05 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -9,7 +9,7 @@ export default defineConfig({ { name: "vips-request-middleware", configureServer(server) { - server.middlewares.use((req, res, next) => { + server.middlewares.use((_req, res, next) => { res.setHeader( "Cross-Origin-Embedder-Policy", "require-corp", From a47b5ffba9aa8140dd123c195ed5814f399d2181 Mon Sep 17 00:00:00 2001 From: JovannMC Date: Tue, 11 Feb 2025 20:44:49 +0300 Subject: [PATCH 06/13] feat: support AVIF & JXL closes #14 --- src/lib/converters/vips.svelte.ts | 5 +++-- src/lib/workers/vips.ts | 2 -- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/lib/converters/vips.svelte.ts b/src/lib/converters/vips.svelte.ts index 9f9a5ac..33fa389 100644 --- a/src/lib/converters/vips.svelte.ts +++ b/src/lib/converters/vips.svelte.ts @@ -33,6 +33,9 @@ export class VipsConverter extends Converter { ".tif", ".tiff", ".jfif", + //".heif", HEIF files that are encoded like HEIC files (and HEIC files in general) aren't supported due to https://github.com/kleisauke/wasm-vips/issues/3 + ".avif", + ".jxl", ]; public readonly reportsProgress = false; @@ -51,8 +54,6 @@ export class VipsConverter extends Converter { error(["converters", this.name], `error in worker: ${message.error}`); addToast("error", `Error in VIPS worker, some features may not work.`); throw new Error(message.error); - } else { - error(["converters", this.name], `unknown message type: ${message.type}`); } }; } diff --git a/src/lib/workers/vips.ts b/src/lib/workers/vips.ts index 058cb67..35f09f1 100644 --- a/src/lib/workers/vips.ts +++ b/src/lib/workers/vips.ts @@ -2,8 +2,6 @@ import { type WorkerMessage, type OmitBetterStrict } from "$lib/types"; import Vips from "wasm-vips"; const vipsPromise = Vips({ - // see https://github.com/kleisauke/wasm-vips/issues/85 - dynamicLibraries: [], }); vipsPromise From 8bcd7d4e5c234843320d48d582c23f17d17b5811 Mon Sep 17 00:00:00 2001 From: JovannMC Date: Tue, 11 Feb 2025 21:50:49 +0300 Subject: [PATCH 07/13] fix: fix animated WEBP to/from GIF --- src/lib/workers/vips.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib/workers/vips.ts b/src/lib/workers/vips.ts index 35f09f1..cde18c6 100644 --- a/src/lib/workers/vips.ts +++ b/src/lib/workers/vips.ts @@ -1,8 +1,7 @@ import { type WorkerMessage, type OmitBetterStrict } from "$lib/types"; import Vips from "wasm-vips"; -const vipsPromise = Vips({ -}); +const vipsPromise = Vips({}); vipsPromise .then(() => { @@ -21,6 +20,7 @@ const handleMessage = async ( if (!message.to.startsWith(".")) message.to = `.${message.to}`; const image = vips.Image.newFromBuffer( await message.input.file.arrayBuffer(), + `${message.to === ".gif" || message.to === ".webp" ? "[n=-1]" : ""}`, ); const output = image.writeToBuffer(message.to); image.delete(); From ff2e5b18668f88a6c0cd2ca94c694e5e7c59f816 Mon Sep 17 00:00:00 2001 From: JovannMC Date: Tue, 11 Feb 2025 23:49:27 +0300 Subject: [PATCH 08/13] feat: warning when selecting animated webp/gif --- src/routes/convert/+page.svelte | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/routes/convert/+page.svelte b/src/routes/convert/+page.svelte index 345aa93..c27ee0c 100644 --- a/src/routes/convert/+page.svelte +++ b/src/routes/convert/+page.svelte @@ -4,7 +4,6 @@ import Uploader from "$lib/components/functional/Uploader.svelte"; import Panel from "$lib/components/visual/Panel.svelte"; import ProgressBar from "$lib/components/visual/ProgressBar.svelte"; - import { converters } from "$lib/converters"; import { effects, files, @@ -12,6 +11,7 @@ showGradient, vertdLoaded, } from "$lib/store/index.svelte"; + import { addToast } from "$lib/store/ToastProvider"; import { VertFile } from "$lib/types"; import { AudioLines, @@ -26,6 +26,18 @@ XIcon, } from "lucide-svelte"; + const handleSelect = (option: string, file: VertFile) => { + file.result = null; + switch (option) { + case ".webp": + case ".gif": + addToast( + "warning", + `Converting this file to "${option}" may take some time if animated.`, + ); + } + }; + $effect(() => { // Set gradient color depending on the file types // TODO: if more file types added, add a "fileType" property to the file object @@ -173,7 +185,7 @@ file.result && (file.result = null)} + onselect={(option) => handleSelect(option, file)} />