From e66a2c7c4339853b43f35ff5e1f642ff448590a0 Mon Sep 17 00:00:00 2001 From: Aaron Eischeid Date: Thu, 13 Aug 2026 19:27:39 -0500 Subject: [PATCH 1/3] quick migration from threads to threadsx --- README.md | 2 +- .../rollup-plugin-web-workers/package.json | 5 +-- .../rollup.testing.js | 10 +++--- .../rollup-plugin-web-workers/src/index.ts | 2 +- packages/web-workers/README.md | 4 +-- packages/web-workers/extensions.d.ts | 2 +- packages/web-workers/package.json | 6 ++-- .../src/__tests__/terminate.spec.ts | 4 +-- .../src/__tests__/transferable.spec.ts | 2 +- packages/web-workers/src/terminate.ts | 2 +- packages/web-workers/src/transferable.ts | 6 ++-- packages/web-workers/src/worker.ts | 4 +-- yarn.lock | 32 ++++--------------- 13 files changed, 31 insertions(+), 50 deletions(-) diff --git a/README.md b/README.md index f7317d1..477cadf 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # web-workers This is a mono-repo that contains utilities to create and build web workers. It -uses the [Threads](https://threads.js.org/) internally to handle the management +uses [threadsx](https://github.com/jmaleonard/threadsx) internally to handle the management of web workers and provide pooling behavior. ## Packages diff --git a/packages/rollup-plugin-web-workers/package.json b/packages/rollup-plugin-web-workers/package.json index a8138ef..01d7449 100644 --- a/packages/rollup-plugin-web-workers/package.json +++ b/packages/rollup-plugin-web-workers/package.json @@ -48,7 +48,7 @@ }, "peerDependencies": { "rollup": ">=2", - "threads": "^1" + "threadsx": "^2" }, "devDependencies": { "@rollup/plugin-commonjs": "^29.0.3", @@ -60,6 +60,7 @@ "http-server": "^13.1.0", "jest-puppeteer": "^5.0.4", "puppeteer": "^10.4.0", - "rollup-plugin-copy": "^3.5.0" + "rollup-plugin-copy": "^3.5.0", + "threadsx": "^2.1.0" } } diff --git a/packages/rollup-plugin-web-workers/rollup.testing.js b/packages/rollup-plugin-web-workers/rollup.testing.js index 7b8aa82..4a9ecea 100644 --- a/packages/rollup-plugin-web-workers/rollup.testing.js +++ b/packages/rollup-plugin-web-workers/rollup.testing.js @@ -7,12 +7,12 @@ import copy from 'rollup-plugin-copy'; import workers from './dist/bundle.esm.js'; -function threadsBrowserEntry() { +function threadsxBrowserEntry() { return { - name: 'threads-browser-entry', + name: 'threadsx-browser-entry', resolveId(source) { - if (source === 'threads') { - return path.resolve('../../node_modules/threads/dist-esm/index.js'); + if (source === 'threadsx') { + return path.resolve('../../node_modules/threadsx/dist-esm/index.js'); } return null; @@ -21,7 +21,7 @@ function threadsBrowserEntry() { } const browserPlugins = [ - threadsBrowserEntry(), + threadsxBrowserEntry(), commonjs(), nodeResolve({ browser: true }), ]; diff --git a/packages/rollup-plugin-web-workers/src/index.ts b/packages/rollup-plugin-web-workers/src/index.ts index c638d8c..f17c196 100644 --- a/packages/rollup-plugin-web-workers/src/index.ts +++ b/packages/rollup-plugin-web-workers/src/index.ts @@ -86,7 +86,7 @@ export async function loadWorker() { function getWorkerModule(workerName: string, workerCode: string): string { return ` -import { BlobWorker, spawn, Pool, Transfer } from 'threads'; +import { BlobWorker, spawn, Pool, Transfer } from 'threadsx'; import { makeTransferable, TerminateController } from '@vertexvis/web-workers'; const workerName = "${workerName}.js"; diff --git a/packages/web-workers/README.md b/packages/web-workers/README.md index 58a9179..fd75fc5 100644 --- a/packages/web-workers/README.md +++ b/packages/web-workers/README.md @@ -1,6 +1,6 @@ # @vertexvis/web-workers -A package for defining, bundling, and loading web workers. The [Threads] package +A package for defining, bundling, and loading web workers. The [threadsx] package is used internally to provide worker creation and pooling behavior. [Transferables] are automatically passed when sending data to and from web workers. @@ -166,6 +166,6 @@ export default { } ``` -[Threads]: https://threads.js.org/ +[threadsx]: https://github.com/jmaleonard/threadsx [Transferables]: https://developer.mozilla.org/en-US/docs/Web/API/Transferable [@vertexvis/rollup-plugin-web-workers]: https://www.npmjs.com/package/@vertexvis/rollup-plugin-web-workers diff --git a/packages/web-workers/extensions.d.ts b/packages/web-workers/extensions.d.ts index b9eaed2..94722b9 100644 --- a/packages/web-workers/extensions.d.ts +++ b/packages/web-workers/extensions.d.ts @@ -2,7 +2,7 @@ * Provides static analysis for import paths that are prefixed with `worker:`. */ declare module 'worker:*' { - import type { Worker } from 'threads'; + import type { Worker } from 'threadsx'; interface SpawnPoolOptions { /** diff --git a/packages/web-workers/package.json b/packages/web-workers/package.json index 93dade8..170b047 100644 --- a/packages/web-workers/package.json +++ b/packages/web-workers/package.json @@ -3,7 +3,7 @@ "version": "0.2.0", "type": "module", "license": "MIT", - "description": "A wrapper around ThreadsJS to make bundling and using web workers even simpler.", + "description": "A wrapper around threadsx to make bundling and using web workers even simpler.", "keywords": [ "thread", "worker", @@ -44,11 +44,11 @@ "devDependencies": { "jest": "^29.7.0", "jest-environment-jsdom": "^29.7.0", - "threads": "^1.7.0", + "threadsx": "^2.1.0", "tslib": "^2.8.1" }, "peerDependencies": { - "threads": "^1", + "threadsx": "^2", "tslib": "^2" } } diff --git a/packages/web-workers/src/__tests__/terminate.spec.ts b/packages/web-workers/src/__tests__/terminate.spec.ts index 6977421..ac0aa68 100644 --- a/packages/web-workers/src/__tests__/terminate.spec.ts +++ b/packages/web-workers/src/__tests__/terminate.spec.ts @@ -1,6 +1,6 @@ -jest.mock('threads'); +jest.mock('threadsx'); -import { Thread } from 'threads'; +import { Thread } from 'threadsx'; import { TerminateController } from '../terminate'; diff --git a/packages/web-workers/src/__tests__/transferable.spec.ts b/packages/web-workers/src/__tests__/transferable.spec.ts index 41f3db2..5966590 100644 --- a/packages/web-workers/src/__tests__/transferable.spec.ts +++ b/packages/web-workers/src/__tests__/transferable.spec.ts @@ -1,6 +1,6 @@ import '../__mocks__/browser'; -import { TransferDescriptor } from 'threads'; +import { TransferDescriptor } from 'threadsx'; import { makeTransferable } from '../transferable'; diff --git a/packages/web-workers/src/terminate.ts b/packages/web-workers/src/terminate.ts index 5530104..72f43ca 100644 --- a/packages/web-workers/src/terminate.ts +++ b/packages/web-workers/src/terminate.ts @@ -1,4 +1,4 @@ -import { Thread } from 'threads'; +import { Thread } from 'threadsx'; interface WorkerPoolLike { terminate(force?: boolean): Promise; diff --git a/packages/web-workers/src/transferable.ts b/packages/web-workers/src/transferable.ts index 8b61ac8..5af3d64 100644 --- a/packages/web-workers/src/transferable.ts +++ b/packages/web-workers/src/transferable.ts @@ -1,4 +1,4 @@ -import { Transfer } from 'threads'; +import { Transfer } from 'threadsx'; import globalThis from './globalThis'; @@ -47,11 +47,11 @@ function isTypedArray(obj: unknown): obj is TypedArray { } /** - * A function that will recursively inspect an object and return a Threads + * A function that will recursively inspect an object and return a threadsx * `Transfer` that contains all the `Transferable`s in the given object. * * @param obj The object to make transferable. - * @returns A `Transfer` from Threads. + * @returns A `Transfer` from threadsx. */ export function makeTransferable(obj: T): ReturnType | T { if (isTransferable(obj)) { diff --git a/packages/web-workers/src/worker.ts b/packages/web-workers/src/worker.ts index 7d005f2..9623571 100644 --- a/packages/web-workers/src/worker.ts +++ b/packages/web-workers/src/worker.ts @@ -1,4 +1,4 @@ -import { expose as threadsExpose } from 'threads'; +import { expose as threadsExpose } from 'threadsx'; import { makeTransferable } from './transferable'; @@ -12,7 +12,7 @@ interface DefineWorkerOptions { /** * Defines a web worker implementation. This function wraps the `expose` method - * of Threads and handles automatic conversion of Transferable types. + * of threadsx and handles automatic conversion of Transferable types. * * @param impl The worker implementation. * @see https://developer.mozilla.org/en-US/docs/Web/API/Transferable diff --git a/yarn.lock b/yarn.lock index 9cd6e5c..ae04801 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2898,7 +2898,7 @@ dateformat@^3.0.3: resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-3.0.3.tgz#a6e37499a4d9a9cf85ef5872044d62901c9889ae" integrity sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q== -debug@4, debug@^4.1.0, debug@^4.1.1, debug@^4.2.0, debug@^4.3.1: +debug@4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1: version "4.3.2" resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.2.tgz#f0a49c18ac8779e31d4a0c6029dfb76873c7428b" integrity sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw== @@ -3277,11 +3277,6 @@ eslint@^8.57.0: strip-ansi "^6.0.1" text-table "^0.2.0" -esm@^3.2.25: - version "3.2.25" - resolved "https://registry.yarnpkg.com/esm/-/esm-3.2.25.tgz#342c18c29d56157688ba5ce31f8431fbb795cc10" - integrity sha512-U1suiZ2oDVWv4zPO56S0NcR5QriEahGtdN2OR6FiOG4WJvcjBVFB0qI4+eKoWFH483PKGuLuu6V8Z4T5g63UVA== - espree@^9.6.0, espree@^9.6.1: version "9.6.1" resolved "https://registry.yarnpkg.com/espree/-/espree-9.6.1.tgz#a2a17b8e434690a5432f2f8018ce71d331a48c6f" @@ -4338,11 +4333,6 @@ is-obj@^2.0.0: resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-2.0.0.tgz#473fb05d973705e3fd9620545018ca8e22ef4982" integrity sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w== -is-observable@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/is-observable/-/is-observable-2.1.0.tgz#5c8d733a0b201c80dff7bb7c0df58c6a255c7c69" - integrity sha512-DailKdLb0WU+xX8K5w7VsJhapwHLZ9jjmazqCJq4X12CTgqq73TKnbRcnSLuXYPOoLQgV5IrD7ePiX/h1vnkBw== - is-path-inside@^3.0.3: version "3.0.3" resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283" @@ -7391,17 +7381,14 @@ text-table@^0.2.0: resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ= -threads@^1.7.0: - version "1.7.0" - resolved "https://registry.yarnpkg.com/threads/-/threads-1.7.0.tgz#d9e9627bfc1ef22ada3b733c2e7558bbe78e589c" - integrity sha512-Mx5NBSHX3sQYR6iI9VYbgHKBLisyB+xROCBGjjWm1O9wb9vfLxdaGtmT/KCjUqMsSNW6nERzCW3T6H43LqjDZQ== +threadsx@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/threadsx/-/threadsx-2.1.0.tgz#059c6a1425e4eef0eb69bf5bc9100f2808c014d0" + integrity sha512-yLwBgwpamvpuPbTzHRsu5zJF+QjWKYTL3Y2VJjWad4HstCM6RIiVGgmjt/1fyAS9aw5jh7C0343osb+rmhNeBw== dependencies: callsites "^3.1.0" - debug "^4.2.0" - is-observable "^2.1.0" + debug "^4.4.3" observable-fns "^0.6.1" - optionalDependencies: - tiny-worker ">= 2" through2@^2.0.0: version "2.0.5" @@ -7416,13 +7403,6 @@ through@2, through@2.3.8, "through@>=2.2.7 <3", through@^2.3.8: resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" integrity sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg== -"tiny-worker@>= 2": - version "2.3.0" - resolved "https://registry.yarnpkg.com/tiny-worker/-/tiny-worker-2.3.0.tgz#715ae34304c757a9af573ae9a8e3967177e6011e" - integrity sha512-pJ70wq5EAqTAEl9IkGzA+fN0836rycEuz2Cn6yeZ6FRzlVS5IDOkFHpIoEsksPRQV34GDqXm65+OlnZqUSyK2g== - dependencies: - esm "^3.2.25" - tinyglobby@0.2.12: version "0.2.12" resolved "https://registry.yarnpkg.com/tinyglobby/-/tinyglobby-0.2.12.tgz#ac941a42e0c5773bd0b5d08f32de82e74a1a61b5" From c4d47db04affedf1942d674bcb42e89922dfde49 Mon Sep 17 00:00:00 2001 From: Aaron Eischeid Date: Thu, 13 Aug 2026 19:35:56 -0500 Subject: [PATCH 2/3] migration notes and cleanup --- README.md | 19 +++++++++++++++++++ .../rollup-plugin-web-workers/package.json | 11 +++++++++++ .../rollup-plugin-web-workers/src/index.ts | 4 ++-- packages/web-workers/README.md | 7 +++++++ packages/web-workers/package.json | 11 +++++++++++ 5 files changed, 50 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 477cadf..d9e9c99 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,25 @@ of web workers and provide pooling behavior. | [@vertexvis/web-workers] | ![npm](https://img.shields.io/npm/v/@vertexvis/web-workers) | Package for defining and loading web workers. | | [@vertexvis/rollup-plugin-web-workers] | ![npm](https://img.shields.io/npm/v/@vertexvis/rollup-plugin-web-workers) | Package for building web workers with Rollup. | +## Migrating from `threads.js` + +This major release replaces the unmaintained `threads` peer dependency with +`threadsx` v2. Install `threadsx` alongside these packages and remove `threads`: + +```sh +yarn remove threads +yarn add threadsx@^2 + +# or +npm uninstall threads +npm install threadsx@^2 +``` + +Update any direct imports from `threads` to `threadsx`, including worker entry +imports such as `threads/worker` to `threadsx/worker`. The APIs used by these +packages, including `defineWorker`, `loadWorker`, and worker pools, are +otherwise unchanged. + ## Simple Usage See [@vertexvis/web-workers](./packages/web-workers/README.md) for more advanced diff --git a/packages/rollup-plugin-web-workers/package.json b/packages/rollup-plugin-web-workers/package.json index 01d7449..77f32d9 100644 --- a/packages/rollup-plugin-web-workers/package.json +++ b/packages/rollup-plugin-web-workers/package.json @@ -23,6 +23,17 @@ "main": "./dist/bundle.cjs", "module": "./dist/bundle.esm.js", "typings": "./dist/index.d.ts", + "exports": { + ".": { + "types": "./dist/index.d.ts", + "import": "./dist/bundle.esm.js", + "require": "./dist/bundle.cjs", + "default": "./dist/bundle.esm.js" + } + }, + "engines": { + "node": ">=20" + }, "publishConfig": { "registry": "https://registry.npmjs.org", "access": "public" diff --git a/packages/rollup-plugin-web-workers/src/index.ts b/packages/rollup-plugin-web-workers/src/index.ts index f17c196..c097f32 100644 --- a/packages/rollup-plugin-web-workers/src/index.ts +++ b/packages/rollup-plugin-web-workers/src/index.ts @@ -1,14 +1,14 @@ import * as path from 'path'; import { Plugin, rollup } from 'rollup'; -interface ThreadsPluginOptions { +interface WorkerPluginOptions { plugins?: Plugin[]; } const workerPrefix = 'worker:'; const workerModulePrefix = 'worker-module:'; -export default function ({ plugins = [] }: ThreadsPluginOptions): Plugin { +export default function ({ plugins = [] }: WorkerPluginOptions): Plugin { return { name: 'web-workers-plugin', diff --git a/packages/web-workers/README.md b/packages/web-workers/README.md index fd75fc5..707a6a8 100644 --- a/packages/web-workers/README.md +++ b/packages/web-workers/README.md @@ -18,6 +18,13 @@ yarn add @vertexvis/web-workers npm install @vertexvis/web-workers ``` +### Migrating from `threads.js` + +This major release replaces the `threads` peer dependency with `threadsx` v2. +Remove `threads` and install `threadsx@^2`, then update direct imports such as +`threads/worker` to `threadsx/worker`. The APIs provided by this package are +otherwise unchanged. + ## Usage ### Defining a Web Worker diff --git a/packages/web-workers/package.json b/packages/web-workers/package.json index 170b047..ff3e98f 100644 --- a/packages/web-workers/package.json +++ b/packages/web-workers/package.json @@ -22,6 +22,17 @@ "main": "./dist/bundle.cjs", "module": "./dist/bundle.esm.js", "typings": "./dist/index.d.ts", + "exports": { + ".": { + "types": "./dist/index.d.ts", + "import": "./dist/bundle.esm.js", + "require": "./dist/bundle.cjs", + "default": "./dist/bundle.esm.js" + } + }, + "engines": { + "node": ">=20" + }, "publishConfig": { "registry": "https://registry.npmjs.org", "access": "public" From 0567fa68afc5d3d6b7ada7fd35f6353cc3675198 Mon Sep 17 00:00:00 2001 From: Aaron Eischeid Date: Thu, 13 Aug 2026 19:42:59 -0500 Subject: [PATCH 3/3] fix spawnPool to consistantly expect/use options object for terminate --- packages/rollup-plugin-web-workers/src/index.ts | 8 ++++++-- packages/rollup-plugin-web-workers/test-src/main.js | 12 +++++++++++- packages/web-workers/README.md | 8 ++++---- 3 files changed, 21 insertions(+), 7 deletions(-) diff --git a/packages/rollup-plugin-web-workers/src/index.ts b/packages/rollup-plugin-web-workers/src/index.ts index c097f32..7a8fa3e 100644 --- a/packages/rollup-plugin-web-workers/src/index.ts +++ b/packages/rollup-plugin-web-workers/src/index.ts @@ -110,8 +110,12 @@ export async function spawnWorker(terminate) { }; } -export function spawnPool(options) { - return Pool(() => spawnWorker(options.terminate), options); +export function spawnPool({ terminate, ...options } = {}) { + const pool = Pool(() => spawnWorker(), options); + if (terminate != null) { + terminate.addPool(pool); + } + return pool; } `; } diff --git a/packages/rollup-plugin-web-workers/test-src/main.js b/packages/rollup-plugin-web-workers/test-src/main.js index ce0f780..b2e7b89 100644 --- a/packages/rollup-plugin-web-workers/test-src/main.js +++ b/packages/rollup-plugin-web-workers/test-src/main.js @@ -29,13 +29,22 @@ async function testPool() { const { spawnPool, makeController } = await loadWorker2(); const controller = makeController(); - const pool = await spawnPool({ controller }); + const pool = await spawnPool({ terminate: controller }); const result = await pool.queue((sum) => sum({ nums })); await controller.terminate(); assert(9, result[0], 'testThread returns sum'); } +async function testPoolWithoutOptions() { + const { spawnPool } = await loadWorker2(); + const pool = await spawnPool(); + const result = await pool.queue((sum) => sum({ nums: Uint8Array.of(2, 3) })); + await pool.terminate(); + + assert(5, result[0], 'testPoolWithoutOptions returns sum'); +} + async function assert(expected, actual, msg) { if (expected !== actual) { recordFailure(`${msg} [expected=${expected}, actual=${actual}]`); @@ -60,6 +69,7 @@ export async function runSuite() { await testThread(); await testTransferables(); await testPool(); + await testPoolWithoutOptions(); window.__test__.done = true; } diff --git a/packages/web-workers/README.md b/packages/web-workers/README.md index 707a6a8..c2ff5c3 100644 --- a/packages/web-workers/README.md +++ b/packages/web-workers/README.md @@ -82,7 +82,7 @@ async function main(): Promise { const { spawnPool, makeController } = await loadWorker(); const controller = makeController(); - const pool = await spawnPool({ controller }); + const pool = await spawnPool({ terminate: controller }); pool .queue((sum) => add(1, 2)) .then((sum) => console.log('sum', sum)); // 3 @@ -113,13 +113,13 @@ interface CreatePoolOptions { size?: number; // A controller to terminate the pool. - controller?: WorkerController; + terminate?: TerminateController; } ``` ### Worker Termination -A `WorkerController` is used to terminate a worker. A worker module exports a +A `TerminateController` is used to terminate a worker. A worker module exports a `makeController` function to create a controller. You can pass a controller to multiple workers and pools to terminate them together. @@ -138,7 +138,7 @@ async function main(): Promise { const controller = makeController(); const worker = await spawnWorker(controller); - const pool = await spawnPool({ controller }); + const pool = await spawnPool({ terminate: controller }); // Terminate the worker and pool. await controller.terminate();