@@ -5,7 +5,11 @@ import getCallsites, { CallSite } from "callsites"
5
5
import EventEmitter from "events"
6
6
import { cpus } from 'os'
7
7
import * as path from "path"
8
- import { ThreadsWorkerOptions , WorkerImplementation } from "../types/master"
8
+ import {
9
+ ImplementationExport ,
10
+ ThreadsWorkerOptions ,
11
+ WorkerImplementation
12
+ } from "../types/master"
9
13
10
14
interface WorkerGlobalScope {
11
15
addEventListener ( eventName : string , listener : ( event : Event ) => void ) : void
@@ -84,7 +88,7 @@ function resolveScriptPath(scriptPath: string, baseURL?: string | undefined) {
84
88
return workerFilePath
85
89
}
86
90
87
- function initWorkerThreadsWorker ( ) : typeof WorkerImplementation {
91
+ function initWorkerThreadsWorker ( ) : ImplementationExport {
88
92
// Webpack hack
89
93
const NativeWorker = typeof __non_webpack_require__ === "function"
90
94
? __non_webpack_require__ ( "worker_threads" ) . Worker
@@ -95,10 +99,16 @@ function initWorkerThreadsWorker(): typeof WorkerImplementation {
95
99
class Worker extends NativeWorker {
96
100
private mappedEventListeners : WeakMap < EventListener , EventListener >
97
101
98
- constructor ( scriptPath : string , options ?: ThreadsWorkerOptions ) {
99
- const resolvedScriptPath = resolveScriptPath ( scriptPath , ( options || { } ) . _baseURL )
102
+ constructor ( scriptPath : string , options ?: ThreadsWorkerOptions & { fromSource : boolean } ) {
103
+ const resolvedScriptPath = options && options . fromSource
104
+ ? null
105
+ : resolveScriptPath ( scriptPath , ( options || { } ) . _baseURL )
100
106
101
- if ( resolvedScriptPath . match ( / \. t s x ? $ / i) && detectTsNode ( ) ) {
107
+ if ( ! resolvedScriptPath ) {
108
+ // `options.fromSource` is true
109
+ const sourceCode = scriptPath
110
+ super ( sourceCode , { ...options , eval : true } )
111
+ } else if ( resolvedScriptPath . match ( / \. t s x ? $ / i) && detectTsNode ( ) ) {
102
112
super ( createTsNodeModule ( resolvedScriptPath ) , { ...options , eval : true } )
103
113
} else if ( resolvedScriptPath . match ( / \. a s a r [ \/ \\ ] / ) ) {
104
114
// See <https://github.com/andywer/threads-plugin/issues/17>
@@ -138,25 +148,44 @@ function initWorkerThreadsWorker(): typeof WorkerImplementation {
138
148
process . on ( "SIGINT" , ( ) => terminateWorkersAndMaster ( ) )
139
149
process . on ( "SIGTERM" , ( ) => terminateWorkersAndMaster ( ) )
140
150
141
- return Worker as any
151
+ class BlobWorker extends Worker {
152
+ constructor ( blob : Uint8Array , options ?: ThreadsWorkerOptions ) {
153
+ super ( Buffer . from ( blob ) . toString ( "utf-8" ) , { ...options , fromSource : true } )
154
+ }
155
+
156
+ public static fromText ( source : string , options ?: ThreadsWorkerOptions ) : WorkerImplementation {
157
+ return new Worker ( source , { ...options , fromSource : true } ) as any
158
+ }
159
+ }
160
+
161
+ return {
162
+ blob : BlobWorker as any ,
163
+ default : Worker as any
164
+ }
142
165
}
143
166
144
- function initTinyWorker ( ) : typeof WorkerImplementation {
167
+ function initTinyWorker ( ) : ImplementationExport {
145
168
const TinyWorker = require ( "tiny-worker" )
146
169
147
170
let allWorkers : Array < typeof TinyWorker > = [ ]
148
171
149
172
class Worker extends TinyWorker {
150
173
private emitter : EventEmitter
151
174
152
- constructor ( scriptPath : string ) {
175
+ constructor ( scriptPath : string , options ?: ThreadsWorkerOptions & { fromSource ?: boolean } ) {
153
176
// Need to apply a work-around for Windows or it will choke upon the absolute path
154
177
// (`Error [ERR_INVALID_PROTOCOL]: Protocol 'c:' not supported`)
155
- const resolvedScriptPath = process . platform === "win32"
156
- ? `file:///${ resolveScriptPath ( scriptPath ) . replace ( / \\ / g, "/" ) } `
157
- : resolveScriptPath ( scriptPath )
158
-
159
- if ( resolvedScriptPath . match ( / \. t s x ? $ / i) && detectTsNode ( ) ) {
178
+ const resolvedScriptPath = options && options . fromSource
179
+ ? null
180
+ : process . platform === "win32"
181
+ ? `file:///${ resolveScriptPath ( scriptPath ) . replace ( / \\ / g, "/" ) } `
182
+ : resolveScriptPath ( scriptPath )
183
+
184
+ if ( ! resolvedScriptPath ) {
185
+ // `options.fromSource` is true
186
+ const sourceCode = scriptPath
187
+ super ( new Function ( sourceCode ) , [ ] , { esm : true } )
188
+ } else if ( resolvedScriptPath . match ( / \. t s x ? $ / i) && detectTsNode ( ) ) {
160
189
super ( new Function ( createTsNodeModule ( resolveScriptPath ( scriptPath ) ) ) , [ ] , { esm : true } )
161
190
} else if ( resolvedScriptPath . match ( / \. a s a r [ \/ \\ ] / ) ) {
162
191
// See <https://github.com/andywer/threads-plugin/issues/17>
@@ -171,12 +200,15 @@ function initTinyWorker(): typeof WorkerImplementation {
171
200
this . onerror = ( error : Error ) => this . emitter . emit ( "error" , error )
172
201
this . onmessage = ( message : MessageEvent ) => this . emitter . emit ( "message" , message )
173
202
}
203
+
174
204
public addEventListener ( eventName : WorkerEventName , listener : EventListener ) {
175
205
this . emitter . addListener ( eventName , listener )
176
206
}
207
+
177
208
public removeEventListener ( eventName : WorkerEventName , listener : EventListener ) {
178
209
this . emitter . removeListener ( eventName , listener )
179
210
}
211
+
180
212
public terminate ( ) {
181
213
allWorkers = allWorkers . filter ( worker => worker !== this )
182
214
return super . terminate ( )
@@ -197,13 +229,26 @@ function initTinyWorker(): typeof WorkerImplementation {
197
229
process . on ( "SIGINT" , ( ) => terminateWorkersAndMaster ( ) )
198
230
process . on ( "SIGTERM" , ( ) => terminateWorkersAndMaster ( ) )
199
231
200
- return Worker as any
232
+ class BlobWorker extends Worker {
233
+ constructor ( blob : Uint8Array , options ?: ThreadsWorkerOptions ) {
234
+ super ( Buffer . from ( blob ) . toString ( "utf-8" ) , { ...options , fromSource : true } )
235
+ }
236
+
237
+ public static fromText ( source : string , options ?: ThreadsWorkerOptions ) : WorkerImplementation {
238
+ return new Worker ( source , { ...options , fromSource : true } ) as any
239
+ }
240
+ }
241
+
242
+ return {
243
+ blob : BlobWorker as any ,
244
+ default : Worker as any
245
+ }
201
246
}
202
247
203
- let implementation : typeof WorkerImplementation
248
+ let implementation : ImplementationExport
204
249
let isTinyWorker : boolean
205
250
206
- function selectWorkerImplementation ( ) : typeof WorkerImplementation {
251
+ function selectWorkerImplementation ( ) : ImplementationExport {
207
252
try {
208
253
isTinyWorker = false
209
254
return initWorkerThreadsWorker ( )
@@ -215,7 +260,7 @@ function selectWorkerImplementation(): typeof WorkerImplementation {
215
260
}
216
261
}
217
262
218
- export function getWorkerImplementation ( ) : typeof WorkerImplementation {
263
+ export function getWorkerImplementation ( ) : ImplementationExport {
219
264
if ( ! implementation ) {
220
265
implementation = selectWorkerImplementation ( )
221
266
}
0 commit comments