@xylabs/threads 4.3.1 → 4.3.3

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 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 and `worker_threads` in node 12+
14
+ Uses web workers in the browser, `worker_threads` in node 12+ and [`tiny-worker`](https://github.com/avoidwork/tiny-worker) in node 8 to 11.
15
15
 
16
16
  ### Features
17
17
 
@@ -28,9 +28,11 @@ 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 tiny-worker
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
+
34
36
  ## Platform support
35
37
 
36
38
  <details>
@@ -71,6 +73,22 @@ Then add it to your `webpack.config.js`:
71
73
  }
72
74
  ```
73
75
 
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
+
74
92
  #### When using TypeScript
75
93
 
76
94
  Note: You'll need to be using Typescript version 4+, as the types generated by threads.js are not supported in Typescript 3.
@@ -6,6 +6,7 @@ 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");
9
10
  const node_os_1 = require("node:os");
10
11
  const node_path_1 = __importDefault(require("node:path"));
11
12
  const node_url_1 = require("node:url");
@@ -113,13 +114,76 @@ function initWorkerThreadsWorker() {
113
114
  default: Worker,
114
115
  };
115
116
  }
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
+ }
116
176
  let implementation;
177
+ let isTinyWorker;
117
178
  function selectWorkerImplementation() {
118
179
  try {
180
+ isTinyWorker = false;
119
181
  return initWorkerThreadsWorker();
120
182
  }
121
183
  catch {
122
- throw new Error('Node worker_threads not available...');
184
+ console.debug('Node worker_threads not available. Trying to fall back to tiny-worker polyfill...');
185
+ isTinyWorker = true;
186
+ return initTinyWorker();
123
187
  }
124
188
  }
125
189
  function getWorkerImplementation() {
@@ -129,8 +193,13 @@ function getWorkerImplementation() {
129
193
  return implementation;
130
194
  }
131
195
  function isWorkerRuntime() {
132
- const isMainThread = typeof __non_webpack_require__ === 'function'
133
- ? __non_webpack_require__('worker_threads').isMainThread
134
- : eval('require')('worker_threads').isMainThread;
135
- return !isMainThread;
196
+ if (isTinyWorker) {
197
+ return self !== undefined && self['postMessage'] ? true : false;
198
+ }
199
+ else {
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
+ }
136
205
  }
@@ -4,6 +4,7 @@ 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"));
7
8
  const implementation_worker_threads_1 = __importDefault(require("./implementation.worker_threads"));
8
9
  const runningInNode = typeof process !== 'undefined' && process.arch !== 'browser' && 'pid' in process;
9
10
  function selectNodeImplementation() {
@@ -12,7 +13,7 @@ function selectNodeImplementation() {
12
13
  return implementation_worker_threads_1.default;
13
14
  }
14
15
  catch {
15
- throw new Error('No worker implementation available in this environment');
16
+ return implementation_tiny_worker_1.default;
16
17
  }
17
18
  }
18
19
  exports.default = runningInNode ? selectNodeImplementation() : implementation_browser_1.default;
@@ -6,6 +6,7 @@ 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");
9
10
  const node_os_1 = require("node:os");
10
11
  const node_path_1 = __importDefault(require("node:path"));
11
12
  const node_url_1 = require("node:url");
@@ -113,13 +114,76 @@ function initWorkerThreadsWorker() {
113
114
  default: Worker,
114
115
  };
115
116
  }
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
+ }
116
176
  let implementation;
177
+ let isTinyWorker;
117
178
  function selectWorkerImplementation() {
118
179
  try {
180
+ isTinyWorker = false;
119
181
  return initWorkerThreadsWorker();
120
182
  }
121
183
  catch {
122
- throw new Error('Node worker_threads not available...');
184
+ console.debug('Node worker_threads not available. Trying to fall back to tiny-worker polyfill...');
185
+ isTinyWorker = true;
186
+ return initTinyWorker();
123
187
  }
124
188
  }
125
189
  function getWorkerImplementation() {
@@ -129,8 +193,13 @@ function getWorkerImplementation() {
129
193
  return implementation;
130
194
  }
131
195
  function isWorkerRuntime() {
132
- const isMainThread = typeof __non_webpack_require__ === 'function'
133
- ? __non_webpack_require__('worker_threads').isMainThread
134
- : eval('require')('worker_threads').isMainThread;
135
- return !isMainThread;
196
+ if (isTinyWorker) {
197
+ return self !== undefined && self['postMessage'] ? true : false;
198
+ }
199
+ else {
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
+ }
136
205
  }
@@ -4,6 +4,7 @@ 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"));
7
8
  const implementation_worker_threads_1 = __importDefault(require("./implementation.worker_threads"));
8
9
  const runningInNode = typeof process !== 'undefined' && process.arch !== 'browser' && 'pid' in process;
9
10
  function selectNodeImplementation() {
@@ -12,7 +13,7 @@ function selectNodeImplementation() {
12
13
  return implementation_worker_threads_1.default;
13
14
  }
14
15
  catch {
15
- throw new Error('No worker implementation available in this environment');
16
+ return implementation_tiny_worker_1.default;
16
17
  }
17
18
  }
18
19
  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.1",
3
+ "version": "4.3.3",
4
4
  "description": "Web workers & worker threads as simple as a function call",
5
5
  "license": "MIT",
6
6
  "main": "dist/index.js",
@@ -95,11 +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/node": "^22.7.7",
98
+ "@types/execa": "^2.0.2",
99
+ "@types/node": "^22.8.0",
99
100
  "@types/webpack": "^5.28.5",
100
101
  "@xylabs/ts-scripts-yarn3": "^4.2.3",
101
102
  "ava": "^6.1.3",
102
- "chai": "^5.1.1",
103
+ "chai": "^5.1.2",
103
104
  "cross-env": "^7.0.3",
104
105
  "mocha": "^10.7.3",
105
106
  "puppet-run": "^0.11.4",
@@ -108,6 +109,7 @@
108
109
  "rimraf": "^5.0.10",
109
110
  "rollup": "^4.24.0",
110
111
  "threads-plugin": "^1.4.0",
112
+ "tiny-worker": "^2.3.0",
111
113
  "ts-loader": "^9.5.1",
112
114
  "ts-node": "^10.9.2",
113
115
  "typescript": "^5.6.3",
@@ -116,6 +118,9 @@
116
118
  "webpack": "^5.95.0",
117
119
  "worker-plugin": "^5.0.1"
118
120
  },
121
+ "optionalDependencies": {
122
+ "tiny-worker": "^2.3.0"
123
+ },
119
124
  "ava": {
120
125
  "extensions": [
121
126
  "ts"
@@ -133,12 +138,15 @@
133
138
  "./dist/esm/master/implementation.js": "./dist/esm/master/implementation.browser.js",
134
139
  "./dist/esm/master/implementation.node.js": false,
135
140
  "./dist/esm/worker/implementation.js": "./dist/esm/worker/implementation.browser.js",
141
+ "./dist/esm/worker/implementation.tiny-worker.js": false,
136
142
  "./dist/esm/worker/implementation.worker_threads.js": false,
137
143
  "./dist/master/implementation.js": "./dist/master/implementation.browser.js",
138
144
  "./dist/master/implementation.node.js": false,
139
145
  "./dist/worker/implementation.js": "./dist/worker/implementation.browser.js",
146
+ "./dist/worker/implementation.tiny-worker.js": false,
140
147
  "./dist/worker/implementation.worker_threads.js": false,
141
148
  "callsites": false,
149
+ "tiny-worker": false,
142
150
  "ts-node": false,
143
151
  "ts-node/register": false,
144
152
  "worker_threads": false
@@ -1,12 +1,16 @@
1
+ /* eslint-disable @typescript-eslint/no-require-imports */
1
2
  /* eslint-disable import-x/no-internal-modules */
2
3
  /* eslint-disable unicorn/no-process-exit */
3
4
  /* eslint-disable unicorn/prefer-logical-operator-over-ternary */
4
5
  /* eslint-disable unicorn/prefer-regexp-test */
5
6
 
7
+ /* eslint-disable unicorn/prefer-add-event-listener */
8
+ /* eslint-disable unicorn/prefer-event-target */
6
9
  /* eslint-disable @typescript-eslint/no-explicit-any */
7
10
  /* eslint-disable unicorn/text-encoding-identifier-case */
8
11
  /// <reference lib="dom" />
9
12
 
13
+ import { EventEmitter } from 'node:events'
10
14
  import { cpus } from 'node:os'
11
15
  import path from 'node:path'
12
16
  import { fileURLToPath } from 'node:url'
@@ -25,9 +29,10 @@ interface WorkerGlobalScope {
25
29
  }
26
30
 
27
31
  declare const __non_webpack_require__: typeof require
28
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
29
32
  declare const self: WorkerGlobalScope
30
33
 
34
+ type WorkerEventName = 'error' | 'message'
35
+
31
36
  let tsNodeAvailable: boolean | undefined
32
37
 
33
38
  export const defaultPoolSize = cpus().length
@@ -162,14 +167,100 @@ function initWorkerThreadsWorker(): ImplementationExport {
162
167
  }
163
168
  }
164
169
 
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
+
165
252
  let implementation: ImplementationExport
253
+ let isTinyWorker: boolean
166
254
 
167
255
  function selectWorkerImplementation(): ImplementationExport {
168
256
  try {
257
+ isTinyWorker = false
169
258
  return initWorkerThreadsWorker()
170
259
  } catch {
171
260
  // tslint:disable-next-line no-console
172
- throw new Error('Node worker_threads not available...')
261
+ console.debug('Node worker_threads not available. Trying to fall back to tiny-worker polyfill...')
262
+ isTinyWorker = true
263
+ return initTinyWorker()
173
264
  }
174
265
  }
175
266
 
@@ -181,10 +272,14 @@ export function getWorkerImplementation(): ImplementationExport {
181
272
  }
182
273
 
183
274
  export function isWorkerRuntime() {
184
- // Webpack hack
185
- const isMainThread
186
- = typeof __non_webpack_require__ === 'function'
187
- ? __non_webpack_require__('worker_threads').isMainThread
188
- : eval('require')('worker_threads').isMainThread
189
- return !isMainThread
275
+ if (isTinyWorker) {
276
+ return self !== undefined && self['postMessage'] ? true : false
277
+ } else {
278
+ // Webpack hack
279
+ const isMainThread
280
+ = typeof __non_webpack_require__ === 'function'
281
+ ? __non_webpack_require__('worker_threads').isMainThread
282
+ : eval('require')('worker_threads').isMainThread
283
+ return !isMainThread
284
+ }
190
285
  }
@@ -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 or `worker_threads` worker.
141
+ * @param worker Instance of `Worker`. Either a web worker, `worker_threads` worker or `tiny-worker` worker.
142
142
  * @param [options]
143
143
  * @param [options.timeout] Init message timeout. Default: 10000 or set by environment variable.
144
144
  */
@@ -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` or `tiny-worker`. */
70
70
  export interface Worker extends EventTarget {
71
71
  postMessage(value: any, transferList?: TransferList): void
72
- /** In nodejs 10+ return type is Promise while in browser return type is void */
72
+ /** In nodejs 10+ return type is Promise while with tiny-worker and 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,6 +34,8 @@ 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
37
39
  self.addEventListener('message', ((event: MessageEvent) => {
38
40
  for (const handler of messageHandlers) handler(event.data)
39
41
  }) as EventListener)
@@ -6,6 +6,7 @@
6
6
 
7
7
  import type { AbstractedWorkerAPI } from '../types/worker'
8
8
  import WebWorkerImplementation from './implementation.browser'
9
+ import TinyWorkerImplementation from './implementation.tiny-worker'
9
10
  import WorkerThreadsImplementation from './implementation.worker_threads'
10
11
 
11
12
  const runningInNode = typeof process !== 'undefined' && (process.arch as string) !== 'browser' && 'pid' in process
@@ -15,7 +16,7 @@ function selectNodeImplementation(): AbstractedWorkerAPI {
15
16
  WorkerThreadsImplementation.testImplementation()
16
17
  return WorkerThreadsImplementation
17
18
  } catch {
18
- throw new Error('No worker implementation available in this environment')
19
+ return TinyWorkerImplementation
19
20
  }
20
21
  }
21
22
 
@@ -6,6 +6,7 @@ module.exports = {
6
6
  context: __dirname,
7
7
  devtool: false,
8
8
  entry: require.resolve('./app.ts'),
9
+ externals: { 'tiny-worker': 'tiny-worker' },
9
10
  mode: 'development',
10
11
  module: {
11
12
  rules: [
@@ -0,0 +1,4 @@
1
+ declare module 'tiny-worker' {
2
+ const TinyWorker: typeof Worker
3
+ export = TinyWorker
4
+ }