The scene graph and all the tools and features of Babylon.js rely on an engine which functions as the central hub from which all orders are dispatched to WebGL (or WebGL2, or WebGPU). This engine is a simple and thin API that handles command caching, shader compilation, etc…
For our 4.1 release we decided to extend the scope of Babylon.js beyond just 3D rendering, and open up the engine for all types of GPU accelerated experiences. To this end, we are now working on decoupling the the engine itself from the scene graph so it can easily be used independently.
Why? Because WebGL (or in a broader way accelerated hardware) can also be used for more 2D oriented features like (and not limited to):
- Rendering inking
- Rendering shapes
- Compositing images
- Applying effects (blur, sepia, etc…)
- Creating GPU accelerated UI controls (going beyond HTML limitations)
Prior to 4.0, the engine, scene and other components were highly coupled, not allowing developers to use ES6 modules features like treeshaking.
The remaining problem that we want to solve for 4.1 is the size of the engine itself.
During our build process, we measure the size of a bundle where only the engine is used. The current size of that bundle is around 246 KB (around 40KB when gzipped by the web servers). This might not seem that large, but for some partners (including some Microsoft products) every tiny enhancement and file size reduction amounts to a big win for our partners with products at large scale. The simple truth is: the smaller the package, the faster it is to compile and run.
The Right Tool for the Right Job
Bundling the engine is equivalent to bringing together all of the files required by the engine to run. As a developer, you can have an idea of which dependencies your project will require, but it could quickly become tricky to find all of them.
For instance the engine can reference fileA, but fileA may need fileB and fileC, and tracking all of these networked dependencies is not an easy task.
Fortunately we found this wonderful tool by the webpack team: https://webpack.github.io/analyse/
If you run the following command line:
webpack --profile --json > webpack-stats.json
you will get a json file that you can give to the webpack analyser tool to get a dependency map:
Thanks to the tool, we learned that math.js and tools.js are a couple of the largest contributors to the file size.
Math.js is our math library (no kidding?) and we quickly discovered that the engine was barely using it. As a result, we decided to make some easy changes eliminating the need for engine to rely on it anymore.
For instance, instead of referencing Color4 directly, it was easier to create a local interface named IColor4Like. No need to get all of the features of the Color4 class when you just need to use its fields.
Removing the dependency to Tools was a bit more complicated. Removing it from Engine.ts was not a big deal but unfortunately, doing so did not help reduce the overall size. For a good reason: Another file was holding it back.
So again, we use the wonderful tool from Webpack to find who was dragging Tools.js. In addition with the list of files and their sizes, the analyzer provides a visual graph where each node is a file, so you can see who depends on what:
More precisely for tools.js, here is the graph:
The red dots are the ones requiring tool.js. By clicking the red dots, it is now easy to find out who is using tools.js:
For instance, we can see here that our promise fallback is one of the culprits.
Now that all files requiring tools.js were identified, it was easy to decouple them.
And I’m happy to announce that our hardware abstraction layer is now fully usable in an autonomous way and the file size went down from 246KB to 162KB. We saved 84KB (34%) with no feature change!