Skip to content

Commit 73c9daa

Browse files
authored
Expose isWorkerRuntime() function (#228)
1 parent 76fe60f commit 73c9daa

File tree

7 files changed

+74
-9
lines changed

7 files changed

+74
-9
lines changed

src/master/implementation.browser.ts

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,7 @@ function createSourceBlobURL(code: string): string {
1717
return URL.createObjectURL(blob)
1818
}
1919

20-
21-
export function selectWorkerImplementation(): typeof WorkerImplementation {
20+
function selectWorkerImplementation(): typeof WorkerImplementation {
2221
if (typeof Worker === "undefined") {
2322
// Might happen on Safari, for instance
2423
// The idea is to only fail if the constructor is actually used
@@ -46,3 +45,17 @@ export function selectWorkerImplementation(): typeof WorkerImplementation {
4645
}
4746
}
4847
}
48+
49+
let implementation: typeof WorkerImplementation
50+
51+
export function getWorkerImplementation(): typeof WorkerImplementation {
52+
if (!implementation) {
53+
implementation = selectWorkerImplementation()
54+
}
55+
return implementation
56+
}
57+
58+
export function isWorkerRuntime() {
59+
const isWindowContext = typeof self !== "undefined" && typeof Window !== "undefined" && self instanceof Window
60+
return typeof self !== "undefined" && self.postMessage && !isWindowContext ? true : false
61+
}

src/master/implementation.node.ts

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
/// <reference lib="dom" />
12
// tslint:disable function-constructor no-eval no-duplicate-super max-classes-per-file
23

34
import getCallsites, { CallSite } from "callsites"
@@ -6,7 +7,14 @@ import { cpus } from 'os'
67
import * as path from "path"
78
import { ThreadsWorkerOptions, WorkerImplementation } from "../types/master"
89

10+
interface WorkerGlobalScope {
11+
addEventListener(eventName: string, listener: (event: Event) => void): void
12+
postMessage(message: any, transferables?: any[]): void
13+
removeEventListener(eventName: string, listener: (event: Event) => void): void
14+
}
15+
916
declare const __non_webpack_require__: typeof require
17+
declare const self: WorkerGlobalScope
1018

1119
type WorkerEventName = "error" | "message"
1220

@@ -191,12 +199,36 @@ function initTinyWorker(): typeof WorkerImplementation {
191199
return Worker as any
192200
}
193201

194-
export function selectWorkerImplementation(): typeof WorkerImplementation {
202+
let implementation: typeof WorkerImplementation
203+
let isTinyWorker: boolean
204+
205+
function selectWorkerImplementation(): typeof WorkerImplementation {
195206
try {
207+
isTinyWorker = false
196208
return initWorkerThreadsWorker()
197209
} catch(error) {
198210
// tslint:disable-next-line no-console
199211
console.debug("Node worker_threads not available. Trying to fall back to tiny-worker polyfill...")
212+
isTinyWorker = true
200213
return initTinyWorker()
201214
}
202215
}
216+
217+
export function getWorkerImplementation(): typeof WorkerImplementation {
218+
if (!implementation) {
219+
implementation = selectWorkerImplementation()
220+
}
221+
return implementation
222+
}
223+
224+
export function isWorkerRuntime() {
225+
if (isTinyWorker) {
226+
return typeof self !== "undefined" && self.postMessage ? true : false
227+
} else {
228+
// Webpack hack
229+
const isMainThread = typeof __non_webpack_require__ === "function"
230+
? __non_webpack_require__("worker_threads").isMainThread
231+
: eval("require")("worker_threads").isMainThread
232+
return !isMainThread
233+
}
234+
}

src/master/implementation.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,10 @@ import * as NodeImplementation from "./implementation.node"
1212
const runningInNode = typeof process !== 'undefined' && process.arch !== 'browser' && 'pid' in process
1313
const implementation = runningInNode ? NodeImplementation : BrowserImplementation
1414

15+
/** Default size of pools. Depending on the platform the value might vary from device to device. */
1516
export const defaultPoolSize = implementation.defaultPoolSize
16-
export const selectWorkerImplementation = implementation.selectWorkerImplementation
17+
18+
export const getWorkerImplementation = implementation.getWorkerImplementation
19+
20+
/** Returns `true` if this code is currently running in a worker. */
21+
export const isWorkerRuntime = implementation.isWorkerRuntime

src/master/index.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
import { Worker as WorkerType } from "../types/master"
2-
import { selectWorkerImplementation } from "./implementation"
2+
import { getWorkerImplementation, isWorkerRuntime } from "./implementation"
33

44
export { FunctionThread, ModuleThread } from "../types/master"
55
export { Pool } from "./pool"
66
export { spawn } from "./spawn"
77
export { Thread } from "./thread"
8+
export { isWorkerRuntime }
89

910
export type Worker = WorkerType
1011

1112
/** Worker implementation. Either web worker or a node.js Worker class. */
12-
export const Worker = selectWorkerImplementation()
13+
export const Worker = getWorkerImplementation()

src/worker/index.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@ import Implementation from "./implementation"
1919
export { registerSerializer } from "../common"
2020
export { Transfer } from "../transferable"
2121

22+
/** Returns `true` if this code is currently running in a worker. */
23+
export const isWorkerRuntime = Implementation.isWorkerRuntime
24+
2225
let exposeCalled = false
2326

2427
const isMasterJobRunMessage = (thing: any): thing is MasterJobRunMessage => thing && thing.type === MasterMessageType.run

test/webpack/addition-worker.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1-
import { expose } from "../../src/worker"
1+
import { expose, isWorkerRuntime } from "../../src/worker"
2+
3+
if (!isWorkerRuntime()) {
4+
throw Error("isWorkerRuntime() says we are not in a worker.")
5+
}
26

37
expose(function add(a: number, b: number) {
48
return a + b

test/webpack/app.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { spawn, Pool, Worker } from "../../src/index"
1+
import { isWorkerRuntime, spawn, Pool, Worker } from "../../src/index"
22

33
type AdditionWorker = (a: number, b: number) => number
44
type HelloWorker = (text: string) => string
@@ -46,8 +46,15 @@ async function test3() {
4646
}
4747
}
4848

49+
function test4() {
50+
if (isWorkerRuntime() !== false) {
51+
throw Error("Expected isWorkerRuntime() to return false. Got: " + isWorkerRuntime())
52+
}
53+
}
54+
4955
export default () => Promise.all([
5056
test(),
5157
test2(),
52-
test3()
58+
test3(),
59+
test4()
5360
])

0 commit comments

Comments
 (0)