import { fileURLToPath } from 'url'; import type { NormalizedOutputOptions, RenderedChunk } from 'rollup'; import { hasOwnProperty, isObject, merge } from 'smob'; import type { Options } from './type'; import { WorkerPool } from './worker-pool'; export default function terser(input: Options = {}) { const { maxWorkers, ...options } = input; let workerPool: WorkerPool | null | undefined; let numOfChunks = 0; let numOfWorkersUsed = 0; return { name: 'terser', async renderChunk(code: string, chunk: RenderedChunk, outputOptions: NormalizedOutputOptions) { if (!workerPool) { workerPool = new WorkerPool({ filePath: fileURLToPath(import.meta.url), maxWorkers }); } numOfChunks += 1; const defaultOptions: Options = { 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: merge({}, options || {}, defaultOptions) }); if (options.nameCache && nameCache) { let vars: Record = { props: {} }; if (hasOwnProperty(options.nameCache, 'vars') && isObject(options.nameCache.vars)) { vars = merge({}, options.nameCache.vars || {}, vars); } if (hasOwnProperty(nameCache, 'vars') && isObject(nameCache.vars)) { vars = merge({}, nameCache.vars, vars); } // eslint-disable-next-line no-param-reassign options.nameCache.vars = vars; let props: Record = {}; if (hasOwnProperty(options.nameCache, 'props') && isObject(options.nameCache.props)) { // eslint-disable-next-line prefer-destructuring props = options.nameCache.props; } if (hasOwnProperty(nameCache, 'props') && isObject(nameCache.props)) { props = merge({}, nameCache.props, props); } // eslint-disable-next-line no-param-reassign options.nameCache.props = props; } if ((!!defaultOptions.sourceMap || !!options.sourceMap) && 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; } }; }