Skip to content

Conversation

@sgomes
Copy link
Contributor

@sgomes sgomes commented Aug 26, 2020

Optional chaining will start making its way into the minification phase of the pipeline once Safari 14 ships (since this will mean all browsers in the evergreen build support optional chaining). Unfortunately, the current version of Terser we use does not support this syntax and will start failing.

This PR updates to the latest version of Terser, so that we're ready ahead of time.

Changes proposed in this Pull Request

  • Update terser to 5.2.1
  • Update terser-webpack-plugin to enable using the new terser.

Testing instructions

Smoke-test the live branch and ensure that the new Terser doesn't introduce any unexpected breakage.

Also update `terser-webpack-plugin` to enable using the new `terser`.
@sgomes sgomes added [Status] Needs Review The PR is ready for review. This also triggers e2e canary tests and wp-desktop tests automatically. Build dependencies Pull requests that update a dependency file labels Aug 26, 2020
@sgomes sgomes requested review from a team, jsnajdr and scinos August 26, 2020 10:54
@matticbot
Copy link
Contributor

@matticbot
Copy link
Contributor

matticbot commented Aug 26, 2020

Here is how your PR affects size of JS and CSS bundles shipped to the user's browser:

App Entrypoints (~3613 bytes removed 📉 [gzipped])

name                   parsed_size           gzip_size
entry-gutenboarding       -12952 B  (-0.7%)    -2765 B  (-0.6%)
entry-main                 -3458 B  (-0.3%)     -577 B  (-0.2%)
entry-login                -2378 B  (-0.3%)     -264 B  (-0.1%)
entry-domains-landing      -1881 B  (-0.3%)       -7 B  (-0.0%)

Common code that is always downloaded and parsed every time the app is loaded, no matter which route is used.

Sections (~10570 bytes removed 📉 [gzipped])

name                    parsed_size           gzip_size
post-editor                -12070 B  (-0.6%)    -2486 B  (-0.4%)
woocommerce                -10348 B  (-0.5%)    -1829 B  (-0.3%)
jetpack-connect             -3851 B  (-0.4%)     -704 B  (-0.3%)
checkout                    -3305 B  (-0.2%)     -622 B  (-0.1%)
gutenberg-editor            -1883 B  (-0.2%)     -560 B  (-0.2%)
purchases                   -1498 B  (-0.1%)     -224 B  (-0.1%)
domains                     -1466 B  (-0.1%)     -135 B  (-0.0%)
wp-super-cache              -1406 B  (-0.6%)      +28 B  (+0.0%)
plans                       -1082 B  (-0.2%)      -92 B  (-0.1%)
reader                       -973 B  (-0.2%)     -189 B  (-0.1%)
home                         -868 B  (-0.2%)      -47 B  (-0.0%)
zoninator                    -823 B  (-0.3%)      +82 B  (+0.1%)
stats                        -809 B  (-0.1%)     -160 B  (-0.1%)
themes                       -654 B  (-0.2%)     -112 B  (-0.1%)
settings                     -551 B  (-0.1%)     -117 B  (-0.1%)
theme                        -550 B  (-0.2%)      -93 B  (-0.1%)
comments                     -544 B  (-0.1%)      -97 B  (-0.1%)
plugins                      -498 B  (-0.1%)     -140 B  (-0.1%)
help                         -480 B  (-0.1%)     -154 B  (-0.1%)
people                       -473 B  (-0.1%)     -115 B  (-0.1%)
account                      -472 B  (-0.1%)      -88 B  (-0.1%)
settings-writing             -459 B  (-0.1%)     -128 B  (-0.1%)
activity                     -457 B  (-0.1%)     -135 B  (-0.1%)
marketing                    -438 B  (-0.1%)     -126 B  (-0.1%)
email                        -423 B  (-0.1%)     -143 B  (-0.2%)
devdocs                      -418 B  (-0.2%)      -59 B  (-0.1%)
pages                        -413 B  (-0.2%)      -68 B  (-0.1%)
signup                       -386 B  (-0.1%)      -96 B  (-0.1%)
media                        -385 B  (-0.1%)     -143 B  (-0.1%)
customize                    -368 B  (-0.2%)      -79 B  (-0.1%)
settings-security            -362 B  (-0.1%)      -80 B  (-0.1%)
accept-invite                -361 B  (-0.1%)      -45 B  (-0.1%)
backup                       -359 B  (-0.1%)      -90 B  (-0.1%)
site-blocks                  -355 B  (-0.1%)     -108 B  (-0.1%)
posts-custom                 -355 B  (-0.1%)      -50 B  (-0.0%)
posts                        -355 B  (-0.1%)      -48 B  (-0.0%)
account-close                -351 B  (-0.1%)     -112 B  (-0.1%)
export                       -349 B  (-0.2%)      -66 B  (-0.1%)
security                     -344 B  (-0.1%)      -93 B  (-0.1%)
settings-performance         -341 B  (-0.1%)      -63 B  (-0.1%)
hosting                      -308 B  (-0.1%)      -45 B  (-0.1%)
settings-jetpack             -305 B  (-0.1%)      -84 B  (-0.1%)
settings-discussion          -305 B  (-0.1%)      -70 B  (-0.1%)
google-my-business           -277 B  (-0.1%)      -49 B  (-0.1%)
earn                         -274 B  (-0.1%)      -61 B  (-0.1%)
scan                         -238 B  (-0.1%)      -74 B  (-0.1%)
notification-settings        -237 B  (-0.1%)      -72 B  (-0.1%)
privacy                      -233 B  (-0.1%)      -54 B  (-0.1%)
concierge                    -232 B  (-0.1%)      -72 B  (-0.1%)
happychat                    -218 B  (-0.1%)      -69 B  (-0.1%)
me                           -202 B  (-0.1%)      -56 B  (-0.1%)
import                       -196 B  (-0.1%)      -36 B  (-0.1%)
jetpack-cloud-settings       -184 B  (-0.1%)      -58 B  (-0.1%)
hello-dolly                  -154 B  (-0.1%)      -22 B  (-0.1%)
migrate                      -150 B  (-0.1%)      -24 B  (-0.1%)
jetpack-cloud                -149 B  (-0.2%)      -28 B  (-0.1%)
preview                      -145 B  (-0.1%)      -28 B  (-0.1%)
sensei                       -138 B  (-0.1%)      -26 B  (-0.1%)
sites                        -135 B  (-0.2%)      -22 B  (-0.1%)
mailing-lists                 -62 B  (-0.9%)      -15 B  (-0.8%)
jetpack-cloud-auth            -58 B  (-1.5%)       +6 B  (+0.4%)
auth                          -33 B  (-0.2%)      -17 B  (-0.3%)
lasagnaMiddleware             -28 B  (-0.1%)       -5 B  (-0.0%)
wpcom-xhr-request             -26 B  (-0.1%)       -6 B  (-0.1%)
purchase-product              -23 B  (-0.0%)       +3 B  (+0.0%)

