-
Notifications
You must be signed in to change notification settings - Fork 6
Expand file tree
/
Copy pathclass.js
More file actions
102 lines (90 loc) · 3.73 KB
/
class.js
File metadata and controls
102 lines (90 loc) · 3.73 KB
1
2
3
4
5
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
import withResolvers from '@webreflection/utils/with-resolvers';
import fetch from '@webreflection/fetch';
import xworker from './xworker.js';
import { getConfigURLAndType } from '../loader.js';
import { assign, create, defineProperties, importCSS, importJS } from '../utils.js';
import Hook from './hook.js';
/**
* @typedef {Object} WorkerOptions custom configuration
* @prop {string} type the interpreter type to use
* @prop {string} [version] the optional interpreter version to use
* @prop {string | object} [config] the optional config to use within such interpreter
* @prop {string} [configURL] the optional configURL used to resolve config entries
* @prop {string} [serviceWorker] the optional Service Worker for SharedArrayBuffer fallback
* @prop {string} [service_worker] alias for `serviceWorker`
*/
// REQUIRES INTEGRATION TEST
/* c8 ignore start */
export default (...args) =>
/**
* A XWorker is a Worker facade able to bootstrap a channel with any desired interpreter.
* @param {string} url the remote file to evaluate on bootstrap
* @param {WorkerOptions} [options] optional arguments to define the interpreter to use
* @returns {Worker}
*/
function XWorker(url, options) {
if (args.length) {
const [type, version] = args;
options = assign({}, options || { type, version });
if (!options.type) options.type = type;
}
// provide a base url to fetch or load config files from a Worker
// because there's no location at all in the Worker as it's embedded.
// fallback to a generic, ignored, config.txt file to still provide a URL.
const [ config ] = getConfigURLAndType(options.config, options.configURL);
const serviceWorker = options?.serviceWorker || options?.service_worker;
const worker = xworker({
serviceWorker,
reflected_ffi_no_symbol: !!globalThis.reflected_ffi_no_symbol,
reflected_ffi_timeout: globalThis.reflected_ffi_timeout ?? -1,
});
const { postMessage } = worker;
const isHook = this instanceof Hook;
const sync = assign(
worker.proxy,
{ importJS, importCSS },
);
const resolver = withResolvers();
let bootstrap = fetch(url)
.text()
.then(code => {
const hooks = isHook ? this.toJSON() : void 0;
postMessage.call(worker, { options, config, code, hooks });
})
.then(() => {
// boost postMessage performance
bootstrap = { then: fn => fn() };
});
defineProperties(worker, {
sync: { value: sync },
ready: { value: resolver.promise },
postMessage: {
value: (data, ...rest) => bootstrap.then(
() => postMessage.call(worker, data, ...rest),
),
},
onerror: {
writable: true,
configurable: true,
value: console.error
}
});
worker.addEventListener('message', event => {
const { data } = event;
const isError = data instanceof Error;
if (isError || data === 'polyscript:done') {
event.stopImmediatePropagation();
if (isError) {
resolver.reject(data);
worker.onerror(create(event, {
type: { value: 'error' },
error: { value: data }
}));
}
else resolver.resolve(worker);
}
});
if (isHook) this.onWorker?.(this.interpreter, worker);
return worker;
};
/* c8 ignore stop */