@b9g/node-webworker 0.1.2

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 ADDED
@@ -0,0 +1,60 @@
1
+ # @b9g/node-webworker
2
+
3
+ Minimal Web Worker shim for Node.js until native support arrives.
4
+
5
+ ## Why This Package Exists
6
+
7
+ Node.js lacks native Web Worker support, despite being a web standard since 2009. This package provides a minimal, reliable shim using Node.js `worker_threads` until native support is added.
8
+
9
+ **🔗 Canonical Issue:** https://github.com/nodejs/node/issues/43583
10
+ **Please 👍 and comment** on the issue to show demand for native Web Worker support!
11
+
12
+ ## Installation
13
+
14
+ ```bash
15
+ npm install @b9g/node-webworker
16
+ ```
17
+
18
+ ## Usage
19
+
20
+ ```typescript
21
+ import { Worker } from '@b9g/node-webworker';
22
+
23
+ // Create a worker (same API as Web Workers)
24
+ const worker = new Worker('./worker.js', { type: 'module' });
25
+
26
+ // Listen for messages
27
+ worker.addEventListener('message', (event) => {
28
+ console.log('Received:', event.data);
29
+ });
30
+
31
+ // Send a message
32
+ worker.postMessage({ hello: 'world' });
33
+
34
+ // Terminate when done
35
+ await worker.terminate();
36
+ ```
37
+
38
+ ## Features
39
+
40
+ - ✅ **Standards-compliant API** - Drop-in replacement for Web Workers
41
+ - ✅ **ES Module support** - Works with modern JavaScript
42
+ - ✅ **Minimal overhead** - Thin wrapper around `worker_threads`
43
+ - ✅ **Error handling** - Proper event forwarding
44
+ - ✅ **Clean termination** - Resource cleanup
45
+
46
+ ## Limitations
47
+
48
+ - **Transferable objects** - Limited support (logs warning)
49
+ - **Node.js only** - Don't use this in browsers (they have native Web Workers)
50
+ - **Basic API** - Only core Worker features, not full spec
51
+
52
+ ## Deprecation Notice
53
+
54
+ ⚠️ **This package will be deprecated** once Node.js implements native Web Workers.
55
+
56
+ We maintain this as a temporary workaround. Please help push for native support by engaging with [nodejs/node#43583](https://github.com/nodejs/node/issues/43583).
57
+
58
+ ## License
59
+
60
+ MIT
package/package.json ADDED
@@ -0,0 +1,47 @@
1
+ {
2
+ "name": "@b9g/node-webworker",
3
+ "version": "0.1.2",
4
+ "description": "Minimal Web Worker shim for Node.js until native support arrives",
5
+ "keywords": [
6
+ "worker",
7
+ "web-worker",
8
+ "node",
9
+ "shim",
10
+ "temporary"
11
+ ],
12
+ "dependencies": {},
13
+ "devDependencies": {
14
+ "@b9g/libuild": "^0.1.11",
15
+ "bun-types": "latest",
16
+ "@types/node": "^18.0.0"
17
+ },
18
+ "engines": {
19
+ "node": ">=18.0.0"
20
+ },
21
+ "type": "module",
22
+ "types": "src/index.d.ts",
23
+ "module": "src/index.js",
24
+ "exports": {
25
+ ".": {
26
+ "types": "./src/index.d.ts",
27
+ "import": "./src/index.js"
28
+ },
29
+ "./package.json": "./package.json",
30
+ "./index": {
31
+ "types": "./src/index.d.ts",
32
+ "import": "./src/index.js"
33
+ },
34
+ "./index.js": {
35
+ "types": "./src/index.d.ts",
36
+ "import": "./src/index.js"
37
+ },
38
+ "./worker-wrapper": {
39
+ "types": "./src/worker-wrapper.d.ts",
40
+ "import": "./src/worker-wrapper.js"
41
+ },
42
+ "./worker-wrapper.js": {
43
+ "types": "./src/worker-wrapper.d.ts",
44
+ "import": "./src/worker-wrapper.js"
45
+ }
46
+ }
47
+ }
package/src/index.d.ts ADDED
@@ -0,0 +1,60 @@
1
+ /**
2
+ * @b9g/node-webworker - Minimal Web Worker shim for Node.js
3
+ *
4
+ * This package provides a minimal Web Worker API implementation for Node.js
5
+ * until native Web Worker support is added to Node.js core.
6
+ *
7
+ * @see https://github.com/nodejs/node/issues/43583
8
+ */
9
+ import { Worker as NodeWorker } from 'worker_threads';
10
+ /**
11
+ * Event-like object for message events
12
+ */
13
+ export interface MessageEvent {
14
+ readonly data: any;
15
+ readonly type: 'message';
16
+ }
17
+ /**
18
+ * Error event object
19
+ */
20
+ export interface ErrorEvent {
21
+ readonly error: Error;
22
+ readonly type: 'error';
23
+ }
24
+ /**
25
+ * Web Worker API implementation using Node.js worker_threads
26
+ *
27
+ * This provides a minimal, standards-compliant interface that maps
28
+ * to Node.js worker_threads underneath.
29
+ */
30
+ export declare class Worker {
31
+ private nodeWorker;
32
+ private messageListeners;
33
+ private errorListeners;
34
+ constructor(scriptURL: string, options?: {
35
+ type?: 'classic' | 'module';
36
+ });
37
+ /**
38
+ * Send a message to the worker
39
+ */
40
+ postMessage(message: any, transfer?: Transferable[]): void;
41
+ /**
42
+ * Add an event listener (Web Worker API)
43
+ */
44
+ addEventListener(type: 'message', listener: (event: MessageEvent) => void): void;
45
+ addEventListener(type: 'error', listener: (event: ErrorEvent) => void): void;
46
+ /**
47
+ * Remove an event listener
48
+ */
49
+ removeEventListener(type: 'message', listener: (event: MessageEvent) => void): void;
50
+ removeEventListener(type: 'error', listener: (event: ErrorEvent) => void): void;
51
+ /**
52
+ * Terminate the worker
53
+ */
54
+ terminate(): Promise<number>;
55
+ /**
56
+ * Get the underlying Node.js Worker (for advanced usage)
57
+ */
58
+ get nodeWorker_(): NodeWorker;
59
+ }
60
+ export default Worker;
package/src/index.js ADDED
@@ -0,0 +1,87 @@
1
+ /// <reference types="./index.d.ts" />
2
+ // src/index.ts
3
+ import { Worker as NodeWorker } from "worker_threads";
4
+ import { fileURLToPath } from "url";
5
+ import { dirname, join } from "path";
6
+ var Worker = class {
7
+ nodeWorker;
8
+ messageListeners = /* @__PURE__ */ new Set();
9
+ errorListeners = /* @__PURE__ */ new Set();
10
+ constructor(scriptURL, options) {
11
+ const __filename = fileURLToPath(import.meta.url);
12
+ const __dirname = dirname(__filename);
13
+ const wrapperScript = join(__dirname, "worker-wrapper.js");
14
+ this.nodeWorker = new NodeWorker(wrapperScript, {
15
+ type: "module",
16
+ env: {
17
+ ...process.env,
18
+ WORKER_SCRIPT_URL: scriptURL
19
+ }
20
+ });
21
+ this.nodeWorker.on("message", (data) => {
22
+ const event = { data, type: "message" };
23
+ this.messageListeners.forEach((listener) => {
24
+ try {
25
+ listener(event);
26
+ } catch (error) {
27
+ console.error("[node-webworker] Error in message listener:", error);
28
+ }
29
+ });
30
+ });
31
+ this.nodeWorker.on("error", (error) => {
32
+ const event = { error, type: "error" };
33
+ this.errorListeners.forEach((listener) => {
34
+ try {
35
+ listener(event);
36
+ } catch (listenerError) {
37
+ console.error("[node-webworker] Error in error listener:", listenerError);
38
+ }
39
+ });
40
+ });
41
+ }
42
+ /**
43
+ * Send a message to the worker
44
+ */
45
+ postMessage(message, transfer) {
46
+ if (transfer && transfer.length > 0) {
47
+ console.warn("[node-webworker] Transferable objects not fully supported");
48
+ }
49
+ this.nodeWorker.postMessage(message);
50
+ }
51
+ addEventListener(type, listener) {
52
+ if (type === "message") {
53
+ this.messageListeners.add(listener);
54
+ } else if (type === "error") {
55
+ this.errorListeners.add(listener);
56
+ } else {
57
+ console.warn(`[node-webworker] Unsupported event type: ${type}`);
58
+ }
59
+ }
60
+ removeEventListener(type, listener) {
61
+ if (type === "message") {
62
+ this.messageListeners.delete(listener);
63
+ } else if (type === "error") {
64
+ this.errorListeners.delete(listener);
65
+ }
66
+ }
67
+ /**
68
+ * Terminate the worker
69
+ */
70
+ async terminate() {
71
+ const exitCode = await this.nodeWorker.terminate();
72
+ this.messageListeners.clear();
73
+ this.errorListeners.clear();
74
+ return exitCode;
75
+ }
76
+ /**
77
+ * Get the underlying Node.js Worker (for advanced usage)
78
+ */
79
+ get nodeWorker_() {
80
+ return this.nodeWorker;
81
+ }
82
+ };
83
+ var src_default = Worker;
84
+ export {
85
+ Worker,
86
+ src_default as default
87
+ };
@@ -0,0 +1,15 @@
1
+ // src/worker-wrapper.js
2
+ import { parentPort } from "worker_threads";
3
+ globalThis.onmessage = null;
4
+ globalThis.postMessage = (data) => parentPort.postMessage(data);
5
+ parentPort.on("message", (data) => {
6
+ if (globalThis.onmessage) {
7
+ globalThis.onmessage({ data, type: "message" });
8
+ }
9
+ });
10
+ var WORKER_SCRIPT_URL = process.env.WORKER_SCRIPT_URL;
11
+ if (WORKER_SCRIPT_URL) {
12
+ await import(WORKER_SCRIPT_URL);
13
+ } else {
14
+ throw new Error("WORKER_SCRIPT_URL environment variable not set");
15
+ }