Sections contain code specific for a given set of routes. Is downloaded and parsed only when a particular route is navigated to.

Async-loaded Components (~2110 bytes removed 📉 [gzipped])

name                                                                  parsed_size           gzip_size
async-load-design-playground                                              +5183 B  (+0.3%)       -5 B  (-0.0%)
async-load-design                                                         +5049 B  (+0.3%)      -55 B  (-0.0%)
async-load-design-blocks                                                  +3392 B  (+0.1%)     -409 B  (-0.1%)
async-load-layout-masterbar-checkout                                       -902 B  (-0.4%)     -216 B  (-0.4%)
async-load-components-web-preview-component                                -623 B  (-0.1%)     -177 B  (-0.1%)
async-load-apps-notifications-index-jsx                                    -507 B  (-0.4%)     -122 B  (-0.4%)
async-load-blocks-inline-help-popover                                      -473 B  (-0.1%)     -142 B  (-0.1%)
async-load-my-sites-site-settings-seo-settings-form                        -469 B  (-0.2%)      -44 B  (-0.1%)
async-load-blocks-support-article-dialog-dialog                            -285 B  (-0.3%)      -74 B  (-0.3%)
async-load-my-sites-sidebar                                                -264 B  (-0.1%)      -69 B  (-0.1%)
async-load-post-editor-media-modal                                         -251 B  (-0.1%)     -110 B  (-0.1%)
async-load-my-sites-current-site-stale-cart-items-notice                   -231 B  (-0.3%)      -52 B  (-0.2%)
async-load-my-sites-current-site-domain-warnings                           -176 B  (-0.3%)      +22 B  (+0.1%)
async-load-layout-guided-tours-component                                   -130 B  (-0.1%)      -27 B  (-0.1%)
async-load-blocks-calendar-popover                                         -125 B  (-0.0%)      -16 B  (-0.0%)
async-load-lib-preferences-helper                                          -114 B  (-0.6%)      -21 B  (-0.4%)
async-load-components-sites-popover                                        -107 B  (-0.2%)      -15 B  (-0.1%)
async-load-blocks-inline-help                                              -105 B  (-0.1%)      -36 B  (-0.1%)
async-load-signup-steps-site-picker                                        -104 B  (-0.2%)      -16 B  (-0.1%)
async-load-reader-following-manage                                          -98 B  (-0.1%)      -29 B  (-0.1%)
async-load-signup-steps-domains                                             -96 B  (-0.0%)      -23 B  (-0.0%)
async-load-signup-steps-theme-selection                                     -84 B  (-0.1%)      -16 B  (-0.1%)
async-load-reader-conversations-stream                                      -81 B  (-1.8%)       +2 B  (+0.1%)
async-load-signup-steps-plans                                               -80 B  (-0.0%)      -13 B  (-0.0%)
async-load-blocks-reader-full-post                                          -69 B  (-0.2%)      -19 B  (-0.2%)
async-load-lib-happychat-connection                                         -67 B  (-0.1%)      -26 B  (-0.1%)
async-load-signup-steps-passwordless                                        -62 B  (-0.2%)      -13 B  (-0.2%)
async-load-blocks-app-banner                                                -60 B  (-0.6%)       +5 B  (+0.1%)
async-load-reader-list-manage                                               -59 B  (-0.2%)       -6 B  (-0.1%)
async-load-blocks-inline-help-dialog                                        -58 B  (-0.2%)      -19 B  (-0.2%)
async-load-signup-steps-import-url                                          -56 B  (-0.2%)       +5 B  (+0.1%)
async-load-my-sites-current-site-notice                                     -52 B  (-0.1%)       -4 B  (-0.0%)
async-load-reader-sidebar                                                   -47 B  (-0.1%)       -9 B  (-0.1%)
async-load-signup-steps-plans-atomic-store                                  -46 B  (-0.0%)      -13 B  (-0.0%)
async-load-reader-site-stream                                               -41 B  (-0.2%)      -27 B  (-0.3%)
async-load-components-community-translator                                  -41 B  (-0.5%)       +1 B  (+0.0%)
async-load-signup-steps-user                                                -39 B  (-0.0%)      -14 B  (-0.0%)
async-load-extensions-woocommerce-app-store-stats-referrers                 -38 B  (-0.1%)      -13 B  (-0.1%)
async-load-signup-steps-clone-credentials                                   -34 B  (-0.1%)      -18 B  (-0.1%)
async-load-components-happychat                                             -34 B  (-0.1%)      -16 B  (-0.1%)
async-load-blocks-login-two-factor-authentication-two-factor-content        -32 B  (-0.1%)       -1 B  (-0.0%)
async-load-signup-steps-rewind-form-creds                                   -30 B  (-0.1%)      -16 B  (-0.1%)
async-load-my-sites-resume-editing                                          -30 B  (-0.2%)       +6 B  (+0.1%)
async-load-layout-masterbar-drafts-popover                                  -28 B  (-0.1%)       -7 B  (-0.0%)
async-load-signup-steps-rebrand-cities-welcome                              -27 B  (-0.2%)       -7 B  (-0.2%)
async-load-signup-steps-creds-permission                                    -27 B  (-0.1%)      -12 B  (-0.1%)
async-load-signup-steps-creds-confirm                                       -27 B  (-0.1%)      -13 B  (-0.2%)
async-load-reader-feed-stream                                               -27 B  (-0.1%)      -19 B  (-0.2%)
async-load-blocks-jitm                                                      -27 B  (-0.3%)      -17 B  (-0.6%)
async-load-signup-steps-clone-point                                         -26 B  (-0.0%)      -16 B  (-0.0%)
async-load-quick-language-switcher                                          -26 B  (-0.1%)       -7 B  (-0.0%)
async-load-extensions-woocommerce-app-store-stats                           -26 B  (-0.1%)      -11 B  (-0.1%)
async-load-layout-guided-tours                                              -25 B  (-0.2%)      -23 B  (-0.7%)
async-load-signup-steps-about                                               -24 B  (-0.0%)       -8 B  (-0.0%)
async-load-reader-tag-stream-main                                           -22 B  (-0.1%)       -6 B  (-0.1%)
async-load-extensions-woocommerce-app-store-stats-listview                  -22 B  (-0.1%)      -16 B  (-0.4%)
async-load-reader-search-stream                                             -20 B  (-0.0%)      -15 B  (-0.1%)
async-load-signup-steps-survey                                              -18 B  (-0.1%)       -4 B  (-0.1%)
async-load-blocks-product-purchase-features-list                            -18 B  (-0.1%)       -7 B  (-0.1%)
async-load-post-editor-editor-location                                      -17 B  (-0.1%)       -3 B  (-0.1%)
async-load-lib-abtest-test-helper                                           -17 B  (-0.2%)       -2 B  (-0.1%)
async-load-my-sites-guided-transfer                                         -16 B  (-0.1%)      -13 B  (-0.2%)
async-load-signup-steps-site-topic                                          -14 B  (-0.0%)       -4 B  (-0.0%)
async-load-signup-steps-rewind-migrate                                      -14 B  (-0.1%)       -6 B  (-0.1%)
async-load-signup-steps-clone-ready                                         -14 B  (-0.1%)       -7 B  (-0.1%)
async-load-layout-community-translator-launcher                             -14 B  (-0.1%)      -11 B  (-0.2%)
async-load-emoji-text                                                       -14 B  (-0.0%)      -15 B  (-0.1%)
async-load-reader-list-stream                                               -13 B  (-0.1%)       -4 B  (-0.1%)
async-load-signup-steps-import-url-onboarding                               -12 B  (-0.0%)       +0 B
async-load-post-editor-editor-sharing-accordion                             -12 B  (-0.0%)       +2 B  (+0.0%)
async-load-signup-steps-site-or-domain                                      -11 B  (-0.1%)       +3 B  (+0.1%)
async-load-post-editor-editor-seo-accordion                                 -11 B  (-0.1%)       -2 B  (-0.1%)

