<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <id>https://web.dev/</id>
  <title>Ingvar Stepanyan on web.dev</title>
  <updated>2026-04-15T23:21:06Z</updated>
  <author>
    <name>Ingvar Stepanyan</name>
  </author>
  <link href="https://web.dev/authors/rreverser/feed.xml" rel="self"/>
  <link href="https://web.dev/"/>
  <icon>https://web-dev.imgix.net/image/admin/Ma3ckXmLV7aj1rVgVT1I.jpg?auto=format</icon>
  <logo>https://web.dev/images/shared/rss-banner.png</logo>
  <subtitle>WebAssembly Advocadoer</subtitle>
  
  
  <entry>
    <title>Drawing to canvas in Emscripten</title>
    <link href="https://web.dev/drawing-to-canvas-in-emscripten/"/>
    <updated>2022-02-07T00:00:00Z</updated>
    <id>https://web.dev/drawing-to-canvas-in-emscripten/</id>
    <content type="html" mode="escaped">&lt;p&gt;Different operating systems have different APIs for drawing graphics. The differences become even more confusing when writing a cross-platform code, or porting graphics from one system to another, including when porting native code to WebAssembly.&lt;/p&gt;
&lt;p&gt;In this post you will learn a couple of methods for drawing 2D graphics to the canvas element on the web from C or C++ code compiled with Emscripten.&lt;/p&gt;
&lt;h2 id=&quot;canvas-via-embind&quot;&gt;Canvas via Embind &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/drawing-to-canvas-in-emscripten/#canvas-via-embind&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If you&#39;re starting a new project rather than trying to port an existing one, it might be easiest to use the HTML &lt;a href=&quot;https://developer.mozilla.org/docs/Web/API/Canvas_API&quot; rel=&quot;noopener&quot;&gt;Canvas API&lt;/a&gt; via Emscripten&#39;s binding system &lt;a href=&quot;https://emscripten.org/docs/porting/connecting_cpp_and_javascript/embind.html&quot; rel=&quot;noopener&quot;&gt;Embind&lt;/a&gt;. Embind allows you to operate directly on arbitrary JavaScript values.&lt;/p&gt;
&lt;p&gt;To understand how to use Embind, first take a look at the following &lt;a href=&quot;https://developer.mozilla.org/docs/Web/API/Canvas_API#javascript&quot; rel=&quot;noopener&quot;&gt;example from MDN&lt;/a&gt; that finds a &amp;lt;canvas&amp;gt; element, and draws some shapes on it&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; canvas &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getElementById&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;canvas&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; ctx &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; canvas&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getContext&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;2d&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;fillStyle &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;green&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;fillRect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;150&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Here&#39;s how it can be transliterated to C++ with Embind:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&amp;lt;emscripten/val.h&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;using&lt;/span&gt; emscripten&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;val&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// Use thread_local when you want to retrieve &amp;amp; cache a global JS variable once per thread.&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;thread_local&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; val document &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; val&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;global&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;document&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// …&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  val canvas &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token generic-function&quot;&gt;&lt;span class=&quot;token function&quot;&gt;call&lt;/span&gt;&lt;span class=&quot;token generic class-name&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;val&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;getElementById&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;canvas&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  val ctx &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; canvas&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token generic-function&quot;&gt;&lt;span class=&quot;token function&quot;&gt;call&lt;/span&gt;&lt;span class=&quot;token generic class-name&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;val&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;getContext&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;2d&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;fillStyle&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;green&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token generic-function&quot;&gt;&lt;span class=&quot;token function&quot;&gt;call&lt;/span&gt;&lt;span class=&quot;token generic class-name&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;fillRect&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;150&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;When linking this code, make sure to pass &lt;code&gt;--bind&lt;/code&gt; to enable Embind:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;emcc --bind example.cpp -o example.html&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Then you can serve the compiled assets with a static server and load the example in a browser:&lt;/p&gt;
&lt;img alt=&quot;Emscripten-generated HTML page showing a green rectangle on a black canvas.&quot; decoding=&quot;async&quot; height=&quot;370&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/19fVztVUElvJ3gKfFn4f.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/19fVztVUElvJ3gKfFn4f.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/19fVztVUElvJ3gKfFn4f.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/19fVztVUElvJ3gKfFn4f.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/19fVztVUElvJ3gKfFn4f.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/19fVztVUElvJ3gKfFn4f.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/19fVztVUElvJ3gKfFn4f.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/19fVztVUElvJ3gKfFn4f.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/19fVztVUElvJ3gKfFn4f.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/19fVztVUElvJ3gKfFn4f.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/19fVztVUElvJ3gKfFn4f.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/19fVztVUElvJ3gKfFn4f.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/19fVztVUElvJ3gKfFn4f.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/19fVztVUElvJ3gKfFn4f.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/19fVztVUElvJ3gKfFn4f.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/19fVztVUElvJ3gKfFn4f.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/19fVztVUElvJ3gKfFn4f.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/19fVztVUElvJ3gKfFn4f.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;h3 id=&quot;choosing-the-canvas-element&quot;&gt;Choosing the canvas element &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/drawing-to-canvas-in-emscripten/#choosing-the-canvas-element&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;When using the Emscripten-generated HTML shell with the preceding shell command, the canvas is included and set up for you. It makes it easier to build simple demos and examples, but in larger applications you&#39;d want to include the Emscripten-generated JavaScript and WebAssembly in an HTML page of your own design.&lt;/p&gt;
&lt;p&gt;The generated JavaScript code expects to find the canvas element stored in the &lt;code&gt;Module.canvas&lt;/code&gt; property. Like &lt;a href=&quot;https://emscripten.org/docs/api_reference/module.html&quot; rel=&quot;noopener&quot;&gt;other Module properties&lt;/a&gt;, it can be set during initialization.&lt;/p&gt;
&lt;p&gt;If you&#39;re using ES6 mode (setting output to a path with an extension &lt;code&gt;.mjs&lt;/code&gt; or using the &lt;code&gt;-s EXPORT_ES6&lt;/code&gt; setting), you can pass the canvas like this:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; initModule &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;./emscripten-generated.mjs&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; Module &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;initModule&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token literal-property property&quot;&gt;canvas&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getElementById&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;my-canvas&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;If you&#39;re using regular script output, you need to declare the &lt;code&gt;Module&lt;/code&gt; object before loading the Emscripten-generated JavaScript file:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token script&quot;&gt;&lt;span class=&quot;token language-javascript&quot;&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; Module &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token literal-property property&quot;&gt;canvas&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getElementById&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;my-canvas&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;script&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;emscripten-generated.js&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token script&quot;&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;h2 id=&quot;opengl-and-sdl2&quot;&gt;OpenGL and SDL2 &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/drawing-to-canvas-in-emscripten/#opengl-and-sdl2&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://www.opengl.org/&quot; rel=&quot;noopener&quot;&gt;OpenGL&lt;/a&gt; is a popular cross-platform API for computer graphics. When used in Emscripten, it will take care of converting the supported subset of OpenGL operations to &lt;a href=&quot;https://developer.mozilla.org/docs/Web/API/WebGL_API&quot; rel=&quot;noopener&quot;&gt;WebGL&lt;/a&gt;. If your application relies on features supported in OpenGL ES 2.0 or 3.0, but not in WebGL, Emscripten can take care of emulating those too, but you need to opt-in via the &lt;a href=&quot;https://emscripten.org/docs/porting/multimedia_and_graphics/OpenGL-support.html?highlight=sdl#opengl-es-2-0-3-0-emulation&quot; rel=&quot;noopener&quot;&gt;corresponding settings&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;You can use OpenGL either directly or via higher-level 2D and 3D graphics libraries. A couple of those have been ported to the web with Emscripten. In this post, I&#39;m focusing on 2D graphics, and for that &lt;a href=&quot;https://www.libsdl.org/&quot; rel=&quot;noopener&quot;&gt;SDL2&lt;/a&gt; is currently the preferred library because it&#39;s been well-tested and supports the Emscripten backend officially upstream.&lt;/p&gt;
&lt;h3 id=&quot;drawing-a-rectangle&quot;&gt;Drawing a rectangle &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/drawing-to-canvas-in-emscripten/#drawing-a-rectangle&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&amp;quot;About SDL&amp;quot; section on the &lt;a href=&quot;https://www.libsdl.org/&quot; rel=&quot;noopener&quot;&gt;official website&lt;/a&gt; says:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Simple DirectMedia Layer is a cross-platform development library designed to provide low level access to audio, keyboard, mouse, joystick, and graphics hardware via OpenGL and Direct3D.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;All those features - controlling audio, keyboard, mouse and graphics - have been ported and work with Emscripten on the web too so you can port entire games built with SDL2 without much hassle. If you&#39;re porting an existing project, check out the &lt;a href=&quot;https://emscripten.org/docs/compiling/Building-Projects.html#integrating-with-a-build-system&quot; rel=&quot;noopener&quot;&gt;&amp;quot;Integrating with a build system&amp;quot;&lt;/a&gt; section of Emscripten docs.&lt;/p&gt;
&lt;p&gt;For simplicity, in this post I&#39;ll focus on a single-file case and translate the earlier rectangle example to SDL2:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&amp;lt;SDL2/SDL.h&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;// Initialize SDL graphics subsystem.&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token function&quot;&gt;SDL_Init&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;SDL_INIT_VIDEO&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;// Initialize a 300x300 window and a renderer.&lt;/span&gt;&lt;br /&gt;  SDL_Window &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;window&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  SDL_Renderer &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;renderer&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token function&quot;&gt;SDL_CreateWindowAndRenderer&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;300&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;300&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;window&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;renderer&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;// Set a color for drawing matching the earlier `ctx.fillStyle = &quot;green&quot;`.&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token function&quot;&gt;SDL_SetRenderDrawColor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;renderer&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;/* RGBA: green */&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0x00&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0x80&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0x00&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0xFF&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;// Create and draw a rectangle like in the earlier `ctx.fillRect()`.&lt;/span&gt;&lt;br /&gt;  SDL_Rect rect &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;x &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;y &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;w &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;150&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;h &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token function&quot;&gt;SDL_RenderFillRect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;renderer&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;rect&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;// Render everything from a buffer to the actual screen.&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token function&quot;&gt;SDL_RenderPresent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;renderer&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;// TODO: cleanup&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;When linking with Emscripten, you need to use &lt;code&gt;-s USE_SDL=2&lt;/code&gt;. This will tell Emscripten to fetch the SDL2 library, already precompiled to WebAssembly, and link it with your main application.&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;emcc example.cpp -o example.html -s &lt;span class=&quot;token assign-left variable&quot;&gt;USE_SDL&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;When the example is loaded in the browser, you&#39;ll see the familiar green rectangle:&lt;/p&gt;
&lt;img alt=&quot;Emscripten-generated HTML page showing a green rectangle on a black square canvas.&quot; decoding=&quot;async&quot; height=&quot;581&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/34ztXnZ2OZvWLwYdBzJd.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/34ztXnZ2OZvWLwYdBzJd.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/34ztXnZ2OZvWLwYdBzJd.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/34ztXnZ2OZvWLwYdBzJd.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/34ztXnZ2OZvWLwYdBzJd.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/34ztXnZ2OZvWLwYdBzJd.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/34ztXnZ2OZvWLwYdBzJd.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/34ztXnZ2OZvWLwYdBzJd.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/34ztXnZ2OZvWLwYdBzJd.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/34ztXnZ2OZvWLwYdBzJd.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/34ztXnZ2OZvWLwYdBzJd.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/34ztXnZ2OZvWLwYdBzJd.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/34ztXnZ2OZvWLwYdBzJd.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/34ztXnZ2OZvWLwYdBzJd.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/34ztXnZ2OZvWLwYdBzJd.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/34ztXnZ2OZvWLwYdBzJd.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/34ztXnZ2OZvWLwYdBzJd.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/34ztXnZ2OZvWLwYdBzJd.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;This code has a couple of problems though. First, it lacks proper cleanup of allocated resources. Second, on the web, pages don&#39;t get closed automatically when an application has finished its execution, so the image on the canvas gets preserved. However, when the same code is recompiled natively with&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;clang example.cpp -o example -lSDL2&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;and executed, the created window will only blink briefly and immediately close upon exit, so the user doesn&#39;t have a chance to see the image.&lt;/p&gt;
&lt;h3 id=&quot;integrating-an-event-loop&quot;&gt;Integrating an event loop &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/drawing-to-canvas-in-emscripten/#integrating-an-event-loop&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;A more complete and idiomatic example would look need to wait in an event loop until the user chooses to quit the application:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&amp;lt;SDL2/SDL.h&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token function&quot;&gt;SDL_Init&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;SDL_INIT_VIDEO&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  SDL_Window &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;window&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  SDL_Renderer &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;renderer&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token function&quot;&gt;SDL_CreateWindowAndRenderer&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;300&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;300&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;window&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;renderer&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token function&quot;&gt;SDL_SetRenderDrawColor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;renderer&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;/* RGBA: green */&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0x00&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0x80&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0x00&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0xFF&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  SDL_Rect rect &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;x &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;y &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;w &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;150&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;h &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token function&quot;&gt;SDL_RenderFillRect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;renderer&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;rect&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token function&quot;&gt;SDL_RenderPresent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;renderer&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;mark class=&quot;highlight-line highlight-line-active&quot;&gt;  &lt;span class=&quot;token keyword&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;/mark&gt;&lt;br /&gt;&lt;mark class=&quot;highlight-line highlight-line-active&quot;&gt;    SDL_Event event&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/mark&gt;&lt;br /&gt;&lt;mark class=&quot;highlight-line highlight-line-active&quot;&gt;    &lt;span class=&quot;token function&quot;&gt;SDL_PollEvent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;event&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/mark&gt;&lt;br /&gt;&lt;mark class=&quot;highlight-line highlight-line-active&quot;&gt;    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;event&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;type &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; SDL_QUIT&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;/mark&gt;&lt;br /&gt;&lt;mark class=&quot;highlight-line highlight-line-active&quot;&gt;      &lt;span class=&quot;token keyword&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/mark&gt;&lt;br /&gt;&lt;mark class=&quot;highlight-line highlight-line-active&quot;&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/mark&gt;&lt;br /&gt;&lt;mark class=&quot;highlight-line highlight-line-active&quot;&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/mark&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token function&quot;&gt;SDL_DestroyRenderer&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;renderer&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token function&quot;&gt;SDL_DestroyWindow&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;window&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token function&quot;&gt;SDL_Quit&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;After the image has been drawn to a window, the application now waits in a loop, where it can process keyboard, mouse and other user events. When the user closes the window, they&#39;ll trigger an &lt;code&gt;SDL_QUIT&lt;/code&gt; event, which will be intercepted to exit the loop. After the loop is exited, the application will do the cleanup and then exit itself.&lt;/p&gt;
&lt;p&gt;Now compiling this example on Linux works as expected and shows a 300 by 300 window with a green rectangle:&lt;/p&gt;
&lt;img alt=&quot;A square Linux window with black background and a green rectangle.&quot; decoding=&quot;async&quot; height=&quot;440&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 400px) 400px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/nUxwRMyWVmdK5zy2Kct6.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/nUxwRMyWVmdK5zy2Kct6.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/nUxwRMyWVmdK5zy2Kct6.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/nUxwRMyWVmdK5zy2Kct6.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/nUxwRMyWVmdK5zy2Kct6.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/nUxwRMyWVmdK5zy2Kct6.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/nUxwRMyWVmdK5zy2Kct6.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/nUxwRMyWVmdK5zy2Kct6.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/nUxwRMyWVmdK5zy2Kct6.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/nUxwRMyWVmdK5zy2Kct6.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/nUxwRMyWVmdK5zy2Kct6.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/nUxwRMyWVmdK5zy2Kct6.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/nUxwRMyWVmdK5zy2Kct6.png?auto=format&amp;w=800 800w&quot; style=&quot;max-width: 400px; margin: 0 auto&quot; width=&quot;400&quot; /&gt;
&lt;p&gt;However, the example no longer works on the web. The Emscripten-generated page freezes immediately during the load and never shows the rendered image:&lt;/p&gt;
&lt;img alt=&quot;Emscripten-generated HTML page overlaid with a &amp;#x27;Page Unresponsive&amp;#x27; error dialogue suggesting to either wait for the page to become responsible or exit the page&quot; decoding=&quot;async&quot; height=&quot;397&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/lirjGAIzCSy3ivxyySnA.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/lirjGAIzCSy3ivxyySnA.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/lirjGAIzCSy3ivxyySnA.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/lirjGAIzCSy3ivxyySnA.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/lirjGAIzCSy3ivxyySnA.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/lirjGAIzCSy3ivxyySnA.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/lirjGAIzCSy3ivxyySnA.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/lirjGAIzCSy3ivxyySnA.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/lirjGAIzCSy3ivxyySnA.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/lirjGAIzCSy3ivxyySnA.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/lirjGAIzCSy3ivxyySnA.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/lirjGAIzCSy3ivxyySnA.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/lirjGAIzCSy3ivxyySnA.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/lirjGAIzCSy3ivxyySnA.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/lirjGAIzCSy3ivxyySnA.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/lirjGAIzCSy3ivxyySnA.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/lirjGAIzCSy3ivxyySnA.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/lirjGAIzCSy3ivxyySnA.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;What happened? I&#39;ll quote the answer from the article &lt;a href=&quot;https://web.dev/asyncify/#asynchronous-model-of-the-web&quot;&gt;&amp;quot;Using asynchronous web APIs from WebAssembly&amp;quot;&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The short version is that the browser runs all the pieces of code in sort of an infinite loop, by taking them from the queue one by one. When some event is triggered, the browser queues the corresponding handler, and on the next loop iteration it&#39;s taken out from the queue and executed. This mechanism allows simulating concurrency and running lots of parallel operations while using only a single thread.&lt;/p&gt;
&lt;p&gt;The important thing to remember about this mechanism is that, while your custom JavaScript (or WebAssembly) code executes, the event loop is blocked […]&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The preceding example executes an infinite event loop, while the code itself runs inside another infinite event loop, implicitly provided by the browser. The inner loop never relinquishes control to the outer one, so the browser doesn&#39;t get a chance to process external events or draw things onto the page.&lt;/p&gt;
&lt;p&gt;There are two ways to fix this problem.&lt;/p&gt;
&lt;h4 id=&quot;unblocking-event-loop-with-asyncify&quot;&gt;Unblocking event loop with Asyncify &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/drawing-to-canvas-in-emscripten/#unblocking-event-loop-with-asyncify&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;First, as described in the &lt;a href=&quot;https://web.dev/asyncify/&quot;&gt;linked article&lt;/a&gt;, you can use &lt;a href=&quot;https://emscripten.org/docs/porting/asyncify.html&quot; rel=&quot;noopener&quot;&gt;Asyncify&lt;/a&gt;. It&#39;s an Emscripten feature that allows to &amp;quot;pause&amp;quot; the C or C++ program, give control back to the event loop, and wake up the program when some asynchronous operation has finished.&lt;/p&gt;
&lt;p&gt;Such asynchronous operation can be even &amp;quot;sleep for the minimum possible time&amp;quot;, expressed via &lt;a href=&quot;https://emscripten.org/docs/api_reference/emscripten.h.html?highlight=emscripten_sleep#c.emscripten_sleep&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;emscripten_sleep(0)&lt;/code&gt;&lt;/a&gt; API. By embedding it in the middle of the loop, I can ensure that the control is returned to browser&#39;s event loop on each iteration, and the page remains responsive and can handle any events:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&amp;lt;SDL2/SDL.h&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;ifdef&lt;/span&gt; &lt;span class=&quot;token expression&quot;&gt;__EMSCRIPTEN__&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&amp;lt;emscripten.h&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;endif&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token function&quot;&gt;SDL_Init&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;SDL_INIT_VIDEO&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  SDL_Window &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;window&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  SDL_Renderer &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;renderer&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token function&quot;&gt;SDL_CreateWindowAndRenderer&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;300&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;300&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;window&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;renderer&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token function&quot;&gt;SDL_SetRenderDrawColor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;renderer&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;/* RGBA: green */&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0x00&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0x80&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0x00&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0xFF&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  SDL_Rect rect &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;x &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;y &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;w &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;150&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;h &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token function&quot;&gt;SDL_RenderFillRect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;renderer&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;rect&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token function&quot;&gt;SDL_RenderPresent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;renderer&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token keyword&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;    SDL_Event event&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;    &lt;span class=&quot;token function&quot;&gt;SDL_PollEvent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;event&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;event&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;type &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; SDL_QUIT&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;      &lt;span class=&quot;token keyword&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;mark class=&quot;highlight-line highlight-line-active&quot;&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;ifdef&lt;/span&gt; &lt;span class=&quot;token expression&quot;&gt;__EMSCRIPTEN__&lt;/span&gt;&lt;/span&gt;&lt;/mark&gt;&lt;br /&gt;&lt;mark class=&quot;highlight-line highlight-line-active&quot;&gt;    &lt;span class=&quot;token function&quot;&gt;emscripten_sleep&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/mark&gt;&lt;br /&gt;&lt;mark class=&quot;highlight-line highlight-line-active&quot;&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;endif&lt;/span&gt;&lt;/span&gt;&lt;/mark&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token function&quot;&gt;SDL_DestroyRenderer&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;renderer&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token function&quot;&gt;SDL_DestroyWindow&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;window&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token function&quot;&gt;SDL_Quit&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;This code now needs to be compiled with Asyncify enabled:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;emcc example.cpp -o example.html -s &lt;span class=&quot;token assign-left variable&quot;&gt;USE_SDL&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt; -s ASYNCIFY&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;And the application works as expected on the web again:&lt;/p&gt;
&lt;img alt=&quot;Emscripten-generated HTML page showing a green rectangle on a black square canvas.&quot; decoding=&quot;async&quot; height=&quot;581&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/34ztXnZ2OZvWLwYdBzJd.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/34ztXnZ2OZvWLwYdBzJd.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/34ztXnZ2OZvWLwYdBzJd.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/34ztXnZ2OZvWLwYdBzJd.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/34ztXnZ2OZvWLwYdBzJd.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/34ztXnZ2OZvWLwYdBzJd.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/34ztXnZ2OZvWLwYdBzJd.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/34ztXnZ2OZvWLwYdBzJd.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/34ztXnZ2OZvWLwYdBzJd.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/34ztXnZ2OZvWLwYdBzJd.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/34ztXnZ2OZvWLwYdBzJd.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/34ztXnZ2OZvWLwYdBzJd.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/34ztXnZ2OZvWLwYdBzJd.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/34ztXnZ2OZvWLwYdBzJd.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/34ztXnZ2OZvWLwYdBzJd.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/34ztXnZ2OZvWLwYdBzJd.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/34ztXnZ2OZvWLwYdBzJd.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/34ztXnZ2OZvWLwYdBzJd.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;However, Asyncify can have non-trivial code size overhead. If it&#39;s only used for a top-level event loop in the application, a better option can be to use the &lt;a href=&quot;https://emscripten.org/docs/api_reference/emscripten.h.html#c.emscripten_set_main_loop&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;emscripten_set_main_loop&lt;/code&gt;&lt;/a&gt; function.&lt;/p&gt;
&lt;h4 id=&quot;unblocking-event-loop-with-main-loop-apis&quot;&gt;Unblocking event loop with &amp;quot;main loop&amp;quot; APIs &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/drawing-to-canvas-in-emscripten/#unblocking-event-loop-with-main-loop-apis&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;&lt;a href=&quot;https://emscripten.org/docs/api_reference/emscripten.h.html#c.emscripten_set_main_loop&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;emscripten_set_main_loop&lt;/code&gt;&lt;/a&gt; doesn&#39;t require any compiler transformations for unwinding and rewinding the call stack, and that way avoids the code size overhead. However, in exchange, it requires a lot more manual modifications to the code.&lt;/p&gt;
&lt;p&gt;First, the body of the event loop needs to be extracted into a separate function. Then, &lt;code&gt;emscripten_set_main_loop&lt;/code&gt; needs to be called with that function as a callback in the first argument, an FPS in the second argument (&lt;code&gt;0&lt;/code&gt; for the native refresh interval), and a boolean indicating whether to simulate infinite loop (&lt;code&gt;true&lt;/code&gt;) in the third:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token function&quot;&gt;emscripten_set_main_loop&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;callback&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;The newly created callback won&#39;t have any access to the stack variables in the &lt;code&gt;main&lt;/code&gt; function, so variables like &lt;code&gt;window&lt;/code&gt; and &lt;code&gt;renderer&lt;/code&gt; need to be either extracted into a heap-allocated struct and its pointer passed via &lt;a href=&quot;https://emscripten.org/docs/api_reference/emscripten.h.html#c.emscripten_set_main_loop_arg&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;emscripten_set_main_loop_arg&lt;/code&gt;&lt;/a&gt; variant of the API, or extracted into global &lt;code&gt;static&lt;/code&gt; variables (I went with the latter for simplicity). The result is slightly harder to follow, but it draws the same rectangle as the last example:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&amp;lt;SDL2/SDL.h&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&amp;lt;stdio.h&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;ifdef&lt;/span&gt; &lt;span class=&quot;token expression&quot;&gt;__EMSCRIPTEN__&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&amp;lt;emscripten.h&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;endif&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;SDL_Window &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;window&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;SDL_Renderer &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;renderer&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;handle_events&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  SDL_Event event&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token function&quot;&gt;SDL_PollEvent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;event&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;event&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;type &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; SDL_QUIT&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;run_main_loop&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;ifdef&lt;/span&gt; &lt;span class=&quot;token expression&quot;&gt;__EMSCRIPTEN__&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;mark class=&quot;highlight-line highlight-line-active&quot;&gt;  &lt;span class=&quot;token function&quot;&gt;emscripten_set_main_loop&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;handle_events&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/mark&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;else&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token keyword&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;handle_events&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;    &lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;endif&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token function&quot;&gt;SDL_Init&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;SDL_INIT_VIDEO&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token function&quot;&gt;SDL_CreateWindowAndRenderer&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;300&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;300&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;window&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;renderer&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token function&quot;&gt;SDL_SetRenderDrawColor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;renderer&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;/* RGBA: green */&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0x00&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0x80&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0x00&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0xFF&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  SDL_Rect rect &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;x &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;y &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;w &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;150&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;h &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token function&quot;&gt;SDL_RenderFillRect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;renderer&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;rect&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token function&quot;&gt;SDL_RenderPresent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;renderer&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token function&quot;&gt;run_main_loop&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token function&quot;&gt;SDL_DestroyRenderer&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;renderer&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token function&quot;&gt;SDL_DestroyWindow&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;window&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token function&quot;&gt;SDL_Quit&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Since all the control flow changes are manual and reflected in the source code, it can be compiled without the Asyncify feature again:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;emcc example.cpp -o example.html -s &lt;span class=&quot;token assign-left variable&quot;&gt;USE_SDL&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;This example might seem useless, because it works no differently from the first version, where the rectangle was drawn on canvas successfully despite the code being a lot simpler, and the &lt;code&gt;SDL_QUIT&lt;/code&gt; event—the only one handled in the &lt;code&gt;handle_events&lt;/code&gt; function—is ignored on the web anyway.&lt;/p&gt;
&lt;p&gt;However, proper event loop integration - either via Asyncify or via &lt;code&gt;emscripten_set_main_loop&lt;/code&gt; - pays off if you decide to add any kind of animation or interactivity.&lt;/p&gt;
&lt;h4 id=&quot;handling-user-interactions&quot;&gt;Handling user interactions &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/drawing-to-canvas-in-emscripten/#handling-user-interactions&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;For example, with a few changes to the last example you can make the rectangle move in response to keyboard events:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&amp;lt;SDL2/SDL.h&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;ifdef&lt;/span&gt; &lt;span class=&quot;token expression&quot;&gt;__EMSCRIPTEN__&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&amp;lt;emscripten.h&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;endif&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;SDL_Window &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;window&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;SDL_Renderer &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;renderer&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;SDL_Rect rect &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;x &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;y &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;w &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;150&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;h &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;redraw&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token function&quot;&gt;SDL_SetRenderDrawColor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;renderer&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;/* RGBA: black */&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0x00&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0x00&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0x00&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0xFF&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token function&quot;&gt;SDL_RenderClear&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;renderer&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token function&quot;&gt;SDL_SetRenderDrawColor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;renderer&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;/* RGBA: green */&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0x00&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0x80&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0x00&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0xFF&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token function&quot;&gt;SDL_RenderFillRect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;renderer&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;rect&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token function&quot;&gt;SDL_RenderPresent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;renderer&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;uint32_t&lt;/span&gt; ticksForNextKeyDown &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;handle_events&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  SDL_Event event&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token function&quot;&gt;SDL_PollEvent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;event&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;event&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;type &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; SDL_QUIT&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;mark class=&quot;highlight-line highlight-line-active&quot;&gt;  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;event&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;type &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; SDL_KEYDOWN&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;/mark&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;    &lt;span class=&quot;token keyword&quot;&gt;uint32_t&lt;/span&gt; ticksNow &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;SDL_GetTicks&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;SDL_TICKS_PASSED&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ticksNow&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; ticksForNextKeyDown&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;      &lt;span class=&quot;token comment&quot;&gt;// Throttle keydown events for 10ms.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;      ticksForNextKeyDown &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; ticksNow &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;      &lt;span class=&quot;token keyword&quot;&gt;switch&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;event&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;key&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;keysym&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;sym&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;        &lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; SDLK_UP&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;          rect&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;y &lt;span class=&quot;token operator&quot;&gt;-=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;          &lt;span class=&quot;token keyword&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;        &lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; SDLK_DOWN&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;          rect&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;y &lt;span class=&quot;token operator&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;          &lt;span class=&quot;token keyword&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;        &lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; SDLK_RIGHT&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;          rect&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;x &lt;span class=&quot;token operator&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;          &lt;span class=&quot;token keyword&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;        &lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; SDLK_LEFT&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;          rect&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;x &lt;span class=&quot;token operator&quot;&gt;-=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;          &lt;span class=&quot;token keyword&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;      &lt;span class=&quot;token function&quot;&gt;redraw&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;run_main_loop&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;ifdef&lt;/span&gt; &lt;span class=&quot;token expression&quot;&gt;__EMSCRIPTEN__&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token function&quot;&gt;emscripten_set_main_loop&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;handle_events&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;else&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token keyword&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;handle_events&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;    &lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;endif&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token function&quot;&gt;SDL_Init&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;SDL_INIT_VIDEO&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token function&quot;&gt;SDL_CreateWindowAndRenderer&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;300&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;300&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;window&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;renderer&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token function&quot;&gt;redraw&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token function&quot;&gt;run_main_loop&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token function&quot;&gt;SDL_DestroyRenderer&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;renderer&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token function&quot;&gt;SDL_DestroyWindow&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;window&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token function&quot;&gt;SDL_Quit&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;&lt;video autoplay=&quot;&quot; loop=&quot;&quot; muted=&quot;&quot; playsinline=&quot;&quot;&gt;      &lt;source src=&quot;https://storage.googleapis.com/web-dev-uploads/video/9oK23mr86lhFOwKaoYZ4EySNFp02/EahORFoNjTjwRhdtuKer.mp4&quot; type=&quot;video/mp4&quot; /&gt;    &lt;/video&gt;&lt;/p&gt;
&lt;h3 id=&quot;drawing-other-shapes-with-sdl2gfx&quot;&gt;Drawing other shapes with SDL2_gfx &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/drawing-to-canvas-in-emscripten/#drawing-other-shapes-with-sdl2gfx&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;SDL2 abstracts away cross-platform differences and various types of media devices in a single API, but it&#39;s still a pretty low-level library. In particular for graphics, while it provides APIs for drawing points, lines and rectangles, implementation of any more complex shapes and transformations is left to the user.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.ferzkopp.net/Software/SDL2_gfx/Docs/html/index.html&quot; rel=&quot;noopener&quot;&gt;SDL2_gfx&lt;/a&gt; is a separate library that fills that gap. For example, it can be used to replace a rectangle in the example above with a circle:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&amp;lt;SDL2/SDL.h&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&amp;lt;SDL2/SDL2_gfxPrimitives.h&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;ifdef&lt;/span&gt; &lt;span class=&quot;token expression&quot;&gt;__EMSCRIPTEN__&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&amp;lt;emscripten.h&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;endif&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;SDL_Window &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;window&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;SDL_Renderer &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;renderer&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;SDL_Point center &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;x &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;y &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; radius &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;redraw&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token function&quot;&gt;SDL_SetRenderDrawColor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;renderer&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;/* RGBA: black */&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0x00&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0x00&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0x00&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0xFF&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token function&quot;&gt;SDL_RenderClear&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;renderer&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;mark class=&quot;highlight-line highlight-line-active&quot;&gt;  &lt;span class=&quot;token function&quot;&gt;filledCircleRGBA&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;renderer&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; center&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;x&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; center&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;y&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; radius&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;/mark&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;                   &lt;span class=&quot;token comment&quot;&gt;/* RGBA: green */&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0x00&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0x80&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0x00&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0xFF&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token function&quot;&gt;SDL_RenderPresent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;renderer&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;uint32_t&lt;/span&gt; ticksForNextKeyDown &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;handle_events&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  SDL_Event event&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token function&quot;&gt;SDL_PollEvent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;event&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;event&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;type &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; SDL_QUIT&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;event&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;type &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; SDL_KEYDOWN&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;    &lt;span class=&quot;token keyword&quot;&gt;uint32_t&lt;/span&gt; ticksNow &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;SDL_GetTicks&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;SDL_TICKS_PASSED&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ticksNow&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; ticksForNextKeyDown&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;      &lt;span class=&quot;token comment&quot;&gt;// Throttle keydown events for 10ms.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;      ticksForNextKeyDown &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; ticksNow &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;      &lt;span class=&quot;token keyword&quot;&gt;switch&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;event&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;key&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;keysym&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;sym&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;        &lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; SDLK_UP&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;          center&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;y &lt;span class=&quot;token operator&quot;&gt;-=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;          &lt;span class=&quot;token keyword&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;        &lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; SDLK_DOWN&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;          center&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;y &lt;span class=&quot;token operator&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;          &lt;span class=&quot;token keyword&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;        &lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; SDLK_RIGHT&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;          center&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;x &lt;span class=&quot;token operator&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;          &lt;span class=&quot;token keyword&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;        &lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; SDLK_LEFT&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;          center&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;x &lt;span class=&quot;token operator&quot;&gt;-=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;          &lt;span class=&quot;token keyword&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;      &lt;span class=&quot;token function&quot;&gt;redraw&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;run_main_loop&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;ifdef&lt;/span&gt; &lt;span class=&quot;token expression&quot;&gt;__EMSCRIPTEN__&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token function&quot;&gt;emscripten_set_main_loop&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;handle_events&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;else&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token keyword&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;handle_events&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;    &lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;endif&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token function&quot;&gt;SDL_Init&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;SDL_INIT_VIDEO&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token function&quot;&gt;SDL_CreateWindowAndRenderer&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;300&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;300&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;window&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;renderer&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token function&quot;&gt;redraw&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token function&quot;&gt;run_main_loop&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token function&quot;&gt;SDL_DestroyRenderer&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;renderer&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token function&quot;&gt;SDL_DestroyWindow&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;window&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token function&quot;&gt;SDL_Quit&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Now the SDL2_gfx library also needs to be linked into the application. It&#39;s done similarly to SDL2:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt; &lt;span class=&quot;token expression&quot;&gt;Native version&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;$ clang example&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;cpp &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;o example &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;lSDL2 &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;lSDL2_gfx&lt;br /&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt; &lt;span class=&quot;token expression&quot;&gt;Web version&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;$ emcc &lt;span class=&quot;token operator&quot;&gt;--&lt;/span&gt;bind foo&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;cpp &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;o foo&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;html &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;s USE_SDL&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;s USE_SDL_GFX&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;And here are the results running on Linux:&lt;/p&gt;
&lt;img alt=&quot;A square Linux window with black background and a green circle.&quot; decoding=&quot;async&quot; height=&quot;440&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 400px) 400px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/ERTe7Nt9z5m4WnrlH5ya.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/ERTe7Nt9z5m4WnrlH5ya.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/ERTe7Nt9z5m4WnrlH5ya.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/ERTe7Nt9z5m4WnrlH5ya.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/ERTe7Nt9z5m4WnrlH5ya.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/ERTe7Nt9z5m4WnrlH5ya.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/ERTe7Nt9z5m4WnrlH5ya.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/ERTe7Nt9z5m4WnrlH5ya.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/ERTe7Nt9z5m4WnrlH5ya.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/ERTe7Nt9z5m4WnrlH5ya.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/ERTe7Nt9z5m4WnrlH5ya.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/ERTe7Nt9z5m4WnrlH5ya.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/ERTe7Nt9z5m4WnrlH5ya.png?auto=format&amp;w=800 800w&quot; style=&quot;max-width:400px; margin: 0 auto;&quot; width=&quot;400&quot; /&gt;
&lt;p&gt;And on the web:&lt;/p&gt;
&lt;img alt=&quot;Emscripten-generated HTML page showing a green circle on a black square canvas.&quot; decoding=&quot;async&quot; height=&quot;580&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/92Aj9foNpDh1UWfBAnIU.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/92Aj9foNpDh1UWfBAnIU.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/92Aj9foNpDh1UWfBAnIU.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/92Aj9foNpDh1UWfBAnIU.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/92Aj9foNpDh1UWfBAnIU.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/92Aj9foNpDh1UWfBAnIU.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/92Aj9foNpDh1UWfBAnIU.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/92Aj9foNpDh1UWfBAnIU.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/92Aj9foNpDh1UWfBAnIU.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/92Aj9foNpDh1UWfBAnIU.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/92Aj9foNpDh1UWfBAnIU.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/92Aj9foNpDh1UWfBAnIU.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/92Aj9foNpDh1UWfBAnIU.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/92Aj9foNpDh1UWfBAnIU.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/92Aj9foNpDh1UWfBAnIU.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/92Aj9foNpDh1UWfBAnIU.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/92Aj9foNpDh1UWfBAnIU.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/92Aj9foNpDh1UWfBAnIU.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;For more graphics primitives, check out the &lt;a href=&quot;https://www.ferzkopp.net/Software/SDL2_gfx/Docs/html/index.html&quot; rel=&quot;noopener&quot;&gt;auto-generated docs&lt;/a&gt;.&lt;/p&gt;
</content>
    <author>
      <name>Ingvar Stepanyan</name>
    </author>
  </entry>
  
  <entry>
    <title>Porting USB applications to the web. Part 2: gPhoto2</title>
    <link href="https://web.dev/porting-gphoto2-to-the-web/"/>
    <updated>2022-02-01T00:00:00Z</updated>
    <id>https://web.dev/porting-gphoto2-to-the-web/</id>
    <content type="html" mode="escaped">&lt;p&gt;In &lt;a href=&quot;https://web.dev/porting-libusb-to-webusb/&quot;&gt;the previous post&lt;/a&gt; I showed how the &lt;a href=&quot;https://libusb.info/&quot; rel=&quot;noopener&quot;&gt;libusb&lt;/a&gt; library was ported to run on the web with WebAssembly / &lt;a href=&quot;https://emscripten.org/&quot; rel=&quot;noopener&quot;&gt;Emscripten&lt;/a&gt;, Asyncify, and &lt;a href=&quot;https://web.dev/usb/&quot;&gt;WebUSB&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I also showed &lt;a href=&quot;https://web.dev/porting-libusb-to-webusb/#first-things-first-a-demo&quot;&gt;a demo&lt;/a&gt; built with &lt;a href=&quot;http://gphoto.org/&quot; rel=&quot;noopener&quot;&gt;gPhoto2&lt;/a&gt; that can control DSLR and mirrorless cameras over USB from a web application. In this post I&#39;ll go deeper into the technical details behind the gPhoto2 port.&lt;/p&gt;
