godotengine / godot-proposals

Godot Improvement Proposals (GIPs)
MIT License
1.16k stars 97 forks source link

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

Open bfelbo opened 2 years ago

bfelbo commented 2 years ago

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 commented 2 years ago

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 commented 2 years ago

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 commented 2 years ago

I think this is what https://github.com/godotengine/godot/pull/62996 implemented already.

bfelbo commented 2 years ago

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

bfelbo commented 2 years ago

Reopening this proposal as the discussion in https://github.com/godotengine/godot/pull/62996 mentions that Godot 4.X will be a 20MB+ WASM bundle even with https://github.com/godotengine/godot/pull/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.

YuriSizov commented 2 years ago

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 commented 2 years ago

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 commented 2 years ago

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 commented 2 years ago

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! 👍