@parcel/workers 2.0.0-nightly.144 → 2.0.0-nightly.1442

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. package/index.d.ts +23 -0
  2. package/lib/Handle.js +16 -58
  3. package/lib/Worker.js +95 -57
  4. package/lib/WorkerFarm.js +272 -192
  5. package/lib/backend.js +4 -6
  6. package/lib/bus.js +10 -11
  7. package/lib/child.js +140 -116
  8. package/lib/childState.js +1 -2
  9. package/lib/core-worker.browser.js +4 -0
  10. package/lib/core-worker.js +4 -0
  11. package/lib/cpuCount.js +36 -25
  12. package/lib/index.js +34 -30
  13. package/lib/process/ProcessChild.js +18 -24
  14. package/lib/process/ProcessWorker.js +27 -38
  15. package/lib/threads/ThreadsChild.js +26 -28
  16. package/lib/threads/ThreadsWorker.js +25 -31
  17. package/lib/web/WebChild.js +44 -0
  18. package/lib/web/WebWorker.js +85 -0
  19. package/package.json +19 -8
  20. package/src/Handle.js +10 -39
  21. package/src/Worker.js +92 -22
  22. package/src/WorkerFarm.js +267 -62
  23. package/src/backend.js +5 -0
  24. package/src/bus.js +3 -2
  25. package/src/child.js +95 -26
  26. package/src/core-worker.browser.js +3 -0
  27. package/src/core-worker.js +2 -0
  28. package/src/cpuCount.js +23 -10
  29. package/src/index.js +8 -2
  30. package/src/process/ProcessChild.js +2 -1
  31. package/src/process/ProcessWorker.js +1 -1
  32. package/src/threads/ThreadsWorker.js +2 -2
  33. package/src/types.js +1 -1
  34. package/src/web/WebChild.js +50 -0
  35. package/src/web/WebWorker.js +85 -0
  36. package/test/cpuCount.test.js +1 -1
  37. package/test/integration/workerfarm/console.js +1 -1
  38. package/test/integration/workerfarm/logging.js +1 -1
  39. package/test/integration/workerfarm/reverse-handle.js +2 -2
  40. package/test/workerfarm.js +5 -5
  41. package/lib/Profiler.js +0 -70
  42. package/lib/Trace.js +0 -126
  43. package/src/Profiler.js +0 -93
  44. package/src/Trace.js +0 -121
package/src/Handle.js CHANGED
@@ -1,20 +1,16 @@
1
- // @flow
2
-
3
- import type {WorkerApi} from './';
4
-
1
+ // @flow strict-local
5
2
  import {registerSerializableClass} from '@parcel/core';
6
-
7
- import {child} from './childState';
3
+ // $FlowFixMe
8
4
  import packageJson from '../package.json';
9
5
 
10
6
  let HANDLE_ID = 0;
11
-
7
+ // $FlowFixMe
12
8
  export type HandleFunction = (...args: Array<any>) => any;
13
9
 
14
10
  type HandleOpts = {|
15
- fn: HandleFunction,
11
+ fn?: HandleFunction,
16
12
  childId?: ?number,
17
- workerApi: WorkerApi,
13
+ id?: number,
18
14
  |};
19
15
 
20
16
  const handleById: Map<number, Handle> = new Map();
