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

Update mangling of our classes names for our minified files #4076

Closed
3 tasks
Tracked by #3478
romaricpascal opened this issue Aug 11, 2023 · 4 comments · Fixed by #4145
Closed
3 tasks
Tracked by #3478

Update mangling of our classes names for our minified files #4076

romaricpascal opened this issue Aug 11, 2023 · 4 comments · Fixed by #4145
Assignees
Milestone

Comments

@romaricpascal
Copy link
Member

romaricpascal commented Aug 11, 2023

What

Update the mangling of our class names for our minified files, as we may want to protect a few extra names than we do at the moment.

Before simply expanding the list of names we protect from mangling, I'd like us to quickly explore other mangling options from terser (a plain false, keep_classnames, keep_fnames, especially) and assess their impact on file size as we may gain in maintainability by not having to hand-maintain a list of names.

Why

Terser's mangling provides further code minification by reducing long symbol names to single letters. This is great, but can make stack traces poorly readable. In the following screenshot, the stacktract lists n, o and a steps in the stacktrace, which users will struggle to reconciliate with our GOVUKFrontendError, SupportError and GOVUKFrontendComponent.

Screenshot of an uncaught SupportError in the browser console

Sourcemaps link users to the right place, but that requires them to take action and click on each entry of the stacktrace.

In v4, the names of our classes were protected because they were attached to the window.GOVUKFrontend object:

// https://github.com/alphagov/govuk-frontend/blob/main/dist/govuk-frontend-4.6.0.min.js
/* ... */t.version="4.6.0",t.Accordion=l,t.Button=u,t.Details=f,t.CharacterCount=h,t.Checkboxes=p/*...*/

This is no longer the case in v5, as we're shipping ESModules. With mangling enabled without reservations, we'd export {h as Accordion/*...*/} which would make errors thrown by the Accordion show an entry for h in the stacktrace (despite the named export). This is why we're currently protecting the names of our components from mangling (which enables the screenshot above to show a nice Accordion).

As we grow our codebase, add base classes and errors, potentially other new classes, it'll become more and more complex to track what to mangle and what not, so I'd like us to discuss revisiting what we mangle to make things more maintainable in the long run (at the price of a potential few extra bytes in the code).

Who needs to work on this

Developers

Who needs to review this

Developers

Done when

  • Assess impact of other mangling configurations
  • Decide on which mangling configuration to follow (existing one or new one)
  • Implement configuration update (tracking missing classes if we keep the current one or whichever new options we pick).
@romaricpascal romaricpascal changed the title Discuss mangling of our classes names for our minified files Update mangling of our classes names for our minified files Aug 11, 2023
@romaricpascal romaricpascal added this to the v5.0 milestone Aug 11, 2023
@romaricpascal
Copy link
Member Author

romaricpascal commented Aug 14, 2023

The spike-mangle-options branch adds a TERSER_MANGLE env variable accepting JSON for configuring terser's mangle option in rollup.release.config.js. For example, TERSER_MANGLE='{"keep_classnames": true}' npm start will set keep_classnames to true instead of our current configuration.

Here is the result of a few options for that mangle option with the respective file sizes (compared to our current situation as well as if we had no mangling at all) and stack traces.

TL;DR:

  • Mangling is useful, without it we'd see a 22% increase of our file size, so we definitely don't want to turn that off altogether
  • There is some gain from maintaining the list ourselves vs using keep_classnames (it limits the increase of size to 0.28% instead of 0.93%)
  • However we're talking of <1% and <1Kb increases, so the gain of not having to maintain a list of classes ourselves has more value than that limit of increase
  • Using keep_fnames doesn't have a heavy drawback either (overall 2%, and still <1Kb increase). It could be handy to turn it on as well, as this would clarify the stacktraces for errors we didn't anticipate

@alphagov/design-system-developers, would there be any opposition to:

  1. going with keep_classnames instead of manually maintaining a list
  2. enabling keep_fnames to get clear stacktraces for errors we didn't anticipate in our functions

