parent
e1c89f9cb0
commit
9f474e3d43
|
@ -30,7 +30,8 @@
|
||||||
"vue-router": "^3.6.5",
|
"vue-router": "^3.6.5",
|
||||||
"vue-virtual-scroller": "1.1.2",
|
"vue-virtual-scroller": "1.1.2",
|
||||||
"vue2-leaflet": "^2.7.1",
|
"vue2-leaflet": "^2.7.1",
|
||||||
"webdav": "^5.3.0"
|
"webdav": "^5.3.0",
|
||||||
|
"webworker-typed": "^1.0.4"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@playwright/test": "^1.39.0",
|
"@playwright/test": "^1.39.0",
|
||||||
|
@ -8908,7 +8909,6 @@
|
||||||
"version": "5.2.2",
|
"version": "5.2.2",
|
||||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz",
|
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz",
|
||||||
"integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==",
|
"integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==",
|
||||||
"dev": true,
|
|
||||||
"bin": {
|
"bin": {
|
||||||
"tsc": "bin/tsc",
|
"tsc": "bin/tsc",
|
||||||
"tsserver": "bin/tsserver"
|
"tsserver": "bin/tsserver"
|
||||||
|
@ -9879,6 +9879,14 @@
|
||||||
"url": "https://opencollective.com/webpack"
|
"url": "https://opencollective.com/webpack"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/webworker-typed": {
|
||||||
|
"version": "1.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/webworker-typed/-/webworker-typed-1.0.4.tgz",
|
||||||
|
"integrity": "sha512-gKIJ8MkFlF44KOSs0eNPhnOUcig9vBcbzDCn0jnHZwKBpvg/p/vM3Gjruaw0fUnxnXGffrDC+aSkwTH2pIC/zg==",
|
||||||
|
"peerDependencies": {
|
||||||
|
"typescript": "^5.2.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/whatwg-url": {
|
"node_modules/whatwg-url": {
|
||||||
"version": "7.1.0",
|
"version": "7.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.1.0.tgz",
|
||||||
|
@ -16671,8 +16679,7 @@
|
||||||
"typescript": {
|
"typescript": {
|
||||||
"version": "5.2.2",
|
"version": "5.2.2",
|
||||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz",
|
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz",
|
||||||
"integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==",
|
"integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w=="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"unbox-primitive": {
|
"unbox-primitive": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
|
@ -17340,6 +17347,12 @@
|
||||||
"resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz",
|
"resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz",
|
||||||
"integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w=="
|
"integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w=="
|
||||||
},
|
},
|
||||||
|
"webworker-typed": {
|
||||||
|
"version": "1.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/webworker-typed/-/webworker-typed-1.0.4.tgz",
|
||||||
|
"integrity": "sha512-gKIJ8MkFlF44KOSs0eNPhnOUcig9vBcbzDCn0jnHZwKBpvg/p/vM3Gjruaw0fUnxnXGffrDC+aSkwTH2pIC/zg==",
|
||||||
|
"requires": {}
|
||||||
|
},
|
||||||
"whatwg-url": {
|
"whatwg-url": {
|
||||||
"version": "7.1.0",
|
"version": "7.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.1.0.tgz",
|
||||||
|
|
|
@ -51,7 +51,8 @@
|
||||||
"vue-router": "^3.6.5",
|
"vue-router": "^3.6.5",
|
||||||
"vue-virtual-scroller": "1.1.2",
|
"vue-virtual-scroller": "1.1.2",
|
||||||
"vue2-leaflet": "^2.7.1",
|
"vue2-leaflet": "^2.7.1",
|
||||||
"webdav": "^5.3.0"
|
"webdav": "^5.3.0",
|
||||||
|
"webworker-typed": "^1.0.4"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=18.2.0",
|
"node": ">=18.2.0",
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { API } from '@services/API';
|
import { API } from '@services/API';
|
||||||
import { onDOMLoaded } from '@services/utils';
|
import { onDOMLoaded } from '@services/utils';
|
||||||
import { importWorker } from '@services/worker';
|
import { importWorker } from 'webworker-typed';
|
||||||
import type XImgWorker from './XImgWorker';
|
import type XImgWorker from './XImgWorker';
|
||||||
|
|
||||||
// Global web worker to fetch images
|
// Global web worker to fetch images
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { CacheExpiration } from 'workbox-expiration';
|
import { CacheExpiration } from 'workbox-expiration';
|
||||||
import { exportWorker } from '@services/worker';
|
import { exportWorker } from 'webworker-typed';
|
||||||
|
|
||||||
declare var self: ServiceWorkerGlobalScope;
|
declare var self: ServiceWorkerGlobalScope;
|
||||||
|
|
||||||
|
|
|
@ -1,121 +0,0 @@
|
||||||
/**
|
|
||||||
* Data sent from main thread to worker.
|
|
||||||
*/
|
|
||||||
type CommRequest = {
|
|
||||||
reqid: number;
|
|
||||||
name: string;
|
|
||||||
args: any[];
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Data sent from worker to main thread.
|
|
||||||
*/
|
|
||||||
type CommResult = {
|
|
||||||
reqid: number;
|
|
||||||
resolve?: any;
|
|
||||||
reject?: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Map of function names to functions.
|
|
||||||
*/
|
|
||||||
type FunctionMap = { [name: string]: Function };
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Utility type to convert all methods in an object to async.
|
|
||||||
*/
|
|
||||||
type Async<T extends FunctionMap> = {
|
|
||||||
[K in keyof T]: T[K] extends (...args: infer A) => Promise<infer R>
|
|
||||||
? (...args: A) => Promise<R>
|
|
||||||
: T[K] extends (...args: infer A) => infer R
|
|
||||||
? (...args: A) => Promise<R>
|
|
||||||
: T[K];
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Export methods from a worker to the main thread.
|
|
||||||
*
|
|
||||||
* @param handlers Object with methods to export
|
|
||||||
*
|
|
||||||
* @example
|
|
||||||
* ```ts
|
|
||||||
* // my-worker.ts
|
|
||||||
* function foo() { return 'bar'; }
|
|
||||||
*
|
|
||||||
* async function asyncFoo() { return 'bar'; }
|
|
||||||
*
|
|
||||||
* export default exportWorker({
|
|
||||||
* foo,
|
|
||||||
* asyncFoo,
|
|
||||||
* inline: () => 'bar',
|
|
||||||
* });
|
|
||||||
*/
|
|
||||||
export function exportWorker<T extends FunctionMap>(handlers: T): Async<T> {
|
|
||||||
self.onmessage = async ({ data }: { data: CommRequest }) => {
|
|
||||||
try {
|
|
||||||
// Get handler from registrations
|
|
||||||
const handler = handlers[data.name];
|
|
||||||
if (!handler) throw new Error(`[BUG] No handler for type ${data.name}`);
|
|
||||||
|
|
||||||
// Run handler
|
|
||||||
let result = handler.apply(self, data.args);
|
|
||||||
if (result instanceof Promise) {
|
|
||||||
result = await result;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Success - post back to main thread
|
|
||||||
self.postMessage({ reqid: data.reqid, resolve: result } as CommResult);
|
|
||||||
} catch (e) {
|
|
||||||
// Error - post back rejection
|
|
||||||
self.postMessage({ reqid: data.reqid, reject: e.message } as CommResult);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return null as unknown as Async<T>;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Import a worker exported with `exportWorker`.
|
|
||||||
*
|
|
||||||
* @param worker Worker to import
|
|
||||||
*
|
|
||||||
* @example
|
|
||||||
* ```ts
|
|
||||||
* // main.ts
|
|
||||||
* import type MyWorker from './my-worker.ts';
|
|
||||||
*
|
|
||||||
* const worker = importWorker<typeof MyWorker>(new Worker(new URL('./XImgWorkerStub.ts', import.meta.url)));
|
|
||||||
*
|
|
||||||
* async (() => {
|
|
||||||
* // all methods are async
|
|
||||||
* console.assert(await worker.foo() === 'bar');
|
|
||||||
* console.assert(await worker.asyncFoo() === 'bar');
|
|
||||||
* console.assert(await worker.inline() === 'bar');
|
|
||||||
* });
|
|
||||||
*/
|
|
||||||
export function importWorker<T>(worker: Worker) {
|
|
||||||
const promises = new Map<number, { resolve: Function; reject: Function }>();
|
|
||||||
|
|
||||||
// Handle messages from worker
|
|
||||||
worker.onmessage = ({ data }: { data: CommResult }) => {
|
|
||||||
const { reqid, resolve, reject } = data;
|
|
||||||
if (resolve) promises.get(reqid)?.resolve(resolve);
|
|
||||||
if (reject) promises.get(reqid)?.reject(reject);
|
|
||||||
promises.delete(reqid);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Create proxy to call worker methods
|
|
||||||
const proxy = new Proxy(worker, {
|
|
||||||
get(target: Worker, name: string) {
|
|
||||||
return async function wrapper(...args: any[]) {
|
|
||||||
return await new Promise((resolve, reject) => {
|
|
||||||
const reqid = Math.random();
|
|
||||||
promises.set(reqid, { resolve, reject });
|
|
||||||
target.postMessage({ reqid, name, args } as CommRequest);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
return proxy as T;
|
|
||||||
}
|
|
Loading…
Reference in New Issue