React components that are loaded lazily, when a certain part of UI is displayed for the first time.

Legend

What is parsed and gzip size?

Parsed Size: Uncompressed size of the JS and CSS files. This much code needs to be parsed and stored in memory.
Gzip Size: Compressed size of the JS and CSS files. This much data needs to be downloaded over network.

Generated by performance advisor bot at iscalypsofastyet.com.

@sgomes
Copy link
Contributor Author

sgomes commented Aug 26, 2020

Looks like Terser somehow got worse, and now produces larger output 😞 Sadly, I think we'll need to just live with these new costs. See below.

@sgomes
Copy link
Contributor Author

sgomes commented Aug 26, 2020

Note: the output is now actually smaller than before, since I enabled 2 passes on the compression. This only appears to add ~ 30s build time on the Calculate ICFY stats / Build ICFY stats, for reference.

@jsnajdr
Copy link
Member

jsnajdr commented Aug 27, 2020

Looks like Terser somehow got worse, and now produces larger output

@sgomes When I'm looking at the original ICFY comment, before it was updated after passes: 2, I see that most sections were getting smaller by ~80 bytes and gzipped sizes were getting larger by ~5 bytes. Was that the larger output you are referring to?

I'd like to reproduce the "output got larger" problem.

@sgomes
Copy link
Contributor Author