Baseline: reserved list of our component's classes

Size: 35.34Kb (-18.30% from no mangling)
Stacktrace: Only component names are same as in source, internal classes (errors, base component) are mangled

terser-mangle-current

Aggressive mangle: true

Size: 35.07Kb (-0.76% from baseline, -18.93% from no mangling )
Stacktrace: All names are mangled

terser-mangle-true

Updated list:

{"reserved":["Accordion","Button","CharacterCount","Checkboxes","ErrorSummary","ExitThisPage","Header","NotificationBanner","Radios","SkipLink","Tabs","initAll","version","GOVUKFrontendError","SupportError","GOVUKFrontendComponent"]}

Size: 35.64 (+0.28% from baseline, -17.61% from no mangling)
Stacktrace: Class names from the reserved list are the same as in source

terser-mangle-updated-list

Easy to maintain: keep_classnames: true

Size: 35.67Kb (+0.93% from baseline, -17.54% from no mangling)
Stacktrace: All class names are same as in source (including errors and base component)

terser-mangle-keep_classnames

Broader, but still easy to maintain keep_classnames: true, keep_fnames: true

Size: 36.06Kb (+2.03% from baseline, -16.64% from no mangling)
Stacktrace: All class names, as well as function names, are as in source

terser-mangle-keep_classnames-keep_fnames

No mangling

Size: 43.26Kb (+22.41% from baseline)
Stacktrace: All class names, as well as function names, are as in source

terser-mangle-false

@colinrotherham
Copy link
Contributor

@alphagov/design-system-developers, would there be any opposition to:

going with keep_classnames instead of manually maintaining a list
enabling keep_fnames to get clear stacktraces for errors we didn't anticipate in our functions

@romaricpascal Thanks for this, no objections from me

One I've considered in the past is targeting "private" class methods beginning with _

properties: {
  regex: /^_/
}

But savings are fairly negligible as you've shown

@36degrees
Copy link
Contributor

@alphagov/design-system-developers, would there be any opposition to:

  1. going with keep_classnames instead of manually maintaining a list
  2. enabling keep_fnames to get clear stacktraces for errors we didn't anticipate in our functions

Sounds sensible 👍🏻 We can always revisit later.

Just to check, is the scope of this limited to dist/govuk/govuk-frontend.min.js in the package and the minified JS in the ZIP file we attach to each release?

Minification is otherwise in the hands of the service teams if they're importing individual our classes into their own JS?

@romaricpascal romaricpascal self-assigned this Aug 29, 2023
@romaricpascal
Copy link
Member Author

Cool, I'll enable the two options then 😊

And Ollie, yes, this is only for us generating dist/govuk/govuk-frontend.min.js (which is the one we'll point people to for using in a <script> tag). Services that further minifie their own bundle and import GOV.UK Frontend have the configuration of how the resulting bundle gets mangled in their hands indeed 😊

romaricpascal added a commit that referenced this issue Aug 29, 2023
This'll keep the names of our classes and functions intact for neater stacktraces.
The [impact on file size](#4076) is very acceptable in front of the maintainability gain.
romaricpascal added a commit that referenced this issue Aug 29, 2023
This'll keep the names of our classes and functions intact for neater stacktraces.
The [impact on file size](#4076) is very acceptable in front of the maintainability gain.
romaricpascal added a commit that referenced this issue Aug 30, 2023
This'll keep the names of our classes and functions intact for neater stacktraces.
The [impact on file size](#4076) is very acceptable in front of the maintainability gain.
romaricpascal added a commit that referenced this issue Aug 31, 2023
This'll keep the names of our classes and functions intact for neater stacktraces.
The [impact on file size](#4076) is very acceptable in front of the maintainability gain.
colinrotherham pushed a commit that referenced this issue Sep 27, 2023
This'll keep the names of our classes and functions intact for neater stacktraces.
The [impact on file size](#4076) is very acceptable in front of the maintainability gain.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Development

Successfully merging a pull request may close this issue.

3 participants