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

Basic support for advanced (property-mangling) minify #29260

Open
wants to merge 1 commit into
base: dev
Choose a base branch
from

Conversation

AshleyScirra
Copy link

Related issue: #29210

Description

This PR is an attempt to support property-mangling minify in three.js. Where obj[str] syntax is used, the object properties must all consistently use string syntax rather than dot syntax to avoid being broken by property mangling. These changes ought to be a no-op and have no impact on any usage other than making property-mangling minify work better, since when not using property mangling, there is no meaningful difference between dot and string syntax for object properties.

This change does not provide full support for property-mangling across the entire three.js codebase. In testing this shows that the core does have support for property mangling. However it still fails with some other modules, such as GLTFLoader - it looks like the next big problem is that this and a few other parts of the codebase rely on parsing JSON. As the property names loaded from JSON must all be preserved, they must all also be updated to use string syntax. This looks like a bigger and more complex change, but can probably be done in a follow-up. Meanwhile this PR is a significant step towards supporting property mangling in three.js, and it should not have any negative impact on anything else.

Ref: issue mrdoob#29210

This change is an attempt to support property-mangling minify in three.js. Where obj[str] syntax is used, the object properties must all consistently use string syntax rather than dot syntax to avoid being broken by property mangling. These changes ought to be a no-op and have no impact on any usage other than making property-mangling minify work better, since when not using property mangling, there is no meaningful difference between dot and string syntax for object properties.
Copy link

📦 Bundle size

Full ESM build, minified and gzipped.

Filesize dev Filesize PR Diff
WebGLRenderer 685.4 kB (169.7 kB) 685.4 kB (169.7 kB) +0 B
WebGPURenderer 818.6 kB (221.2 kB) 818.6 kB (221.2 kB) +0 B

🌳 Bundle size after tree-shaking

Minimal build including a renderer, camera, empty scene, and dependencies.

Filesize dev Filesize PR Diff
WebGLRenderer 462 kB (111.4 kB) 462 kB (111.4 kB) +0 B
WebGPURenderer 564.8 kB (153.4 kB) 564.8 kB (153.4 kB) +0 B

@mrdoob
Copy link
Owner

mrdoob commented Sep 5, 2024

@Mugen87 Do you see any issues with this change?

@Mugen87
Copy link
Collaborator

Mugen87 commented Sep 5, 2024

Basically no but I always wondering if updating the code base to fix such issues is the right step.

To me, the minify tool would be the better place for a fix.

@donmccurdy
Copy link
Collaborator

I'm OK with the changes, no objection! These requirements have been in Closure Compiler for a long time, if I remember correctly. I am worried that it will be difficult to avoid regressions in future versions though, since we don't use these compilers ourselves and ESLint can't detect the problem, so it's hard to make guarantees about future compatibility.

@AshleyScirra
Copy link
Author

To me, the minify tool would be the better place for a fix.

This is possible by using lists of property names to not change (Closure Compiler calls these "externs"). There are two downsides with this though: firstly those names are globally prevented from renaming, so for example if the name material is on the list, it will never rename it even in cases where it is safe do to so. If you end up with huge lists of properties to not rename - which looks likely with a large library like this - then it can significantly impact the effectiveness of property mangling. Using string property syntax allows marking specific cases to not rename, e.g. obj["material"] will not be renamed, but obj.material is allowed to be renamed. A second downside is that in my view maintenance is more difficult: if someone does something like add a new property to ShaderLib, then property mangling is broken until the name is added to the externs list; if it's using string syntax instead, and the author just copies the existing string syntax to be consistent with all the other properties, then it still works. In other words there's a single place to specify properties not to be renamed, which is in the codebase itself. (Experience dealing with similar situations in Construct led me to end up using string syntax over long lists of externs.)

I am worried that it will be difficult to avoid regressions in future versions though

If nobody cares about property mangling other than us, I'm happy to maintain it and submit fixes if we notice it break. Most likely we will do incremental updates on this to cover just the parts of the codebase we need and maintain them if anything stops working with property mangling. And if things stop working with property mangling, all it means is something used dot syntax instead of string syntax, and that doesn't affect anyone else, so the impact of any regressions should be strictly limited to property mangling.

@mrdoob
Copy link
Owner

mrdoob commented Sep 12, 2024

Hmm...

Do you know what kind of saving are we talking about here? How many kb? And what % of that is relative to the whole game package?

@AshleyScirra
Copy link
Author

Using UglifyJS:

uglifyjs three.module.js --compress --output thee.module.simple.min.js
uglifyjs three.module.js --compress --mangle-props keep_quoted --output thee.module.advanced.min.js
Mode Size Zipped
None 1322 KB 260 KB
Simple 899 KB 191 KB
Advanced 597 KB 159 KB

So advanced brings the script size down a further 33% (and 17% zipped) relative to simple minify.

Closure Compiler does better, but it has dead code elimination in advanced mode and the file size is so much smaller I suspect it just deleted a lot of code as it was just fed a library script on its own (which I suppose is therefore entirely dead code). So the above figures should be seen as a baseline that Closure Compiler would probably beat.

FWIW advanced mode also provides stronger protection against reverse engineering which is important for Construct developers.

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.

4 participants