&lt;h2 id=&quot;pointing-build-systems-to-custom-forks&quot;&gt;Pointing build systems to custom forks &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/porting-gphoto2-to-the-web/#pointing-build-systems-to-custom-forks&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Since I was targeting WebAssembly, I couldn&#39;t use the libusb and libgphoto2 provided by the system distributions. Instead, I needed my application to use my custom fork of libgphoto2, while that fork of libgphoto2 had to use my custom fork of libusb.&lt;/p&gt;
&lt;p&gt;Additionally, libgphoto2 uses libtool for loading dynamic plugins, and even though I didn&#39;t have to fork libtool like the other two libraries, I still had to build it to WebAssembly, and point libgphoto2 to that custom build instead of the system package.&lt;/p&gt;
&lt;p&gt;Here&#39;s an approximate dependency diagram (dashed lines denote dynamic linking):&lt;/p&gt;
&lt;img alt=&quot;A diagram shows &amp;#x27;the app&amp;#x27; depending on &amp;#x27;libgphoto2 fork&amp;#x27;, which depends on &amp;#x27;libtool&amp;#x27;. &amp;#x27;libtool&amp;#x27; block depends dynamically on &amp;#x27;libgphoto2 ports&amp;#x27; and &amp;#x27;libgphoto2 camlibs&amp;#x27;. Finally, &amp;#x27;libgphoto2 ports&amp;#x27; depends statically on the &amp;#x27;libusb fork&amp;#x27;.&quot; decoding=&quot;async&quot; height=&quot;481&quot; loading=&quot;lazy&quot; src=&quot;https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/ziuavwzLjYb5ZopEUzvi.svg&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;Most configure-based build systems, including the ones used in these libraries, allow overriding paths for dependencies via various flags, so that&#39;s what I tried to do first. However, when the dependency graph becomes complex, the list of path overrides for each library&#39;s dependencies becomes verbose and error-prone. I also found some bugs where build systems weren&#39;t actually prepared for their dependencies to live in non-standard paths.&lt;/p&gt;
&lt;p&gt;Instead, an easier approach is to create a separate folder as a custom system root (often shortened to &amp;quot;sysroot&amp;quot;) and point all the involved build systems to it. That way, each library will both search for its dependencies in the specified sysroot during build, and it will also install itself in the same sysroot so that others can find it more easily.&lt;/p&gt;
&lt;p&gt;Emscripten already has its own sysroot under &lt;code&gt;(path to emscripten cache)/sysroot&lt;/code&gt;, which it uses for its &lt;a href=&quot;https://emscripten.org/docs/getting_started/FAQ.html#how-do-i-link-against-system-libraries-like-sdl-boost-etc&quot; rel=&quot;noopener&quot;&gt;system libraries&lt;/a&gt;, &lt;a href=&quot;https://emscripten.org/docs/compiling/Building-Projects.html#emscripten-ports&quot; rel=&quot;noopener&quot;&gt;Emscripten ports&lt;/a&gt;, and tools like CMake and pkg-config. I chose to reuse the same sysroot for my dependencies too.&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-makefile&quot;&gt;&lt;code class=&quot;language-makefile&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# This is the default path, but you can override it&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;# to store the cache elsewhere if you want.&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;#&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;# For example, it might be useful for Docker builds&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;# if you want to preserve the deps between reruns.&lt;/span&gt;&lt;br /&gt;EM_CACHE &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;EMSCRIPTEN&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;/cache&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;# Sysroot is always under the `sysroot` subfolder.&lt;/span&gt;&lt;br /&gt;SYSROOT &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;EM_CACHE&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;/sysroot&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;# …&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;# For all dependencies I&#39;ve used the same ./configure command with the&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;# earlier defined SYSROOT path as the --prefix.&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token target symbol&quot;&gt;deps/%/Makefile&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; deps/%/configure&lt;br /&gt;        cd &lt;span class=&quot;token variable&quot;&gt;$(@D)&lt;/span&gt; &amp;amp;&amp;amp; ./configure --prefix&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;SYSROOT&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;# …&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;With such configuration, I only needed to run &lt;code&gt;make install&lt;/code&gt; in each dependency, which installed it under the sysroot, and then the libraries found each other automatically.&lt;/p&gt;
&lt;h2 id=&quot;dealing-with-dynamic-loading&quot;&gt;Dealing with dynamic loading &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/porting-gphoto2-to-the-web/#dealing-with-dynamic-loading&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;As mentioned above, libgphoto2 uses libtool to enumerate and dynamically load I/O port adapters and camera libraries. For example, the code for loading I/O libraries looks like this:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-c&quot;&gt;&lt;code class=&quot;language-c&quot;&gt;&lt;span class=&quot;token function&quot;&gt;lt_dlinit&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token function&quot;&gt;lt_dladdsearchdir&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;iolibs&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;result &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;lt_dlforeachfile&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;iolibs&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; foreach_func&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; list&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token function&quot;&gt;lt_dlexit&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;There are a few problems with this approach on the web:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;There is no standard support for dynamic linking of WebAssembly modules. Emscripten has its &lt;a href=&quot;https://emscripten.org/docs/compiling/Dynamic-Linking.html&quot; rel=&quot;noopener&quot;&gt;custom implementation&lt;/a&gt; that can simulate the &lt;a href=&quot;https://man7.org/linux/man-pages/man3/dlopen.3.html&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;dlopen()&lt;/code&gt;&lt;/a&gt; API used by libtool, but it requires you to build &amp;quot;main&#39;&#39; and &amp;quot;side&amp;quot; modules with different flags, and, specifically for &lt;code&gt;dlopen()&lt;/code&gt;, also to &lt;a href=&quot;https://emscripten.org/docs/compiling/Dynamic-Linking.html#runtime-dynamic-linking-with-dlopen&quot; rel=&quot;noopener&quot;&gt;preload the side modules into the emulated filesystem&lt;/a&gt; during the application start-up. It can be difficult to integrate those flags and tweaks into an existing autoconf build system with lots of dynamic libraries.&lt;/li&gt;
&lt;li&gt;Even if the &lt;code&gt;dlopen()&lt;/code&gt; itself is implemented, there&#39;s no way to enumerate all dynamic libraries in a certain folder on the web, because most HTTP servers don&#39;t expose directory listings for security reasons.&lt;/li&gt;
&lt;li&gt;Linking dynamic libraries on the command line instead of enumerating in runtime can also lead to problems, such as the &lt;a href=&quot;https://github.com/emscripten-core/emscripten/issues/11985&quot; rel=&quot;noopener&quot;&gt;duplicate symbols issue&lt;/a&gt;, that are caused by differences between representation of shared libraries in Emscripten and on other platforms.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It&#39;s possible to adapt the build system to those differences and hardcode the list of dynamic plugins somewhere during the build, but an even easier way to solve all those issues is to avoid dynamic linking to begin with.&lt;/p&gt;
&lt;p&gt;Turns out, libtool abstracts away various &lt;a href=&quot;https://www.gnu.org/software/libtool/manual/html_node/Module-loaders-for-libltdl.html&quot; rel=&quot;noopener&quot;&gt;dynamic linking methods&lt;/a&gt; on different platforms, and even supports writing custom loaders for others. One of the built-in loaders it supports is called &lt;a href=&quot;https://www.gnu.org/software/libtool/manual/html_node/Dlpreopening.html&quot; rel=&quot;noopener&quot;&gt;&amp;quot;Dlpreopening&amp;quot;&lt;/a&gt;:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;“Libtool provides special support for dlopening libtool object and libtool library files, so that their symbols can be resolved even on platforms without any dlopen and dlsym functions.&lt;br /&gt;
…&lt;br /&gt;
Libtool emulates -dlopen on static platforms by linking objects into the program at compile time, and creating data structures that represent the program’s symbol table. In order to use this feature, you must declare the objects you want your application to dlopen by using the -dlopen or -dlpreopen flags when you link your program (see &lt;a href=&quot;https://www.gnu.org/software/libtool/manual/html_node/Link-mode.html#Link-mode&quot; rel=&quot;noopener&quot;&gt;Link mode&lt;/a&gt;).”&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;This mechanism allows emulating dynamic loading at libtool level instead of Emscripten, while linking everything statically into a single library.&lt;/p&gt;
&lt;p&gt;The only problem this doesn&#39;t solve is enumeration of dynamic libraries. The list of those still needs to be hardcoded somewhere. Luckily, the set of plugins I needed for the app is minimal:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;On the ports side, I only care about the libusb-based camera connection and not about PTP/IP, serial access, or USB drive modes.&lt;/li&gt;
&lt;li&gt;On the camlibs side, there are various vendor-specific plugins which might provide some specialized functions, but for general settings control and capture it&#39;s enough to use the &lt;a href=&quot;https://en.wikipedia.org/wiki/Picture_Transfer_Protocol&quot; rel=&quot;noopener&quot;&gt;Picture Transfer Protocol&lt;/a&gt;, which is represented by the ptp2 camlib and supported by virtually every camera on the market.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Here&#39;s what the updated dependency diagram looks like with everything linked statically together:&lt;/p&gt;
&lt;img alt=&quot;A diagram shows &amp;#x27;the app&amp;#x27; depending on &amp;#x27;libgphoto2 fork&amp;#x27;, which depends on &amp;#x27;libtool&amp;#x27;. &amp;#x27;libtool&amp;#x27; depends on &amp;#x27;ports: libusb1&amp;#x27; and &amp;#x27;camlibs: libptp2&amp;#x27;. &amp;#x27;ports: libusb1&amp;#x27; depends on the &amp;#x27;libusb fork&amp;#x27;.&quot; decoding=&quot;async&quot; height=&quot;481&quot; loading=&quot;lazy&quot; src=&quot;https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/5Fg5aJnydnIVMn44fiBE.svg&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;So that&#39;s what I hardcoded for Emscripten builds:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-c&quot;&gt;&lt;code class=&quot;language-c&quot;&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token function&quot;&gt;LTDL_SET_PRELOADED_SYMBOLS&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token function&quot;&gt;lt_dlinit&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;mark class=&quot;highlight-line highlight-line-active&quot;&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;ifdef&lt;/span&gt; &lt;span class=&quot;token expression&quot;&gt;__EMSCRIPTEN__&lt;/span&gt;&lt;/span&gt;&lt;/mark&gt;&lt;br /&gt;&lt;mark class=&quot;highlight-line highlight-line-active&quot;&gt;  result &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;foreach_func&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;libusb1&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; list&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/mark&gt;&lt;br /&gt;&lt;mark class=&quot;highlight-line highlight-line-active&quot;&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;else&lt;/span&gt;&lt;/span&gt;&lt;/mark&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token function&quot;&gt;lt_dladdsearchdir&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;iolibs&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  result &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;lt_dlforeachfile&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;iolibs&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; foreach_func&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; list&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;endif&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token function&quot;&gt;lt_dlexit&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;and&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-c&quot;&gt;&lt;code class=&quot;language-c&quot;&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token function&quot;&gt;LTDL_SET_PRELOADED_SYMBOLS&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token function&quot;&gt;lt_dlinit&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;mark class=&quot;highlight-line highlight-line-active&quot;&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;ifdef&lt;/span&gt; &lt;span class=&quot;token expression&quot;&gt;__EMSCRIPTEN__&lt;/span&gt;&lt;/span&gt;&lt;/mark&gt;&lt;br /&gt;&lt;mark class=&quot;highlight-line highlight-line-active&quot;&gt;  ret &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;foreach_func&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;libptp2&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;foreach_data&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/mark&gt;&lt;br /&gt;&lt;mark class=&quot;highlight-line highlight-line-active&quot;&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;else&lt;/span&gt;&lt;/span&gt;&lt;/mark&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token function&quot;&gt;lt_dladdsearchdir&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;dir&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  ret &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;lt_dlforeachfile&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;dir&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; foreach_func&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;foreach_data&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;endif&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token function&quot;&gt;lt_dlexit&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;In the autoconf build system, I now had to add &lt;code&gt;-dlpreopen&lt;/code&gt; with both of those files as link flags for all executables (examples, tests and my own demo app), like this:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; HAVE_EMSCRIPTEN&lt;br /&gt;LDADD &lt;span class=&quot;token operator&quot;&gt;+=&lt;/span&gt; -dlpreopen &lt;span class=&quot;token variable&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$(&lt;/span&gt;top_builddir&lt;span class=&quot;token variable&quot;&gt;)&lt;/span&gt;&lt;/span&gt;/libgphoto2_port/usb1.la &lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;&lt;br /&gt;         -dlpreopen &lt;span class=&quot;token variable&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$(&lt;/span&gt;top_builddir&lt;span class=&quot;token variable&quot;&gt;)&lt;/span&gt;&lt;/span&gt;/camlibs/ptp2.la&lt;br /&gt;endif&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Finally, now that all the symbols are linked statically in a single library, libtool needs a way to determine which symbol belongs to which library. To achieve this, it requires developers to rename all exposed symbols like &lt;code&gt;{function name}&lt;/code&gt; to &lt;code&gt;{library name}_LTX_{function name}&lt;/code&gt;. The easiest way to do this is by using &lt;code&gt;#define&lt;/code&gt; to redefine symbol names at the top of the implementation file:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-c&quot;&gt;&lt;code class=&quot;language-c&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// …&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;config.h&quot;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;/* Define _LTX_ names - required to prevent clashes when using libtool preloading. */&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;token macro-name&quot;&gt;gp_port_library_type&lt;/span&gt; &lt;span class=&quot;token expression&quot;&gt;libusb1_LTX_gp_port_library_type&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;token macro-name&quot;&gt;gp_port_library_list&lt;/span&gt; &lt;span class=&quot;token expression&quot;&gt;libusb1_LTX_gp_port_library_list&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;token macro-name&quot;&gt;gp_port_library_operations&lt;/span&gt; &lt;span class=&quot;token expression&quot;&gt;libusb1_LTX_gp_port_library_operations&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&amp;lt;gphoto2/gphoto2-port-library.h&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// …&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;This naming scheme also prevents name clashes in case I decide to link camera-specific plugins in the same app in the future.&lt;/p&gt;
&lt;p&gt;After all these changes were implemented, I could build the test application and load the plugins successfully.&lt;/p&gt;
&lt;h2 id=&quot;generating-the-settings-ui&quot;&gt;Generating the settings UI &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/porting-gphoto2-to-the-web/#generating-the-settings-ui&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;gPhoto2 allows camera libraries to define their own settings in a form of widget tree. The hierarchy of &lt;a href=&quot;http://www.gphoto.org/doc/api/gphoto2-widget_8h.html#a8c7e7c5b04d992022d9a821a0d3f9c30&quot; rel=&quot;noopener&quot;&gt;widget types&lt;/a&gt; consists of:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Window - top-level configuration container
&lt;ul&gt;
&lt;li&gt;Sections - named groups of other widgets
&lt;ul&gt;
&lt;li&gt;Button fields&lt;/li&gt;
&lt;li&gt;Text fields&lt;/li&gt;
&lt;li&gt;Numeric fields&lt;/li&gt;
&lt;li&gt;Date fields&lt;/li&gt;
&lt;li&gt;Toggles&lt;/li&gt;
&lt;li&gt;Radio buttons&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The name, type, children, and all the other relevant properties of each widget can be queried (and, in case of values, also modified) via the &lt;a href=&quot;http://www.gphoto.org/doc/api/gphoto2-widget_8h.html&quot; rel=&quot;noopener&quot;&gt;exposed C API&lt;/a&gt;. Together, they provide a foundation for automatically generating settings UI in any language that can interact with C.&lt;/p&gt;
&lt;p&gt;Settings can be changed either via gPhoto2, or on the camera itself at any point in time. Additionally, some widgets can be readonly, and even the readonly state itself depends on the camera mode and other settings. For example, &lt;a href=&quot;https://en.wikipedia.org/wiki/Shutter_speed&quot; rel=&quot;noopener&quot;&gt;shutter speed&lt;/a&gt; is a writable numeric field in &lt;a href=&quot;https://en.wikipedia.org/wiki/Digital_camera_modes#:~:text=an%20ISO%20sensitivity).-,M%3A%20Manual%20mode,-both%20shutter%20speed&quot; rel=&quot;noopener&quot;&gt;M (manual mode)&lt;/a&gt;, but becomes an informational readonly field in &lt;a href=&quot;https://en.wikipedia.org/wiki/Digital_camera_modes#:~:text=abbreviated%20%22PASM%22%2C%20are%3A-,P%3A%20Program%20mode,-has%20the%20camera&quot; rel=&quot;noopener&quot;&gt;P (program mode)&lt;/a&gt;. In P mode, the value of shutter speed will also be dynamic and continuously changing depending on the brightness of the scene the camera is looking at.&lt;/p&gt;
&lt;p&gt;All in all, it&#39;s important to always show up-to-date information from the connected camera in the UI, while at the same time allowing the user to edit those settings from the same UI. Such bidirectional data flow is more complex to handle.&lt;/p&gt;
&lt;p&gt;gPhoto2 does not have a mechanism to retrieve only changed settings, only the entire tree or individual widgets. In order to keep the UI up-to-date without flickering and losing input focus or scroll position, I needed a way to diff the widget trees between the invocations and update only the changed UI properties. Luckily, this is a solved problem on the web, and is the core functionality of frameworks like &lt;a href=&quot;https://reactjs.org/&quot; rel=&quot;noopener&quot;&gt;React&lt;/a&gt; or &lt;a href=&quot;https://preactjs.com/&quot; rel=&quot;noopener&quot;&gt;Preact&lt;/a&gt;. I went with Preact for this project, as it&#39;s much more lightweight and does everything I need.&lt;/p&gt;
&lt;p&gt;On the C++ side I now needed to retrieve and recursively walk the settings tree via the earlier linked C API, and convert each widget to a JavaScript object:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;static&lt;/span&gt; std&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;pair&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;val&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; val&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;walk_config&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;CameraWidget &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;widget&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  val result &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; val&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;object&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  val &lt;span class=&quot;token function&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;GPP_CALL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;gp_widget_get_name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;widget&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; _&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  result&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; name&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  result&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;info&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;/* … */&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  result&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;label&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;/* … */&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  result&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;readonly&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;/* … */&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;auto&lt;/span&gt; type &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;GPP_CALL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;CameraWidgetType&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;gp_widget_get_type&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;widget&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; _&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;switch&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;type&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; GP_WIDGET_RANGE&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;      result&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;range&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;      result&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;value&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;GPP_CALL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;float&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;gp_widget_get_value&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;widget&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; _&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;      &lt;span class=&quot;token keyword&quot;&gt;float&lt;/span&gt; min&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; max&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; step&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token function&quot;&gt;gpp_try&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;gp_widget_get_range&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;widget&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;min&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;max&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;step&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;      result&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;min&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; min&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;      result&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;max&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; max&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;      result&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;step&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; step&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;      &lt;span class=&quot;token keyword&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; GP_WIDGET_TEXT&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;      result&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;text&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;      result&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;value&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;                  &lt;span class=&quot;token function&quot;&gt;GPP_CALL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;gp_widget_get_value&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;widget&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; _&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;      &lt;span class=&quot;token keyword&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// …&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;On the JavaScript side, I could now call &lt;code&gt;configToJS&lt;/code&gt;, walk over the returned JavaScript representation of the settings tree, and build the UI via Preact function &lt;code&gt;h&lt;/code&gt;:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; inputElem&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;switch&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;config&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;type&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;range&#39;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; min&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; max&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; step &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; config&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    inputElem &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;h&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;EditableInput&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token literal-property property&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;number&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;      min&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;      max&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;      step&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;      …attrs&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;text&#39;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;br /&gt;    inputElem &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;h&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;EditableInput&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; attrs&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;toggle&#39;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    inputElem &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;h&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;input&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token literal-property property&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;checkbox&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;      …attrs&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;// …&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;By running this function repeatedly in an infinite event loop, I could get the settings UI to always show the latest information, while also sending commands to the camera whenever one of the fields is edited by the user.&lt;/p&gt;
&lt;p&gt;Preact can take care of diffing the results and updating the DOM only for the changed bits of the UI, without disrupting the page focus or edit states. One problem that remains is the bidirectional data flow. Frameworks like React and Preact were designed around unidirectional data flow, because it makes it a lot easier to reason about the data and compare it between reruns, but I&#39;m breaking that expectation by allowing an external source - the camera - to update the settings UI at any time.&lt;/p&gt;
&lt;p&gt;I worked around this problem by opting out from UI updates for any input fields that are currently being edited by the user:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;/**&lt;br /&gt; * Wrapper around &amp;lt;input /&gt; that doesn&#39;t update it while it&#39;s in focus to allow editing.&lt;br /&gt; */&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;EditableInput&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Component&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  ref &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;createRef&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token function&quot;&gt;shouldComponentUpdate&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;props&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;readonly &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;activeElement &lt;span class=&quot;token operator&quot;&gt;!==&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ref&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;current&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token function&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;props&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;h&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;input&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; Object&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;assign&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;props&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token literal-property property&quot;&gt;ref&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ref&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;This way, there is always only one owner of any given field. Either the user is currently editing it, and won&#39;t be disrupted by the updated values from the camera, or the camera is updating the field value while it&#39;s out of focus.&lt;/p&gt;
&lt;h2 id=&quot;building-a-live-video-feed&quot;&gt;Building a live &amp;quot;video&amp;quot; feed &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/porting-gphoto2-to-the-web/#building-a-live-video-feed&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;During the pandemic, a lot of people moved to online meetings. Among other things, this led to &lt;a href=&quot;https://www.bbc.co.uk/news/technology-53506401&quot; rel=&quot;noopener&quot;&gt;shortages on the webcam market&lt;/a&gt;. To get a better video quality compared to built-in cameras in laptops, and in response to said shortages, many DSLR and mirrorless camera owners started looking for ways to use their photography cameras as webcams. Several camera vendors even &lt;a href=&quot;https://www.pcmag.com/how-to/how-to-use-your-canon-dslr-as-a-webcam&quot; rel=&quot;noopener&quot;&gt;shipped&lt;/a&gt; official utilities for this very purpose.&lt;/p&gt;
&lt;p&gt;Like the official tools, gPhoto2 &lt;a href=&quot;http://www.gphoto.org/doc/remote/#:~:text=Using%20as%20webcam%20/%20video%20conferencing%20camera&quot; rel=&quot;noopener&quot;&gt;supports&lt;/a&gt; streaming video from the camera to a locally stored file or directly to a virtual webcam too. I wanted to use that feature to provide a live view in my demo. However, while it&#39;s available in the console utility, I couldn&#39;t find it anywhere in the libgphoto2 library APIs.&lt;/p&gt;
&lt;p&gt;Looking at the source code of the corresponding function in the console utility, I found that it&#39;s not actually getting a video at all, but instead &lt;a href=&quot;https://github.com/gphoto/gphoto2/blob/e9ad2a460990afec3d09033000642297b16d8950/gphoto2/actions.c#L1068-L1070&quot; rel=&quot;noopener&quot;&gt;keeps retrieving the camera&#39;s preview&lt;/a&gt; as individual JPEG images in an endless loop, and writing them out one by one to form an &lt;a href=&quot;https://en.wikipedia.org/wiki/Motion_JPEG&quot; rel=&quot;noopener&quot;&gt;M-JPEG&lt;/a&gt; stream:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-c&quot;&gt;&lt;code class=&quot;language-c&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;mime&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  r &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;gp_camera_capture_preview&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;p&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;camera&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; file&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; p&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;context&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;// …&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;I was astonished that this approach works efficiently enough to get an impression of smooth realtime video. I was even more skeptical about being able to match the same performance in the web application too, with all the extra abstractions and Asyncify in the way. However, I decided to try anyway.&lt;/p&gt;
&lt;p&gt;On the C++ side I exposed a method called &lt;code&gt;capturePreviewAsBlob()&lt;/code&gt; that invokes the same &lt;code&gt;gp_camera_capture_preview()&lt;/code&gt; function, and converts the resulting in-memory file to a &lt;a href=&quot;https://developer.mozilla.org/docs/Web/API/Blob&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;Blob&lt;/code&gt;&lt;/a&gt; that can be passed to other web APIs more easily:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;val &lt;span class=&quot;token function&quot;&gt;capturePreviewAsBlob&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;gpp_rethrow&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;file &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;get_file&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token function&quot;&gt;gpp_try&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;gp_camera_capture_preview&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;camera&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;file&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; context&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;auto&lt;/span&gt; params &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;blob_chunks_and_opts&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;file&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; Blob&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;new_&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;std&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;move&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;params&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;first&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; std&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;move&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;params&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;second&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;On the JavaScript side, I have a loop, similar to the one in gPhoto2, that keeps retrieving preview images as &lt;code&gt;Blob&lt;/code&gt;s, decodes them in the background with &lt;a href=&quot;https://developer.mozilla.org/docs/Web/API/createImageBitmap&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;createImageBitmap&lt;/code&gt;&lt;/a&gt;, and &lt;a href=&quot;https://developer.mozilla.org/docs/Web/API/ImageBitmapRenderingContext/transferFromImageBitmap&quot; rel=&quot;noopener&quot;&gt;transfers&lt;/a&gt; them to the canvas on the next animation frame:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;canvasRef&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;current&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; blob &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;props&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getPreview&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; img &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;createImageBitmap&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;blob&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;/* … */&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;resolve&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;requestAnimationFrame&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;resolve&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    canvasCtx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;transferFromImageBitmap&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;img&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;catch&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;err&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// …&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Using those modern APIs ensures that all of the decoding work is done in the background, and the canvas gets updated only when both the image and the browser are fully prepared for drawing. This achieved a consistent 30+ FPS on my laptop, which matched the native performance of both gPhoto2 and the official Sony software.&lt;/p&gt;
&lt;h2 id=&quot;synchronizing-the-usb-access&quot;&gt;Synchronizing the USB access &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/porting-gphoto2-to-the-web/#synchronizing-the-usb-access&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;When a USB data transfer is requested while another operation is already in progress, it will commonly result in a &amp;quot;device is busy&amp;quot; error. Since the preview and the settings UI update regularly, and the user might be trying to capture an image or modify settings at the same time, such conflicts between different operations turned out to be very frequent.&lt;/p&gt;
&lt;p&gt;To avoid them, I needed to synchronize all the accesses within the application. For that, I&#39;ve built a promise-based async queue:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; context &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Module&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Context&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; queue &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Promise&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;resolve&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;schedule&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;op&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; res &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; queue&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;op&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;context&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  queue &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; res&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;catch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;rethrowIfCritical&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; res&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;By chaining each operation in a &lt;code&gt;then()&lt;/code&gt; callback of the existing &lt;code&gt;queue&lt;/code&gt; promise, and storing the chained result as the new value of &lt;code&gt;queue&lt;/code&gt;, I can make sure that all operations are executed one by one, in order and without overlaps.&lt;/p&gt;
&lt;p&gt;Any operation errors are returned to the caller, while critical (unexpected) errors mark the entire chain as a rejected promise, and ensure that no new operation will be scheduled afterwards.&lt;/p&gt;
&lt;p&gt;By keeping the module context in a private (non-exported) variable, I&#39;m minimizing the risks of accessing the &lt;code&gt;context&lt;/code&gt; by accident somewhere else in the app without going through the &lt;code&gt;schedule()&lt;/code&gt; call.&lt;/p&gt;
&lt;p&gt;To tie things together, now each access to the device context has to be wrapped in a &lt;code&gt;schedule()&lt;/code&gt; call like this:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; config &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;connection&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;schedule&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; context&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;configToJS&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;and&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;connection&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;schedule&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; context&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;captureImageAsFile&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;After that, all the operations were executing successfully without conflicts.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/porting-gphoto2-to-the-web/#conclusion&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Feel free to browse the &lt;a href=&quot;https://github.com/GoogleChromeLabs/web-gphoto2&quot; rel=&quot;noopener&quot;&gt;codebase on Github&lt;/a&gt; for more implementation insights. I also want to thank &lt;a href=&quot;https://github.com/msmeissn&quot; rel=&quot;noopener&quot;&gt;Marcus Meissner&lt;/a&gt; for maintenance of gPhoto2 and for his reviews of my upstream PRs.&lt;/p&gt;
&lt;p&gt;As shows in these posts, WebAssembly, Asyncify and Fugu APIs provide a capable compilation target for even the most complex applications. They allow you to take a library or an application previously built for a single platform, and port it to the web, making it available to a vastly larger number of users across desktop and mobile devices alike.&lt;/p&gt;
</content>
    <author>
      <name>Ingvar Stepanyan</name>
    </author>
  </entry>
  
  <entry>
    <title>WebAssembly feature detection</title>
    <link href="https://web.dev/webassembly-feature-detection/"/>
    <updated>2022-01-27T00:00:00Z</updated>
    <id>https://web.dev/webassembly-feature-detection/</id>
    <content type="html" mode="escaped">&lt;p&gt;WebAssembly 1.0 was released four years ago, but development didn&#39;t stop there. New features are added through the &lt;a href=&quot;https://github.com/WebAssembly/meetings/blob/main/process/phases.md&quot; rel=&quot;noopener&quot;&gt;proposal standardization process&lt;/a&gt;. As is generally the case with new features on the web, their implementation order and timelines can differ significantly between different engines. If you want to use those new features, you need to ensure that none of your users are left out. In this article you’ll learn an approach for achieving this.&lt;/p&gt;
&lt;p&gt;Some new features improve code size by adding new instructions for common operations, some add powerful performance primitives, and others improve developer experience and integration with the rest of the web.&lt;/p&gt;
&lt;p&gt;You can find the complete list of proposals and their respective stages in the &lt;a href=&quot;https://github.com/WebAssembly/proposals&quot; rel=&quot;noopener&quot;&gt;official repo&lt;/a&gt; or track their implementation status in engines on the official &lt;a href=&quot;https://webassembly.org/roadmap/&quot; rel=&quot;noopener&quot;&gt;feature roadmap&lt;/a&gt; page.&lt;/p&gt;
&lt;p&gt;To ensure that users of all browsers can use your application, you need to figure out which features you want to use. Then, split them up into groups based on browser support. Then, compile your codebase separately for each of those groups. Finally, on the browser side you need to detect supported features and load the corresponding JavaScript and Wasm bundle.&lt;/p&gt;
&lt;h2 id=&quot;picking-and-grouping-features&quot;&gt;Picking and grouping features &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/webassembly-feature-detection/#picking-and-grouping-features&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Let&#39;s walk through those steps by picking some arbitrary feature set as an example. Let&#39;s say I&#39;ve identified that I want to use SIMD, threads, and exception handling in my library for size and performance reasons. Their &lt;a href=&quot;https://webassembly.org/roadmap/&quot; rel=&quot;noopener&quot;&gt;browser support&lt;/a&gt; is as follows:&lt;/p&gt;
&lt;figure&gt;
&lt;img alt=&quot;A table showing browser support of the chosen features.&quot; decoding=&quot;async&quot; height=&quot;813&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/2HAGqxkbSoNhK03itXBK.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/2HAGqxkbSoNhK03itXBK.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/2HAGqxkbSoNhK03itXBK.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/2HAGqxkbSoNhK03itXBK.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/2HAGqxkbSoNhK03itXBK.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/2HAGqxkbSoNhK03itXBK.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/2HAGqxkbSoNhK03itXBK.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/2HAGqxkbSoNhK03itXBK.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/2HAGqxkbSoNhK03itXBK.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/2HAGqxkbSoNhK03itXBK.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/2HAGqxkbSoNhK03itXBK.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/2HAGqxkbSoNhK03itXBK.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/2HAGqxkbSoNhK03itXBK.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/2HAGqxkbSoNhK03itXBK.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/2HAGqxkbSoNhK03itXBK.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/2HAGqxkbSoNhK03itXBK.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/2HAGqxkbSoNhK03itXBK.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/2HAGqxkbSoNhK03itXBK.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
  &lt;figcaption&gt;
    View this feature table on &lt;a href=&quot;https://webassembly.org/roadmap/&quot;&gt;webassembly.org/roadmap&lt;/a&gt;.
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;You can split browsers into the following cohorts to make sure that each user gets the most optimized experience:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Chrome-based browsers: Threads, SIMD, and exception handling are all supported.&lt;/li&gt;
&lt;li&gt;Firefox: Thread and SIMD are supported, exception handling is not.&lt;/li&gt;
&lt;li&gt;Safari: Threads are supported, SIMD and exception handling are not.&lt;/li&gt;
&lt;li&gt;Other browsers: assume only baseline WebAssembly support.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This breakdown splits by feature support in the latest version of each browser. Modern browsers are evergreen and auto-update, so in the majority of cases you only need to worry about the latest release. However, as long as you include baseline WebAssembly as a fallback cohort, you can still provide a working application even for users with outdated browsers.&lt;/p&gt;
&lt;h2 id=&quot;compiling-for-different-feature-sets&quot;&gt;Compiling for different feature sets &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/webassembly-feature-detection/#compiling-for-different-feature-sets&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;WebAssembly doesn&#39;t have a built-in way to detect supported features in runtime,  therefore all instructions in the module must be supported on the target. Because of that, you need to compile the source code into Wasm separately for each of those different feature sets.&lt;/p&gt;
&lt;p&gt;Each toolchain and build system is different, and you&#39;ll need to consult the documentation of your own compiler for how to tweak those features. For the sake of simplicity, I&#39;ll use a single-file C++ library in the following example and show how to compile it with Emscripten.&lt;/p&gt;
&lt;p&gt;I&#39;ll use &lt;a href=&quot;https://v8.dev/features/simd&quot; rel=&quot;noopener&quot;&gt;SIMD&lt;/a&gt; via &lt;a href=&quot;https://emscripten.org/docs/porting/simd.html#compiling-simd-code-targeting-x86-sse-instruction-set&quot; rel=&quot;noopener&quot;&gt;SSE2 emulation&lt;/a&gt;, threads via &lt;a href=&quot;https://emscripten.org/docs/porting/pthreads.html&quot; rel=&quot;noopener&quot;&gt;Pthreads&lt;/a&gt; library support, and choose between &lt;a href=&quot;https://emscripten.org/docs/porting/exceptions.html#webassembly-exception-handling-proposal&quot; rel=&quot;noopener&quot;&gt;Wasm exception handling&lt;/a&gt; and the &lt;a href=&quot;https://emscripten.org/docs/porting/exceptions.html#javascript-based-exception-support&quot; rel=&quot;noopener&quot;&gt;fallback JavaScript implementation&lt;/a&gt;:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# First bundle: threads + SIMD + Wasm exceptions&lt;/span&gt;&lt;br /&gt;$ emcc main.cpp -o main.threads-simd-exceptions.mjs -pthread -msimd128 -msse2 -fwasm-exceptions&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;# Second bundle: threads + SIMD + JS exceptions fallback&lt;/span&gt;&lt;br /&gt;$ emcc main.cpp -o main.threads-simd.mjs -pthread -msimd128 -msse2 -fexceptions&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;# Third bundle: threads + JS exception fallback&lt;/span&gt;&lt;br /&gt;$ emcc main.cpp -o main.threads.mjs -pthread -fexceptions&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;# Fourth bundle: basic Wasm with JS exceptions fallback&lt;/span&gt;&lt;br /&gt;$ emcc main.cpp -o main.basic.mjs -fexceptions&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;The C++ code itself can use &lt;code&gt;#ifdef __EMSCRIPTEN_PTHREADS__&lt;/code&gt; and &lt;code&gt;#ifdef __SSE2__&lt;/code&gt; to conditionally choose between parallel (threads and SIMD) implementations of the same functions and the serial implementations at compile-time. It would look like this:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;process_data&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;std&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;vector&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt; some_input&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;ifdef&lt;/span&gt; &lt;span class=&quot;token expression&quot;&gt;__EMSCRIPTEN_PTHREADS__&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;ifdef&lt;/span&gt; &lt;span class=&quot;token expression&quot;&gt;__SSE2__&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;// …implementation using threads and SIMD for max speed&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;else&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;// …implementation using threads but not SIMD&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;endif&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;else&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;// …fallback implementation for browsers without those features&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;endif&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;The exception handling doesn&#39;t need &lt;code&gt;#ifdef&lt;/code&gt; directives, because it can be used in the same way from C++ regardless of the underlying implementation chosen via the compilation flags.&lt;/p&gt;
&lt;h2 id=&quot;loading-the-correct-bundle&quot;&gt;Loading the correct bundle &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/webassembly-feature-detection/#loading-the-correct-bundle&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Once you have built bundles for all feature cohorts, you need to load the correct one from the main JavaScript application. To do that, first, detect which features are supported in the current browser. You can do that with the &lt;a href=&quot;https://github.com/GoogleChromeLabs/wasm-feature-detect&quot; rel=&quot;noopener&quot;&gt;wasm-feature-detect&lt;/a&gt; library. By combining it with &lt;a href=&quot;https://v8.dev/features/dynamic-import&quot; rel=&quot;noopener&quot;&gt;dynamic import&lt;/a&gt;, you can load the most optimized bundle in any browser:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; simd&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; threads&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; exceptions &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;https://unpkg.com/wasm-feature-detect?module&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; initModule&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;threads&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;simd&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;exceptions&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;      initModule &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;./main.threads-simd-exceptions.mjs&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;      initModule &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;./main.threads-simd.mjs&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    initModule &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;./main.threads.mjs&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  initModule &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;./main.basic.mjs&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; Module &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;initModule&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// now you can use `Module` Emscripten object like you normally would&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;h2 id=&quot;final-words&quot;&gt;Final words &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/webassembly-feature-detection/#final-words&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In this post, I&#39;ve shown how to choose, build and switch between bundles for different feature sets.&lt;/p&gt;
&lt;p&gt;As the number of features grows,the number of feature cohorts may become unmaintainable. To alleviate this problem, you can choose feature cohorts based on your real-world user data, skip the less popular browsers and let them fall back to slightly less optimal cohorts. As long as your application still works for all users, this approach can provide a reasonable balance between progressive enhancement and runtime performance.&lt;/p&gt;
&lt;p&gt;In the future, WebAssembly might get a built-in way to detect supported features and switch between different implementations of the same function within the module. However, such a mechanism would itself be a post-MVP feature that you would need to detect and load conditionally using the approach above. Until then, this approach remains the only way to build and load code using new WebAssembly features across all browsers.&lt;/p&gt;
</content>
    <author>
      <name>Ingvar Stepanyan</name>
    </author>
  </entry>
  
  <entry>
    <title>Porting USB applications to the web. Part 1: libusb</title>
    <link href="https://web.dev/porting-libusb-to-webusb/"/>
    <updated>2022-01-20T00:00:00Z</updated>
    <id>https://web.dev/porting-libusb-to-webusb/</id>
    <content type="html" mode="escaped">&lt;p&gt;In &lt;a href=&quot;https://web.dev/asyncify/&quot;&gt;a previous post&lt;/a&gt;, I showed how to port apps using filesystem APIs to the web with &lt;a href=&quot;https://web.dev/file-system-access/&quot;&gt;File System Access API&lt;/a&gt;, WebAssembly and &lt;a href=&quot;https://emscripten.org/docs/porting/asyncify.html&quot; rel=&quot;noopener&quot;&gt;Asyncify&lt;/a&gt;. Now I want to continue the same topic of integrating &lt;a href=&quot;https://fugu-tracker.web.app/&quot; rel=&quot;noopener&quot;&gt;Fugu APIs&lt;/a&gt; with WebAssembly and porting apps to the web without losing important features.&lt;/p&gt;
&lt;p&gt;I&#39;ll show how apps that communicate with USB devices can be ported to the web by porting &lt;a href=&quot;https://libusb.info/&quot; rel=&quot;noopener&quot;&gt;libusb&lt;/a&gt;—a popular USB library written in C—to WebAssembly (via &lt;a href=&quot;https://emscripten.org/&quot; rel=&quot;noopener&quot;&gt;Emscripten&lt;/a&gt;), Asyncify and &lt;a href=&quot;https://web.dev/usb/&quot;&gt;WebUSB&lt;/a&gt;.&lt;/p&gt;
&lt;aside class=&quot;aside flow bg-state-info-bg color-state-info-text&quot;&gt;&lt;div class=&quot; flow&quot;&gt; Fun fact: On some platforms, implementation of WebUSB also uses libusb under the hood. So what the port achieves is, in fact, one libusb, compiled to WebAssembly, talking to another libusb, shipped as part of the browser, through an intermediate layer. Isn&#39;t the web fun? &lt;/div&gt;&lt;/aside&gt;
&lt;h2 id=&quot;first-things-first-a-demo&quot;&gt;First things first: a demo &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/porting-libusb-to-webusb/#first-things-first-a-demo&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The most important thing to do when porting a library is choosing the right demo—something that would showcase the capabilities of the ported library, allowing you to test it in a variety of ways, and be visually compelling at the same time.&lt;/p&gt;
&lt;p&gt;The idea I chose was DSLR remote control. In particular, an open source project &lt;a href=&quot;http://gphoto.org/&quot; rel=&quot;noopener&quot;&gt;gPhoto2&lt;/a&gt; has been in this space long enough to reverse-engineer and implement support for a wide variety of digital cameras. It supports several protocols, but the one I was most interested in was USB support, which it performs via libusb.&lt;/p&gt;
&lt;p&gt;I&#39;ll describe the steps for building this demo in two parts. In this blog post, I&#39;ll describe how I ported libusb itself, and what tricks might be necessary to port other popular libraries to Fugu APIs. In the &lt;a href=&quot;https://web.dev/porting-gphoto2-to-the-web&quot;&gt;second post&lt;/a&gt;, I&#39;ll go into details on porting and integrating gPhoto2 itself.&lt;/p&gt;
&lt;p&gt;In the end, I got a working web application that previews live feed from a DSLR and can control its settings over USB. Feel free to check out the &lt;a href=&quot;https://web-gphoto2.rreverser.com/&quot; rel=&quot;noopener&quot;&gt;live&lt;/a&gt; or the pre-recorded demo before reading up on technical details:&lt;/p&gt;
&lt;figure&gt;
  &lt;video controls=&quot;&quot;&gt;      &lt;source src=&quot;https://storage.googleapis.com/web-dev-uploads/video/9oK23mr86lhFOwKaoYZ4EySNFp02/4MUKvJhKOPK2CSTkhnEC.mp4&quot; type=&quot;video/mp4&quot; /&gt;    &lt;/video&gt;
  &lt;figcaption&gt;
    &lt;a href=&quot;https://web-gphoto2.rreverser.com/&quot;&gt;The demo&lt;/a&gt; running on a laptop connected to a Sony camera.
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h3 id=&quot;note-on-camera-specific-quirks&quot;&gt;Note on camera-specific quirks &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/porting-libusb-to-webusb/#note-on-camera-specific-quirks&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;You might have noticed that changing settings takes a while in the video. Like with most other issues you might see, this is not caused by the performance of WebAssembly or WebUSB, but by how gPhoto2 interacts with the specific camera chosen for the demo.&lt;/p&gt;
&lt;p&gt;Sony a6600 doesn&#39;t expose an API to set values like ISO, aperture or shutter speed directly, and instead only provides commands to increase or decrease them by the specified number of steps. To make matters more complicated, it doesn&#39;t return a list of the actually supported values, either—the returned list seems hardcoded across many Sony camera models.&lt;/p&gt;
&lt;p&gt;When setting one of those values, gPhoto2 has no other choice but to:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Make a step (or a few) in the direction of the chosen value.&lt;/li&gt;
&lt;li&gt;Wait a bit for the camera to update the settings.&lt;/li&gt;
&lt;li&gt;Read back the value the camera actually landed on.&lt;/li&gt;
&lt;li&gt;Check that the last step didn&#39;t jump over the desired value nor wrapped around the end or the beginning of the list.&lt;/li&gt;
&lt;li&gt;Repeat.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;It can take some time, but if the value is actually supported by the camera, it will get there, and, if not, it will stop on the nearest supported value.&lt;/p&gt;
&lt;p&gt;Other cameras will likely have different sets of settings, underlying APIs, and quirks. Keep in mind that gPhoto2 is an open-source project, and either automated or manual testing of all the camera models out there is simply not feasible, so detailed issue reports and PRs are always welcome (but make sure to reproduce the issues with the official gPhoto2 client first).&lt;/p&gt;
&lt;h3 id=&quot;important-cross-platform-compatibility-notes&quot;&gt;Important cross-platform compatibility notes &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/porting-libusb-to-webusb/#important-cross-platform-compatibility-notes&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Unfortunately, on Windows any &amp;quot;well-known&amp;quot; devices, including DSLR cameras, are assigned a system driver, which is not compatible with WebUSB. If you want to try the demo on Windows, you&#39;ll have to use a tool like &lt;a href=&quot;https://zadig.akeo.ie/&quot; rel=&quot;noopener&quot;&gt;Zadig&lt;/a&gt; to override the driver for the connected DSLR to either WinUSB or libusb. This approach works fine for me and many other users, but you should use it at your own risk.&lt;/p&gt;
&lt;p&gt;On Linux, you will likely need to &lt;a href=&quot;https://web.dev/build-for-webusb/#linux&quot;&gt;set custom permissions&lt;/a&gt; to allow access to your DSLR via WebUSB, although this depends on your distribution.&lt;/p&gt;
&lt;p&gt;On macOS and Android, the demo should work out of the box. If you&#39;re trying it on an Android phone, make sure to switch to the landscape mode as I didn&#39;t put much effort into making it responsive (PRs are welcome!):&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;Android phone connected to a Canon camera via a USB-C cable.&quot; decoding=&quot;async&quot; height=&quot;533&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/POZGEUlnjJeRKvVDFdiR.jpg?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/POZGEUlnjJeRKvVDFdiR.jpg?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/POZGEUlnjJeRKvVDFdiR.jpg?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/POZGEUlnjJeRKvVDFdiR.jpg?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/POZGEUlnjJeRKvVDFdiR.jpg?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/POZGEUlnjJeRKvVDFdiR.jpg?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/POZGEUlnjJeRKvVDFdiR.jpg?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/POZGEUlnjJeRKvVDFdiR.jpg?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/POZGEUlnjJeRKvVDFdiR.jpg?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/POZGEUlnjJeRKvVDFdiR.jpg?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/POZGEUlnjJeRKvVDFdiR.jpg?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/POZGEUlnjJeRKvVDFdiR.jpg?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/POZGEUlnjJeRKvVDFdiR.jpg?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/POZGEUlnjJeRKvVDFdiR.jpg?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/POZGEUlnjJeRKvVDFdiR.jpg?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/POZGEUlnjJeRKvVDFdiR.jpg?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/POZGEUlnjJeRKvVDFdiR.jpg?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/POZGEUlnjJeRKvVDFdiR.jpg?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
  &lt;figcaption&gt;
    &lt;a href=&quot;https://web-gphoto2.rreverser.com/&quot;&gt;The same demo&lt;/a&gt; running on an Android phone. Picture by &lt;a href=&quot;https://twitter.com/DasSurma&quot;&gt;Surma&lt;/a&gt;.
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;For a more in-depth guide on cross-platform usage of WebUSB, see the &lt;a href=&quot;https://web.dev/build-for-webusb/#platform-specific-considerations&quot;&gt;&amp;quot;Platform-specific considerations&amp;quot; section of &amp;quot;Building a device for WebUSB&amp;quot;&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;adding-a-new-backend-to-libusb&quot;&gt;Adding a new backend to libusb &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/porting-libusb-to-webusb/#adding-a-new-backend-to-libusb&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Now onto the technical details. While it&#39;s possible to provide a shim API similar to libusb (this has been done by others before) and link other applications against it, this approach is error-prone and makes any further extension or maintenance harder. I wanted to do things right, in a way that could be potentially contributed back upstream and merged into libusb in the future.&lt;/p&gt;
&lt;p&gt;Luckily, the &lt;a href=&quot;https://github.com/libusb/libusb/blob/f2b218b61867f27568ba74fa38e156e5f55ed825/README#L13-L15&quot; rel=&quot;noopener&quot;&gt;libusb README&lt;/a&gt; says:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;“libusb is abstracted internally in such a way that it can hopefully be ported to other operating systems. Please see the &lt;a href=&quot;https://github.com/libusb/libusb/blob/master/PORTING&quot; rel=&quot;noopener&quot;&gt;PORTING&lt;/a&gt; file for more information.”&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;libusb is structured in a way where the public API is separate from &amp;quot;backends&amp;quot;. Those backends are responsible for listing, opening, closing and actually communicating to the devices via the operating system&#39;s low-level APIs. This is how libusb already abstracts away differences between Linux, macOS, Windows, Android, OpenBSD/NetBSD, Haiku and Solaris and works on all these platforms.&lt;/p&gt;
&lt;p&gt;What I had to do was add another backend for the Emscripten+WebUSB &amp;quot;operating system&amp;quot;. The implementations for those backends live in the &lt;a href=&quot;https://github.com/libusb/libusb/tree/master/libusb/os&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;libusb/os&lt;/code&gt;&lt;/a&gt; folder:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;~/w/d/libusb $ &lt;span class=&quot;token function&quot;&gt;ls&lt;/span&gt; libusb/os&lt;br /&gt;darwin_usb.c           haiku_usb_raw.h  threads_posix.lo&lt;br /&gt;darwin_usb.h           linux_netlink.c  threads_posix.o&lt;br /&gt;events_posix.c         linux_udev.c     threads_windows.c&lt;br /&gt;events_posix.h         linux_usbfs.c    threads_windows.h&lt;br /&gt;events_posix.lo        linux_usbfs.h    windows_common.c&lt;br /&gt;events_posix.o         netbsd_usb.c     windows_common.h&lt;br /&gt;events_windows.c       null_usb.c       windows_usbdk.c&lt;br /&gt;events_windows.h       openbsd_usb.c    windows_usbdk.h&lt;br /&gt;haiku_pollfs.cpp       sunos_usb.c      windows_winusb.c&lt;br /&gt;haiku_usb_backend.cpp  sunos_usb.h      windows_winusb.h&lt;br /&gt;haiku_usb.h            threads_posix.c&lt;br /&gt;haiku_usb_raw.cpp      threads_posix.h&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Each backend includes the &lt;a href=&quot;https://github.com/libusb/libusb/blob/master/libusb/libusbi.h&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;libusbi.h&lt;/code&gt;&lt;/a&gt; header with common types and helpers, and needs to expose a &lt;code&gt;usbi_backend&lt;/code&gt; variable of type &lt;a href=&quot;https://github.com/libusb/libusb/blob/f2b218b61867f27568ba74fa38e156e5f55ed825/libusb/libusbi.h#L886&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;usbi_os_backend&lt;/code&gt;&lt;/a&gt;. For example, this is what the &lt;a href=&quot;https://github.com/libusb/libusb/blob/6cae9c6dbd74c0840848f343dd605c5ddcef1ad1/libusb/os/windows_common.c#L866-L904&quot; rel=&quot;noopener&quot;&gt;Windows backend&lt;/a&gt; looks like:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-c&quot;&gt;&lt;code class=&quot;language-c&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;usbi_os_backend&lt;/span&gt; usbi_backend &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token string&quot;&gt;&quot;Windows&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  USBI_CAP_HAS_HID_ACCESS&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  windows_init&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  windows_exit&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  windows_set_option&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  windows_get_device_list&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;   &lt;span class=&quot;token comment&quot;&gt;/* hotplug_poll */&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;   &lt;span class=&quot;token comment&quot;&gt;/* wrap_sys_device */&lt;/span&gt;&lt;br /&gt;  windows_open&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  windows_close&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  windows_get_active_config_descriptor&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  windows_get_config_descriptor&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  windows_get_config_descriptor_by_value&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  windows_get_configuration&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  windows_set_configuration&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  windows_claim_interface&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  windows_release_interface&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  windows_set_interface_altsetting&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  windows_clear_halt&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  windows_reset_device&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;   &lt;span class=&quot;token comment&quot;&gt;/* alloc_streams */&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;   &lt;span class=&quot;token comment&quot;&gt;/* free_streams */&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;   &lt;span class=&quot;token comment&quot;&gt;/* dev_mem_alloc */&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;   &lt;span class=&quot;token comment&quot;&gt;/* dev_mem_free */&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;   &lt;span class=&quot;token comment&quot;&gt;/* kernel_driver_active */&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;   &lt;span class=&quot;token comment&quot;&gt;/* detach_kernel_driver */&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;   &lt;span class=&quot;token comment&quot;&gt;/* attach_kernel_driver */&lt;/span&gt;&lt;br /&gt;  windows_destroy_device&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  windows_submit_transfer&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  windows_cancel_transfer&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;   &lt;span class=&quot;token comment&quot;&gt;/* clear_transfer_priv */&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;   &lt;span class=&quot;token comment&quot;&gt;/* handle_events */&lt;/span&gt;&lt;br /&gt;  windows_handle_transfer_completion&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;sizeof&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;windows_context_priv&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;sizeof&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;union&lt;/span&gt; windows_device_priv&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;sizeof&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;windows_device_handle_priv&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;sizeof&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;windows_transfer_priv&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Looking through the properties, we can see that the struct includes the backend name, a set of its capabilities, handlers for various low-level USB operations in form of function pointers, and, finally, sizes to allocate for storing private device-/context-/transfer-level data.&lt;/p&gt;
&lt;p&gt;The private data fields are useful at least for storing OS handles to all those things, as without handles we don&#39;t know which item any given operation applies to. In the web implementation, the OS handles would be the underlying WebUSB JavaScript objects. The natural way to represent and store them in Emscripten is via the &lt;a href=&quot;https://emscripten.org/docs/api_reference/val.h.html#_CPPv4N10emscripten10emscripten3valE&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;emscripten::val&lt;/code&gt;&lt;/a&gt; class, which is provided as part of &lt;a href=&quot;https://emscripten.org/docs/porting/connecting_cpp_and_javascript/embind.html&quot; rel=&quot;noopener&quot;&gt;Embind&lt;/a&gt; (Emscripten&#39;s bindings system).&lt;/p&gt;
&lt;p&gt;Most of the backends in the folder are implemented in C, but a few are implemented in C++. Embind only works with C++, so the choice was made for me and I&#39;ve added &lt;code&gt;libusb/libusb/os/emscripten_webusb.cpp&lt;/code&gt; with the required structure and with &lt;code&gt;sizeof(val)&lt;/code&gt; for the private data fields:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&amp;lt;emscripten.h&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&amp;lt;emscripten/val.h&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;libusbi.h&quot;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;using&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;namespace&lt;/span&gt; emscripten&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// …function implementations&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; usbi_os_backend usbi_backend &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;name &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Emscripten + WebUSB backend&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;caps &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; LIBUSB_CAP_HAS_CAPABILITY&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;// …handlers—function pointers to implementations above&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;device_priv_size &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;sizeof&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;val&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;transfer_priv_size &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;sizeof&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;val&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;h3 id=&quot;storing-webusb-objects-as-device-handles&quot;&gt;Storing WebUSB objects as device handles &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/porting-libusb-to-webusb/#storing-webusb-objects-as-device-handles&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;libusb provides ready-to-use pointers to the allocated area for private data. To work with those pointers as &lt;code&gt;val&lt;/code&gt; instances, I&#39;ve added small helpers that construct them in-place, retrieve them as references, and move values out:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// We store an Embind handle to WebUSB USBDevice in &quot;priv&quot; metadata of&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// libusb device, this helper returns a pointer to it.&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ValPtr&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;init_to&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;val &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt;value&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ptr&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;val&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;std&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;move&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;value&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  val &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;ptr&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;  val &lt;span class=&quot;token function&quot;&gt;take&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; std&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;move&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class=&quot;token keyword&quot;&gt;protected&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token function&quot;&gt;ValPtr&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;val &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;ptr&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;ptr&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ptr&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;br /&gt;  val &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;ptr&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;WebUsbDevicePtr&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token base-clause&quot;&gt;&lt;span class=&quot;token class-name&quot;&gt;ValPtr&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token function&quot;&gt;WebUsbDevicePtr&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;libusb_device &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;dev&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;ValPtr&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token generic-function&quot;&gt;&lt;span class=&quot;token function&quot;&gt;static_cast&lt;/span&gt;&lt;span class=&quot;token generic class-name&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;val &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;usbi_get_device_priv&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;dev&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;val &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;get_web_usb_device&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;libusb_device &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;dev&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;WebUsbDevicePtr&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;dev&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;WebUsbTransferPtr&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token base-clause&quot;&gt;&lt;span class=&quot;token class-name&quot;&gt;ValPtr&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token function&quot;&gt;WebUsbTransferPtr&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;usbi_transfer &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;itransfer&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;ValPtr&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token generic-function&quot;&gt;&lt;span class=&quot;token function&quot;&gt;static_cast&lt;/span&gt;&lt;span class=&quot;token generic class-name&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;val &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;usbi_get_transfer_priv&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;itransfer&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;h3 id=&quot;async-web-apis-in-synchronous-c-contexts&quot;&gt;Async web APIs in synchronous C contexts &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/porting-libusb-to-webusb/#async-web-apis-in-synchronous-c-contexts&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Now needed a way to handle async WebUSB APIs where libusb expects synchronous operations. For this, I could use Asyncify, or, more specifically, its Embind integration via &lt;a href=&quot;https://emscripten.org/docs/api_reference/val.h.html#_CPPv4NK10emscripten10emscripten3val5awaitEv&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;val::await()&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I also wanted to correctly handle WebUSB errors and convert them into libusb error codes, but Embind currently doesn&#39;t have any way to handle JavaScript exceptions or &lt;code&gt;Promise&lt;/code&gt; rejections from the C++ side. This problem can be worked around by catching a rejection on the JavaScript side and converting the result into an &lt;code&gt;{ error, value }&lt;/code&gt; object that can be now safely parsed from the C++ side. I did this with a combination of the &lt;a href=&quot;https://emscripten.org/docs/api_reference/emscripten.h.html#c.EM_JS&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;EM_JS&lt;/code&gt;&lt;/a&gt; macro and &lt;a href=&quot;https://emscripten.org/docs/api_reference/val.h.html#_CPPv4NK10emscripten10emscripten3val9as_handleEv&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;Emval.to{Handle, Value}&lt;/code&gt;&lt;/a&gt; APIs:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token function&quot;&gt;EM_JS&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;EM_VAL&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; em_promise_catch_impl&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;EM_VAL handle&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  let promise &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Emval&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toValue&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;handle&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  promise &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; promise&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;br /&gt;    value &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;error &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; value&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    error &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; ERROR_CODES &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token comment&quot;&gt;// LIBUSB_ERROR_IO&lt;/span&gt;&lt;br /&gt;        NetworkError &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token comment&quot;&gt;// LIBUSB_ERROR_INVALID_PARAM&lt;/span&gt;&lt;br /&gt;        DataError &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;        TypeMismatchError &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;        IndexSizeError &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token comment&quot;&gt;// LIBUSB_ERROR_ACCESS&lt;/span&gt;&lt;br /&gt;        SecurityError &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;        …&lt;br /&gt;      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;      console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;error&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;      let errorCode &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;99&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// LIBUSB_ERROR_OTHER&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;error instanceof DOMException&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        errorCode &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; ERROR_CODES&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;error&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;name&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; errorCode&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;error instanceof RangeError &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; error instanceof TypeError&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        errorCode &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// LIBUSB_ERROR_INVALID_PARAM&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;error&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; errorCode&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; value&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; undefined&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; Emval&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toHandle&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;promise&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;val &lt;span class=&quot;token function&quot;&gt;em_promise_catch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;val &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt;promise&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  EM_VAL handle &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; promise&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;as_handle&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  handle &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;em_promise_catch_impl&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;handle&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; val&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;take_ownership&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;handle&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// C++ struct representation for {value, error} object from above&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// (performs conversion in the constructor).&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;promise_result&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  libusb_error error&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  val value&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token function&quot;&gt;promise_result&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;val &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt;result&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token generic-function&quot;&gt;&lt;span class=&quot;token function&quot;&gt;static_cast&lt;/span&gt;&lt;span class=&quot;token generic class-name&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;libusb_error&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;result&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;error&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token generic-function&quot;&gt;&lt;span class=&quot;token function&quot;&gt;as&lt;/span&gt;&lt;span class=&quot;token generic class-name&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token function&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;result&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;value&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;// C++ counterpart of the promise helper above that takes a promise, catches&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;// its error, converts to a libusb status and returns the whole thing as&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;// `promise_result` struct for easier handling.&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;static&lt;/span&gt; promise_result &lt;span class=&quot;token function&quot;&gt;await&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;val &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt;promise&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    promise &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;em_promise_catch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;std&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;move&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;promise&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;promise&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;await&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Now I could use &lt;code&gt;promise_result::await()&lt;/code&gt; on any &lt;code&gt;Promise&lt;/code&gt; returned from WebUSB operations and inspect its &lt;code&gt;error&lt;/code&gt; and &lt;code&gt;value&lt;/code&gt; fields separately.&lt;/p&gt;
&lt;p&gt;For example, retrieving a &lt;code&gt;val&lt;/code&gt; representing a &lt;a href=&quot;https://developer.mozilla.org/docs/Web/API/USBDevice&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;USBDevice&lt;/code&gt;&lt;/a&gt; from &lt;code&gt;libusb_device_handle&lt;/code&gt;, calling its &lt;a href=&quot;https://developer.mozilla.org/docs/Web/API/USBDevice/open&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;open()&lt;/code&gt;&lt;/a&gt; method, awaiting its result, and returning an error code as a libusb status code looks like this:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;em_open&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;libusb_device_handle &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;handle&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;auto&lt;/span&gt; web_usb_device &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;get_web_usb_device&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;handle&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;dev&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; promise_result&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;await&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;web_usb_device&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token generic-function&quot;&gt;&lt;span class=&quot;token function&quot;&gt;call&lt;/span&gt;&lt;span class=&quot;token generic class-name&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;val&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;open&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;error&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;h3 id=&quot;device-enumeration&quot;&gt;Device enumeration &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/porting-libusb-to-webusb/#device-enumeration&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Of course, before I can open any device, libusb needs to retrieve a list of available devices. The backend must implement this operation via a &lt;code&gt;get_device_list&lt;/code&gt; handler.&lt;/p&gt;
&lt;p&gt;The difficulty is that, unlike on other platforms, there is no way to enumerate all the connected USB devices on the web for security reasons. Instead, the flow is split into two parts. First, the web application requests devices with specific properties via &lt;a href=&quot;https://developer.mozilla.org/docs/Web/API/USB/requestDevice&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;navigator.usb.requestDevice()&lt;/code&gt;&lt;/a&gt; and the user manually chooses which device they want to expose or rejects the permission prompt. Afterwards, the application lists the already approved and connected devices via &lt;a href=&quot;https://developer.mozilla.org/docs/Web/API/USB/getDevices&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;navigator.usb.getDevices()&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;At first I tried to use &lt;code&gt;requestDevice()&lt;/code&gt; directly in the implementation of the &lt;code&gt;get_device_list&lt;/code&gt; handler. However, showing a permission prompt with a list of connected devices is considered a sensitive operation, and it must be triggered by user interaction (like a button click on a page), otherwise it always returns a rejected promise. libusb applications might often want to list the connected devices upon application start-up, so using &lt;code&gt;requestDevice()&lt;/code&gt; was not an option.&lt;/p&gt;
&lt;p&gt;Instead, I had to leave invocation of &lt;code&gt;navigator.usb.requestDevice()&lt;/code&gt; to the end developer, and only expose the already approved devices from &lt;code&gt;navigator.usb.getDevices()&lt;/code&gt;:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// Store the global `navigator.usb` once upon initialisation.&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;thread_local&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; val web_usb &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; val&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;global&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;navigator&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;usb&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;em_get_device_list&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;libusb_context &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;ctx&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; discovered_devs &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;devs&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;// C++ equivalent of `await navigator.usb.getDevices()`.&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;// Note: at this point we must already have some devices exposed -&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;// caller must have called `await navigator.usb.requestDevice(...)`&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;// in response to user interaction before going to LibUSB.&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;// Otherwise this list will be empty.&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;auto&lt;/span&gt; result &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; promise_result&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;await&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;web_usb&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token generic-function&quot;&gt;&lt;span class=&quot;token function&quot;&gt;call&lt;/span&gt;&lt;span class=&quot;token generic class-name&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;val&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;getDevices&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;result&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;error&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; result&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;error&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;web_usb_devices &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; result&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;value&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;// Iterate over the exposed devices.&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;uint8_t&lt;/span&gt; devices_num &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; web_usb_devices&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;length&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token generic-function&quot;&gt;&lt;span class=&quot;token function&quot;&gt;as&lt;/span&gt;&lt;span class=&quot;token generic class-name&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;uint8_t&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;uint8_t&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; devices_num&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; i&lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;auto&lt;/span&gt; web_usb_device &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; web_usb_devices&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// …&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;devs &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;discovered_devs_append&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;devs&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; dev&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; LIBUSB_SUCCESS&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Most of the backend code uses &lt;code&gt;val&lt;/code&gt; and &lt;code&gt;promise_result&lt;/code&gt; in a similar way as already shown above. There are few more interesting hacks in the data transfer handling code, but those implementation details are less important for the purposes of this article. Make sure to check the code and comments on Github if you&#39;re interested.&lt;/p&gt;
&lt;h2 id=&quot;porting-event-loops-to-the-web&quot;&gt;Porting event loops to the web &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/porting-libusb-to-webusb/#porting-event-loops-to-the-web&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;One more piece of the libusb port that I want to discuss is event handling. As described in the previous article, most APIs in system languages like C are synchronous, and event handling is no exception. It&#39;s usually implemented via an infinite loop that &amp;quot;polls&amp;quot; (tries to read data or blocks execution until some data is available) from a set of external I/O sources, and, when at least one of those responds, passes that as an event to the corresponding handler. Once the handler is finished, the control returns to the loop, and it pauses for another poll.&lt;/p&gt;
&lt;p&gt;There are a couple of problems with this approach on the web.&lt;/p&gt;
&lt;p&gt;First, WebUSB doesn&#39;t and cannot expose raw handles of the underlying devices, so polling those directly is not an option. Second, libusb uses &lt;a href=&quot;https://man7.org/linux/man-pages/man2/eventfd.2.html&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;eventfd&lt;/code&gt;&lt;/a&gt; and &lt;a href=&quot;https://man7.org/linux/man-pages/man2/pipe.2.html&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;pipe&lt;/code&gt;&lt;/a&gt; APIs for other events as well as for handling transfers on operating systems without raw device handles, but &lt;code&gt;eventfd&lt;/code&gt; is not currently supported in Emscripten, and &lt;code&gt;pipe&lt;/code&gt;, while supported, &lt;a href=&quot;https://github.com/emscripten-core/emscripten/issues/13214&quot; rel=&quot;noopener&quot;&gt;currently doesn&#39;t conform to the spec&lt;/a&gt; and can&#39;t wait for events.&lt;/p&gt;
&lt;p&gt;Finally, the biggest problem is that the web has its own event loop. This global event loop is used for any external I/O operations (including &lt;code&gt;fetch()&lt;/code&gt;, timers, or, in this case, WebUSB), and it invokes event or &lt;code&gt;Promise&lt;/code&gt; handlers whenever corresponding operations finish. Executing another, nested, infinite event loop will block the browser&#39;s event loop from ever progressing, which means that not only will the UI become unresponsive, but also that the code will never get notifications for the very same I/O events it&#39;s waiting for. This usually results in a deadlock, and that&#39;s what happened when I tried to use libusb in a demo, too. The page froze.&lt;/p&gt;
&lt;p&gt;Like with other blocking I/O, to port such event loops to the web, developers need to find a way to run those loops without blocking the main thread. One way is to refactor the application to handle I/O events in a separate thread and pass the results back to the main one. The other is to use Asyncify to pause the loop and wait for events in a non-blocking fashion.&lt;/p&gt;
&lt;p&gt;I didn&#39;t want to do significant changes to either libusb or gPhoto2, and I&#39;ve already used Asyncify for &lt;code&gt;Promise&lt;/code&gt; integration, so that&#39;s the path I&#39;ve chosen. To simulate a blocking variant of &lt;code&gt;poll()&lt;/code&gt;, for the initial proof of concept I&#39;ve used a loop as shown below:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;ifdef&lt;/span&gt; &lt;span class=&quot;token expression&quot;&gt;__EMSCRIPTEN__&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;// TODO: optimize this. Right now it will keep unwinding-rewinding the stack&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;// on each short sleep until an event comes or the timeout expires.&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;// We should probably create an actual separate thread that does signaling&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;// or come up with a custom event mechanism to report events from&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;// `usbi_signal_event` and process them here.&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;double&lt;/span&gt; until_time &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;emscripten_get_now&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; timeout_ms&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// Emscripten `poll` ignores timeout param, but pass 0 explicitly just&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// in case.&lt;/span&gt;&lt;br /&gt;    num_ready &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;poll&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;fds&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; nfds&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;num_ready &lt;span class=&quot;token operator&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// Yield to the browser event loop to handle events.&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token function&quot;&gt;emscripten_sleep&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;emscripten_get_now&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; until_time&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;else&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  num_ready &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;poll&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;fds&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; nfds&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; timeout_ms&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;endif&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;What it does is:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Calls &lt;code&gt;poll()&lt;/code&gt; to check if any events were reported by the backend yet. If there are some, the loop stops. Otherwise Emscripten&#39;s implementation of &lt;code&gt;poll()&lt;/code&gt; will immediately return with &lt;code&gt;0&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Calls &lt;code&gt;emscripten_sleep(0)&lt;/code&gt;. This function uses Asyncify and &lt;code&gt;setTimeout()&lt;/code&gt; under the hood and is used here to yield control back to the main browser event loop. This allows the browser to handle any user interactions and I/O events, including WebUSB.&lt;/li&gt;
&lt;li&gt;Check if the specified timeout has expired yet, and, if not, continue the loop.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;As the comment mentions, this approach was not optimal, because it kept saving-restoring the entire call stack with Asyncify even when there were no USB events to handle yet (which is most of the time), and because &lt;code&gt;setTimeout()&lt;/code&gt; itself has a minimal duration of 4ms in modern browsers. Still, it worked well enough to produce 13-14 FPS livestream from DSLR in the proof-of-concept.&lt;/p&gt;
&lt;p&gt;Later, I decided to improve it by leveraging the browser event system. There are several ways in which this implementation could be improved further, but for now I&#39;ve chosen to emit custom events directly on the global object, without associating them with a particular libusb data structure. I&#39;ve done so via the following wait and notify mechanism based on the &lt;a href=&quot;https://web.dev/emscripten-embedding-js-snippets/#emasyncjs-macro&quot;&gt;&lt;code&gt;EM_ASYNC_JS&lt;/code&gt; macro&lt;/a&gt;:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token constant&quot;&gt;EM_JS&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; em_libusb_notify&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token function&quot;&gt;dispatchEvent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Event&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;em-libusb&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token constant&quot;&gt;EM_ASYNC_JS&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;int&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; em_libusb_wait&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;int timeout&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; onEvent&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; timeoutId&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;resolve&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token function-variable function&quot;&gt;onEvent&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;resolve&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token function&quot;&gt;addEventListener&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;em-libusb&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; onEvent&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;      timeoutId &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;setTimeout&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;resolve&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; timeout&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;finally&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token function&quot;&gt;removeEventListener&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;em-libusb&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; onEvent&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token function&quot;&gt;clearTimeout&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;timeoutId&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;The &lt;code&gt;em_libusb_notify()&lt;/code&gt; function is used whenever libusb tries to report an event, such as data transfer completion:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;usbi_signal_event&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;usbi_event_t &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;event&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token keyword&quot;&gt;uint64_t&lt;/span&gt; dummy &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  ssize_t r&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  r &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;write&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;EVENT_WRITE_FD&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;event&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;dummy&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;sizeof&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;dummy&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;r &lt;span class=&quot;token operator&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;sizeof&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;dummy&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;    &lt;span class=&quot;token function&quot;&gt;usbi_warn&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;event write failed&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;mark class=&quot;highlight-line highlight-line-active&quot;&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;ifdef&lt;/span&gt; &lt;span class=&quot;token expression&quot;&gt;__EMSCRIPTEN__&lt;/span&gt;&lt;/span&gt;&lt;/mark&gt;&lt;br /&gt;&lt;mark class=&quot;highlight-line highlight-line-active&quot;&gt;  &lt;span class=&quot;token function&quot;&gt;em_libusb_notify&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/mark&gt;&lt;br /&gt;&lt;mark class=&quot;highlight-line highlight-line-active&quot;&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;endif&lt;/span&gt;&lt;/span&gt;&lt;/mark&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Meanwhile, the &lt;code&gt;em_libusb_wait()&lt;/code&gt; part is used to &amp;quot;wake up&amp;quot; from Asyncify sleep when either an &lt;code&gt;em-libusb&lt;/code&gt; event is received, or the timeout has expired:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;double&lt;/span&gt; until_time &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;emscripten_get_now&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; timeout_ms&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token comment&quot;&gt;// Emscripten `poll` ignores timeout param, but pass 0 explicitly just&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token comment&quot;&gt;// in case.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  num_ready &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;poll&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;fds&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; nfds&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;num_ready &lt;span class=&quot;token operator&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; timeout &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; until_time &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;emscripten_get_now&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;timeout &lt;span class=&quot;token operator&quot;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;mark class=&quot;highlight-line highlight-line-active&quot;&gt;  &lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; result &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;em_libusb_wait&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;timeout&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/mark&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;result &lt;span class=&quot;token operator&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Due to significant reduction in sleeps and wake-ups, this mechanism fixed the efficiency problems of the earlier &lt;code&gt;emscripten_sleep()&lt;/code&gt;-based implementation, and increased the DSLR demo throughput from 13-14 FPS to consistent 30+ FPS, which is enough for a smooth live feed.&lt;/p&gt;
&lt;h2 id=&quot;build-system-and-the-first-test&quot;&gt;Build system and the first test &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/porting-libusb-to-webusb/#build-system-and-the-first-test&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;After the backend was done, I had to add it to &lt;code&gt;Makefile.am&lt;/code&gt; and &lt;code&gt;configure.ac&lt;/code&gt;. The only interesting bit here is Emscripten-specific flags modification:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;emscripten&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;  AC_SUBST&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;EXEEXT, &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;.html&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;# Note: LT_LDFLAGS is not enough here because we need link flags for executable.&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token assign-left variable&quot;&gt;AM_LDFLAGS&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&lt;span class=&quot;token variable&quot;&gt;${AM_LDFLAGS}&lt;/span&gt; --bind -s ASYNCIFY -s ASSERTIONS -s ALLOW_MEMORY_GROWTH -s INVOKE_RUN=0 -s EXPORTED_RUNTIME_METHODS=[&#39;callMain&#39;]&quot;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;First, executables on Unix platforms normally don&#39;t have file extensions. Emscripten, however, produces different output depending on which extension you request. I&#39;m using &lt;code&gt;AC_SUBST(EXEEXT, …)&lt;/code&gt; to change the executable extension to &lt;code&gt;.html&lt;/code&gt; so that any executable within a package—tests and examples—becomes an HTML with Emscripten&#39;s default shell that takes care of loading and instantiating JavaScript and WebAssembly.&lt;/p&gt;
&lt;p&gt;Second, because I&#39;m using Embind and Asyncify, I need to enable those features (&lt;code&gt;--bind -s ASYNCIFY&lt;/code&gt;) as well as allow dynamic memory growth (&lt;code&gt;-s ALLOW_MEMORY_GROWTH&lt;/code&gt;) via linker parameters. Unfortunately, there is no way for a library to report those flags to the linker, so every application that uses this libusb port will have to add the same linker flags into their build configuration as well.&lt;/p&gt;
&lt;p&gt;Finally, as mentioned earlier, WebUSB requires device enumeration to be done via a user gesture. libusb examples and tests assume that they can enumerate devices at start-up, and fail with an error without changes. Instead, I had to disable automatic execution (&lt;code&gt;-s INVOKE_RUN=0&lt;/code&gt;) and expose the manual &lt;code&gt;callMain()&lt;/code&gt; method (&lt;code&gt;-s EXPORTED_RUNTIME_METHODS=...&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;Once all of this was done, I could serve the generated files with a static web server, initialize WebUSB, and run those HTML executables manually with the help of DevTools.&lt;/p&gt;
&lt;img alt=&quot;Screenshot showing a Chrome window with DevTools open on a locally served &amp;#x60;testlibusb&amp;#x60; page. DevTools console is evaluating &amp;#x60;navigator.usb.requestDevice({ filters: [] })&amp;#x60;, which triggered a permission prompt and it&amp;#x27;s currently asking the user to choose a USB device that should be shared with the page. ILCE-6600 (a Sony camera) is currently selected.&quot; decoding=&quot;async&quot; height=&quot;626&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/i6dUiRRDtb0ucKX9gHOH.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/i6dUiRRDtb0ucKX9gHOH.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/i6dUiRRDtb0ucKX9gHOH.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/i6dUiRRDtb0ucKX9gHOH.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/i6dUiRRDtb0ucKX9gHOH.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/i6dUiRRDtb0ucKX9gHOH.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/i6dUiRRDtb0ucKX9gHOH.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/i6dUiRRDtb0ucKX9gHOH.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/i6dUiRRDtb0ucKX9gHOH.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/i6dUiRRDtb0ucKX9gHOH.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/i6dUiRRDtb0ucKX9gHOH.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/i6dUiRRDtb0ucKX9gHOH.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/i6dUiRRDtb0ucKX9gHOH.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/i6dUiRRDtb0ucKX9gHOH.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/i6dUiRRDtb0ucKX9gHOH.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/i6dUiRRDtb0ucKX9gHOH.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/i6dUiRRDtb0ucKX9gHOH.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/i6dUiRRDtb0ucKX9gHOH.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;img alt=&quot;Screenshot of the next step, with DevTools still open. After the device was selected, Console has evaluated a new expression &amp;#x60;Module.callMain([&amp;#x27;-v&amp;#x27;])&amp;#x60;, which executed the &amp;#x60;testlibusb&amp;#x60; app in verbose mode. The output shows various detailed information about the previously connected USB camera: manufacturer Sony, product ILCE-6600, serial number, configuration etc.&quot; decoding=&quot;async&quot; height=&quot;824&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/0FhFjozbwA1sqk1Dhx7f.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/0FhFjozbwA1sqk1Dhx7f.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/0FhFjozbwA1sqk1Dhx7f.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/0FhFjozbwA1sqk1Dhx7f.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/0FhFjozbwA1sqk1Dhx7f.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/0FhFjozbwA1sqk1Dhx7f.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/0FhFjozbwA1sqk1Dhx7f.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/0FhFjozbwA1sqk1Dhx7f.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/0FhFjozbwA1sqk1Dhx7f.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/0FhFjozbwA1sqk1Dhx7f.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/0FhFjozbwA1sqk1Dhx7f.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/0FhFjozbwA1sqk1Dhx7f.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/0FhFjozbwA1sqk1Dhx7f.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/0FhFjozbwA1sqk1Dhx7f.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/0FhFjozbwA1sqk1Dhx7f.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/0FhFjozbwA1sqk1Dhx7f.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/0FhFjozbwA1sqk1Dhx7f.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/0FhFjozbwA1sqk1Dhx7f.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;It doesn&#39;t look like much, but, when porting libraries to a new platform, getting to the stage where it produces a valid output for the first time is pretty exciting!&lt;/p&gt;
&lt;h2 id=&quot;using-the-port&quot;&gt;Using the port &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/porting-libusb-to-webusb/#using-the-port&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;As mentioned &lt;a href=&quot;https://web.dev/porting-libusb-to-webusb/#build-system-and-the-first-test&quot;&gt;above&lt;/a&gt;, the port depends on a few Emscripten features that currently need to be enabled at the linking stage of the application. If you want to use this libusb port in your own application, here&#39;s what you&#39;ll need to do:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Download the latest &lt;a href=&quot;https://github.com/libusb/libusb&quot; rel=&quot;noopener&quot;&gt;libusb&lt;/a&gt; either as an archive as part of your build or add it as a git submodule in your project.&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;autoreconf -fiv&lt;/code&gt; in the &lt;code&gt;libusb&lt;/code&gt; folder.&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;emconfigure ./configure –host=wasm32 –prefix=/some/installation/path&lt;/code&gt; to initialize the project for cross-compilation and to set a path where you want to put the built artifacts.&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;emmake make install&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Point your application or higher-level library to search for the libusb under the earlier chosen path.&lt;/li&gt;
&lt;li&gt;Add the following flags to your application&#39;s link arguments: &lt;code&gt;--bind -s ASYNCIFY -s ALLOW_MEMORY_GROWTH&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The library currently has a few limitations:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;No transfer cancellation support. This is a limitation of WebUSB, which, in turn, stems from lack of cross-platform transfer cancellation in libusb itself.&lt;/li&gt;
&lt;li&gt;No isochronous transfer support. It shouldn&#39;t be hard to add it by following the implementation of existing transfer modes as examples, but it&#39;s also a somewhat rare mode and I didn&#39;t have any devices to test it on, so for now I left it as unsupported. If you do have such devices, and want to contribute to the library, PRs are welcome!&lt;/li&gt;
&lt;li&gt;The &lt;a href=&quot;https://web.dev/porting-libusb-to-webusb/#important-cross-platform-compatibility-notes&quot;&gt;earlier mentioned cross-platform limitations&lt;/a&gt;. Those limitations are imposed by operating systems, so not much we can do here, except ask users to override the driver or permissions. However, if you&#39;re porting HID or serial devices, you can follow the libusb example and port some other library to another Fugu API. For example, you could port a C library &lt;a href=&quot;https://github.com/libusb/hidapi&quot; rel=&quot;noopener&quot;&gt;hidapi&lt;/a&gt; to &lt;a href=&quot;https://web.dev/hid/&quot;&gt;WebHID&lt;/a&gt; and side-step those issues, associated with low-level USB access, altogether.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/porting-libusb-to-webusb/#conclusion&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In this post I&#39;ve shown how, with the help of Emscripten, Asyncify and Fugu APIs even low-level libraries like libusb can be ported to the web with a few integration tricks.&lt;/p&gt;
&lt;p&gt;Porting such essential and widely used low-level libraries is particularly rewarding, because, in turn, it allows bringing higher-level libraries or even whole applications to the web, too. This opens experiences that were previously limited to users of one or two platforms, to all kinds of devices and operating systems, making those experiences available just a link click away.&lt;/p&gt;
&lt;p&gt;In the &lt;a href=&quot;https://web.dev/porting-gphoto2-to-the-web&quot;&gt;next post&lt;/a&gt; I&#39;ll walk through the steps involved in building the web gPhoto2 demo which not only retrieves device information, but extensively uses the transfer feature of libusb too. Meanwhile, I hope you found the libusb example inspiring and will try out the demo, play with the library itself, or perhaps even go ahead and port another widely used library to one of the Fugu APIs too.&lt;/p&gt;
</content>
    <author>
      <name>Ingvar Stepanyan</name>
    </author>
  </entry>
  
  <entry>
    <title>Embedding JavaScript snippets in C++ with Emscripten</title>
    <link href="https://web.dev/emscripten-embedding-js-snippets/"/>
    <updated>2022-01-18T00:00:00Z</updated>
    <id>https://web.dev/emscripten-embedding-js-snippets/</id>
    <content type="html" mode="escaped">&lt;p&gt;When working on WebAssembly integration with the web, you need a way to call out to external APIs such as web APIs and third-party libraries. You then need a way to store the values and object instances those APIs return, and a way to pass those stored values to other APIs later. For asynchronous APIs, you might also need to await promises in your synchronous C/C++ code with &lt;a href=&quot;https://web.dev/asyncify/&quot;&gt;Asyncify&lt;/a&gt; and read the result once the operation is finished.&lt;/p&gt;
&lt;p&gt;Emscripten provides several tools for such interactions:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;emscripten::val&lt;/code&gt; for storing and operating on JavaScript values in C++.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;EM_JS&lt;/code&gt; for embedding JavaScript snippets and binding them as C/C++ functions.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;EM_ASYNC_JS&lt;/code&gt; that&#39;s similar to &lt;code&gt;EM_JS&lt;/code&gt;, but makes it easier to embed asynchronous JavaScript snippets.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;EM_ASM&lt;/code&gt; for embedding short snippets and executing them inline, without declaring a function.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--js-library&lt;/code&gt; for advanced scenarios where you want to declare lots of JavaScript functions together as a single library.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In this post you’ll learn how to use all of them for similar tasks.&lt;/p&gt;
&lt;h2 id=&quot;emscriptenval-class&quot;&gt;emscripten::val class &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/emscripten-embedding-js-snippets/#emscriptenval-class&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;emcripten::val&lt;/code&gt; class is provided by Embind. It can invoke global APIs, bind JavaScript values to C++ instances, and convert values between C++ and JavaScript types.&lt;/p&gt;
&lt;p&gt;Here&#39;s how to use it with Asyncify&#39;s &lt;a href=&quot;https://emscripten.org/docs/api_reference/val.h.html#_CPPv4NK10emscripten10emscripten3val5awaitEv&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;.await()&lt;/code&gt;&lt;/a&gt; to fetch and parse some JSON:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&amp;lt;emscripten/val.h&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;using&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;namespace&lt;/span&gt; emscripten&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;val &lt;span class=&quot;token function&quot;&gt;fetch_json&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;url&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;// Get and cache a binding to the global `fetch` API in each thread.&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;thread_local&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; val fetch &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; val&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;global&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;fetch&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;// Invoke fetch and await the returned `Promise&amp;lt;Response&gt;`.&lt;/span&gt;&lt;br /&gt;  val response &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fetch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;url&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;await&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;// Ask to read the response body as JSON and await the returned `Promise&amp;lt;any&gt;`.&lt;/span&gt;&lt;br /&gt;  val json &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; response&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token generic-function&quot;&gt;&lt;span class=&quot;token function&quot;&gt;call&lt;/span&gt;&lt;span class=&quot;token generic class-name&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;val&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;json&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;await&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;// Return the JSON object.&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; json&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// Example URL.&lt;/span&gt;&lt;br /&gt;val example_json &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fetch_json&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;https://httpbin.org/json&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// Now we can extract fields, e.g.&lt;/span&gt;&lt;br /&gt;std&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;string author &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; json&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;slideshow&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;author&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token generic-function&quot;&gt;&lt;span class=&quot;token function&quot;&gt;as&lt;/span&gt;&lt;span class=&quot;token generic class-name&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;std&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;string&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;This code works well, but it performs lots of intermediate steps. Each operation on &lt;code&gt;val&lt;/code&gt; needs to perform the following steps:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Convert C++ values passed as arguments into some intermediate format.&lt;/li&gt;
&lt;li&gt;Go to JavaScript, read and convert arguments into JavaScript values.&lt;/li&gt;
&lt;li&gt;Execute the function&lt;/li&gt;
&lt;li&gt;Convert the result from JavaScript to intermediate format.&lt;/li&gt;
&lt;li&gt;Return the converted result to C++, and C++ finally reads it back.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Each &lt;code&gt;await()&lt;/code&gt; also has to pause the C++ side by unwinding the entire call stack of the WebAssembly module, returning to JavaScript, waiting, and restoring the WebAssembly stack when the operation is complete.&lt;/p&gt;
&lt;p&gt;Such code doesn&#39;t need anything from C++. C++ code is acting only as a driver for a series of JavaScript operations. What if you could move &lt;code&gt;fetch_json&lt;/code&gt; to JavaScript and reduce the overhead of intermediate steps at the same time?&lt;/p&gt;
&lt;h2 id=&quot;emjs-macro&quot;&gt;EM_JS macro &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/emscripten-embedding-js-snippets/#emjs-macro&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The &lt;a href=&quot;https://emscripten.org/docs/api_reference/emscripten.h.html#c.EM_JS&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;EM_JS macro&lt;/code&gt;&lt;/a&gt; lets you move &lt;code&gt;fetch_json&lt;/code&gt; to JavaScript. &lt;code&gt;EM_JS&lt;/code&gt; in Emscripten lets you declare a C/C++ function that is implemented by a JavaScript snippet.&lt;/p&gt;
&lt;p&gt;Like WebAssembly itself, it has a limitation of supporting only numeric arguments and return values. In order to pass any other values, you need to convert them manually via corresponding APIs. Here are some examples.&lt;/p&gt;
&lt;p&gt;Passing numbers doesn&#39;t need any conversion:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// Passing numbers, doesn&#39;t need any conversion.&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token function&quot;&gt;EM_JS&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; add_one&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; x&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; x &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; x &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;add_one&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;41&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;When passing strings to and from JavaScript you need to use the corresponding conversion and allocation functions from &lt;a href=&quot;https://emscripten.org/docs/api_reference/preamble.js.html&quot; rel=&quot;noopener&quot;&gt;preamble.js&lt;/a&gt;:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token function&quot;&gt;EM_JS&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; log_string&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;UTF8ToString&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token function&quot;&gt;EM_JS&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; get_input&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  let str &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getElementById&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token char&quot;&gt;&#39;myinput&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;value&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;// Returns heap-allocated string.&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;// C/C++ code is responsible for calling `free` once unused.&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;allocate&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;intArrayFromString&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;str&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token char&quot;&gt;&#39;i8&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; ALLOC_NORMAL&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Finally, for more complex, arbitrary, value types, you can use the JavaScript API for the earlier mentioned &lt;code&gt;val&lt;/code&gt; class. Using it, you can convert JavaScript values and C++ classes into intermediate handles and back:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token function&quot;&gt;EM_JS&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; log_value&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;EM_VAL val_handle&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  let value &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Emval&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toValue&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;val_handle&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;value&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token function&quot;&gt;EM_JS&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;EM_VAL&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; find_myinput&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  let input &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getElementById&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token char&quot;&gt;&#39;myinput&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; Emval&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toHandle&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;input&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;val obj &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; val&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;object&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;obj&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;x&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;obj&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;y&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token function&quot;&gt;log_value&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;obj&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;as_handle&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// logs { x: 1, y: 2 }&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;val myinput &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; val&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;take_ownership&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;find_input&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// Now you can store the `find_myinput` DOM element for as long as you like, and access it later like:&lt;/span&gt;&lt;br /&gt;std&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;string value &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; input&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;value&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token generic-function&quot;&gt;&lt;span class=&quot;token function&quot;&gt;as&lt;/span&gt;&lt;span class=&quot;token generic class-name&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;std&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;string&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;With those APIs in mind, the &lt;code&gt;fetch_json&lt;/code&gt; example could be rewritten to do most work without leaving JavaScript:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token function&quot;&gt;EM_JS&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;EM_VAL&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; fetch_json&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;url&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; Asyncify&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;handleAsync&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    url &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;UTF8ToString&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;url&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// Invoke fetch and await the returned `Promise&amp;lt;Response&gt;`.&lt;/span&gt;&lt;br /&gt;    let response &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; await &lt;span class=&quot;token function&quot;&gt;fetch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;url&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// Ask to read the response body as JSON and await the returned `Promise&amp;lt;any&gt;`.&lt;/span&gt;&lt;br /&gt;    let json &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; await response&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;json&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// Convert JSON into a handle and return it.&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; Emval&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toHandle&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;json&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// Example URL.&lt;/span&gt;&lt;br /&gt;val example_json &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; val&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;take_ownership&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;fetch_json&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;https://httpbin.org/json&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// Now we can extract fields, e.g.&lt;/span&gt;&lt;br /&gt;std&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;string author &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; json&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;slideshow&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;author&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token generic-function&quot;&gt;&lt;span class=&quot;token function&quot;&gt;as&lt;/span&gt;&lt;span class=&quot;token generic class-name&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;std&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;string&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;We still have a couple of explicit conversions at the entry and exit points of the function, but the rest is now regular JavaScript code. Unlike &lt;code&gt;val&lt;/code&gt; equivalent, it can now be optimized by the JavaScript engine and only requires pausing the C++ side once for all async operations.&lt;/p&gt;
&lt;h2 id=&quot;emasyncjs-macro&quot;&gt;EM_ASYNC_JS macro &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/emscripten-embedding-js-snippets/#emasyncjs-macro&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The only bit left that does not look pretty is the &lt;code&gt;Asyncify.handleAsync&lt;/code&gt; wrapper—its only purpose is to allow executing &lt;code&gt;async&lt;/code&gt; JavaScript functions with Asyncify. In fact, this use case is so common that there is now a specialized &lt;code&gt;EM_ASYNC_JS&lt;/code&gt; macro that combines them together.&lt;/p&gt;
&lt;p&gt;Here&#39;s how you could use it to produce the final version of the &lt;code&gt;fetch&lt;/code&gt; example:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token function&quot;&gt;EM_ASYNC_JS&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;EM_VAL&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; fetch_json&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;url&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  url &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;UTF8ToString&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;url&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;// Invoke fetch and await the returned `Promise&amp;lt;Response&gt;`.&lt;/span&gt;&lt;br /&gt;  let response &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; await &lt;span class=&quot;token function&quot;&gt;fetch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;url&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;// Ask to read the response body as JSON and await the returned `Promise&amp;lt;any&gt;`.&lt;/span&gt;&lt;br /&gt;  let json &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; await response&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;json&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;// Convert JSON into a handle and return it.&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; Emval&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toHandle&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;json&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// Example URL.&lt;/span&gt;&lt;br /&gt;val example_json &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; val&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;take_ownership&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;fetch_json&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;https://httpbin.org/json&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// Now we can extract fields, e.g.&lt;/span&gt;&lt;br /&gt;std&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;string author &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; json&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;slideshow&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;author&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token generic-function&quot;&gt;&lt;span class=&quot;token function&quot;&gt;as&lt;/span&gt;&lt;span class=&quot;token generic class-name&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;std&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;string&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;h2 id=&quot;emasm&quot;&gt;EM_ASM &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/emscripten-embedding-js-snippets/#emasm&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;EM_JS&lt;/code&gt; is the recommended way to declare JavaScript snippets. It&#39;s efficient because it binds the declared snippets directly like any other JavaScript function imports. It also provides good ergonomics by enabling you to explicitly declare all parameter types and names.&lt;/p&gt;
&lt;p&gt;In some cases, however, you want to insert a quick snippet for &lt;a href=&quot;https://developer.mozilla.org/docs/Web/API/Console/log&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;console.log&lt;/code&gt;&lt;/a&gt; call, a &lt;a href=&quot;https://developer.mozilla.org/docs/Web/JavaScript/Reference/Statements/debugger&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;debugger;&lt;/code&gt;&lt;/a&gt; statement or something similar and don&#39;t want to bother with declaring a whole separate function. In those rare cases, an &lt;a href=&quot;https://emscripten.org/docs/api_reference/emscripten.h.html#c.EM_ASM&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;EM_ASM macros family&lt;/code&gt;&lt;/a&gt; (&lt;code&gt;EM_ASM&lt;/code&gt;, &lt;code&gt;EM_ASM_INT&lt;/code&gt; and &lt;code&gt;EM_ASM_DOUBLE&lt;/code&gt;) might be a simpler choice. Those macros are similar to the &lt;code&gt;EM_JS&lt;/code&gt; macro, but they execute code inline where they&#39;re inserted, instead of defining a function.&lt;/p&gt;
&lt;p&gt;Since they don&#39;t declare a function prototype, they need a different way of specifying the return type and accessing arguments.&lt;/p&gt;
&lt;p&gt;You need to use the right macro name to choose the return type. &lt;code&gt;EM_ASM&lt;/code&gt; blocks are expected to act like &lt;code&gt;void&lt;/code&gt; functions, &lt;code&gt;EM_ASM_INT&lt;/code&gt; blocks can return an integer value, and &lt;code&gt;EM_ASM_DOUBLE&lt;/code&gt; blocks return floating-point numbers correspondingly.&lt;/p&gt;
&lt;p&gt;Any passed arguments will be available under names &lt;code&gt;$0&lt;/code&gt;, &lt;code&gt;$1&lt;/code&gt;, and so on in the JavaScript body. As with &lt;code&gt;EM_JS&lt;/code&gt; or WebAssembly in general, the arguments are limited only to numeric values—integers, floating-point numbers, pointers and handles.&lt;/p&gt;
&lt;p&gt;Here&#39;s an example of how you could use an &lt;code&gt;EM_ASM&lt;/code&gt; macro to log an arbitrary JS value to the console:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;val obj &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; val&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;object&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;obj&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;x&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;obj&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;y&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// executes inline immediately&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token function&quot;&gt;EM_ASM&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;// convert handle passed under $0 into a JavaScript value&lt;/span&gt;&lt;br /&gt;  let obj &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Emval&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;fromHandle&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;$&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;obj&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// logs { x: 1, y: 2 }&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; obj&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;as_handle&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;h2 id=&quot;js-library&quot;&gt;--js-library &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/emscripten-embedding-js-snippets/#js-library&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Finally, Emscripten supports declaring JavaScript code in a separate file in a customits own &lt;a href=&quot;https://emscripten.org/docs/porting/connecting_cpp_and_javascript/Interacting-with-code.html#implement-a-c-api-in-javascript&quot; rel=&quot;noopener&quot;&gt;library format&lt;/a&gt;:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token function&quot;&gt;mergeInto&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;LibraryManager&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;library&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token function-variable function&quot;&gt;log_value&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;val_handle&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; value &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Emval&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toValue&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;val_handle&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;value&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Then you need to declare corresponding prototypes manually on the C++ side:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;extern&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;C&quot;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;log_value&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;EM_VAL val_handle&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Once declared on both sides, the JavaScript library can be linked together with the main code via the &lt;a href=&quot;https://emscripten.org/docs/tools_reference/emcc.html#emcc-js-library&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;--js-library option&lt;/code&gt;&lt;/a&gt;, connecting prototypes with corresponding JavaScript implementations.&lt;/p&gt;
&lt;p&gt;However, this module format is non-standard and requires careful dependency annotations. As such, it&#39;s mostly reserved for advanced scenarios.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/emscripten-embedding-js-snippets/#conclusion&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In this post we&#39;ve looked at various ways to integrate JavaScript code into C++ when working with WebAssembly.&lt;/p&gt;
&lt;p&gt;Including such snippets allows you to express long sequences of operations in a cleaner and more efficient way, and to tap into third-party libraries, new JavaScript APIs, and even JavaScript syntax features that are not yet expressible via C++ or Embind.&lt;/p&gt;
</content>
    <author>
      <name>Ingvar Stepanyan</name>
    </author>
  </entry>
  
  <entry>
    <title>Bundling non-JavaScript resources</title>
    <link href="https://web.dev/bundling-non-js-resources/"/>
    <updated>2021-09-08T00:00:00Z</updated>
    <id>https://web.dev/bundling-non-js-resources/</id>
    <content type="html" mode="escaped">&lt;p&gt;Suppose you&#39;re working on a web app. In that case, it&#39;s likely that you have to deal not only with JavaScript modules, but also with all sorts of other resources—Web Workers (which are also JavaScript, but not part of the regular module graph), images, stylesheets, fonts, WebAssembly modules and others.&lt;/p&gt;
&lt;p&gt;It&#39;s possible to include references to some of those resources directly in the HTML, but often they&#39;re logically coupled to reusable components. For example, a stylesheet for a custom dropdown tied to its JavaScript part, icon images tied to a toolbar component, or WebAssembly module tied to its JavaScript glue. In those cases, it&#39;s more convenient to reference the resources directly from their JavaScript modules and load them dynamically when (or if) the corresponding component is loaded.&lt;/p&gt;
&lt;img alt=&quot;Graph visualising various types of asssets imported into JS.&quot; decoding=&quot;async&quot; height=&quot;496&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/QBZDTToXECua2ixAZf9U.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/QBZDTToXECua2ixAZf9U.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/QBZDTToXECua2ixAZf9U.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/QBZDTToXECua2ixAZf9U.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/QBZDTToXECua2ixAZf9U.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/QBZDTToXECua2ixAZf9U.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/QBZDTToXECua2ixAZf9U.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/QBZDTToXECua2ixAZf9U.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/QBZDTToXECua2ixAZf9U.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/QBZDTToXECua2ixAZf9U.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/QBZDTToXECua2ixAZf9U.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/QBZDTToXECua2ixAZf9U.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/QBZDTToXECua2ixAZf9U.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/QBZDTToXECua2ixAZf9U.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/QBZDTToXECua2ixAZf9U.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/QBZDTToXECua2ixAZf9U.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/QBZDTToXECua2ixAZf9U.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/QBZDTToXECua2ixAZf9U.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;However, most large projects have build systems that perform additional optimizations and reorganization of content—for example, bundling and minification. They can&#39;t execute the code and predict what the result of execution will be, nor can they traverse every possible string literal in JavaScript and make guesses about whether it&#39;s a resource URL or not. So how can you make them &amp;quot;see&amp;quot; those dynamic assets loaded by JavaScript components, and include them in the build?&lt;/p&gt;
&lt;h3 id=&quot;custom-imports-in-bundlers&quot;&gt;Custom imports in bundlers &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/bundling-non-js-resources/#custom-imports-in-bundlers&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;One common approach is to reuse the static import syntax. In some bundlers it might auto-detect format by the file extension, while others allow plugins to use a custom URL scheme like in the following example:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// regular JavaScript import&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; loadImg &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;./utils.js&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// special &quot;URL imports&quot; for assets&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; imageUrl &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;asset-url:./image.png&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; wasmUrl &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;asset-url:./module.wasm&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; workerUrl &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;js-url:./worker.js&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token function&quot;&gt;loadImg&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;imageUrl&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;WebAssembly&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;instantiateStreaming&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;fetch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;wasmUrl&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Worker&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;workerUrl&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;When a bundler plugin finds an import with either an extension it recognizes or such an explicit custom scheme (&lt;code&gt;asset-url:&lt;/code&gt; and &lt;code&gt;js-url:&lt;/code&gt; in the example above), it adds the referenced asset to the build graph, copies it to the final destination, performs optimizations applicable for the asset&#39;s type and returns the final URL to be used during runtime.&lt;/p&gt;
&lt;p&gt;The benefits of this approach: reusing the JavaScript import syntax guarantees that all URLs are static and relative to the current file, which makes locating such dependencies easy for the build system.&lt;/p&gt;
&lt;p&gt;However, it has one significant drawback: such code can&#39;t work directly in the browser, as the browser doesn&#39;t know how to handle those custom import schemes or extensions. This might be fine if you control all the code and rely on a bundler for development anyway, but it&#39;s increasingly common to use JavaScript modules directly in the browser, at least during development, to reduce the friction. Someone working on a small demo might not even need a bundler at all, even in production.&lt;/p&gt;
&lt;h3 id=&quot;universal-pattern-for-browsers-and-bundlers&quot;&gt;Universal pattern for browsers and bundlers &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/bundling-non-js-resources/#universal-pattern-for-browsers-and-bundlers&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;If you&#39;re working on a reusable component, you&#39;d want it to function in either environment, whether it&#39;s used directly in the browser or pre-built as part of a larger app. Most modern bundlers allow for this by accepting the following pattern in JavaScript modules:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;URL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;./relative-path&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;meta&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;url&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;This pattern can be detected statically by tools, almost as if it was a special syntax, yet it&#39;s a valid JavaScript expression that works directly in the browser, too.&lt;/p&gt;
&lt;p&gt;When using this pattern, the example above can be rewritten as:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// regular JavaScript import&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; loadImg &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;./utils.js&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token function&quot;&gt;loadImg&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;URL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;./image.png&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;meta&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;url&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;WebAssembly&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;instantiateStreaming&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token function&quot;&gt;fetch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;URL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;./module.wasm&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;meta&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;url&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;/* … */&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Worker&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;URL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;./worker.js&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;meta&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;url&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;How does it work? Let&#39;s break it up. The &lt;code&gt;new URL(...)&lt;/code&gt; constructor takes a relative URL as the first argument and resolves it against an absolute URL provided as the second argument. In our case, the second argument is &lt;a href=&quot;https://v8.dev/features/modules#import-meta&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;import.meta.url&lt;/code&gt;&lt;/a&gt; which gives the URL of the current JavaScript module, so the first argument can be any path relative to it.&lt;/p&gt;
&lt;p&gt;It has similar tradeoffs to the &lt;a href=&quot;https://v8.dev/features/dynamic-import&quot; rel=&quot;noopener&quot;&gt;dynamic import&lt;/a&gt;. While it&#39;s possible to use &lt;code&gt;import(...)&lt;/code&gt; with arbitrary expressions like &lt;code&gt;import(someUrl)&lt;/code&gt;, the bundlers give special treatment to a pattern with static URL &lt;code&gt;import(&#39;./some-static-url.js&#39;)&lt;/code&gt; as a way to preprocess a dependency known at compile-time, yet &lt;a href=&quot;https://web.dev/reduce-javascript-payloads-with-code-splitting/&quot;&gt;split it out into its own chunk&lt;/a&gt; that&#39;s loaded dynamically.&lt;/p&gt;
&lt;p&gt;Similarly, you can use &lt;code&gt;new URL(...)&lt;/code&gt; with arbitrary expressions like &lt;code&gt;new URL(relativeUrl, customAbsoluteBase)&lt;/code&gt;, yet the &lt;code&gt;new URL(&#39;...&#39;, import.meta.url)&lt;/code&gt; pattern is a clear signal for bundlers to preprocess and include a dependency alongside the main JavaScript.&lt;/p&gt;
&lt;h3 id=&quot;ambiguous-relative-urls&quot;&gt;Ambiguous relative URLs &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/bundling-non-js-resources/#ambiguous-relative-urls&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;You might be wondering, why can&#39;t bundlers detect other common patterns—for example, &lt;code&gt;fetch(&#39;./module.wasm&#39;)&lt;/code&gt; without the &lt;code&gt;new URL&lt;/code&gt; wrappers?&lt;/p&gt;
&lt;p&gt;The reason is that, unlike import statements, any dynamic requests are resolved relatively to the document itself, and not to the current JavaScript file. Let&#39;s say you have the following structure:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;index.html&lt;/code&gt;:&lt;div&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;script&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;src/main.js&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;module&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token script&quot;&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;src/&lt;/code&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;main.js&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;module.wasm&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you want to load &lt;code&gt;module.wasm&lt;/code&gt; from &lt;code&gt;main.js&lt;/code&gt;, it might be tempting to use a relative path like &lt;code&gt;fetch(&#39;./module.wasm&#39;)&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;However, &lt;code&gt;fetch&lt;/code&gt; does not know the URL of the JavaScript file it&#39;s executed in, instead, it resolves URLs relatively to the document. As a result, &lt;code&gt;fetch(&#39;./module.wasm&#39;)&lt;/code&gt; would end up trying to load &lt;code&gt;http://example.com/module.wasm&lt;/code&gt; instead of the intended &lt;code&gt;http://example.com/src/module.wasm&lt;/code&gt; and fail (or, worse, silently load a different resource than you intended).&lt;/p&gt;
&lt;p&gt;By wrapping the relative URL into &lt;code&gt;new URL(&#39;...&#39;, import.meta.url)&lt;/code&gt; you can avoid this problem and guarantee that any provided URL is resolved relative to the URL of the current JavaScript module (&lt;code&gt;import.meta.url&lt;/code&gt;) before it&#39;s passed on to any loaders.&lt;/p&gt;
&lt;p&gt;Replace &lt;code&gt;fetch(&#39;./module.wasm&#39;)&lt;/code&gt; with &lt;code&gt;fetch(new URL(&#39;./module.wasm&#39;, import.meta.url))&lt;/code&gt; and it will successfully load the expected WebAssembly module, as well as give bundlers a way to find those relative paths during the build time too.&lt;/p&gt;
&lt;h3 id=&quot;tooling-support&quot;&gt;Tooling support &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/bundling-non-js-resources/#tooling-support&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;h4 id=&quot;bundlers&quot;&gt;Bundlers &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/bundling-non-js-resources/#bundlers&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Following bundlers support the &lt;code&gt;new URL&lt;/code&gt; scheme already:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://webpack.js.org/guides/asset-modules/#url-assets&quot; rel=&quot;noopener&quot;&gt;Webpack v5&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://rollupjs.org/&quot; rel=&quot;noopener&quot;&gt;Rollup&lt;/a&gt; (Achieved via plugins—&lt;a href=&quot;https://modern-web.dev/docs/building/rollup-plugin-import-meta-assets/&quot; rel=&quot;noopener&quot;&gt;@web/rollup-plugin-import-meta-assets&lt;/a&gt; for generic assets and &lt;a href=&quot;https://github.com/surma/rollup-plugin-off-main-thread&quot; rel=&quot;noopener&quot;&gt;@surma/rollup-plugin-off-main-thread&lt;/a&gt; for Workers specifically.)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://v2.parceljs.org/languages/javascript/#url-dependencies&quot; rel=&quot;noopener&quot;&gt;Parcel v2 (beta)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://vitejs.dev/guide/assets.html#new-url-url-import-meta-url&quot; rel=&quot;noopener&quot;&gt;Vite&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;webassembly&quot;&gt;WebAssembly &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/bundling-non-js-resources/#webassembly&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;When working with WebAssembly, you will commonly not load the Wasm module by hand, but instead import the JavaScript glue emitted by the toolchain. The following toolchains can emit the described &lt;code&gt;new URL(...)&lt;/code&gt; pattern under the hood for you.&lt;/p&gt;
&lt;h5 id=&quot;cc-via-emscripten&quot;&gt;C/C++ via Emscripten &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/bundling-non-js-resources/#cc-via-emscripten&quot;&gt;#&lt;/a&gt;&lt;/h5&gt;
&lt;p&gt;When using Emscripten, you can ask it to emit JavaScript glue as an ES6 module instead of a regular script via one of the following options:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;$ emcc input.cpp -o output.mjs&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;## or, if you don&#39;t want to use .mjs extension&lt;/span&gt;&lt;br /&gt;$ emcc input.cpp -o output.js -s EXPORT_ES6&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;When using this option, the output will use the &lt;code&gt;new URL(..., import.meta.url)&lt;/code&gt; pattern under the hood, so that bundlers can find the associated Wasm file automatically.&lt;/p&gt;
&lt;p&gt;You can also use this option with &lt;a href=&quot;https://web.dev/webassembly-threads/#c&quot;&gt;WebAssembly threads&lt;/a&gt; by adding a &lt;code&gt;-pthread&lt;/code&gt; flag:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;$ emcc input.cpp -o output.mjs -pthread&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;## or, if you don&#39;t want to use .mjs extension&lt;/span&gt;&lt;br /&gt;$ emcc input.cpp -o output.js -s EXPORT_ES6 -pthread&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;In this case, the generated Web Worker will be included in the same fashion and will also be discoverable by bundlers and browsers alike.&lt;/p&gt;
&lt;h5 id=&quot;rust-via-wasm-pack-wasm-bindgen&quot;&gt;Rust via wasm-pack / wasm-bindgen &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/bundling-non-js-resources/#rust-via-wasm-pack-wasm-bindgen&quot;&gt;#&lt;/a&gt;&lt;/h5&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/rustwasm/wasm-pack&quot; rel=&quot;noopener&quot;&gt;wasm-pack&lt;/a&gt;—the primary Rust toolchain for WebAssembly—also has several output modes.&lt;/p&gt;
&lt;p&gt;By default, it will emit a JavaScript module that relies on the &lt;a href=&quot;https://github.com/WebAssembly/esm-integration&quot; rel=&quot;noopener&quot;&gt;WebAssembly ESM integration proposal&lt;/a&gt;. At the moment of writing, this proposal is still experimental, and the output will work only when bundled with Webpack.&lt;/p&gt;
&lt;p&gt;Instead, you can ask wasm-pack to emit a browser-compatible ES6 module via &lt;code&gt;--target web&lt;/code&gt;:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;$ wasm-pack build --target web&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;The output will use the described &lt;code&gt;new URL(..., import.meta.url)&lt;/code&gt; pattern, and the Wasm file will be automatically discovered by bundlers as well.&lt;/p&gt;
&lt;p&gt;If you want to use WebAssembly threads with Rust, the story is a bit more complicated. Check out the &lt;a href=&quot;https://web.dev/webassembly-threads/#rust&quot;&gt;corresponding section of the guide&lt;/a&gt; to learn more.&lt;/p&gt;
&lt;p&gt;Short version is that you can&#39;t use arbitrary thread APIs, but if you use &lt;a href=&quot;https://github.com/rayon-rs/rayon&quot; rel=&quot;noopener&quot;&gt;Rayon&lt;/a&gt;, you can combine it with the &lt;a href=&quot;https://github.com/GoogleChromeLabs/wasm-bindgen-rayon&quot; rel=&quot;noopener&quot;&gt;wasm-bindgen-rayon&lt;/a&gt; adapter so that it can spawn Workers on the Web. The JavaScript glue used by wasm-bindgen-rayon &lt;a href=&quot;https://github.com/GoogleChromeLabs/wasm-bindgen-rayon/blob/4cd0666d2089886d6e8731de2371e7210f848c5d/demo/index.js#L26&quot; rel=&quot;noopener&quot;&gt;also includes&lt;/a&gt; the &lt;code&gt;new URL(...)&lt;/code&gt; pattern under the hood, and so the Workers will be discoverable and included by bundlers as well.&lt;/p&gt;
&lt;h2 id=&quot;future-features&quot;&gt;Future features &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/bundling-non-js-resources/#future-features&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;importmetaresolve&quot;&gt;import.meta.resolve &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/bundling-non-js-resources/#importmetaresolve&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;A dedicated &lt;code&gt;import.meta.resolve(...)&lt;/code&gt; call is a potential future improvement. It would allow resolving specifiers relatively to the current module in a more straightforward fashion, without extra params:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;del class=&quot;highlight-line highlight-line-remove&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;URL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;...&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;meta&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;url&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/del&gt;&lt;br /&gt;&lt;ins class=&quot;highlight-line highlight-line-add&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;meta&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;resolve&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;...&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/ins&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;It would also integrate better with import maps and custom resolvers as it would go through the same module resolution system as &lt;code&gt;import&lt;/code&gt;. It would be a stronger signal for bundlers too as it&#39;s a static syntax that doesn&#39;t depend on runtime APIs like &lt;code&gt;URL&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;import.meta.resolve&lt;/code&gt; is already implemented &lt;a href=&quot;https://nodejs.org/api/esm.html#esm_import_meta_resolve_specifier_parent&quot; rel=&quot;noopener&quot;&gt;as an experiment in Node.js&lt;/a&gt; but there are still some &lt;a href=&quot;https://github.com/WICG/import-maps/issues/79&quot; rel=&quot;noopener&quot;&gt;unresolved questions&lt;/a&gt; about how it should work on the web.&lt;/p&gt;
&lt;h3 id=&quot;import-assertions&quot;&gt;Import assertions &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/bundling-non-js-resources/#import-assertions&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Import assertions are a new feature that allows to import types other than ECMAScript modules. For now they&#39;re limited to JSON:&lt;/p&gt;
&lt;p class=&quot;label&quot;&gt;foo.json:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;&quot;answer&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;42&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p class=&quot;label&quot;&gt;main.mjs:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; json &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;./foo.json&#39;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;assert&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;json&#39;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;json&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;answer&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// 42&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;They might also be used by bundlers and replace the use-cases currently covered by the &lt;code&gt;new URL&lt;/code&gt; pattern, but types in import assertions are added on a per-case basis. For now they only cover JSON, with CSS modules coming up soon, but other kinds of assets will still require a more generic solution.&lt;/p&gt;
&lt;p&gt;Check out the &lt;a href=&quot;https://v8.dev/features/import-assertions&quot; rel=&quot;noopener&quot;&gt;v8.dev feature explainer&lt;/a&gt; to learn more about this feature.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/bundling-non-js-resources/#conclusion&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;As you can see, there are various ways to include non-JavaScript resources on the web, but they have various drawbacks and don&#39;t work across various toolchains. Future proposals might let us import such assets with specialized syntax, but we&#39;re not quite there yet.&lt;/p&gt;
&lt;p&gt;Until then, the &lt;code&gt;new URL(..., import.meta.url)&lt;/code&gt; pattern is the most promising solution that already works in browsers, various bundlers and WebAssembly toolchains today.&lt;/p&gt;
</content>
    <author>
      <name>Ingvar Stepanyan</name>
    </author>
  </entry>
  
  <entry>
    <title>Using WebAssembly threads from C, C++ and Rust</title>
    <link href="https://web.dev/webassembly-threads/"/>
    <updated>2021-07-12T00:00:00Z</updated>
    <id>https://web.dev/webassembly-threads/</id>
    <content type="html" mode="escaped">&lt;p&gt;WebAssembly threads support is one of the most important performance additions to WebAssembly. It
allows you to either run parts of your code in parallel on separate cores, or the same code over
independent parts of the input data, scaling it to as many cores as the user has and significantly
reducing the overall execution time.&lt;/p&gt;
&lt;p&gt;In this article you will learn how to use WebAssembly threads to bring multithreaded applications
written in languages like C, C++, and Rust to the web.&lt;/p&gt;
&lt;h2 id=&quot;how-webassembly-threads-work&quot;&gt;How WebAssembly threads work &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/webassembly-threads/#how-webassembly-threads-work&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;WebAssembly threads is not a separate feature, but a combination of several components that allows
WebAssembly apps to use traditional multithreading paradigms on the web.&lt;/p&gt;
&lt;h3 id=&quot;web-workers&quot;&gt;Web Workers &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/webassembly-threads/#web-workers&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;First component is the regular
&lt;a href=&quot;https://developer.mozilla.org/docs/Web/API/Web_Workers_API/Using_web_workers&quot; rel=&quot;noopener&quot;&gt;Workers&lt;/a&gt; you know and
love from JavaScript. WebAssembly threads use the &lt;code&gt;new Worker&lt;/code&gt; constructor to create new underlying
threads. Each thread loads a JavaScript glue, and then the main thread uses
&lt;a href=&quot;https://developer.mozilla.org/docs/Web/API/Worker/postMessage&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;Worker#postMessage&lt;/code&gt;&lt;/a&gt; method to
share the compiled
&lt;a href=&quot;https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/Module&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;WebAssembly.Module&lt;/code&gt;&lt;/a&gt;
as well as a shared
&lt;a href=&quot;https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/Memory&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;WebAssembly.Memory&lt;/code&gt;&lt;/a&gt;
(see below) with those other threads. This establishes communication and allows all those threads to
run the same WebAssembly code on the same shared memory without going through JavaScript again.&lt;/p&gt;
&lt;p&gt;Web Workers have been around for over a decade now, are widely supported, and don&#39;t require any
special flags.&lt;/p&gt;
&lt;h3 id=&quot;sharedarraybuffer&quot;&gt;&lt;code&gt;SharedArrayBuffer&lt;/code&gt; &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/webassembly-threads/#sharedarraybuffer&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;WebAssembly memory is represented by a
&lt;a href=&quot;https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/Memory&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;WebAssembly.Memory&lt;/code&gt;&lt;/a&gt;
object in the JavaScript API. By default &lt;code&gt;WebAssembly.Memory&lt;/code&gt; is a wrapper around an
&lt;a href=&quot;https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;ArrayBuffer&lt;/code&gt;&lt;/a&gt;—a
raw byte buffer that can be accessed only by a single thread.&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;WebAssembly&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Memory&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;initial&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;maximum&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;buffer&lt;br /&gt;ArrayBuffer &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; … &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;To support multithreading, &lt;code&gt;WebAssembly.Memory&lt;/code&gt; gained a shared variant too. When created with a
&lt;code&gt;shared&lt;/code&gt; flag via the JavaScript API, or by the WebAssembly binary itself, it becomes a wrapper
around a
&lt;a href=&quot;https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/SharedArrayBuffer&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;SharedArrayBuffer&lt;/code&gt;&lt;/a&gt;
instead. It&#39;s a variation of &lt;code&gt;ArrayBuffer&lt;/code&gt; that can be shared with other threads and read or
modified simultaneously from either side.&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;WebAssembly&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Memory&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;initial&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;maximum&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;shared&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;buffer&lt;br /&gt;SharedArrayBuffer &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; … &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Unlike &lt;a href=&quot;https://developer.mozilla.org/docs/Web/API/Worker/postMessage&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;postMessage&lt;/code&gt;&lt;/a&gt;, normally used
for communication between main thread and Web Workers,
&lt;a href=&quot;https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/SharedArrayBuffer&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;SharedArrayBuffer&lt;/code&gt;&lt;/a&gt;
doesn&#39;t require copying data or even waiting for the event loop to send and receive messages.
Instead, any changes are seen by all threads nearly instantly, which makes it a much better
compilation target for traditional synchronisation primitives.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;SharedArrayBuffer&lt;/code&gt; has a complicated history. It was initially shipped in several browsers
mid-2017, but had to be disabled in the beginning of 2018 due to discovery of &lt;a href=&quot;https://developer.chrome.com/blog/meltdown-spectre/&quot; rel=&quot;noopener&quot;&gt;Spectre
vulnerabilities&lt;/a&gt;. The particular
reason was that data extraction in Spectre relies on timing attacks—measuring execution time of a
particular piece of code. To make this kind of attack harder, browsers reduced precision of standard
timing APIs like &lt;code&gt;Date.now&lt;/code&gt; and &lt;code&gt;performance.now&lt;/code&gt;. However, shared memory, combined with a simple
counter loop running in a separate thread &lt;a href=&quot;https://github.com/tc39/security/issues/3&quot; rel=&quot;noopener&quot;&gt;is also a very reliable way to get high-precision
timing&lt;/a&gt;, and it&#39;s much harder to mitigate without
significantly throttling runtime performance.&lt;/p&gt;
&lt;p&gt;Instead, Chrome 68 (mid-2018) re-enabled &lt;code&gt;SharedArrayBuffer&lt;/code&gt; again by leveraging &lt;a href=&quot;https://developer.chrome.com/blog/site-isolation&quot; rel=&quot;noopener&quot;&gt;Site
Isolation&lt;/a&gt;—a feature that puts
different websites into different processes and makes it much more difficult to use side-channel
attacks like Spectre. However, this mitigation was still limited only to Chrome desktop, as Site
Isolation is a fairly expensive feature, and couldn&#39;t be enabled by default for all sites on
low-memory mobile devices nor was it yet implemented by other vendors.&lt;/p&gt;
&lt;p&gt;Fast-forward to 2020, Chrome and Firefox both have implementations of Site Isolation, and a standard
way for websites to opt-in to the feature with &lt;a href=&quot;https://web.dev/coop-coep/&quot;&gt;COOP and COEP headers&lt;/a&gt;. An opt-in
mechanism allows to use Site Isolation even on low-powered devices where enabling it for all the
websites would be too expensive. To opt-in, add the following headers to the main document in your
server configuration:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-http&quot;&gt;&lt;code class=&quot;language-http&quot;&gt;&lt;span class=&quot;token header&quot;&gt;&lt;span class=&quot;token header-name keyword&quot;&gt;Cross-Origin-Embedder-Policy&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token header-value&quot;&gt;require-corp&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token header&quot;&gt;&lt;span class=&quot;token header-name keyword&quot;&gt;Cross-Origin-Opener-Policy&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token header-value&quot;&gt;same-origin&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Once you opt-in, you get access to &lt;code&gt;SharedArrayBuffer&lt;/code&gt; (including &lt;code&gt;WebAssembly.Memory&lt;/code&gt; backed by a
&lt;code&gt;SharedArrayBuffer&lt;/code&gt;), precise timers, memory measurement and other APIs that require an isolated
origin for security reasons. Check out the &lt;a href=&quot;https://web.dev/coop-coep/&quot;&gt;Making your website &amp;quot;cross-origin isolated&amp;quot; using COOP
and COEP&lt;/a&gt; for more details.&lt;/p&gt;
&lt;h3 id=&quot;webassembly-atomics&quot;&gt;WebAssembly atomics &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/webassembly-threads/#webassembly-atomics&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;While &lt;code&gt;SharedArrayBuffer&lt;/code&gt; allows each thread to read and write to the same memory, for correct
communication you want to make sure they don&#39;t perform conflicting operations at the same time. For example, it&#39;s
possible for one thread to start reading data from a shared address, while another thread is writing
to it, so the first thread will now get a corrupted result. This category of bugs is known as race
conditions. In order to prevent race conditions, you need to somehow synchronize those accesses.
This is where atomic operations come in.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://webassembly.github.io/threads/core/syntax/instructions.html#atomic-memory-instructions&quot; rel=&quot;noopener&quot;&gt;WebAssembly
atomics&lt;/a&gt;
is an extension to the WebAssembly instruction set that allow to read and write small cells of data
(usually 32- and 64-bit integers) &amp;quot;atomically&amp;quot;. That is, in a way that guarantees that no two
threads are reading or writing to the same cell at the same time, preventing such conflicts at a low
level. Additionally, WebAssembly atomics contain two more instruction kinds—&amp;quot;wait&amp;quot; and &amp;quot;notify&amp;quot;—that
allow one thread to sleep (&amp;quot;wait&amp;quot;) on a given address in a shared memory until another thread wakes
it up via &amp;quot;notify&amp;quot;.&lt;/p&gt;
&lt;p&gt;All the higher-level synchronisation primitives, including channels, mutexes, and read-write locks
build upon those instructions.&lt;/p&gt;
&lt;h2 id=&quot;how-to-use-webassembly-threads&quot;&gt;How to use WebAssembly threads &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/webassembly-threads/#how-to-use-webassembly-threads&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;feature-detection&quot;&gt;Feature detection &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/webassembly-threads/#feature-detection&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;WebAssembly atomics and &lt;code&gt;SharedArrayBuffer&lt;/code&gt; are relatively new features and aren&#39;t yet available in
all browsers with WebAssembly support. You can find which browsers support new WebAssembly features
on the &lt;a href=&quot;https://webassembly.org/roadmap/&quot; rel=&quot;noopener&quot;&gt;webassembly.org roadmap&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;To ensure that all users can load your application, you&#39;ll need to implement progressive enhancement
by building two different versions of Wasm—one with multithreading support and one without it. Then
load the supported version depending on feature detection results. To detect WebAssembly threads
support at runtime, use &lt;a href=&quot;https://github.com/GoogleChromeLabs/wasm-feature-detect&quot; rel=&quot;noopener&quot;&gt;wasm-feature-detect
library&lt;/a&gt; and load the module like this:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; threads &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;wasm-feature-detect&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; hasThreads &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;threads&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; module &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;br /&gt;  hasThreads&lt;br /&gt;    &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;./module-with-threads.js&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;./module-without-threads.js&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// …now use `module` as you normally would&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Now let&#39;s take a look at how to build a multithreaded version of the WebAssembly module.&lt;/p&gt;
&lt;h3 id=&quot;c&quot;&gt;C &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/webassembly-threads/#c&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;In C, particularly on Unix-like systems, the common way to use threads is via &lt;a href=&quot;https://en.wikipedia.org/wiki/POSIX_Threads&quot; rel=&quot;noopener&quot;&gt;POSIX
Threads&lt;/a&gt; provided by the &lt;code&gt;pthread&lt;/code&gt; library. Emscripten
&lt;a href=&quot;https://emscripten.org/docs/porting/pthreads.html&quot; rel=&quot;noopener&quot;&gt;provides an API-compatible implementation&lt;/a&gt; of
the &lt;code&gt;pthread&lt;/code&gt; library built atop Web Workers, shared memory and atomics, so that the same code can
work on the web without changes.&lt;/p&gt;
&lt;p&gt;Let&#39;s take a look at an example:&lt;/p&gt;
&lt;p class=&quot;label&quot;&gt;example.c:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-c&quot;&gt;&lt;code class=&quot;language-c&quot;&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&amp;lt;stdio.h&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&amp;lt;unistd.h&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;mark class=&quot;highlight-line highlight-line-active&quot;&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&amp;lt;pthread.h&gt;&lt;/span&gt;&lt;/span&gt;&lt;/mark&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;thread_callback&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;arg&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;    &lt;span class=&quot;token function&quot;&gt;sleep&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;    &lt;span class=&quot;token function&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Inside the thread: %d\n&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;arg&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;    &lt;span class=&quot;token function&quot;&gt;puts&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Before the thread&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;    &lt;span class=&quot;token class-name&quot;&gt;pthread_t&lt;/span&gt; thread_id&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;    &lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; arg &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;42&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;mark class=&quot;highlight-line highlight-line-active&quot;&gt;    &lt;span class=&quot;token function&quot;&gt;pthread_create&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;thread_id&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; thread_callback&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;arg&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/mark&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;mark class=&quot;highlight-line highlight-line-active&quot;&gt;    &lt;span class=&quot;token function&quot;&gt;pthread_join&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;thread_id&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/mark&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;    &lt;span class=&quot;token function&quot;&gt;puts&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;After the thread&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Here the headers for the &lt;code&gt;pthread&lt;/code&gt; library are included via &lt;code&gt;pthread.h&lt;/code&gt;. You can also see a couple
of crucial functions for dealing with threads.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://man7.org/linux/man-pages/man3/pthread_create.3.html&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;pthread_create&lt;/code&gt;&lt;/a&gt; will create a
background thread. It takes a destination to store a thread handle in, some thread creation
attributes (here not passing any, so it&#39;s just &lt;code&gt;NULL&lt;/code&gt;), the callback to be executed in the new
thread (here &lt;code&gt;thread_callback&lt;/code&gt;), and an optional argument pointer to pass to that callback in case
you want to share some data from the main thread—in this example we&#39;re sharing a pointer to a
variable &lt;code&gt;arg&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://man7.org/linux/man-pages/man3/pthread_join.3.html&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;pthread_join&lt;/code&gt;&lt;/a&gt; can be called later at
any time to wait for the thread to finish the execution, and get the result returned from the
callback. It accepts the earlier assigned thread handle as well as a pointer to store the result. In
this case, there aren&#39;t any results so the function takes a &lt;code&gt;NULL&lt;/code&gt; as an argument.&lt;/p&gt;
&lt;p&gt;To compile code using threads with Emscripten, you need to invoke &lt;code&gt;emcc&lt;/code&gt; and pass a &lt;code&gt;-pthread&lt;/code&gt;
parameter, as when compiling the same code with Clang or GCC on other platforms:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;emcc -pthread example.c -o example.js&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;However, when you try to run it in a browser or Node.js, you&#39;ll see a warning and then the program
will hang:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;Before the thread&lt;br /&gt;Tried to spawn a new thread, but the thread pool is exhausted.&lt;br /&gt;This might result in a deadlock unless some threads eventually exit or the code&lt;br /&gt;explicitly breaks out to the event loop.&lt;br /&gt;If you want to increase the pool size, use setting `-s PTHREAD_POOL_SIZE=...`.&lt;br /&gt;If you want to throw an explicit error instead of the risk of deadlocking in those&lt;br /&gt;cases, use setting `-s PTHREAD_POOL_SIZE_STRICT=2`.&lt;br /&gt;[…hangs here…]&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;What happened? The problem is, most of the time-consuming APIs on the web are asynchronous and rely
on the event loop to execute. This limitation is an important distinction compared to traditional
environments, where applications normally run I/O in synchronous, blocking manner. Check out the
blog post about &lt;a href=&quot;https://web.dev/asyncify/&quot;&gt;Using asynchronous web APIs from WebAssembly&lt;/a&gt; if you&#39;d like to learn
more.&lt;/p&gt;
&lt;p&gt;In this case, the code synchronously invokes &lt;code&gt;pthread_create&lt;/code&gt; to create a background thread, and
follows up by another synchronous call to &lt;code&gt;pthread_join&lt;/code&gt; that waits for the background thread to
finish execution. However, Web Workers, that are used behind the scenes when this code is compiled
with Emscripten, are asynchronous. So what happens is, &lt;code&gt;pthread_create&lt;/code&gt; only &lt;em&gt;schedules&lt;/em&gt; a new
Worker thread to be created on the next event loop run, but then &lt;code&gt;pthread_join&lt;/code&gt; immediately blocks
the event loop to wait for that Worker, and by doing so prevents it from ever being created. It&#39;s a
classic example of a &lt;a href=&quot;https://en.wikipedia.org/wiki/Deadlock&quot; rel=&quot;noopener&quot;&gt;deadlock&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;One way to solve this problem is to create a pool of Workers ahead of time, before the program has
even started. When &lt;code&gt;pthread_create&lt;/code&gt; is invoked, it can take a ready-to-use Worker from the pool, run
the provided callback on its background thread, and return the Worker back to the pool. All of this
can be done synchronously, so there won&#39;t be any deadlocks as long as the pool is sufficiently
large.&lt;/p&gt;
&lt;p&gt;This is exactly what Emscripten allows with the &lt;a href=&quot;https://emsettings.surma.technology/#PTHREAD_POOL_SIZE&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;-s PTHREAD_POOL_SIZE=...&lt;/code&gt;&lt;/a&gt; option. It allows to
specify a number of threads—either a fixed number, or a JavaScript expression like
&lt;a href=&quot;https://developer.mozilla.org/docs/Web/API/NavigatorConcurrentHardware/hardwareConcurrency&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;navigator.hardwareConcurrency&lt;/code&gt;&lt;/a&gt;
to create as many threads as there are cores on the CPU. The latter option is helpful when your code
can scale to an arbitrary number of threads.&lt;/p&gt;
&lt;p&gt;In the example above, there is only one thread being created, so instead of reserving all cores it&#39;s
sufficient to use &lt;code&gt;-s PTHREAD_POOL_SIZE=1&lt;/code&gt;:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;emcc -pthread -s &lt;span class=&quot;token assign-left variable&quot;&gt;PTHREAD_POOL_SIZE&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt; example.c -o example.js&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;This time, when you execute it, things work successfully:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;Before the thread&lt;br /&gt;Inside the thread: 42&lt;br /&gt;After the thread&lt;br /&gt;Pthread 0x701510 exited.&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;There is another problem though: see that &lt;code&gt;sleep(1)&lt;/code&gt; in the code example? It executes in the thread
callback, meaning off the main thread, so it should be fine, right? Well, it isn&#39;t.&lt;/p&gt;
&lt;p&gt;When &lt;code&gt;pthread_join&lt;/code&gt; is called, it has to wait for the thread execution to finish, meaning that if
the created thread is performing long-running tasks—in this case, sleeping 1 second—then the main
thread will also have to block for the same amount of time till the results are back. When this JS
is executed in the browser, it will block the UI thread for 1 second until the thread callback
returns. This leads to poor user experience.&lt;/p&gt;
&lt;p&gt;There are few solutions to this:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;pthread_detach&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-s PROXY_TO_PTHREAD&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Custom Worker and Comlink&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;pthreaddetach&quot;&gt;pthread_detach &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/webassembly-threads/#pthreaddetach&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;First, if you only need to run some tasks off the main thread, but don&#39;t need to wait for the
results, you can use &lt;a href=&quot;https://man7.org/linux/man-pages/man3/pthread_detach.3.html&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;pthread_detach&lt;/code&gt;&lt;/a&gt;
instead of &lt;code&gt;pthread_join&lt;/code&gt;. This will leave the thread callback running in the background. If you&#39;re
using this option, you can switch off the warning with &lt;a href=&quot;https://emsettings.surma.technology/#PTHREAD_POOL_SIZE_STRICT&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;-s PTHREAD_POOL_SIZE_STRICT=0&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;h4 id=&quot;proxytopthread&quot;&gt;PROXY_TO_PTHREAD &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/webassembly-threads/#proxytopthread&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Second, if you&#39;re compiling a C application rather than a library, you can use &lt;a href=&quot;https://emsettings.surma.technology/#PROXY_TO_PTHREAD&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;-s PROXY_TO_PTHREAD&lt;/code&gt;&lt;/a&gt; option, which will offload
the main application code to a separate thread in addition to any nested threads created by the
application itself. This way, main code can block safely at any time without freezing the UI.
Incidentally, when using this option, you don&#39;t have to precreate the thread pool either—instead,
Emscripten can leverage the main thread for creating new underlying Workers, and then block the
helper thread in &lt;code&gt;pthread_join&lt;/code&gt; without deadlocking.&lt;/p&gt;
&lt;h4 id=&quot;comlink&quot;&gt;Comlink &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/webassembly-threads/#comlink&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Third, if you&#39;re working on a library and still need to block, you can create your own Worker,
import the Emscripten-generated code and expose it with
&lt;a href=&quot;https://github.com/GoogleChromeLabs/comlink&quot; rel=&quot;noopener&quot;&gt;Comlink&lt;/a&gt; to the main thread. Main thread will be able
to invoke any exported methods as asynchronous functions, and that way will also avoid blocking the
UI.&lt;/p&gt;
&lt;p&gt;In a simple application such as the previous example &lt;code&gt;-s PROXY_TO_PTHREAD&lt;/code&gt; is the best option:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;emcc -pthread -s PROXY_TO_PTHREAD example.c -o example.js&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;h3 id=&quot;c-2&quot;&gt;C++ &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/webassembly-threads/#c-2&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;All the same caveats and logic apply in the same way to C++. The only new thing you gain is access
to higher-level APIs like &lt;a href=&quot;https://en.cppreference.com/w/cpp/thread/thread&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;std::thread&lt;/code&gt;&lt;/a&gt; and
&lt;a href=&quot;https://en.cppreference.com/w/cpp/thread/async&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;std::async&lt;/code&gt;&lt;/a&gt;, which use the previously discussed
&lt;code&gt;pthread&lt;/code&gt; library under the hood.&lt;/p&gt;
&lt;p&gt;So the example above can be rewritten in more idiomatic C++ like this:&lt;/p&gt;
&lt;p class=&quot;label&quot;&gt;example.cpp:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&amp;lt;iostream&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;mark class=&quot;highlight-line highlight-line-active&quot;&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&amp;lt;thread&gt;&lt;/span&gt;&lt;/span&gt;&lt;/mark&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&amp;lt;chrono&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;    &lt;span class=&quot;token function&quot;&gt;puts&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Before the thread&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;    &lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; arg &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;42&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;mark class=&quot;highlight-line highlight-line-active&quot;&gt;    std&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;thread &lt;span class=&quot;token function&quot;&gt;thread&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;/mark&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;        std&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;this_thread&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;sleep_for&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;std&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;chrono&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;seconds&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;        std&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;cout &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Inside the thread: &quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; arg &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; std&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;endl&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;mark class=&quot;highlight-line highlight-line-active&quot;&gt;    thread&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/mark&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;    std&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;cout &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;After the thread&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; std&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;endl&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;When compiled and executed with similar parameters, it will behave in the same way as the C example:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;emcc -std&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;c++11 -pthread -s PROXY_TO_PTHREAD example.cpp -o example.js&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Output:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;Before the thread&lt;br /&gt;Inside the thread: 42&lt;br /&gt;Pthread 0xc06190 exited.&lt;br /&gt;After the thread&lt;br /&gt;Proxied main thread 0xa05c18 finished with return code 0. EXIT_RUNTIME=0 set, so&lt;br /&gt;keeping main thread alive for asynchronous event operations.&lt;br /&gt;Pthread 0xa05c18 exited.&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;h3 id=&quot;rust&quot;&gt;Rust &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/webassembly-threads/#rust&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Unlike Emscripten, Rust doesn&#39;t have a specialized end-to-end web target, but instead provides a
generic &lt;code&gt;wasm32-unknown-unknown&lt;/code&gt; target for generic WebAssembly output.&lt;/p&gt;
&lt;p&gt;If Wasm is intended to be used in a web environment, any interaction with JavaScript APIs is left to
external libraries and tooling like &lt;a href=&quot;https://rustwasm.github.io/docs/wasm-bindgen/&quot; rel=&quot;noopener&quot;&gt;wasm-bindgen&lt;/a&gt;
and &lt;a href=&quot;https://rustwasm.github.io/docs/wasm-pack/&quot; rel=&quot;noopener&quot;&gt;wasm-pack&lt;/a&gt;. Unfortunately, this means that the
standard library is not aware of Web Workers and standard APIs such as
&lt;a href=&quot;https://doc.rust-lang.org/std/thread/&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;std::thread&lt;/code&gt;&lt;/a&gt; won&#39;t work when compiled to WebAssembly.&lt;/p&gt;
&lt;p&gt;Luckily, the majority of the ecosystem depends on higher-level libraries to take care of
multithreading. At that level it&#39;s much easier to abstract away all the platform differences.&lt;/p&gt;
&lt;p&gt;In particular, &lt;a href=&quot;https://crates.io/crates/rayon&quot; rel=&quot;noopener&quot;&gt;Rayon&lt;/a&gt; is the most popular choice for
data-parallelism in Rust. It allows you to take method chains on regular iterators and, usually with
a single line change, convert them in a way where they&#39;d run in parallel on all available threads
instead of sequentially. For example:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-rust&quot;&gt;&lt;code class=&quot;language-rust&quot;&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;pub&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;token function-definition function&quot;&gt;sum_of_squares&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;numbers&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;i32&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;i32&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  numbers&lt;/span&gt;&lt;br /&gt;&lt;del class=&quot;highlight-line highlight-line-remove&quot;&gt;  &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;iter&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/del&gt;&lt;br /&gt;&lt;ins class=&quot;highlight-line highlight-line-add&quot;&gt;  &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;par_iter&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/ins&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token closure-params&quot;&gt;&lt;span class=&quot;token closure-punctuation punctuation&quot;&gt;|&lt;/span&gt;x&lt;span class=&quot;token closure-punctuation punctuation&quot;&gt;|&lt;/span&gt;&lt;/span&gt; x &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; x&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;sum&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;With this small change, the code will split up the input data, calculate &lt;code&gt;x * x&lt;/code&gt; and partial sums in
parallel threads, and in the end add up those partial results together.&lt;/p&gt;
&lt;p&gt;To accommodate for platforms without working &lt;code&gt;std::thread&lt;/code&gt;, Rayon provides hooks that allow to
define custom logic for spawning and exiting threads.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/GoogleChromeLabs/wasm-bindgen-rayon&quot; rel=&quot;noopener&quot;&gt;wasm-bindgen-rayon&lt;/a&gt; taps into those hooks
to spawn WebAssembly threads as Web Workers. To use it, you need to add it as a dependency and
follow the configuration steps described in the
&lt;a href=&quot;https://github.com/GoogleChromeLabs/wasm-bindgen-rayon#setting-up&quot; rel=&quot;noopener&quot;&gt;docs&lt;/a&gt;. The example above will
end up looking like this:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-rust&quot;&gt;&lt;code class=&quot;language-rust&quot;&gt;&lt;ins class=&quot;highlight-line highlight-line-add&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;pub&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;token namespace&quot;&gt;wasm_bindgen_rayon&lt;span class=&quot;token punctuation&quot;&gt;::&lt;/span&gt;&lt;/span&gt;init_thread_pool&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/ins&gt;&lt;br /&gt;&lt;ins class=&quot;highlight-line highlight-line-add&quot;&gt;&lt;/ins&gt;&lt;br /&gt;&lt;ins class=&quot;highlight-line highlight-line-add&quot;&gt;&lt;span class=&quot;token attribute attr-name&quot;&gt;#[wasm_bindgen]&lt;/span&gt;&lt;/ins&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;pub&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;token function-definition function&quot;&gt;sum_of_squares&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;numbers&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;i32&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;i32&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  numbers&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;par_iter&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token closure-params&quot;&gt;&lt;span class=&quot;token closure-punctuation punctuation&quot;&gt;|&lt;/span&gt;x&lt;span class=&quot;token closure-punctuation punctuation&quot;&gt;|&lt;/span&gt;&lt;/span&gt; x &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; x&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;sum&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Once done, the generated JavaScript will export an extra &lt;code&gt;initThreadPool&lt;/code&gt; function. This function
will create a pool of Workers and reuse them throughout the lifetime of the program for any
multithreaded operations done by Rayon.&lt;/p&gt;
&lt;p&gt;This pool mechanism is similar to the &lt;code&gt;-s PTHREAD_POOL_SIZE=...&lt;/code&gt; option in Emscripten explained
earlier, and also needs to be initialized before the main code to avoid deadlocks:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;mark class=&quot;highlight-line highlight-line-active&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; init&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; initThreadPool&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; sum_of_squares &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;./pkg/index.js&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/mark&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// Regular wasm-bindgen initialization.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;init&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;mark class=&quot;highlight-line highlight-line-active&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// Thread pool initialization with the given number of threads&lt;/span&gt;&lt;/mark&gt;&lt;br /&gt;&lt;mark class=&quot;highlight-line highlight-line-active&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// (pass `navigator.hardwareConcurrency` if you want to use all cores).&lt;/span&gt;&lt;/mark&gt;&lt;br /&gt;&lt;mark class=&quot;highlight-line highlight-line-active&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;initThreadPool&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;navigator&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;hardwareConcurrency&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/mark&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// ...now you can invoke any exported functions as you normally would&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;sum_of_squares&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Int32Array&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// 14&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Note that the same &lt;a href=&quot;https://github.com/GoogleChromeLabs/wasm-bindgen-rayon#caveats&quot; rel=&quot;noopener&quot;&gt;caveats&lt;/a&gt; about
blocking the main thread apply here too. Even the &lt;code&gt;sum_of_squares&lt;/code&gt; example still needs to block the
main thread to wait for the partial results from other threads.&lt;/p&gt;
&lt;p&gt;It might be a very short wait or a long one, depending on the complexity of iterators and number of
available threads, but, to be on the safe side, browser engines actively prevent blocking the main
thread altogether and such code will throw an error. Instead, you should create a Worker, import the
&lt;code&gt;wasm-bindgen&lt;/code&gt;-generated code there, and expose its API with a library like
&lt;a href=&quot;https://github.com/GoogleChromeLabs/comlink&quot; rel=&quot;noopener&quot;&gt;Comlink&lt;/a&gt; to the main thread.&lt;/p&gt;
&lt;p&gt;Check out &lt;a href=&quot;https://github.com/GoogleChromeLabs/wasm-bindgen-rayon/tree/main/demo&quot; rel=&quot;noopener&quot;&gt;the wasm-bindgen-rayon
example&lt;/a&gt; for an end-to-end
demo showing:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/GoogleChromeLabs/wasm-bindgen-rayon/blob/e13485d6d64a062b890f5bb3a842b1fe609eb3c1/demo/wasm-worker.js#L27&quot; rel=&quot;noopener&quot;&gt;Feature detection of
threads.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/GoogleChromeLabs/wasm-bindgen-rayon/blob/e13485d6d64a062b890f5bb3a842b1fe609eb3c1/demo/package.json#L4-L5&quot; rel=&quot;noopener&quot;&gt;Building single- and multi-threaded versions of the same Rust
app.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/GoogleChromeLabs/wasm-bindgen-rayon/blob/e13485d6d64a062b890f5bb3a842b1fe609eb3c1/demo/wasm-worker.js#L28-L31&quot; rel=&quot;noopener&quot;&gt;Loading the JS+Wasm generated by wasm-bindgen in a
Worker.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/GoogleChromeLabs/wasm-bindgen-rayon/blob/e13485d6d64a062b890f5bb3a842b1fe609eb3c1/demo/wasm-worker.js#L32&quot; rel=&quot;noopener&quot;&gt;Using wasm-bindgen-rayon to initialize a thread
pool.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Using Comlink to &lt;a href=&quot;https://github.com/GoogleChromeLabs/wasm-bindgen-rayon/blob/e13485d6d64a062b890f5bb3a842b1fe609eb3c1/demo/wasm-worker.js#L44-L46&quot; rel=&quot;noopener&quot;&gt;expose Worker&#39;s
API&lt;/a&gt;
to &lt;a href=&quot;https://github.com/GoogleChromeLabs/wasm-bindgen-rayon/blob/e13485d6d64a062b890f5bb3a842b1fe609eb3c1/demo/index.js#L25-L29&quot; rel=&quot;noopener&quot;&gt;the main
thread&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;real-world-use-cases&quot;&gt;Real-world use cases &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/webassembly-threads/#real-world-use-cases&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We actively use WebAssembly threads in &lt;a href=&quot;https://squoosh.app/&quot; rel=&quot;noopener&quot;&gt;Squoosh.app&lt;/a&gt; for client-side image
compression—in particular, for formats like AVIF (C++), JPEG-XL (C++), OxiPNG (Rust) and WebP v2
(C++). Thanks to the multithreading alone, we&#39;ve seen consistent 1.5x-3x speed-ups (exact ratio
differs per codec), and were able to push those numbers even further by combining WebAssembly threads
with &lt;a href=&quot;https://v8.dev/features/simd&quot; rel=&quot;noopener&quot;&gt;WebAssembly SIMD&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;Google Earth is another notable service that&#39;s using WebAssembly threads for its &lt;a href=&quot;https://earth.google.com/web/&quot; rel=&quot;noopener&quot;&gt;web
version&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://ffmpegwasm.netlify.app/&quot; rel=&quot;noopener&quot;&gt;FFMPEG.WASM&lt;/a&gt; is a WebAssembly version of a popular
&lt;a href=&quot;https://www.ffmpeg.org/&quot; rel=&quot;noopener&quot;&gt;FFmpeg&lt;/a&gt; multimedia toolchain that uses WebAssembly threads to efficiently
encode videos directly in the browser.&lt;/p&gt;
&lt;p&gt;There are many more exciting examples using WebAssembly threads out there. Be sure to check out
the demos and bring your own multithreaded applications and libraries to the web!&lt;/p&gt;
</content>
    <author>
      <name>Ingvar Stepanyan</name>
    </author>
  </entry>
  
  <entry>
    <title>Using asynchronous web APIs from WebAssembly</title>
    <link href="https://web.dev/asyncify/"/>
    <updated>2021-04-26T00:00:00Z</updated>
    <id>https://web.dev/asyncify/</id>
    <content type="html" mode="escaped">&lt;p&gt;The I/O APIs on the web are asynchronous, but they&#39;re synchronous in most system languages. When
compiling code to WebAssembly, you need to bridge one kind of APIs to another—and this bridge is
Asyncify. In this post, you&#39;ll learn when and how to use Asyncify and how it works under the hood.&lt;/p&gt;
&lt;h2 id=&quot;io-in-system-languages&quot;&gt;I/O in system languages &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/asyncify/#io-in-system-languages&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I&#39;ll start with a simple example in C. Say, you want to read the user&#39;s name from a file, and greet
them with a &amp;quot;Hello, (username)!&amp;quot; message:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&amp;lt;stdio.h&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    FILE &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;stream &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fopen&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;name.txt&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;r&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;char&lt;/span&gt; name&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;20&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    size_t len &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fread&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;name&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;20&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; stream&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    name&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;len&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token char&quot;&gt;&#39;\0&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token function&quot;&gt;fclose&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;stream&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token function&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Hello, %s!\n&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; name&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;While the example doesn&#39;t do much, it already demonstrates something you&#39;ll find in an application
of any size: it reads some inputs from the external world, processes them internally and writes
outputs back to the external world. All such interaction with the outside world happens via a few
functions commonly called input-output functions, also shortened to I/O.&lt;/p&gt;
&lt;p&gt;To read the name from C, you need at least two crucial I/O calls: &lt;code&gt;fopen&lt;/code&gt;, to open the file, and
&lt;code&gt;fread&lt;/code&gt; to read data from it. Once you retrieve the data, you can use another I/O function &lt;code&gt;printf&lt;/code&gt;
to print the result to the console.&lt;/p&gt;
&lt;p&gt;Those functions look quite simple at first glance and you don&#39;t have to think twice about the
machinery involved to read or write data. However, depending on the environment, there can be quite
a lot going on inside:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;If the input file is located on a local drive, the application needs to perform a series of
memory and disk accesses to locate the file, check permissions, open it for reading, and then
read block by block until the requested number of bytes is retrieved. This can be pretty slow,
depending on the speed of your disk and the requested size.&lt;/li&gt;
&lt;li&gt;Or, the input file might be located on a mounted network location, in which case, the network
stack will now be involved too, increasing the complexity, latency and number of potential
retries for each operation.&lt;/li&gt;
&lt;li&gt;Finally, even &lt;code&gt;printf&lt;/code&gt; is not guaranteed to print things to the console and might be redirected
to a file or a network location, in which case it would have to go via the same steps above.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Long story short, I/O can be slow and you can&#39;t predict how long a particular call will take by a
quick glance at the code. While that operation is running, your whole application will appear frozen
and unresponsive to the user.&lt;/p&gt;
&lt;p&gt;This is not limited to C or C++ either. Most system languages present all the I/O in a form of
synchronous APIs. For example, if you translate the example to Rust, the API might look simpler, but
the same principles apply. You just make a call and synchronously wait for it to return the result,
while it performs all the expensive operations and eventually returns the result in a single
invocation:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-rust&quot;&gt;&lt;code class=&quot;language-rust&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;token function-definition function&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; s &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token namespace&quot;&gt;std&lt;span class=&quot;token punctuation&quot;&gt;::&lt;/span&gt;fs&lt;span class=&quot;token punctuation&quot;&gt;::&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;read_to_string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;name.txt&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token macro property&quot;&gt;println!&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Hello, {}!&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; s&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;But what happens when you try to compile any of those samples to WebAssembly and translate them to
the web? Or, to provide a specific example, what could &amp;quot;file read&amp;quot; operation translate to? It would
need to read data from some storage.&lt;/p&gt;
&lt;h2 id=&quot;asynchronous-model-of-the-web&quot;&gt;Asynchronous model of the web &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/asyncify/#asynchronous-model-of-the-web&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The web has a variety of different storage options you could map to, such as in-memory storage (JS
objects), &lt;a href=&quot;https://developer.mozilla.org/docs/Web/API/Window/localStorage&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;localStorage&lt;/code&gt;&lt;/a&gt;,
&lt;a href=&quot;https://developer.mozilla.org/docs/Web/API/IndexedDB_API&quot; rel=&quot;noopener&quot;&gt;IndexedDB&lt;/a&gt;, server-side storage,
and a new &lt;a href=&quot;https://web.dev/file-system-access/&quot;&gt;File System Access API&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;However, only two of those APIs—the in-memory storage and the &lt;code&gt;localStorage&lt;/code&gt;—can be used
synchronously, and both are the most limiting options in what you can store and for how long. All
the other options provide only asynchronous APIs.&lt;/p&gt;
&lt;p&gt;This is one of the core properties of executing code on the web: any time-consuming operation, which
includes any I/O, has to be asynchronous.&lt;/p&gt;
&lt;p&gt;The reason is that the web is historically single-threaded, and any user code that touches the UI
has to run on the same thread as the UI. It has to compete with the other important tasks like
layout, rendering and event handling for the CPU time. You wouldn&#39;t want a piece of JavaScript or
WebAssembly to be able to start a &amp;quot;file read&amp;quot; operation and block everything else—the entire tab,
or, in the past, the entire browser—for a range from milliseconds to a few seconds, until it&#39;s over.&lt;/p&gt;
&lt;p&gt;Instead, code is only allowed to schedule an I/O operation together with a callback to be executed
once it&#39;s finished. Such callbacks are executed as part of the browser&#39;s event loop. I won&#39;t be
going into details here, but if you&#39;re interested in learning how the event loop works under the hood,
check out
&lt;a href=&quot;https://jakearchibald.com/2015/tasks-microtasks-queues-and-schedules/&quot; rel=&quot;noopener&quot;&gt;Tasks, microtasks, queues and schedules&lt;/a&gt;
which explains this topic in-depth.&lt;/p&gt;
&lt;p&gt;The short version is that the browser runs all the pieces of code in sort of an infinite loop, by
taking them from the queue one by one. When some event is triggered, the browser queues the
corresponding handler, and on the next loop iteration it&#39;s taken out from the queue and executed.
This mechanism allows simulating concurrency and running lots of parallel operations while using only
a single thread.&lt;/p&gt;
&lt;p&gt;The important thing to remember about this mechanism is that, while your custom JavaScript (or
WebAssembly) code executes, the event loop is blocked and, while it is, there is no way to react to
any external handlers, events, I/O, etc. The only way to get the I/O results back is to register a
callback, finish executing your code, and give the control back to the browser so that it can keep
processing any pending tasks. Once I/O is finished, your handler will become one of those tasks and
will get executed.&lt;/p&gt;
&lt;p&gt;For example, if you wanted to rewrite the samples above in modern JavaScript and decided to read a
name from a remote URL, you would use Fetch API and async-await syntax:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; response &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fetch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;name.txt&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; name &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; response&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Hello, %s!&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; name&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Even though it looks synchronous, under the hood each &lt;code&gt;await&lt;/code&gt; is essentially syntax sugar for
callbacks:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fetch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;name.txt&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;response&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; response&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Hello, %s!&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; name&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;In this de-sugared example, which is a bit clearer, a request is started and responses are subscribed to with the first callback. Once the browser receives the initial response—just the HTTP
headers—it asynchronously invokes this callback. The callback starts reading the body as text using
&lt;code&gt;response.text()&lt;/code&gt;, and subscribes to the result with another callback. Finally, once &lt;code&gt;fetch&lt;/code&gt; has
retrieved all the contents, it invokes the last callback, which prints &amp;quot;Hello, (username)!&amp;quot; to the
console.&lt;/p&gt;
&lt;p&gt;Thanks to the asynchronous nature of those steps, the original function can return control to the
browser as soon as the I/O has been scheduled, and leave the entire UI responsive and available for
other tasks, including rendering, scrolling and so on, while the I/O is executing in background.&lt;/p&gt;
&lt;p&gt;As a final example, even simple APIs like &amp;quot;sleep&amp;quot;, which makes an application wait a specified
number of seconds, are also a form of an I/O operation:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&amp;lt;stdio.h&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&amp;lt;unistd.h&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// ...&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token function&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;A\n&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token function&quot;&gt;sleep&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token function&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;B\n&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Sure, you could translate it in a very straightforward manner that would block the current thread
until the time expires:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;A&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; start &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Date&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;now&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; Date&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;now&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; start &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;B&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;In fact, that&#39;s exactly what Emscripten does in &lt;a href=&quot;https://github.com/emscripten-core/emscripten/blob/16d5755a3f71f27d0c67b8d7752f94844e56ef7c/src/library_pthread_stub.js#L47-L52&quot; rel=&quot;noopener&quot;&gt;its default implementation of
&amp;quot;sleep&amp;quot;,&lt;/a&gt;
but that&#39;s very inefficient, will block the entire UI and won&#39;t allow any other events to be handled
meanwhile. Generally, don&#39;t do that in production code.&lt;/p&gt;
&lt;p&gt;Instead, a more idiomatic version of &amp;quot;sleep&amp;quot; in JavaScript would involve calling &lt;code&gt;setTimeout()&lt;/code&gt;, and
subscribing with a handler:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;A&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token function&quot;&gt;setTimeout&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;B&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;What&#39;s common to all these examples and APIs? In each case, the idiomatic code in the original
systems language uses a blocking API for the I/O, whereas an equivalent example for the web uses an
asynchronous API instead. When compiling to the web, you need to somehow transform between those two
execution models, and WebAssembly has no built-in ability to do so just yet.&lt;/p&gt;
&lt;h2 id=&quot;bridging-the-gap-with-asyncify&quot;&gt;Bridging the gap with Asyncify &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/asyncify/#bridging-the-gap-with-asyncify&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This is where &lt;a href=&quot;https://emscripten.org/docs/porting/asyncify.html&quot; rel=&quot;noopener&quot;&gt;Asyncify&lt;/a&gt; comes in. Asyncify is a
compile-time feature supported by Emscripten that allows pausing the entire program and
asynchronously resuming it later.&lt;/p&gt;
&lt;img alt=&quot;A call graph describing a JavaScript -&amp;gt; WebAssembly -&amp;gt; web API -&amp;gt; async task invocation, where Asyncify connects the result of the async task back into WebAssembly&quot; decoding=&quot;async&quot; height=&quot;200&quot; loading=&quot;lazy&quot; src=&quot;https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/VSMrdTiQ7PubW6vfE6WZ.svg&quot; width=&quot;800&quot; /&gt;
&lt;h3 id=&quot;usage-in-c-c-with-emscripten&quot;&gt;Usage in C / C++ with Emscripten &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/asyncify/#usage-in-c-c-with-emscripten&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;If you wanted to use Asyncify to implement an asynchronous sleep for the last example, you could do
it like this:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&amp;lt;stdio.h&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&amp;lt;emscripten.h&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token function&quot;&gt;EM_JS&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; async_sleep&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; seconds&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    Asyncify&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;handleSleep&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;wakeUp &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token function&quot;&gt;setTimeout&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;wakeUp&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; seconds &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;…&lt;br /&gt;&lt;span class=&quot;token function&quot;&gt;puts&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;A&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token function&quot;&gt;async_sleep&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token function&quot;&gt;puts&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;B&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;&lt;a href=&quot;https://emscripten.org/docs/api_reference/emscripten.h.html?highlight=em_js#c.EM_JS&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;EM_JS&lt;/code&gt;&lt;/a&gt; is a
macro that allows defining JavaScript snippets as if they were C functions. Inside, use a function
&lt;a href=&quot;https://emscripten.org/docs/porting/asyncify.html#making-async-web-apis-behave-as-if-they-were-synchronous&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;Asyncify.handleSleep()&lt;/code&gt;&lt;/a&gt;
which tells Emscripten to suspend the program and provides a &lt;code&gt;wakeUp()&lt;/code&gt; handler that should be
called once the asynchronous operation has finished. In the example above, the handler is passed to
&lt;code&gt;setTimeout()&lt;/code&gt;, but it could be used in any other context that accepts callbacks. Finally, you can
call &lt;code&gt;async_sleep()&lt;/code&gt; anywhere you want just like regular &lt;code&gt;sleep()&lt;/code&gt; or any other synchronous API.&lt;/p&gt;
&lt;p&gt;When compiling such code, you need to tell Emscripten to activate the Asyncify feature. Do that by
passing &lt;code&gt;-s ASYNCIFY&lt;/code&gt; as well as &lt;a href=&quot;https://emscripten.org/docs/porting/asyncify.html#more-on-asyncify-imports&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;-s ASYNCIFY_IMPORTS=[func1, func2]&lt;/code&gt;&lt;/a&gt; with an
array-like list of functions that might be asynchronous.&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;emcc -O2 &lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;&lt;br /&gt;    -s ASYNCIFY &lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;&lt;br /&gt;    -s &lt;span class=&quot;token assign-left variable&quot;&gt;ASYNCIFY_IMPORTS&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;async_sleep&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;..&lt;/span&gt;.&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;This lets Emscripten know that any calls to those functions might require saving and restoring the
state, so the compiler will inject supporting code around such calls.&lt;/p&gt;
&lt;p&gt;Now, when you execute this code in the browser you&#39;ll see a seamless output log like you&#39;d expect,
with B coming after a short delay after A.&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;A&lt;br /&gt;B&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;You can &lt;a href=&quot;https://emscripten.org/docs/porting/asyncify.html#returning-values&quot; rel=&quot;noopener&quot;&gt;return values from
Asyncify&lt;/a&gt; functions too. What
you need to do is return the result of &lt;code&gt;handleSleep()&lt;/code&gt;, and pass the result to the &lt;code&gt;wakeUp()&lt;/code&gt;
callback. For example, if, instead of reading from a file, you want to fetch a number from a remote
resource, you can use a snippet like the one below to issue a request, suspend the C code, and
resume once the response body is retrieved—all done seamlessly as if the call were synchronous.&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token constant&quot;&gt;EM_JS&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;int&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; get_answer&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;     &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; Asyncify&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;handleSleep&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;wakeUp&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token function&quot;&gt;fetch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;answer.txt&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;response&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; response&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;text&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;wakeUp&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;text&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token function&quot;&gt;puts&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Getting answer...&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;int answer &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;get_answer&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token function&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Answer is %d\n&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; answer&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;In fact, for Promise-based APIs like &lt;code&gt;fetch()&lt;/code&gt;, you can even combine Asyncify with JavaScript&#39;s
async-await feature instead of using the callback-based API. For that, instead of
&lt;code&gt;Asyncify.handleSleep()&lt;/code&gt;, call &lt;code&gt;Asyncify.handleAsync()&lt;/code&gt;. Then, instead of having to schedule a
&lt;code&gt;wakeUp()&lt;/code&gt; callback, you can pass an &lt;code&gt;async&lt;/code&gt; JavaScript function and use &lt;code&gt;await&lt;/code&gt; and &lt;code&gt;return&lt;/code&gt;
inside, making code look even more natural and synchronous, while not losing any of the benefits of
the asynchronous I/O.&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token constant&quot;&gt;EM_JS&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;int&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; get_answer&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;     &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; Asyncify&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;handleAsync&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; response &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fetch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;answer.txt&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; text &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; response&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;Number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;text&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;int answer &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;get_answer&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;h4 id=&quot;awaiting-complex-values&quot;&gt;Awaiting complex values &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/asyncify/#awaiting-complex-values&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;But this example still limits you only to numbers. What if you want to implement the original
example, where I tried to get a user&#39;s name from a file as a string? Well, you can do that too!&lt;/p&gt;
&lt;p&gt;Emscripten provides a feature called
&lt;a href=&quot;https://emscripten.org/docs/porting/connecting_cpp_and_javascript/embind.html&quot; rel=&quot;noopener&quot;&gt;Embind&lt;/a&gt; that allows
you to handle conversions between JavaScript and C++ values. It has support for Asyncify as well, so
you can call &lt;code&gt;await()&lt;/code&gt; on external &lt;code&gt;Promise&lt;/code&gt;s and it will act just like &lt;code&gt;await&lt;/code&gt; in async-await
JavaScript code:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;val fetch &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; val&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;global&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;fetch&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;val response &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fetch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;std&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;answer.txt&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;await&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;val text &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; response&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token generic-function&quot;&gt;&lt;span class=&quot;token function&quot;&gt;call&lt;/span&gt;&lt;span class=&quot;token generic class-name&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;val&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;text&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;await&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;auto&lt;/span&gt; answer &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; text&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token generic-function&quot;&gt;&lt;span class=&quot;token function&quot;&gt;as&lt;/span&gt;&lt;span class=&quot;token generic class-name&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;std&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;string&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;When using this method, you don&#39;t even need to pass &lt;code&gt;ASYNCIFY_IMPORTS&lt;/code&gt; as a compile flag, as it&#39;s
already included by default.&lt;/p&gt;
&lt;p&gt;Okay, so this all works great in Emscripten. What about other toolchains and languages?&lt;/p&gt;
&lt;h3 id=&quot;usage-from-other-languages&quot;&gt;Usage from other languages &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/asyncify/#usage-from-other-languages&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Say that you have a similar synchronous call somewhere in your Rust code that you want to map to an
async API on the web. Turns out, you can do that too!&lt;/p&gt;
&lt;p&gt;First, you need to define such a function as a regular import via &lt;code&gt;extern&lt;/code&gt; block (or your chosen
language&#39;s syntax for foreign functions).&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-rust&quot;&gt;&lt;code class=&quot;language-rust&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;extern&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;token function-definition function&quot;&gt;get_answer&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;i32&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token macro property&quot;&gt;println!&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Getting answer...&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; answer &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;get_answer&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token macro property&quot;&gt;println!&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Answer is {}&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; answer&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;And compile your code to WebAssembly:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;cargo build --target wasm32-unknown-unknown&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Now you need to instrument the WebAssembly file with code for storing/restoring the stack. For C /
C++, Emscripten would do this for us, but it&#39;s not used here, so the process is a bit more manual.&lt;/p&gt;
&lt;p&gt;Luckily, the Asyncify transform itself is completely toolchain-agnostic. It can transform arbitrary
WebAssembly files, no matter which compiler it&#39;s produced by. The transform is provided separately
as part of the &lt;code&gt;wasm-opt&lt;/code&gt; optimiser from the &lt;a href=&quot;https://github.com/WebAssembly/binaryen&quot; rel=&quot;noopener&quot;&gt;Binaryen
toolchain&lt;/a&gt; and can be invoked like this:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;wasm-opt -O2 --asyncify &lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;&lt;br /&gt;      --pass-arg&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;asyncify-imports@env.get_answer &lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;..&lt;/span&gt;.&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Pass &lt;code&gt;--asyncify&lt;/code&gt; to enable the transform, and then use &lt;code&gt;--pass-arg=…&lt;/code&gt; to provide a comma-separated
list of asynchronous functions, where the program state should be suspended and later resumed.&lt;/p&gt;
&lt;p&gt;All that&#39;s left is to provide supporting runtime code that will actually do that—suspend and resume
WebAssembly code. Again, in the C / C++ case this would be included by Emscripten, but now you need
custom JavaScript glue code that would handle arbitrary WebAssembly files. We&#39;ve created a library
just for that.&lt;/p&gt;
&lt;p&gt;You can find it on GitHub at
&lt;a href=&quot;https://github.com/GoogleChromeLabs/asyncify&quot; rel=&quot;noopener&quot;&gt;https://github.com/GoogleChromeLabs/asyncify&lt;/a&gt; or npm
under the name &lt;a href=&quot;https://www.npmjs.com/package/asyncify-wasm&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;asyncify-wasm&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;It simulates a standard &lt;a href=&quot;https://developer.mozilla.org/docs/WebAssembly&quot; rel=&quot;noopener&quot;&gt;WebAssembly instantiation
API&lt;/a&gt;, but under its own namespace. The only
difference is that, under a regular WebAssembly API you can only provide synchronous functions as
imports, while under the Asyncify wrapper, you can provide asynchronous imports as well:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; instance &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; Asyncify&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;instantiateStreaming&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;fetch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;app.wasm&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    env&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;get_answer&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; response &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fetch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;answer.txt&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; text &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; response&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;Number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;text&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;…&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; instance&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;exports&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Once you try to call such an asynchronous function - like &lt;code&gt;get_answer()&lt;/code&gt; in the example above - from
the WebAssembly side, the library will detect the returned &lt;code&gt;Promise&lt;/code&gt;, suspend and save the state of
the WebAssembly application, subscribe to the promise completion, and later, once it&#39;s resolved,
seamlessly restore the call stack and state and continue execution as if nothing has happened.&lt;/p&gt;
&lt;p&gt;Since any function in the module might make an asynchronous call, all the exports become potentially
asynchronous too, so they get wrapped as well. You might have noticed in the example above that you
need to &lt;code&gt;await&lt;/code&gt; the result of &lt;code&gt;instance.exports.main()&lt;/code&gt; to know when the execution is truly
finished.&lt;/p&gt;
&lt;h3 id=&quot;how-does-this-all-work-under-the-hood&quot;&gt;How does this all work under the hood? &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/asyncify/#how-does-this-all-work-under-the-hood&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;When Asyncify detects a call to one of the &lt;code&gt;ASYNCIFY_IMPORTS&lt;/code&gt; functions, it starts an asynchronous
operation, saves the entire state of the application, including the call stack and any temporary
locals, and later, when that operation is finished, restores all the memory and call stack and
resumes from the same place and with the same state as if the program has never stopped.&lt;/p&gt;
&lt;p&gt;This is quite similar to async-await feature in JavaScript that I showed earlier, but, unlike the
JavaScript one, doesn&#39;t require any special syntax or runtime support from the language, and instead
works by transforming plain synchronous functions at compile-time.&lt;/p&gt;
&lt;p&gt;When compiling the earlier shown asynchronous sleep example:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token function&quot;&gt;puts&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;A&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token function&quot;&gt;async_sleep&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token function&quot;&gt;puts&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;B&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Asyncify takes this code and transforms it to roughly like the following one (pseudo-code, real
transformation is more involved than this):&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;mode &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;NORMAL_EXECUTION&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token function&quot;&gt;puts&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;A&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token function&quot;&gt;async_sleep&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token function&quot;&gt;saveLocals&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    mode &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;UNWINDING&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;mode &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;REWINDING&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token function&quot;&gt;restoreLocals&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    mode &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;NORMAL_EXECUTION&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token function&quot;&gt;puts&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;B&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Initially &lt;code&gt;mode&lt;/code&gt; is set to &lt;code&gt;NORMAL_EXECUTION&lt;/code&gt;. Correspondingly, the first time such transformed code
is executed, only the part leading up to &lt;code&gt;async_sleep()&lt;/code&gt; will get evaluated. As soon as the
asynchronous operation is scheduled, Asyncify saves all the locals, and unwinds the stack by
returning from each function all the way to the top, this way giving control back to the browser
event loop.&lt;/p&gt;
&lt;p&gt;Then, once &lt;code&gt;async_sleep()&lt;/code&gt; resolves, Asyncify support code will change &lt;code&gt;mode&lt;/code&gt; to &lt;code&gt;REWINDING&lt;/code&gt;, and
call the function again. This time, the &amp;quot;normal execution&amp;quot; branch is skipped - since it already did
the job last time and I want to avoid printing &amp;quot;A&amp;quot; twice - and instead it comes straight to the
&amp;quot;rewinding&amp;quot; branch. Once it&#39;s reached, it restores all the stored locals, changes mode back to
&amp;quot;normal&amp;quot; and continues the execution as if the code were never stopped in the first place.&lt;/p&gt;
&lt;h3 id=&quot;transformation-costs&quot;&gt;Transformation costs &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/asyncify/#transformation-costs&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Unfortunately, Asyncify transform isn&#39;t completely free, since it has to inject quite a bit of
supporting code for storing and restoring all those locals, navigating the call stack under
different modes and so on. It tries to modify only functions marked as asynchronous on the command
line, as well as any of their potential callers, but the code size overhead might still add up to approximately 50% before compression.&lt;/p&gt;
&lt;img alt=&quot;A graph showing code size overhead for various benchmarks, from near-0% under fine-tuned conditions to over 100% in worst cases&quot; decoding=&quot;async&quot; height=&quot;494&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/Im4hmQOYRHFcsg8UTfTR.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/Im4hmQOYRHFcsg8UTfTR.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/Im4hmQOYRHFcsg8UTfTR.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/Im4hmQOYRHFcsg8UTfTR.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/Im4hmQOYRHFcsg8UTfTR.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/Im4hmQOYRHFcsg8UTfTR.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/Im4hmQOYRHFcsg8UTfTR.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/Im4hmQOYRHFcsg8UTfTR.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/Im4hmQOYRHFcsg8UTfTR.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/Im4hmQOYRHFcsg8UTfTR.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/Im4hmQOYRHFcsg8UTfTR.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/Im4hmQOYRHFcsg8UTfTR.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/Im4hmQOYRHFcsg8UTfTR.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/Im4hmQOYRHFcsg8UTfTR.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/Im4hmQOYRHFcsg8UTfTR.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/Im4hmQOYRHFcsg8UTfTR.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/Im4hmQOYRHFcsg8UTfTR.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/Im4hmQOYRHFcsg8UTfTR.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;This isn&#39;t ideal, but in many cases acceptable when the alternative is not having the functionality
altogether or having to make significant rewrites to the original code.&lt;/p&gt;
&lt;p&gt;Make sure to always enable optimizations for the final builds to avoid it going even higher. You can
also check &lt;a href=&quot;https://emscripten.org/docs/porting/asyncify.html#optimizing&quot; rel=&quot;noopener&quot;&gt;Asyncify-specific optimization
options&lt;/a&gt; to reduce the overhead by
limiting transforms only to specified functions and/or only direct function calls. There is also a
minor cost to runtime performance, but it&#39;s limited to the async calls themselves. However, compared
to the cost of the actual work, it&#39;s usually negligible.&lt;/p&gt;
&lt;h2 id=&quot;real-world-demos&quot;&gt;Real-world demos &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/asyncify/#real-world-demos&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Now that you&#39;ve looked at the simple examples, I&#39;ll move on to more complicated scenarios.&lt;/p&gt;
&lt;p&gt;As mentioned in the beginning of the article, one of the storage options on the web is an
asynchronous &lt;a href=&quot;https://web.dev/file-system-access/&quot;&gt;File System Access API&lt;/a&gt;. It provides access to a
real host filesystem from a web application.&lt;/p&gt;
&lt;p&gt;On the other hand, there is a de-facto standard called &lt;a href=&quot;https://github.com/WebAssembly/WASI&quot; rel=&quot;noopener&quot;&gt;WASI&lt;/a&gt;
for WebAssembly I/O in the console and the server-side. It was designed as a compilation target for
system languages, and exposes all sorts of file system and other operations in a traditional
synchronous form.&lt;/p&gt;
&lt;p&gt;What if you could map one to another? Then you could compile any application in any source language
with any toolchain supporting the WASI target, and run it in a sandbox on the web, while still
allowing it to operate on real user files! With Asyncify, you can do just that.&lt;/p&gt;
&lt;p&gt;In this demo, I&#39;ve compiled Rust &lt;a href=&quot;https://github.com/RReverser/coreutils&quot; rel=&quot;noopener&quot;&gt;coreutils&lt;/a&gt; crate with a
few minor patches to WASI, passed via Asyncify transform and implemented asynchronous
&lt;a href=&quot;https://github.com/GoogleChromeLabs/wasi-fs-access/blob/main/src/bindings.ts&quot; rel=&quot;noopener&quot;&gt;bindings&lt;/a&gt; from WASI
to File System Access API on the JavaScript side. Once combined with
&lt;a href=&quot;https://xtermjs.org/&quot; rel=&quot;noopener&quot;&gt;Xterm.js&lt;/a&gt; terminal component, this provides a realistic shell running in the
browser tab and operating on real user files - just like an actual terminal.&lt;/p&gt;
&lt;p&gt;&lt;video&gt;      &lt;source src=&quot;https://storage.googleapis.com/web-dev-uploads/video/9oK23mr86lhFOwKaoYZ4EySNFp02/4244yB6c9RbMCjGjP8ZW.mp4&quot; type=&quot;video/mp4&quot; /&gt;    &lt;/video&gt;&lt;/p&gt;
&lt;p&gt;Check it out live at &lt;a href=&quot;https://wasi.rreverser.com/&quot; rel=&quot;noopener&quot;&gt;https://wasi.rreverser.com/&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Asyncify use-cases are not limited just to timers and filesystems, either. You can go further and
use more niche APIs on the web.&lt;/p&gt;
&lt;p&gt;For example, also with the help of Asyncify, it&#39;s possible to map
&lt;a href=&quot;https://github.com/libusb/libusb&quot; rel=&quot;noopener&quot;&gt;libusb&lt;/a&gt;—probably the most popular native library for working with
USB devices—to a &lt;a href=&quot;https://web.dev/usb/&quot;&gt;WebUSB API&lt;/a&gt;, which gives asynchronous access to such devices
on the web. Once mapped and compiled, I got standard libusb tests and examples to run against chosen
devices right in the sandbox of a web page.&lt;/p&gt;
&lt;img alt=&quot;Screenshot of libusb debug output on a web page, showing information about the connected Canon camera&quot; decoding=&quot;async&quot; height=&quot;548&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 375px) 375px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/2rscL8dyhOVMacuq54Ad.jpg?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/2rscL8dyhOVMacuq54Ad.jpg?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/2rscL8dyhOVMacuq54Ad.jpg?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/2rscL8dyhOVMacuq54Ad.jpg?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/2rscL8dyhOVMacuq54Ad.jpg?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/2rscL8dyhOVMacuq54Ad.jpg?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/2rscL8dyhOVMacuq54Ad.jpg?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/2rscL8dyhOVMacuq54Ad.jpg?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/2rscL8dyhOVMacuq54Ad.jpg?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/2rscL8dyhOVMacuq54Ad.jpg?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/2rscL8dyhOVMacuq54Ad.jpg?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/2rscL8dyhOVMacuq54Ad.jpg?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/9oK23mr86lhFOwKaoYZ4EySNFp02/2rscL8dyhOVMacuq54Ad.jpg?auto=format&amp;w=750 750w&quot; width=&quot;375&quot; /&gt;
&lt;p&gt;It&#39;s probably a story for another blog post though.&lt;/p&gt;
&lt;p&gt;Those examples demonstrate just how powerful Asyncify can be for bridging the gap and porting all
sorts of applications to the web, allowing you to gain cross-platform access, sandboxing, and better
security, all without losing functionality.&lt;/p&gt;
</content>
    <author>
      <name>Ingvar Stepanyan</name>
    </author>
  </entry>
  
  <entry>
    <title>Debugging memory leaks in WebAssembly using Emscripten</title>
    <link href="https://web.dev/webassembly-memory-debugging/"/>
    <updated>2020-08-13T00:00:00Z</updated>
    <id>https://web.dev/webassembly-memory-debugging/</id>
    <content type="html" mode="escaped">&lt;p&gt;&lt;a href=&quot;https://squoosh.app/&quot; rel=&quot;noopener&quot;&gt;Squoosh.app&lt;/a&gt; is a PWA that illustrates just how much different image codecs
and settings can improve image file size without significantly affecting quality. However, it&#39;s also
a technical demo showcasing how you can take libraries written in C++ or Rust and bring them to the
web.&lt;/p&gt;
&lt;p&gt;Being able to port code from existing ecosystems is incredibly valuable, but there are some key
differences between those static languages and JavaScript. One of those is in their different
approaches to memory management.&lt;/p&gt;
&lt;p&gt;While JavaScript is fairly forgiving in cleaning up after itself, such static languages are
definitely not. You need to explicitly ask for a new allocated memory and you really need to make
sure you give it back afterwards, and never use it again. If that doesn&#39;t happen, you get leaks… and
it actually happens fairly regularly. Let&#39;s take a look at how you can debug those memory leaks and,
even better, how you can design your code to avoid them next time.&lt;/p&gt;
&lt;h2 id=&quot;suspicious-pattern&quot;&gt;Suspicious pattern &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/webassembly-memory-debugging/#suspicious-pattern&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Recently, while starting to work on Squoosh, I couldn&#39;t help but notice an interesting pattern in
C++ codec wrappers. Let&#39;s take a look at an &lt;a href=&quot;https://pngquant.org/lib/&quot; rel=&quot;noopener&quot;&gt;ImageQuant&lt;/a&gt; wrapper as an
example (reduced to show only object creation and deallocation parts):&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;liq_attr&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; attr&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;liq_image&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; image&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;liq_result&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; res&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;uint8_t&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; result&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;RawImage &lt;span class=&quot;token function&quot;&gt;quantize&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;std&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;string rawimage&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;                  &lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; image_width&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;                  &lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; image_height&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;                  &lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; num_colors&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;                  &lt;span class=&quot;token keyword&quot;&gt;float&lt;/span&gt; dithering&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;uint8_t&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; image_buffer &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;uint8_t&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;rawimage&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;c_str&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; size &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; image_width &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; image_height&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  attr &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;liq_attr_create&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  image &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;liq_image_create_rgba&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;attr&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; image_buffer&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; image_width&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; image_height&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token function&quot;&gt;liq_set_max_colors&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;attr&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; num_colors&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token function&quot;&gt;liq_image_quantize&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;image&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; attr&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;res&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token function&quot;&gt;liq_set_dithering_level&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;res&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; dithering&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;uint8_t&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; image8bit &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;uint8_t&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;malloc&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;size&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  result &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;uint8_t&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;malloc&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;size &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;// …&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token function&quot;&gt;free&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;image8bit&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token function&quot;&gt;liq_result_destroy&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;res&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token function&quot;&gt;liq_image_destroy&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;image&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token function&quot;&gt;liq_attr_destroy&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;attr&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token function&quot;&gt;val&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;typed_memory_view&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;image_width &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; image_height &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; result&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    image_width&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    image_height&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;free_result&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token function&quot;&gt;free&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;result&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;JavaScript (well, TypeScript):&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;process&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;data&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; ImageData&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; opts&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; QuantizeOptions&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;emscriptenModule&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    emscriptenModule &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;initEmscriptenModule&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;imagequant&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; wasmUrl&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; module &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; emscriptenModule&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; result &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; module&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;quantize&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token comment&quot;&gt;/* … */&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  module&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;free_result&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ImageData&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Uint8ClampedArray&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;result&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;view&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    result&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;width&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    result&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;height&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Do you spot an issue? Hint: it&#39;s
&lt;a href=&quot;https://owasp.org/www-community/vulnerabilities/Using_freed_memory&quot; rel=&quot;noopener&quot;&gt;use-after-free&lt;/a&gt;, but in
JavaScript!&lt;/p&gt;
&lt;p&gt;In Emscripten, &lt;code&gt;typed_memory_view&lt;/code&gt; returns a JavaScript &lt;code&gt;Uint8Array&lt;/code&gt; backed by the WebAssembly (Wasm)
memory buffer, with &lt;code&gt;byteOffset&lt;/code&gt; and &lt;code&gt;byteLength&lt;/code&gt; set to the given pointer and length. The main
point is that this is a TypedArray &lt;em&gt;view&lt;/em&gt; into a WebAssembly memory buffer, rather than a
JavaScript-owned copy of the data.&lt;/p&gt;
&lt;p&gt;When we call &lt;code&gt;free_result&lt;/code&gt; from JavaScript, it, in turn, calls a standard C function &lt;code&gt;free&lt;/code&gt; to mark
this memory as available for any future allocations, which means the data that our &lt;code&gt;Uint8Array&lt;/code&gt; view
points to, can be overwritten with arbitrary data by any future call into Wasm.&lt;/p&gt;
&lt;p&gt;Or, some implementation of &lt;code&gt;free&lt;/code&gt; might even decide to zero-fill the freed memory immediately. The
&lt;code&gt;free&lt;/code&gt; that Emscripten uses doesn&#39;t do that, but we are relying on an implementation detail here
that cannot be guaranteed.&lt;/p&gt;
&lt;p&gt;Or, even if the memory behind the pointer gets preserved, new allocation might need to grow the
WebAssembly memory. When &lt;code&gt;WebAssembly.Memory&lt;/code&gt; is grown either via JavaScript API, or corresponding
&lt;code&gt;memory.grow&lt;/code&gt; instruction, it invalidates the existing &lt;code&gt;ArrayBuffer&lt;/code&gt; and, transitively, any views
backed by it.&lt;/p&gt;
&lt;p&gt;Let me use the DevTools (or Node.js) console to demonstrate this behavior:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; memory &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;WebAssembly&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Memory&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;initial&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;Memory &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; view &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Uint8Array&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;memory&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;buffer&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;42&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token function&quot;&gt;Uint8Array&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// ^ all good, we got a 10 bytes long view at address 42&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; view&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;buffer&lt;br /&gt;&lt;span class=&quot;token function&quot;&gt;ArrayBuffer&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;&lt;span class=&quot;token number&quot;&gt;65536&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// ^ its buffer is the same as the one used for WebAssembly memory&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;//   (the size of the buffer is 1 WebAssembly &quot;page&quot; == 64KB)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; memory&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;grow&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// ^ let&#39;s say we grow Wasm memory by +1 page to fit some new data&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; view&lt;br /&gt;Uint8Array &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// ^ our original view is no longer valid and looks empty!&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; view&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;buffer&lt;br /&gt;&lt;span class=&quot;token function&quot;&gt;ArrayBuffer&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// ^ its buffer got invalidated as well and turned into an empty one&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Finally, even if we don&#39;t explicitly call into Wasm again between &lt;code&gt;free_result&lt;/code&gt; and &lt;code&gt;new Uint8ClampedArray&lt;/code&gt;, at some point we might add multithreading support to our codecs. In that case it
could be a completely different thread that overwrites the data just before we manage to clone it.&lt;/p&gt;
&lt;h2 id=&quot;looking-for-memory-bugs&quot;&gt;Looking for memory bugs &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/webassembly-memory-debugging/#looking-for-memory-bugs&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Just in case, I&#39;ve decided to go further and check if this code exhibits any issues in practice.
This seems like a perfect opportunity to try out the new(ish) &lt;a href=&quot;https://emscripten.org/docs/debugging/Sanitizers.html&quot; rel=&quot;noopener&quot;&gt;Emscripten sanitizers
support&lt;/a&gt; that was added last year
and presented in our WebAssembly talk at the Chrome Dev Summit:&lt;/p&gt;
&lt;div class=&quot;youtube&quot;&gt;  &lt;lite-youtube videoid=&quot;kZrl91SPSpc&quot;&gt;  &lt;/lite-youtube&gt;&lt;/div&gt;
&lt;aside class=&quot;aside flow bg-state-info-bg color-state-info-text&quot;&gt;&lt;div class=&quot; flow&quot;&gt; &lt;a href=&quot;https://github.com/google/sanitizers&quot;&gt;Sanitizers&lt;/a&gt; are special tools that instrument the code with auto-generated checks during compilation, which can then help catch common bugs during runtime. Since they introduce runtime overhead, they&#39;re primarily used during development, although in some critical applications they&#39;re sometimes enabled on a [subset of] production environments as well. &lt;/div&gt;&lt;/aside&gt;
&lt;p&gt;In this case, we&#39;re interested in the
&lt;a href=&quot;https://emscripten.org/docs/debugging/Sanitizers.html#address-sanitizer&quot; rel=&quot;noopener&quot;&gt;AddressSanitizer&lt;/a&gt;, which
can detect various pointer- and memory-related issues. To use it, we need to recompile our codec
with &lt;code&gt;-fsanitize=address&lt;/code&gt;:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;&lt;span class=&quot;highlight-line&quot;&gt;emcc &lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  --bind &lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token variable&quot;&gt;${OPTIMIZE}&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  --closure &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  -s &lt;span class=&quot;token assign-left variable&quot;&gt;ALLOW_MEMORY_GROWTH&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  -s &lt;span class=&quot;token assign-left variable&quot;&gt;MODULARIZE&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  -s &lt;span class=&quot;token string&quot;&gt;&#39;EXPORT_NAME=&quot;imagequant&quot;&#39;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  -I node_modules/libimagequant &lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  -o ./imagequant.js &lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  --std&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;c++11 &lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  imagequant.cpp &lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;ins class=&quot;highlight-line highlight-line-add&quot;&gt;  -fsanitize&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;address &lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;&lt;/ins&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  node_modules/libimagequant/libimagequant.a&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;This will automatically enable pointer safety checks, but we also want to find potential memory
leaks. Since we&#39;re using ImageQuant as a library rather than a program, there is no &amp;quot;exit point&amp;quot; at
which Emscripten could automatically validate that all memory has been freed.&lt;/p&gt;
&lt;p&gt;Instead, for such cases the LeakSanitizer (included in the AddressSanitizer) provides the functions
&lt;a href=&quot;https://emscripten.org/docs/debugging/Sanitizers.html#memory-leaks&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;__lsan_do_leak_check&lt;/code&gt; and
&lt;code&gt;__lsan_do_recoverable_leak_check&lt;/code&gt;&lt;/a&gt;,
which can be manually invoked whenever we expect all memory to be freed and want to validate that
assumption. &lt;code&gt;__lsan_do_leak_check&lt;/code&gt; is meant to be used at the end of a running application, when you
want to abort the process in case any leaks are detected, while &lt;code&gt;__lsan_do_recoverable_leak_check&lt;/code&gt;
is more suitable for library use-cases like ours, when you want to print leaks to the console, but
keep the application running regardless.&lt;/p&gt;
&lt;p&gt;Let&#39;s expose that second helper via Embind so that we can call it from JavaScript at any time:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;ins class=&quot;highlight-line highlight-line-add&quot;&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&amp;lt;sanitizer/lsan_interface.h&gt;&lt;/span&gt;&lt;/span&gt;&lt;/ins&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// …&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;free_result&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token function&quot;&gt;free&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;result&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token function&quot;&gt;EMSCRIPTEN_BINDINGS&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;my_module&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token function&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;zx_quantize&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;zx_quantize&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token function&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;version&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;version&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token function&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;free_result&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;free_result&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;ins class=&quot;highlight-line highlight-line-add&quot;&gt;  &lt;span class=&quot;token function&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;doLeakCheck&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;__lsan_do_recoverable_leak_check&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/ins&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;And invoke it from the JavaScript side once we&#39;re done with the image. Doing this from the
JavaScript side, rather than the C++ one, helps to ensure that all the scopes have been
exited and all the temporary C++ objects were freed by the time we run those checks:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token comment&quot;&gt;// …&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; result &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; opts&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;zx&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;    &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; module&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;zx_quantize&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; data&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;width&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; data&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;height&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; opts&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;dither&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;    &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; module&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;quantize&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; data&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;width&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; data&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;height&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; opts&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;maxNumColors&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; opts&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;dither&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  module&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;free_result&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;ins class=&quot;highlight-line highlight-line-add&quot;&gt;  module&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;doLeakCheck&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/ins&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ImageData&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;    &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Uint8ClampedArray&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;result&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;view&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;    result&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;width&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;    result&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;height&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;This gives us a report like the following in the console:&lt;/p&gt;
&lt;img alt=&quot;Screenshot of a message &amp;amp;quot;Direct leak of 12 bytes&amp;amp;quot; coming from an anonymous wasm-function[…].&quot; decoding=&quot;async&quot; height=&quot;239&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 768px) 768px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/6gm8BJfm97IWnBD5vYBc.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/6gm8BJfm97IWnBD5vYBc.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/6gm8BJfm97IWnBD5vYBc.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/6gm8BJfm97IWnBD5vYBc.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/6gm8BJfm97IWnBD5vYBc.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/6gm8BJfm97IWnBD5vYBc.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/6gm8BJfm97IWnBD5vYBc.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/6gm8BJfm97IWnBD5vYBc.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/6gm8BJfm97IWnBD5vYBc.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/6gm8BJfm97IWnBD5vYBc.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/6gm8BJfm97IWnBD5vYBc.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/6gm8BJfm97IWnBD5vYBc.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/6gm8BJfm97IWnBD5vYBc.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/6gm8BJfm97IWnBD5vYBc.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/6gm8BJfm97IWnBD5vYBc.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/6gm8BJfm97IWnBD5vYBc.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/6gm8BJfm97IWnBD5vYBc.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/6gm8BJfm97IWnBD5vYBc.png?auto=format&amp;w=1536 1536w&quot; width=&quot;768&quot; /&gt;
&lt;p&gt;Uh-oh, there are some small leaks, but the stacktrace is not very helpful as all the function names
are mangled. Let&#39;s recompile with a basic debugging info to preserve them:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;&lt;span class=&quot;highlight-line&quot;&gt;emcc &lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  --bind &lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token variable&quot;&gt;${OPTIMIZE}&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  --closure &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  -s &lt;span class=&quot;token assign-left variable&quot;&gt;ALLOW_MEMORY_GROWTH&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  -s &lt;span class=&quot;token assign-left variable&quot;&gt;MODULARIZE&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  -s &lt;span class=&quot;token string&quot;&gt;&#39;EXPORT_NAME=&quot;imagequant&quot;&#39;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  -I node_modules/libimagequant &lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  -o ./imagequant.js &lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  --std&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;c++11 &lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  imagequant.cpp &lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  -fsanitize&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;address &lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;ins class=&quot;highlight-line highlight-line-add&quot;&gt;  -g2 &lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;&lt;/ins&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  node_modules/libimagequant/libimagequant.a&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;This looks much better:&lt;/p&gt;
&lt;img alt=&quot;Screenshot of a message &amp;amp;quot;Direct leak of 12 bytes&amp;amp;quot; coming from a &amp;#x60;GenericBindingType&amp;lt;RawImage&amp;gt;::toWireType&amp;#x60; function&quot; decoding=&quot;async&quot; height=&quot;271&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 768px) 768px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/mISFSSAJBklHqRj8WcaC.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/mISFSSAJBklHqRj8WcaC.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/mISFSSAJBklHqRj8WcaC.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/mISFSSAJBklHqRj8WcaC.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/mISFSSAJBklHqRj8WcaC.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/mISFSSAJBklHqRj8WcaC.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/mISFSSAJBklHqRj8WcaC.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/mISFSSAJBklHqRj8WcaC.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/mISFSSAJBklHqRj8WcaC.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/mISFSSAJBklHqRj8WcaC.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/mISFSSAJBklHqRj8WcaC.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/mISFSSAJBklHqRj8WcaC.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/mISFSSAJBklHqRj8WcaC.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/mISFSSAJBklHqRj8WcaC.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/mISFSSAJBklHqRj8WcaC.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/mISFSSAJBklHqRj8WcaC.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/mISFSSAJBklHqRj8WcaC.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/mISFSSAJBklHqRj8WcaC.png?auto=format&amp;w=1536 1536w&quot; width=&quot;768&quot; /&gt;
&lt;p&gt;Some parts of the stacktrace still look obscure as they point to Emscripten internals, but we can
tell that the leak is coming from a &lt;code&gt;RawImage&lt;/code&gt; conversion to &amp;quot;wire type&amp;quot; (to a JavaScript value) by
Embind. Indeed, when we look at the code, we can see that we return &lt;code&gt;RawImage&lt;/code&gt; C++ instances to
JavaScript, but we never free them on either side.&lt;/p&gt;
&lt;p&gt;As a reminder, currently there is no garbage collection integration between JavaScript and
WebAssembly, although &lt;a href=&quot;https://github.com/WebAssembly/gc&quot; rel=&quot;noopener&quot;&gt;one is being developed&lt;/a&gt;. Instead, you have
to manually free any memory and call destructors from the JavaScript side once you&#39;re done with the
object. For Embind specifically, the &lt;a href=&quot;https://emscripten.org/docs/porting/connecting_cpp_and_javascript/embind.html#memory-management&quot; rel=&quot;noopener&quot;&gt;official
docs&lt;/a&gt;
suggest to call a &lt;code&gt;.delete()&lt;/code&gt; method on exposed C++ classes:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;JavaScript code must explicitly delete any C++ object handles it has received, or the Emscripten
heap will grow indefinitely.&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; x &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Module&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;MyClass&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;x&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;method&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;x&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;delete&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;/blockquote&gt;
&lt;p&gt;Indeed, when we do that in JavaScript for our class:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token comment&quot;&gt;// …&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; result &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; opts&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;zx&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;    &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; module&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;zx_quantize&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; data&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;width&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; data&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;height&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; opts&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;dither&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;    &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; module&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;quantize&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; data&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;width&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; data&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;height&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; opts&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;maxNumColors&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; opts&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;dither&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  module&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;free_result&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;ins class=&quot;highlight-line highlight-line-add&quot;&gt;  result&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;delete&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/ins&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  module&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;doLeakCheck&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ImageData&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;    &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Uint8ClampedArray&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;result&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;view&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;    result&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;width&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;    result&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;height&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;The leak goes away as expected.&lt;/p&gt;
&lt;h3 id=&quot;discovering-more-issues-with-sanitizers&quot;&gt;Discovering more issues with sanitizers &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/webassembly-memory-debugging/#discovering-more-issues-with-sanitizers&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Building other Squoosh codecs with sanitizers reveals both similar as well as some new issues. For
example, I&#39;ve got this error in MozJPEG bindings:&lt;/p&gt;
&lt;img alt=&quot;Screenshot of a message &amp;amp;quot;memory access out of bounds&amp;amp;quot; coming from a &amp;#x60;jpeg_start_compress&amp;#x60; function&quot; decoding=&quot;async&quot; height=&quot;174&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 768px) 768px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/ArR34HLUVjU5violfalT.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/ArR34HLUVjU5violfalT.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/ArR34HLUVjU5violfalT.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/ArR34HLUVjU5violfalT.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/ArR34HLUVjU5violfalT.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/ArR34HLUVjU5violfalT.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/ArR34HLUVjU5violfalT.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/ArR34HLUVjU5violfalT.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/ArR34HLUVjU5violfalT.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/ArR34HLUVjU5violfalT.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/ArR34HLUVjU5violfalT.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/ArR34HLUVjU5violfalT.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/ArR34HLUVjU5violfalT.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/ArR34HLUVjU5violfalT.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/ArR34HLUVjU5violfalT.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/ArR34HLUVjU5violfalT.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/ArR34HLUVjU5violfalT.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/ArR34HLUVjU5violfalT.png?auto=format&amp;w=1536 1536w&quot; width=&quot;768&quot; /&gt;
&lt;p&gt;Here, it&#39;s not a leak, but us writing to a memory outside of the allocated boundaries 😱&lt;/p&gt;
&lt;p&gt;Digging into the code of MozJPEG, we find that the problem here is that &lt;code&gt;jpeg_mem_dest&lt;/code&gt;—the
function that we use to allocate a memory destination for JPEG—&lt;a href=&quot;https://github.com/mozilla/mozjpeg/blob/1d2320994dd0d293d39cfaea3d13060b60f32c45/jdatadst.c#L282-L288&quot; rel=&quot;noopener&quot;&gt;reuses existing values of
&lt;code&gt;outbuffer&lt;/code&gt; and &lt;code&gt;outsize&lt;/code&gt; when they&#39;re
non-zero&lt;/a&gt;:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;mark class=&quot;highlight-line highlight-line-active&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;outbuffer &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;outsize &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;/mark&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token comment&quot;&gt;/* Allocate initial buffer */&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  dest&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;newbuffer &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;outbuffer &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;unsigned&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;malloc&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;OUTPUT_BUF_SIZE&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;dest&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;newbuffer &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;    &lt;span class=&quot;token function&quot;&gt;ERREXIT1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;cinfo&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; JERR_OUT_OF_MEMORY&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;outsize &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; OUTPUT_BUF_SIZE&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;However, we invoke it without initialising either of those variables, which means MozJPEG writes the
result into a potentially random memory address that happened to be stored in those variables at the
time of the call!&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;mark class=&quot;highlight-line highlight-line-active&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;uint8_t&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; output&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/mark&gt;&lt;br /&gt;&lt;mark class=&quot;highlight-line highlight-line-active&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;unsigned&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;long&lt;/span&gt; size&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/mark&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// …&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token function&quot;&gt;jpeg_mem_dest&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;cinfo&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;output&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;size&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Zero-initialising both variables before the invocation solves this issue, and now the code reaches a
memory leak check instead. Luckily, the check passes successfully, indicating that we don&#39;t have any
leaks in this codec.&lt;/p&gt;
&lt;h2 id=&quot;issues-with-shared-state&quot;&gt;Issues with shared state &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/webassembly-memory-debugging/#issues-with-shared-state&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;…Or do we?&lt;/p&gt;
&lt;p&gt;We know that our codec bindings store some of the state as well as results in global static
variables, and MozJPEG has some particularly complicated structures.&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;uint8_t&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; last_result&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;jpeg_compress_struct&lt;/span&gt; cinfo&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;val &lt;span class=&quot;token function&quot;&gt;encode&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;std&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;string image_in&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; image_width&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; image_height&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; MozJpegOptions opts&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;// …&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;What if some of those get lazily initialized on the first run, and then improperly reused on future
runs? Then a single call with a sanitizer would not report them as problematic.&lt;/p&gt;
&lt;p&gt;Let&#39;s try and process the image a couple of times by randomly clicking at different quality levels
in the UI. Indeed, now we get the following report:&lt;/p&gt;
&lt;img alt=&quot;Screenshot of a message &amp;amp;quot;Direct leak of 262144 bytes&amp;amp;quot; coming from a &amp;#x60;jpeg_finish_compress&amp;#x60; function&quot; decoding=&quot;async&quot; height=&quot;265&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 768px) 768px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/3X5eGopvZ9m5mxySmoWj.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/3X5eGopvZ9m5mxySmoWj.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/3X5eGopvZ9m5mxySmoWj.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/3X5eGopvZ9m5mxySmoWj.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/3X5eGopvZ9m5mxySmoWj.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/3X5eGopvZ9m5mxySmoWj.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/3X5eGopvZ9m5mxySmoWj.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/3X5eGopvZ9m5mxySmoWj.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/3X5eGopvZ9m5mxySmoWj.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/3X5eGopvZ9m5mxySmoWj.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/3X5eGopvZ9m5mxySmoWj.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/3X5eGopvZ9m5mxySmoWj.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/3X5eGopvZ9m5mxySmoWj.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/3X5eGopvZ9m5mxySmoWj.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/3X5eGopvZ9m5mxySmoWj.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/3X5eGopvZ9m5mxySmoWj.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/3X5eGopvZ9m5mxySmoWj.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/3X5eGopvZ9m5mxySmoWj.png?auto=format&amp;w=1536 1536w&quot; width=&quot;768&quot; /&gt;
&lt;p&gt;262,144 bytes—looks like the whole sample image is leaked from &lt;code&gt;jpeg_finish_compress&lt;/code&gt;!&lt;/p&gt;
&lt;p&gt;After checking out the docs and the official examples, it turns out that &lt;code&gt;jpeg_finish_compress&lt;/code&gt;
doesn&#39;t free the memory allocated by our earlier &lt;code&gt;jpeg_mem_dest&lt;/code&gt; call—it only frees the
compression structure, even though that compression structure already knows about our memory
destination… Sigh.&lt;/p&gt;
&lt;p&gt;We can fix this by freeing the data manually in the &lt;code&gt;free_result&lt;/code&gt; function:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;free_result&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token comment&quot;&gt;/* This is an important step since it will release a good deal of memory. */&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token function&quot;&gt;free&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;last_result&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;ins class=&quot;highlight-line highlight-line-add&quot;&gt;  &lt;span class=&quot;token function&quot;&gt;jpeg_destroy_compress&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;cinfo&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/ins&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;I could keep hunting those memory bugs one by one, but I think by now it&#39;s clear enough that the
current approach to memory management leads to some nasty systematic issues.&lt;/p&gt;
&lt;p&gt;Some of them can be caught by the sanitizer right away. Others require intricate tricks to be caught.
Finally, there are issues like in the beginning of the post that, as we can see from the logs,
aren&#39;t caught by the sanitizer at all. The reason is that the actual mis-use happens on the
JavaScript side, into which the sanitizer has no visibility. Those issues will reveal themselves
only in production or after seemingly unrelated changes to the code in the future.&lt;/p&gt;
&lt;h2 id=&quot;building-a-safe-wrapper&quot;&gt;Building a safe wrapper &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/webassembly-memory-debugging/#building-a-safe-wrapper&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Let&#39;s take a couple of steps back, and instead fix all of these problems by restructuring the code
in a safer way. I&#39;ll use ImageQuant wrapper as an example again, but similar refactoring rules apply
to all the codecs, as well as other similar codebases.&lt;/p&gt;
&lt;p&gt;First of all, let&#39;s fix the use-after-free issue from the beginning of the post. For that, we need
to clone the data from the WebAssembly-backed view before marking it as free on the JavaScript side:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token comment&quot;&gt;// …&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; result &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;/* … */&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;ins class=&quot;highlight-line highlight-line-add&quot;&gt;  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; imgData &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ImageData&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;/ins&gt;&lt;br /&gt;&lt;ins class=&quot;highlight-line highlight-line-add&quot;&gt;    &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Uint8ClampedArray&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;result&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;view&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;/ins&gt;&lt;br /&gt;&lt;ins class=&quot;highlight-line highlight-line-add&quot;&gt;    result&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;width&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;/ins&gt;&lt;br /&gt;&lt;ins class=&quot;highlight-line highlight-line-add&quot;&gt;    result&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;height&lt;/ins&gt;&lt;br /&gt;&lt;ins class=&quot;highlight-line highlight-line-add&quot;&gt;  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/ins&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  module&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;free_result&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  result&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;delete&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  module&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;doLeakCheck&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;del class=&quot;highlight-line highlight-line-remove&quot;&gt;  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ImageData&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;/del&gt;&lt;br /&gt;&lt;del class=&quot;highlight-line highlight-line-remove&quot;&gt;    &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Uint8ClampedArray&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;result&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;view&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;/del&gt;&lt;br /&gt;&lt;del class=&quot;highlight-line highlight-line-remove&quot;&gt;    result&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;width&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;/del&gt;&lt;br /&gt;&lt;del class=&quot;highlight-line highlight-line-remove&quot;&gt;    result&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;height&lt;/del&gt;&lt;br /&gt;&lt;del class=&quot;highlight-line highlight-line-remove&quot;&gt;  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/del&gt;&lt;br /&gt;&lt;ins class=&quot;highlight-line highlight-line-add&quot;&gt;  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; imgData&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/ins&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Now, let&#39;s make sure that we don&#39;t share any state in global variables between invocations. This
will both fix some of the issues we&#39;ve already seen, as well as will make it easier to use our
codecs in a multithreaded environment in the future.&lt;/p&gt;
&lt;p&gt;To do that, we refactor the C++ wrapper to make sure that each call to the function manages its own
data using local variables. Then, we can change the signature of our &lt;code&gt;free_result&lt;/code&gt; function to
accept the pointer back:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;del class=&quot;highlight-line highlight-line-remove&quot;&gt;liq_attr&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; attr&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/del&gt;&lt;br /&gt;&lt;del class=&quot;highlight-line highlight-line-remove&quot;&gt;liq_image&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; image&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/del&gt;&lt;br /&gt;&lt;del class=&quot;highlight-line highlight-line-remove&quot;&gt;liq_result&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; res&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/del&gt;&lt;br /&gt;&lt;del class=&quot;highlight-line highlight-line-remove&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;uint8_t&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; result&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/del&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;RawImage &lt;span class=&quot;token function&quot;&gt;quantize&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;std&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;string rawimage&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;                  &lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; image_width&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;                  &lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; image_height&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;                  &lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; num_colors&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;                  &lt;span class=&quot;token keyword&quot;&gt;float&lt;/span&gt; dithering&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;uint8_t&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; image_buffer &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;uint8_t&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;rawimage&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;c_str&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; size &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; image_width &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; image_height&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;del class=&quot;highlight-line highlight-line-remove&quot;&gt;  attr &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;liq_attr_create&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/del&gt;&lt;br /&gt;&lt;del class=&quot;highlight-line highlight-line-remove&quot;&gt;  image &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;liq_image_create_rgba&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;attr&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; image_buffer&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; image_width&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; image_height&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/del&gt;&lt;br /&gt;&lt;ins class=&quot;highlight-line highlight-line-add&quot;&gt;  liq_attr&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; attr &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;liq_attr_create&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/ins&gt;&lt;br /&gt;&lt;ins class=&quot;highlight-line highlight-line-add&quot;&gt;  liq_image&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; image &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;liq_image_create_rgba&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;attr&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; image_buffer&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; image_width&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; image_height&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/ins&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token function&quot;&gt;liq_set_max_colors&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;attr&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; num_colors&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;ins class=&quot;highlight-line highlight-line-add&quot;&gt;  liq_result&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; res &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;nullptr&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/ins&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token function&quot;&gt;liq_image_quantize&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;image&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; attr&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;res&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token function&quot;&gt;liq_set_dithering_level&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;res&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; dithering&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token keyword&quot;&gt;uint8_t&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; image8bit &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;uint8_t&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;malloc&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;size&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;del class=&quot;highlight-line highlight-line-remove&quot;&gt;  result &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;uint8_t&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;malloc&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;size &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/del&gt;&lt;br /&gt;&lt;ins class=&quot;highlight-line highlight-line-add&quot;&gt;  &lt;span class=&quot;token keyword&quot;&gt;uint8_t&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; result &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;uint8_t&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;malloc&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;size &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/ins&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token comment&quot;&gt;// …&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;del class=&quot;highlight-line highlight-line-remove&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;free_result&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;/del&gt;&lt;br /&gt;&lt;ins class=&quot;highlight-line highlight-line-add&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;free_result&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;uint8_t&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;result&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;/ins&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token function&quot;&gt;free&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;result&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;But, since we&#39;re already using Embind in Emscripten to interact with JavaScript, we might as well
make the API even safer by hiding C++ memory management details altogether!&lt;/p&gt;
&lt;p&gt;For that, let&#39;s move the &lt;code&gt;new Uint8ClampedArray(…)&lt;/code&gt; part from JavaScript to the C++ side with
Embind. Then, we can use it to clone the data into the JavaScript memory even &lt;em&gt;before&lt;/em&gt; returning
from the function:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;del class=&quot;highlight-line highlight-line-remove&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;RawImage&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;/del&gt;&lt;br /&gt;&lt;del class=&quot;highlight-line highlight-line-remove&quot;&gt; &lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;/del&gt;&lt;br /&gt;&lt;del class=&quot;highlight-line highlight-line-remove&quot;&gt;  val buffer&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/del&gt;&lt;br /&gt;&lt;del class=&quot;highlight-line highlight-line-remove&quot;&gt;  int width&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/del&gt;&lt;br /&gt;&lt;del class=&quot;highlight-line highlight-line-remove&quot;&gt;  int height&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/del&gt;&lt;br /&gt;&lt;del class=&quot;highlight-line highlight-line-remove&quot;&gt;&lt;/del&gt;&lt;br /&gt;&lt;del class=&quot;highlight-line highlight-line-remove&quot;&gt;  &lt;span class=&quot;token function&quot;&gt;RawImage&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;val b&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; int w&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; int h&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;buffer&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;b&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;w&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;h&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/del&gt;&lt;br /&gt;&lt;del class=&quot;highlight-line highlight-line-remove&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/del&gt;&lt;br /&gt;&lt;ins class=&quot;highlight-line highlight-line-add&quot;&gt;thread_local &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; val Uint8ClampedArray &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; val&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;global&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Uint8ClampedArray&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/ins&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;del class=&quot;highlight-line highlight-line-remove&quot;&gt;RawImage &lt;span class=&quot;token function&quot;&gt;quantize&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token comment&quot;&gt;/* … */&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;/del&gt;&lt;br /&gt;&lt;ins class=&quot;highlight-line highlight-line-add&quot;&gt;val &lt;span class=&quot;token function&quot;&gt;quantize&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token comment&quot;&gt;/* … */&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;/ins&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token comment&quot;&gt;// …&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;del class=&quot;highlight-line highlight-line-remove&quot;&gt;  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;/del&gt;&lt;br /&gt;&lt;del class=&quot;highlight-line highlight-line-remove&quot;&gt;    &lt;span class=&quot;token function&quot;&gt;val&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;typed_memory_view&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;image_width &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; image_height &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; result&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;/del&gt;&lt;br /&gt;&lt;del class=&quot;highlight-line highlight-line-remove&quot;&gt;    image_width&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;/del&gt;&lt;br /&gt;&lt;del class=&quot;highlight-line highlight-line-remove&quot;&gt;    image_height&lt;/del&gt;&lt;br /&gt;&lt;del class=&quot;highlight-line highlight-line-remove&quot;&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/del&gt;&lt;br /&gt;&lt;ins class=&quot;highlight-line highlight-line-add&quot;&gt;  val js_result &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Uint8ClampedArray&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;new_&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;typed_memory_view&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;/ins&gt;&lt;br /&gt;&lt;ins class=&quot;highlight-line highlight-line-add&quot;&gt;    image_width &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; image_height &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;/ins&gt;&lt;br /&gt;&lt;ins class=&quot;highlight-line highlight-line-add&quot;&gt;    result&lt;/ins&gt;&lt;br /&gt;&lt;ins class=&quot;highlight-line highlight-line-add&quot;&gt;  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/ins&gt;&lt;br /&gt;&lt;ins class=&quot;highlight-line highlight-line-add&quot;&gt;  &lt;span class=&quot;token function&quot;&gt;free&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;result&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/ins&gt;&lt;br /&gt;&lt;ins class=&quot;highlight-line highlight-line-add&quot;&gt;  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; js_result&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/ins&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;aside class=&quot;aside flow bg-state-info-bg color-state-info-text&quot;&gt;&lt;div class=&quot; flow&quot;&gt;  In this case we can return &lt;code&gt;Uint8ClampedArray&lt;/code&gt;, because JavaScript already knows the width and height of the resulting image. If this wasn&#39;t the case, then we could return an &lt;code&gt;ImageData&lt;/code&gt; instance instead, which is functionally equivalent to our previous &lt;code&gt;RawImage&lt;/code&gt; wrapper, but is a standard JavaScript-owned object:  &lt;code&gt;ts   // …   val js_result = Uint8ClampedArray.new_(typed_memory_view(     image_width * image_height * 4,     result   ));   free(result);   return ImageData.new_(js_result, image_width, image_height); } &lt;/code&gt;  &lt;/div&gt;&lt;/aside&gt;
&lt;p&gt;Note how, with a single change, we both ensure that the resulting byte array is owned by JavaScript
and not backed by WebAssembly memory, &lt;em&gt;&lt;strong&gt;and&lt;/strong&gt;&lt;/em&gt; get rid of the previously leaked &lt;code&gt;RawImage&lt;/code&gt; wrapper
too.&lt;/p&gt;
&lt;p&gt;Now JavaScript doesn&#39;t have to worry about freeing data at all anymore, and can use the result like
any other garbage-collected object:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-ts&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token comment&quot;&gt;// …&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;del class=&quot;highlight-line highlight-line-remove&quot;&gt;  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; result &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;/* … */&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/del&gt;&lt;br /&gt;&lt;del class=&quot;highlight-line highlight-line-remove&quot;&gt;&lt;/del&gt;&lt;br /&gt;&lt;del class=&quot;highlight-line highlight-line-remove&quot;&gt;  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; imgData &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ImageData&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;/del&gt;&lt;br /&gt;&lt;del class=&quot;highlight-line highlight-line-remove&quot;&gt;    &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Uint8ClampedArray&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;result&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;view&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;/del&gt;&lt;br /&gt;&lt;del class=&quot;highlight-line highlight-line-remove&quot;&gt;    result&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;width&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;/del&gt;&lt;br /&gt;&lt;del class=&quot;highlight-line highlight-line-remove&quot;&gt;    result&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;height&lt;/del&gt;&lt;br /&gt;&lt;del class=&quot;highlight-line highlight-line-remove&quot;&gt;  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/del&gt;&lt;br /&gt;&lt;del class=&quot;highlight-line highlight-line-remove&quot;&gt;&lt;/del&gt;&lt;br /&gt;&lt;del class=&quot;highlight-line highlight-line-remove&quot;&gt;  module&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;free_result&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/del&gt;&lt;br /&gt;&lt;del class=&quot;highlight-line highlight-line-remove&quot;&gt;  result&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;delete&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/del&gt;&lt;br /&gt;&lt;del class=&quot;highlight-line highlight-line-remove&quot;&gt;  &lt;span class=&quot;token comment&quot;&gt;// module.doLeakCheck();&lt;/span&gt;&lt;/del&gt;&lt;br /&gt;&lt;del class=&quot;highlight-line highlight-line-remove&quot;&gt;&lt;/del&gt;&lt;br /&gt;&lt;del class=&quot;highlight-line highlight-line-remove&quot;&gt;  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; imgData&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/del&gt;&lt;br /&gt;&lt;ins class=&quot;highlight-line highlight-line-add&quot;&gt;  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ImageData&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;result&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; result&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;width&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; result&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;height&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/ins&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;This also means we no longer need a custom &lt;code&gt;free_result&lt;/code&gt; binding on the C++ side:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;del class=&quot;highlight-line highlight-line-remove&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;free_result&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;uint8_t&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; result&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;/del&gt;&lt;br /&gt;&lt;del class=&quot;highlight-line highlight-line-remove&quot;&gt;  &lt;span class=&quot;token function&quot;&gt;free&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;result&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/del&gt;&lt;br /&gt;&lt;del class=&quot;highlight-line highlight-line-remove&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/del&gt;&lt;br /&gt;&lt;del class=&quot;highlight-line highlight-line-remove&quot;&gt;&lt;/del&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token function&quot;&gt;EMSCRIPTEN_BINDINGS&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;my_module&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;del class=&quot;highlight-line highlight-line-remove&quot;&gt;  &lt;span class=&quot;token generic-function&quot;&gt;&lt;span class=&quot;token function&quot;&gt;class_&lt;/span&gt;&lt;span class=&quot;token generic class-name&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;RawImage&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;RawImage&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/del&gt;&lt;br /&gt;&lt;del class=&quot;highlight-line highlight-line-remove&quot;&gt;      &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;property&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;buffer&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;RawImage&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;buffer&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/del&gt;&lt;br /&gt;&lt;del class=&quot;highlight-line highlight-line-remove&quot;&gt;      &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;property&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;width&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;RawImage&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;width&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/del&gt;&lt;br /&gt;&lt;del class=&quot;highlight-line highlight-line-remove&quot;&gt;      &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;property&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;height&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;RawImage&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;height&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/del&gt;&lt;br /&gt;&lt;del class=&quot;highlight-line highlight-line-remove&quot;&gt;&lt;/del&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token function&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;quantize&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;quantize&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token function&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;zx_quantize&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;zx_quantize&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token function&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;version&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;version&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;del class=&quot;highlight-line highlight-line-remove&quot;&gt;  &lt;span class=&quot;token function&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;free_result&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;free_result&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;allow_raw_pointers&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/del&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;All in all, our wrapper code became both cleaner and safer at the same time.&lt;/p&gt;
&lt;p&gt;After this I went through some further minor improvements to the code of the ImageQuant wrapper and
replicated similar memory management fixes for other codecs. If you&#39;re interested in more details,
you can see the resulting PR here: &lt;a href=&quot;https://github.com/GoogleChromeLabs/squoosh/pull/780&quot; rel=&quot;noopener&quot;&gt;Memory fixes for C++
codecs&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;takeaways&quot;&gt;Takeaways &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/webassembly-memory-debugging/#takeaways&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;What lessons can we learn and share from this refactoring that could be applied to other codebases?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Don&#39;t use memory views backed by WebAssembly—no matter which language it&#39;s built from—beyond a
single invocation. You can&#39;t rely on them surviving any longer than that, and you won&#39;t be able
to catch these bugs by conventional means, so if you need to store the data for later, copy it to
the JavaScript side and store it there.&lt;/li&gt;
&lt;li&gt;If possible, use a safe memory management language or, at least, safe type wrappers, instead of
operating on raw pointers directly. This won&#39;t save you from bugs on the JavaScript ↔ WebAssembly
boundary, but at least it will reduce the surface for bugs self-contained by the static language code.&lt;/li&gt;
&lt;li&gt;No matter which language you use, run code with sanitizers during development—they can help to
catch not only problems in the static language code, but also some issues across the JavaScript ↔
WebAssembly boundary, such as forgetting to call &lt;code&gt;.delete()&lt;/code&gt; or passing in invalid pointers from
the JavaScript side.&lt;/li&gt;
&lt;li&gt;If possible, avoid exposing unmanaged data and objects from WebAssembly to JavaScript altogether.
JavaScript is a garbage-collected language, and manual memory management is not common in it.
This can be considered an abstraction leak of the memory model of the language your WebAssembly
was built from, and incorrect management is easy to overlook in a JavaScript codebase.&lt;/li&gt;
&lt;li&gt;This might be obvious, but, like in any other codebase, avoid storing mutable state in global
variables. You don&#39;t want to debug issues with its reuse across various invocations or even
threads, so it&#39;s best to keep it as self-contained as possible.&lt;/li&gt;
&lt;/ul&gt;
</content>
    <author>
      <name>Ingvar Stepanyan</name>
    </author>
  </entry>
</feed>
