Our Journey into the Module World.

Stop 1: From Namespace to Module in ts files

As we have about 400 TS files and we are pragmatic developers, it sounds possible to automate that task. We created a tool to remove the declare Namespace BABYLON { header in each file and the corresponding }. Then, we went with some friends from the community over all the files to resolve the missing import in VSCode (Big thanks to them).

Stop 2: Module Augmentation

Thanks to TypeScript and their documentation, it looked like we simply needed to convert our interface augmentation to module augmentation.

Stop 3: Adding More tooling and tooling for the tooling

We were definitely in need of a bundler and we quickly figured webpack would be the most frequently used solution in the community (at the time of this post). This was enough to push us to use it to ensure we rely on the same tools than the community. So, here we were, modifying our gulp process to bundle everything in webpack to generate a UMD lib. We could still rely on tsc directly to create our ES6 target for most of the modules as they purely are TypeScript.

Stop 4: Memory Budget

Looking at the Github issues around Webpack + TsLoader it sounds like we are not the only ones with those kinds of issues, so I was willing to give it a shot to help the community. I began to check by profiling our node process if this was easily solvable but unfortunately this was related to some ts-loader caching mechanism and several webpack processes we run during the build.

Stop 5: Shaders

Simple, let’s create a quick node script transforming our .fx in .ts by wrapping the glsl code in string and allowing import: ProcessShaders. The custom script was easy enough to hack together. We even converted our shader #include mechanism in TypeScript import statement to allow better granularity in the tree shaking. This is the Grail of tree shaking for our shaders and everything is now done… we thought.

Stop 6: Circular Dependencies

Despite ES6 support for circular dependencies, it is not the case in most bundlers and our community favorite one: Webpack. Off we went, installing another tool to help listing all of the project circular dependencies: DependencyCruiser. First run worked (Hooray !!!) and we figured we have about 700 circular dependencies in the code base (Boooooooo !!!). Great I thought, there should be some tools available to help fixing this. After surfing the web for hours always ending up on cute cat videos, I contacted the TypeScript team. We understood quickly that we simply had to reorganize some code. I then went manually fixing our dependencies by relying on mainly 3 techniques:

Stop 7: Nested Namespace

We chose here to follow one approach made by a community member where basically we have a legacy entry point module which is re-exposing all the index members in the Namespace they belonged before. It is a bit ugly but pragmatic, back compatible, it works and as we have a lot of code to migrate, maybe nobody will ever notice.

Stop 8: Declaration Files

At this point I started to cry as much as I wanted to make the modules cry but I thought I couldn’t simply give up on that. I am currently watching Vikings and I have got too much honor and pride… or I simply love my job and want to keep it. As TypeScript does not want to deal with bundle, we found a lot of npm packages doing just that (How weird is that? there are packages for this and I even found one making nyancat). Looking at their code they all semt to be derived from dts-bundle where the main readme highlights that the developer was in the same situation than us but it is unmaintained, experimental, and to use with care… As we enjoy the risk, we tried and it failed due to only one unsupported feature: Module Augmentation. Unfortunately, we are relying on this to split some part of the framework and allow tree shaking. The solution again: create our own tool.

Stop 9: Cross Plat Build

Travis builds run on Linux, I work on Windows, so I ran the build on MacOS (it usually is pretty close from linux and we already had issues with case sensitivity of paths before). Fixing a couple of issues in the new build process, I was confident, but Travis was still failing. After 2 hours of fail and retry with a reference not found TypeScript exception on travis only, I had to install Linux to give it a try. It all ended up being Module Augmentation which is case sensitive on Linux but not MacOS nor Windows. This sounds simple enough but was still an interesting waste of my weekend.

Stop 10: ES6 Flavor

Native Browser support for ES6 is strict in terms of import resolution and unfortunately TypeScript transpiled JavaScript is more “node friendly”. The funny part is TypeScript, Whatwg and Node would need to find an agreement and a strong norm to ensure full compliance. But in the end, this is the users like us who need to find workarounds. So, that was it, I began to know the solution, I created my own tool to adapt the generated import path to be browser and bundler compatibles.

What I wish for Christmas is an easy to follow process to create js framework for browsers (targeting different flavors UMD, ES6, Native Browser ES6) with their attached artifacts (.map, .d.ts) directly from TypeScript.

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Babylon.js

Babylon.js

1.4K Followers

Babylon.js: Powerful, Beautiful, Simple, Open — Web-Based 3D At Its Best. https://www.babylonjs.com/