TypeScript in Babylon Native

Babylon.js
4 min readFeb 27, 2024
Babylon Native been used with TypeScript.

Babylon Native is a technology that allows you to run JavaScript code in a C++ application. I have already done articles here that show how one can get started with a cross platform application that uses Babylon Native. However, one of the things that is very frequently asked in the Babylon.js forum is how one can get Babylon Native to work with TypeScript instead of JavaScript.

The short answer to that question is basically that you can’t. At the end of the day Babylon Native uses JavaScript engines to run your scripts in the C++ application and those only support JavaScript code. However, it is perfectly possible for you to write your code in a TypeScript project and get it compiled to a JavaScript bundle.

One important thing to note however, is that some JavaScript engines (such as Chakra) have very strict limitation for the type of JavaScript it is able to run. So, for a new user to create a new TypeScript project that works across multiple JavaScript runtimes and platforms in Babylon Native it might not be such a simple task.

To help users get started on that, I have created a new Babylon Native sample application. This time, instead of coding directly into a JavaScript file, we have a TypeScript project in a subfolder of our CMake project. We use webpack to create a bundle.js and that is loaded at runtime by our C++ application.

Project can be found in the following link:

SergioRZMasson/BabylonNativeTypescriptSample (github.com)

Main benefits to this approach

There are several benefits of using this approach instead of the one used in previews Babylon Native GLFW samples. First, the total size of your application should be much smaller, since you no longer need to ship the babylon.max.js (~36 Mb) and other Babylon.js files, the only script that you project will need is the generated bundle.js. Since webpack has tools that help us only generate JavaScript that we are actually using, the size of bundle.js will vary depending on how many features we are actually using from Babylon.js. In our example, our final bundle.js for rendering a simple 3D scene was 2.6 Mb.

The other main benefit is the fact that you can now use TypeScript and implement all best practices that come with it. It makes you code less error-prone.

Project Structure

Our sample project is structured in the following way:

Project structure.

We are using CMake to generate a cross platform C++ project. Babylon Native and Glfw (cross platform library for window manipulation) are added as git submodules in the Dependencies folder.

In the Typescript folder we have a standard Typescript project that uses webpack to generate a compiled bundle.js with all our application code.

CMake will copy the generated bundle.js file into our final application compilation folder. This way we can find it at runtime in C++.

TypeScript sub-project

For those who are familiar with web development, our TypeScript project is pretty standard. The only caveat is that we must use babel to make the generated JavaScript compatible with Internet Explorer 11, this is required because when running on Windows, Babylon Native uses Chakra as the default JavaScript engine.

For the generated bundle.js to be compatible with Chakra we must make it compatible with Internet Explorer 11.

Babel is a JavaScript transpiler that can be used to ensure compatibility with older JavaScript engines, it can remove new JavaScript features and replace them with old ways of doing things that will be compatible with old engines. In the modules section we add a rule for babel as a plugin to webpack and use it to transpile all Babylon.js JavaScript into a version that will be compatible with Chakra.

const path = require("path");

module.exports = {
entry: "./src/index.ts",
output: {
path: path.resolve(__dirname, "build"),
filename: "bundle.js",
},
module: {
rules: [
{
include: /@babylonjs/,
test: /\.js$/,
use: {
loader: "babel-loader",
options: {
presets: [['@babel/preset-env', { targets: "ie 11" }]]
},
},
},
{
test: /\.ts$/,
use: {
loader: "ts-loader"
},
},
],
},
};

If your project uses V8 as the target JavaScript engine (this can be changed by setting the NAPI_JAVASCRIPT_ENGINE configuration variable in CMake) you won’t need the babel plugin, since V8 is already compatible with the latest JavaScript features so babel transpilation will not be required.

C++ Project

The C++ project is basically unchanged compared to the GLFW sample. The only change is that now we only need to load bundle.js in the ScriptLoader, since bundle.js already has all the required Babylon.js code:

Babylon::ScriptLoader loader{*g_runtime};
loader.LoadScript("app:///Scripts/bundle.js");

Final thoughts

Even though this is a short article I hope people can use it as a reference. The setup for using TypeScript with Babylon Native is not very complex but It might have some caveats such as using babel for compatibility with Chakra.

More advanced users can expand this project to make workflow improvements such as using webpack in watch mode and implement a file watcher in C++ to automatically reload the JavaScript runtime once bundle.js get updated.

I will try to bring more examples of those advanced workflows in the next blog.

References

Getting cross platform rendering with Babylon Native and GLFW | by Babylon.js | Medium

Babel loader: babel-loader | webpack

Sergio R. Z. Masson — Babylon.js Team

Sergio Ricardo Zerbetto Masson (@ZerbettoMasson) / Twitter

--

--

Babylon.js

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