We’ve previously blogged about some of the features of Qt for WebAssembly. In this blog post we’ll take a look at how to get started: building Qt, building your application, and finally deploying the application.

If you would like to know more about this topic, then please join me for the Qt for WebAssembly webinar.

Emscripten

The first step is installing emscripten. Please refer to the emscripten documentation for how to do so, and also note that Qt requires a unix host system: GNU/linux, macOS, or Windows subsystem for Linux. When done you should have a working em++ compiler in the path:



$ em++ --version

emcc (Emscripten gcc/clang-like replacement) 1.38.16 (commit 7a0e27441eda6cb0e3f1210e6837cae4b080ab4c)



Qt for WebAssembly applications are also Emscripten-based applications. Qt makes use of many of its features and so can application code.

Qt

Next, install the Qt 5.12 sources, for example using the online installer:

Build Qt from source and specify that we are cross-compiling for wasm using emscripten:



$ ~/Qt/5.12.0/Src/configure -xplatform wasm-emscripten -nomake examples -prefix $PWD/qtbase

$ make module-qtbase module-qtdeclarative [other modules]



This Qt build is different from standard desktop builds in two additional ways: It is a static build, and does not support threads. Depending on how your application is structured and which features you use this may pose a problem. One way to find out is to make a separate "-static -no-feature-thread" desktop Qt build, and then debug/fix any issues there. The reason this may be preferable is that the build-debug cycle is usually faster on desktop, and you have a working debugger.

Your Application

Finally, build the application. Qmake is the currently supported build system.



$ /path/to/qt-wasm/qtbase/bin/qmake

$ make



This will produce several output files:

Name Producer Purpose app.html Qt HTML container qtloader.js Qt JS API for loading Qt apps app.js emscripten app runtime and JS API app.wasm emscripten app binary

Here, the app.wasm contains the majority (if not all) of the application and Qt code, while the .js files provide loading and run-time support.

The .html file provides the html page structure which contains the application as a <canvas> element. The default version of this file displays a Qt logo during the loading and compile stage and contains a simple HTML page structure which makes the application use the entire browser viewport. You will probably want to replace this with application-specific branding and perhaps integrate with existing html content.

For qtloader.js our intention is to have a public and stable API for loading Qt-based applications, but we are not there yet and the API in that file is subject so change.

The files are plain data files and can be served from any http server; there is no requirement for any special active server component or plugin. Note that loading from the file system is not supported by current browsers. I use Python http.server for development, which works well.

When deploying applications we do recommend using a server that supports compression. The following table gives an indication of what the expected file sizes (for the main .wasm file) are:

Qt Modules gzip brotli Core Gui 2.8MB 2.1MB Core Gui Widgets 4.3MB 3.2MB Core Gui Widgets Quick Charts 8.6MB 6.3MB

gzip is a good default choice as compressor and is supported by most web servers. brotli provides a nice compression gain and is supported by all wasm-enabled browsers.

Slate

The final result of all this should be your application running in a web browser, here represented by the Slate app created by my colleague Mitch. Slate is a Qt Quick Controls 2 based image editor.

A live version is available as well. If you've looked at this demo before the news is that it should be actually usable now: local file access is possible and there are few or none visual glitches.

For those that are attending Qt World Summit in Berlin next month: I look forward to seeing you there. If you a are not going then let me link to the webinar once again.

edit: Modified configure string in build instructions to include -nomake examples, since it will currently fail on the threading examples as some have noted in the comments. This will be fixed in Qt 5.12.1.