@rollup/plugin-terser 0.3.0 → 0.4.1

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/dist/cjs/index.js CHANGED
@@ -2,11 +2,11 @@
2
2
 
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
- var process = require('process');
6
5
  var worker_threads = require('worker_threads');
7
6
  var smob = require('smob');
8
7
  var terser$1 = require('terser');
9
8
  var url = require('url');
9
+ var async_hooks = require('async_hooks');
10
10
  var os = require('os');
11
11
  var events = require('events');
12
12
  var serializeJavascript = require('serialize-javascript');
@@ -23,17 +23,20 @@ function isWorkerContextSerialized(input) {
23
23
  smob.hasOwnProperty(input, 'options') &&
24
24
  typeof input.options === 'string');
25
25
  }
26
- async function runWorker() {
27
- if (worker_threads.isMainThread || !worker_threads.parentPort || !isWorkerContextSerialized(worker_threads.workerData)) {
26
+ function runWorker() {
27
+ if (worker_threads.isMainThread || !worker_threads.parentPort) {
28
28
  return;
29
29
  }
30
- try {
31
- // eslint-disable-next-line no-eval
32
- const eval2 = eval;
33
- const options = eval2(`(${worker_threads.workerData.options})`);
34
- const result = await terser$1.minify(worker_threads.workerData.code, options);
30
+ // eslint-disable-next-line no-eval
31
+ const eval2 = eval;
32
+ worker_threads.parentPort.on('message', async (data) => {
33
+ if (!isWorkerContextSerialized(data)) {
34
+ return;
35
+ }
36
+ const options = eval2(`(${data.options})`);
37
+ const result = await terser$1.minify(data.code, options);
35
38
  const output = {
36
- code: result.code || worker_threads.workerData.code,
39
+ code: result.code || data.code,
37
40
  nameCache: options.nameCache
38
41
  };
39
42
  if (typeof result.map === 'string') {
@@ -42,40 +45,44 @@ async function runWorker() {
42
45
  if (smob.isObject(result.map)) {
43
46
  output.sourceMap = result.map;
44
47
  }
45
- worker_threads.parentPort.postMessage(output);
48
+ worker_threads.parentPort === null || worker_threads.parentPort === void 0 ? void 0 : worker_threads.parentPort.postMessage(output);
49
+ });
50
+ }
51
+
52
+ const taskInfo = Symbol('taskInfo');
53
+ const freeWorker = Symbol('freeWorker');
54
+
55
+ class WorkerPoolTaskInfo extends async_hooks.AsyncResource {
56
+ constructor(callback) {
57
+ super('WorkerPoolTaskInfo');
58
+ this.callback = callback;
46
59
  }
47
- catch (e) {
48
- process.exit(1);
60
+ done(err, result) {
61
+ this.runInAsyncScope(this.callback, null, err, result);
62
+ this.emitDestroy();
49
63
  }
50
64
  }
51
-
52
- const symbol = Symbol.for('FreeWoker');
53
65
  class WorkerPool extends events.EventEmitter {
54
66
  constructor(options) {
55
67
  super();
56
68
  this.tasks = [];
57
- this.workers = 0;
69
+ this.workers = [];
70
+ this.freeWorkers = [];
58
71
  this.maxInstances = options.maxWorkers || os.cpus().length;
59
72
  this.filePath = options.filePath;
60
- this.on(symbol, () => {
73
+ this.on(freeWorker, () => {
61
74
  if (this.tasks.length > 0) {
62
- this.run();
75
+ const { context, cb } = this.tasks.shift();
76
+ this.runTask(context, cb);
63
77
  }
64
78
  });
65
79
  }
66
- add(context, cb) {
67
- this.tasks.push({
68
- context,
69
- cb
70
- });
71
- if (this.workers >= this.maxInstances) {
72
- return;
73
- }
74
- this.run();
80
+ get numWorkers() {
81
+ return this.workers.length;
75
82
  }
76
- async addAsync(context) {
83
+ addAsync(context) {
77
84
  return new Promise((resolve, reject) => {
78
- this.add(context, (err, output) => {
85
+ this.runTask(context, (err, output) => {
79
86
  if (err) {
80
87
  reject(err);
81
88
  return;
@@ -88,54 +95,69 @@ class WorkerPool extends events.EventEmitter {
88
95
  });
89
96
  });
90
97
  }
91
- run() {
92
- if (this.tasks.length === 0) {
93
- return;
94
- }
95
- const task = this.tasks.shift();
96
- if (typeof task === 'undefined') {
97
- return;
98
+ close() {
99
+ for (let i = 0; i < this.workers.length; i++) {
100
+ const worker = this.workers[i];
101
+ worker.terminate();
98
102
  }
99
- this.workers += 1;
100
- let called = false;
101
- const callCallback = (err, output) => {
102
- if (called) {
103
- return;
104
- }
105
- called = true;
106
- this.workers -= 1;
107
- task.cb(err, output);
108
- this.emit(symbol);
109
- };
110
- const worker = new worker_threads.Worker(this.filePath, {
111
- workerData: {
112
- code: task.context.code,
113
- options: serializeJavascript(task.context.options)
114
- }
115
- });
116
- worker.on('message', (data) => {
117
- callCallback(null, data);
103
+ }
104
+ addNewWorker() {
105
+ const worker = new worker_threads.Worker(this.filePath);
106
+ worker.on('message', (result) => {
107
+ var _a;
108
+ (_a = worker[taskInfo]) === null || _a === void 0 ? void 0 : _a.done(null, result);
109
+ worker[taskInfo] = null;
110
+ this.freeWorkers.push(worker);
111
+ this.emit(freeWorker);
118
112
  });
119
113
  worker.on('error', (err) => {
120
- callCallback(err);
121
- });
122
- worker.on('exit', (code) => {
123
- if (code !== 0) {
124
- callCallback(new Error(`Minify worker stopped with exit code ${code}`));
114
+ if (worker[taskInfo]) {
115
+ worker[taskInfo].done(err, null);
116
+ }
117
+ else {
118
+ this.emit('error', err);
125
119
  }
120
+ this.workers.splice(this.workers.indexOf(worker), 1);
121
+ this.addNewWorker();
126
122
  });
123
+ this.workers.push(worker);
124
+ this.freeWorkers.push(worker);
125
+ this.emit(freeWorker);
126
+ }
127
+ runTask(context, cb) {
128
+ if (this.freeWorkers.length === 0) {
129
+ this.tasks.push({ context, cb });
130
+ if (this.numWorkers < this.maxInstances) {
131
+ this.addNewWorker();
132
+ }
133
+ return;
134
+ }
135
+ const worker = this.freeWorkers.pop();
136
+ if (worker) {
137
+ worker[taskInfo] = new WorkerPoolTaskInfo(cb);
138
+ worker.postMessage({
139
+ code: context.code,
140
+ options: serializeJavascript(context.options)
141
+ });
142
+ }
127
143
  }
128
144
  }
129
145
 
130
146
  function terser(input = {}) {
131
147
  const { maxWorkers, ...options } = input;
132
- const workerPool = new WorkerPool({
133
- filePath: url.fileURLToPath((typeof document === 'undefined' ? new (require('u' + 'rl').URL)('file:' + __filename).href : (document.currentScript && document.currentScript.src || new URL('index.js', document.baseURI).href))),
134
- maxWorkers
135
- });
148
+ let workerPool;
149
+ let numOfChunks = 0;
150
+ let numOfWorkersUsed = 0;
136
151
  return {
137
152
  name: 'terser',
138
153
  async renderChunk(code, chunk, outputOptions) {
154
+ if (!workerPool) {
155
+ workerPool = new WorkerPool({
156
+ filePath: url.fileURLToPath((typeof document === 'undefined' ? new (require('u' + 'rl').URL)('file:' + __filename).href : (document.currentScript && document.currentScript.src || new URL('index.js', document.baseURI).href))),
157
+ maxWorkers
158
+ });
159
+ }
160
+ numOfChunks += 1;
139
161
  const defaultOptions = {
140
162
  sourceMap: outputOptions.sourcemap === true || typeof outputOptions.sourcemap === 'string'
141
163
  };
@@ -184,6 +206,17 @@ function terser(input = {}) {
184
206
  catch (e) {
185
207
  return Promise.reject(e);
186
208
  }
209
+ finally {
210
+ numOfChunks -= 1;
211
+ if (numOfChunks === 0) {
212
+ numOfWorkersUsed = workerPool.numWorkers;
213
+ workerPool.close();
214
+ workerPool = null;
215
+ }
216
+ }
217
+ },
218
+ get numOfWorkersUsed() {
219
+ return numOfWorkersUsed;
187
220
  }
188
221
  };
189
222
  }
package/dist/es/index.js CHANGED
@@ -1,8 +1,8 @@
1
- import process from 'process';
2
- import { isMainThread, parentPort, workerData, Worker } from 'worker_threads';
1
+ import { isMainThread, parentPort, Worker } from 'worker_threads';
3
2
  import { isObject, hasOwnProperty, merge } from 'smob';
4
3
  import { minify } from 'terser';
5
4
  import { fileURLToPath } from 'url';
5
+ import { AsyncResource } from 'async_hooks';
6
6
  import { cpus } from 'os';
7
7
  import { EventEmitter } from 'events';
8
8
  import serializeJavascript from 'serialize-javascript';
@@ -19,17 +19,20 @@ function isWorkerContextSerialized(input) {
19
19
  hasOwnProperty(input, 'options') &&
20
20
  typeof input.options === 'string');
21
21
  }
22
- async function runWorker() {
23
- if (isMainThread || !parentPort || !isWorkerContextSerialized(workerData)) {
22
+ function runWorker() {
23
+ if (isMainThread || !parentPort) {
24
24
  return;
25
25
  }
26
- try {
27
- // eslint-disable-next-line no-eval
28
- const eval2 = eval;
29
- const options = eval2(`(${workerData.options})`);
30
- const result = await minify(workerData.code, options);
26
+ // eslint-disable-next-line no-eval
27
+ const eval2 = eval;
28
+ parentPort.on('message', async (data) => {
29
+ if (!isWorkerContextSerialized(data)) {
30
+ return;
31
+ }
32
+ const options = eval2(`(${data.options})`);
33
+ const result = await minify(data.code, options);
31
34
  const output = {
32
- code: result.code || workerData.code,
35
+ code: result.code || data.code,
33
36
  nameCache: options.nameCache
34
37
  };
35
38
  if (typeof result.map === 'string') {
@@ -38,40 +41,44 @@ async function runWorker() {
38
41
  if (isObject(result.map)) {
39
42
  output.sourceMap = result.map;
40
43
  }
41
- parentPort.postMessage(output);
44
+ parentPort === null || parentPort === void 0 ? void 0 : parentPort.postMessage(output);
45
+ });
46
+ }
47
+
48
+ const taskInfo = Symbol('taskInfo');
49
+ const freeWorker = Symbol('freeWorker');
50
+
51
+ class WorkerPoolTaskInfo extends AsyncResource {
52
+ constructor(callback) {
53
+ super('WorkerPoolTaskInfo');
54
+ this.callback = callback;
42
55
  }
43
- catch (e) {
44
- process.exit(1);
56
+ done(err, result) {
57
+ this.runInAsyncScope(this.callback, null, err, result);
58
+ this.emitDestroy();
45
59
  }
46
60
  }
47
-
48
- const symbol = Symbol.for('FreeWoker');
49
61
  class WorkerPool extends EventEmitter {
50
62
  constructor(options) {
51
63
  super();
52
64
  this.tasks = [];
53
- this.workers = 0;
65
+ this.workers = [];
66
+ this.freeWorkers = [];
54
67
  this.maxInstances = options.maxWorkers || cpus().length;
55
68
  this.filePath = options.filePath;
56
- this.on(symbol, () => {
69
+ this.on(freeWorker, () => {
57
70
  if (this.tasks.length > 0) {
58
- this.run();
71
+ const { context, cb } = this.tasks.shift();
72
+ this.runTask(context, cb);
59
73
  }
60
74
  });
61
75
  }
62
- add(context, cb) {
63
- this.tasks.push({
64
- context,
65
- cb
66
- });
67
- if (this.workers >= this.maxInstances) {
68
- return;
69
- }
70
- this.run();
76
+ get numWorkers() {
77
+ return this.workers.length;
71
78
  }
72
- async addAsync(context) {
79
+ addAsync(context) {
73
80
  return new Promise((resolve, reject) => {
74
- this.add(context, (err, output) => {
81
+ this.runTask(context, (err, output) => {
75
82
  if (err) {
76
83
  reject(err);
77
84
  return;
@@ -84,54 +91,69 @@ class WorkerPool extends EventEmitter {
84
91
  });
85
92
  });
86
93
  }
87
- run() {
88
- if (this.tasks.length === 0) {
89
- return;
90
- }
91
- const task = this.tasks.shift();
92
- if (typeof task === 'undefined') {
93
- return;
94
+ close() {
95
+ for (let i = 0; i < this.workers.length; i++) {
96
+ const worker = this.workers[i];
97
+ worker.terminate();
94
98
  }
95
- this.workers += 1;
96
- let called = false;
97
- const callCallback = (err, output) => {
98
- if (called) {
99
- return;
100
- }
101
- called = true;
102
- this.workers -= 1;
103
- task.cb(err, output);
104
- this.emit(symbol);
105
- };
106
- const worker = new Worker(this.filePath, {
107
- workerData: {
108
- code: task.context.code,
109
- options: serializeJavascript(task.context.options)
110
- }
111
- });
112
- worker.on('message', (data) => {
113
- callCallback(null, data);
99
+ }
100
+ addNewWorker() {
101
+ const worker = new Worker(this.filePath);
102
+ worker.on('message', (result) => {
103
+ var _a;
104
+ (_a = worker[taskInfo]) === null || _a === void 0 ? void 0 : _a.done(null, result);
105
+ worker[taskInfo] = null;
106
+ this.freeWorkers.push(worker);
107
+ this.emit(freeWorker);
114
108
  });
115
109
  worker.on('error', (err) => {
116
- callCallback(err);
117
- });
118
- worker.on('exit', (code) => {
119
- if (code !== 0) {
120
- callCallback(new Error(`Minify worker stopped with exit code ${code}`));
110
+ if (worker[taskInfo]) {
111
+ worker[taskInfo].done(err, null);
112
+ }
113
+ else {
114
+ this.emit('error', err);
121
115
  }
116
+ this.workers.splice(this.workers.indexOf(worker), 1);
117
+ this.addNewWorker();
122
118
  });
119
+ this.workers.push(worker);
120
+ this.freeWorkers.push(worker);
121
+ this.emit(freeWorker);
122
+ }
123
+ runTask(context, cb) {
124
+ if (this.freeWorkers.length === 0) {
125
+ this.tasks.push({ context, cb });
126
+ if (this.numWorkers < this.maxInstances) {
127
+ this.addNewWorker();
128
+ }
129
+ return;
130
+ }
131
+ const worker = this.freeWorkers.pop();
132
+ if (worker) {
133
+ worker[taskInfo] = new WorkerPoolTaskInfo(cb);
134
+ worker.postMessage({
135
+ code: context.code,
136
+ options: serializeJavascript(context.options)
137
+ });
138
+ }
123
139
  }
124
140
  }
125
141
 
126
142
  function terser(input = {}) {
127
143
  const { maxWorkers, ...options } = input;
128
- const workerPool = new WorkerPool({
129
- filePath: fileURLToPath(import.meta.url),
130
- maxWorkers
131
- });
144
+ let workerPool;
145
+ let numOfChunks = 0;
146
+ let numOfWorkersUsed = 0;
132
147
  return {
133
148
  name: 'terser',
134
149
  async renderChunk(code, chunk, outputOptions) {
150
+ if (!workerPool) {
151
+ workerPool = new WorkerPool({
152
+ filePath: fileURLToPath(import.meta.url),
153
+ maxWorkers
154
+ });
155
+ }
156
+ numOfChunks += 1;
135
157
  const defaultOptions = {
136
158
  sourceMap: outputOptions.sourcemap === true || typeof outputOptions.sourcemap === 'string'
137
159
  };
@@ -180,6 +202,17 @@ function terser(input = {}) {
180
202
  catch (e) {
181
203
  return Promise.reject(e);
182
204
  }
205
+ finally {
206
+ numOfChunks -= 1;
207
+ if (numOfChunks === 0) {
208
+ numOfWorkersUsed = workerPool.numWorkers;
209
+ workerPool.close();
210
+ workerPool = null;
211
+ }
212
+ }
213
+ },
214
+ get numOfWorkersUsed() {
215
+ return numOfWorkersUsed;
183
216
  }
184
217
  };
185
218
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rollup/plugin-terser",
3
- "version": "0.3.0",
3
+ "version": "0.4.1",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -0,0 +1,2 @@
1
+ export const taskInfo = Symbol('taskInfo');
2
+ export const freeWorker = Symbol('freeWorker');
package/src/module.ts CHANGED
@@ -9,15 +9,23 @@ import { WorkerPool } from './worker-pool';
9
9
  export default function terser(input: Options = {}) {
10
10
  const { maxWorkers, ...options } = input;
11
11
 
12
- const workerPool = new WorkerPool({
13
- filePath: fileURLToPath(import.meta.url),
14
- maxWorkers
15
- });
12
+ let workerPool: WorkerPool | null | undefined;
13
+ let numOfChunks = 0;
14
+ let numOfWorkersUsed = 0;
16
15
 
17
16
  return {
18
17
  name: 'terser',
19
18
 
20
19
  async renderChunk(code: string, chunk: RenderedChunk, outputOptions: NormalizedOutputOptions) {
20
+ if (!workerPool) {
21
+ workerPool = new WorkerPool({
22
+ filePath: fileURLToPath(import.meta.url),
23
+ maxWorkers
24
+ });
25
+ }
26
+
27
+ numOfChunks += 1;
28
+
21
29
  const defaultOptions: Options = {
22
30
  sourceMap: outputOptions.sourcemap === true || typeof outputOptions.sourcemap === 'string'
23
31
  };
@@ -80,7 +88,18 @@ export default function terser(input: Options = {}) {
80
88
  return result;
81
89
  } catch (e) {
82
90
  return Promise.reject(e);
91
+ } finally {
92
+ numOfChunks -= 1;
93
+ if (numOfChunks === 0) {
94
+ numOfWorkersUsed = workerPool.numWorkers;
95
+ workerPool.close();
96
+ workerPool = null;
97
+ }
83
98
  }
99
+ },
100
+
101
+ get numOfWorkersUsed() {
102
+ return numOfWorkersUsed;
84
103
  }
85
104
  };
86
105
  }
package/src/type.ts CHANGED
@@ -1,5 +1,10 @@
1
+ import type { AsyncResource } from 'async_hooks';
2
+ import type { Worker } from 'worker_threads';
3
+
1
4
  import type { MinifyOptions } from 'terser';
2
5
 
6
+ import type { taskInfo } from './constants';
7
+
3
8
  export interface Options extends MinifyOptions {
4
9
  nameCache?: Record<string, any>;
5
10
  maxWorkers?: number;
@@ -12,6 +17,12 @@ export interface WorkerContext {
12
17
 
13
18
  export type WorkerCallback = (err: Error | null, output?: WorkerOutput) => void;
14
19
 
20
+ interface WorkerPoolTaskInfo extends AsyncResource {
21
+ done(err: Error | null, result: any): void;
22
+ }
23
+
24
+ export type WorkerWithTaskInfo = Worker & { [taskInfo]?: WorkerPoolTaskInfo | null };
25
+
15
26
  export interface WorkerContextSerialized {
16
27
  code: string;
17
28
  options: string;
@@ -1,18 +1,31 @@
1
+ import { AsyncResource } from 'async_hooks';
1
2
  import { Worker } from 'worker_threads';
2
3
  import { cpus } from 'os';
3
4
  import { EventEmitter } from 'events';
4
5
 
5
6
  import serializeJavascript from 'serialize-javascript';
6
7
 
8
+ import { freeWorker, taskInfo } from './constants';
9
+
7
10
  import type {
8
11
  WorkerCallback,
9
12
  WorkerContext,
10
13
  WorkerOutput,
11
14
  WorkerPoolOptions,
12
- WorkerPoolTask
15
+ WorkerPoolTask,
16
+ WorkerWithTaskInfo
13
17
  } from './type';
14
18
 
15
- const symbol = Symbol.for('FreeWoker');
19
+ class WorkerPoolTaskInfo extends AsyncResource {
20
+ constructor(private callback: WorkerCallback) {
21
+ super('WorkerPoolTaskInfo');
22
+ }
23
+
24
+ done(err: Error | null, result: any) {
25
+ this.runInAsyncScope(this.callback, null, err, result);
26
+ this.emitDestroy();
27
+ }
28
+ }
16
29
 
17
30
  export class WorkerPool extends EventEmitter {
18
31
  protected maxInstances: number;
@@ -21,7 +34,8 @@ export class WorkerPool extends EventEmitter {
21
34
 
22
35
  protected tasks: WorkerPoolTask[] = [];
23
36
 
24
- protected workers = 0;
37
+ protected workers: WorkerWithTaskInfo[] = [];
38
+ protected freeWorkers: WorkerWithTaskInfo[] = [];
25
39
 
26
40
  constructor(options: WorkerPoolOptions) {
27
41
  super();
@@ -29,29 +43,21 @@ export class WorkerPool extends EventEmitter {
29
43
  this.maxInstances = options.maxWorkers || cpus().length;
30
44
  this.filePath = options.filePath;
31
45
 
32
- this.on(symbol, () => {
46
+ this.on(freeWorker, () => {
33
47
  if (this.tasks.length > 0) {
34
- this.run();
48
+ const { context, cb } = this.tasks.shift()!;
49
+ this.runTask(context, cb);
35
50
  }
36
51
  });
37
52
  }
38
53
 
39
- add(context: WorkerContext, cb: WorkerCallback) {
40
- this.tasks.push({
41
- context,
42
- cb
43
- });
44
-
45
- if (this.workers >= this.maxInstances) {
46
- return;
47
- }
48
-
49
- this.run();
54
+ get numWorkers(): number {
55
+ return this.workers.length;
50
56
  }
51
57
 
52
- async addAsync(context: WorkerContext): Promise<WorkerOutput> {
58
+ addAsync(context: WorkerContext): Promise<WorkerOutput> {
53
59
  return new Promise((resolve, reject) => {
54
- this.add(context, (err, output) => {
60
+ this.runTask(context, (err, output) => {
55
61
  if (err) {
56
62
  reject(err);
57
63
  return;
@@ -67,51 +73,54 @@ export class WorkerPool extends EventEmitter {
67
73
  });
68
74
  }
69
75
 
70
- private run() {
71
- if (this.tasks.length === 0) {
72
- return;
73
- }
74
-
75
- const task = this.tasks.shift();
76
-
77
- if (typeof task === 'undefined') {
78
- return;
76
+ close() {
77
+ for (let i = 0; i < this.workers.length; i++) {
78
+ const worker = this.workers[i];
79
+ worker.terminate();
79
80
  }
81
+ }
80
82
 
81
- this.workers += 1;
82
-
83
- let called = false;
84
- const callCallback = (err: Error | null, output?: WorkerOutput) => {
85
- if (called) {
86
- return;
87
- }
88
- called = true;
89
-
90
- this.workers -= 1;
91
-
92
- task.cb(err, output);
93
- this.emit(symbol);
94
- };
95
-
96
- const worker = new Worker(this.filePath, {
97
- workerData: {
98
- code: task.context.code,
99
- options: serializeJavascript(task.context.options)
100
- }
101
- });
83
+ private addNewWorker() {
84
+ const worker: WorkerWithTaskInfo = new Worker(this.filePath);
102
85
 
103
- worker.on('message', (data) => {
104
- callCallback(null, data);
86
+ worker.on('message', (result) => {
87
+ worker[taskInfo]?.done(null, result);
88
+ worker[taskInfo] = null;
89
+ this.freeWorkers.push(worker);
90
+ this.emit(freeWorker);
105
91
  });
106
92
 
107
93
  worker.on('error', (err) => {
108
- callCallback(err);
94
+ if (worker[taskInfo]) {
95
+ worker[taskInfo].done(err, null);
96
+ } else {
97
+ this.emit('error', err);
98
+ }
99
+ this.workers.splice(this.workers.indexOf(worker), 1);
100
+ this.addNewWorker();
109
101
  });
110
102
 
111
- worker.on('exit', (code) => {
112
- if (code !== 0) {
113
- callCallback(new Error(`Minify worker stopped with exit code ${code}`));
103
+ this.workers.push(worker);
104
+ this.freeWorkers.push(worker);
105
+ this.emit(freeWorker);
106
+ }
107
+
108
+ private runTask(context: WorkerContext, cb: WorkerCallback) {
109
+ if (this.freeWorkers.length === 0) {
110
+ this.tasks.push({ context, cb });
111
+ if (this.numWorkers < this.maxInstances) {
112
+ this.addNewWorker();
114
113
  }
115
- });
114
+ return;
115
+ }
116
+
117
+ const worker = this.freeWorkers.pop();
118
+ if (worker) {
119
+ worker[taskInfo] = new WorkerPoolTaskInfo(cb);
120
+ worker.postMessage({
121
+ code: context.code,
122
+ options: serializeJavascript(context.options)
123
+ });
124
+ }
116
125
  }
117
126
  }
package/src/worker.ts CHANGED
@@ -1,5 +1,4 @@
1
- import process from 'process';
2
- import { isMainThread, parentPort, workerData } from 'worker_threads';
1
+ import { isMainThread, parentPort } from 'worker_threads';
3
2
 
4
3
  import { hasOwnProperty, isObject } from 'smob';
5
4
 
@@ -22,21 +21,25 @@ function isWorkerContextSerialized(input: unknown): input is WorkerContextSerial
22
21
  );
23
22
  }
24
23
 
25
- export async function runWorker() {
26
- if (isMainThread || !parentPort || !isWorkerContextSerialized(workerData)) {
24
+ export function runWorker() {
25
+ if (isMainThread || !parentPort) {
27
26
  return;
28
27
  }
29
28
 
30
- try {
31
- // eslint-disable-next-line no-eval
32
- const eval2 = eval;
29
+ // eslint-disable-next-line no-eval
30
+ const eval2 = eval;
33
31
 
34
- const options = eval2(`(${workerData.options})`);
32
+ parentPort.on('message', async (data: WorkerContextSerialized) => {
33
+ if (!isWorkerContextSerialized(data)) {
34
+ return;
35
+ }
36
+
37
+ const options = eval2(`(${data.options})`);
35
38
 
36
- const result = await minify(workerData.code, options);
39
+ const result = await minify(data.code, options);
37
40
 
38
41
  const output: WorkerOutput = {
39
- code: result.code || workerData.code,
42
+ code: result.code || data.code,
40
43
  nameCache: options.nameCache
41
44
  };
42
45
 
@@ -48,8 +51,6 @@ export async function runWorker() {
48
51
  output.sourceMap = result.map;
49
52
  }
50
53
 
51
- parentPort.postMessage(output);
52
- } catch (e) {
53
- process.exit(1);
54
- }
54
+ parentPort?.postMessage(output);
55
+ });
55
56
  }
package/types/index.d.ts CHANGED
@@ -1,10 +1,15 @@
1
1
  import type { Plugin } from 'rollup';
2
2
  import type { MinifyOptions } from 'terser';
3
3
 
4
+ export interface Options extends MinifyOptions {
5
+ nameCache?: Record<string, any>;
6
+ maxWorkers?: number;
7
+ }
8
+
4
9
  /**
5
10
  * A Rollup plugin to generate a minified output bundle.
6
11
  *
7
12
  * @param options - Plugin options.
8
13
  * @returns Plugin instance.
9
14
  */
10
- export default function terser(options?: MinifyOptions): Plugin;
15
+ export default function terser(options?: Options): Plugin;