From 086ed700b8bb17f6ce0780e98e9e4646bdba637d Mon Sep 17 00:00:00 2001 From: aminya Date: Sun, 9 Aug 2020 01:40:34 -0500 Subject: [PATCH 01/21] feat: add createWorker function --- src/createWorker.ts | 26 ++++++++++++++++++++++++++ src/index.ts | 1 + 2 files changed, 27 insertions(+) create mode 100644 src/createWorker.ts diff --git a/src/createWorker.ts b/src/createWorker.ts new file mode 100644 index 00000000..2f69f5ce --- /dev/null +++ b/src/createWorker.ts @@ -0,0 +1,26 @@ +import * as WebImplementation from "./master/implementation.browser" +import * as NodeImplementation from "./master/implementation.node" + +interface WorkerOptions { + backend: string + blob: boolean +} + +export function createWorker(workerPath: string, options: WorkerOptions) { + let WorkerConstructor: any + if (options.backend === "web") { + WorkerConstructor = options.blob ? + WebImplementation.getWorkerImplementation().blob : + WebImplementation.getWorkerImplementation().default + } else if (options.backend === "node") { + WorkerConstructor = options.blob ? + NodeImplementation.getWorkerImplementation().blob : + NodeImplementation.getWorkerImplementation().default + } else if (options.backend === "tiny") { + // TODO + throw new Error("Tiny worker is not supported using `createWorker` yet.") + } else { + throw new Error("The worker backend is not supported.") + } + return new WorkerConstructor(workerPath) +} diff --git a/src/index.ts b/src/index.ts index 8daf5286..3239e2ec 100644 --- a/src/index.ts +++ b/src/index.ts @@ -3,3 +3,4 @@ export * from "./master/index" export { expose } from "./worker/index" export { DefaultSerializer, JsonSerializable, Serializer, SerializerImplementation } from "./serializers" export { Transfer, TransferDescriptor } from "./transferable" +export { createWorker } from "./createWorker" From cc1c915ad8453b548b6dafd09810bb209a908199 Mon Sep 17 00:00:00 2001 From: aminya Date: Sun, 9 Aug 2020 01:50:34 -0500 Subject: [PATCH 02/21] feat: only import the needed function --- src/createWorker.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/createWorker.ts b/src/createWorker.ts index 2f69f5ce..608f4421 100644 --- a/src/createWorker.ts +++ b/src/createWorker.ts @@ -1,5 +1,5 @@ -import * as WebImplementation from "./master/implementation.browser" -import * as NodeImplementation from "./master/implementation.node" +import {getWorkerImplementation as getWebWorker} from "./master/implementation.browser" +import {getWorkerImplementation as getNodeWorker} from "./master/implementation.node" interface WorkerOptions { backend: string @@ -10,12 +10,12 @@ export function createWorker(workerPath: string, options: WorkerOptions) { let WorkerConstructor: any if (options.backend === "web") { WorkerConstructor = options.blob ? - WebImplementation.getWorkerImplementation().blob : - WebImplementation.getWorkerImplementation().default + getWebWorker().blob : + getWebWorker().default } else if (options.backend === "node") { WorkerConstructor = options.blob ? - NodeImplementation.getWorkerImplementation().blob : - NodeImplementation.getWorkerImplementation().default + getNodeWorker().blob : + getNodeWorker().default } else if (options.backend === "tiny") { // TODO throw new Error("Tiny worker is not supported using `createWorker` yet.") From 5da90ce58e674d402c414ee66aed64ad98f1935a Mon Sep 17 00:00:00 2001 From: aminya Date: Sun, 9 Aug 2020 02:14:49 -0500 Subject: [PATCH 03/21] feat: use the correct types for WorkerConstructor and workerPath --- src/createWorker.ts | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/createWorker.ts b/src/createWorker.ts index 608f4421..f58117a5 100644 --- a/src/createWorker.ts +++ b/src/createWorker.ts @@ -1,13 +1,18 @@ import {getWorkerImplementation as getWebWorker} from "./master/implementation.browser" -import {getWorkerImplementation as getNodeWorker} from "./master/implementation.node" +import {getWorkerImplementation as getNodeWorker } from "./master/implementation.node" + +import { + BlobWorker, + WorkerImplementation, +} from "./types/master" interface WorkerOptions { backend: string blob: boolean } -export function createWorker(workerPath: string, options: WorkerOptions) { - let WorkerConstructor: any +export function createWorker(workerPath: string & Blob, options: WorkerOptions) { + let WorkerConstructor: typeof WorkerImplementation | typeof BlobWorker if (options.backend === "web") { WorkerConstructor = options.blob ? getWebWorker().blob : From a6e3c41187d42a017de1e25c0f75baf947ac779d Mon Sep 17 00:00:00 2001 From: aminya Date: Sun, 9 Aug 2020 02:22:05 -0500 Subject: [PATCH 04/21] feat: select between tiny and node --- src/createWorker.ts | 9 +++++---- src/master/implementation.node.ts | 28 +++++++++++++++++++++------- 2 files changed, 26 insertions(+), 11 deletions(-) diff --git a/src/createWorker.ts b/src/createWorker.ts index f58117a5..293932b6 100644 --- a/src/createWorker.ts +++ b/src/createWorker.ts @@ -19,11 +19,12 @@ export function createWorker(workerPath: string & Blob, options: WorkerOptions) getWebWorker().default } else if (options.backend === "node") { WorkerConstructor = options.blob ? - getNodeWorker().blob : - getNodeWorker().default + getNodeWorker("node").blob : + getNodeWorker("node").default } else if (options.backend === "tiny") { - // TODO - throw new Error("Tiny worker is not supported using `createWorker` yet.") + WorkerConstructor = options.blob ? + getNodeWorker("tiny").blob : + getNodeWorker("tiny").default } else { throw new Error("The worker backend is not supported.") } diff --git a/src/master/implementation.node.ts b/src/master/implementation.node.ts index 68878c4a..d4c3d21f 100644 --- a/src/master/implementation.node.ts +++ b/src/master/implementation.node.ts @@ -248,21 +248,35 @@ function initTinyWorker(): ImplementationExport { let implementation: ImplementationExport let isTinyWorker: boolean -function selectWorkerImplementation(): ImplementationExport { - try { +function selectWorkerImplementation(selection?: string): ImplementationExport { + if (!selection) { + + // automatic version based selection + try { + isTinyWorker = false + return initWorkerThreadsWorker() + } catch(error) { + // tslint:disable-next-line no-console + console.debug("Node worker_threads not available. Trying to fall back to tiny-worker polyfill...") + isTinyWorker = true + return initTinyWorker() + } + + // manual selection + } else if (selection === "node") { isTinyWorker = false return initWorkerThreadsWorker() - } catch(error) { - // tslint:disable-next-line no-console - console.debug("Node worker_threads not available. Trying to fall back to tiny-worker polyfill...") + } else if (selection === "tiny") { isTinyWorker = true return initTinyWorker() + } else { + throw new Error("selection is not supported" + selection) } } -export function getWorkerImplementation(): ImplementationExport { +export function getWorkerImplementation(selection?: string): ImplementationExport { if (!implementation) { - implementation = selectWorkerImplementation() + implementation = selectWorkerImplementation(selection) } return implementation } From 2734f8bbdba8f981f50dbfe85588ceaf9e5fb196 Mon Sep 17 00:00:00 2001 From: Amin Yahyaabadi Date: Tue, 25 Aug 2020 09:27:56 -0500 Subject: [PATCH 05/21] extend ThreadsWorkerOptions in CreateWorkerOptions - pass ThreadsWorkerOptions options to the worker constructor --- src/createWorker.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/createWorker.ts b/src/createWorker.ts index 293932b6..64384458 100644 --- a/src/createWorker.ts +++ b/src/createWorker.ts @@ -3,15 +3,16 @@ import {getWorkerImplementation as getNodeWorker } from "./master/implementation import { BlobWorker, + ThreadsWorkerOptions, WorkerImplementation, } from "./types/master" -interface WorkerOptions { +export interface CreateWorkerOptions extends ThreadsWorkerOptions { backend: string blob: boolean } -export function createWorker(workerPath: string & Blob, options: WorkerOptions) { +export function createWorker(workerPath: string & Blob, options: CreateWorkerOptions) { let WorkerConstructor: typeof WorkerImplementation | typeof BlobWorker if (options.backend === "web") { WorkerConstructor = options.blob ? @@ -28,5 +29,5 @@ export function createWorker(workerPath: string & Blob, options: WorkerOptions) } else { throw new Error("The worker backend is not supported.") } - return new WorkerConstructor(workerPath) + return new WorkerConstructor(workerPath, options) } From 5785b5a2009d4999a18bc0716e25c70e62e8cadb Mon Sep 17 00:00:00 2001 From: Amin Yahyaabadi Date: Tue, 25 Aug 2020 09:29:02 -0500 Subject: [PATCH 06/21] move CreateWorkerOptions to types file --- src/createWorker.ts | 7 +------ src/types/master.ts | 5 +++++ 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/createWorker.ts b/src/createWorker.ts index 64384458..0a3b9e29 100644 --- a/src/createWorker.ts +++ b/src/createWorker.ts @@ -3,15 +3,10 @@ import {getWorkerImplementation as getNodeWorker } from "./master/implementation import { BlobWorker, - ThreadsWorkerOptions, + CreateWorkerOptions, WorkerImplementation, } from "./types/master" -export interface CreateWorkerOptions extends ThreadsWorkerOptions { - backend: string - blob: boolean -} - export function createWorker(workerPath: string & Blob, options: CreateWorkerOptions) { let WorkerConstructor: typeof WorkerImplementation | typeof BlobWorker if (options.backend === "web") { diff --git a/src/types/master.ts b/src/types/master.ts index f3f72a7d..ebe4181e 100644 --- a/src/types/master.ts +++ b/src/types/master.ts @@ -88,6 +88,11 @@ export interface ThreadsWorkerOptions extends WorkerOptions { CORSWorkaround?: boolean } +export interface CreateWorkerOptions extends ThreadsWorkerOptions { + backend: string + blob: boolean +} + /** Worker implementation. Either web worker or a node.js Worker class. */ export declare class WorkerImplementation extends EventTarget implements Worker { constructor(path: string, options?: ThreadsWorkerOptions) From 075e368371e97bc60b1eeb21f360719e695ed9e2 Mon Sep 17 00:00:00 2001 From: Amin Yahyaabadi Date: Tue, 25 Aug 2020 09:30:22 -0500 Subject: [PATCH 07/21] add docs for the options --- src/types/master.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/types/master.ts b/src/types/master.ts index ebe4181e..cf0a140d 100644 --- a/src/types/master.ts +++ b/src/types/master.ts @@ -89,7 +89,9 @@ export interface ThreadsWorkerOptions extends WorkerOptions { } export interface CreateWorkerOptions extends ThreadsWorkerOptions { - backend: string + /** backend for the threads */ + backend: "web" | "node" | "tiny" + /** flag to return a BlobWorker */ blob: boolean } From bcacf386a5b6b73c7b45e7e5a3b4c79dfece3070 Mon Sep 17 00:00:00 2001 From: Amin Yahyaabadi Date: Sat, 9 Jan 2021 20:48:13 -0600 Subject: [PATCH 08/21] Use dynamic imports and make createWorker async --- src/createWorker.ts | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/createWorker.ts b/src/createWorker.ts index 0a3b9e29..eb2b5848 100644 --- a/src/createWorker.ts +++ b/src/createWorker.ts @@ -1,26 +1,27 @@ -import {getWorkerImplementation as getWebWorker} from "./master/implementation.browser" -import {getWorkerImplementation as getNodeWorker } from "./master/implementation.node" - import { BlobWorker, CreateWorkerOptions, WorkerImplementation, } from "./types/master" -export function createWorker(workerPath: string & Blob, options: CreateWorkerOptions) { +/** async function to creat a webworker. This function uses dynamic imports to only import the required implementation */ +export async function createWorker(workerPath: string & Blob, options: CreateWorkerOptions) { let WorkerConstructor: typeof WorkerImplementation | typeof BlobWorker if (options.backend === "web") { + const { getWorkerImplementation } = await import("./master/implementation.browser") WorkerConstructor = options.blob ? - getWebWorker().blob : - getWebWorker().default + getWorkerImplementation().blob : + getWorkerImplementation().default } else if (options.backend === "node") { + const { getWorkerImplementation } = await import("./master/implementation.node") WorkerConstructor = options.blob ? - getNodeWorker("node").blob : - getNodeWorker("node").default + getWorkerImplementation("node").blob : + getWorkerImplementation("node").default } else if (options.backend === "tiny") { + const { getWorkerImplementation } = await import("./master/implementation.node") WorkerConstructor = options.blob ? - getNodeWorker("tiny").blob : - getNodeWorker("tiny").default + getWorkerImplementation("tiny").blob : + getWorkerImplementation("tiny").default } else { throw new Error("The worker backend is not supported.") } From 209808a296bdd15d1bae05860e00306c251e07a6 Mon Sep 17 00:00:00 2001 From: Amin Yahyaabadi Date: Sat, 9 Jan 2021 20:56:38 -0600 Subject: [PATCH 09/21] Add top level files --- createWorker.d.ts | 1 + createWorker.js | 1 + createWorker.mjs | 1 + 3 files changed, 3 insertions(+) create mode 100644 createWorker.d.ts create mode 100644 createWorker.js create mode 100644 createWorker.mjs diff --git a/createWorker.d.ts b/createWorker.d.ts new file mode 100644 index 00000000..58beaffd --- /dev/null +++ b/createWorker.d.ts @@ -0,0 +1 @@ +export { createWorker } from "./dist-esm/createWorker" diff --git a/createWorker.js b/createWorker.js new file mode 100644 index 00000000..ac8419d7 --- /dev/null +++ b/createWorker.js @@ -0,0 +1 @@ +module.exports = require("./dist/createWorker") diff --git a/createWorker.mjs b/createWorker.mjs new file mode 100644 index 00000000..58beaffd --- /dev/null +++ b/createWorker.mjs @@ -0,0 +1 @@ +export { createWorker } from "./dist-esm/createWorker" From 9a62784ad5cce0dcd02e0b115bcbba5343ddda6b Mon Sep 17 00:00:00 2001 From: Amin Yahyaabadi Date: Sat, 9 Jan 2021 21:22:17 -0600 Subject: [PATCH 10/21] Rename implementation-node to prevent conflicts with native node addons --- package.json | 4 ++-- src/createWorker.ts | 4 ++-- src/master/{implementation.node.ts => implementation-node.ts} | 0 src/master/implementation.ts | 3 +-- 4 files changed, 5 insertions(+), 6 deletions(-) rename src/master/{implementation.node.ts => implementation-node.ts} (100%) diff --git a/package.json b/package.json index d99b82a7..622dfa90 100644 --- a/package.json +++ b/package.json @@ -122,12 +122,12 @@ "ts-node/register": false, "worker_threads": false, "./dist/master/implementation.js": "./dist/master/implementation.browser.js", - "./dist/master/implementation.node.js": false, + "./dist/master/implementation-node.js": false, "./dist/worker/implementation.js": "./dist/worker/implementation.browser.js", "./dist/worker/implementation.tiny-worker.js": false, "./dist/worker/implementation.worker_threads.js": false, "./dist-esm/master/implementation.js": "./dist-esm/master/implementation.browser.js", - "./dist-esm/master/implementation.node.js": false, + "./dist-esm/master/implementation-node.js": false, "./dist-esm/worker/implementation.js": "./dist-esm/worker/implementation.browser.js", "./dist-esm/worker/implementation.tiny-worker.js": false, "./dist-esm/worker/implementation.worker_threads.js": false diff --git a/src/createWorker.ts b/src/createWorker.ts index eb2b5848..0b0a582f 100644 --- a/src/createWorker.ts +++ b/src/createWorker.ts @@ -13,12 +13,12 @@ export async function createWorker(workerPath: string & Blob, options: CreateWor getWorkerImplementation().blob : getWorkerImplementation().default } else if (options.backend === "node") { - const { getWorkerImplementation } = await import("./master/implementation.node") + const { getWorkerImplementation } = await import("./master/implementation-node") WorkerConstructor = options.blob ? getWorkerImplementation("node").blob : getWorkerImplementation("node").default } else if (options.backend === "tiny") { - const { getWorkerImplementation } = await import("./master/implementation.node") + const { getWorkerImplementation } = await import("./master/implementation-node") WorkerConstructor = options.blob ? getWorkerImplementation("tiny").blob : getWorkerImplementation("tiny").default diff --git a/src/master/implementation.node.ts b/src/master/implementation-node.ts similarity index 100% rename from src/master/implementation.node.ts rename to src/master/implementation-node.ts diff --git a/src/master/implementation.ts b/src/master/implementation.ts index b6839478..ba2e5ffa 100644 --- a/src/master/implementation.ts +++ b/src/master/implementation.ts @@ -5,9 +5,8 @@ // We alias `src/master/implementation` to `src/master/implementation.browser` for web // browsers already in the package.json, so if get here, it's safe to pass-through the // node implementation - +import * as NodeImplementation from "./implementation-node" import * as BrowserImplementation from "./implementation.browser" -import * as NodeImplementation from "./implementation.node" const runningInNode = typeof process !== 'undefined' && process.arch !== 'browser' && 'pid' in process const implementation = runningInNode ? NodeImplementation : BrowserImplementation From 78c4b6a3efbe2357e9b75f20ef26d4d2f1d0fec3 Mon Sep 17 00:00:00 2001 From: Amin Yahyaabadi Date: Sat, 9 Jan 2021 21:23:29 -0600 Subject: [PATCH 11/21] Add rollup test for createWorker --- test/rollup/app-createWorker.js | 17 +++++++++++++++++ test/rollup/rollup.test.ts | 12 +++++++++++- 2 files changed, 28 insertions(+), 1 deletion(-) create mode 100644 test/rollup/app-createWorker.js diff --git a/test/rollup/app-createWorker.js b/test/rollup/app-createWorker.js new file mode 100644 index 00000000..a6cd9484 --- /dev/null +++ b/test/rollup/app-createWorker.js @@ -0,0 +1,17 @@ +import { createWorker } from "../../createWorker.mjs" +import { spawn, Thread } from "../../" + +async function run() { + const add = await spawn(await createWorker("./worker.js", {backend: "node"})) + const result = await add(2, 3) + await Thread.terminate(add) + return result +} + +run().then(result => { + console.log(`Result: ${result}`) + puppet.exit(0) +}).catch(error => { + console.error(error) + puppet.exit(1) +}) diff --git a/test/rollup/rollup.test.ts b/test/rollup/rollup.test.ts index 42e6253d..39ea6b96 100644 --- a/test/rollup/rollup.test.ts +++ b/test/rollup/rollup.test.ts @@ -12,6 +12,11 @@ test("can be bundled using rollup", async t => { ...config }) + const appCreateWorkerBundleP = rollup({ + input: path.resolve(__dirname, "app-createWorker.js"), + ...config + }) + const workerBundleP = rollup({ input: path.resolve(__dirname, "worker.js"), ...config @@ -22,12 +27,17 @@ test("can be bundled using rollup", async t => { format: "iife" }) + const appCreateWorkerBundleWriteP = (await appCreateWorkerBundleP).write({ + dir: path.resolve(__dirname, "dist"), + format: "es" + }) + const workerBundleWriteP = (await workerBundleP).write({ dir: path.resolve(__dirname, "dist"), format: "iife" }) - await Promise.all([appBundleWriteP, workerBundleWriteP]) + await Promise.all([appBundleWriteP, workerBundleWriteP, appCreateWorkerBundleWriteP]) if (process.platform === "win32") { // Quick-fix for weird Windows issue in CI From a3d1e25499c42cc0e603d9457cb728c16838714f Mon Sep 17 00:00:00 2001 From: Amin Yahyaabadi Date: Sat, 9 Jan 2021 21:26:00 -0600 Subject: [PATCH 12/21] include src in the pack (allow directly importing ts) --- package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 622dfa90..a80cee3b 100644 --- a/package.json +++ b/package.json @@ -137,6 +137,7 @@ "dist-esm/**", "*.js", "*.mjs", - "*.ts" + "*.ts", + "src" ] } From b819c490a40ac2c573c318e16caebd67fd267325 Mon Sep 17 00:00:00 2001 From: Amin Yahyaabadi Date: Sat, 9 Jan 2021 21:40:04 -0600 Subject: [PATCH 13/21] Add createWorker to the docs --- docs/usage.md | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/docs/usage.md b/docs/usage.md index 32b58459..5e43e8b2 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -166,6 +166,30 @@ const worker = await spawn(BlobWorker.fromText(MyWorker)) Bundle this module and you will obtain a stand-alone bundle that has its worker inlined. This is particularly useful for libraries using threads.js. +### createWorker - select worker backend +`createWorker` allows selecting the worker backend (among web, node, and tiny), and also if you want a blob worker. The second argument to the `createWorker` is an object that specifies `backend: 'web' | 'node' | 'tiny'` and `blob: boolean`. + +`createWorker` uses dynamic imports to only import the needed implementation, so you can import the needed functions directly to reduce the bundle size. + +```js +import { createWorker, spawn, Thread } from "threads" + +async function run() { + const worker = await createWorker("./worker.js", {backend: "node"}) + const add = await spawn(worker) + const result = await add(2, 3) + await Thread.terminate(add) + return result +} + +run().then(result => { + console.log(`Result: ${result}`) +}).catch(error => { + console.error(error) +}) +``` + + ## TypeScript ### Type-safe workers From eee7976c1bb3eb855e8e0f398e32621fe0f73dd8 Mon Sep 17 00:00:00 2001 From: Amin Yahyaabadi Date: Sat, 9 Jan 2021 22:21:47 -0600 Subject: [PATCH 14/21] Mention the possibility of passing WorkerOptions --- docs/usage.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/usage.md b/docs/usage.md index 5e43e8b2..2f83ac5b 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -167,7 +167,10 @@ const worker = await spawn(BlobWorker.fromText(MyWorker)) Bundle this module and you will obtain a stand-alone bundle that has its worker inlined. This is particularly useful for libraries using threads.js. ### createWorker - select worker backend -`createWorker` allows selecting the worker backend (among web, node, and tiny), and also if you want a blob worker. The second argument to the `createWorker` is an object that specifies `backend: 'web' | 'node' | 'tiny'` and `blob: boolean`. +`createWorker` allows selecting the worker backend (among web, node, and tiny), and also if you want a blob worker. + +The second argument to the `createWorker` is an object that specifies `backend: 'web' | 'node' | 'tiny'` and `blob: boolean`. +You can also pass other `WorkerOptions` in this object. `createWorker` uses dynamic imports to only import the needed implementation, so you can import the needed functions directly to reduce the bundle size. From 3be9a0541aa90d8fa95cfa1407c2f7007ab22269 Mon Sep 17 00:00:00 2001 From: Amin Yahyaabadi Date: Sat, 27 Mar 2021 09:57:39 -0500 Subject: [PATCH 15/21] Don't export createWorker from index --- docs/usage.md | 3 ++- src/index.ts | 1 - tsconfig.json | 1 + 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/usage.md b/docs/usage.md index 2f83ac5b..0d0dc16f 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -175,7 +175,8 @@ You can also pass other `WorkerOptions` in this object. `createWorker` uses dynamic imports to only import the needed implementation, so you can import the needed functions directly to reduce the bundle size. ```js -import { createWorker, spawn, Thread } from "threads" +import { createWorker } from "threads/createWorker" +import { spawn, Thread } from "threads" async function run() { const worker = await createWorker("./worker.js", {backend: "node"}) diff --git a/src/index.ts b/src/index.ts index 3239e2ec..8daf5286 100644 --- a/src/index.ts +++ b/src/index.ts @@ -3,4 +3,3 @@ export * from "./master/index" export { expose } from "./worker/index" export { DefaultSerializer, JsonSerializable, Serializer, SerializerImplementation } from "./serializers" export { Transfer, TransferDescriptor } from "./transferable" -export { createWorker } from "./createWorker" diff --git a/tsconfig.json b/tsconfig.json index a855de20..a3161ad0 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -13,6 +13,7 @@ }, "include": [ "./src/index.ts", + "./src/createWorker.ts", "./src/observable.ts", "./src/master/*", "./src/worker/*", From c323c34165eb6570dea7a5320cd3fa6f97222cda Mon Sep 17 00:00:00 2001 From: Amin Yahyaabadi Date: Sat, 27 Mar 2021 10:25:43 -0500 Subject: [PATCH 16/21] Make the backend a required argument in createWorker --- docs/usage.md | 5 ++--- src/createWorker.ts | 15 ++++++++++----- src/types/master.ts | 4 +--- test/rollup/app-createWorker.js | 2 +- 4 files changed, 14 insertions(+), 12 deletions(-) diff --git a/docs/usage.md b/docs/usage.md index 0d0dc16f..61954992 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -169,8 +169,7 @@ Bundle this module and you will obtain a stand-alone bundle that has its worker ### createWorker - select worker backend `createWorker` allows selecting the worker backend (among web, node, and tiny), and also if you want a blob worker. -The second argument to the `createWorker` is an object that specifies `backend: 'web' | 'node' | 'tiny'` and `blob: boolean`. -You can also pass other `WorkerOptions` in this object. +The second required argument to the `createWorker` is a string that specifies `backend: 'web' | 'node' | 'tiny'`. The third optional argument is an object that can be used to specify `blob: boolean` or other `WorkerOptions`. `createWorker` uses dynamic imports to only import the needed implementation, so you can import the needed functions directly to reduce the bundle size. @@ -179,7 +178,7 @@ import { createWorker } from "threads/createWorker" import { spawn, Thread } from "threads" async function run() { - const worker = await createWorker("./worker.js", {backend: "node"}) + const worker = await createWorker("./worker.js", "node") const add = await spawn(worker) const result = await add(2, 3) await Thread.terminate(add) diff --git a/src/createWorker.ts b/src/createWorker.ts index 0b0a582f..215e7dfe 100644 --- a/src/createWorker.ts +++ b/src/createWorker.ts @@ -4,20 +4,25 @@ import { WorkerImplementation, } from "./types/master" -/** async function to creat a webworker. This function uses dynamic imports to only import the required implementation */ -export async function createWorker(workerPath: string & Blob, options: CreateWorkerOptions) { +/** + * async function to creat a webworker. This function uses dynamic imports to only import the required implementation + * @param workerPath the path or Blob to the worker code + * @param backend backend for the threads + * @param {CreateWorkerOptions} options an object that can be used to specify `blob: boolean` or other {WorkerOptions}. Defaults to `{}`. + */ +export async function createWorker(workerPath: string & Blob, backend: "web" | "node" | "tiny", options: CreateWorkerOptions = {}) { let WorkerConstructor: typeof WorkerImplementation | typeof BlobWorker - if (options.backend === "web") { + if (backend === "web") { const { getWorkerImplementation } = await import("./master/implementation.browser") WorkerConstructor = options.blob ? getWorkerImplementation().blob : getWorkerImplementation().default - } else if (options.backend === "node") { + } else if (backend === "node") { const { getWorkerImplementation } = await import("./master/implementation-node") WorkerConstructor = options.blob ? getWorkerImplementation("node").blob : getWorkerImplementation("node").default - } else if (options.backend === "tiny") { + } else if (backend === "tiny") { const { getWorkerImplementation } = await import("./master/implementation-node") WorkerConstructor = options.blob ? getWorkerImplementation("tiny").blob : diff --git a/src/types/master.ts b/src/types/master.ts index cf0a140d..0a21764d 100644 --- a/src/types/master.ts +++ b/src/types/master.ts @@ -89,10 +89,8 @@ export interface ThreadsWorkerOptions extends WorkerOptions { } export interface CreateWorkerOptions extends ThreadsWorkerOptions { - /** backend for the threads */ - backend: "web" | "node" | "tiny" /** flag to return a BlobWorker */ - blob: boolean + blob?: boolean } /** Worker implementation. Either web worker or a node.js Worker class. */ diff --git a/test/rollup/app-createWorker.js b/test/rollup/app-createWorker.js index a6cd9484..c3fd9fce 100644 --- a/test/rollup/app-createWorker.js +++ b/test/rollup/app-createWorker.js @@ -2,7 +2,7 @@ import { createWorker } from "../../createWorker.mjs" import { spawn, Thread } from "../../" async function run() { - const add = await spawn(await createWorker("./worker.js", {backend: "node"})) + const add = await spawn(await createWorker("./worker.js", "node")) const result = await add(2, 3) await Thread.terminate(add) return result From d813a9c80b226309536fc0053111de0a293dc44e Mon Sep 17 00:00:00 2001 From: Amin Yahyaabadi Date: Sat, 27 Mar 2021 10:32:13 -0500 Subject: [PATCH 17/21] Directly import the implementation function --- src/createWorker.ts | 12 ++++++------ src/master/implementation-node.ts | 10 ++++------ 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/src/createWorker.ts b/src/createWorker.ts index 215e7dfe..37aba458 100644 --- a/src/createWorker.ts +++ b/src/createWorker.ts @@ -18,15 +18,15 @@ export async function createWorker(workerPath: string & Blob, backend: "web" | " getWorkerImplementation().blob : getWorkerImplementation().default } else if (backend === "node") { - const { getWorkerImplementation } = await import("./master/implementation-node") + const { initWorkerThreadsWorker } = await import("./master/implementation-node") WorkerConstructor = options.blob ? - getWorkerImplementation("node").blob : - getWorkerImplementation("node").default + initWorkerThreadsWorker().blob : + initWorkerThreadsWorker().default } else if (backend === "tiny") { - const { getWorkerImplementation } = await import("./master/implementation-node") + const { initTinyWorker } = await import("./master/implementation-node") WorkerConstructor = options.blob ? - getWorkerImplementation("tiny").blob : - getWorkerImplementation("tiny").default + initTinyWorker().blob : + initTinyWorker().default } else { throw new Error("The worker backend is not supported.") } diff --git a/src/master/implementation-node.ts b/src/master/implementation-node.ts index d4c3d21f..799a5717 100644 --- a/src/master/implementation-node.ts +++ b/src/master/implementation-node.ts @@ -88,7 +88,8 @@ function resolveScriptPath(scriptPath: string, baseURL?: string | undefined) { return workerFilePath } -function initWorkerThreadsWorker(): ImplementationExport { +export function initWorkerThreadsWorker(): ImplementationExport { + isTinyWorker = false // Webpack hack const NativeWorker = typeof __non_webpack_require__ === "function" ? __non_webpack_require__("worker_threads").Worker @@ -164,7 +165,8 @@ function initWorkerThreadsWorker(): ImplementationExport { } } -function initTinyWorker(): ImplementationExport { +export function initTinyWorker(): ImplementationExport { + isTinyWorker = true const TinyWorker = require("tiny-worker") let allWorkers: Array = [] @@ -253,21 +255,17 @@ function selectWorkerImplementation(selection?: string): ImplementationExport { // automatic version based selection try { - isTinyWorker = false return initWorkerThreadsWorker() } catch(error) { // tslint:disable-next-line no-console console.debug("Node worker_threads not available. Trying to fall back to tiny-worker polyfill...") - isTinyWorker = true return initTinyWorker() } // manual selection } else if (selection === "node") { - isTinyWorker = false return initWorkerThreadsWorker() } else if (selection === "tiny") { - isTinyWorker = true return initTinyWorker() } else { throw new Error("selection is not supported" + selection) From 93eb19eb15793c517c34a27ff5cd89014d46bb38 Mon Sep 17 00:00:00 2001 From: Amin Yahyaabadi Date: Mon, 29 Mar 2021 14:55:02 -0500 Subject: [PATCH 18/21] Move app-createWorker test to test-tooling folder --- {test => test-tooling}/rollup/app-createWorker.js | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename {test => test-tooling}/rollup/app-createWorker.js (100%) diff --git a/test/rollup/app-createWorker.js b/test-tooling/rollup/app-createWorker.js similarity index 100% rename from test/rollup/app-createWorker.js rename to test-tooling/rollup/app-createWorker.js From faceacab34c9fc8d2bbf3e581b9126890f9a319f Mon Sep 17 00:00:00 2001 From: Amin Yahyaabadi Date: Fri, 30 Apr 2021 05:41:18 -0500 Subject: [PATCH 19/21] Add types for root level index --- index.d.ts | 1 + 1 file changed, 1 insertion(+) create mode 100644 index.d.ts diff --git a/index.d.ts b/index.d.ts new file mode 100644 index 00000000..bdd85a3d --- /dev/null +++ b/index.d.ts @@ -0,0 +1 @@ +export { registerSerializer, spawn, DefaultSerializer, Pool, Thread, Transfer, Worker } from "./src/index.js" From c4e0a577462ea523c783c3a574c1fbaf38da844b Mon Sep 17 00:00:00 2001 From: Amin Yahyaabadi Date: Fri, 30 Apr 2021 05:41:47 -0500 Subject: [PATCH 20/21] Add documentation for createWorker return --- src/createWorker.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/createWorker.ts b/src/createWorker.ts index 37aba458..5eb67aa2 100644 --- a/src/createWorker.ts +++ b/src/createWorker.ts @@ -9,8 +9,9 @@ import { * @param workerPath the path or Blob to the worker code * @param backend backend for the threads * @param {CreateWorkerOptions} options an object that can be used to specify `blob: boolean` or other {WorkerOptions}. Defaults to `{}`. + * @returns A web worker, a node.js worker, or a tiny worker class. */ -export async function createWorker(workerPath: string & Blob, backend: "web" | "node" | "tiny", options: CreateWorkerOptions = {}) { +export async function createWorker(workerPath: string | Blob, backend: "web" | "node" | "tiny", options: CreateWorkerOptions = {}) { let WorkerConstructor: typeof WorkerImplementation | typeof BlobWorker if (backend === "web") { const { getWorkerImplementation } = await import("./master/implementation.browser") @@ -30,5 +31,5 @@ export async function createWorker(workerPath: string & Blob, backend: "web" | " } else { throw new Error("The worker backend is not supported.") } - return new WorkerConstructor(workerPath, options) + return new WorkerConstructor(workerPath as string & Blob, options) } From 4fdfda96c389f3162c9d9e90bcae03ea026544cf Mon Sep 17 00:00:00 2001 From: Amin Yahyaabadi Date: Fri, 30 Apr 2021 05:41:56 -0500 Subject: [PATCH 21/21] Add createWorker tests --- test/createWorker.test.ts | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 test/createWorker.test.ts diff --git a/test/createWorker.test.ts b/test/createWorker.test.ts new file mode 100644 index 00000000..952d2a0e --- /dev/null +++ b/test/createWorker.test.ts @@ -0,0 +1,27 @@ +import test from "ava" +import { createWorker } from '../src/createWorker' +import { spawn, Thread } from "../src/index" + +test("createWorker web", async t => { + const worker = await createWorker("./workers/hello-world", "web") + const helloWorld = await spawn(worker) + t.is(await helloWorld(), "Hello World") + await Thread.terminate(helloWorld) + t.pass() +}) + +test("createWorker node", async t => { + const worker = await createWorker("./workers/hello-world", "node") + const helloWorld = await spawn(worker) + t.is(await helloWorld(), "Hello World") + await Thread.terminate(helloWorld) + t.pass() +}) + +test("createWorker tiny", async t => { + const worker = await createWorker("./workers/hello-world", "tiny") + const helloWorld = await spawn(worker) + t.is(await helloWorld(), "Hello World") + await Thread.terminate(helloWorld) + t.pass() +})