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

Tree-shaking compiler to reduce size and load time of exported games #5168

Open
bfelbo opened this issue Aug 14, 2022 · 9 comments
Open

Tree-shaking compiler to reduce size and load time of exported games #5168

bfelbo opened this issue Aug 14, 2022 · 9 comments

Comments

@bfelbo
Copy link

bfelbo commented Aug 14, 2022

Describe the project you are working on

Many small HTML5 and iOS/Android games, where it's crucial to have fast download and load times.

Describe the problem or limitation you are having in your project

Godot has an ever-growing bundle of amazing functionality, which is hugely helpful for making games. However, most of this functionality is not used, leading to bloated game bundles that take longer for the player to download. For instance, even the simplest HTML5 games made with Godot need 15 MB for the engine, whereas the game logic and assets might only be 2-3 MB.

These simple games can also take 10+ seconds to load on old devices because the device has to load a lot of unneeded functionality into memory. This will likely become an increasingly important issue as more functionality is added to Godot.

Describe the feature / enhancement and how it helps to overcome the problem or limitation

Add tree-shaking functionality to the compiler so only the part of the Godot engine that are actually used by the game are included. This would dramatically reduce size and load times.

Describe how your proposal will work, with code, pseudo-code, mock-ups, and/or diagrams

This would work similar to webpack's tree-shaking in that Godot would identify which functions are being used and remove the rest from the exported bundle.

This is similar to disabling 3D mentioned in the docs, but more refined and with much bigger benefit because it would disable lots of other unused functionality besides 3D. That being said, it might be cool to just do a simple initial version that just automatically detects if 3D is used and disables it otherwise.

Implementing tree-shaking would likely take quite a bit of effort, but would improve the bundle size and load time of every single game exported with Godot (there’s no game that uses all the functionality).

If this enhancement will not be used often, can it be worked around with a few lines of script?

No.

Is there a reason why this should be core and not an add-on in the asset library?

AFAIK this would only be possible to do in core.

@Mickeon
Copy link

Mickeon commented Aug 14, 2022

With the "destringification" that has been happening in Godot 4, I can see something like this becoming closer and closer to reality, but it would still prove outstandingly difficult to implement. Godot is a dynamic language. It's possible to connect signals with Strings(Object.connect()), it's possible to call methods through Strings (Object.call() & Object.call_deferred()). If the associated methods were to just disappear in the release build?

How could such a system be able to tell what to strip away in the following, albeit very niche, cases?

var method_name = "show" if condition else "hide"
call(method_name)

call(LIST_OF_RANDOM_METHODS)

@bfelbo
Copy link
Author

bfelbo commented Aug 14, 2022

Great points and thanks for the quick response!

JavaScript is also a dynamic language with similar functionality and webpack is able to handle it so I'm sure there's a way forward if there's enough enthusiasm for this. It might be interesting to dig a bit into the webpack docs and code.

Perhaps an easy solution is to have the tree-shaking be toggleable and it then throws if it encounters the more niche examples you mentioned?

@KoBeWi
Copy link
Member

KoBeWi commented Aug 14, 2022

I think this is what godotengine/godot#62996 implemented already.

@bfelbo
Copy link
Author

bfelbo commented Aug 14, 2022

Thanks @KoBeWi. I had done some searching, but missed godotengine/godot#62996. That's great! Closing this proposal then.

@bfelbo
Copy link
Author

bfelbo commented Aug 17, 2022

Reopening this proposal as the discussion in godotengine/godot#62996 mentions that Godot 4.X will be a 20MB+ WASM bundle even with godotengine/godot#62996 and as many features disabled as possible.

It would be hard, but would amazing to implement more sophisticated tree-shaking to really trim the WASM bundle size down.

@bfelbo bfelbo reopened this Aug 17, 2022
@KoBeWi KoBeWi removed the archived label Aug 17, 2022
@YuriSizov
Copy link
Contributor

YuriSizov commented Aug 17, 2022

I think before implementing something like this it needs to be proven that a significant benefit can be achieved. It's a game engine after all, and a small one comparatively to other major engines. It can only be reduced so far, and disabling features is also not a silver bullet as you may need some of those features.

@Mickeon
Copy link

Mickeon commented Aug 17, 2022

By all means, if someone were to impressively figure out a way to make the average file size even smaller, they're welcome to bring up an implementation, but it may not be any time soon. For now at least, 20 MBs minimum for a modern game, not accounting for assets, sounds pretty good all things considered.

@Calinou
Copy link
Member

Calinou commented Aug 17, 2022

Regarding performing tree shaking (or other forms of dead code elimiantion) on GDScript code: it won't help much (if at all) on most projects, as GDScript code only represents a small fraction of the total size of the PCK (and none of the actual binary size).

Unfortunately, C++ is not designed in a way where you can avoid compiling individual functions if they're not used. Per-class granularity is probably the best that can be done (and it's what we have right now). It's not like JavaScript which is more flexible in this regard.

@bfelbo
Copy link
Author

bfelbo commented Aug 17, 2022

Unfortunately, C++ is not designed in a way where you can avoid compiling individual functions if they're not used. Per-class granularity is probably the best that can be done (and it's what we have right now). It's not like JavaScript which is more flexible in this regard.

Makes sense, thanks! 👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants