@xylabs/threads 4.7.0 → 4.7.1

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.
Files changed (227) hide show
  1. package/dist/{types/common.d.ts → common.d.ts} +1 -5
  2. package/dist/common.js +16 -0
  3. package/dist/esm/common.js +16 -0
  4. package/dist/esm/index.js +26 -0
  5. package/dist/esm/master/get-bundle-url.browser.js +25 -0
  6. package/dist/esm/master/implementation.browser.js +65 -0
  7. package/dist/esm/master/implementation.js +43 -0
  8. package/dist/esm/master/implementation.node.js +205 -0
  9. package/dist/esm/master/index.js +14 -0
  10. package/dist/esm/master/invocation-proxy.js +121 -0
  11. package/dist/esm/master/pool-types.js +14 -0
  12. package/dist/esm/master/pool.js +262 -0
  13. package/dist/esm/master/register.js +11 -0
  14. package/dist/esm/master/spawn.js +114 -0
  15. package/dist/esm/master/thread.js +18 -0
  16. package/dist/esm/observable-promise.js +132 -0
  17. package/dist/esm/observable.js +33 -0
  18. package/dist/esm/ponyfills.js +20 -0
  19. package/dist/esm/promise.js +23 -0
  20. package/dist/esm/serializers.js +41 -0
  21. package/dist/esm/symbols.js +8 -0
  22. package/dist/esm/transferable.js +25 -0
  23. package/dist/esm/types/master.js +9 -0
  24. package/dist/esm/types/messages.js +16 -0
  25. package/dist/esm/types/worker.js +2 -0
  26. package/dist/esm/worker/bundle-entry.js +26 -0
  27. package/dist/esm/worker/implementation.browser.js +24 -0
  28. package/dist/esm/worker/implementation.js +19 -0
  29. package/dist/esm/worker/implementation.tiny-worker.js +37 -0
  30. package/dist/esm/worker/implementation.worker_threads.js +41 -0
  31. package/dist/esm/worker/index.js +174 -0
  32. package/dist/esm/worker_threads.js +13 -0
  33. package/dist/index.d.ts +7 -0
  34. package/dist/index.js +26 -0
  35. package/dist/{types/master → master}/get-bundle-url.browser.d.ts +0 -1
  36. package/dist/master/get-bundle-url.browser.js +25 -0
  37. package/dist/{types/master → master}/implementation.browser.d.ts +1 -2
  38. package/dist/master/implementation.browser.js +65 -0
  39. package/dist/{types/master → master}/implementation.d.ts +1 -4
  40. package/dist/master/implementation.js +43 -0
  41. package/dist/{types/master → master}/implementation.node.d.ts +1 -2
  42. package/dist/master/implementation.node.js +205 -0
  43. package/dist/master/index.d.ts +10 -0
  44. package/dist/master/index.js +14 -0
  45. package/dist/{types/master → master}/invocation-proxy.d.ts +1 -2
  46. package/dist/master/invocation-proxy.js +121 -0
  47. package/dist/{types/master → master}/pool-types.d.ts +1 -16
  48. package/dist/master/pool-types.js +14 -0
  49. package/dist/master/pool.d.ts +50 -0
  50. package/dist/master/pool.js +262 -0
  51. package/dist/master/register.d.ts +1 -0
  52. package/dist/master/register.js +11 -0
  53. package/dist/{types/master → master}/spawn.d.ts +2 -12
  54. package/dist/master/spawn.js +114 -0
  55. package/dist/master/thread.d.ts +8 -0
  56. package/dist/master/thread.js +18 -0
  57. package/dist/{types/observable-promise.d.ts → observable-promise.d.ts} +0 -14
  58. package/dist/observable-promise.js +132 -0
  59. package/dist/observable.d.ts +11 -0
  60. package/dist/observable.js +33 -0
  61. package/dist/{types/ponyfills.d.ts → ponyfills.d.ts} +0 -1
  62. package/dist/ponyfills.js +20 -0
  63. package/dist/promise.d.ts +1 -0
  64. package/dist/promise.js +23 -0
  65. package/dist/{types/serializers.d.ts → serializers.d.ts} +0 -1
  66. package/dist/serializers.js +41 -0
  67. package/dist/{types/symbols.d.ts → symbols.d.ts} +0 -1
  68. package/dist/symbols.js +8 -0
  69. package/dist/transferable.d.ts +9 -0
  70. package/dist/transferable.js +25 -0
  71. package/dist/types/{types/master.d.ts → master.d.ts} +3 -17
  72. package/dist/types/master.js +9 -0
  73. package/dist/types/{types/messages.d.ts → messages.d.ts} +0 -1
  74. package/dist/types/messages.js +16 -0
  75. package/dist/types/{types/worker.d.ts → worker.d.ts} +0 -1
  76. package/dist/types/worker.js +2 -0
  77. package/dist/worker/bundle-entry.d.ts +1 -0
  78. package/dist/worker/bundle-entry.js +26 -0
  79. package/dist/worker/implementation.browser.d.ts +6 -0
  80. package/dist/worker/implementation.browser.js +24 -0
  81. package/dist/worker/implementation.d.ts +3 -0
  82. package/dist/worker/implementation.js +19 -0
  83. package/dist/worker/implementation.tiny-worker.d.ts +6 -0
  84. package/dist/worker/implementation.tiny-worker.js +37 -0
  85. package/dist/worker/implementation.worker_threads.d.ts +8 -0
  86. package/dist/worker/implementation.worker_threads.js +41 -0
  87. package/dist/worker/index.d.ts +5 -0
  88. package/dist/worker/index.js +174 -0
  89. package/dist/worker_threads.d.ts +8 -0
  90. package/dist/worker_threads.js +13 -0
  91. package/observable.d.ts +2 -0
  92. package/observable.js +2 -0
  93. package/observable.mjs +4 -0
  94. package/package.json +77 -66
  95. package/register.d.ts +2 -0
  96. package/register.js +2 -0
  97. package/register.mjs +1 -0
  98. package/rollup.config.js +16 -0
  99. package/src/common.ts +6 -10
  100. package/src/index.ts +9 -10
  101. package/src/master/get-bundle-url.browser.ts +1 -2
  102. package/src/master/implementation.browser.ts +2 -2
  103. package/src/master/implementation.node.ts +96 -19
  104. package/src/master/implementation.ts +2 -2
  105. package/src/master/index.ts +7 -7
  106. package/src/master/invocation-proxy.ts +6 -6
  107. package/src/master/pool-types.ts +1 -1
  108. package/src/master/pool.ts +13 -14
  109. package/src/master/register.ts +1 -2
  110. package/src/master/spawn.ts +8 -8
  111. package/src/master/thread.ts +2 -2
  112. package/src/observable-promise.ts +2 -3
  113. package/src/serializers.ts +1 -1
  114. package/src/transferable.ts +1 -2
  115. package/src/types/master.ts +3 -3
  116. package/src/worker/bundle-entry.ts +10 -0
  117. package/src/worker/{worker.browser.ts → implementation.browser.ts} +10 -26
  118. package/src/worker/implementation.tiny-worker.ts +55 -0
  119. package/src/worker/implementation.ts +23 -0
  120. package/src/worker/{worker.node.ts → implementation.worker_threads.ts} +12 -30
  121. package/src/worker/index.ts +230 -0
  122. package/src/worker_threads.ts +27 -0
  123. package/test/lib/index.ts +1 -0
  124. package/test/lib/serialization.ts +38 -0
  125. package/test/observable-promise.test.ts +205 -0
  126. package/test/observable.test.ts +87 -0
  127. package/test/pool.test.ts +183 -0
  128. package/test/serialization.test.ts +23 -0
  129. package/test/spawn.chromium.mocha.ts +53 -0
  130. package/test/spawn.test.ts +87 -0
  131. package/test/streaming.test.ts +29 -0
  132. package/test/transferables.test.ts +71 -0
  133. package/test/workers/arraybuffer-xor.ts +10 -0
  134. package/test/workers/count-to-five.ts +12 -0
  135. package/test/workers/counter.ts +19 -0
  136. package/test/workers/faulty-function.ts +5 -0
  137. package/test/workers/hello-world.ts +5 -0
  138. package/test/workers/increment.ts +8 -0
  139. package/test/workers/minmax.ts +25 -0
  140. package/test/workers/serialization.ts +13 -0
  141. package/test/workers/top-level-throw.ts +1 -0
  142. package/test-tooling/rollup/app.js +21 -0
  143. package/test-tooling/rollup/rollup.config.ts +14 -0
  144. package/test-tooling/rollup/worker.js +7 -0
  145. package/test-tooling/tsconfig/minimal.ts +12 -0
  146. package/test-tooling/webpack/addition-worker.ts +9 -0
  147. package/test-tooling/webpack/app-with-inlined-worker.ts +28 -0
  148. package/test-tooling/webpack/app.ts +61 -0
  149. package/test-tooling/webpack/pool-worker.ts +5 -0
  150. package/test-tooling/webpack/raw-loader.d.ts +4 -0
  151. package/test-tooling/webpack/webpack.chromium.mocha.ts +21 -0
  152. package/test-tooling/webpack/webpack.node.config.js +29 -0
  153. package/test-tooling/webpack/webpack.web.config.js +28 -0
  154. package/types/is-observable.d.ts +1 -1
  155. package/types/webworker.d.ts +9 -0
  156. package/worker.d.ts +2 -0
  157. package/worker.js +2 -0
  158. package/worker.mjs +6 -0
  159. package/dist/browser/master/implementation.browser.mjs +0 -89
  160. package/dist/browser/master/implementation.browser.mjs.map +0 -1
  161. package/dist/browser/worker/worker.browser.mjs +0 -291
  162. package/dist/browser/worker/worker.browser.mjs.map +0 -1
  163. package/dist/neutral/index.mjs +0 -1022
  164. package/dist/neutral/index.mjs.map +0 -1
  165. package/dist/neutral/master/implementation.mjs +0 -264
  166. package/dist/neutral/master/implementation.mjs.map +0 -1
  167. package/dist/neutral/master/index.mjs +0 -988
  168. package/dist/neutral/master/index.mjs.map +0 -1
  169. package/dist/neutral/master/pool.mjs +0 -579
  170. package/dist/neutral/master/pool.mjs.map +0 -1
  171. package/dist/neutral/master/register.mjs +0 -272
  172. package/dist/neutral/master/register.mjs.map +0 -1
  173. package/dist/neutral/master/spawn.mjs +0 -412
  174. package/dist/neutral/master/spawn.mjs.map +0 -1
  175. package/dist/neutral/master/thread.mjs +0 -29
  176. package/dist/neutral/master/thread.mjs.map +0 -1
  177. package/dist/neutral/observable-promise.mjs +0 -132
  178. package/dist/neutral/observable-promise.mjs.map +0 -1
  179. package/dist/neutral/observable.mjs +0 -31
  180. package/dist/neutral/observable.mjs.map +0 -1
  181. package/dist/node/master/implementation.node.mjs +0 -154
  182. package/dist/node/master/implementation.node.mjs.map +0 -1
  183. package/dist/node/worker/worker.node.mjs +0 -304
  184. package/dist/node/worker/worker.node.mjs.map +0 -1
  185. package/dist/types/common.d.ts.map +0 -1
  186. package/dist/types/index.d.ts +0 -9
  187. package/dist/types/index.d.ts.map +0 -1
  188. package/dist/types/master/get-bundle-url.browser.d.ts.map +0 -1
  189. package/dist/types/master/implementation.browser.d.ts.map +0 -1
  190. package/dist/types/master/implementation.d.ts.map +0 -1
  191. package/dist/types/master/implementation.node.d.ts.map +0 -1
  192. package/dist/types/master/index.d.ts +0 -13
  193. package/dist/types/master/index.d.ts.map +0 -1
  194. package/dist/types/master/invocation-proxy.d.ts.map +0 -1
  195. package/dist/types/master/pool-types.d.ts.map +0 -1
  196. package/dist/types/master/pool.d.ts +0 -93
  197. package/dist/types/master/pool.d.ts.map +0 -1
  198. package/dist/types/master/register.d.ts +0 -2
  199. package/dist/types/master/register.d.ts.map +0 -1
  200. package/dist/types/master/spawn.d.ts.map +0 -1
  201. package/dist/types/master/thread.d.ts +0 -13
  202. package/dist/types/master/thread.d.ts.map +0 -1
  203. package/dist/types/observable-promise.d.ts.map +0 -1
  204. package/dist/types/observable.d.ts +0 -21
  205. package/dist/types/observable.d.ts.map +0 -1
  206. package/dist/types/ponyfills.d.ts.map +0 -1
  207. package/dist/types/promise.d.ts +0 -6
  208. package/dist/types/promise.d.ts.map +0 -1
  209. package/dist/types/serializers.d.ts.map +0 -1
  210. package/dist/types/symbols.d.ts.map +0 -1
  211. package/dist/types/transferable.d.ts +0 -43
  212. package/dist/types/transferable.d.ts.map +0 -1
  213. package/dist/types/types/master.d.ts.map +0 -1
  214. package/dist/types/types/messages.d.ts.map +0 -1
  215. package/dist/types/types/worker.d.ts.map +0 -1
  216. package/dist/types/worker/WorkerGlobalScope.d.ts +0 -6
  217. package/dist/types/worker/WorkerGlobalScope.d.ts.map +0 -1
  218. package/dist/types/worker/expose.d.ts +0 -4
  219. package/dist/types/worker/expose.d.ts.map +0 -1
  220. package/dist/types/worker/worker.browser.d.ts +0 -14
  221. package/dist/types/worker/worker.browser.d.ts.map +0 -1
  222. package/dist/types/worker/worker.node.d.ts +0 -25
  223. package/dist/types/worker/worker.node.d.ts.map +0 -1
  224. package/src/worker/WorkerGlobalScope.ts +0 -5
  225. package/src/worker/expose.ts +0 -234
  226. package/src/worker/is-observable.d.ts +0 -7
  227. package/xy.config.ts +0 -24
