Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add passes compress option. Fix duplicate compress warnings. #1040

Closed
wants to merge 1 commit into from
Closed

Add passes compress option. Fix duplicate compress warnings. #1040

wants to merge 1 commit into from

Conversation

kzc
Copy link
Contributor

@kzc kzc commented Apr 12, 2016

Added new method Compressor.prototype.compress(node) to facilitate the passes=n optimization to further compress code in some cases.

Also added basic sanity test for minify().

@rvanvelzen
Copy link
Collaborator

I'm not sure whether introducing iterations is a good solution. It works, obviously, but it'd be much nicer to fix the core issue.

@kzc
Copy link
Contributor Author

kzc commented Apr 15, 2016

There is no single core issue. It's not specific to this particular issue or any individual optimization. Finding a perfectly optimal compress algorithm in all situations is intractable because of the order in which individual AST node optimizations are applied - particularly when compress options are enabled or disabled in different combinations. What optimization order works best for one JS program will not necessarily be optimal for another. Presently uglify marks an AST node as being optimized to prevent an infinite compress cycle as transformed code can flip/flop between states. The default would remain at a single pass and run at the same speed. Giving the user the option to run the compress pass more than once to squeeze extra bytes from their JS at the expense of uglify running for a little more time is a good compromise, and it is not uncommon in compilers.

@kzc
Copy link
Contributor Author

kzc commented Apr 15, 2016

$ bin/uglifyjs --self -m -c warnings=false,collapse_vars=1,passes=1 | wc -c
  127631
$ bin/uglifyjs --self -m -c warnings=false,collapse_vars=1,passes=2 | wc -c
  127607

@kzc kzc changed the title Fix duplicate compress warnings. Add passes compress option. Add passes compress option. Fix duplicate compress warnings. Apr 15, 2016
@kzc
Copy link
Contributor Author

kzc commented Apr 18, 2016

@mishoo Any objection to merging this PR?

@rvanvelzen
Copy link
Collaborator

rvanvelzen commented Apr 19, 2016

I stand by my previous words, but I don't see a reason not to include this option anyway. Merged as c55dd5e, thanks!

@rvanvelzen rvanvelzen closed this Apr 19, 2016
@kzc
Copy link
Contributor Author

kzc commented Apr 19, 2016

passes is optional. The default is still the same - 1 pass.

I've observed passes=2 drop unnecessary parentheses around expressions, and braces from loops with single statement bodies, further optimize ternary and boolean expressions, drop unused variables to create longer sequences. Probably a few other optimizations as well. Very little code for this option. I don't see any downside.

AST_Node.warn.apply(AST_Node, arguments);
compress: function(node) {
var passes = +this.options.passes || 1;
for (var pass = 0; pass < passes && pass < 3; ++pass) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kzc Mind explaining the implicit maximum of 3 passes? My assumption is that it's an arbitrary "good enough" amount that prevents the user from shooting their foot. However I still feel it should be mentioned in the readme.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is arbitrary. I haven't seen any JS input that produces smaller output with more than 3 passes, and each additional pass makes minification slower. If you can demonstrate code that appreciably benefits from a higher number we will reconsider increasing the value.

If you wish to make a PR mentioning its max value of 3, that would be great.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense - thanks so much.

I'm putting together a PR tackling the side_effects option with passes - since pure annotations are removed on the first pass, thus removing the benefit of multiple passes. I'm having a hard time creating a small reproduction of code that doesn't get fully minified in one pass though - it's an interesting problem.

Copy link
Contributor Author

@kzc kzc May 12, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

since pure annotations are removed on the first pass, thus removing the benefit of multiple passes

That hasn't been my experience with #__PURE__ annotations. Test different passes settings in the following examples:

#1261 (comment)
#1261 (comment)
#1261 (comment)

Also, you can set an option to keep the pure annotation comments if you want uglify to emit them after minification.

Clarification: the /*#__PURE__*/ annotation is not set on a function, but a function call. I had missed that in the recent README doc fix.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmm - thanks for the test references. Seems I need to better understand my problem.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry for the misunderstanding - you were right and my issue was not thoroughly marking the functions I needed to. I'll put together the PR for max passes now.

@kzc kzc deleted the warnings-and-passes branch November 21, 2018 16:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants