UNPKG

56.6 kBMarkdownView Raw
1<h1><img src="https://terser.org/img/terser-banner-logo.png" alt="Terser" width="400"></h1>
2
3 [![NPM Version][npm-image]][npm-url]
4 [![NPM Downloads][downloads-image]][downloads-url]
5 [![Travis Build][travis-image]][travis-url]
6 [![Opencollective financial contributors][opencollective-contributors]][opencollective-url]
7
8A JavaScript parser and mangler/compressor toolkit for ES6+.
9
10*note*: You can support this project on patreon: <a target="_blank" rel="nofollow" href="https://www.patreon.com/fabiosantoscode"><img src="https://c5.patreon.com/external/logo/become_a_patron_button@2x.png" alt="patron" width="100px" height="auto"></a>. Check out [PATRONS.md](https://github.com/terser/terser/blob/master/PATRONS.md) for our first-tier patrons.
11
12Terser recommends you use RollupJS to bundle your modules, as that produces smaller code overall.
13
14*Beautification* has been undocumented and is *being removed* from terser, we recommend you use [prettier](https://npmjs.com/package/prettier).
15
16Find the changelog in [CHANGELOG.md](https://github.com/terser/terser/blob/master/CHANGELOG.md)
17
18
19
20[npm-image]: https://img.shields.io/npm/v/terser.svg
21[npm-url]: https://npmjs.org/package/terser
22[downloads-image]: https://img.shields.io/npm/dm/terser.svg
23[downloads-url]: https://npmjs.org/package/terser
24[travis-image]: https://img.shields.io/travis/terser/terser/master.svg
25[travis-url]: https://travis-ci.org/terser/terser
26[opencollective-contributors]: https://opencollective.com/terser/tiers/badge.svg
27[opencollective-url]: https://opencollective.com/terser
28
29Why choose terser?
30------------------
31
32`uglify-es` is [no longer maintained](https://github.com/mishoo/UglifyJS2/issues/3156#issuecomment-392943058) and `uglify-js` does not support ES6+.
33
34**`terser`** is a fork of `uglify-es` that mostly retains API and CLI compatibility
35with `uglify-es` and `uglify-js@3`.
36
37Install
38-------
39
40First make sure you have installed the latest version of [node.js](http://nodejs.org/)
41(You may need to restart your computer after this step).
42
43From NPM for use as a command line app:
44
45 npm install terser -g
46
47From NPM for programmatic use:
48
49 npm install terser
50
51# Command line usage
52
53 terser [input files] [options]
54
55Terser can take multiple input files. It's recommended that you pass the
56input files first, then pass the options. Terser will parse input files
57in sequence and apply any compression options. The files are parsed in the
58same global scope, that is, a reference from a file to some
59variable/function declared in another file will be matched properly.
60
61If no input file is specified, Terser will read from STDIN.
62
63If you wish to pass your options before the input files, separate the two with
64a double dash to prevent input files being used as option arguments:
65
66 terser --compress --mangle -- input.js
67
68### Command line options
69
70```
71 -h, --help Print usage information.
72 `--help options` for details on available options.
73 -V, --version Print version number.
74 -p, --parse <options> Specify parser options:
75 `acorn` Use Acorn for parsing.
76 `bare_returns` Allow return outside of functions.
77 Useful when minifying CommonJS
78 modules and Userscripts that may
79 be anonymous function wrapped (IIFE)
80 by the .user.js engine `caller`.
81 `expression` Parse a single expression, rather than
82 a program (for parsing JSON).
83 `spidermonkey` Assume input files are SpiderMonkey
84 AST format (as JSON).
85 -c, --compress [options] Enable compressor/specify compressor options:
86 `pure_funcs` List of functions that can be safely
87 removed when their return values are
88 not used.
89 -m, --mangle [options] Mangle names/specify mangler options:
90 `reserved` List of names that should not be mangled.
91 --mangle-props [options] Mangle properties/specify mangler options:
92 `builtins` Mangle property names that overlaps
93 with standard JavaScript globals and DOM
94 API props.
95 `debug` Add debug prefix and suffix.
96 `keep_quoted` Only mangle unquoted properties, quoted
97 properties are automatically reserved.
98 `strict` disables quoted properties
99 being automatically reserved.
100 `regex` Only mangle matched property names.
101 `reserved` List of names that should not be mangled.
102 -f, --format [options] Specify format options.
103 `preamble` Preamble to prepend to the output. You
104 can use this to insert a comment, for
105 example for licensing information.
106 This will not be parsed, but the source
107 map will adjust for its presence.
108 `quote_style` Quote style:
109 0 - auto
110 1 - single
111 2 - double
112 3 - original
113 `wrap_iife` Wrap IIFEs in parenthesis. Note: you may
114 want to disable `negate_iife` under
115 compressor options.
116 `wrap_func_args` Wrap function arguments in parenthesis.
117 -o, --output <file> Output file path (default STDOUT). Specify `ast` or
118 `spidermonkey` to write Terser or SpiderMonkey AST
119 as JSON to STDOUT respectively.
120 --comments [filter] Preserve copyright comments in the output. By
121 default this works like Google Closure, keeping
122 JSDoc-style comments that contain "@license" or
123 "@preserve". You can optionally pass one of the
124 following arguments to this flag:
125 - "all" to keep all comments
126 - `false` to omit comments in the output
127 - a valid JS RegExp like `/foo/` or `/^!/` to
128 keep only matching comments.
129 Note that currently not *all* comments can be
130 kept when compression is on, because of dead
131 code removal or cascading statements into
132 sequences.
133 --config-file <file> Read `minify()` options from JSON file.
134 -d, --define <expr>[=value] Global definitions.
135 --ecma <version> Specify ECMAScript release: 5, 2015, 2016, etc.
136 -e, --enclose [arg[:value]] Embed output in a big function with configurable
137 arguments and values.
138 --ie8 Support non-standard Internet Explorer 8.
139 Equivalent to setting `ie8: true` in `minify()`
140 for `compress`, `mangle` and `format` options.
141 By default Terser will not try to be IE-proof.
142 --keep-classnames Do not mangle/drop class names.
143 --keep-fnames Do not mangle/drop function names. Useful for
144 code relying on Function.prototype.name.
145 --module Input is an ES6 module. If `compress` or `mangle` is
146 enabled then the `toplevel` option will be enabled.
147 --name-cache <file> File to hold mangled name mappings.
148 --safari10 Support non-standard Safari 10/11.
149 Equivalent to setting `safari10: true` in `minify()`
150 for `mangle` and `format` options.
151 By default `terser` will not work around
152 Safari 10/11 bugs.
153 --source-map [options] Enable source map/specify source map options:
154 `base` Path to compute relative paths from input files.
155 `content` Input source map, useful if you're compressing
156 JS that was generated from some other original
157 code. Specify "inline" if the source map is
158 included within the sources.
159 `filename` Name and/or location of the output source.
160 `includeSources` Pass this flag if you want to include
161 the content of source files in the
162 source map as sourcesContent property.
163 `root` Path to the original source to be included in
164 the source map.
165 `url` If specified, path to the source map to append in
166 `//# sourceMappingURL`.
167 --timings Display operations run time on STDERR.
168 --toplevel Compress and/or mangle variables in top level scope.
169 --wrap <name> Embed everything in a big function, making the
170 “exports” and “global” variables available. You
171 need to pass an argument to this option to
172 specify the name that your module will take
173 when included in, say, a browser.
174```
175
176Specify `--output` (`-o`) to declare the output file. Otherwise the output
177goes to STDOUT.
178
179## CLI source map options
180
181Terser can generate a source map file, which is highly useful for
182debugging your compressed JavaScript. To get a source map, pass
183`--source-map --output output.js` (source map will be written out to
184`output.js.map`).
185
186Additional options:
187
188- `--source-map "filename='<NAME>'"` to specify the name of the source map.
189
190- `--source-map "root='<URL>'"` to pass the URL where the original files can be found.
191
192- `--source-map "url='<URL>'"` to specify the URL where the source map can be found.
193 Otherwise Terser assumes HTTP `X-SourceMap` is being used and will omit the
194 `//# sourceMappingURL=` directive.
195
196For example:
197
198 terser js/file1.js js/file2.js \
199 -o foo.min.js -c -m \
200 --source-map "root='http://foo.com/src',url='foo.min.js.map'"
201
202The above will compress and mangle `file1.js` and `file2.js`, will drop the
203output in `foo.min.js` and the source map in `foo.min.js.map`. The source
204mapping will refer to `http://foo.com/src/js/file1.js` and
205`http://foo.com/src/js/file2.js` (in fact it will list `http://foo.com/src`
206as the source map root, and the original files as `js/file1.js` and
207`js/file2.js`).
208
209### Composed source map
210
211When you're compressing JS code that was output by a compiler such as
212CoffeeScript, mapping to the JS code won't be too helpful. Instead, you'd
213like to map back to the original code (i.e. CoffeeScript). Terser has an
214option to take an input source map. Assuming you have a mapping from
215CoffeeScript → compiled JS, Terser can generate a map from CoffeeScript →
216compressed JS by mapping every token in the compiled JS to its original
217location.
218
219To use this feature pass `--source-map "content='/path/to/input/source.map'"`
220or `--source-map "content=inline"` if the source map is included inline with
221the sources.
222
223## CLI compress options
224
225You need to pass `--compress` (`-c`) to enable the compressor. Optionally
226you can pass a comma-separated list of [compress options](#compress-options).
227
228Options are in the form `foo=bar`, or just `foo` (the latter implies
229a boolean option that you want to set `true`; it's effectively a
230shortcut for `foo=true`).
231
232Example:
233
234 terser file.js -c toplevel,sequences=false
235
236## CLI mangle options
237
238To enable the mangler you need to pass `--mangle` (`-m`). The following
239(comma-separated) options are supported:
240
241- `toplevel` (default `false`) -- mangle names declared in the top level scope.
242
243- `eval` (default `false`) -- mangle names visible in scopes where `eval` or `with` are used.
244
245When mangling is enabled but you want to prevent certain names from being
246mangled, you can declare those names with `--mangle reserved` — pass a
247comma-separated list of names. For example:
248
249 terser ... -m reserved=['$','require','exports']
250
251to prevent the `require`, `exports` and `$` names from being changed.
252
253### CLI mangling property names (`--mangle-props`)
254
255**Note:** THIS **WILL** BREAK YOUR CODE. A good rule of thumb is not to use this unless you know exactly what you're doing and how this works and read this section until the end.
256
257Mangling property names is a separate step, different from variable name mangling. Pass
258`--mangle-props` to enable it. The least dangerous
259way to use this is to use the `regex` option like so:
260
261```
262terser example.js -c -m --mangle-props regex=/_$/
263```
264
265This will mangle all properties that end with an
266underscore. So you can use it to mangle internal methods.
267
268By default, it will mangle all properties in the
269input code with the exception of built in DOM properties and properties
270in core JavaScript classes, which is what will break your code if you don't:
271
2721. Control all the code you're mangling
2732. Avoid using a module bundler, as they usually will call Terser on each file individually, making it impossible to pass mangled objects between modules.
2743. Avoid calling functions like `defineProperty` or `hasOwnProperty`, because they refer to object properties using strings and will break your code if you don't know what you are doing.
275
276An example:
277
278```javascript
279// example.js
280var x = {
281 baz_: 0,
282 foo_: 1,
283 calc: function() {
284 return this.foo_ + this.baz_;
285 }
286};
287x.bar_ = 2;
288x["baz_"] = 3;
289console.log(x.calc());
290```
291Mangle all properties (except for JavaScript `builtins`) (**very** unsafe):
292```bash
293$ terser example.js -c passes=2 -m --mangle-props
294```
295```javascript
296var x={o:3,t:1,i:function(){return this.t+this.o},s:2};console.log(x.i());
297```
298Mangle all properties except for `reserved` properties (still very unsafe):
299```bash
300$ terser example.js -c passes=2 -m --mangle-props reserved=[foo_,bar_]
301```
302```javascript
303var x={o:3,foo_:1,t:function(){return this.foo_+this.o},bar_:2};console.log(x.t());
304```
305Mangle all properties matching a `regex` (not as unsafe but still unsafe):
306```bash
307$ terser example.js -c passes=2 -m --mangle-props regex=/_$/
308```
309```javascript
310var x={o:3,t:1,calc:function(){return this.t+this.o},i:2};console.log(x.calc());
311```
312
313Combining mangle properties options:
314```bash
315$ terser example.js -c passes=2 -m --mangle-props regex=/_$/,reserved=[bar_]
316```
317```javascript
318var x={o:3,t:1,calc:function(){return this.t+this.o},bar_:2};console.log(x.calc());
319```
320
321In order for this to be of any use, we avoid mangling standard JS names and DOM
322API properties by default (`--mangle-props builtins` to override).
323
324A regular expression can be used to define which property names should be
325mangled. For example, `--mangle-props regex=/^_/` will only mangle property
326names that start with an underscore.
327
328When you compress multiple files using this option, in order for them to
329work together in the end we need to ensure somehow that one property gets
330mangled to the same name in all of them. For this, pass `--name-cache filename.json`
331and Terser will maintain these mappings in a file which can then be reused.
332It should be initially empty. Example:
333
334```bash
335$ rm -f /tmp/cache.json # start fresh
336$ terser file1.js file2.js --mangle-props --name-cache /tmp/cache.json -o part1.js
337$ terser file3.js file4.js --mangle-props --name-cache /tmp/cache.json -o part2.js
338```
339
340Now, `part1.js` and `part2.js` will be consistent with each other in terms
341of mangled property names.
342
343Using the name cache is not necessary if you compress all your files in a
344single call to Terser.
345
346### Mangling unquoted names (`--mangle-props keep_quoted`)
347
348Using quoted property name (`o["foo"]`) reserves the property name (`foo`)
349so that it is not mangled throughout the entire script even when used in an
350unquoted style (`o.foo`). Example:
351
352```javascript
353// stuff.js
354var o = {
355 "foo": 1,
356 bar: 3
357};
358o.foo += o.bar;
359console.log(o.foo);
360```
361```bash
362$ terser stuff.js --mangle-props keep_quoted -c -m
363```
364```javascript
365var o={foo:1,o:3};o.foo+=o.o,console.log(o.foo);
366```
367
368### Debugging property name mangling
369
370You can also pass `--mangle-props debug` in order to mangle property names
371without completely obscuring them. For example the property `o.foo`
372would mangle to `o._$foo$_` with this option. This allows property mangling
373of a large codebase while still being able to debug the code and identify
374where mangling is breaking things.
375
376```bash
377$ terser stuff.js --mangle-props debug -c -m
378```
379```javascript
380var o={_$foo$_:1,_$bar$_:3};o._$foo$_+=o._$bar$_,console.log(o._$foo$_);
381```
382
383You can also pass a custom suffix using `--mangle-props debug=XYZ`. This would then
384mangle `o.foo` to `o._$foo$XYZ_`. You can change this each time you compile a
385script to identify how a property got mangled. One technique is to pass a
386random number on every compile to simulate mangling changing with different
387inputs (e.g. as you update the input script with new properties), and to help
388identify mistakes like writing mangled keys to storage.
389
390
391# API Reference
392
393Assuming installation via NPM, you can load Terser in your application
394like this:
395
396```javascript
397const { minify } = require("terser");
398```
399
400Or,
401
402```javascript
403import { minify } from "terser";
404```
405
406Browser loading is also supported:
407```html
408<script src="node_modules/source-map/dist/source-map.min.js"></script>
409<script src="dist/bundle.min.js"></script>
410```
411
412There is a single async high level function, **`async minify(code, options)`**,
413which will perform all minification [phases](#minify-options) in a configurable
414manner. There is no synchronous function, but this functionality can be achieved with a package like [deasync](https://github.com/abbr/deasync). By default `minify()` will enable the options [`compress`](#compress-options)
415and [`mangle`](#mangle-options). Example:
416```javascript
417var code = "function add(first, second) { return first + second; }";
418var result = await minify(code, { sourceMap: true });
419console.log(result.code); // minified output: function add(n,d){return n+d}
420console.log(result.map); // source map
421```
422
423You can `minify` more than one JavaScript file at a time by using an object
424for the first argument where the keys are file names and the values are source
425code:
426```javascript
427var code = {
428 "file1.js": "function add(first, second) { return first + second; }",
429 "file2.js": "console.log(add(1 + 2, 3 + 4));"
430};
431var result = await minify(code);
432console.log(result.code);
433// function add(d,n){return d+n}console.log(add(3,7));
434```
435
436The `toplevel` option:
437```javascript
438var code = {
439 "file1.js": "function add(first, second) { return first + second; }",
440 "file2.js": "console.log(add(1 + 2, 3 + 4));"
441};
442var options = { toplevel: true };
443var result = await minify(code, options);
444console.log(result.code);
445// console.log(3+7);
446```
447
448The `nameCache` option:
449```javascript
450var options = {
451 mangle: {
452 toplevel: true,
453 },
454 nameCache: {}
455};
456var result1 = await minify({
457 "file1.js": "function add(first, second) { return first + second; }"
458}, options);
459var result2 = await minify({
460 "file2.js": "console.log(add(1 + 2, 3 + 4));"
461}, options);
462console.log(result1.code);
463// function n(n,r){return n+r}
464console.log(result2.code);
465// console.log(n(3,7));
466```
467
468You may persist the name cache to the file system in the following way:
469```javascript
470var cacheFileName = "/tmp/cache.json";
471var options = {
472 mangle: {
473 properties: true,
474 },
475 nameCache: JSON.parse(fs.readFileSync(cacheFileName, "utf8"))
476};
477fs.writeFileSync("part1.js", await minify({
478 "file1.js": fs.readFileSync("file1.js", "utf8"),
479 "file2.js": fs.readFileSync("file2.js", "utf8")
480}, options).code, "utf8");
481fs.writeFileSync("part2.js", await minify({
482 "file3.js": fs.readFileSync("file3.js", "utf8"),
483 "file4.js": fs.readFileSync("file4.js", "utf8")
484}, options).code, "utf8");
485fs.writeFileSync(cacheFileName, JSON.stringify(options.nameCache), "utf8");
486```
487
488An example of a combination of `minify()` options:
489```javascript
490var code = {
491 "file1.js": "function add(first, second) { return first + second; }",
492 "file2.js": "console.log(add(1 + 2, 3 + 4));"
493};
494var options = {
495 toplevel: true,
496 compress: {
497 global_defs: {
498 "@console.log": "alert"
499 },
500 passes: 2
501 },
502 format: {
503 preamble: "/* minified */"
504 }
505};
506var result = await minify(code, options);
507console.log(result.code);
508// /* minified */
509// alert(10);"
510```
511
512An error example:
513```javascript
514try {
515 const result = await minify({"foo.js" : "if (0) else console.log(1);"});
516 // Do something with result
517} catch (error) {
518 const { message, filename, line, col, pos } = error;
519 // Do something with error
520}
521```
522
523## Minify options
524
525- `ecma` (default `undefined`) - pass `5`, `2015`, `2016`, etc to override
526 `compress` and `format`'s `ecma` options.
527
528- `parse` (default `{}`) — pass an object if you wish to specify some
529 additional [parse options](#parse-options).
530
531- `compress` (default `{}`) — pass `false` to skip compressing entirely.
532 Pass an object to specify custom [compress options](#compress-options).
533
534- `mangle` (default `true`) — pass `false` to skip mangling names, or pass
535 an object to specify [mangle options](#mangle-options) (see below).
536
537 - `mangle.properties` (default `false`) — a subcategory of the mangle option.
538 Pass an object to specify custom [mangle property options](#mangle-properties-options).
539
540- `module` (default `false`) — Use when minifying an ES6 module. "use strict"
541 is implied and names can be mangled on the top scope. If `compress` or
542 `mangle` is enabled then the `toplevel` option will be enabled.
543
544- `format` or `output` (default `null`) — pass an object if you wish to specify
545 additional [format options](#format-options). The defaults are optimized
546 for best compression.
547
548- `sourceMap` (default `false`) - pass an object if you wish to specify
549 [source map options](#source-map-options).
550
551- `toplevel` (default `false`) - set to `true` if you wish to enable top level
552 variable and function name mangling and to drop unused variables and functions.
553
554- `nameCache` (default `null`) - pass an empty object `{}` or a previously
555 used `nameCache` object if you wish to cache mangled variable and
556 property names across multiple invocations of `minify()`. Note: this is
557 a read/write property. `minify()` will read the name cache state of this
558 object and update it during minification so that it may be
559 reused or externally persisted by the user.
560
561- `ie8` (default `false`) - set to `true` to support IE8.
562
563- `keep_classnames` (default: `undefined`) - pass `true` to prevent discarding or mangling
564 of class names. Pass a regular expression to only keep class names matching that regex.
565
566- `keep_fnames` (default: `false`) - pass `true` to prevent discarding or mangling
567 of function names. Pass a regular expression to only keep class names matching that regex.
568 Useful for code relying on `Function.prototype.name`. If the top level minify option
569 `keep_classnames` is `undefined` it will be overridden with the value of the top level
570 minify option `keep_fnames`.
571
572- `safari10` (default: `false`) - pass `true` to work around Safari 10/11 bugs in
573 loop scoping and `await`. See `safari10` options in [`mangle`](#mangle-options)
574 and [`format`](#format-options) for details.
575
576## Minify options structure
577
578```javascript
579{
580 parse: {
581 // parse options
582 },
583 compress: {
584 // compress options
585 },
586 mangle: {
587 // mangle options
588
589 properties: {
590 // mangle property options
591 }
592 },
593 format: {
594 // format options (can also use `output` for backwards compatibility)
595 },
596 sourceMap: {
597 // source map options
598 },
599 ecma: 5, // specify one of: 5, 2015, 2016, etc.
600 keep_classnames: false,
601 keep_fnames: false,
602 ie8: false,
603 module: false,
604 nameCache: null, // or specify a name cache object
605 safari10: false,
606 toplevel: false,
607}
608```
609
610### Source map options
611
612To generate a source map:
613```javascript
614var result = await minify({"file1.js": "var a = function() {};"}, {
615 sourceMap: {
616 filename: "out.js",
617 url: "out.js.map"
618 }
619});
620console.log(result.code); // minified output
621console.log(result.map); // source map
622```
623
624Note that the source map is not saved in a file, it's just returned in
625`result.map`. The value passed for `sourceMap.url` is only used to set
626`//# sourceMappingURL=out.js.map` in `result.code`. The value of
627`filename` is only used to set `file` attribute (see [the spec][sm-spec])
628in source map file.
629
630You can set option `sourceMap.url` to be `"inline"` and source map will
631be appended to code.
632
633You can also specify sourceRoot property to be included in source map:
634```javascript
635var result = await minify({"file1.js": "var a = function() {};"}, {
636 sourceMap: {
637 root: "http://example.com/src",
638 url: "out.js.map"
639 }
640});
641```
642
643If you're compressing compiled JavaScript and have a source map for it, you
644can use `sourceMap.content`:
645```javascript
646var result = await minify({"compiled.js": "compiled code"}, {
647 sourceMap: {
648 content: "content from compiled.js.map",
649 url: "minified.js.map"
650 }
651});
652// same as before, it returns `code` and `map`
653```
654
655If you're using the `X-SourceMap` header instead, you can just omit `sourceMap.url`.
656
657If you happen to need the source map as a raw object, set `sourceMap.asObject` to `true`.
658
659## Parse options
660
661- `bare_returns` (default `false`) -- support top level `return` statements
662
663- `html5_comments` (default `true`)
664
665- `shebang` (default `true`) -- support `#!command` as the first line
666
667## Compress options
668
669- `defaults` (default: `true`) -- Pass `false` to disable most default
670 enabled `compress` transforms. Useful when you only want to enable a few
671 `compress` options while disabling the rest.
672
673- `arrows` (default: `true`) -- Class and object literal methods are converted
674 will also be converted to arrow expressions if the resultant code is shorter:
675 `m(){return x}` becomes `m:()=>x`. To do this to regular ES5 functions which
676 don't use `this` or `arguments`, see `unsafe_arrows`.
677
678- `arguments` (default: `false`) -- replace `arguments[index]` with function
679 parameter name whenever possible.
680
681- `booleans` (default: `true`) -- various optimizations for boolean context,
682 for example `!!a ? b : c → a ? b : c`
683
684- `booleans_as_integers` (default: `false`) -- Turn booleans into 0 and 1, also
685 makes comparisons with booleans use `==` and `!=` instead of `===` and `!==`.
686
687- `collapse_vars` (default: `true`) -- Collapse single-use non-constant variables,
688 side effects permitting.
689
690- `comparisons` (default: `true`) -- apply certain optimizations to binary nodes,
691 e.g. `!(a <= b) → a > b` (only when `unsafe_comps`), attempts to negate binary
692 nodes, e.g. `a = !b && !c && !d && !e → a=!(b||c||d||e)` etc.
693
694- `computed_props` (default: `true`) -- Transforms constant computed properties
695 into regular ones: `{["computed"]: 1}` is converted to `{computed: 1}`.
696
697- `conditionals` (default: `true`) -- apply optimizations for `if`-s and conditional
698 expressions
699
700- `dead_code` (default: `true`) -- remove unreachable code
701
702- `directives` (default: `true`) -- remove redundant or non-standard directives
703
704- `drop_console` (default: `false`) -- Pass `true` to discard calls to
705 `console.*` functions. If you wish to drop a specific function call
706 such as `console.info` and/or retain side effects from function arguments
707 after dropping the function call then use `pure_funcs` instead.
708
709- `drop_debugger` (default: `true`) -- remove `debugger;` statements
710
711- `ecma` (default: `5`) -- Pass `2015` or greater to enable `compress` options that
712 will transform ES5 code into smaller ES6+ equivalent forms.
713
714- `evaluate` (default: `true`) -- attempt to evaluate constant expressions
715
716- `expression` (default: `false`) -- Pass `true` to preserve completion values
717 from terminal statements without `return`, e.g. in bookmarklets.
718
719- `global_defs` (default: `{}`) -- see [conditional compilation](#conditional-compilation)
720
721- `hoist_funs` (default: `false`) -- hoist function declarations
722
723- `hoist_props` (default: `true`) -- hoist properties from constant object and
724 array literals into regular variables subject to a set of constraints. For example:
725 `var o={p:1, q:2}; f(o.p, o.q);` is converted to `f(1, 2);`. Note: `hoist_props`
726 works best with `mangle` enabled, the `compress` option `passes` set to `2` or higher,
727 and the `compress` option `toplevel` enabled.
728
729- `hoist_vars` (default: `false`) -- hoist `var` declarations (this is `false`
730 by default because it seems to increase the size of the output in general)
731
732- `if_return` (default: `true`) -- optimizations for if/return and if/continue
733
734- `inline` (default: `true`) -- inline calls to function with simple/`return` statement:
735 - `false` -- same as `0`
736 - `0` -- disabled inlining
737 - `1` -- inline simple functions
738 - `2` -- inline functions with arguments
739 - `3` -- inline functions with arguments and variables
740 - `true` -- same as `3`
741
742- `join_vars` (default: `true`) -- join consecutive `var` statements
743
744- `keep_classnames` (default: `false`) -- Pass `true` to prevent the compressor from
745 discarding class names. Pass a regular expression to only keep class names matching
746 that regex. See also: the `keep_classnames` [mangle option](#mangle).
747
748- `keep_fargs` (default: `true`) -- Prevents the compressor from discarding unused
749 function arguments. You need this for code which relies on `Function.length`.
750
751- `keep_fnames` (default: `false`) -- Pass `true` to prevent the
752 compressor from discarding function names. Pass a regular expression to only keep
753 function names matching that regex. Useful for code relying on `Function.prototype.name`.
754 See also: the `keep_fnames` [mangle option](#mangle).
755
756- `keep_infinity` (default: `false`) -- Pass `true` to prevent `Infinity` from
757 being compressed into `1/0`, which may cause performance issues on Chrome.
758
759- `loops` (default: `true`) -- optimizations for `do`, `while` and `for` loops
760 when we can statically determine the condition.
761
762- `module` (default `false`) -- Pass `true` when compressing an ES6 module. Strict
763 mode is implied and the `toplevel` option as well.
764
765- `negate_iife` (default: `true`) -- negate "Immediately-Called Function Expressions"
766 where the return value is discarded, to avoid the parens that the
767 code generator would insert.
768
769- `passes` (default: `1`) -- The maximum number of times to run compress.
770 In some cases more than one pass leads to further compressed code. Keep in
771 mind more passes will take more time.
772
773- `properties` (default: `true`) -- rewrite property access using the dot notation, for
774 example `foo["bar"] → foo.bar`
775
776- `pure_funcs` (default: `null`) -- You can pass an array of names and
777 Terser will assume that those functions do not produce side
778 effects. DANGER: will not check if the name is redefined in scope.
779 An example case here, for instance `var q = Math.floor(a/b)`. If
780 variable `q` is not used elsewhere, Terser will drop it, but will
781 still keep the `Math.floor(a/b)`, not knowing what it does. You can
782 pass `pure_funcs: [ 'Math.floor' ]` to let it know that this
783 function won't produce any side effect, in which case the whole
784 statement would get discarded. The current implementation adds some
785 overhead (compression will be slower).
786
787- `pure_getters` (default: `"strict"`) -- If you pass `true` for
788 this, Terser will assume that object property access
789 (e.g. `foo.bar` or `foo["bar"]`) doesn't have any side effects.
790 Specify `"strict"` to treat `foo.bar` as side-effect-free only when
791 `foo` is certain to not throw, i.e. not `null` or `undefined`.
792
793- `reduce_funcs` (legacy option, safely ignored for backwards compatibility).
794
795- `reduce_vars` (default: `true`) -- Improve optimization on variables assigned with and
796 used as constant values.
797
798- `sequences` (default: `true`) -- join consecutive simple statements using the
799 comma operator. May be set to a positive integer to specify the maximum number
800 of consecutive comma sequences that will be generated. If this option is set to
801 `true` then the default `sequences` limit is `200`. Set option to `false` or `0`
802 to disable. The smallest `sequences` length is `2`. A `sequences` value of `1`
803 is grandfathered to be equivalent to `true` and as such means `200`. On rare
804 occasions the default sequences limit leads to very slow compress times in which
805 case a value of `20` or less is recommended.
806
807- `side_effects` (default: `true`) -- Remove expressions which have no side effects
808 and whose results aren't used.
809
810- `switches` (default: `true`) -- de-duplicate and remove unreachable `switch` branches
811
812- `toplevel` (default: `false`) -- drop unreferenced functions (`"funcs"`) and/or
813 variables (`"vars"`) in the top level scope (`false` by default, `true` to drop
814 both unreferenced functions and variables)
815
816- `top_retain` (default: `null`) -- prevent specific toplevel functions and
817 variables from `unused` removal (can be array, comma-separated, RegExp or
818 function. Implies `toplevel`)
819
820- `typeofs` (default: `true`) -- Transforms `typeof foo == "undefined"` into
821 `foo === void 0`. Note: recommend to set this value to `false` for IE10 and
822 earlier versions due to known issues.
823
824- `unsafe` (default: `false`) -- apply "unsafe" transformations
825 ([details](#the-unsafe-compress-option)).
826
827- `unsafe_arrows` (default: `false`) -- Convert ES5 style anonymous function
828 expressions to arrow functions if the function body does not reference `this`.
829 Note: it is not always safe to perform this conversion if code relies on the
830 the function having a `prototype`, which arrow functions lack.
831 This transform requires that the `ecma` compress option is set to `2015` or greater.
832
833- `unsafe_comps` (default: `false`) -- Reverse `<` and `<=` to `>` and `>=` to
834 allow improved compression. This might be unsafe when an at least one of two
835 operands is an object with computed values due the use of methods like `get`,
836 or `valueOf`. This could cause change in execution order after operands in the
837 comparison are switching. Compression only works if both `comparisons` and
838 `unsafe_comps` are both set to true.
839
840- `unsafe_Function` (default: `false`) -- compress and mangle `Function(args, code)`
841 when both `args` and `code` are string literals.
842
843- `unsafe_math` (default: `false`) -- optimize numerical expressions like
844 `2 * x * 3` into `6 * x`, which may give imprecise floating point results.
845
846- `unsafe_symbols` (default: `false`) -- removes keys from native Symbol
847 declarations, e.g `Symbol("kDog")` becomes `Symbol()`.
848
849- `unsafe_methods` (default: false) -- Converts `{ m: function(){} }` to
850 `{ m(){} }`. `ecma` must be set to `6` or greater to enable this transform.
851 If `unsafe_methods` is a RegExp then key/value pairs with keys matching the
852 RegExp will be converted to concise methods.
853 Note: if enabled there is a risk of getting a "`<method name>` is not a
854 constructor" TypeError should any code try to `new` the former function.
855
856- `unsafe_proto` (default: `false`) -- optimize expressions like
857 `Array.prototype.slice.call(a)` into `[].slice.call(a)`
858
859- `unsafe_regexp` (default: `false`) -- enable substitutions of variables with
860 `RegExp` values the same way as if they are constants.
861
862- `unsafe_undefined` (default: `false`) -- substitute `void 0` if there is a
863 variable named `undefined` in scope (variable name will be mangled, typically
864 reduced to a single character)
865
866- `unused` (default: `true`) -- drop unreferenced functions and variables (simple
867 direct variable assignments do not count as references unless set to `"keep_assign"`)
868
869## Mangle options
870
871- `eval` (default `false`) -- Pass `true` to mangle names visible in scopes
872 where `eval` or `with` are used.
873
874- `keep_classnames` (default `false`) -- Pass `true` to not mangle class names.
875 Pass a regular expression to only keep class names matching that regex.
876 See also: the `keep_classnames` [compress option](#compress-options).
877
878- `keep_fnames` (default `false`) -- Pass `true` to not mangle function names.
879 Pass a regular expression to only keep class names matching that regex.
880 Useful for code relying on `Function.prototype.name`. See also: the `keep_fnames`
881 [compress option](#compress-options).
882
883- `module` (default `false`) -- Pass `true` an ES6 modules, where the toplevel
884 scope is not the global scope. Implies `toplevel`.
885
886- `reserved` (default `[]`) -- Pass an array of identifiers that should be
887 excluded from mangling. Example: `["foo", "bar"]`.
888
889- `toplevel` (default `false`) -- Pass `true` to mangle names declared in the
890 top level scope.
891
892- `safari10` (default `false`) -- Pass `true` to work around the Safari 10 loop
893 iterator [bug](https://bugs.webkit.org/show_bug.cgi?id=171041)
894 "Cannot declare a let variable twice".
895 See also: the `safari10` [format option](#format-options).
896
897Examples:
898
899```javascript
900// test.js
901var globalVar;
902function funcName(firstLongName, anotherLongName) {
903 var myVariable = firstLongName + anotherLongName;
904}
905```
906```javascript
907var code = fs.readFileSync("test.js", "utf8");
908
909await minify(code).code;
910// 'function funcName(a,n){}var globalVar;'
911
912await minify(code, { mangle: { reserved: ['firstLongName'] } }).code;
913// 'function funcName(firstLongName,a){}var globalVar;'
914
915await minify(code, { mangle: { toplevel: true } }).code;
916// 'function n(n,a){}var a;'
917```
918
919### Mangle properties options
920
921- `builtins` (default: `false`) — Use `true` to allow the mangling of builtin
922 DOM properties. Not recommended to override this setting.
923
924- `debug` (default: `false`) — Mangle names with the original name still present.
925 Pass an empty string `""` to enable, or a non-empty string to set the debug suffix.
926
927- `keep_quoted` (default: `false`) — Only mangle unquoted property names.
928 - `true` -- Quoted property names are automatically reserved and any unquoted
929 property names will not be mangled.
930 - `"strict"` -- Advanced, all unquoted property names are mangled unless
931 explicitly reserved.
932
933- `regex` (default: `null`) — Pass a [RegExp literal or pattern string](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp) to only mangle property matching the regular expression.
934
935- `reserved` (default: `[]`) — Do not mangle property names listed in the
936 `reserved` array.
937
938- `undeclared` (default: `false`) - Mangle those names when they are accessed
939 as properties of known top level variables but their declarations are never
940 found in input code. May be useful when only minifying parts of a project.
941 See [#397](https://github.com/terser/terser/issues/397) for more details.
942
943
944## Format options
945
946These options control the format of Terser's output code. Previously known
947as "output options".
948
949- `ascii_only` (default `false`) -- escape Unicode characters in strings and
950 regexps (affects directives with non-ascii characters becoming invalid)
951
952- `beautify` (default `false`) -- whether to actually beautify the output.
953 Passing `-b` will set this to true, but you might need to pass `-b` even
954 when you want to generate minified code, in order to specify additional
955 arguments, so you can use `-b beautify=false` to override it.
956
957- `braces` (default `false`) -- always insert braces in `if`, `for`,
958 `do`, `while` or `with` statements, even if their body is a single
959 statement.
960
961- `comments` (default `"some"`) -- by default it keeps JSDoc-style comments
962 that contain "@license" or "@preserve", pass `true` or `"all"` to preserve all
963 comments, `false` to omit comments in the output, a regular expression string
964 (e.g. `/^!/`) or a function.
965
966- `ecma` (default `5`) -- set desired EcmaScript standard version for output.
967 Set `ecma` to `2015` or greater to emit shorthand object properties - i.e.:
968 `{a}` instead of `{a: a}`. The `ecma` option will only change the output in
969 direct control of the beautifier. Non-compatible features in your input will
970 still be output as is. For example: an `ecma` setting of `5` will **not**
971 convert modern code to ES5.
972
973- `indent_level` (default `4`)
974
975- `indent_start` (default `0`) -- prefix all lines by that many spaces
976
977- `inline_script` (default `true`) -- escape HTML comments and the slash in
978 occurrences of `</script>` in strings
979
980- `keep_numbers` (default `false`) -- keep number literals as it was in original code
981 (disables optimizations like converting `1000000` into `1e6`)
982
983- `keep_quoted_props` (default `false`) -- when turned on, prevents stripping
984 quotes from property names in object literals.
985
986- `max_line_len` (default `false`) -- maximum line length (for minified code)
987
988- `preamble` (default `null`) -- when passed it must be a string and
989 it will be prepended to the output literally. The source map will
990 adjust for this text. Can be used to insert a comment containing
991 licensing information, for example.
992
993- `quote_keys` (default `false`) -- pass `true` to quote all keys in literal
994 objects
995
996- `quote_style` (default `0`) -- preferred quote style for strings (affects
997 quoted property names and directives as well):
998 - `0` -- prefers double quotes, switches to single quotes when there are
999 more double quotes in the string itself. `0` is best for gzip size.
1000 - `1` -- always use single quotes
1001 - `2` -- always use double quotes
1002 - `3` -- always use the original quotes
1003
1004- `preserve_annotations` -- (default `false`) -- Preserve [Terser annotations](#annotations) in the output.
1005
1006- `safari10` (default `false`) -- set this option to `true` to work around
1007 the [Safari 10/11 await bug](https://bugs.webkit.org/show_bug.cgi?id=176685).
1008 See also: the `safari10` [mangle option](#mangle-options).
1009
1010- `semicolons` (default `true`) -- separate statements with semicolons. If
1011 you pass `false` then whenever possible we will use a newline instead of a
1012 semicolon, leading to more readable output of minified code (size before
1013 gzip could be smaller; size after gzip insignificantly larger).
1014
1015- `shebang` (default `true`) -- preserve shebang `#!` in preamble (bash scripts)
1016
1017- `webkit` (default `false`) -- enable workarounds for WebKit bugs.
1018 PhantomJS users should set this option to `true`.
1019
1020- `wrap_iife` (default `false`) -- pass `true` to wrap immediately invoked
1021 function expressions. See
1022 [#640](https://github.com/mishoo/UglifyJS2/issues/640) for more details.
1023
1024- `wrap_func_args` (default `true`) -- pass `false` if you do not want to wrap
1025 function expressions that are passed as arguments, in parenthesis. See
1026 [OptimizeJS](https://github.com/nolanlawson/optimize-js) for more details.
1027
1028# Miscellaneous
1029
1030### Keeping copyright notices or other comments
1031
1032You can pass `--comments` to retain certain comments in the output. By
1033default it will keep JSDoc-style comments that contain "@preserve",
1034"@license" or "@cc_on" (conditional compilation for IE). You can pass
1035`--comments all` to keep all the comments, or a valid JavaScript regexp to
1036keep only comments that match this regexp. For example `--comments /^!/`
1037will keep comments like `/*! Copyright Notice */`.
1038
1039Note, however, that there might be situations where comments are lost. For
1040example:
1041```javascript
1042function f() {
1043 /** @preserve Foo Bar */
1044 function g() {
1045 // this function is never called
1046 }
1047 return something();
1048}
1049```
1050
1051Even though it has "@preserve", the comment will be lost because the inner
1052function `g` (which is the AST node to which the comment is attached to) is
1053discarded by the compressor as not referenced.
1054
1055The safest comments where to place copyright information (or other info that
1056needs to be kept in the output) are comments attached to toplevel nodes.
1057
1058### The `unsafe` `compress` option
1059
1060It enables some transformations that *might* break code logic in certain
1061contrived cases, but should be fine for most code. It assumes that standard
1062built-in ECMAScript functions and classes have not been altered or replaced.
1063You might want to try it on your own code; it should reduce the minified size.
1064Some examples of the optimizations made when this option is enabled:
1065
1066- `new Array(1, 2, 3)` or `Array(1, 2, 3)``[ 1, 2, 3 ]`
1067- `new Object()``{}`
1068- `String(exp)` or `exp.toString()``"" + exp`
1069- `new Object/RegExp/Function/Error/Array (...)` → we discard the `new`
1070- `"foo bar".substr(4)``"bar"`
1071
1072### Conditional compilation
1073
1074You can use the `--define` (`-d`) switch in order to declare global
1075variables that Terser will assume to be constants (unless defined in
1076scope). For example if you pass `--define DEBUG=false` then, coupled with
1077dead code removal Terser will discard the following from the output:
1078```javascript
1079if (DEBUG) {
1080 console.log("debug stuff");
1081}
1082```
1083
1084You can specify nested constants in the form of `--define env.DEBUG=false`.
1085
1086Another way of doing that is to declare your globals as constants in a
1087separate file and include it into the build. For example you can have a
1088`build/defines.js` file with the following:
1089```javascript
1090var DEBUG = false;
1091var PRODUCTION = true;
1092// etc.
1093```
1094
1095and build your code like this:
1096
1097 terser build/defines.js js/foo.js js/bar.js... -c
1098
1099Terser will notice the constants and, since they cannot be altered, it
1100will evaluate references to them to the value itself and drop unreachable
1101code as usual. The build will contain the `const` declarations if you use
1102them. If you are targeting < ES6 environments which does not support `const`,
1103using `var` with `reduce_vars` (enabled by default) should suffice.
1104
1105### Conditional compilation API
1106
1107You can also use conditional compilation via the programmatic API. With the difference that the
1108property name is `global_defs` and is a compressor property:
1109
1110```javascript
1111var result = await minify(fs.readFileSync("input.js", "utf8"), {
1112 compress: {
1113 dead_code: true,
1114 global_defs: {
1115 DEBUG: false
1116 }
1117 }
1118});
1119```
1120
1121To replace an identifier with an arbitrary non-constant expression it is
1122necessary to prefix the `global_defs` key with `"@"` to instruct Terser
1123to parse the value as an expression:
1124```javascript
1125await minify("alert('hello');", {
1126 compress: {
1127 global_defs: {
1128 "@alert": "console.log"
1129 }
1130 }
1131}).code;
1132// returns: 'console.log("hello");'
1133```
1134
1135Otherwise it would be replaced as string literal:
1136```javascript
1137await minify("alert('hello');", {
1138 compress: {
1139 global_defs: {
1140 "alert": "console.log"
1141 }
1142 }
1143}).code;
1144// returns: '"console.log"("hello");'
1145```
1146
1147### Annotations
1148
1149Annotations in Terser are a way to tell it to treat a certain function call differently. The following annotations are available:
1150
1151 * `/*@__INLINE__*/` - forces a function to be inlined somewhere.
1152 * `/*@__NOINLINE__*/` - Makes sure the called function is not inlined into the call site.
1153 * `/*@__PURE__*/` - Marks a function call as pure. That means, it can safely be dropped.
1154
1155You can use either a `@` sign at the start, or a `#`.
1156
1157Here are some examples on how to use them:
1158
1159```javascript
1160/*@__INLINE__*/
1161function_always_inlined_here()
1162
1163/*#__NOINLINE__*/
1164function_cant_be_inlined_into_here()
1165
1166const x = /*#__PURE__*/i_am_dropped_if_x_is_not_used()
1167```
1168
1169### ESTree / SpiderMonkey AST
1170
1171Terser has its own abstract syntax tree format; for
1172[practical reasons](http://lisperator.net/blog/uglifyjs-why-not-switching-to-spidermonkey-ast/)
1173we can't easily change to using the SpiderMonkey AST internally. However,
1174Terser now has a converter which can import a SpiderMonkey AST.
1175
1176For example [Acorn][acorn] is a super-fast parser that produces a
1177SpiderMonkey AST. It has a small CLI utility that parses one file and dumps
1178the AST in JSON on the standard output. To use Terser to mangle and
1179compress that:
1180
1181 acorn file.js | terser -p spidermonkey -m -c
1182
1183The `-p spidermonkey` option tells Terser that all input files are not
1184JavaScript, but JS code described in SpiderMonkey AST in JSON. Therefore we
1185don't use our own parser in this case, but just transform that AST into our
1186internal AST.
1187
1188### Use Acorn for parsing
1189
1190More for fun, I added the `-p acorn` option which will use Acorn to do all
1191the parsing. If you pass this option, Terser will `require("acorn")`.
1192
1193Acorn is really fast (e.g. 250ms instead of 380ms on some 650K code), but
1194converting the SpiderMonkey tree that Acorn produces takes another 150ms so
1195in total it's a bit more than just using Terser's own parser.
1196
1197[acorn]: https://github.com/ternjs/acorn
1198[sm-spec]: https://docs.google.com/document/d/1U1RGAehQwRypUTovF1KRlpiOFze0b-_2gc6fAH0KY0k
1199
1200### Terser Fast Minify Mode
1201
1202It's not well known, but whitespace removal and symbol mangling accounts
1203for 95% of the size reduction in minified code for most JavaScript - not
1204elaborate code transforms. One can simply disable `compress` to speed up
1205Terser builds by 3 to 4 times.
1206
1207| d3.js | size | gzip size | time (s) |
1208| --- | ---: | ---: | ---: |
1209| original | 451,131 | 108,733 | - |
1210| terser@3.7.5 mangle=false, compress=false | 316,600 | 85,245 | 0.82 |
1211| terser@3.7.5 mangle=true, compress=false | 220,216 | 72,730 | 1.45 |
1212| terser@3.7.5 mangle=true, compress=true | 212,046 | 70,954 | 5.87 |
1213| babili@0.1.4 | 210,713 | 72,140 | 12.64 |
1214| babel-minify@0.4.3 | 210,321 | 72,242 | 48.67 |
1215| babel-minify@0.5.0-alpha.01eac1c3 | 210,421 | 72,238 | 14.17 |
1216
1217To enable fast minify mode from the CLI use:
1218```
1219terser file.js -m
1220```
1221To enable fast minify mode with the API use:
1222```js
1223await minify(code, { compress: false, mangle: true });
1224```
1225
1226#### Source maps and debugging
1227
1228Various `compress` transforms that simplify, rearrange, inline and remove code
1229are known to have an adverse effect on debugging with source maps. This is
1230expected as code is optimized and mappings are often simply not possible as
1231some code no longer exists. For highest fidelity in source map debugging
1232disable the `compress` option and just use `mangle`.
1233
1234### Compiler assumptions
1235
1236To allow for better optimizations, the compiler makes various assumptions:
1237
1238- `.toString()` and `.valueOf()` don't have side effects, and for built-in
1239 objects they have not been overridden.
1240- `undefined`, `NaN` and `Infinity` have not been externally redefined.
1241- `arguments.callee`, `arguments.caller` and `Function.prototype.caller` are not used.
1242- The code doesn't expect the contents of `Function.prototype.toString()` or
1243 `Error.prototype.stack` to be anything in particular.
1244- Getting and setting properties on a plain object does not cause other side effects
1245 (using `.watch()` or `Proxy`).
1246- Object properties can be added, removed and modified (not prevented with
1247 `Object.defineProperty()`, `Object.defineProperties()`, `Object.freeze()`,
1248 `Object.preventExtensions()` or `Object.seal()`).
1249- `document.all` is not `== null`
1250- Assigning properties to a class doesn't have side effects and does not throw.
1251
1252### Build Tools and Adaptors using Terser
1253
1254https://www.npmjs.com/browse/depended/terser
1255
1256### Replacing `uglify-es` with `terser` in a project using `yarn`
1257
1258A number of JS bundlers and uglify wrappers are still using buggy versions
1259of `uglify-es` and have not yet upgraded to `terser`. If you are using `yarn`
1260you can add the following alias to your project's `package.json` file:
1261
1262```js
1263 "resolutions": {
1264 "uglify-es": "npm:terser"
1265 }
1266```
1267
1268to use `terser` instead of `uglify-es` in all deeply nested dependencies
1269without changing any code.
1270
1271Note: for this change to take effect you must run the following commands
1272to remove the existing `yarn` lock file and reinstall all packages:
1273
1274```
1275$ rm -rf node_modules yarn.lock
1276$ yarn
1277```
1278
1279# Reporting issues
1280
1281In the terser CLI we use [source-map-support](https://npmjs.com/source-map-support) to produce good error stacks. In your own app, you're expected to enable source-map-support (read their docs) to have nice stack traces that will help you write good issues.
1282
1283# README.md Patrons:
1284
1285*note*: You can support this project on patreon: <a target="_blank" rel="nofollow" href="https://www.patreon.com/fabiosantoscode"><img src="https://c5.patreon.com/external/logo/become_a_patron_button@2x.png" alt="patron" width="100px" height="auto"></a>. Check out [PATRONS.md](https://github.com/terser/terser/blob/master/PATRONS.md) for our first-tier patrons.
1286
1287These are the second-tier patrons. Great thanks for your support!
1288
1289 * CKEditor ![](https://c10.patreonusercontent.com/3/eyJoIjoxMDAsInciOjEwMH0%3D/patreon-media/p/user/15452278/f8548dcf48d740619071e8d614459280/1?token-time=2145916800&token-hash=SIQ54PhIPHv3M7CVz9LxS8_8v4sOw4H304HaXsXj8MM%3D)
1290 * 38elements ![](https://c10.patreonusercontent.com/3/eyJ3IjoyMDB9/patreon-media/p/user/12501844/88e7fc5dd62d45c6a5626533bbd48cfb/1?token-time=2145916800&token-hash=c3AsQ5T0IQWic0zKxFHu-bGGQJkXQFvafvJ4bPerFR4%3D)
1291
1292## Contributors
1293
1294### Code Contributors
1295
1296This project exists thanks to all the people who contribute. [[Contribute](CONTRIBUTING.md)].
1297<a href="https://github.com/terser/terser/graphs/contributors"><img src="https://opencollective.com/terser/contributors.svg?width=890&button=false" /></a>
1298
1299### Financial Contributors
1300
1301Become a financial contributor and help us sustain our community. [[Contribute](https://opencollective.com/terser/contribute)]
1302
1303#### Individuals
1304
1305<a href="https://opencollective.com/terser"><img src="https://opencollective.com/terser/individuals.svg?width=890"></a>
1306
1307#### Organizations
1308
1309Support this project with your organization. Your logo will show up here with a link to your website. [[Contribute](https://opencollective.com/terser/contribute)]
1310
1311<a href="https://opencollective.com/terser/organization/0/website"><img src="https://opencollective.com/terser/organization/0/avatar.svg"></a>
1312<a href="https://opencollective.com/terser/organization/1/website"><img src="https://opencollective.com/terser/organization/1/avatar.svg"></a>
1313<a href="https://opencollective.com/terser/organization/2/website"><img src="https://opencollective.com/terser/organization/2/avatar.svg"></a>
1314<a href="https://opencollective.com/terser/organization/3/website"><img src="https://opencollective.com/terser/organization/3/avatar.svg"></a>
1315<a href="https://opencollective.com/terser/organization/4/website"><img src="https://opencollective.com/terser/organization/4/avatar.svg"></a>
1316<a href="https://opencollective.com/terser/organization/5/website"><img src="https://opencollective.com/terser/organization/5/avatar.svg"></a>
1317<a href="https://opencollective.com/terser/organization/6/website"><img src="https://opencollective.com/terser/organization/6/avatar.svg"></a>
1318<a href="https://opencollective.com/terser/organization/7/website"><img src="https://opencollective.com/terser/organization/7/avatar.svg"></a>
1319<a href="https://opencollective.com/terser/organization/8/website"><img src="https://opencollective.com/terser/organization/8/avatar.svg"></a>
1320<a href="https://opencollective.com/terser/organization/9/website"><img src="https://opencollective.com/terser/organization/9/avatar.svg"></a>