threadsx 2.0.0
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/LICENSE +21 -0
- package/README.md +164 -0
- package/dist/common.d.ts +4 -0
- package/dist/common.js +16 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +26 -0
- package/dist/master/get-bundle-url.browser.d.ts +3 -0
- package/dist/master/get-bundle-url.browser.js +28 -0
- package/dist/master/implementation.browser.d.ts +4 -0
- package/dist/master/implementation.browser.js +72 -0
- package/dist/master/implementation.d.ts +6 -0
- package/dist/master/implementation.js +51 -0
- package/dist/master/implementation.node.d.ts +4 -0
- package/dist/master/implementation.node.js +196 -0
- package/dist/master/index.d.ts +14 -0
- package/dist/master/index.js +15 -0
- package/dist/master/invocation-proxy.d.ts +3 -0
- package/dist/master/invocation-proxy.js +128 -0
- package/dist/master/pool-types.d.ts +65 -0
- package/dist/master/pool-types.js +15 -0
- package/dist/master/pool.d.ts +89 -0
- package/dist/master/pool.js +290 -0
- package/dist/master/register.d.ts +1 -0
- package/dist/master/register.js +9 -0
- package/dist/master/spawn.d.ts +20 -0
- package/dist/master/spawn.js +159 -0
- package/dist/master/thread.d.ts +12 -0
- package/dist/master/thread.js +22 -0
- package/dist/observable-promise.d.ts +38 -0
- package/dist/observable-promise.js +150 -0
- package/dist/observable.d.ts +19 -0
- package/dist/observable.js +40 -0
- package/dist/ponyfills.d.ts +8 -0
- package/dist/ponyfills.js +21 -0
- package/dist/promise.d.ts +5 -0
- package/dist/promise.js +27 -0
- package/dist/serializers.d.ts +16 -0
- package/dist/serializers.js +51 -0
- package/dist/symbols.d.ts +5 -0
- package/dist/symbols.js +8 -0
- package/dist/transferable.d.ts +42 -0
- package/dist/transferable.js +26 -0
- package/dist/types/master.d.ts +98 -0
- package/dist/types/master.js +12 -0
- package/dist/types/messages.d.ts +62 -0
- package/dist/types/messages.js +20 -0
- package/dist/types/worker.d.ts +11 -0
- package/dist/types/worker.js +2 -0
- package/dist/worker/bundle-entry.d.ts +1 -0
- package/dist/worker/bundle-entry.js +24 -0
- package/dist/worker/implementation.browser.d.ts +6 -0
- package/dist/worker/implementation.browser.js +25 -0
- package/dist/worker/implementation.d.ts +3 -0
- package/dist/worker/implementation.js +18 -0
- package/dist/worker/implementation.worker_threads.d.ts +8 -0
- package/dist/worker/implementation.worker_threads.js +42 -0
- package/dist/worker/index.d.ts +13 -0
- package/dist/worker/index.js +224 -0
- package/dist/worker_threads.d.ts +8 -0
- package/dist/worker_threads.js +16 -0
- package/dist-esm/common.js +11 -0
- package/dist-esm/index.js +5 -0
- package/dist-esm/master/get-bundle-url.browser.js +25 -0
- package/dist-esm/master/implementation.browser.js +67 -0
- package/dist-esm/master/implementation.js +15 -0
- package/dist-esm/master/implementation.node.js +155 -0
- package/dist-esm/master/index.js +9 -0
- package/dist-esm/master/invocation-proxy.js +121 -0
- package/dist-esm/master/pool-types.js +12 -0
- package/dist-esm/master/pool.js +283 -0
- package/dist-esm/master/register.js +7 -0
- package/dist-esm/master/spawn.js +153 -0
- package/dist-esm/master/thread.js +19 -0
- package/dist-esm/observable-promise.js +146 -0
- package/dist-esm/observable.js +36 -0
- package/dist-esm/ponyfills.js +18 -0
- package/dist-esm/promise.js +24 -0
- package/dist-esm/serializers.js +47 -0
- package/dist-esm/symbols.js +5 -0
- package/dist-esm/transferable.js +22 -0
- package/dist-esm/types/master.js +9 -0
- package/dist-esm/types/messages.js +17 -0
- package/dist-esm/types/worker.js +1 -0
- package/dist-esm/worker/bundle-entry.js +8 -0
- package/dist-esm/worker/implementation.browser.js +23 -0
- package/dist-esm/worker/implementation.js +13 -0
- package/dist-esm/worker/implementation.worker_threads.js +37 -0
- package/dist-esm/worker/index.js +215 -0
- package/dist-esm/worker_threads.js +13 -0
- package/index.mjs +4 -0
- package/observable.mjs +1 -0
- package/package.json +168 -0
- package/register.mjs +2 -0
- package/worker.mjs +1 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2019 Andy Wermke
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
|
13
|
+
all copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
21
|
+
THE SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
<h1 align="center">threadsx</h1>
|
|
2
|
+
|
|
3
|
+
<p align="center">
|
|
4
|
+
<strong>Make web workers & worker threads as simple as a function call.</strong>
|
|
5
|
+
</p>
|
|
6
|
+
|
|
7
|
+
<p align="center">
|
|
8
|
+
<a href="https://github.com/jmaleonard/threadsx/actions/workflows/ci.yml"><img alt="CI" src="https://github.com/jmaleonard/threadsx/actions/workflows/ci.yml/badge.svg"></a>
|
|
9
|
+
<img alt="Node" src="https://img.shields.io/badge/node-%E2%89%A520-3c873a">
|
|
10
|
+
<img alt="Modules" src="https://img.shields.io/badge/modules-ESM%20%26%20CommonJS-f97316">
|
|
11
|
+
<img alt="TypeScript" src="https://img.shields.io/badge/TypeScript-ready-3178c6">
|
|
12
|
+
<img alt="License" src="https://img.shields.io/badge/license-MIT-blue">
|
|
13
|
+
</p>
|
|
14
|
+
|
|
15
|
+
<p align="center">
|
|
16
|
+
A maintained, modernized fork of <a href="https://github.com/andywer/threads.js">threads.js</a> · <a href="https://threadsx.jmaleonard.com">threadsx.jmaleonard.com</a>
|
|
17
|
+
</p>
|
|
18
|
+
|
|
19
|
+
<br />
|
|
20
|
+
|
|
21
|
+
Offload CPU-intensive tasks to worker threads in node.js and web browsers using one uniform API. Uses [web workers](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API) in the browser and native [`worker_threads`](https://nodejs.org/api/worker_threads.html) in node.
|
|
22
|
+
|
|
23
|
+
### Features
|
|
24
|
+
|
|
25
|
+
* First-class support for **async functions** & **observables**
|
|
26
|
+
* Write code once, run it **in the browser and in node**
|
|
27
|
+
* Manage bulk task executions with **thread pools**
|
|
28
|
+
* Use **`require()`** and **`import`/`export`** in workers
|
|
29
|
+
* Ships **ESM and CommonJS** builds with **up-to-date TypeScript types**
|
|
30
|
+
* Works with modern bundlers (**webpack 5, Vite, esbuild, rollup**) out of the box
|
|
31
|
+
|
|
32
|
+
### About this fork
|
|
33
|
+
|
|
34
|
+
`threadsx` continues [andywer/threads.js](https://github.com/andywer/threads.js), which is no longer actively maintained. It modernizes the toolchain and dependencies, targets **Node.js 20+** with native `worker_threads`, drops the legacy `tiny-worker` fallback, and supports the `new Worker(new URL(…, import.meta.url))` pattern emitted by modern bundlers. The public API is unchanged.
|
|
35
|
+
|
|
36
|
+
## Installation
|
|
37
|
+
|
|
38
|
+
```
|
|
39
|
+
npm install threadsx
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Requires **Node.js 20 or newer**.
|
|
43
|
+
|
|
44
|
+
## Platform support
|
|
45
|
+
|
|
46
|
+
<details>
|
|
47
|
+
<summary>Run on node.js</summary>
|
|
48
|
+
|
|
49
|
+
<p></p>
|
|
50
|
+
|
|
51
|
+
Running code using threadsx in node works out of the box.
|
|
52
|
+
|
|
53
|
+
Note that we wrap the native `Worker`, so `new Worker("./foo/bar")` will resolve the path relative to the module that calls it, not relative to the current working directory. That aligns it with the behavior when bundling the code.
|
|
54
|
+
|
|
55
|
+
During development you can also point a worker at a TypeScript file directly — threadsx runs it through [`tsx`](https://github.com/privatenumber/tsx) (or `ts-node`) when either is installed.
|
|
56
|
+
|
|
57
|
+
</details>
|
|
58
|
+
|
|
59
|
+
<details>
|
|
60
|
+
<summary>Bundlers (webpack 5, Vite, esbuild, rollup)</summary>
|
|
61
|
+
|
|
62
|
+
<p></p>
|
|
63
|
+
|
|
64
|
+
Modern bundlers detect workers from the standard URL form, so **no extra plugin is required**:
|
|
65
|
+
|
|
66
|
+
```js
|
|
67
|
+
import { spawn, Worker } from "threadsx"
|
|
68
|
+
|
|
69
|
+
const worker = new Worker(new URL("./workers/auth", import.meta.url))
|
|
70
|
+
const auth = await spawn(worker)
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
This replaces the old `threads-plugin` flow, which is no longer needed.
|
|
74
|
+
|
|
75
|
+
When using TypeScript, make sure the compiler keeps the `import` / `export` statements intact (e.g. `"module": "esnext"` on the worker entry) so the bundler can resolve `new Worker(new URL(...))`.
|
|
76
|
+
|
|
77
|
+
</details>
|
|
78
|
+
|
|
79
|
+
<details>
|
|
80
|
+
<summary>Making <code>Worker</code> global (Parcel and similar)</summary>
|
|
81
|
+
|
|
82
|
+
<p></p>
|
|
83
|
+
|
|
84
|
+
If your bundler only recognizes `new Worker()` when `Worker` is the global, import `threadsx/register` once at the start of your master code:
|
|
85
|
+
|
|
86
|
+
```diff
|
|
87
|
+
import { spawn } from "threadsx"
|
|
88
|
+
+ import "threadsx/register"
|
|
89
|
+
|
|
90
|
+
// ...
|
|
91
|
+
|
|
92
|
+
const work = await spawn(new Worker("./worker"))
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
This registers the library's `Worker` implementation as the global `Worker`. Be aware this affects any code that instantiates a plain web worker `Worker`.
|
|
96
|
+
|
|
97
|
+
</details>
|
|
98
|
+
|
|
99
|
+
## Getting started
|
|
100
|
+
|
|
101
|
+
```js
|
|
102
|
+
// master.js
|
|
103
|
+
import { spawn, Thread, Worker } from "threadsx"
|
|
104
|
+
|
|
105
|
+
const auth = await spawn(new Worker("./workers/auth"))
|
|
106
|
+
const hashed = await auth.hashPassword("Super secret password", "1234")
|
|
107
|
+
|
|
108
|
+
console.log("Hashed password:", hashed)
|
|
109
|
+
|
|
110
|
+
await Thread.terminate(auth)
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
```js
|
|
114
|
+
// workers/auth.js
|
|
115
|
+
import sha256 from "js-sha256"
|
|
116
|
+
import { expose } from "threadsx/worker"
|
|
117
|
+
|
|
118
|
+
expose({
|
|
119
|
+
hashPassword(password, salt) {
|
|
120
|
+
return sha256(password + salt)
|
|
121
|
+
}
|
|
122
|
+
})
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### spawn()
|
|
126
|
+
|
|
127
|
+
The `hashPassword()` function of the `auth` object in the master code proxies the call to the `hashPassword()` function in the worker.
|
|
128
|
+
|
|
129
|
+
If the worker's function returns a promise or an observable then you can use the return value as such in the master code. If the function returns a primitive value, expect the master function to return a promise resolving to that value.
|
|
130
|
+
|
|
131
|
+
### expose()
|
|
132
|
+
|
|
133
|
+
Use `expose()` to make a function or an object containing methods callable from the master thread.
|
|
134
|
+
|
|
135
|
+
When exposing an object, `spawn()` asynchronously returns an object exposing all the object's functions. If you `expose()` a function, `spawn()` returns a callable function instead.
|
|
136
|
+
|
|
137
|
+
## Documentation
|
|
138
|
+
|
|
139
|
+
Find the full documentation on the [website](https://threadsx.jmaleonard.com):
|
|
140
|
+
|
|
141
|
+
- [**Quick start**](https://threadsx.jmaleonard.com/getting-started)
|
|
142
|
+
- [**Basic usage**](https://threadsx.jmaleonard.com/usage)
|
|
143
|
+
- [**Using observables**](https://threadsx.jmaleonard.com/usage-observables)
|
|
144
|
+
- [**Thread pools**](https://threadsx.jmaleonard.com/usage-pool)
|
|
145
|
+
- [**Advanced**](https://threadsx.jmaleonard.com/usage-advanced)
|
|
146
|
+
|
|
147
|
+
## Debug
|
|
148
|
+
|
|
149
|
+
We use the [`debug`](https://github.com/debug-js/debug) package to provide opt-in debug logging. All debug messages have a scope starting with `threads:`, with different sub-scopes:
|
|
150
|
+
|
|
151
|
+
- `threads:master:messages`
|
|
152
|
+
- `threads:master:spawn`
|
|
153
|
+
- `threads:master:thread-utils`
|
|
154
|
+
- `threads:pool:${poolName || poolID}`
|
|
155
|
+
|
|
156
|
+
Set `DEBUG=threads:*` to enable all of the library's debug logging:
|
|
157
|
+
|
|
158
|
+
```
|
|
159
|
+
DEBUG=threads:* npm test
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
## License
|
|
163
|
+
|
|
164
|
+
MIT — see [LICENSE](./LICENSE). Originally created by [Andy Wermke](https://github.com/andywer) as [threads.js](https://github.com/andywer/threads.js).
|
package/dist/common.d.ts
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { JsonSerializable, SerializerImplementation } from "./serializers";
|
|
2
|
+
export declare function registerSerializer(serializer: SerializerImplementation<JsonSerializable>): void;
|
|
3
|
+
export declare function deserialize(message: JsonSerializable): any;
|
|
4
|
+
export declare function serialize(input: any): JsonSerializable;
|
package/dist/common.js
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.registerSerializer = registerSerializer;
|
|
4
|
+
exports.deserialize = deserialize;
|
|
5
|
+
exports.serialize = serialize;
|
|
6
|
+
const serializers_1 = require("./serializers");
|
|
7
|
+
let registeredSerializer = serializers_1.DefaultSerializer;
|
|
8
|
+
function registerSerializer(serializer) {
|
|
9
|
+
registeredSerializer = (0, serializers_1.extendSerializer)(registeredSerializer, serializer);
|
|
10
|
+
}
|
|
11
|
+
function deserialize(message) {
|
|
12
|
+
return registeredSerializer.deserialize(message);
|
|
13
|
+
}
|
|
14
|
+
function serialize(input) {
|
|
15
|
+
return registeredSerializer.serialize(input);
|
|
16
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { registerSerializer } from "./common";
|
|
2
|
+
export * from "./master/index";
|
|
3
|
+
export { expose } from "./worker/index";
|
|
4
|
+
export { DefaultSerializer, JsonSerializable, Serializer, SerializerImplementation } from "./serializers";
|
|
5
|
+
export { Transfer, TransferDescriptor } from "./transferable";
|
|
6
|
+
export { ExposedToThreadType as ExposedAs } from "./master/spawn";
|
|
7
|
+
export { QueuedTask } from "./master/pool";
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
exports.Transfer = exports.DefaultSerializer = exports.expose = exports.registerSerializer = void 0;
|
|
18
|
+
var common_1 = require("./common");
|
|
19
|
+
Object.defineProperty(exports, "registerSerializer", { enumerable: true, get: function () { return common_1.registerSerializer; } });
|
|
20
|
+
__exportStar(require("./master/index"), exports);
|
|
21
|
+
var index_1 = require("./worker/index");
|
|
22
|
+
Object.defineProperty(exports, "expose", { enumerable: true, get: function () { return index_1.expose; } });
|
|
23
|
+
var serializers_1 = require("./serializers");
|
|
24
|
+
Object.defineProperty(exports, "DefaultSerializer", { enumerable: true, get: function () { return serializers_1.DefaultSerializer; } });
|
|
25
|
+
var transferable_1 = require("./transferable");
|
|
26
|
+
Object.defineProperty(exports, "Transfer", { enumerable: true, get: function () { return transferable_1.Transfer; } });
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Source: <https://github.com/parcel-bundler/parcel/blob/master/packages/core/parcel-bundler/src/builtins/bundle-url.js>
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.getBaseURL = getBaseURL;
|
|
5
|
+
exports.getBundleURL = getBundleURLCached;
|
|
6
|
+
let bundleURL;
|
|
7
|
+
function getBundleURLCached() {
|
|
8
|
+
if (!bundleURL) {
|
|
9
|
+
bundleURL = getBundleURL();
|
|
10
|
+
}
|
|
11
|
+
return bundleURL;
|
|
12
|
+
}
|
|
13
|
+
function getBundleURL() {
|
|
14
|
+
// Attempt to find the URL of the current script and use that as the base URL
|
|
15
|
+
try {
|
|
16
|
+
throw new Error;
|
|
17
|
+
}
|
|
18
|
+
catch (err) {
|
|
19
|
+
const matches = ("" + err.stack).match(/(https?|file|ftp|chrome-extension|moz-extension):\/\/[^)\n]+/g);
|
|
20
|
+
if (matches) {
|
|
21
|
+
return getBaseURL(matches[0]);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
return "/";
|
|
25
|
+
}
|
|
26
|
+
function getBaseURL(url) {
|
|
27
|
+
return ("" + url).replace(/^((?:https?|file|ftp|chrome-extension|moz-extension):\/\/.+)?\/[^/]+(?:\?.*)?$/, '$1') + '/';
|
|
28
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.defaultPoolSize = void 0;
|
|
4
|
+
exports.getWorkerImplementation = getWorkerImplementation;
|
|
5
|
+
exports.isWorkerRuntime = isWorkerRuntime;
|
|
6
|
+
const get_bundle_url_browser_1 = require("./get-bundle-url.browser");
|
|
7
|
+
exports.defaultPoolSize = typeof navigator !== "undefined" && navigator.hardwareConcurrency
|
|
8
|
+
? navigator.hardwareConcurrency
|
|
9
|
+
: 4;
|
|
10
|
+
const isAbsoluteURL = (value) => /^[a-zA-Z][a-zA-Z\d+\-.]*:/.test(value);
|
|
11
|
+
function createSourceBlobURL(code) {
|
|
12
|
+
const blob = new Blob([code], { type: "application/javascript" });
|
|
13
|
+
return URL.createObjectURL(blob);
|
|
14
|
+
}
|
|
15
|
+
function selectWorkerImplementation() {
|
|
16
|
+
if (typeof Worker === "undefined") {
|
|
17
|
+
// Might happen on Safari, for instance
|
|
18
|
+
// The idea is to only fail if the constructor is actually used
|
|
19
|
+
return class NoWebWorker {
|
|
20
|
+
constructor() {
|
|
21
|
+
throw Error("No web worker implementation available. You might have tried to spawn a worker within a worker in a browser that doesn't support workers in workers.");
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
class WebWorker extends Worker {
|
|
26
|
+
constructor(url, options) {
|
|
27
|
+
var _a, _b;
|
|
28
|
+
if (typeof url === "string" && options && options._baseURL) {
|
|
29
|
+
url = new URL(url, options._baseURL);
|
|
30
|
+
}
|
|
31
|
+
else if (typeof url === "string" && !isAbsoluteURL(url) && (0, get_bundle_url_browser_1.getBundleURL)().match(/^file:\/\//i)) {
|
|
32
|
+
url = new URL(url, (0, get_bundle_url_browser_1.getBundleURL)().replace(/\/[^/]+$/, "/"));
|
|
33
|
+
if ((_a = options === null || options === void 0 ? void 0 : options.CORSWorkaround) !== null && _a !== void 0 ? _a : true) {
|
|
34
|
+
url = createSourceBlobURL(`importScripts(${JSON.stringify(url)});`);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
if (typeof url === "string" && isAbsoluteURL(url)) {
|
|
38
|
+
// Create source code blob loading JS file via `importScripts()`
|
|
39
|
+
// to circumvent worker CORS restrictions
|
|
40
|
+
if ((_b = options === null || options === void 0 ? void 0 : options.CORSWorkaround) !== null && _b !== void 0 ? _b : true) {
|
|
41
|
+
url = createSourceBlobURL(`importScripts(${JSON.stringify(url)});`);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
super(url, options);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
class BlobWorker extends WebWorker {
|
|
48
|
+
constructor(blob, options) {
|
|
49
|
+
const url = window.URL.createObjectURL(blob);
|
|
50
|
+
super(url, options);
|
|
51
|
+
}
|
|
52
|
+
static fromText(source, options) {
|
|
53
|
+
const blob = new window.Blob([source], { type: "text/javascript" });
|
|
54
|
+
return new BlobWorker(blob, options);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return {
|
|
58
|
+
blob: BlobWorker,
|
|
59
|
+
default: WebWorker
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
let implementation;
|
|
63
|
+
function getWorkerImplementation() {
|
|
64
|
+
if (!implementation) {
|
|
65
|
+
implementation = selectWorkerImplementation();
|
|
66
|
+
}
|
|
67
|
+
return implementation;
|
|
68
|
+
}
|
|
69
|
+
function isWorkerRuntime() {
|
|
70
|
+
const isWindowContext = typeof self !== "undefined" && typeof Window !== "undefined" && self instanceof Window;
|
|
71
|
+
return typeof self !== "undefined" && typeof self.postMessage === "function" && !isWindowContext;
|
|
72
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import * as BrowserImplementation from "./implementation.browser";
|
|
2
|
+
/** Default size of pools. Depending on the platform the value might vary from device to device. */
|
|
3
|
+
export declare const defaultPoolSize: number;
|
|
4
|
+
export declare const getWorkerImplementation: typeof BrowserImplementation.getWorkerImplementation;
|
|
5
|
+
/** Returns `true` if this code is currently running in a worker. */
|
|
6
|
+
export declare const isWorkerRuntime: typeof BrowserImplementation.isWorkerRuntime;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/*
|
|
3
|
+
* This file is only a stub to make './implementation' resolve to the right module.
|
|
4
|
+
*/
|
|
5
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
6
|
+
if (k2 === undefined) k2 = k;
|
|
7
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
8
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
9
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
10
|
+
}
|
|
11
|
+
Object.defineProperty(o, k2, desc);
|
|
12
|
+
}) : (function(o, m, k, k2) {
|
|
13
|
+
if (k2 === undefined) k2 = k;
|
|
14
|
+
o[k2] = m[k];
|
|
15
|
+
}));
|
|
16
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
17
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
18
|
+
}) : function(o, v) {
|
|
19
|
+
o["default"] = v;
|
|
20
|
+
});
|
|
21
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
22
|
+
var ownKeys = function(o) {
|
|
23
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
24
|
+
var ar = [];
|
|
25
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
26
|
+
return ar;
|
|
27
|
+
};
|
|
28
|
+
return ownKeys(o);
|
|
29
|
+
};
|
|
30
|
+
return function (mod) {
|
|
31
|
+
if (mod && mod.__esModule) return mod;
|
|
32
|
+
var result = {};
|
|
33
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
34
|
+
__setModuleDefault(result, mod);
|
|
35
|
+
return result;
|
|
36
|
+
};
|
|
37
|
+
})();
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.isWorkerRuntime = exports.getWorkerImplementation = exports.defaultPoolSize = void 0;
|
|
40
|
+
// We alias `src/master/implementation` to `src/master/implementation.browser` for web
|
|
41
|
+
// browsers already in the package.json, so if get here, it's safe to pass-through the
|
|
42
|
+
// node implementation
|
|
43
|
+
const BrowserImplementation = __importStar(require("./implementation.browser"));
|
|
44
|
+
const NodeImplementation = __importStar(require("./implementation.node"));
|
|
45
|
+
const runningInNode = typeof process !== 'undefined' && process.arch !== 'browser' && 'pid' in process;
|
|
46
|
+
const implementation = runningInNode ? NodeImplementation : BrowserImplementation;
|
|
47
|
+
/** Default size of pools. Depending on the platform the value might vary from device to device. */
|
|
48
|
+
exports.defaultPoolSize = implementation.defaultPoolSize;
|
|
49
|
+
exports.getWorkerImplementation = implementation.getWorkerImplementation;
|
|
50
|
+
/** Returns `true` if this code is currently running in a worker. */
|
|
51
|
+
exports.isWorkerRuntime = implementation.isWorkerRuntime;
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/// <reference lib="dom" />
|
|
3
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
4
|
+
if (k2 === undefined) k2 = k;
|
|
5
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
6
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
7
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
8
|
+
}
|
|
9
|
+
Object.defineProperty(o, k2, desc);
|
|
10
|
+
}) : (function(o, m, k, k2) {
|
|
11
|
+
if (k2 === undefined) k2 = k;
|
|
12
|
+
o[k2] = m[k];
|
|
13
|
+
}));
|
|
14
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
15
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
16
|
+
}) : function(o, v) {
|
|
17
|
+
o["default"] = v;
|
|
18
|
+
});
|
|
19
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
20
|
+
var ownKeys = function(o) {
|
|
21
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
22
|
+
var ar = [];
|
|
23
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
24
|
+
return ar;
|
|
25
|
+
};
|
|
26
|
+
return ownKeys(o);
|
|
27
|
+
};
|
|
28
|
+
return function (mod) {
|
|
29
|
+
if (mod && mod.__esModule) return mod;
|
|
30
|
+
var result = {};
|
|
31
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
32
|
+
__setModuleDefault(result, mod);
|
|
33
|
+
return result;
|
|
34
|
+
};
|
|
35
|
+
})();
|
|
36
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
37
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
38
|
+
};
|
|
39
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
40
|
+
exports.defaultPoolSize = void 0;
|
|
41
|
+
exports.getWorkerImplementation = getWorkerImplementation;
|
|
42
|
+
exports.isWorkerRuntime = isWorkerRuntime;
|
|
43
|
+
const callsites_1 = __importDefault(require("callsites"));
|
|
44
|
+
const os_1 = require("os");
|
|
45
|
+
const path = __importStar(require("path"));
|
|
46
|
+
const url_1 = require("url");
|
|
47
|
+
let detectedTsRuntime;
|
|
48
|
+
exports.defaultPoolSize = (0, os_1.cpus)().length;
|
|
49
|
+
/**
|
|
50
|
+
* Detects an available TypeScript runtime so `.ts`/`.tsx` worker files can be
|
|
51
|
+
* spawned directly during development. Prefers `tsx`, falls back to `ts-node`.
|
|
52
|
+
*/
|
|
53
|
+
function detectTsRuntime() {
|
|
54
|
+
if (typeof __non_webpack_require__ === "function") {
|
|
55
|
+
// Webpack build: => No TS runtime required or possible
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
if (detectedTsRuntime !== undefined) {
|
|
59
|
+
return detectedTsRuntime;
|
|
60
|
+
}
|
|
61
|
+
detectedTsRuntime = null;
|
|
62
|
+
for (const candidate of ["tsx", "ts-node"]) {
|
|
63
|
+
try {
|
|
64
|
+
eval("require").resolve(candidate);
|
|
65
|
+
detectedTsRuntime = candidate;
|
|
66
|
+
break;
|
|
67
|
+
}
|
|
68
|
+
catch (error) {
|
|
69
|
+
if (error && error.code === "MODULE_NOT_FOUND") {
|
|
70
|
+
continue;
|
|
71
|
+
}
|
|
72
|
+
// Re-throw
|
|
73
|
+
throw error;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return detectedTsRuntime;
|
|
77
|
+
}
|
|
78
|
+
function createTsRuntimeModule(scriptPath, runtime) {
|
|
79
|
+
const register = runtime === "tsx"
|
|
80
|
+
? `require("tsx/cjs");`
|
|
81
|
+
: `require("ts-node/register/transpile-only");`;
|
|
82
|
+
const content = `
|
|
83
|
+
${register}
|
|
84
|
+
require(${JSON.stringify(scriptPath)});
|
|
85
|
+
`;
|
|
86
|
+
return content;
|
|
87
|
+
}
|
|
88
|
+
function rebaseScriptPath(scriptPath, ignoreRegex) {
|
|
89
|
+
const parentCallSite = (0, callsites_1.default)().find((callsite) => {
|
|
90
|
+
const filename = callsite.getFileName();
|
|
91
|
+
return Boolean(filename &&
|
|
92
|
+
!filename.match(ignoreRegex) &&
|
|
93
|
+
!filename.match(/[/\\]master[/\\]implementation/) &&
|
|
94
|
+
!filename.match(/^internal\/process/));
|
|
95
|
+
});
|
|
96
|
+
const rawCallerPath = parentCallSite ? parentCallSite.getFileName() : null;
|
|
97
|
+
let callerPath = rawCallerPath ? rawCallerPath : null;
|
|
98
|
+
if (callerPath && callerPath.startsWith('file:')) {
|
|
99
|
+
callerPath = (0, url_1.fileURLToPath)(callerPath);
|
|
100
|
+
}
|
|
101
|
+
const rebasedScriptPath = callerPath ? path.join(path.dirname(callerPath), scriptPath) : scriptPath;
|
|
102
|
+
return rebasedScriptPath;
|
|
103
|
+
}
|
|
104
|
+
function resolveScriptPath(scriptPath, baseURL) {
|
|
105
|
+
const makeRelative = (filePath) => {
|
|
106
|
+
// eval() hack is also webpack-related
|
|
107
|
+
return path.isAbsolute(filePath) ? filePath : path.join(baseURL || eval("__dirname"), filePath);
|
|
108
|
+
};
|
|
109
|
+
const workerFilePath = typeof __non_webpack_require__ === "function"
|
|
110
|
+
? __non_webpack_require__.resolve(makeRelative(scriptPath))
|
|
111
|
+
: eval("require").resolve(makeRelative(rebaseScriptPath(scriptPath, /[/\\]worker_threads[/\\]/)));
|
|
112
|
+
return workerFilePath;
|
|
113
|
+
}
|
|
114
|
+
function initWorkerThreadsWorker() {
|
|
115
|
+
// Webpack hack
|
|
116
|
+
const NativeWorker = typeof __non_webpack_require__ === "function"
|
|
117
|
+
? __non_webpack_require__("worker_threads").Worker
|
|
118
|
+
: eval("require")("worker_threads").Worker;
|
|
119
|
+
let allWorkers = [];
|
|
120
|
+
class Worker extends NativeWorker {
|
|
121
|
+
constructor(scriptPath, options) {
|
|
122
|
+
// Bundlers like webpack 5 pass a `URL` (from `new Worker(new URL(...))`)
|
|
123
|
+
// pointing at the emitted worker chunk.
|
|
124
|
+
const normalizedScriptPath = scriptPath instanceof URL ? (0, url_1.fileURLToPath)(scriptPath) : scriptPath;
|
|
125
|
+
const resolvedScriptPath = options && options.fromSource
|
|
126
|
+
? null
|
|
127
|
+
: resolveScriptPath(normalizedScriptPath, (options || {})._baseURL);
|
|
128
|
+
const tsRuntime = resolvedScriptPath && /\.tsx?$/i.test(resolvedScriptPath) ? detectTsRuntime() : null;
|
|
129
|
+
if (!resolvedScriptPath) {
|
|
130
|
+
// `options.fromSource` is true
|
|
131
|
+
const sourceCode = scriptPath;
|
|
132
|
+
super(sourceCode, Object.assign(Object.assign({}, options), { eval: true }));
|
|
133
|
+
}
|
|
134
|
+
else if (tsRuntime) {
|
|
135
|
+
super(createTsRuntimeModule(resolvedScriptPath, tsRuntime), Object.assign(Object.assign({}, options), { eval: true }));
|
|
136
|
+
}
|
|
137
|
+
else if (resolvedScriptPath.match(/\.asar[/\\]/)) {
|
|
138
|
+
// See <https://github.com/andywer/threads-plugin/issues/17>
|
|
139
|
+
super(resolvedScriptPath.replace(/\.asar([/\\])/, ".asar.unpacked$1"), options);
|
|
140
|
+
}
|
|
141
|
+
else {
|
|
142
|
+
super(resolvedScriptPath, options);
|
|
143
|
+
}
|
|
144
|
+
this.mappedEventListeners = new WeakMap();
|
|
145
|
+
allWorkers.push(this);
|
|
146
|
+
}
|
|
147
|
+
addEventListener(eventName, rawListener) {
|
|
148
|
+
const listener = (message) => {
|
|
149
|
+
rawListener({ data: message });
|
|
150
|
+
};
|
|
151
|
+
this.mappedEventListeners.set(rawListener, listener);
|
|
152
|
+
this.on(eventName, listener);
|
|
153
|
+
}
|
|
154
|
+
removeEventListener(eventName, rawListener) {
|
|
155
|
+
const listener = this.mappedEventListeners.get(rawListener) || rawListener;
|
|
156
|
+
this.off(eventName, listener);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
const terminateWorkersAndMaster = () => {
|
|
160
|
+
// we should terminate all workers and then gracefully shutdown self process
|
|
161
|
+
Promise.all(allWorkers.map(worker => worker.terminate())).then(() => process.exit(0), () => process.exit(1));
|
|
162
|
+
allWorkers = [];
|
|
163
|
+
};
|
|
164
|
+
// Take care to not leave orphaned processes behind. See #147.
|
|
165
|
+
process.on("SIGINT", () => terminateWorkersAndMaster());
|
|
166
|
+
process.on("SIGTERM", () => terminateWorkersAndMaster());
|
|
167
|
+
class BlobWorker extends Worker {
|
|
168
|
+
constructor(blob, options) {
|
|
169
|
+
super(Buffer.from(blob).toString("utf-8"), Object.assign(Object.assign({}, options), { fromSource: true }));
|
|
170
|
+
}
|
|
171
|
+
static fromText(source, options) {
|
|
172
|
+
return new Worker(source, Object.assign(Object.assign({}, options), { fromSource: true }));
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
return {
|
|
176
|
+
blob: BlobWorker,
|
|
177
|
+
default: Worker
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
let implementation;
|
|
181
|
+
function selectWorkerImplementation() {
|
|
182
|
+
return initWorkerThreadsWorker();
|
|
183
|
+
}
|
|
184
|
+
function getWorkerImplementation() {
|
|
185
|
+
if (!implementation) {
|
|
186
|
+
implementation = selectWorkerImplementation();
|
|
187
|
+
}
|
|
188
|
+
return implementation;
|
|
189
|
+
}
|
|
190
|
+
function isWorkerRuntime() {
|
|
191
|
+
// Webpack hack
|
|
192
|
+
const isMainThread = typeof __non_webpack_require__ === "function"
|
|
193
|
+
? __non_webpack_require__("worker_threads").isMainThread
|
|
194
|
+
: eval("require")("worker_threads").isMainThread;
|
|
195
|
+
return !isMainThread;
|
|
196
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { BlobWorker as BlobWorkerClass } from "../types/master";
|
|
2
|
+
import { Worker as WorkerType } from "../types/master";
|
|
3
|
+
import { isWorkerRuntime } from "./implementation";
|
|
4
|
+
export { FunctionThread, ModuleThread } from "../types/master";
|
|
5
|
+
export { Pool } from "./pool";
|
|
6
|
+
export { spawn } from "./spawn";
|
|
7
|
+
export { Thread } from "./thread";
|
|
8
|
+
export { isWorkerRuntime };
|
|
9
|
+
export type BlobWorker = typeof BlobWorkerClass;
|
|
10
|
+
export type Worker = WorkerType;
|
|
11
|
+
/** Separate class to spawn workers from source code blobs or strings. */
|
|
12
|
+
export declare const BlobWorker: typeof BlobWorkerClass;
|
|
13
|
+
/** Worker implementation. Either web worker or a node.js Worker class. */
|
|
14
|
+
export declare const Worker: typeof import("../types/master").WorkerImplementation;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Worker = exports.BlobWorker = exports.isWorkerRuntime = exports.Thread = exports.spawn = exports.Pool = void 0;
|
|
4
|
+
const implementation_1 = require("./implementation");
|
|
5
|
+
Object.defineProperty(exports, "isWorkerRuntime", { enumerable: true, get: function () { return implementation_1.isWorkerRuntime; } });
|
|
6
|
+
var pool_1 = require("./pool");
|
|
7
|
+
Object.defineProperty(exports, "Pool", { enumerable: true, get: function () { return pool_1.Pool; } });
|
|
8
|
+
var spawn_1 = require("./spawn");
|
|
9
|
+
Object.defineProperty(exports, "spawn", { enumerable: true, get: function () { return spawn_1.spawn; } });
|
|
10
|
+
var thread_1 = require("./thread");
|
|
11
|
+
Object.defineProperty(exports, "Thread", { enumerable: true, get: function () { return thread_1.Thread; } });
|
|
12
|
+
/** Separate class to spawn workers from source code blobs or strings. */
|
|
13
|
+
exports.BlobWorker = (0, implementation_1.getWorkerImplementation)().blob;
|
|
14
|
+
/** Worker implementation. Either web worker or a node.js Worker class. */
|
|
15
|
+
exports.Worker = (0, implementation_1.getWorkerImplementation)().default;
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { ModuleMethods, ModuleProxy, ProxyableFunction, Worker as WorkerType } from "../types/master";
|
|
2
|
+
export declare function createProxyFunction<Args extends any[], ReturnType>(worker: WorkerType, method?: string): ProxyableFunction<Args, ReturnType>;
|
|
3
|
+
export declare function createProxyModule<Methods extends ModuleMethods>(worker: WorkerType, methodNames: string[]): ModuleProxy<Methods>;
|