@@ -22,14 +18,12 @@ const handleById: Map<number, Handle> = new Map();
22
18
  export default class Handle {
23
19
  id: number;
24
20
  childId: ?number;
25
- fn: HandleFunction;
26
- workerApi: WorkerApi;
21
+ fn: ?HandleFunction;
27
22
 
28
23
  constructor(opts: HandleOpts) {
29
- this.id = ++HANDLE_ID;
24
+ this.id = opts.id ?? ++HANDLE_ID;
30
25
  this.fn = opts.fn;
31
26
  this.childId = opts.childId;
32
- this.workerApi = opts.workerApi;
33
27
  handleById.set(this.id, this);
34
28
  }
35
29
 
@@ -37,38 +31,15 @@ export default class Handle {
37
31
  handleById.delete(this.id);
38
32
  }
39
33
 
40
- serialize() {
34
+ serialize(): {|childId: ?number, id: number|} {
41
35
  return {
42
36
  id: this.id,
43
37
  childId: this.childId,
44
38
  };
45
39
  }
46
40
 
47
- static deserialize(opts: {|id: number, childId?: number|}) {
48
- return function(...args: Array<mixed>) {
49
- let workerApi;
50
- if (child) {
51
- workerApi = child.workerApi;
52
- } else {
53
- let handle = handleById.get(opts.id);
54
- if (!handle) {
55
- throw new Error(
56
- 'Corresponding Handle was not found. It may have been disposed.',
57
- );
58
- }
59
- workerApi = handle.workerApi;
60
- }
61
-
62
- if (opts.childId != null && child) {
63
- throw new Error('Cannot call another child from a child');
64
- }
65
-
66
- if (opts.childId != null && workerApi.callChild) {
67
- return workerApi.callChild(opts.childId, {handle: opts.id, args});
68
- }
69
-
70
- return workerApi.callMaster({handle: opts.id, args}, true);
71
- };
41
+ static deserialize(opts: HandleOpts): Handle {
42
+ return new Handle(opts);
72
43
  }
73
44
  }
74
45
 
package/src/Worker.js CHANGED
@@ -1,8 +1,10 @@
1
1
  // @flow
2
2
 
3
3
  import type {FilePath} from '@parcel/types';
4
- import type {WorkerMessage, WorkerImpl, BackendType} from './types';
4
+ import type {BackendType, WorkerImpl, WorkerMessage} from './types';
5
+ import type {SharedReference} from './WorkerFarm';
5
6
 
7
+ import nullthrows from 'nullthrows';
6
8
  import EventEmitter from 'events';
7
9
  import ThrowableDiagnostic from '@parcel/diagnostic';
8
10
  import {getWorkerBackend} from './backend';
@@ -12,6 +14,7 @@ export type WorkerCall = {|
12
14
  handle?: number,
13
15
  args: $ReadOnlyArray<any>,
14
16
  retries: number,
17
+ skipReadyCheck?: boolean,
15
18
  resolve: (result: Promise<any> | any) => void,
16
19
  reject: (error: any) => void,
17
20
  |};
@@ -19,7 +22,9 @@ export type WorkerCall = {|
19
22
  type WorkerOpts = {|
20
23
  forcedKillTime: number,
21
24
  backend: BackendType,
22
- patchConsole?: boolean,
25
+ shouldPatchConsole?: boolean,
26
+ shouldTrace?: boolean,
27
+ sharedReferences: $ReadOnlyMap<SharedReference, mixed>,
23
28
  |};
24
29
 
25
30
  let WORKER_ID = 0;
@@ -27,14 +32,15 @@ export default class Worker extends EventEmitter {
27
32
  +options: WorkerOpts;
28
33
  worker: WorkerImpl;
29
34
  id: number = WORKER_ID++;
35
+ sentSharedReferences: Set<SharedReference> = new Set();
30
36
 
31
37
  calls: Map<number, WorkerCall> = new Map();
32
- exitCode = null;
33
- callId = 0;
38
+ exitCode: ?number = null;
39
+ callId: number = 0;
34
40
 
35
- ready = false;
36
- stopped = false;
37
- isStopping = false;
41
+ ready: boolean = false;
42
+ stopped: boolean = false;
43
+ isStopping: boolean = false;
38
44
 
39
45
  constructor(options: WorkerOpts) {
40
46
  super();
@@ -42,18 +48,46 @@ export default class Worker extends EventEmitter {
42
48
  }
43
49
 
44
50
  async fork(forkModule: FilePath) {
45
- let filteredArgs = process.execArgv.filter(
46
- v => !/^--(debug|inspect)/.test(v),
47
- );
48
-
49
- for (let i = 0; i < filteredArgs.length; i++) {
50
- let arg = filteredArgs[i];
51
- if (
52
- (arg === '-r' || arg === '--require') &&
53
- filteredArgs[i + 1] === '@parcel/register'
54
- ) {
55
- filteredArgs.splice(i, 2);
56
- i--;
51
+ let filteredArgs = [];
52
+ if (process.execArgv) {
53
+ filteredArgs = process.execArgv.filter(
54
+ v => !/^--(debug|inspect|no-opt|max-old-space-size=)/.test(v),
55
+ );
56
+
57
+ for (let i = 0; i < filteredArgs.length; i++) {
58
+ let arg = filteredArgs[i];
59
+ let isArgWithParam =
60
+ ((arg === '-r' || arg === '--require') &&
61
+ filteredArgs[i + 1] === '@parcel/register') ||
62
+ arg === '--title';
63
+ if (isArgWithParam) {
64
+ filteredArgs.splice(i, 2);
65
+ i--;
66
+ }
67
+ }
68
+ }
69
+
70
+ // Workaround for https://github.com/nodejs/node/issues/29117
71
+ if (process.env.NODE_OPTIONS) {
72
+ // arg parsing logic adapted from https://stackoverflow.com/a/46946420/2352201
73
+ let opts = [''];
74
+ let quote = false;
75
+ for (let c of nullthrows(process.env.NODE_OPTIONS.match(/.|^$/g))) {
76
+ if (c === '"') {
77
+ quote = !quote;
78
+ } else if (!quote && c === ' ') {
79
+ opts.push('');
80
+ } else {
81
+ opts[opts.length - 1] += c.replace(/\\(.)/, '$1');
82
+ }
83
+ }
84
+
85
+ for (let i = 0; i < opts.length; i++) {
86
+ let opt = opts[i];
87
+ if (opt === '-r' || opt === '--require') {
88
+ filteredArgs.push(opt, opts[i + 1]);
89
+ i++;
90
+ }
57
91
  }
58
92
  }
59
93
 
@@ -77,19 +111,49 @@ export default class Worker extends EventEmitter {
77
111
  args: [
78
112
  forkModule,
79
113
  {
80
- patchConsole: !!this.options.patchConsole,
114
+ shouldPatchConsole: !!this.options.shouldPatchConsole,
115
+ shouldTrace: !!this.options.shouldTrace,
81
116
  },
82
117
  ],
83
118
  retries: 0,
119
+ skipReadyCheck: true,
84
120
  resolve,
85
121
  reject,
86
122
  });
87
123
  });
88
124
 
125
+ let sharedRefs = this.options.sharedReferences;
126
+ let refsShared = new Set();
127
+ // in case more refs are created while initial refs are sending
128
+ while (refsShared.size < sharedRefs.size) {
129
+ await Promise.all(
130
+ [...sharedRefs]
131
+ .filter(([ref]) => !refsShared.has(ref))
132
+ .map(async ([ref, value]) => {
133
+ await this.sendSharedReference(ref, value);
134
+ refsShared.add(ref);
135
+ }),
136
+ );
137
+ }
138
+
89
139
  this.ready = true;
90
140
  this.emit('ready');
91
141
  }
92
142
 
143
+ sendSharedReference(ref: SharedReference, value: mixed): Promise<any> {
144
+ this.sentSharedReferences.add(ref);
145
+ return new Promise((resolve, reject) => {
146
+ this.call({
147
+ method: 'createSharedReference',
148
+ args: [ref, value],
149
+ resolve,
150
+ reject,
151
+ retries: 0,
152
+ skipReadyCheck: true,
153
+ });
154
+ });
155
+ }
156
+
93
157
  send(data: WorkerMessage): void {
94
158
  this.worker.send(data);
95
159
  }
@@ -102,14 +166,20 @@ export default class Worker extends EventEmitter {
102
166
  let idx = this.callId++;
103
167
  this.calls.set(idx, call);
104
168
 
105
- this.send({
169
+ let msg = {
106
170
  type: 'request',
107
171
  idx: idx,
108
172
  child: this.id,
109
173
  handle: call.handle,
110
174
  method: call.method,
111
175
  args: call.args,
112
- });
176
+ };
177
+
178
+ if (this.ready || call.skipReadyCheck === true) {
179
+ this.send(msg);
180
+ } else {
181
+ this.once('ready', () => this.send(msg));
182
+ }
113
183
  }
114
184
 
115
185
  receive(message: WorkerMessage): void {