@@ -0,0 +1,71 @@
1
+ /* eslint-disable import-x/no-internal-modules */
2
+ /* eslint-disable @typescript-eslint/no-unnecessary-type-constraint */
3
+ /* eslint-disable @typescript-eslint/no-explicit-any */
4
+
5
+ import { expect, test } from 'vitest'
6
+
7
+ import {
8
+ spawn, Thread, Transfer, Worker,
9
+ } from '../src/index'
10
+ import type { XorBuffer } from './workers/arraybuffer-xor.ts'
11
+
12
+ type SpyInit<Args extends any[], OriginalReturn, NewReturn> = (originalFn: (...args: Args) => OriginalReturn) => (...args: Args) => NewReturn
13
+
14
+ const arrayBufferPlaceholder = Symbol('ArrayBufferPlaceholder')
15
+
16
+ function spyOn<Args extends any[], OriginalReturn, NewReturn>(
17
+ target: (...args: Args) => OriginalReturn,
18
+ spy: SpyInit<Args, OriginalReturn, NewReturn>,
19
+ ): (...args: Args) => NewReturn {
20
+ return spy(target)
21
+ }
22
+
23
+ function replaceArrayBufferWithPlaceholder<In extends any>(
24
+ obj: In,
25
+ arrayBuffer: ArrayBufferLike,
26
+ ): In extends ArrayBufferLike ? In | typeof arrayBufferPlaceholder : In {
27
+ if ((obj as any) === arrayBuffer) {
28
+ return arrayBufferPlaceholder as any
29
+ } else if (Array.isArray(obj)) {
30
+ return (obj as any[]).map(element => replaceArrayBufferWithPlaceholder(element, arrayBuffer)) as any
31
+ } else if (obj && typeof obj === 'object') {
32
+ const result: In = Object.create(Object.getPrototypeOf(obj))
33
+
34
+ for (const key of Object.getOwnPropertyNames(obj)) {
35
+ (result as any)[key] = replaceArrayBufferWithPlaceholder((obj as any)[key], arrayBuffer)
36
+ }
37
+ return result as any
38
+ } else {
39
+ return obj as any
40
+ }
41
+ }
42
+
43
+ test('can pass transferable objects on thread call', async () => {
44
+ const testData = new ArrayBuffer(64)
45
+
46
+ const worker = new Worker('./workers/arraybuffer-xor.ts')
47
+ const postMessageCalls: Array<any[]> = []
48
+
49
+ worker.postMessage = spyOn(worker.postMessage.bind(worker), postMessage => (...args) => {
50
+ postMessageCalls.push(replaceArrayBufferWithPlaceholder(args, testData))
51
+ return postMessage(...args)
52
+ })
53
+
54
+ const xorBuffer = await spawn<XorBuffer>(worker)
55
+ const returnedBuffer = await xorBuffer(Transfer(testData), 15)
56
+
57
+ expect(returnedBuffer.byteLength).toBe(64)
58
+ expect(postMessageCalls.length).toBe(1)
59
+ expect(postMessageCalls[0].length).toBe(2)
60
+ expect(postMessageCalls[0][0]).toEqual({
61
+ args: [arrayBufferPlaceholder, 15],
62
+ method: undefined,
63
+ type: 'run',
64
+ uid: postMessageCalls[0][0].uid,
65
+ })
66
+ expect(postMessageCalls[0][1]).toEqual([arrayBufferPlaceholder])
67
+
68
+ await Thread.terminate(xorBuffer)
69
+ })
70
+
71
+ test.todo('can pass transferable objects as observable values')
@@ -0,0 +1,10 @@
1
+ import { expose, Transfer } from '../../src/worker'
2
+
3
+ function xor(buffer: ArrayBufferLike, value: number) {
4
+ const view = new Uint8Array(buffer)
5
+ for (const [offset, byte] of view.entries()) view.set([byte ^ value], offset)
6
+ return Transfer(buffer)
7
+ }
8
+
9
+ expose(xor)
10
+ export type XorBuffer = typeof xor
@@ -0,0 +1,12 @@
1
+ import { Observable } from 'observable-fns'
2
+
3
+ import { expose } from '../../src/worker'
4
+
5
+ expose(function countToFive() {
6
+ return new Observable((observer) => {
7
+ for (let counter = 1; counter <= 5; counter++) {
8
+ observer.next(counter)
9
+ }
10
+ observer.complete()
11
+ })
12
+ })
@@ -0,0 +1,19 @@
1
+ import { expose } from '../../src/worker'
2
+
3
+ let currentCount = 0
4
+
5
+ const counter = {
6
+ decrement() {
7
+ return --currentCount
8
+ },
9
+ getCount() {
10
+ return currentCount
11
+ },
12
+ increment() {
13
+ return ++currentCount
14
+ },
15
+ }
16
+
17
+ expose(counter)
18
+
19
+ export type Counter = typeof counter
@@ -0,0 +1,5 @@
1
+ import { expose } from '../../src/worker'
2
+
3
+ expose(function fail() {
4
+ throw new Error('I am supposed to fail.')
5
+ })
@@ -0,0 +1,5 @@
1
+ import { expose } from '../../src/worker'
2
+
3
+ expose(function helloWorld() {
4
+ return 'Hello World'
5
+ })
@@ -0,0 +1,8 @@
1
+ import { expose } from '../../src/worker'
2
+
3
+ let counter = 0
4
+
5
+ expose(function increment(by: number = 1) {
6
+ counter += by
7
+ return counter
8
+ })
@@ -0,0 +1,25 @@
1
+ // eslint-disable-next-line import-x/no-internal-modules
2
+ import { Observable, Subject } from '../../src/observable'
3
+ import { expose } from '../../src/worker'
4
+
5
+ let max = Number.NEGATIVE_INFINITY
6
+ let min = Number.POSITIVE_INFINITY
7
+
8
+ let subject = new Subject()
9
+
10
+ const minmax = {
11
+ finish() {
12
+ subject.complete()
13
+ subject = new Subject()
14
+ },
15
+ push(value) {
16
+ max = Math.max(max, value)
17
+ min = Math.min(min, value)
18
+ subject.next({ max, min })
19
+ },
20
+ values() {
21
+ return Observable.from(subject)
22
+ },
23
+ }
24
+
25
+ expose(minmax)
@@ -0,0 +1,13 @@
1
+ /* eslint-disable import-x/no-internal-modules */
2
+ /* eslint-disable require-await */
3
+
4
+ import { expose, registerSerializer } from '../../src/worker'
5
+ import { Foo, fooSerializer } from '../lib/serialization'
6
+
7
+ registerSerializer(fooSerializer)
8
+
9
+ async function run(foo: Foo<string>) {
10
+ return new Foo(foo.getValue() + foo.getValue())
11
+ }
12
+
13
+ expose(run)
@@ -0,0 +1 @@
1
+ throw new Error('Top-level worker error')
@@ -0,0 +1,21 @@
1
+ /* eslint-disable no-restricted-imports */
2
+ import {
3
+ spawn, Thread, Worker,
4
+ } from '../..'
5
+
6
+ async function run() {
7
+ const add = await spawn(new Worker('./worker.js'))
8
+ const result = await add(2, 3)
9
+ await Thread.terminate(add)
10
+ return result
11
+ }
12
+
13
+ run()
14
+ .then((result) => {
15
+ console.log(`Result: ${result}`)
16
+ puppet.exit(0)
17
+ })
18
+ .catch((error) => {
19
+ console.error(error)
20
+ puppet.exit(1)
21
+ })
@@ -0,0 +1,14 @@
1
+ import commonjs from '@rollup/plugin-commonjs'
2
+ import { nodeResolve } from '@rollup/plugin-node-resolve'
3
+
4
+ export default {
5
+ plugins: [
6
+ nodeResolve({
7
+ browser: true,
8
+ mainFields: ['module', 'main'],
9
+ preferBuiltins: true,
10
+ }),
11
+
12
+ commonjs(),
13
+ ],
14
+ }
@@ -0,0 +1,7 @@
1
+ /* eslint-disable require-await */
2
+
3
+ import { expose } from '../../dist/esm/worker'
4
+
5
+ expose(async function add(a, b) {
6
+ return a + b
7
+ })
@@ -0,0 +1,12 @@
1
+ /* eslint-disable no-restricted-imports */
2
+ /* eslint-disable @typescript-eslint/no-floating-promises */
3
+ import {
4
+ spawn, Thread, Worker,
5
+ } from '../..'
6
+
7
+ async function main() {
8
+ const helloWorld = await spawn(new Worker('./workers/hello-world.ts'))
9
+ await Thread.terminate(helloWorld)
10
+ }
11
+
12
+ main()
@@ -0,0 +1,9 @@
1
+ import { expose, isWorkerRuntime } from '../../src/worker'
2
+
3
+ if (!isWorkerRuntime()) {
4
+ throw new Error('isWorkerRuntime() says we are not in a worker.')
5
+ }
6
+
7
+ expose(function add(a: number, b: number) {
8
+ return a + b
9
+ })
@@ -0,0 +1,28 @@
1
+ /* eslint-disable import-x/no-unresolved */
2
+ /* eslint-disable @typescript-eslint/no-explicit-any */
3
+
4
+ /// <reference types="./raw-loader" />
5
+
6
+ import AdditionWorkerNodeBundle from 'raw-loader!./dist/addition-worker.node/worker.js'
7
+ import AdditionWorkerWebBundle from 'raw-loader!./dist/addition-worker.web/worker.js'
8
+
9
+ import { BlobWorker, spawn } from '../../src/index'
10
+
11
+ const AdditionWorkerBundle = (process as any).browser ? AdditionWorkerWebBundle : AdditionWorkerNodeBundle
12
+ type AdditionWorker = (a: number, b: number) => number
13
+
14
+ async function test() {
15
+ // We also want to test if referencing multiple different workers in a module
16
+ // built using webpack works
17
+
18
+ const add = await spawn<AdditionWorker>(BlobWorker.fromText(AdditionWorkerBundle))
19
+ const result = await add(2, 3)
20
+
21
+ if (result !== 5) {
22
+ throw new Error('Unexpected result returned by addition worker: ' + result)
23
+ }
24
+
25
+ return 'test succeeded'
26
+ }
27
+
28
+ export default test
@@ -0,0 +1,61 @@
1
+ /* eslint-disable @typescript-eslint/no-explicit-any */
2
+
3
+ import {
4
+ isWorkerRuntime, Pool, spawn, Worker,
5
+ } from '../../src/index'
6
+
7
+ type AdditionWorker = (a: number, b: number) => number
8
+ type HelloWorker = (text: string) => string
9
+
10
+ async function test() {
11
+ const pool = Pool(() => spawn<HelloWorker>(new Worker('./pool-worker')))
12
+ const results = await Promise.all([
13
+ pool.queue(hello => hello('World')),
14
+ pool.queue(hello => hello('World')),
15
+ pool.queue(hello => hello('World')),
16
+ pool.queue(hello => hello('World')),
17
+ ])
18
+ await pool.terminate()
19
+
20
+ for (const result of results) {
21
+ if (result !== 'Hello, World') {
22
+ throw new Error('Unexpected result returned by pool worker: ' + result)
23
+ }
24
+ }
25
+ }
26
+
27
+ async function test2() {
28
+ // We also want to test if referencing multiple different workers in a module
29
+ // built using webpack works
30
+
31
+ const add = await spawn<AdditionWorker>(new Worker('./addition-worker'))
32
+ const result = await add(2, 3)
33
+
34
+ if (result !== 5) {
35
+ throw new Error('Unexpected result returned by addition worker: ' + result)
36
+ }
37
+ }
38
+
39
+ async function test3() {
40
+ if (!(process as any).browser) {
41
+ // Running workers from remote URLs is disabled in node.js
42
+ return
43
+ }
44
+
45
+ const hello = await spawn<HelloWorker>(new Worker('https://infallible-turing-115958.netlify.com/hello-worker.js'))
46
+ const result = await hello('World')
47
+
48
+ if (result !== 'Hello, World') {
49
+ throw new Error('Unexpected result returned by hello worker: ' + result)
50
+ }
51
+ }
52
+
53
+ function test4() {
54
+ if (isWorkerRuntime() !== false) {
55
+ throw new Error('Expected isWorkerRuntime() to return false. Got: ' + isWorkerRuntime())
56
+ }
57
+ }
58
+
59
+ const testAll = () => Promise.all([test(), test2(), test3(), test4()])
60
+
61
+ export default testAll
@@ -0,0 +1,5 @@
1
+ import { expose } from '../../src/worker'
2
+
3
+ expose(function hello(text: string) {
4
+ return `Hello, ${text}`
5
+ })
@@ -0,0 +1,4 @@
1
+ declare module 'raw-loader!*' {
2
+ const content: string
3
+ export = content
4
+ }
@@ -0,0 +1,21 @@
1
+ /* eslint-disable @typescript-eslint/no-require-imports */
2
+ // NOTE:
3
+ // We are gonna test the bundles previously built by the AVA tests (see webpack.test.ts)
4
+
5
+ describe('threads webpack browser bundle', function () {
6
+ this.timeout(80_000)
7
+
8
+ it('works fine', async function () {
9
+ const bundle = require('./dist/app.web/main')
10
+ await bundle.test()
11
+ })
12
+ })
13
+
14
+ describe('threads webpack browser bundle with inlined worker', function () {
15
+ this.timeout(80_000)
16
+
17
+ it('works fine', async function () {
18
+ const bundle = require('./dist/app-inlined.web/main')
19
+ await bundle.test()
20
+ })
21
+ })
@@ -0,0 +1,29 @@
1
+ /* eslint-disable @typescript-eslint/no-require-imports */
2
+ const path = require('node:path')
3
+ const ThreadsPlugin = require('threads-plugin')
4
+
5
+ module.exports = {
6
+ context: __dirname,
7
+ devtool: false,
8
+ entry: require.resolve('./app.ts'),
9
+ externals: { 'tiny-worker': 'tiny-worker' },
10
+ mode: 'development',
11
+ module: {
12
+ rules: [
13
+ {
14
+ loader: 'ts-loader',
15
+ options: { compilerOptions: { module: 'esnext' } },
16
+ test: /\.ts$/,
17
+ },
18
+ ],
19
+ },
20
+ output: {
21
+ library: 'test',
22
+ libraryExport: 'default',
23
+ libraryTarget: 'commonjs',
24
+ path: path.resolve(__dirname, './dist/app.node'),
25
+ },
26
+ plugins: [new ThreadsPlugin()],
27
+ resolve: { extensions: ['.js', '.ts'] },
28
+ target: 'node',
29
+ }
@@ -0,0 +1,28 @@
1
+ /* eslint-disable @typescript-eslint/no-require-imports */
2
+ const path = require('node:path')
3
+ const ThreadsPlugin = require('threads-plugin')
4
+
5
+ module.exports = {
6
+ context: __dirname,
7
+ devtool: false,
8
+ entry: require.resolve('./app.ts'),
9
+ mode: 'development',
10
+ module: {
11
+ rules: [
12
+ {
13
+ loader: 'ts-loader',
14
+ options: { compilerOptions: { module: 'esnext' } },
15
+ test: /\.ts$/,
16
+ },
17
+ ],
18
+ },
19
+ output: {
20
+ library: 'test',
21
+ libraryExport: 'default',
22
+ libraryTarget: 'commonjs',
23
+ path: path.resolve(__dirname, './dist/app.web'),
24
+ },
25
+ plugins: [new ThreadsPlugin()],
26
+ resolve: { extensions: ['.js', '.ts'] },
27
+ target: 'web',
28
+ }
@@ -4,4 +4,4 @@ declare module 'is-observable-2-1-0' {
4
4
 
5
5
  function isObservable(thing: any): thing is Observable<any>
6
6
  export = isObservable
7
- }
7
+ }
@@ -0,0 +1,9 @@
1
+ /* eslint-disable @typescript-eslint/no-explicit-any */
2
+ /// <reference no-default-lib="true"/>
3
+ /// <reference lib="webworker" />
4
+
5
+ interface WorkerGlobalScope {
6
+ addEventListener(eventName: string, listener: (event: Event) => void): void
7
+ postMessage(message: any, transferables?: any[]): void
8
+ removeEventListener(eventName: string, listener: (event: Event) => void): void
9
+ }
package/worker.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ /* eslint-disable import-x/no-internal-modules */
2
+ export * from './dist/worker/index'
package/worker.js ADDED
@@ -0,0 +1,2 @@
1
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
2
+ module.exports = require('./dist/worker/index')
package/worker.mjs ADDED
@@ -0,0 +1,6 @@
1
+ import * as WorkerContext from './dist/worker/index.js'
2
+
3
+ export const expose = WorkerContext.expose
4
+ export const registerSerializer = WorkerContext.registerSerializer
5
+ export const Transfer = WorkerContext.Transfer
6
+ export const isWorkerRuntime = WorkerContext.isWorkerRuntime
@@ -1,89 +0,0 @@
1
- // src/master/get-bundle-url.browser.ts
2
- var bundleURL;
3
- function getBundleURLCached() {
4
- if (!bundleURL) {
5
- bundleURL = getBundleURL();
6
- }
7
- return bundleURL;
8
- }
9
- function getBundleURL() {
10
- try {
11
- throw new Error("getBundleURL failed");
12
- } catch (ex) {
13
- const err = ex;
14
- const matches = ("" + err.stack).match(/(https?|file|ftp|chrome-extension|moz-extension):\/\/[^\n)]+/g);
15
- if (matches) {
16
- return getBaseURL(matches[0]);
17
- }
18
- }
19
- return "/";
20
- }
21
- function getBaseURL(url) {
22
- return ("" + url).replace(/^((?:https?|file|ftp|chrome-extension|moz-extension):\/\/.+)?\/[^/]+(?:\?.*)?$/, "$1") + "/";
23
- }
24
-
25
- // src/master/implementation.browser.ts
26
- var defaultPoolSize = typeof navigator !== "undefined" && navigator.hardwareConcurrency ? navigator.hardwareConcurrency : 4;
27
- var isAbsoluteURL = (value) => /^[A-Za-z][\d+.A-Za-z\-]*:/.test(value);
28
- function createSourceBlobURL(code) {
29
- const blob = new Blob([code], { type: "application/javascript" });
30
- return URL.createObjectURL(blob);
31
- }
32
- function selectWorkerImplementation() {
33
- if (typeof Worker === "undefined") {
34
- return class NoWebWorker {
35
- constructor() {
36
- throw new Error(
37
- "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."
38
- );
39
- }
40
- };
41
- }
42
- class WebWorker extends Worker {
43
- constructor(url, options) {
44
- if (typeof url === "string" && options && options._baseURL) {
45
- url = new URL(url, options._baseURL);
46
- } else if (typeof url === "string" && !isAbsoluteURL(url) && /^file:\/\//i.test(getBundleURLCached())) {
47
- url = new URL(url, getBundleURLCached().replace(/\/[^/]+$/, "/"));
48
- if (options?.CORSWorkaround ?? true) {
49
- url = createSourceBlobURL(`importScripts(${JSON.stringify(url)});`);
50
- }
51
- }
52
- if (typeof url === "string" && isAbsoluteURL(url) && (options?.CORSWorkaround ?? true)) {
53
- url = createSourceBlobURL(`importScripts(${JSON.stringify(url)});`);
54
- }
55
- super(url, options);
56
- }
57
- }
58
- class BlobWorker extends WebWorker {
59
- constructor(blob, options) {
60
- const url = globalThis.URL.createObjectURL(blob);
61
- super(url, options);
62
- }
63
- static fromText(source, options) {
64
- const blob = new globalThis.Blob([source], { type: "text/javascript" });
65
- return new BlobWorker(blob, options);
66
- }
67
- }
68
- return {
69
- blob: BlobWorker,
70
- default: WebWorker
71
- };
72
- }
73
- var implementation;
74
- function getWorkerImplementation() {
75
- if (!implementation) {
76
- implementation = selectWorkerImplementation();
77
- }
78
- return implementation;
79
- }
80
- function isWorkerRuntime() {
81
- const isWindowContext = typeof globalThis !== "undefined" && typeof Window !== "undefined" && globalThis instanceof Window;
82
- return typeof globalThis !== "undefined" && self["postMessage"] && !isWindowContext ? true : false;
83
- }
84
- export {
85
- defaultPoolSize,
86
- getWorkerImplementation,
87
- isWorkerRuntime
88
- };
89
- //# sourceMappingURL=implementation.browser.mjs.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../../src/master/get-bundle-url.browser.ts","../../../src/master/implementation.browser.ts"],"sourcesContent":["// Source: <https://github.com/parcel-bundler/parcel/blob/master/packages/core/parcel-bundler/src/builtins/bundle-url.js>\n\nlet bundleURL: string | undefined\n\nfunction getBundleURLCached(): string {\n if (!bundleURL) {\n bundleURL = getBundleURL()\n }\n\n return bundleURL\n}\n\nfunction getBundleURL(): string {\n // Attempt to find the URL of the current script and use that as the base URL\n try {\n throw new Error('getBundleURL failed')\n } catch (ex) {\n const err = ex as Error\n const matches = ('' + err.stack).match(/(https?|file|ftp|chrome-extension|moz-extension):\\/\\/[^\\n)]+/g)\n if (matches) {\n return getBaseURL(matches[0])\n }\n }\n\n return '/'\n}\n\nfunction getBaseURL(url: string): string {\n return ('' + url).replace(/^((?:https?|file|ftp|chrome-extension|moz-extension):\\/\\/.+)?\\/[^/]+(?:\\?.*)?$/, '$1') + '/'\n}\n\nexport { getBundleURLCached as getBundleURL }\n","/* eslint-disable @stylistic/max-len */\n/* eslint-disable import-x/no-internal-modules */\n// tslint:disable max-classes-per-file\n\nimport type { ImplementationExport, ThreadsWorkerOptions } from '../types/master.ts'\nimport { getBundleURL } from './get-bundle-url.browser.ts'\n\nexport const defaultPoolSize = typeof navigator !== 'undefined' && navigator.hardwareConcurrency ? navigator.hardwareConcurrency : 4\n\nconst isAbsoluteURL = (value: string) => /^[A-Za-z][\\d+.A-Za-z\\-]*:/.test(value)\n\nfunction createSourceBlobURL(code: string): string {\n const blob = new Blob([code], { type: 'application/javascript' })\n return URL.createObjectURL(blob)\n}\n\nfunction selectWorkerImplementation(): ImplementationExport {\n if (typeof Worker === 'undefined') {\n // Might happen on Safari, for instance\n // The idea is to only fail if the constructor is actually used\n return class NoWebWorker {\n constructor() {\n throw new Error(\n \"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.\",\n )\n }\n } as unknown as ImplementationExport\n }\n\n class WebWorker extends Worker {\n constructor(url: string | URL, options?: ThreadsWorkerOptions) {\n if (typeof url === 'string' && options && options._baseURL) {\n url = new URL(url, options._baseURL)\n } else if (typeof url === 'string' && !isAbsoluteURL(url) && /^file:\\/\\//i.test(getBundleURL())) {\n url = new URL(url, getBundleURL().replace(/\\/[^/]+$/, '/'))\n if (options?.CORSWorkaround ?? true) {\n url = createSourceBlobURL(`importScripts(${JSON.stringify(url)});`)\n }\n }\n if (\n typeof url === 'string'\n && isAbsoluteURL(url) // Create source code blob loading JS file via `importScripts()`\n // to circumvent worker CORS restrictions\n && (options?.CORSWorkaround ?? true)\n ) {\n url = createSourceBlobURL(`importScripts(${JSON.stringify(url)});`)\n }\n super(url, options)\n }\n }\n\n class BlobWorker extends WebWorker {\n constructor(blob: Blob, options?: ThreadsWorkerOptions) {\n const url = globalThis.URL.createObjectURL(blob)\n super(url, options)\n }\n\n static fromText(source: string, options?: ThreadsWorkerOptions): WebWorker {\n const blob = new globalThis.Blob([source], { type: 'text/javascript' })\n return new BlobWorker(blob, options)\n }\n }\n\n return {\n blob: BlobWorker,\n default: WebWorker,\n }\n}\n\nlet implementation: ImplementationExport\n\nexport function getWorkerImplementation(): ImplementationExport {\n if (!implementation) {\n implementation = selectWorkerImplementation()\n }\n return implementation\n}\n\nexport function isWorkerRuntime() {\n const isWindowContext = typeof globalThis !== 'undefined' && typeof Window !== 'undefined' && globalThis instanceof Window\n return typeof globalThis !== 'undefined' && self['postMessage'] && !isWindowContext ? true : false\n}\n"],"mappings":";AAEA,IAAI;AAEJ,SAAS,qBAA6B;AACpC,MAAI,CAAC,WAAW;AACd,gBAAY,aAAa;AAAA,EAC3B;AAEA,SAAO;AACT;AAEA,SAAS,eAAuB;AAE9B,MAAI;AACF,UAAM,IAAI,MAAM,qBAAqB;AAAA,EACvC,SAAS,IAAI;AACX,UAAM,MAAM;AACZ,UAAM,WAAW,KAAK,IAAI,OAAO,MAAM,+DAA+D;AACtG,QAAI,SAAS;AACX,aAAO,WAAW,QAAQ,CAAC,CAAC;AAAA,IAC9B;AAAA,EACF;AAEA,SAAO;AACT;AAEA,SAAS,WAAW,KAAqB;AACvC,UAAQ,KAAK,KAAK,QAAQ,kFAAkF,IAAI,IAAI;AACtH;;;ACtBO,IAAM,kBAAkB,OAAO,cAAc,eAAe,UAAU,sBAAsB,UAAU,sBAAsB;AAEnI,IAAM,gBAAgB,CAAC,UAAkB,4BAA4B,KAAK,KAAK;AAE/E,SAAS,oBAAoB,MAAsB;AACjD,QAAM,OAAO,IAAI,KAAK,CAAC,IAAI,GAAG,EAAE,MAAM,yBAAyB,CAAC;AAChE,SAAO,IAAI,gBAAgB,IAAI;AACjC;AAEA,SAAS,6BAAmD;AAC1D,MAAI,OAAO,WAAW,aAAa;AAGjC,WAAO,MAAM,YAAY;AAAA,MACvB,cAAc;AACZ,cAAM,IAAI;AAAA,UACR;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAM,kBAAkB,OAAO;AAAA,IAC7B,YAAY,KAAmB,SAAgC;AAC7D,UAAI,OAAO,QAAQ,YAAY,WAAW,QAAQ,UAAU;AAC1D,cAAM,IAAI,IAAI,KAAK,QAAQ,QAAQ;AAAA,MACrC,WAAW,OAAO,QAAQ,YAAY,CAAC,cAAc,GAAG,KAAK,cAAc,KAAK,mBAAa,CAAC,GAAG;AAC/F,cAAM,IAAI,IAAI,KAAK,mBAAa,EAAE,QAAQ,YAAY,GAAG,CAAC;AAC1D,YAAI,SAAS,kBAAkB,MAAM;AACnC,gBAAM,oBAAoB,iBAAiB,KAAK,UAAU,GAAG,CAAC,IAAI;AAAA,QACpE;AAAA,MACF;AACA,UACE,OAAO,QAAQ,YACZ,cAAc,GAAG,MAEhB,SAAS,kBAAkB,OAC/B;AACA,cAAM,oBAAoB,iBAAiB,KAAK,UAAU,GAAG,CAAC,IAAI;AAAA,MACpE;AACA,YAAM,KAAK,OAAO;AAAA,IACpB;AAAA,EACF;AAAA,EAEA,MAAM,mBAAmB,UAAU;AAAA,IACjC,YAAY,MAAY,SAAgC;AACtD,YAAM,MAAM,WAAW,IAAI,gBAAgB,IAAI;AAC/C,YAAM,KAAK,OAAO;AAAA,IACpB;AAAA,IAEA,OAAO,SAAS,QAAgB,SAA2C;AACzE,YAAM,OAAO,IAAI,WAAW,KAAK,CAAC,MAAM,GAAG,EAAE,MAAM,kBAAkB,CAAC;AACtE,aAAO,IAAI,WAAW,MAAM,OAAO;AAAA,IACrC;AAAA,EACF;AAEA,SAAO;AAAA,IACL,MAAM;AAAA,IACN,SAAS;AAAA,EACX;AACF;AAEA,IAAI;AAEG,SAAS,0BAAgD;AAC9D,MAAI,CAAC,gBAAgB;AACnB,qBAAiB,2BAA2B;AAAA,EAC9C;AACA,SAAO;AACT;AAEO,SAAS,kBAAkB;AAChC,QAAM,kBAAkB,OAAO,eAAe,eAAe,OAAO,WAAW,eAAe,sBAAsB;AACpH,SAAO,OAAO,eAAe,eAAe,KAAK,aAAa,KAAK,CAAC,kBAAkB,OAAO;AAC/F;","names":[]}