sgomes commented Aug 27, 2020

@jsnajdr: The original comment has everything getting larger in gzipped size except for some async chunks. If you check the original comment in the history it's still there. E.g.:

name                   parsed_size           gzip_size
entry-gutenboarding        -1797 B  (-0.1%)     +487 B  (+0.1%)
entry-login                 -892 B  (-0.1%)     +265 B  (+0.1%)
entry-domains-landing       +387 B  (+0.1%)     +895 B  (+0.6%)
entry-main                  +350 B  (+0.0%)     +923 B  (+0.3%)
name                    parsed_size           gzip_size
post-editor                 -1470 B  (-0.1%)     +482 B  (+0.1%)
woocommerce                 -1406 B  (-0.1%)     +698 B  (+0.1%)
wp-super-cache              -1265 B  (-0.5%)      +76 B  (+0.1%)
domains                      -762 B  (-0.1%)     +113 B  (+0.0%)
purchases                    -671 B  (-0.1%)      +55 B  (+0.0%)
zoninator                    -633 B  (-0.2%)     +198 B  (+0.2%)
home                         -562 B  (-0.1%)      +65 B  (+0.1%)
plans                        -470 B  (-0.1%)      +43 B  (+0.0%)
checkout                     -403 B  (-0.0%)      +62 B  (+0.0%)
jetpack-connect              -336 B  (-0.0%)      +31 B  (+0.0%)
account                      -283 B  (-0.1%)       +5 B  (+0.0%)
reader                       -277 B  (-0.1%)      +94 B  (+0.1%)
people                       -256 B  (-0.1%)      +83 B  (+0.1%)
stats                        -234 B  (-0.0%)      +55 B  (+0.0%)
comments                     -207 B  (-0.0%)      +24 B  (+0.0%)
gutenberg-editor             -188 B  (-0.0%)      +43 B  (+0.0%)
help                         -167 B  (-0.0%)       +4 B  (+0.0%)
pages                        -163 B  (-0.1%)      +16 B  (+0.0%)
themes                       -151 B  (-0.0%)      +11 B  (+0.0%)
theme                        -151 B  (-0.0%)      +11 B  (+0.0%)
earn                         -140 B  (-0.0%)      +17 B  (+0.0%)
accept-invite                -140 B  (-0.0%)      +85 B  (+0.1%)
...

