'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); var worker_threads = require('worker_threads'); var smob = require('smob'); var terser$1 = require('terser'); var url = require('url'); var async_hooks = require('async_hooks'); var os = require('os'); var events = require('events'); var serializeJavascript = require('serialize-javascript'); var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null; const taskInfo = Symbol('taskInfo'); const freeWorker = Symbol('freeWorker'); const workerPoolWorkerFlag = 'WorkerPoolWorker'; /** * Duck typing worker context. * * @param input */ function isWorkerContextSerialized(input) { return (smob.isObject(input) && smob.hasOwnProperty(input, 'code') && typeof input.code === 'string' && smob.hasOwnProperty(input, 'options') && typeof input.options === 'string'); } function runWorker() { if (worker_threads.isMainThread || !worker_threads.parentPort || worker_threads.workerData !== workerPoolWorkerFlag) { return; } // eslint-disable-next-line no-eval const eval2 = eval; worker_threads.parentPort.on('message', async (data) => { if (!isWorkerContextSerialized(data)) { return; } const options = eval2(`(${data.options})`); const result = await terser$1.minify(data.code, options); const output = { code: result.code || data.code, nameCache: options.nameCache }; if (typeof result.map === 'string') { output.sourceMap = JSON.parse(result.map); } if (smob.isObject(result.map)) { output.sourceMap = result.map; } worker_threads.parentPort === null || worker_threads.parentPort === void 0 ? void 0 : worker_threads.parentPort.postMessage(output); }); } class WorkerPoolTaskInfo extends async_hooks.AsyncResource { constructor(callback) { super('WorkerPoolTaskInfo'); this.callback = callback; } done(err, result) { this.runInAsyncScope(this.callback, null, err, result); this.emitDestroy(); } } class WorkerPool extends events.EventEmitter { constructor(options) { super(); this.tasks = []; this.workers = []; this.freeWorkers = []; this.maxInstances = options.maxWorkers || os.cpus().length; this.filePath = options.filePath; this.on(freeWorker, () => { if (this.tasks.length > 0) { const { context, cb } = this.tasks.shift(); this.runTask(context, cb); } }); } get numWorkers() { return this.workers.length; } addAsync(context) { return new Promise((resolve, reject) => { this.runTask(context, (err, output) => { if (err) { reject(err); return; } if (!output) { reject(new Error('The output is empty')); return; } resolve(output); }); }); } close() { for (let i = 0; i < this.workers.length; i++) { const worker = this.workers[i]; worker.terminate(); } } addNewWorker() { const worker = new worker_threads.Worker(this.filePath, { workerData: workerPoolWorkerFlag }); worker.on('message', (result) => { var _a; (_a = worker[taskInfo]) === null || _a === void 0 ? void 0 : _a.done(null, result); worker[taskInfo] = null; this.freeWorkers.push(worker); this.emit(freeWorker); }); worker.on('error', (err) => { if (worker[taskInfo]) { worker[taskInfo].done(err, null); } else { this.emit('error', err); } this.workers.splice(this.workers.indexOf(worker), 1); this.addNewWorker(); }); this.workers.push(worker); this.freeWorkers.push(worker); this.emit(freeWorker); } runTask(context, cb) { if (this.freeWorkers.length === 0) { this.tasks.push({ context, cb }); if (this.numWorkers < this.maxInstances) { this.addNewWorker(); } return; } const worker = this.freeWorkers.pop(); if (worker) { worker[taskInfo] = new WorkerPoolTaskInfo(cb); worker.postMessage({ code: context.code, options: serializeJavascript(context.options) }); } } } function terser(input = {}) { const { maxWorkers, ...options } = input; let workerPool; let numOfChunks = 0; let numOfWorkersUsed = 0; return { name: 'terser', async renderChunk(code, chunk, outputOptions) { if (!workerPool) { workerPool = new WorkerPool({ filePath: url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.src || new URL('index.js', document.baseURI).href))), maxWorkers }); } numOfChunks += 1; const defaultOptions = { sourceMap: outputOptions.sourcemap === true || typeof outputOptions.sourcemap === 'string' }; if (outputOptions.format === 'es') { defaultOptions.module = true; } if (outputOptions.format === 'cjs') { defaultOptions.toplevel = true; } try { const { code: result, nameCache, sourceMap } = await workerPool.addAsync({ code, options: smob.merge({}, options || {}, defaultOptions) }); if (options.nameCache && nameCache) { let vars = { props: {} }; if (smob.hasOwnProperty(options.nameCache, 'vars') && smob.isObject(options.nameCache.vars)) { vars = smob.merge({}, options.nameCache.vars || {}, vars); } if (smob.hasOwnProperty(nameCache, 'vars') && smob.isObject(nameCache.vars)) { vars = smob.merge({}, nameCache.vars, vars); } // eslint-disable-next-line no-param-reassign options.nameCache.vars = vars; let props = {}; if (smob.hasOwnProperty(options.nameCache, 'props') && smob.isObject(options.nameCache.props)) { // eslint-disable-next-line prefer-destructuring props = options.nameCache.props; } if (smob.hasOwnProperty(nameCache, 'props') && smob.isObject(nameCache.props)) { props = smob.merge({}, nameCache.props, props); } // eslint-disable-next-line no-param-reassign options.nameCache.props = props; } if ((!!defaultOptions.sourceMap || !!options.sourceMap) && smob.isObject(sourceMap)) { return { code: result, map: sourceMap }; } return result; } catch (e) { return Promise.reject(e); } finally { numOfChunks -= 1; if (numOfChunks === 0) { numOfWorkersUsed = workerPool.numWorkers; workerPool.close(); workerPool = null; } } }, get numOfWorkersUsed() { return numOfWorkersUsed; } }; } runWorker(); exports.default = terser; module.exports = Object.assign(exports.default, exports); //# sourceMappingURL=index.js.map