@parcel/workers 2.0.0-nightly.97 → 2.1.0

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/src/WorkerFarm.js CHANGED
@@ -20,7 +20,7 @@ import {
20
20
  restoreDeserializedObject,
21
21
  serialize,
22
22
  } from '@parcel/core';
23
- import ThrowableDiagnostic, {anyToDiagnostic} from '@parcel/diagnostic';
23
+ import ThrowableDiagnostic, {anyToDiagnostic, md} from '@parcel/diagnostic';
24
24
  import Worker, {type WorkerCall} from './Worker';
25
25
  import cpuCount from './cpuCount';
26
26
  import Handle from './Handle';
@@ -31,9 +31,10 @@ import Trace from './Trace';
31
31
  import fs from 'fs';
32
32
  import logger from '@parcel/logger';
33
33
 
34
- let profileId = 1;
35
34
  let referenceId = 1;
36
35
 
36
+ export opaque type SharedReference = number;
37
+
37
38
  export type FarmOptions = {|
38
39
  maxConcurrentWorkers: number,
39
40
  maxConcurrentCallsPerWorker: number,
@@ -42,7 +43,7 @@ export type FarmOptions = {|
42
43
  warmWorkers: boolean,
43
44
  workerPath?: FilePath,
44
45
  backend: BackendType,
45
- patchConsole?: boolean,
46
+ shouldPatchConsole?: boolean,
46
47
  |};
47
48
 
48
49
  type WorkerModule = {|
@@ -52,8 +53,8 @@ type WorkerModule = {|
52
53
  export type WorkerApi = {|
53
54
  callMaster(CallRequest, ?boolean): Promise<mixed>,
54
55
  createReverseHandle(fn: HandleFunction): Handle,
55
- getSharedReference(ref: number): mixed,
56
- resolveSharedReference(value: mixed): ?number,
56
+ getSharedReference(ref: SharedReference): mixed,
57
+ resolveSharedReference(value: mixed): ?SharedReference,
57
58
  callChild?: (childId: number, request: HandleCallRequest) => Promise<mixed>,
58
59
  |};
59
60
 
@@ -67,13 +68,14 @@ export default class WorkerFarm extends EventEmitter {
67
68
  callQueue: Array<WorkerCall> = [];
68
69
  ending: boolean = false;
69
70
  localWorker: WorkerModule;
71
+ localWorkerInit: ?Promise<void>;
70
72
  options: FarmOptions;
71
73
  run: HandleFunction;
72
74
  warmWorkers: number = 0;
73
75
  workers: Map<number, Worker> = new Map();
74
76
  handles: Map<number, Handle> = new Map();
75
- sharedReferences: Map<number, mixed> = new Map();
76
- sharedReferencesByValue: Map<mixed, number> = new Map();
77
+ sharedReferences: Map<SharedReference, mixed> = new Map();
78
+ sharedReferencesByValue: Map<mixed, SharedReference> = new Map();
77
79
  profiler: ?Profiler;
78
80
 
79
81
  constructor(farmOptions: $Shape<FarmOptions> = {}) {
@@ -94,12 +96,24 @@ export default class WorkerFarm extends EventEmitter {
94
96
 
95
97
  // $FlowFixMe this must be dynamic
96
98
  this.localWorker = require(this.options.workerPath);
99
+ this.localWorkerInit =
100
+ this.localWorker.childInit != null ? this.localWorker.childInit() : null;
97
101
  this.run = this.createHandle('run');
98
102
 
99
103
  this.startMaxWorkers();
100
104
  }
101
105
 
102
- workerApi = {
106
+ workerApi: {|
107
+ callChild: (childId: number, request: HandleCallRequest) => Promise<mixed>,
108
+ callMaster: (
109
+ request: CallRequest,
110
+ awaitResponse?: ?boolean,
111
+ ) => Promise<mixed>,
112
+ createReverseHandle: (fn: HandleFunction) => Handle,
113
+ getSharedReference: (ref: SharedReference) => mixed,
114
+ resolveSharedReference: (value: mixed) => void | SharedReference,
115
+ runHandle: (handle: Handle, args: Array<any>) => Promise<mixed>,
116
+ |} = {
103
117
  callMaster: async (
104
118
  request: CallRequest,
105
119
  awaitResponse: ?boolean = true,
@@ -122,7 +136,13 @@ export default class WorkerFarm extends EventEmitter {
122
136
  retries: 0,
123
137
  });
124
138
  }),
125
- getSharedReference: (ref: number) => this.sharedReferences.get(ref),
139
+ runHandle: (handle: Handle, args: Array<any>): Promise<mixed> =>
140
+ this.workerApi.callChild(nullthrows(handle.childId), {
141
+ handle: handle.id,
142
+ args,
143
+ }),
144
+ getSharedReference: (ref: SharedReference) =>
145
+ this.sharedReferences.get(ref),
126
146
  resolveSharedReference: (value: mixed) =>
127
147
  this.sharedReferencesByValue.get(value),
128
148
  };
@@ -156,7 +176,7 @@ export default class WorkerFarm extends EventEmitter {
156
176
  }
157
177
 
158
178
  createHandle(method: string): HandleFunction {
159
- return (...args) => {
179
+ return async (...args) => {
160
180
  // Child process workers are slow to start (~600ms).
161
181
  // While we're waiting, just run on the main thread.
162
182
  // This significantly speeds up startup time.
@@ -170,15 +190,22 @@ export default class WorkerFarm extends EventEmitter {
170
190
  let processedArgs = restoreDeserializedObject(
171
191
  prepareForSerialization([...args, false]),
172
192
  );
193
+
194
+ if (this.localWorkerInit != null) {
195
+ await this.localWorkerInit;
196
+ this.localWorkerInit = null;
197
+ }
173
198
  return this.localWorker[method](this.workerApi, ...processedArgs);
174
199
  }
175
200
  };
176
201
  }
177
202
 
178
- onError(error: ErrorWithCode, worker: Worker) {
203
+ onError(error: ErrorWithCode, worker: Worker): void | Promise<void> {
179
204
  // Handle ipc errors
180
205
  if (error.code === 'ERR_IPC_CHANNEL_CLOSED') {
181
206
  return this.stopWorker(worker);
207
+ } else {
208
+ logger.error(error, '@parcel/workers');
182
209
  }
183
210
  }
184
211
 
@@ -186,7 +213,8 @@ export default class WorkerFarm extends EventEmitter {
186
213
  let worker = new Worker({
187
214
  forcedKillTime: this.options.forcedKillTime,
188
215
  backend: this.options.backend,
189
- patchConsole: this.options.patchConsole,
216
+ shouldPatchConsole: this.options.shouldPatchConsole,
217
+ sharedReferences: this.sharedReferences,
190
218
  });
191
219
 
192
220
  worker.fork(nullthrows(this.options.workerPath));
@@ -231,7 +259,11 @@ export default class WorkerFarm extends EventEmitter {
231
259
  this.startChild();
232
260
  }
233
261
 
234
- for (let worker of this.workers.values()) {
262
+ let workers = [...this.workers.values()].sort(
263
+ (a, b) => a.calls.size - b.calls.size,
264
+ );
265
+
266
+ for (let worker of workers) {
235
267
  if (!this.callQueue.length) {
236
268
  break;
237
269
  }
@@ -255,7 +287,7 @@ export default class WorkerFarm extends EventEmitter {
255
287
  let {method, args, location, awaitResponse, idx, handle: handleId} = data;
256
288
  let mod;
257
289
  if (handleId != null) {
258
- mod = nullthrows(this.handles.get(handleId)).fn;
290
+ mod = nullthrows(this.handles.get(handleId)?.fn);
259
291
  } else if (location) {
260
292
  // $FlowFixMe this must be dynamic
261
293
  mod = require(location);
@@ -286,7 +318,6 @@ export default class WorkerFarm extends EventEmitter {
286
318
  }
287
319
  } else {
288
320
  // ESModule default interop
289
- // $FlowFixMe
290
321
  if (mod.__esModule && !mod[method] && mod.default) {
291
322
  mod = mod.default;
292
323
  }
@@ -331,6 +362,10 @@ export default class WorkerFarm extends EventEmitter {
331
362
  async end(): Promise<void> {
332
363
  this.ending = true;
333
364
 
365
+ await Promise.all(
366
+ Array.from(this.workers.values()).map(worker => this.stopWorker(worker)),
367
+ );
368
+
334
369
  for (let handle of this.handles.values()) {
335
370
  handle.dispose();
336
371
  }
@@ -338,9 +373,6 @@ export default class WorkerFarm extends EventEmitter {
338
373
  this.sharedReferences = new Map();
339
374
  this.sharedReferencesByValue = new Map();
340
375
 
341
- await Promise.all(
342
- Array.from(this.workers.values()).map(worker => this.stopWorker(worker)),
343
- );
344
376
  this.ending = false;
345
377
  }
346
378
 
@@ -362,29 +394,28 @@ export default class WorkerFarm extends EventEmitter {
362
394
  );
363
395
  }
364
396
 
365
- createReverseHandle(fn: HandleFunction) {
366
- let handle = new Handle({fn, workerApi: this.workerApi});
397
+ createReverseHandle(fn: HandleFunction): Handle {
398
+ let handle = new Handle({fn});
367
399
  this.handles.set(handle.id, handle);
368
400
  return handle;
369
401
  }
370
402
 
371
- async createSharedReference(value: mixed) {
403
+ async createSharedReference(
404
+ value: mixed,
405
+ // An optional, pre-serialized representation of the value to be used
406
+ // in its place.
407
+ buffer?: Buffer,
408
+ ): Promise<{|ref: SharedReference, dispose(): Promise<mixed>|}> {
372
409
  let ref = referenceId++;
373
410
  this.sharedReferences.set(ref, value);
374
411
  this.sharedReferencesByValue.set(value, ref);
412
+
413
+ let toSend = buffer ? buffer.buffer : value;
375
414
  let promises = [];
376
415
  for (let worker of this.workers.values()) {
377
- promises.push(
378
- new Promise((resolve, reject) => {
379
- worker.call({
380
- method: 'createSharedReference',
381
- args: [ref, value],
382
- resolve,
383
- reject,
384
- retries: 0,
385
- });
386
- }),
387
- );
416
+ if (worker.ready) {
417
+ promises.push(worker.sendSharedReference(ref, toSend));
418
+ }
388
419
  }
389
420
 
390
421
  await Promise.all(promises);
@@ -403,6 +434,7 @@ export default class WorkerFarm extends EventEmitter {
403
434
  args: [ref],
404
435
  resolve,
405
436
  reject,
437
+ skipReadyCheck: true,
406
438
  retries: 0,
407
439
  });
408
440
  }),
@@ -424,6 +456,7 @@ export default class WorkerFarm extends EventEmitter {
424
456
  resolve,
425
457
  reject,
426
458
  retries: 0,
459
+ skipReadyCheck: true,
427
460
  });
428
461
  }),
429
462
  );
@@ -453,6 +486,7 @@ export default class WorkerFarm extends EventEmitter {
453
486
  resolve,
454
487
  reject,
455
488
  retries: 0,
489
+ skipReadyCheck: true,
456
490
  });
457
491
  }),
458
492
  );
@@ -460,7 +494,7 @@ export default class WorkerFarm extends EventEmitter {
460
494
 
461
495
  var profiles = await Promise.all(promises);
462
496
  let trace = new Trace();
463
- let filename = `profile-${profileId++}.trace`;
497
+ let filename = `profile-${getTimeId()}.trace`;
464
498
  let stream = trace.pipe(fs.createWriteStream(filename));
465
499
 
466
500
  for (let profile of profiles) {
@@ -474,21 +508,84 @@ export default class WorkerFarm extends EventEmitter {
474
508
 
475
509
  logger.info({
476
510
  origin: '@parcel/workers',
477
- message: `Wrote profile to ${filename}`,
511
+ message: md`Wrote profile to ${filename}`,
478
512
  });
479
513
  }
480
514
 
481
- static getNumWorkers() {
515
+ async callAllWorkers(method: string, args: Array<any>) {
516
+ let promises = [];
517
+ for (let worker of this.workers.values()) {
518
+ promises.push(
519
+ new Promise((resolve, reject) => {
520
+ worker.call({
521
+ method,
522
+ args,
523
+ resolve,
524
+ reject,
525
+ retries: 0,
526
+ });
527
+ }),
528
+ );
529
+ }
530
+
531
+ promises.push(this.localWorker[method](this.workerApi, ...args));
532
+ await Promise.all(promises);
533
+ }
534
+
535
+ async takeHeapSnapshot() {
536
+ let snapshotId = getTimeId();
537
+
538
+ try {
539
+ let snapshotPaths = await Promise.all(
540
+ [...this.workers.values()].map(
541
+ worker =>
542
+ new Promise((resolve, reject) => {
543
+ worker.call({
544
+ method: 'takeHeapSnapshot',
545
+ args: [snapshotId],
546
+ resolve,
547
+ reject,
548
+ retries: 0,
549
+ skipReadyCheck: true,
550
+ });
551
+ }),
552
+ ),
553
+ );
554
+
555
+ logger.info({
556
+ origin: '@parcel/workers',
557
+ message: md`Wrote heap snapshots to the following paths:\n${snapshotPaths.join(
558
+ '\n',
559
+ )}`,
560
+ });
561
+ } catch {
562
+ logger.error({
563
+ origin: '@parcel/workers',
564
+ message: 'Unable to take heap snapshots. Note: requires Node 11.13.0+',
565
+ });
566
+ }
567
+ }
568
+
569
+ static getNumWorkers(): number {
482
570
  return process.env.PARCEL_WORKERS
483
571
  ? parseInt(process.env.PARCEL_WORKERS, 10)
484
- : cpuCount();
572
+ : Math.ceil(cpuCount() / 2);
485
573
  }
486
574
 
487
- static isWorker() {
575
+ static isWorker(): boolean {
488
576
  return !!child;
489
577
  }
490
578
 
491
- static getWorkerApi() {
579
+ static getWorkerApi(): {|
580
+ callMaster: (
581
+ request: CallRequest,
582
+ awaitResponse?: ?boolean,
583
+ ) => Promise<mixed>,
584
+ createReverseHandle: (fn: (...args: Array<any>) => mixed) => Handle,
585
+ getSharedReference: (ref: SharedReference) => mixed,
586
+ resolveSharedReference: (value: mixed) => void | SharedReference,
587
+ runHandle: (handle: Handle, args: Array<any>) => Promise<mixed>,
588
+ |} {
492
589
  invariant(
493
590
  child != null,
494
591
  'WorkerFarm.getWorkerApi can only be called within workers',
@@ -496,7 +593,20 @@ export default class WorkerFarm extends EventEmitter {
496
593
  return child.workerApi;
497
594
  }
498
595
 
499
- static getConcurrentCallsPerWorker() {
500
- return parseInt(process.env.PARCEL_MAX_CONCURRENT_CALLS, 10) || 5;
596
+ static getConcurrentCallsPerWorker(): number {
597
+ return parseInt(process.env.PARCEL_MAX_CONCURRENT_CALLS, 10) || 30;
501
598
  }
502
599
  }
600
+
601
+ function getTimeId() {
602
+ let now = new Date();
603
+ return (
604
+ String(now.getFullYear()) +
605
+ String(now.getMonth() + 1).padStart(2, '0') +
606
+ String(now.getDate()).padStart(2, '0') +
607
+ '-' +
608
+ String(now.getHours()).padStart(2, '0') +
609
+ String(now.getMinutes()).padStart(2, '0') +
610
+ String(now.getSeconds()).padStart(2, '0')
611
+ );
612
+ }
package/src/backend.js CHANGED
@@ -2,6 +2,12 @@
2
2
  import type {BackendType, WorkerImpl} from './types';
3
3
 
4
4
  export function detectBackend(): BackendType {
5
+ switch (process.env.PARCEL_WORKER_BACKEND) {
6
+ case 'threads':
7
+ case 'process':
8
+ return process.env.PARCEL_WORKER_BACKEND;
9
+ }
10
+
5
11
  try {
6
12
  require('worker_threads');
7
13
  return 'threads';
package/src/bus.js CHANGED
@@ -20,4 +20,4 @@ class Bus extends EventEmitter {
20
20
  }
21
21
  }
22
22
 
23
- export default new Bus();
23
+ export default (new Bus(): Bus);
package/src/child.js CHANGED
@@ -9,16 +9,20 @@ import type {
9
9
  WorkerResponse,
10
10
  ChildImpl,
11
11
  } from './types';
12
- import type {IDisposable} from '@parcel/types';
13
- import type {WorkerApi} from './WorkerFarm';
12
+ import type {Async, IDisposable} from '@parcel/types';
13
+ import type {SharedReference, WorkerApi} from './WorkerFarm';
14
14
 
15
15
  import invariant from 'assert';
16
16
  import nullthrows from 'nullthrows';
17
17
  import Logger, {patchConsole, unpatchConsole} from '@parcel/logger';
18
18
  import ThrowableDiagnostic, {anyToDiagnostic} from '@parcel/diagnostic';
19
+ import {deserialize} from '@parcel/core';
19
20
  import bus from './bus';
20
21
  import Profiler from './Profiler';
21
- import Handle from './Handle';
22
+ import _Handle from './Handle';
23
+
24
+ // The import of './Handle' should really be imported eagerly (with @babel/plugin-transform-modules-commonjs's lazy mode).
25
+ const Handle = _Handle;
22
26
 
23
27
  type ChildCall = WorkerRequest & {|
24
28
  resolve: (result: Promise<any> | any) => void,
@@ -30,20 +34,22 @@ export class Child {
30
34
  childId: ?number;
31
35
  maxConcurrentCalls: number = 10;
32
36
  module: ?any;
33
- responseId = 0;
37
+ responseId: number = 0;
34
38
  responseQueue: Map<number, ChildCall> = new Map();
35
39
  loggerDisposable: IDisposable;
36
40
  child: ChildImpl;
37
41
  profiler: ?Profiler;
38
42
  workerApi: WorkerApi;
39
43
  handles: Map<number, Handle> = new Map();
40
- sharedReferences: Map<number, mixed> = new Map();
41
- sharedReferencesByValue: Map<mixed, number> = new Map();
44
+ sharedReferences: Map<SharedReference, mixed> = new Map();
45
+ sharedReferencesByValue: Map<mixed, SharedReference> = new Map();
42
46
 
43
47
  constructor(ChildBackend: Class<ChildImpl>) {
44
48
  this.child = new ChildBackend(
45
- this.messageListener.bind(this),
46
- this.handleEnd.bind(this),
49
+ m => {
50
+ this.messageListener(m);
51
+ },
52
+ () => this.handleEnd(),
47
53
  );
48
54
 
49
55
  // Monitior all logging events inside this child process and forward to
@@ -53,19 +59,31 @@ export class Child {
53
59
  });
54
60
  }
55
61
 
56
- workerApi = {
62
+ workerApi: {|
63
+ callMaster: (
64
+ request: CallRequest,
65
+ awaitResponse?: ?boolean,
66
+ ) => Promise<mixed>,
67
+ createReverseHandle: (fn: (...args: Array<any>) => mixed) => Handle,
68
+ getSharedReference: (ref: SharedReference) => mixed,
69
+ resolveSharedReference: (value: mixed) => void | SharedReference,
70
+ runHandle: (handle: Handle, args: Array<any>) => Promise<mixed>,
71
+ |} = {
57
72
  callMaster: (
58
73
  request: CallRequest,
59
74
  awaitResponse: ?boolean = true,
60
75
  ): Promise<mixed> => this.addCall(request, awaitResponse),
61
76
  createReverseHandle: (fn: (...args: Array<any>) => mixed): Handle =>
62
77
  this.createReverseHandle(fn),
63
- getSharedReference: (ref: number) => this.sharedReferences.get(ref),
78
+ runHandle: (handle: Handle, args: Array<any>): Promise<mixed> =>
79
+ this.workerApi.callMaster({handle: handle.id, args}, true),
80
+ getSharedReference: (ref: SharedReference) =>
81
+ this.sharedReferences.get(ref),
64
82
  resolveSharedReference: (value: mixed) =>
65
83
  this.sharedReferencesByValue.get(value),
66
84
  };
67
85
 
68
- messageListener(message: WorkerMessage): void | Promise<void> {
86
+ messageListener(message: WorkerMessage): Async<void> {
69
87
  if (message.type === 'response') {
70
88
  return this.handleResponse(message);
71
89
  } else if (message.type === 'request') {
@@ -77,10 +95,14 @@ export class Child {
77
95
  this.child.send(data);
78
96
  }
79
97
 
80
- childInit(module: string, childId: number): void {
98
+ async childInit(module: string, childId: number): Promise<void> {
81
99
  // $FlowFixMe this must be dynamic
82
100
  this.module = require(module);
83
101
  this.childId = childId;
102
+
103
+ if (this.module.childInit != null) {
104
+ await this.module.childInit();
105
+ }
84
106
  }
85
107
 
86
108
  async handleRequest(data: WorkerRequest): Promise<void> {
@@ -106,7 +128,7 @@ export class Child {
106
128
  let result;
107
129
  if (handleId != null) {
108
130
  try {
109
- let fn = nullthrows(this.handles.get(handleId)).fn;
131
+ let fn = nullthrows(this.handles.get(handleId)?.fn);
110
132
  result = responseFromContent(fn(...args));
111
133
  } catch (e) {
112
134
  result = errorResponseFromError(e);
@@ -114,13 +136,13 @@ export class Child {
114
136
  } else if (method === 'childInit') {
115
137
  try {
116
138
  let [moduleName, childOptions] = args;
117
- if (childOptions.patchConsole) {
139
+ if (childOptions.shouldPatchConsole) {
118
140
  patchConsole();
119
141
  } else {
120
142
  unpatchConsole();
121
143
  }
122
144
 
123
- result = responseFromContent(this.childInit(moduleName, child));
145
+ result = responseFromContent(await this.childInit(moduleName, child));
124
146
  } catch (e) {
125
147
  result = errorResponseFromError(e);
126
148
  }
@@ -138,13 +160,38 @@ export class Child {
138
160
  } catch (e) {
139
161
  result = errorResponseFromError(e);
140
162
  }
163
+ } else if (method === 'takeHeapSnapshot') {
164
+ try {
165
+ let v8 = require('v8');
166
+ result = responseFromContent(
167
+ // $FlowFixMe
168
+ v8.writeHeapSnapshot(
169
+ 'heap-' +
170
+ args[0] +
171
+ '-' +
172
+ (this.childId ? 'worker' + this.childId : 'main') +
173
+ '.heapsnapshot',
174
+ ),
175
+ );
176
+ } catch (e) {
177
+ result = errorResponseFromError(e);
178
+ }
141
179
  } else if (method === 'createSharedReference') {
142
- let [ref, value] = args;
180
+ let [ref, _value] = args;
181
+ let value =
182
+ _value instanceof ArrayBuffer
183
+ ? // In the case the value is pre-serialized as a buffer,
184
+ // deserialize it.
185
+ deserialize(Buffer.from(_value))
186
+ : _value;
143
187
  this.sharedReferences.set(ref, value);
144
188
  this.sharedReferencesByValue.set(value, ref);
145
189
  result = responseFromContent(null);
146
190
  } else if (method === 'deleteSharedReference') {
147
- this.sharedReferences.delete(args[0]);
191
+ let ref = args[0];
192
+ let value = this.sharedReferences.get(ref);
193
+ this.sharedReferencesByValue.delete(value);
194
+ this.sharedReferences.delete(ref);
148
195
  result = responseFromContent(null);
149
196
  } else {
150
197
  try {
@@ -157,7 +204,11 @@ export class Child {
157
204
  }
158
205
  }
159
206
 
160
- this.send(result);
207
+ try {
208
+ this.send(result);
209
+ } catch (e) {
210
+ result = this.send(errorResponseFromError(e));
211
+ }
161
212
  }
162
213
 
163
214
  handleResponse(data: WorkerResponse): void {
@@ -189,6 +240,7 @@ export class Child {
189
240
  ...request,
190
241
  type: 'request',
191
242
  child: this.childId,
243
+ // $FlowFixMe Added in Flow 0.121.0 upgrade in #4381
192
244
  awaitResponse,
193
245
  resolve: () => {},
194
246
  reject: () => {},
@@ -241,10 +293,9 @@ export class Child {
241
293
  this.loggerDisposable.dispose();
242
294
  }
243
295
 
244
- createReverseHandle(fn: (...args: Array<any>) => mixed) {
296
+ createReverseHandle(fn: (...args: Array<any>) => mixed): Handle {
245
297
  let handle = new Handle({
246
298
  fn,
247
- workerApi: this.workerApi,
248
299
  childId: this.childId,
249
300
  });
250
301
  this.handles.set(handle.id, handle);
package/src/cpuCount.js CHANGED
@@ -26,6 +26,11 @@ export function detectRealCores(): number {
26
26
  );
27
27
  } else if (platform === 'darwin') {
28
28
  amount = parseInt(exec('sysctl -n hw.physicalcpu_max'), 10);
29
+ } else if (platform === 'win32') {
30
+ const str = exec('wmic cpu get NumberOfCores').match(/\d+/g);
31
+ if (str !== null) {
32
+ amount = parseInt(str.filter(n => n !== '')[0], 10);
33
+ }
29
34
  }
30
35
 
31
36
  if (!amount || amount <= 0) {
@@ -36,9 +41,8 @@ export function detectRealCores(): number {
36
41
  }
37
42
 
38
43
  let cores;
39
- export default function getCores(bypassCache?: boolean = false) {
44
+ export default function getCores(bypassCache?: boolean = false): number {
40
45
  // Do not re-run commands if we already have the count...
41
- // $FlowFixMe
42
46
  if (cores && !bypassCache) {
43
47
  return cores;
44
48
  }
@@ -49,8 +53,9 @@ export default function getCores(bypassCache?: boolean = false) {
49
53
  // Guess the amount of real cores
50
54
  cores = os
51
55
  .cpus()
52
- .filter((cpu, index) => !cpu.model.includes('Intel') || index % 2 === 1)
53
- .length;
56
+ .filter(
57
+ (cpu, index) => !cpu.model.includes('Intel') || index % 2 === 1,
58
+ ).length;
54
59
  }
55
60
 
56
61
  // Another fallback
package/src/index.js CHANGED
@@ -34,4 +34,4 @@ if (!WorkerFarm.isWorker()) {
34
34
  export default WorkerFarm;
35
35
  export {bus};
36
36
  export {Handle} from './WorkerFarm';
37
- export type {WorkerApi, FarmOptions} from './WorkerFarm';
37
+ export type {WorkerApi, FarmOptions, SharedReference} from './WorkerFarm';
@@ -25,7 +25,7 @@ export default class ProcessChild implements ChildImpl {
25
25
  process.on('message', data => this.handleMessage(data));
26
26
  }
27
27
 
28
- handleMessage(data: string) {
28
+ handleMessage(data: string): void {
29
29
  if (data === 'die') {
30
30
  return this.stop();
31
31
  }
@@ -34,7 +34,7 @@ export default class ProcessWorker implements WorkerImpl {
34
34
  this.onExit = onExit;
35
35
  }
36
36
 
37
- start() {
37
+ start(): Promise<void> {
38
38
  this.child = childProcess.fork(WORKER_PATH, process.argv, {
39
39
  execArgv: this.execArgv,
40
40
  env: process.env,
@@ -32,7 +32,7 @@ export default class ThreadsWorker implements WorkerImpl {
32
32
  this.onExit = onExit;
33
33
  }
34
34
 
35
- start() {
35
+ start(): Promise<void> {
36
36
  this.worker = new Worker(WORKER_PATH, {
37
37
  execArgv: this.execArgv,
38
38
  env: process.env,
@@ -47,7 +47,7 @@ export default class ThreadsWorker implements WorkerImpl {
47
47
  });
48
48
  }
49
49
 
50
- stop() {
50
+ stop(): Promise<void> {
51
51
  // In node 12, this returns a promise, but previously it accepted a callback
52
52
  // TODO: Pass a callback in earlier versions of Node
53
53
  return Promise.resolve(this.worker.terminate());
@@ -3,7 +3,7 @@ import os from 'os';
3
3
 
4
4
  import getCores, {detectRealCores} from '../src/cpuCount';
5
5
 
6
- describe('cpuCount', function() {
6
+ describe('cpuCount', function () {
7
7
  it('Should be able to detect real cpu count', () => {
8
8
  // Windows not supported as getting the cpu count takes a couple seconds...
9
9
  if (os.platform() === 'win32') return;
@@ -1,4 +1,4 @@
1
- const WorkerFarm = require('../../../').default;
1
+ const WorkerFarm = require('../../../src/WorkerFarm').default;
2
2
 
3
3
  function run() {
4
4
  if (WorkerFarm.isWorker()) {