There are a lot of chunks getting smaller in parsed size but larger in gzipped size; I'm not sure if that's real or an artifact of how the bundle analyzer measures things.

If you want to reproduce locally, you can try commit f2d8838.

@jsnajdr
Copy link
Member

jsnajdr commented Aug 27, 2020

@sgomes Thanks for confirming! I was curious what part of terser compression comes from the syntax transforms, and what part comes from the mere variable name mangling and whitespace/comments removal. So I disabled compression in #45244. The result is that disabled compression inflates most chunks by ~7%, and the gzipped sized by ~4%.

@sgomes
Copy link
Contributor Author

sgomes commented Aug 27, 2020

@sgomes Thanks for confirming! I was curious what part of terser compression comes from the syntax transforms, and what part comes from the mere variable name mangling and whitespace/comments removal. So I disabled compression in #45244. The result is that disabled compression inflates most chunks by ~7%, and the gzipped sized by ~4%.

Oh, that's good data, thank you @jsnajdr! 👍

@jsnajdr
Copy link
Member

jsnajdr commented Aug 27, 2020

Did some Terser learning today and I have some findings why we see the changes we do.

Suppose we have code like this:

s.getItem("jetpack_cloud_redirect_path_expires_in");
s.setItem("jetpack_cloud_redirect_path_expires_in");

Since 5.2.0, Terser has a slightly different criteria whether to extract or inline variables and newly transforms this code into:

let k = "jetpack_cloud_redirect_path_expires_in";
s.getItem(k);
s.setItem(k);

This makes the unzipped code shorter, but steals come compression opportunities from the gzip algorithm. The result is that the gzipped size is a few bytes bigger.

This gzip paradox is not new or rare: last year, we were experimenting with a webpack plugin that would optimize the React.createElement statements (that every React app has thousands of) and the result was similar: unzipped code size is smaller, gzipped is bigger.

What benefits do the two passes give us:
I've seen two kinds of optimizations:

  1. Coalescing var declarations:
var a = 1; var b = 2;
// into
var a = 1, b = 2;
  1. Doing innocuous code moves to save semicolons:
a(1);function b() { return 1; };
// into
function b() { return 1; }a(1);

Apparently, some of these opportunities are created only after other code transforms are done: they were not in the original code.

Copy link
Member

@jsnajdr jsnajdr left a comment

Choose a reason for hiding this comment

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

Looks ready to 🚢

I'm not excited about the passes: 2 change. Build times and occasional Terser OOM errors are a big problem for us. On the other hand, I'd argue that adding a few bytes to the output, where the addition is a rather random coincidence, is not a that big problem 🙂

@sgomes
Copy link
Contributor Author

sgomes commented Aug 27, 2020

I'm not excited about the passes: 2 change. Build times and occasional Terser OOM errors are a big problem for us.

Yeah, I totally see where you're coming from. The gains are quite good on some chunks, though (2.7KB gzipped), so I think we should give it a fair shot. If terser is properly coded, the second pass won't take up any more memory than the first; it'll only take a bit more time.

@sgomes
Copy link
Contributor Author

sgomes commented Aug 27, 2020

Thank you for the review, @jsnajdr! 👍

@sgomes sgomes merged commit e21b79d into master Aug 27, 2020
@sgomes sgomes deleted the update/update-terser-to-5.2.1 branch August 27, 2020 13:34
@matticbot matticbot removed the [Status] Needs Review The PR is ready for review. This also triggers e2e canary tests and wp-desktop tests automatically. label Aug 27, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Build dependencies Pull requests that update a dependency file

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants