Subtitles section Play video
Native Web Apps: React, JavaScript and WebAssembly to rewrite native apps
Florian Rival PARISS: Okay. How was everyone's lunch?
[ Applause ] Good. I had a really successful lunch. I finally
beat all the kids to the desserts. I didn't get any on Monday. So, feeling good. Can we
give a round of applause for our next speaker speaking on native web apps, Florian Rival.
[ Applause ] FLORIAN: Hi, everyone. My name is Florian,
I'm working as a software engineer at Google. And today I want to talk about something that
I really like. It's applications. And when I say applications, it's any kind of application,
but in particular the ones that allow people to create things or to do things that they
were not able to do before. So there is something that I really like. It's video games. That's
why I created GDevelop. It's an open source and cross platform game engine that anyone
can use to create any kind of games. Why anyone? It's a visual editor for games where you can
create. And there are some kinds of visual programming. I will show an example. And anyone
can use it, even those who don't know thousand create games. And then you can get an HTML
game that you can put on the web. So, here is what the software used to look like. I
say used to because it's a software that was created, in C + +, it's a desktop C + + application.
You can see on the right, there's a list of objects in the game. And in the intermediary
of the game. Is, here it's a platform. And what we want to do as an example is to have
when the player is stepping button, we want the button on the platform on the right to
go up in the air. I will show how to do it using visual programming. And so, here we
go. I go to the events tab and I'm adding a new event. An event is a condition, an action,
kind of like an if then. I'm adding a new condition to check if the player is collision
with the tree. And if that's the case, I can add two actions. The first action would be
to change the animation of the button so it's going to the state where it's pressed. It's
animation number one. And I'm adding another action, which is an action to move the platform
up in the air. So, I'm adding to the platform a false on the Y axis. And now, if I press
play, the game is compiled to demonstrate and running in the browser. And we can verify
that the button is working. It's kind of simple for people that don't know how to program
and it's only based on logic. Syntax. So, a few games have been done with it. So, a
few were working quite well. And the game with the cat, but at some point I had some
issues. And the editor was getting quite old. I had lots of cross platform issues. In particular
on macOS and Linux. It wasn't working that well. And iterating on the software of the
quite slow, C++. And it was limited to old UI components, and the UX would need some
enhancements. And the entry barrier for new contributors was quite high. C++, again. So,
it was time for me to react. And I was wondering, would web technologies help? I have been doing
a lot of React before at work. And I was like, okay. That's perfect for making complex UI.
I was iterating. Can we have hundreds of elements, dynamic panels, 2D and 3D visualizations,
and all of the things that make a real application, you know? Can we make an ambitious application
using React? And the same goes for JavaScript. It's perfect for most applications. Or is
it really? Can we reuse an existing native codebase? Should we? Or if we have advanced
situations or computations, what do we do? Or if we need consistent performance? Still,
let's look at the quick post of GDevelop. There is the core of the software, composed
of the C++ classes and defining what a game is, what is an object, and how an event is
composed of conditions and actions. And then all the tools that are transpiring to the
events to JavaScript that you get a running game. And on the top of this there was an
interface in C++ using WX widgets. And there was the interaction with the device. So, my
first idea is, okay, let's replace the interface with React. Because I have an idea that it
could be better. And in a fortified system, I could write adapters for Node.js or even
in the browser simulator file system. We could run this on the JS or a browser or on electrons
so that we have a browser in the JS and you can package the application. And for the central
part, we could use WebAssembly to expose the code to the rest of the JavaScript application.
So, a few notes about WebAssembly. It's a kind of a language that is running in your
browsers. And it's a bit like assembly, meaning that it's not one that you write to, but what
you're compiling to. And at the end, it's simply like a language. Browsers are able
to generate really fast execution of any program that is retaining WebAssembly. And it is running
on actually most recent browsers including on iOS and Android. So, how do we write WebAssembly?
Well, there was the first solution was to use Emscripten. Which is what I did. It's
a project with a C++ WebAssembly compiler. It's a C++, running through a compiler, and
translating it to WebAssembly. And there are solutions for any language you can compile
to WebAssembly. Or even things like AssemblyScript which allows you to create WebAssembly using
a syntax that is really that looks like TypeScript. So, it's really interesting. In
my case, I have been using Emscripten. And I will show you the way it works. So, using
Emscripten, you can download it and sort it. It's pretty easy. And then getting EMCC, the
C++ to WebAssembly compiler. And you can run it on a C or C++ file. And in my case, as
I have a large codebase, I can replace the build to chain that was using the compiler,
and instead of at the end having a binary, I have a WebAssembly. And so, we have the
WebAssembly, which is the C++ codebase compiled to WebAssembly. And we have to expose the
existing classes in C++ so that we could view them in JavaScript. So, let's take an example.
For example, we have a class that is an objects container. So, it's think of it as the list
of objects that you've seen. So, we could have objects and get some objects inside.
And then we can have a layout. It's a bit like a level, again. Which is iterating from
an objects container so it can have a list of objects. And there are additional, name,
to change the name. So, also, we have this. We ought to write bindings. Bindings in my
case I have been using WebIDL. There are a few ways to write it. But in my case, use WebIDL,
we use something that is the interface of your C++ class. You have to write it for all
the classes in your codebase. And this will generate new code that will be doing the bridge
between JavaScript and the WebAssembly module. So, the way it works once you have compiles
the WebAssembly module plus the bindings is that you have a module that you can instant
ship into the JavaScript engine. So, on the browser or in the JS. And when it's an instant
change, here it's called GD. You have this module and you can start creating new classes,
new instances of your classes just like usual JavaScript. And you can call them and it's
working more or less automatically out of the box because the primitive types of your
functions are automatically converted. So, depends on the language that you're using.
C++ or another language. But in my case, C++ and JavaScript are translated to C++. Same
for numbers and for strings. It's also more or less automatic. So it's quite convenient.
If you are passing objects to the parameters, then they are converted to a pointer or a
reference in C++. And you can debug using the input and output stream that's converted
to console.log in JavaScript. With this, we have something that is running in the browser.
Here is the Chrome debugger. And you can see on the top, they also output it's outputted
by the C++ codebase. It's working. And then I can create a new object. So, yeah, it's
working. And it's quite nice to have, you know, with V C++ codebase you have been writing
since a few years. There are a few things to know. First is the memory management requires
care. Because when you're creating a new object, it's quite interesting because it's not garbage
collected. We mean that. If I'm looking at what this layout object is, it's a pointer
to some place in the WebAssembly memory. So, you can think of the WebAssembly memory as
a huge array that is containing bytes. When you're creating a new object, it's already
creating some bytes in this memory. Meaning that if you just drop the reference to the
object in the JavaScript world, the WebAssembly object will still be living in memory. So,
you have to explicitly call GD, to destroy, to remove this content from memory. So, in
the case of using React or any component based framework, if you're creating a framework
when the component is mounted, you have to remember to delete it or you can use an effect
hook if you're using React. So, know that the output files are quite large. For GDevelop,
it's at least 3 megabytes when compared to the WebAssembly module. And honestly, I don't
really care because I'm making a kind of desktop application, a rich application. So, knowing
that I will package one thing and make it a few hundred megabytes. 300 megabytes, more
or less. And something else to know, having a complete test set is really, really useful
because without the kind of heroes that you will be getting when something is going wrong
in the WebAssembly module. And for example, you have the wrong type of parameter. Or if
you forgot parameter, then instead of getting a number of boolean or a pointer in the C++
world, we get undefined which is translated, I guess, zeros. Everything will be broken.
And same thing if you're using a deleted object. Trying to iterate on something that was removed
from memory, and it will crush, basic lip. This being said, we have something that is
working in the browser. So, my next change was, oh, I can create an interface on top
of it is that as good or even better as the one that I use to do in the native world using
C++ before. So, let's see how to do it. Again in my case I was using React. And my change
was to make all of these examples. For example, context menus, trace objects, lots of forms
and buttons and properties. All of this in in the browser. So, we go through a few buttons.
An example that I have been using in the hope that it will the first advice I have is
to find a component library, material UI, React Toolbox or Blueprint. These are examples
of React's component libraries. And the things I was looking at was the extensive list of
high quality components because I don't want to spend time redoing the basic widgets. I
want to build an application, not to make a design system. And good theming support
and accessibility. And some good documentation. Because the world interface will be standing
on this component library. It better be good. I went with Material UI. It was the library
with the most extensive support. And it was allowing me to design quickly. And once I
had it, the first thing I had to get was to display a large list of objects. When they
say large list, in the case of drag and drop, a large list of objects that are living in
the game and can be a few hundred objects. So, this originally here was to use categorization.
So, for example, using react virtualized and react sortable hoc, and you can create a list.
That means that instead of having in the DOM in the browser to have a button for 300 DOM
elements for every object, then you will only have the object that are on the screen in
the DOM. So, 10 or maybe 20 objects. The way it works is that instead of having a list
of objects that is just mapping over an array, you're converting your list to be using the
list component that is referred to by the list and using this property. And you can
say this is the function that you will call to identify every line that is to display
on the screen. And then using React sortable hoc, you can add on top of the list. And you
are using sortable elements and you get a list that is virtualized and you can reorder
and drag and drop. That was the first way to get things that not but working well
even with large lists and big games. And the next thing is that I wanted to have patterns.
And it was as on the screen. As I'm doing a game, people want to customize their workspace.
And so, for this I have been using a tiling window library which is called a react mosaic.
There are a few different libraries like this. But this is the one I've used and it's I
mean, it's working out of the box. So, check it out. Then I've been trying to remake the
events. It's more or less large trees. A large trees arrays with events. An event is composed
of conditions and actions. But it can also have sub events like blocks of code in a traditional
programming language. So, here, again, the solution was to use a virtualization. Previously
I have been using React sortable tree which is a library to make a tree of nodes which
you can reorder. And the interesting thing about this library is it's using React virtualized
under the hood. So, quickly, every node that you see on the screen here is actually a line
in the list. And the lines that are in between the node is just a fake scaffolding that is
making like that is making the tree look like a tree and another a list. So, it's a
customized version of what I have been using. And then at some point I wanted to remake
it was the first thing that I did. And at this moment, I wanted to display the screen
so it can be composed of individual tiles and objects to be displayed. And at this moment
you can forget the DOM and go to be using WebGL. Not using WebGL directly, but a library