@rollup/plugin-terser 0.1.0 → 0.2.0

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/README.md CHANGED
@@ -9,11 +9,11 @@
9
9
 
10
10
  # @rollup/plugin-terser
11
11
 
12
- 🍣 A Rollup plugin to generate a minified output bundle.
12
+ 🍣 A Rollup plugin to generate a minified bundle with terser.
13
13
 
14
14
  ## Requirements
15
15
 
16
- This plugin requires an [LTS](https://github.com/nodejs/Release) Node version (v14.0.0+) and Rollup v1.20.0+.
16
+ This plugin requires an [LTS](https://github.com/nodejs/Release) Node version (v14.0.0+) and Rollup v2.0+.
17
17
 
18
18
  ## Install
19
19
 
@@ -27,7 +27,7 @@ npm install @rollup/plugin-terser --save-dev
27
27
 
28
28
  Create a `rollup.config.js` [configuration file](https://www.rollupjs.org/guide/en/#configuration-files) and import the plugin:
29
29
 
30
- ```js
30
+ ```typescript
31
31
  import terser from '@rollup/plugin-terser';
32
32
 
33
33
  export default {
@@ -47,13 +47,34 @@ Then call `rollup` either via the [CLI](https://www.rollupjs.org/guide/en/#comma
47
47
  The plugin accepts a terser [Options](https://github.com/terser/terser#minify-options) object as input parameter,
48
48
  to modify the default behaviour.
49
49
 
50
+ In addition to the `terser` options, it is also possible to provide the following options:
51
+
52
+ ### `maxWorkers`
53
+
54
+ Type: `Number`<br>
55
+ Default: `undefined`
56
+
57
+ Instructs the plugin to use a specific amount of cpu threads.
58
+
59
+ ```typescript
60
+ import terser from '@rollup/plugin-terser';
61
+
62
+ export default {
63
+ input: 'src/index.js',
64
+ output: {
65
+ dir: 'output',
66
+ format: 'cjs'
67
+ },
68
+ plugins: [
69
+ terser({
70
+ maxWorkers: 4
71
+ })
72
+ ]
73
+ };
74
+ ```
75
+
50
76
  ## Meta
51
77
 
52
78
  [CONTRIBUTING](/.github/CONTRIBUTING.md)
53
79
 
54
80
  [LICENSE (MIT)](/LICENSE)
55
-
56
- ## Credits
57
-
58
- This package was originally developed by [https://github.com/TrySound](TrySound) but is not
59
- maintained anymore.
package/dist/cjs/index.js CHANGED
@@ -2,9 +2,129 @@
2
2
 
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
+ var process = require('process');
6
+ var worker_threads = require('worker_threads');
7
+ var smob = require('smob');
5
8
  var terser$1 = require('terser');
9
+ var os = require('os');
10
+ var events = require('events');
11
+ var serializeJavascript = require('serialize-javascript');
6
12
 
7
- function terser(options) {
13
+ /**
14
+ * Duck typing worker context.
15
+ *
16
+ * @param input
17
+ */
18
+ function isWorkerContextSerialized(input) {
19
+ return (smob.isObject(input) &&
20
+ smob.hasOwnProperty(input, 'code') &&
21
+ typeof input.code === 'string' &&
22
+ smob.hasOwnProperty(input, 'options') &&
23
+ typeof input.options === 'string');
24
+ }
25
+ async function runWorker() {
26
+ if (worker_threads.isMainThread || !worker_threads.parentPort || !isWorkerContextSerialized(worker_threads.workerData)) {
27
+ return;
28
+ }
29
+ try {
30
+ // eslint-disable-next-line no-eval
31
+ const eval2 = eval;
32
+ const options = eval2(`(${worker_threads.workerData.options})`);
33
+ const result = await terser$1.minify(worker_threads.workerData.code, options);
34
+ const output = {
35
+ code: result.code || worker_threads.workerData.code,
36
+ nameCache: options.nameCache
37
+ };
38
+ worker_threads.parentPort.postMessage(output);
39
+ }
40
+ catch (e) {
41
+ process.exit(1);
42
+ }
43
+ }
44
+
45
+ const symbol = Symbol.for('FreeWoker');
46
+ class WorkerPool extends events.EventEmitter {
47
+ constructor(options) {
48
+ super();
49
+ this.tasks = [];
50
+ this.workers = 0;
51
+ this.maxInstances = options.maxWorkers || os.cpus().length;
52
+ this.filePath = options.filePath;
53
+ this.on(symbol, () => {
54
+ if (this.tasks.length > 0) {
55
+ this.run();
56
+ }
57
+ });
58
+ }
59
+ add(context, cb) {
60
+ this.tasks.push({
61
+ context,
62
+ cb
63
+ });
64
+ if (this.workers >= this.maxInstances) {
65
+ return;
66
+ }
67
+ this.run();
68
+ }
69
+ async addAsync(context) {
70
+ return new Promise((resolve, reject) => {
71
+ this.add(context, (err, output) => {
72
+ if (err) {
73
+ reject(err);
74
+ return;
75
+ }
76
+ if (!output) {
77
+ reject(new Error('The output is empty'));
78
+ return;
79
+ }
80
+ resolve(output);
81
+ });
82
+ });
83
+ }
84
+ run() {
85
+ if (this.tasks.length === 0) {
86
+ return;
87
+ }
88
+ const task = this.tasks.shift();
89
+ if (typeof task === 'undefined') {
90
+ return;
91
+ }
92
+ this.workers += 1;
93
+ let called = false;
94
+ const callCallback = (err, output) => {
95
+ if (called) {
96
+ return;
97
+ }
98
+ called = true;
99
+ this.workers -= 1;
100
+ task.cb(err, output);
101
+ this.emit(symbol);
102
+ };
103
+ const worker = new worker_threads.Worker(this.filePath, {
104
+ workerData: {
105
+ code: task.context.code,
106
+ options: serializeJavascript(task.context.options)
107
+ }
108
+ });
109
+ worker.on('message', (data) => {
110
+ callCallback(null, data);
111
+ });
112
+ worker.on('error', (err) => {
113
+ callCallback(err);
114
+ });
115
+ worker.on('exit', (code) => {
116
+ if (code !== 0) {
117
+ callCallback(new Error(`Minify worker stopped with exit code ${code}`));
118
+ }
119
+ });
120
+ }
121
+ }
122
+
123
+ function terser(options = {}) {
124
+ const workerPool = new WorkerPool({
125
+ filePath: __filename,
126
+ maxWorkers: options.maxWorkers
127
+ });
8
128
  return {
9
129
  name: 'terser',
10
130
  async renderChunk(code, chunk, outputOptions) {
@@ -17,11 +137,45 @@ function terser(options) {
17
137
  if (outputOptions.format === 'cjs') {
18
138
  defaultOptions.toplevel = true;
19
139
  }
20
- return terser$1.minify(code, { ...defaultOptions, ...(options || {}) });
140
+ try {
141
+ const { code: result, nameCache } = await workerPool.addAsync({
142
+ code,
143
+ options: smob.merge({}, options || {}, defaultOptions)
144
+ });
145
+ if (options.nameCache && nameCache) {
146
+ let vars = {
147
+ props: {}
148
+ };
149
+ if (smob.hasOwnProperty(options.nameCache, 'vars') && smob.isObject(options.nameCache.vars)) {
150
+ vars = smob.merge({}, options.nameCache.vars || {}, vars);
151
+ }
152
+ if (smob.hasOwnProperty(nameCache, 'vars') && smob.isObject(nameCache.vars)) {
153
+ vars = smob.merge({}, nameCache.vars, vars);
154
+ }
155
+ // eslint-disable-next-line no-param-reassign
156
+ options.nameCache.vars = vars;
157
+ let props = {};
158
+ if (smob.hasOwnProperty(options.nameCache, 'props') && smob.isObject(options.nameCache.props)) {
159
+ // eslint-disable-next-line prefer-destructuring
160
+ props = options.nameCache.props;
161
+ }
162
+ if (smob.hasOwnProperty(nameCache, 'props') && smob.isObject(nameCache.props)) {
163
+ props = smob.merge({}, nameCache.props, props);
164
+ }
165
+ // eslint-disable-next-line no-param-reassign
166
+ options.nameCache.props = props;
167
+ }
168
+ return result;
169
+ }
170
+ catch (e) {
171
+ return Promise.reject(e);
172
+ }
21
173
  }
22
174
  };
23
175
  }
24
176
 
177
+ runWorker();
178
+
25
179
  exports.default = terser;
26
180
  module.exports = Object.assign(exports.default, exports);
27
181
  //# sourceMappingURL=index.js.map
package/dist/es/index.js CHANGED
@@ -1,6 +1,126 @@
1
+ import process from 'process';
2
+ import { isMainThread, parentPort, workerData, Worker } from 'worker_threads';
3
+ import { isObject, hasOwnProperty, merge } from 'smob';
1
4
  import { minify } from 'terser';
5
+ import { cpus } from 'os';
6
+ import { EventEmitter } from 'events';
7
+ import serializeJavascript from 'serialize-javascript';
2
8
 
3
- function terser(options) {
9
+ /**
10
+ * Duck typing worker context.
11
+ *
12
+ * @param input
13
+ */
14
+ function isWorkerContextSerialized(input) {
15
+ return (isObject(input) &&
16
+ hasOwnProperty(input, 'code') &&
17
+ typeof input.code === 'string' &&
18
+ hasOwnProperty(input, 'options') &&
19
+ typeof input.options === 'string');
20
+ }
21
+ async function runWorker() {
22
+ if (isMainThread || !parentPort || !isWorkerContextSerialized(workerData)) {
23
+ return;
24
+ }
25
+ try {
26
+ // eslint-disable-next-line no-eval
27
+ const eval2 = eval;
28
+ const options = eval2(`(${workerData.options})`);
29
+ const result = await minify(workerData.code, options);
30
+ const output = {
31
+ code: result.code || workerData.code,
32
+ nameCache: options.nameCache
33
+ };
34
+ parentPort.postMessage(output);
35
+ }
36
+ catch (e) {
37
+ process.exit(1);
38
+ }
39
+ }
40
+
41
+ const symbol = Symbol.for('FreeWoker');
42
+ class WorkerPool extends EventEmitter {
43
+ constructor(options) {
44
+ super();
45
+ this.tasks = [];
46
+ this.workers = 0;
47
+ this.maxInstances = options.maxWorkers || cpus().length;
48
+ this.filePath = options.filePath;
49
+ this.on(symbol, () => {
50
+ if (this.tasks.length > 0) {
51
+ this.run();
52
+ }
53
+ });
54
+ }
55
+ add(context, cb) {
56
+ this.tasks.push({
57
+ context,
58
+ cb
59
+ });
60
+ if (this.workers >= this.maxInstances) {
61
+ return;
62
+ }
63
+ this.run();
64
+ }
65
+ async addAsync(context) {
66
+ return new Promise((resolve, reject) => {
67
+ this.add(context, (err, output) => {
68
+ if (err) {
69
+ reject(err);
70
+ return;
71
+ }
72
+ if (!output) {
73
+ reject(new Error('The output is empty'));
74
+ return;
75
+ }
76
+ resolve(output);
77
+ });
78
+ });
79
+ }
80
+ run() {
81
+ if (this.tasks.length === 0) {
82
+ return;
83
+ }
84
+ const task = this.tasks.shift();
85
+ if (typeof task === 'undefined') {
86
+ return;
87
+ }
88
+ this.workers += 1;
89
+ let called = false;
90
+ const callCallback = (err, output) => {
91
+ if (called) {
92
+ return;
93
+ }
94
+ called = true;
95
+ this.workers -= 1;
96
+ task.cb(err, output);
97
+ this.emit(symbol);
98
+ };
99
+ const worker = new Worker(this.filePath, {
100
+ workerData: {
101
+ code: task.context.code,
102
+ options: serializeJavascript(task.context.options)
103
+ }
104
+ });
105
+ worker.on('message', (data) => {
106
+ callCallback(null, data);
107
+ });
108
+ worker.on('error', (err) => {
109
+ callCallback(err);
110
+ });
111
+ worker.on('exit', (code) => {
112
+ if (code !== 0) {
113
+ callCallback(new Error(`Minify worker stopped with exit code ${code}`));
114
+ }
115
+ });
116
+ }
117
+ }
118
+
119
+ function terser(options = {}) {
120
+ const workerPool = new WorkerPool({
121
+ filePath: __filename,
122
+ maxWorkers: options.maxWorkers
123
+ });
4
124
  return {
5
125
  name: 'terser',
6
126
  async renderChunk(code, chunk, outputOptions) {
@@ -13,10 +133,44 @@ function terser(options) {
13
133
  if (outputOptions.format === 'cjs') {
14
134
  defaultOptions.toplevel = true;
15
135
  }
16
- return minify(code, { ...defaultOptions, ...(options || {}) });
136
+ try {
137
+ const { code: result, nameCache } = await workerPool.addAsync({
138
+ code,
139
+ options: merge({}, options || {}, defaultOptions)
140
+ });
141
+ if (options.nameCache && nameCache) {
142
+ let vars = {
143
+ props: {}
144
+ };
145
+ if (hasOwnProperty(options.nameCache, 'vars') && isObject(options.nameCache.vars)) {
146
+ vars = merge({}, options.nameCache.vars || {}, vars);
147
+ }
148
+ if (hasOwnProperty(nameCache, 'vars') && isObject(nameCache.vars)) {
149
+ vars = merge({}, nameCache.vars, vars);
150
+ }
151
+ // eslint-disable-next-line no-param-reassign
152
+ options.nameCache.vars = vars;
153
+ let props = {};
154
+ if (hasOwnProperty(options.nameCache, 'props') && isObject(options.nameCache.props)) {
155
+ // eslint-disable-next-line prefer-destructuring
156
+ props = options.nameCache.props;
157
+ }
158
+ if (hasOwnProperty(nameCache, 'props') && isObject(nameCache.props)) {
159
+ props = merge({}, nameCache.props, props);
160
+ }
161
+ // eslint-disable-next-line no-param-reassign
162
+ options.nameCache.props = props;
163
+ }
164
+ return result;
165
+ }
166
+ catch (e) {
167
+ return Promise.reject(e);
168
+ }
17
169
  }
18
170
  };
19
171
  }
20
172
 
173
+ runWorker();
174
+
21
175
  export { terser as default };
22
176
  //# sourceMappingURL=index.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rollup/plugin-terser",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -61,9 +61,12 @@
61
61
  }
62
62
  },
63
63
  "dependencies": {
64
+ "serialize-javascript": "^6.0.0",
65
+ "smob": "^0.0.6",
64
66
  "terser": "^5.15.1"
65
67
  },
66
68
  "devDependencies": {
69
+ "@types/serialize-javascript": "^5.0.2",
67
70
  "rollup": "^3.0.0-7",
68
71
  "typescript": "^4.8.3"
69
72
  },
package/src/index.ts CHANGED
@@ -1,24 +1,8 @@
1
- import { NormalizedOutputOptions, RenderedChunk } from 'rollup';
2
- import { minify, MinifyOptions } from 'terser';
1
+ import { runWorker } from './worker';
2
+ import terser from './module';
3
3
 
4
- export default function terser(options?: MinifyOptions) {
5
- return {
6
- name: 'terser',
4
+ runWorker();
7
5
 
8
- async renderChunk(code: string, chunk: RenderedChunk, outputOptions: NormalizedOutputOptions) {
9
- const defaultOptions: MinifyOptions = {
10
- sourceMap: outputOptions.sourcemap === true || typeof outputOptions.sourcemap === 'string'
11
- };
6
+ export * from './type';
12
7
 
13
- if (outputOptions.format === 'es') {
14
- defaultOptions.module = true;
15
- }
16
-
17
- if (outputOptions.format === 'cjs') {
18
- defaultOptions.toplevel = true;
19
- }
20
-
21
- return minify(code, { ...defaultOptions, ...(options || {}) });
22
- }
23
- };
24
- }
8
+ export default terser;
package/src/module.ts ADDED
@@ -0,0 +1,72 @@
1
+ import type { NormalizedOutputOptions, RenderedChunk } from 'rollup';
2
+ import { hasOwnProperty, isObject, merge } from 'smob';
3
+
4
+ import type { Options } from './type';
5
+ import { WorkerPool } from './worker-pool';
6
+
7
+ export default function terser(options: Options = {}) {
8
+ const workerPool = new WorkerPool({
9
+ filePath: __filename,
10
+ maxWorkers: options.maxWorkers
11
+ });
12
+
13
+ return {
14
+ name: 'terser',
15
+
16
+ async renderChunk(code: string, chunk: RenderedChunk, outputOptions: NormalizedOutputOptions) {
17
+ const defaultOptions: Options = {
18
+ sourceMap: outputOptions.sourcemap === true || typeof outputOptions.sourcemap === 'string'
19
+ };
20
+
21
+ if (outputOptions.format === 'es') {
22
+ defaultOptions.module = true;
23
+ }
24
+
25
+ if (outputOptions.format === 'cjs') {
26
+ defaultOptions.toplevel = true;
27
+ }
28
+
29
+ try {
30
+ const { code: result, nameCache } = await workerPool.addAsync({
31
+ code,
32
+ options: merge({}, options || {}, defaultOptions)
33
+ });
34
+
35
+ if (options.nameCache && nameCache) {
36
+ let vars: Record<string, any> = {
37
+ props: {}
38
+ };
39
+
40
+ if (hasOwnProperty(options.nameCache, 'vars') && isObject(options.nameCache.vars)) {
41
+ vars = merge({}, options.nameCache.vars || {}, vars);
42
+ }
43
+
44
+ if (hasOwnProperty(nameCache, 'vars') && isObject(nameCache.vars)) {
45
+ vars = merge({}, nameCache.vars, vars);
46
+ }
47
+
48
+ // eslint-disable-next-line no-param-reassign
49
+ options.nameCache.vars = vars;
50
+
51
+ let props: Record<string, any> = {};
52
+
53
+ if (hasOwnProperty(options.nameCache, 'props') && isObject(options.nameCache.props)) {
54
+ // eslint-disable-next-line prefer-destructuring
55
+ props = options.nameCache.props;
56
+ }
57
+
58
+ if (hasOwnProperty(nameCache, 'props') && isObject(nameCache.props)) {
59
+ props = merge({}, nameCache.props, props);
60
+ }
61
+
62
+ // eslint-disable-next-line no-param-reassign
63
+ options.nameCache.props = props;
64
+ }
65
+
66
+ return result;
67
+ } catch (e) {
68
+ return Promise.reject(e);
69
+ }
70
+ }
71
+ };
72
+ }
package/src/type.ts ADDED
@@ -0,0 +1,33 @@
1
+ import type { MinifyOptions } from 'terser';
2
+
3
+ export interface Options extends MinifyOptions {
4
+ nameCache?: Record<string, any>;
5
+ maxWorkers?: number;
6
+ }
7
+
8
+ export interface WorkerContext {
9
+ code: string;
10
+ options: Options;
11
+ }
12
+
13
+ export type WorkerCallback = (err: Error | null, output?: WorkerOutput) => void;
14
+
15
+ export interface WorkerContextSerialized {
16
+ code: string;
17
+ options: string;
18
+ }
19
+
20
+ export interface WorkerOutput {
21
+ code: string;
22
+ nameCache?: Options['nameCache'];
23
+ }
24
+
25
+ export interface WorkerPoolOptions {
26
+ filePath: string;
27
+ maxWorkers?: number;
28
+ }
29
+
30
+ export interface WorkerPoolTask {
31
+ context: WorkerContext;
32
+ cb: WorkerCallback;
33
+ }
@@ -0,0 +1,117 @@
1
+ import { Worker } from 'worker_threads';
2
+ import { cpus } from 'os';
3
+ import { EventEmitter } from 'events';
4
+
5
+ import serializeJavascript from 'serialize-javascript';
6
+
7
+ import type {
8
+ WorkerCallback,
9
+ WorkerContext,
10
+ WorkerOutput,
11
+ WorkerPoolOptions,
12
+ WorkerPoolTask
13
+ } from './type';
14
+
15
+ const symbol = Symbol.for('FreeWoker');
16
+
17
+ export class WorkerPool extends EventEmitter {
18
+ protected maxInstances: number;
19
+
20
+ protected filePath: string;
21
+
22
+ protected tasks: WorkerPoolTask[] = [];
23
+
24
+ protected workers = 0;
25
+
26
+ constructor(options: WorkerPoolOptions) {
27
+ super();
28
+
29
+ this.maxInstances = options.maxWorkers || cpus().length;
30
+ this.filePath = options.filePath;
31
+
32
+ this.on(symbol, () => {
33
+ if (this.tasks.length > 0) {
34
+ this.run();
35
+ }
36
+ });
37
+ }
38
+
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();
50
+ }
51
+
52
+ async addAsync(context: WorkerContext): Promise<WorkerOutput> {
53
+ return new Promise((resolve, reject) => {
54
+ this.add(context, (err, output) => {
55
+ if (err) {
56
+ reject(err);
57
+ return;
58
+ }
59
+
60
+ if (!output) {
61
+ reject(new Error('The output is empty'));
62
+ return;
63
+ }
64
+
65
+ resolve(output);
66
+ });
67
+ });
68
+ }
69
+
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;
79
+ }
80
+
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
+ });
102
+
103
+ worker.on('message', (data) => {
104
+ callCallback(null, data);
105
+ });
106
+
107
+ worker.on('error', (err) => {
108
+ callCallback(err);
109
+ });
110
+
111
+ worker.on('exit', (code) => {
112
+ if (code !== 0) {
113
+ callCallback(new Error(`Minify worker stopped with exit code ${code}`));
114
+ }
115
+ });
116
+ }
117
+ }
package/src/worker.ts ADDED
@@ -0,0 +1,47 @@
1
+ import process from 'process';
2
+ import { isMainThread, parentPort, workerData } from 'worker_threads';
3
+
4
+ import { hasOwnProperty, isObject } from 'smob';
5
+
6
+ import { minify } from 'terser';
7
+
8
+ import type { WorkerContextSerialized, WorkerOutput } from './type';
9
+
10
+ /**
11
+ * Duck typing worker context.
12
+ *
13
+ * @param input
14
+ */
15
+ function isWorkerContextSerialized(input: unknown): input is WorkerContextSerialized {
16
+ return (
17
+ isObject(input) &&
18
+ hasOwnProperty(input, 'code') &&
19
+ typeof input.code === 'string' &&
20
+ hasOwnProperty(input, 'options') &&
21
+ typeof input.options === 'string'
22
+ );
23
+ }
24
+
25
+ export async function runWorker() {
26
+ if (isMainThread || !parentPort || !isWorkerContextSerialized(workerData)) {
27
+ return;
28
+ }
29
+
30
+ try {
31
+ // eslint-disable-next-line no-eval
32
+ const eval2 = eval;
33
+
34
+ const options = eval2(`(${workerData.options})`);
35
+
36
+ const result = await minify(workerData.code, options);
37
+
38
+ const output: WorkerOutput = {
39
+ code: result.code || workerData.code,
40
+ nameCache: options.nameCache
41
+ };
42
+
43
+ parentPort.postMessage(output);
44
+ } catch (e) {
45
+ process.exit(1);
46
+ }
47
+ }
package/types/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { Plugin } from 'rollup';
2
- import { MinifyOptions } from 'terser';
1
+ import type { Plugin } from 'rollup';
2
+ import type { MinifyOptions } from 'terser';
3
3
 
4
4
  /**
5
5
  * A Rollup plugin to generate a minified output bundle.