C/C++ with Emscripten is one of the initial languages to implement WebAssembly. It requires a lot of setup to compile C/C++ into WebAssembly. Especially number of team members. To support scalability, the developer experience, containerization is main actor.
I’m going to walk you through setup Docker for React and WebAssembly (C++) then deploy it to fly.io
react-create-app cli package
Create React Application.
WebAssembly Hello World (C++ Emscripten).
Integrate Webassembly with React.
Containerization with Docker and Nginx.
We create react application with webpack bundling here:
$ npx create-react-app --typescript react-wasm-docker
By default, an app created by command is bind the webpack configuration. We need them to run our compiled webassembly js module. So, I ejected it to a custom few in webpack.
$ cd react-wasm-docker $ npm run eject
The config/ folder appear and you can go to
webpack.config.js to add a couple of lines.
These above lines tell webpack to ignore including
fs. At this state now our react application should be ready. Next, create webassembly hello world
We can write several supporting languages with WebAssembly such as Rust, Go, C, C++, and even python. The Webassembly itself has its own language similar to assembly language (explain it here will last for another article)
react-wasm-docker directory, create another sub-directory name webassembly and create
my-module.cpp file within it.
$ cd react-wasm-docker $ mkdir webassembly
Next, we need a shell script to build our
.cpp module to .wasm file. So, I’ll create
build.sh in the root directory of react-wasm-docker.
This bash script will loop through all
.cpp extension files in webassembly then compiled them into single js files (with base64 encoded binary wasm). emcc is a frontend for emscripten which optimized our single js files. Then copy all compiled files to src/wasm/
--bind: enables embind.
STRICT=1: ignore the support of deprecated options to build.
SINGLE_FILE=1: compile original source into one single js file. originally, it will be one js file and another wasm file.
ALLOW_MEMORY_GROWTH=1: allocate memory for wasm module requiring memory. It is possible wasm module to consume memory more than the default of emscripten (16MB by default).
MALLOC=emmaloc: export malloc function (c++ build-in). JS files can import and use to allocate memory.
MODULARIZE=1: compiled js file as a module which we can import as import something from ....
EXPORT_ES6=1: turn JS code into JS6 module.
ENVIRONMENT=web: set the default to be run JS file on web browser. WASM can be imported from both web browser and server (like node).
We will compile it with emcc docker image by the below command in the root directory of our project.
$ docker run --rm -v $(pwd):/src trzeci/emscripten ./build.sh
Thank you trzeci!
src/wasm/ should show
my-module.js That is our wasm file to go.
Modify App.ts (or .js) in
This file will import wasm all as
console.log in browser console by calling
sayHello() from wasm. Moreover, we create button with Hello Wasm text in HTML. If that button is clicked, then it’ll get a text from
helloWasm() and set it in the middle of the page.
Now you can run
$ npm start
You can go to
localhost:[port]. The website should display as below.
Now the application is running locally. We noticed there are several steps before reaching this point. How can we shorten it for other team members or scale it in the future? That is where containers come in.
At the root of our application, creating
Dockerfile with instructions below.
This docker file will multi-state build our project sequently.
Starting with building web assembly in our webassembly.
Next, move all wasm files to
src/wasmand build all React applications.
Last, copy all files from the previous step (React and WebAssembly) to Nginx (Revert proxy server for web application).
If you noticed, we involve Nginx in the last step, so we need the Nginx configuration file. Let creating
nginx.conf at the root of the application.
To reduce size of docker image and skip unnecessary files. We need
Everything is all set. We are ready to build our docker image and run it!
Build docker image
docker build -t react-wasm-docker .
After the image is ready run it!
docker run --name react-wasm-docker-container -p 8080:8080 react-wasm-docker
Now you can go to
localhost:8080 The result page show appears below!
Although That’s all for everything, We have further improvement such as
WebAssembly is now locate in same repository of React. If project grow bigger, it would be harder to handle. We can implement Monorepo architecture to split them out.
This is just a setup project. I’ll apply it in a real project like Image Processing/Computer Vision/Microservices.
All codebase is at Github: https://github.com/kanin-kearpimy/React-with-WebAssembly-and-Docker
Connect with me!
- website: https://www.kkanin.com/
- linkedin: https://www.linkedin.com/in/kanin-kearpimy-48a2b2165/
- twitter: https://twitter.com/Kanin_Kearpimy