@xylabs/threads 4.2.2 → 4.3.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/README.md +2 -20
- package/dist/esm/master/implementation.node.js +5 -74
- package/dist/esm/worker/implementation.js +1 -2
- package/dist/master/implementation.node.js +5 -74
- package/dist/worker/implementation.js +1 -2
- package/package.json +3 -12
- package/src/master/implementation.node.ts +7 -110
- package/src/master/spawn.ts +1 -1
- package/src/types/master.ts +2 -2
- package/src/worker/implementation.tiny-worker.ts +0 -2
- package/src/worker/implementation.ts +1 -2
- package/test-tooling/webpack/webpack.node.config.js +0 -1
- package/test-tooling/rollup/rollup.test.ts +0 -44
- package/test-tooling/tsconfig/minimal-tsconfig.test.ts +0 -7
- package/types/tiny-worker.d.ts +0 -4
package/README.md
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
|
|
12
12
|
Offload CPU-intensive tasks to worker threads in node.js, web browsers and electron using one uniform API.
|
|
13
13
|
|
|
14
|
-
Uses web workers in the browser
|
|
14
|
+
Uses web workers in the browser and `worker_threads` in node 12+
|
|
15
15
|
|
|
16
16
|
### Features
|
|
17
17
|
|
|
@@ -28,11 +28,9 @@ You can find the old version 0.12 of threads.js on the [`v0` branch](https://git
|
|
|
28
28
|
## Installation
|
|
29
29
|
|
|
30
30
|
```
|
|
31
|
-
npm install threads
|
|
31
|
+
npm install threads
|
|
32
32
|
```
|
|
33
33
|
|
|
34
|
-
*You only need to install the `tiny-worker` package to support node.js < 12. It's an optional dependency and used as a fallback if `worker_threads` are not available.*
|
|
35
|
-
|
|
36
34
|
## Platform support
|
|
37
35
|
|
|
38
36
|
<details>
|
|
@@ -73,22 +71,6 @@ Then add it to your `webpack.config.js`:
|
|
|
73
71
|
}
|
|
74
72
|
```
|
|
75
73
|
|
|
76
|
-
#### Node.js bundles
|
|
77
|
-
|
|
78
|
-
If you are using webpack to create a bundle that will be run in node (webpack config `target: "node"`), you also need to specify that the `tiny-worker` package used for node < 12 should not be bundled:
|
|
79
|
-
|
|
80
|
-
```diff
|
|
81
|
-
module.exports = {
|
|
82
|
-
// ...
|
|
83
|
-
+ externals: {
|
|
84
|
-
+ "tiny-worker": "tiny-worker"
|
|
85
|
-
+ }
|
|
86
|
-
// ...
|
|
87
|
-
}
|
|
88
|
-
```
|
|
89
|
-
|
|
90
|
-
Make sure that `tiny-worker` is listed in your `package.json` `dependencies` in that case.
|
|
91
|
-
|
|
92
74
|
#### When using TypeScript
|
|
93
75
|
|
|
94
76
|
Note: You'll need to be using Typescript version 4+, as the types generated by threads.js are not supported in Typescript 3.
|
|
@@ -6,7 +6,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
exports.defaultPoolSize = void 0;
|
|
7
7
|
exports.getWorkerImplementation = getWorkerImplementation;
|
|
8
8
|
exports.isWorkerRuntime = isWorkerRuntime;
|
|
9
|
-
const node_events_1 = require("node:events");
|
|
10
9
|
const node_os_1 = require("node:os");
|
|
11
10
|
const node_path_1 = __importDefault(require("node:path"));
|
|
12
11
|
const node_url_1 = require("node:url");
|
|
@@ -114,76 +113,13 @@ function initWorkerThreadsWorker() {
|
|
|
114
113
|
default: Worker,
|
|
115
114
|
};
|
|
116
115
|
}
|
|
117
|
-
function initTinyWorker() {
|
|
118
|
-
const TinyWorker = require('tiny-worker');
|
|
119
|
-
let allWorkers = [];
|
|
120
|
-
class Worker extends TinyWorker {
|
|
121
|
-
emitter;
|
|
122
|
-
constructor(scriptPath, options) {
|
|
123
|
-
const resolvedScriptPath = options && options.fromSource
|
|
124
|
-
? null
|
|
125
|
-
: process.platform === 'win32'
|
|
126
|
-
? `file:///${resolveScriptPath(scriptPath).replaceAll('\\', '/')}`
|
|
127
|
-
: resolveScriptPath(scriptPath);
|
|
128
|
-
if (!resolvedScriptPath) {
|
|
129
|
-
const sourceCode = scriptPath;
|
|
130
|
-
super(new Function(sourceCode), [], { esm: true });
|
|
131
|
-
}
|
|
132
|
-
else if (/\.tsx?$/i.test(resolvedScriptPath) && detectTsNode()) {
|
|
133
|
-
super(new Function(createTsNodeModule(resolveScriptPath(scriptPath))), [], { esm: true });
|
|
134
|
-
}
|
|
135
|
-
else if (/\.asar[/\\]/.test(resolvedScriptPath)) {
|
|
136
|
-
super(resolvedScriptPath.replace(/\.asar([/\\])/, '.asar.unpacked$1'), [], { esm: true });
|
|
137
|
-
}
|
|
138
|
-
else {
|
|
139
|
-
super(resolvedScriptPath, [], { esm: true });
|
|
140
|
-
}
|
|
141
|
-
allWorkers.push(this);
|
|
142
|
-
this.emitter = new node_events_1.EventEmitter();
|
|
143
|
-
this.onerror = (error) => this.emitter.emit('error', error);
|
|
144
|
-
this.onmessage = (message) => this.emitter.emit('message', message);
|
|
145
|
-
}
|
|
146
|
-
addEventListener(eventName, listener) {
|
|
147
|
-
this.emitter.addListener(eventName, listener);
|
|
148
|
-
}
|
|
149
|
-
removeEventListener(eventName, listener) {
|
|
150
|
-
this.emitter.removeListener(eventName, listener);
|
|
151
|
-
}
|
|
152
|
-
terminate() {
|
|
153
|
-
allWorkers = allWorkers.filter(worker => worker !== this);
|
|
154
|
-
return super.terminate();
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
const terminateWorkersAndMaster = () => {
|
|
158
|
-
Promise.all(allWorkers.map(worker => worker.terminate())).then(() => process.exit(0), () => process.exit(1));
|
|
159
|
-
allWorkers = [];
|
|
160
|
-
};
|
|
161
|
-
process.on('SIGINT', () => terminateWorkersAndMaster());
|
|
162
|
-
process.on('SIGTERM', () => terminateWorkersAndMaster());
|
|
163
|
-
class BlobWorker extends Worker {
|
|
164
|
-
constructor(blob, options) {
|
|
165
|
-
super(Buffer.from(blob).toString('utf-8'), { ...options, fromSource: true });
|
|
166
|
-
}
|
|
167
|
-
static fromText(source, options) {
|
|
168
|
-
return new Worker(source, { ...options, fromSource: true });
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
return {
|
|
172
|
-
blob: BlobWorker,
|
|
173
|
-
default: Worker,
|
|
174
|
-
};
|
|
175
|
-
}
|
|
176
116
|
let implementation;
|
|
177
|
-
let isTinyWorker;
|
|
178
117
|
function selectWorkerImplementation() {
|
|
179
118
|
try {
|
|
180
|
-
isTinyWorker = false;
|
|
181
119
|
return initWorkerThreadsWorker();
|
|
182
120
|
}
|
|
183
121
|
catch {
|
|
184
|
-
|
|
185
|
-
isTinyWorker = true;
|
|
186
|
-
return initTinyWorker();
|
|
122
|
+
throw new Error('Node worker_threads not available...');
|
|
187
123
|
}
|
|
188
124
|
}
|
|
189
125
|
function getWorkerImplementation() {
|
|
@@ -193,13 +129,8 @@ function getWorkerImplementation() {
|
|
|
193
129
|
return implementation;
|
|
194
130
|
}
|
|
195
131
|
function isWorkerRuntime() {
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
const isMainThread = typeof __non_webpack_require__ === 'function'
|
|
201
|
-
? __non_webpack_require__('worker_threads').isMainThread
|
|
202
|
-
: eval('require')('worker_threads').isMainThread;
|
|
203
|
-
return !isMainThread;
|
|
204
|
-
}
|
|
132
|
+
const isMainThread = typeof __non_webpack_require__ === 'function'
|
|
133
|
+
? __non_webpack_require__('worker_threads').isMainThread
|
|
134
|
+
: eval('require')('worker_threads').isMainThread;
|
|
135
|
+
return !isMainThread;
|
|
205
136
|
}
|
|
@@ -4,7 +4,6 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
const implementation_browser_1 = __importDefault(require("./implementation.browser"));
|
|
7
|
-
const implementation_tiny_worker_1 = __importDefault(require("./implementation.tiny-worker"));
|
|
8
7
|
const implementation_worker_threads_1 = __importDefault(require("./implementation.worker_threads"));
|
|
9
8
|
const runningInNode = typeof process !== 'undefined' && process.arch !== 'browser' && 'pid' in process;
|
|
10
9
|
function selectNodeImplementation() {
|
|
@@ -13,7 +12,7 @@ function selectNodeImplementation() {
|
|
|
13
12
|
return implementation_worker_threads_1.default;
|
|
14
13
|
}
|
|
15
14
|
catch {
|
|
16
|
-
|
|
15
|
+
throw new Error('No worker implementation available in this environment');
|
|
17
16
|
}
|
|
18
17
|
}
|
|
19
18
|
exports.default = runningInNode ? selectNodeImplementation() : implementation_browser_1.default;
|
|
@@ -6,7 +6,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
exports.defaultPoolSize = void 0;
|
|
7
7
|
exports.getWorkerImplementation = getWorkerImplementation;
|
|
8
8
|
exports.isWorkerRuntime = isWorkerRuntime;
|
|
9
|
-
const node_events_1 = require("node:events");
|
|
10
9
|
const node_os_1 = require("node:os");
|
|
11
10
|
const node_path_1 = __importDefault(require("node:path"));
|
|
12
11
|
const node_url_1 = require("node:url");
|
|
@@ -114,76 +113,13 @@ function initWorkerThreadsWorker() {
|
|
|
114
113
|
default: Worker,
|
|
115
114
|
};
|
|
116
115
|
}
|
|
117
|
-
function initTinyWorker() {
|
|
118
|
-
const TinyWorker = require('tiny-worker');
|
|
119
|
-
let allWorkers = [];
|
|
120
|
-
class Worker extends TinyWorker {
|
|
121
|
-
emitter;
|
|
122
|
-
constructor(scriptPath, options) {
|
|
123
|
-
const resolvedScriptPath = options && options.fromSource
|
|
124
|
-
? null
|
|
125
|
-
: process.platform === 'win32'
|
|
126
|
-
? `file:///${resolveScriptPath(scriptPath).replaceAll('\\', '/')}`
|
|
127
|
-
: resolveScriptPath(scriptPath);
|
|
128
|
-
if (!resolvedScriptPath) {
|
|
129
|
-
const sourceCode = scriptPath;
|
|
130
|
-
super(new Function(sourceCode), [], { esm: true });
|
|
131
|
-
}
|
|
132
|
-
else if (/\.tsx?$/i.test(resolvedScriptPath) && detectTsNode()) {
|
|
133
|
-
super(new Function(createTsNodeModule(resolveScriptPath(scriptPath))), [], { esm: true });
|
|
134
|
-
}
|
|
135
|
-
else if (/\.asar[/\\]/.test(resolvedScriptPath)) {
|
|
136
|
-
super(resolvedScriptPath.replace(/\.asar([/\\])/, '.asar.unpacked$1'), [], { esm: true });
|
|
137
|
-
}
|
|
138
|
-
else {
|
|
139
|
-
super(resolvedScriptPath, [], { esm: true });
|
|
140
|
-
}
|
|
141
|
-
allWorkers.push(this);
|
|
142
|
-
this.emitter = new node_events_1.EventEmitter();
|
|
143
|
-
this.onerror = (error) => this.emitter.emit('error', error);
|
|
144
|
-
this.onmessage = (message) => this.emitter.emit('message', message);
|
|
145
|
-
}
|
|
146
|
-
addEventListener(eventName, listener) {
|
|
147
|
-
this.emitter.addListener(eventName, listener);
|
|
148
|
-
}
|
|
149
|
-
removeEventListener(eventName, listener) {
|
|
150
|
-
this.emitter.removeListener(eventName, listener);
|
|
151
|
-
}
|
|
152
|
-
terminate() {
|
|
153
|
-
allWorkers = allWorkers.filter(worker => worker !== this);
|
|
154
|
-
return super.terminate();
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
const terminateWorkersAndMaster = () => {
|
|
158
|
-
Promise.all(allWorkers.map(worker => worker.terminate())).then(() => process.exit(0), () => process.exit(1));
|
|
159
|
-
allWorkers = [];
|
|
160
|
-
};
|
|
161
|
-
process.on('SIGINT', () => terminateWorkersAndMaster());
|
|
162
|
-
process.on('SIGTERM', () => terminateWorkersAndMaster());
|
|
163
|
-
class BlobWorker extends Worker {
|
|
164
|
-
constructor(blob, options) {
|
|
165
|
-
super(Buffer.from(blob).toString('utf-8'), { ...options, fromSource: true });
|
|
166
|
-
}
|
|
167
|
-
static fromText(source, options) {
|
|
168
|
-
return new Worker(source, { ...options, fromSource: true });
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
return {
|
|
172
|
-
blob: BlobWorker,
|
|
173
|
-
default: Worker,
|
|
174
|
-
};
|
|
175
|
-
}
|
|
176
116
|
let implementation;
|
|
177
|
-
let isTinyWorker;
|
|
178
117
|
function selectWorkerImplementation() {
|
|
179
118
|
try {
|
|
180
|
-
isTinyWorker = false;
|
|
181
119
|
return initWorkerThreadsWorker();
|
|
182
120
|
}
|
|
183
121
|
catch {
|
|
184
|
-
|
|
185
|
-
isTinyWorker = true;
|
|
186
|
-
return initTinyWorker();
|
|
122
|
+
throw new Error('Node worker_threads not available...');
|
|
187
123
|
}
|
|
188
124
|
}
|
|
189
125
|
function getWorkerImplementation() {
|
|
@@ -193,13 +129,8 @@ function getWorkerImplementation() {
|
|
|
193
129
|
return implementation;
|
|
194
130
|
}
|
|
195
131
|
function isWorkerRuntime() {
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
const isMainThread = typeof __non_webpack_require__ === 'function'
|
|
201
|
-
? __non_webpack_require__('worker_threads').isMainThread
|
|
202
|
-
: eval('require')('worker_threads').isMainThread;
|
|
203
|
-
return !isMainThread;
|
|
204
|
-
}
|
|
132
|
+
const isMainThread = typeof __non_webpack_require__ === 'function'
|
|
133
|
+
? __non_webpack_require__('worker_threads').isMainThread
|
|
134
|
+
: eval('require')('worker_threads').isMainThread;
|
|
135
|
+
return !isMainThread;
|
|
205
136
|
}
|
|
@@ -4,7 +4,6 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
const implementation_browser_1 = __importDefault(require("./implementation.browser"));
|
|
7
|
-
const implementation_tiny_worker_1 = __importDefault(require("./implementation.tiny-worker"));
|
|
8
7
|
const implementation_worker_threads_1 = __importDefault(require("./implementation.worker_threads"));
|
|
9
8
|
const runningInNode = typeof process !== 'undefined' && process.arch !== 'browser' && 'pid' in process;
|
|
10
9
|
function selectNodeImplementation() {
|
|
@@ -13,7 +12,7 @@ function selectNodeImplementation() {
|
|
|
13
12
|
return implementation_worker_threads_1.default;
|
|
14
13
|
}
|
|
15
14
|
catch {
|
|
16
|
-
|
|
15
|
+
throw new Error('No worker implementation available in this environment');
|
|
17
16
|
}
|
|
18
17
|
}
|
|
19
18
|
exports.default = runningInNode ? selectNodeImplementation() : implementation_browser_1.default;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xylabs/threads",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.3.0",
|
|
4
4
|
"description": "Web workers & worker threads as simple as a function call",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -95,14 +95,12 @@
|
|
|
95
95
|
"@rollup/plugin-node-resolve": "^15.3.0",
|
|
96
96
|
"@types/chai": "^5.0.0",
|
|
97
97
|
"@types/debug": "^4.1.12",
|
|
98
|
-
"@types/
|
|
99
|
-
"@types/node": "^22.7.6",
|
|
98
|
+
"@types/node": "^22.7.7",
|
|
100
99
|
"@types/webpack": "^5.28.5",
|
|
101
|
-
"@xylabs/ts-scripts-yarn3": "^4.2.
|
|
100
|
+
"@xylabs/ts-scripts-yarn3": "^4.2.3",
|
|
102
101
|
"ava": "^6.1.3",
|
|
103
102
|
"chai": "^5.1.1",
|
|
104
103
|
"cross-env": "^7.0.3",
|
|
105
|
-
"execa": "^9.4.1",
|
|
106
104
|
"mocha": "^10.7.3",
|
|
107
105
|
"puppet-run": "^0.11.4",
|
|
108
106
|
"puppet-run-plugin-mocha": "^0.1.1",
|
|
@@ -110,7 +108,6 @@
|
|
|
110
108
|
"rimraf": "^5.0.10",
|
|
111
109
|
"rollup": "^4.24.0",
|
|
112
110
|
"threads-plugin": "^1.4.0",
|
|
113
|
-
"tiny-worker": "^2.3.0",
|
|
114
111
|
"ts-loader": "^9.5.1",
|
|
115
112
|
"ts-node": "^10.9.2",
|
|
116
113
|
"typescript": "^5.6.3",
|
|
@@ -119,9 +116,6 @@
|
|
|
119
116
|
"webpack": "^5.95.0",
|
|
120
117
|
"worker-plugin": "^5.0.1"
|
|
121
118
|
},
|
|
122
|
-
"optionalDependencies": {
|
|
123
|
-
"tiny-worker": "^2.3.0"
|
|
124
|
-
},
|
|
125
119
|
"ava": {
|
|
126
120
|
"extensions": [
|
|
127
121
|
"ts"
|
|
@@ -139,15 +133,12 @@
|
|
|
139
133
|
"./dist/esm/master/implementation.js": "./dist/esm/master/implementation.browser.js",
|
|
140
134
|
"./dist/esm/master/implementation.node.js": false,
|
|
141
135
|
"./dist/esm/worker/implementation.js": "./dist/esm/worker/implementation.browser.js",
|
|
142
|
-
"./dist/esm/worker/implementation.tiny-worker.js": false,
|
|
143
136
|
"./dist/esm/worker/implementation.worker_threads.js": false,
|
|
144
137
|
"./dist/master/implementation.js": "./dist/master/implementation.browser.js",
|
|
145
138
|
"./dist/master/implementation.node.js": false,
|
|
146
139
|
"./dist/worker/implementation.js": "./dist/worker/implementation.browser.js",
|
|
147
|
-
"./dist/worker/implementation.tiny-worker.js": false,
|
|
148
140
|
"./dist/worker/implementation.worker_threads.js": false,
|
|
149
141
|
"callsites": false,
|
|
150
|
-
"tiny-worker": false,
|
|
151
142
|
"ts-node": false,
|
|
152
143
|
"ts-node/register": false,
|
|
153
144
|
"worker_threads": false
|
|
@@ -1,16 +1,12 @@
|
|
|
1
|
-
/* eslint-disable @typescript-eslint/no-require-imports */
|
|
2
1
|
/* eslint-disable import-x/no-internal-modules */
|
|
3
2
|
/* eslint-disable unicorn/no-process-exit */
|
|
4
3
|
/* eslint-disable unicorn/prefer-logical-operator-over-ternary */
|
|
5
4
|
/* eslint-disable unicorn/prefer-regexp-test */
|
|
6
5
|
|
|
7
|
-
/* eslint-disable unicorn/prefer-add-event-listener */
|
|
8
|
-
/* eslint-disable unicorn/prefer-event-target */
|
|
9
6
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
10
7
|
/* eslint-disable unicorn/text-encoding-identifier-case */
|
|
11
8
|
/// <reference lib="dom" />
|
|
12
9
|
|
|
13
|
-
import { EventEmitter } from 'node:events'
|
|
14
10
|
import { cpus } from 'node:os'
|
|
15
11
|
import path from 'node:path'
|
|
16
12
|
import { fileURLToPath } from 'node:url'
|
|
@@ -22,16 +18,7 @@ import type {
|
|
|
22
18
|
ImplementationExport, ThreadsWorkerOptions, WorkerImplementation,
|
|
23
19
|
} from '../types/master'
|
|
24
20
|
|
|
25
|
-
interface WorkerGlobalScope {
|
|
26
|
-
addEventListener(eventName: string, listener: (event: Event) => void): void
|
|
27
|
-
postMessage(message: any, transferables?: any[]): void
|
|
28
|
-
removeEventListener(eventName: string, listener: (event: Event) => void): void
|
|
29
|
-
}
|
|
30
|
-
|
|
31
21
|
declare const __non_webpack_require__: typeof require
|
|
32
|
-
declare const self: WorkerGlobalScope
|
|
33
|
-
|
|
34
|
-
type WorkerEventName = 'error' | 'message'
|
|
35
22
|
|
|
36
23
|
let tsNodeAvailable: boolean | undefined
|
|
37
24
|
|
|
@@ -167,100 +154,14 @@ function initWorkerThreadsWorker(): ImplementationExport {
|
|
|
167
154
|
}
|
|
168
155
|
}
|
|
169
156
|
|
|
170
|
-
function initTinyWorker(): ImplementationExport {
|
|
171
|
-
const TinyWorker = require('tiny-worker')
|
|
172
|
-
|
|
173
|
-
let allWorkers: Array<typeof TinyWorker> = []
|
|
174
|
-
|
|
175
|
-
class Worker extends TinyWorker {
|
|
176
|
-
private emitter: EventEmitter
|
|
177
|
-
|
|
178
|
-
constructor(scriptPath: string, options?: ThreadsWorkerOptions & { fromSource?: boolean }) {
|
|
179
|
-
// Need to apply a work-around for Windows or it will choke upon the absolute path
|
|
180
|
-
// (`Error [ERR_INVALID_PROTOCOL]: Protocol 'c:' not supported`)
|
|
181
|
-
const resolvedScriptPath
|
|
182
|
-
= options && options.fromSource
|
|
183
|
-
? null
|
|
184
|
-
: process.platform === 'win32'
|
|
185
|
-
? `file:///${resolveScriptPath(scriptPath).replaceAll('\\', '/')}`
|
|
186
|
-
: resolveScriptPath(scriptPath)
|
|
187
|
-
|
|
188
|
-
if (!resolvedScriptPath) {
|
|
189
|
-
// `options.fromSource` is true
|
|
190
|
-
const sourceCode = scriptPath
|
|
191
|
-
super(new Function(sourceCode), [], { esm: true })
|
|
192
|
-
} else if (/\.tsx?$/i.test(resolvedScriptPath) && detectTsNode()) {
|
|
193
|
-
super(new Function(createTsNodeModule(resolveScriptPath(scriptPath))), [], { esm: true })
|
|
194
|
-
} else if (/\.asar[/\\]/.test(resolvedScriptPath)) {
|
|
195
|
-
// See <https://github.com/andywer/threads-plugin/issues/17>
|
|
196
|
-
super(resolvedScriptPath.replace(/\.asar([/\\])/, '.asar.unpacked$1'), [], { esm: true })
|
|
197
|
-
} else {
|
|
198
|
-
super(resolvedScriptPath, [], { esm: true })
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
allWorkers.push(this)
|
|
202
|
-
|
|
203
|
-
this.emitter = new EventEmitter()
|
|
204
|
-
this.onerror = (error: Error) => this.emitter.emit('error', error)
|
|
205
|
-
this.onmessage = (message: MessageEvent) => this.emitter.emit('message', message)
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
addEventListener(eventName: WorkerEventName, listener: EventListener) {
|
|
209
|
-
this.emitter.addListener(eventName, listener)
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
removeEventListener(eventName: WorkerEventName, listener: EventListener) {
|
|
213
|
-
this.emitter.removeListener(eventName, listener)
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
terminate() {
|
|
217
|
-
allWorkers = allWorkers.filter(worker => worker !== this)
|
|
218
|
-
return super.terminate()
|
|
219
|
-
}
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
const terminateWorkersAndMaster = () => {
|
|
223
|
-
// we should terminate all workers and then gracefully shutdown self process
|
|
224
|
-
Promise.all(allWorkers.map(worker => worker.terminate())).then(
|
|
225
|
-
() => process.exit(0),
|
|
226
|
-
() => process.exit(1),
|
|
227
|
-
)
|
|
228
|
-
allWorkers = []
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
// Take care to not leave orphaned processes behind
|
|
232
|
-
// See <https://github.com/avoidwork/tiny-worker#faq>
|
|
233
|
-
process.on('SIGINT', () => terminateWorkersAndMaster())
|
|
234
|
-
process.on('SIGTERM', () => terminateWorkersAndMaster())
|
|
235
|
-
|
|
236
|
-
class BlobWorker extends Worker {
|
|
237
|
-
constructor(blob: Uint8Array, options?: ThreadsWorkerOptions) {
|
|
238
|
-
super(Buffer.from(blob).toString('utf-8'), { ...options, fromSource: true })
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
static fromText(source: string, options?: ThreadsWorkerOptions): WorkerImplementation {
|
|
242
|
-
return new Worker(source, { ...options, fromSource: true }) as any
|
|
243
|
-
}
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
return {
|
|
247
|
-
blob: BlobWorker as any,
|
|
248
|
-
default: Worker as any,
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
|
-
|
|
252
157
|
let implementation: ImplementationExport
|
|
253
|
-
let isTinyWorker: boolean
|
|
254
158
|
|
|
255
159
|
function selectWorkerImplementation(): ImplementationExport {
|
|
256
160
|
try {
|
|
257
|
-
isTinyWorker = false
|
|
258
161
|
return initWorkerThreadsWorker()
|
|
259
162
|
} catch {
|
|
260
163
|
// tslint:disable-next-line no-console
|
|
261
|
-
|
|
262
|
-
isTinyWorker = true
|
|
263
|
-
return initTinyWorker()
|
|
164
|
+
throw new Error('Node worker_threads not available...')
|
|
264
165
|
}
|
|
265
166
|
}
|
|
266
167
|
|
|
@@ -272,14 +173,10 @@ export function getWorkerImplementation(): ImplementationExport {
|
|
|
272
173
|
}
|
|
273
174
|
|
|
274
175
|
export function isWorkerRuntime() {
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
? __non_webpack_require__('worker_threads').isMainThread
|
|
282
|
-
: eval('require')('worker_threads').isMainThread
|
|
283
|
-
return !isMainThread
|
|
284
|
-
}
|
|
176
|
+
// Webpack hack
|
|
177
|
+
const isMainThread
|
|
178
|
+
= typeof __non_webpack_require__ === 'function'
|
|
179
|
+
? __non_webpack_require__('worker_threads').isMainThread
|
|
180
|
+
: eval('require')('worker_threads').isMainThread
|
|
181
|
+
return !isMainThread
|
|
285
182
|
}
|
package/src/master/spawn.ts
CHANGED
|
@@ -138,7 +138,7 @@ function setPrivateThreadProps<T>(
|
|
|
138
138
|
* abstraction layer to provide the transparent API and verifies that
|
|
139
139
|
* the worker has initialized successfully.
|
|
140
140
|
*
|
|
141
|
-
* @param worker Instance of `Worker`. Either a web worker
|
|
141
|
+
* @param worker Instance of `Worker`. Either a web worker or `worker_threads` worker.
|
|
142
142
|
* @param [options]
|
|
143
143
|
* @param [options.timeout] Init message timeout. Default: 10000 or set by environment variable.
|
|
144
144
|
*/
|
package/src/types/master.ts
CHANGED
|
@@ -66,10 +66,10 @@ export type Thread = AnyFunctionThread | AnyModuleThread
|
|
|
66
66
|
|
|
67
67
|
export type TransferList = Transferable[]
|
|
68
68
|
|
|
69
|
-
/** Worker instance. Either a web worker or a node.js Worker provided by `worker_threads
|
|
69
|
+
/** Worker instance. Either a web worker or a node.js Worker provided by `worker_threads`. */
|
|
70
70
|
export interface Worker extends EventTarget {
|
|
71
71
|
postMessage(value: any, transferList?: TransferList): void
|
|
72
|
-
/** In nodejs 10+ return type is Promise while
|
|
72
|
+
/** In nodejs 10+ return type is Promise while in browser return type is void */
|
|
73
73
|
terminate(callback?: (error?: Error, exitCode?: number) => void): void | Promise<number>
|
|
74
74
|
}
|
|
75
75
|
export interface ThreadsWorkerOptions extends WorkerOptions {
|
|
@@ -34,8 +34,6 @@ const messageHandlers = new Set<(data: any) => void>()
|
|
|
34
34
|
|
|
35
35
|
const subscribeToMasterMessages: AbstractedWorkerAPI['subscribeToMasterMessages'] = function subscribeToMasterMessages(onMessage) {
|
|
36
36
|
if (!muxingHandlerSetUp) {
|
|
37
|
-
// We have one multiplexing message handler as tiny-worker's
|
|
38
|
-
// addEventListener() only allows you to set a single message handler
|
|
39
37
|
self.addEventListener('message', ((event: MessageEvent) => {
|
|
40
38
|
for (const handler of messageHandlers) handler(event.data)
|
|
41
39
|
}) as EventListener)
|
|
@@ -6,7 +6,6 @@
|
|
|
6
6
|
|
|
7
7
|
import type { AbstractedWorkerAPI } from '../types/worker'
|
|
8
8
|
import WebWorkerImplementation from './implementation.browser'
|
|
9
|
-
import TinyWorkerImplementation from './implementation.tiny-worker'
|
|
10
9
|
import WorkerThreadsImplementation from './implementation.worker_threads'
|
|
11
10
|
|
|
12
11
|
const runningInNode = typeof process !== 'undefined' && (process.arch as string) !== 'browser' && 'pid' in process
|
|
@@ -16,7 +15,7 @@ function selectNodeImplementation(): AbstractedWorkerAPI {
|
|
|
16
15
|
WorkerThreadsImplementation.testImplementation()
|
|
17
16
|
return WorkerThreadsImplementation
|
|
18
17
|
} catch {
|
|
19
|
-
|
|
18
|
+
throw new Error('No worker implementation available in this environment')
|
|
20
19
|
}
|
|
21
20
|
}
|
|
22
21
|
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
import path from 'node:path'
|
|
2
|
-
|
|
3
|
-
import test from 'ava'
|
|
4
|
-
import execa from 'execa'
|
|
5
|
-
import { rollup } from 'rollup'
|
|
6
|
-
|
|
7
|
-
import config from './rollup.config'
|
|
8
|
-
|
|
9
|
-
test('can be bundled using rollup', async (t) => {
|
|
10
|
-
t.timeout(2_000_000) // milliseconds
|
|
11
|
-
|
|
12
|
-
const appBundleP = rollup({
|
|
13
|
-
input: path.resolve(__dirname, 'app.js'),
|
|
14
|
-
...config,
|
|
15
|
-
})
|
|
16
|
-
|
|
17
|
-
const workerBundleP = rollup({
|
|
18
|
-
input: path.resolve(__dirname, 'worker.js'),
|
|
19
|
-
...config,
|
|
20
|
-
})
|
|
21
|
-
|
|
22
|
-
const appBundleWriteP = (await appBundleP).write({
|
|
23
|
-
dir: path.resolve(__dirname, 'dist'),
|
|
24
|
-
format: 'iife',
|
|
25
|
-
})
|
|
26
|
-
|
|
27
|
-
const workerBundleWriteP = (await workerBundleP).write({
|
|
28
|
-
dir: path.resolve(__dirname, 'dist'),
|
|
29
|
-
format: 'iife',
|
|
30
|
-
})
|
|
31
|
-
|
|
32
|
-
await Promise.all([appBundleWriteP, workerBundleWriteP])
|
|
33
|
-
|
|
34
|
-
if (process.platform === 'win32') {
|
|
35
|
-
// Quick-fix for weird Windows issue in CI
|
|
36
|
-
return t.pass()
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
const result = await execa.command('puppet-run --serve ./dist/worker.js:/worker.js ./dist/app.js', {
|
|
40
|
-
cwd: __dirname,
|
|
41
|
-
stderr: process.stderr,
|
|
42
|
-
})
|
|
43
|
-
t.is(result.exitCode, 0)
|
|
44
|
-
})
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
import test from 'ava'
|
|
2
|
-
import execa from 'execa'
|
|
3
|
-
|
|
4
|
-
test('can compile with a minimal TypeScript config', async (t) => {
|
|
5
|
-
const result = await execa('tsc', ['--project', require.resolve('./minimal-tsconfig.json')])
|
|
6
|
-
t.is(result.exitCode, 0, `tsc exited with non-zero exit code.\nStderr:\n${result.stderr}`)
|
|
7
|
-
})
|
package/types/tiny-worker.d.ts
DELETED