@parcel/workers 2.0.0-nightly.151 → 2.0.0-nightly.1511

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 +103 -62
  4. package/lib/WorkerFarm.js +272 -192
  5. package/lib/backend.js +4 -6
  6. package/lib/bus.js +11 -13
  7. package/lib/child.js +140 -116
  8. package/lib/childState.js +2 -4
  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 +35 -32
  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 +95 -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,49 @@ 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 =>
55
+ !/^--(debug|inspect|no-opt|max-old-space-size=|max-semi-space-size=|expose-gc)/.test(
56
+ v,
57
+ ),
58
+ );
59
+
60
+ for (let i = 0; i < filteredArgs.length; i++) {
61
+ let arg = filteredArgs[i];
62
+ let isArgWithParam =
63
+ ((arg === '-r' || arg === '--require') &&
64
+ filteredArgs[i + 1] === '@parcel/register') ||
65
+ arg === '--title';
66
+ if (isArgWithParam) {
67
+ filteredArgs.splice(i, 2);
68
+ i--;
69
+ }
70
+ }
71
+ }
72
+
73
+ // Workaround for https://github.com/nodejs/node/issues/29117
74
+ if (process.env.NODE_OPTIONS) {
75
+ // arg parsing logic adapted from https://stackoverflow.com/a/46946420/2352201
76
+ let opts = [''];
77
+ let quote = false;
78
+ for (let c of nullthrows(process.env.NODE_OPTIONS.match(/.|^$/g))) {
79
+ if (c === '"') {
80
+ quote = !quote;
81
+ } else if (!quote && c === ' ') {
82
+ opts.push('');
83
+ } else {
84
+ opts[opts.length - 1] += c.replace(/\\(.)/, '$1');
85
+ }
86
+ }
87
+
88
+ for (let i = 0; i < opts.length; i++) {
89
+ let opt = opts[i];
90
+ if (opt === '-r' || opt === '--require') {
91
+ filteredArgs.push(opt, opts[i + 1]);
92
+ i++;
93
+ }
57
94
  }
58
95
  }
59
96
 
@@ -77,19 +114,49 @@ export default class Worker extends EventEmitter {
77
114
  args: [
78
115
  forkModule,
79
116
  {
80
- patchConsole: !!this.options.patchConsole,
117
+ shouldPatchConsole: !!this.options.shouldPatchConsole,
118
+ shouldTrace: !!this.options.shouldTrace,
81
119
  },
82
120
  ],
83
121
  retries: 0,
122
+ skipReadyCheck: true,
84
123
  resolve,
85
124
  reject,
86
125
  });
87
126
  });
88
127
 
128
+ let sharedRefs = this.options.sharedReferences;
129
+ let refsShared = new Set();
130
+ // in case more refs are created while initial refs are sending
131
+ while (refsShared.size < sharedRefs.size) {
132
+ await Promise.all(
133
+ [...sharedRefs]
134
+ .filter(([ref]) => !refsShared.has(ref))
135
+ .map(async ([ref, value]) => {
136
+ await this.sendSharedReference(ref, value);
137
+ refsShared.add(ref);
138
+ }),
139
+ );
140
+ }
141
+
89
142
  this.ready = true;
90
143
  this.emit('ready');
91
144
  }
92
145
 
146
+ sendSharedReference(ref: SharedReference, value: mixed): Promise<any> {
147
+ this.sentSharedReferences.add(ref);
148
+ return new Promise((resolve, reject) => {
149
+ this.call({
150
+ method: 'createSharedReference',
151
+ args: [ref, value],
152
+ resolve,
153
+ reject,
154
+ retries: 0,
155
+ skipReadyCheck: true,
156
+ });
157
+ });
158
+ }
159
+
93
160
  send(data: WorkerMessage): void {
94
161
  this.worker.send(data);
95
162
  }
@@ -102,14 +169,20 @@ export default class Worker extends EventEmitter {
102
169
  let idx = this.callId++;
103
170
  this.calls.set(idx, call);
104
171
 
105
- this.send({
172
+ let msg = {
106
173
  type: 'request',
107
174
  idx: idx,
108
175
  child: this.id,
109
176
  handle: call.handle,
110
177
  method: call.method,
111
178
  args: call.args,
112
- });
179
+ };
180
+
181
+ if (this.ready || call.skipReadyCheck === true) {
182
+ this.send(msg);
183
+ } else {
184
+ this.once('ready', () => this.send(msg));
185
+ }
113
186
  }
114
187
 
115
188
  receive(message: WorkerMessage): void {