speice.io/2018/09/isomorphic-apps/index.html

184 lines
49 KiB
HTML

<!doctype html><html lang=en dir=ltr class="blog-wrapper blog-post-page plugin-blog plugin-id-default" data-has-hydrated=false><meta charset=UTF-8><meta name=generator content="Docusaurus v3.6.0"><title data-rh=true>Isomorphic desktop apps with Rust | The Old Speice Guy</title><meta data-rh=true name=viewport content="width=device-width,initial-scale=1.0"><meta data-rh=true name=twitter:card content=summary_large_image><meta data-rh=true property=og:url content=https://speice.io/2018/09/isomorphic-apps><meta data-rh=true property=og:locale content=en><meta data-rh=true name=docusaurus_locale content=en><meta data-rh=true name=docusaurus_tag content=default><meta data-rh=true name=docsearch:language content=en><meta data-rh=true name=docsearch:docusaurus_tag content=default><meta data-rh=true property=og:title content="Isomorphic desktop apps with Rust | The Old Speice Guy"><meta data-rh=true name=description content="I both despise Javascript and am stunned by its success doing some really cool things. It's"><meta data-rh=true property=og:description content="I both despise Javascript and am stunned by its success doing some really cool things. It's"><meta data-rh=true property=og:type content=article><meta data-rh=true property=article:published_time content=2018-09-15T12:00:00.000Z><link data-rh=true rel=icon href=/img/favicon.ico><link data-rh=true rel=canonical href=https://speice.io/2018/09/isomorphic-apps><link data-rh=true rel=alternate href=https://speice.io/2018/09/isomorphic-apps hreflang=en><link data-rh=true rel=alternate href=https://speice.io/2018/09/isomorphic-apps hreflang=x-default><script data-rh=true type=application/ld+json>{"@context":"https://schema.org","@id":"https://speice.io/2018/09/isomorphic-apps","@type":"BlogPosting","author":{"@type":"Person","name":"Bradlee Speice"},"dateModified":"2024-11-09T21:40:50.000Z","datePublished":"2018-09-15T12:00:00.000Z","description":"I both despise Javascript and am stunned by its success doing some really cool things. It's","headline":"Isomorphic desktop apps with Rust","isPartOf":{"@id":"https://speice.io/","@type":"Blog","name":"Blog"},"keywords":[],"mainEntityOfPage":"https://speice.io/2018/09/isomorphic-apps","name":"Isomorphic desktop apps with Rust","url":"https://speice.io/2018/09/isomorphic-apps"}</script><link rel=alternate type=application/rss+xml href=/rss.xml title="The Old Speice Guy RSS Feed"><link rel=alternate type=application/atom+xml href=/atom.xml title="The Old Speice Guy Atom Feed"><link rel=stylesheet href=https://cdn.jsdelivr.net/npm/katex@0.13.24/dist/katex.min.css integrity=sha384-odtC+0UGzzFL/6PNoE8rX/SPcQDXBJ+uRepguP4QkPCm2LBxH3FA3y+fKSiJ+AmM crossorigin><link rel=stylesheet href=/assets/css/styles.ae6ff4a3.css><script src=/assets/js/runtime~main.751b419d.js defer></script><script src=/assets/js/main.62ce6156.js defer></script><body class=navigation-with-keyboard><script>!function(){var t,e=function(){try{return new URLSearchParams(window.location.search).get("docusaurus-theme")}catch(t){}}()||function(){try{return window.localStorage.getItem("theme")}catch(t){}}();t=null!==e?e:"light",document.documentElement.setAttribute("data-theme",t)}(),function(){try{for(var[t,e]of new URLSearchParams(window.location.search).entries())if(t.startsWith("docusaurus-data-")){var a=t.replace("docusaurus-data-","data-");document.documentElement.setAttribute(a,e)}}catch(t){}}()</script><div id=__docusaurus><div role=region aria-label="Skip to main content"><a class=skipToContent_fXgn href=#__docusaurus_skipToContent_fallback>Skip to main content</a></div><nav aria-label=Main class="navbar navbar--fixed-top"><div class=navbar__inner><div class=navbar__items><button aria-label="Toggle navigation bar" aria-expanded=false class="navbar__toggle clean-btn" type=button><svg width=30 height=30 viewBox="0 0 30 30" aria-hidden=true><path stroke=currentColor stroke-linecap=round stroke-miterlimit=10 stroke-width=2 d="M4 7h22M4 15h22M4 23h22"/></svg></button><a class=navbar__brand href=/><div class=navbar__logo><img src=/img/logo.svg alt="Sierpinski Gasket" class="themedComponent_mlkZ themedComponent--light_NVdE"><img src=/img/logo-dark.svg alt="Sierpinski Gasket" class="themedComponent_mlkZ themedComponent--dark_xIcU"></div><b class="navbar__title text--truncate">The Old Speice Guy</b></a></div><div class="navbar__items navbar__items--right"><a href=https://github.com/bspeice target=_blank rel="noopener noreferrer" class="navbar__item navbar__link header-github-link"></a><div class="toggle_vylO colorModeToggle_DEke"><button class="clean-btn toggleButton_gllP toggleButtonDisabled_aARS" type=button disabled title="Switch between dark and light mode (currently light mode)" aria-label="Switch between dark and light mode (currently light mode)" aria-live=polite aria-pressed=false><svg viewBox="0 0 24 24" width=24 height=24 class=lightToggleIcon_pyhR><path fill=currentColor d="M12,9c1.65,0,3,1.35,3,3s-1.35,3-3,3s-3-1.35-3-3S10.35,9,12,9 M12,7c-2.76,0-5,2.24-5,5s2.24,5,5,5s5-2.24,5-5 S14.76,7,12,7L12,7z M2,13l2,0c0.55,0,1-0.45,1-1s-0.45-1-1-1l-2,0c-0.55,0-1,0.45-1,1S1.45,13,2,13z M20,13l2,0c0.55,0,1-0.45,1-1 s-0.45-1-1-1l-2,0c-0.55,0-1,0.45-1,1S19.45,13,20,13z M11,2v2c0,0.55,0.45,1,1,1s1-0.45,1-1V2c0-0.55-0.45-1-1-1S11,1.45,11,2z M11,20v2c0,0.55,0.45,1,1,1s1-0.45,1-1v-2c0-0.55-0.45-1-1-1C11.45,19,11,19.45,11,20z M5.99,4.58c-0.39-0.39-1.03-0.39-1.41,0 c-0.39,0.39-0.39,1.03,0,1.41l1.06,1.06c0.39,0.39,1.03,0.39,1.41,0s0.39-1.03,0-1.41L5.99,4.58z M18.36,16.95 c-0.39-0.39-1.03-0.39-1.41,0c-0.39,0.39-0.39,1.03,0,1.41l1.06,1.06c0.39,0.39,1.03,0.39,1.41,0c0.39-0.39,0.39-1.03,0-1.41 L18.36,16.95z M19.42,5.99c0.39-0.39,0.39-1.03,0-1.41c-0.39-0.39-1.03-0.39-1.41,0l-1.06,1.06c-0.39,0.39-0.39,1.03,0,1.41 s1.03,0.39,1.41,0L19.42,5.99z M7.05,18.36c0.39-0.39,0.39-1.03,0-1.41c-0.39-0.39-1.03-0.39-1.41,0l-1.06,1.06 c-0.39,0.39-0.39,1.03,0,1.41s1.03,0.39,1.41,0L7.05,18.36z"/></svg><svg viewBox="0 0 24 24" width=24 height=24 class=darkToggleIcon_wfgR><path fill=currentColor d="M9.37,5.51C9.19,6.15,9.1,6.82,9.1,7.5c0,4.08,3.32,7.4,7.4,7.4c0.68,0,1.35-0.09,1.99-0.27C17.45,17.19,14.93,19,12,19 c-3.86,0-7-3.14-7-7C5,9.07,6.81,6.55,9.37,5.51z M12,3c-4.97,0-9,4.03-9,9s4.03,9,9,9s9-4.03,9-9c0-0.46-0.04-0.92-0.1-1.36 c-0.98,1.37-2.58,2.26-4.4,2.26c-2.98,0-5.4-2.42-5.4-5.4c0-1.81,0.89-3.42,2.26-4.4C12.92,3.04,12.46,3,12,3L12,3z"/></svg></button></div><div class=navbarSearchContainer_Bca1><div class=navbar__search><span aria-label="expand searchbar" role=button class=search-icon tabindex=0></span><input id=search_input_react type=search placeholder=Loading... aria-label=Search class="navbar__search-input search-bar" disabled></div></div></div></div><div role=presentation class=navbar-sidebar__backdrop></div></nav><div id=__docusaurus_skipToContent_fallback class="main-wrapper mainWrapper_z2l0"><div class="container margin-vert--lg"><div class=row><aside class="col col--3"><nav class="sidebar_re4s thin-scrollbar" aria-label="Blog recent posts navigation"><div class="sidebarItemTitle_pO2u margin-bottom--md">All posts</div><div role=group><h3>2022</h3><ul class="sidebarItemList_Yudw clean-list"><li class=sidebarItem__DBe><a class=sidebarItemLink_mo7H href=/2011/11/webpack-industrial-complex>The webpack industrial complex</a></ul></div><div role=group><h3>2019</h3><ul class="sidebarItemList_Yudw clean-list"><li class=sidebarItem__DBe><a class=sidebarItemLink_mo7H href=/2019/12/release-the-gil>Release the GIL</a></ul><ul class="sidebarItemList_Yudw clean-list"><li class=sidebarItem__DBe><a class=sidebarItemLink_mo7H href=/2019/09/binary-format-shootout>Binary format shootout</a></ul><ul class="sidebarItemList_Yudw clean-list"><li class=sidebarItem__DBe><a class=sidebarItemLink_mo7H href=/2019/06/high-performance-systems>On building high performance systems</a></ul><ul class="sidebarItemList_Yudw clean-list"><li class=sidebarItem__DBe><a class=sidebarItemLink_mo7H href=/2019/05/making-bread>Making bread</a></ul><div role=group><h4>Allocations in Rust</h4><ul><ul class="sidebarItemList_Yudw clean-list"><li class=sidebarItem__DBe><a class=sidebarItemLink_mo7H href=/2019/02/understanding-allocations-in-rust>Foreword</a><li class=sidebarItem__DBe><a class=sidebarItemLink_mo7H href=/2019/02/the-whole-world>Global memory</a><li class=sidebarItem__DBe><a class=sidebarItemLink_mo7H href=/2019/02/stacking-up>Fixed memory</a><li class=sidebarItem__DBe><a class=sidebarItemLink_mo7H href=/2019/02/a-heaping-helping>Dynamic memory</a><li class=sidebarItem__DBe><a class=sidebarItemLink_mo7H href=/2019/02/08/compiler-optimizations>Compiler optimizations</a><li class=sidebarItem__DBe><a class=sidebarItemLink_mo7H href=/2019/02/summary>Summary</a></ul></ul></div></div><div role=group><h3>2018</h3><ul class="sidebarItemList_Yudw clean-list"><li class=sidebarItem__DBe><a class=sidebarItemLink_mo7H href=/2018/12/allocation-safety>QADAPT - debug_assert! for allocations</a></ul><ul class="sidebarItemList_Yudw clean-list"><li class=sidebarItem__DBe><a class=sidebarItemLink_mo7H href=/2018/12/what-small-business-really-means>More "what companies really mean"</a></ul><ul class="sidebarItemList_Yudw clean-list"><li class=sidebarItem__DBe><a class=sidebarItemLink_mo7H href=/2018/10/case-study-optimization>A case study in heaptrack</a></ul><ul class="sidebarItemList_Yudw clean-list"><li class=sidebarItem__DBe><a aria-current=page class="sidebarItemLink_mo7H sidebarItemLinkActive_I1ZP" href=/2018/09/isomorphic-apps>Isomorphic desktop apps with Rust</a></ul><ul class="sidebarItemList_Yudw clean-list"><li class=sidebarItem__DBe><a class=sidebarItemLink_mo7H href=/2018/09/primitives-in-rust-are-weird>Primitives in Rust are weird (and cool)</a></ul><ul class="sidebarItemList_Yudw clean-list"><li class=sidebarItem__DBe><a class=sidebarItemLink_mo7H href=/2018/06/dateutil-parser-to-rust>What I learned porting dateutil to Rust</a></ul><ul class="sidebarItemList_Yudw clean-list"><li class=sidebarItem__DBe><a class=sidebarItemLink_mo7H href=/2018/05/hello>Hello!</a></ul><div role=group><h4>Captain's Cookbook</h4><ul><ul class="sidebarItemList_Yudw clean-list"><li class=sidebarItem__DBe><a class=sidebarItemLink_mo7H href=/2018/01/captains-cookbook-part-1>Project setup</a><li class=sidebarItem__DBe><a class=sidebarItemLink_mo7H href=/2018/01/captains-cookbook-part-2>Practical usage</a></ul></ul></div></div><div role=group><h3>2016</h3><ul class="sidebarItemList_Yudw clean-list"><li class=sidebarItem__DBe><a class=sidebarItemLink_mo7H href=/2016/11/pca-audio-compression>PCA audio compression</a></ul><ul class="sidebarItemList_Yudw clean-list"><li class=sidebarItem__DBe><a class=sidebarItemLink_mo7H href=/2016/10/rustic-repodcasting>A Rustic re-podcasting server</a></ul><ul class="sidebarItemList_Yudw clean-list"><li class=sidebarItem__DBe><a class=sidebarItemLink_mo7H href=/2016/06/event-studies-and-earnings-releases>Event studies and earnings releases</a></ul><ul class="sidebarItemList_Yudw clean-list"><li class=sidebarItem__DBe><a class=sidebarItemLink_mo7H href=/2016/05/the-unfair-casino>The unfair casino</a></ul><ul class="sidebarItemList_Yudw clean-list"><li class=sidebarItem__DBe><a class=sidebarItemLink_mo7H href=/2016/04/tick-tock>Tick tock...</a></ul><ul class="sidebarItemList_Yudw clean-list"><li class=sidebarItem__DBe><a class=sidebarItemLink_mo7H href=/2016/03/tweet-like-me>Tweet like me</a></ul><ul class="sidebarItemList_Yudw clean-list"><li class=sidebarItem__DBe><a class=sidebarItemLink_mo7H href=/2016/03/predicting-santander-customer-happiness>Predicting Santander customer happiness</a></ul><ul class="sidebarItemList_Yudw clean-list"><li class=sidebarItem__DBe><a class=sidebarItemLink_mo7H href=/2016/02/profitability-using-the-investment-formula>Profitability using the investment formula</a></ul><ul class="sidebarItemList_Yudw clean-list"><li class=sidebarItem__DBe><a class=sidebarItemLink_mo7H href=/2016/02/guaranteed-money-maker>Guaranteed money maker</a></ul><ul class="sidebarItemList_Yudw clean-list"><li class=sidebarItem__DBe><a class=sidebarItemLink_mo7H href=/2016/01/cloudy-in-seattle>Cloudy in Seattle</a></ul><ul class="sidebarItemList_Yudw clean-list"><li class=sidebarItem__DBe><a class=sidebarItemLink_mo7H href=/2016/01/complaining-about-the-weather>Complaining about the weather</a></ul></div><div role=group><h3>2015</h3><ul class="sidebarItemList_Yudw clean-list"><li class=sidebarItem__DBe><a class=sidebarItemLink_mo7H href=/2015/12/testing-cramer>Testing Cramer</a></ul><ul class="sidebarItemList_Yudw clean-list"><li class=sidebarItem__DBe><a class=sidebarItemLink_mo7H href=/2015/11/autocallable>Autocallable Bonds</a></ul><ul class="sidebarItemList_Yudw clean-list"><li class=sidebarItem__DBe><a class=sidebarItemLink_mo7H href=/2015/11/welcome>Welcome, and an algorithm</a></ul></div></nav></aside><main class="col col--7"><article><header><h1 class=title_f1Hy>Isomorphic desktop apps with Rust</h1><div class="container_mt6G margin-vert--md"><time datetime=2018-09-15T12:00:00.000Z>September 15, 2018</time> · <!-- -->10 min read</div><div class="margin-top--md margin-bottom--sm row"><div class="col col--12 authorCol_Hf19"><div class="avatar margin-bottom--sm"><div class="avatar__intro authorDetails_lV9A"><div class=avatar__name><span class=authorName_yefp>Bradlee Speice</span></div><div class=authorSocials_rSDt><a href=https://github.com/bspeice target=_blank rel="noopener noreferrer" class=authorSocialLink_owbf title=GitHub><svg viewBox="0 0 256 250" width=1em height=1em class="authorSocialLink_owbf githubSvg_Uu4N" style=--dark:#000;--light:#fff preserveAspectRatio=xMidYMid><path d="M128.001 0C57.317 0 0 57.307 0 128.001c0 56.554 36.676 104.535 87.535 121.46 6.397 1.185 8.746-2.777 8.746-6.158 0-3.052-.12-13.135-.174-23.83-35.61 7.742-43.124-15.103-43.124-15.103-5.823-14.795-14.213-18.73-14.213-18.73-11.613-7.944.876-7.78.876-7.78 12.853.902 19.621 13.19 19.621 13.19 11.417 19.568 29.945 13.911 37.249 10.64 1.149-8.272 4.466-13.92 8.127-17.116-28.431-3.236-58.318-14.212-58.318-63.258 0-13.975 5-25.394 13.188-34.358-1.329-3.224-5.71-16.242 1.24-33.874 0 0 10.749-3.44 35.21 13.121 10.21-2.836 21.16-4.258 32.038-4.307 10.878.049 21.837 1.47 32.066 4.307 24.431-16.56 35.165-13.12 35.165-13.12 6.967 17.63 2.584 30.65 1.255 33.873 8.207 8.964 13.173 20.383 13.173 34.358 0 49.163-29.944 59.988-58.447 63.157 4.591 3.972 8.682 11.762 8.682 23.704 0 17.126-.148 30.91-.148 35.126 0 3.407 2.304 7.398 8.792 6.14C219.37 232.5 256 184.537 256 128.002 256 57.307 198.691 0 128.001 0Zm-80.06 182.34c-.282.636-1.283.827-2.194.39-.929-.417-1.45-1.284-1.15-1.922.276-.655 1.279-.838 2.205-.399.93.418 1.46 1.293 1.139 1.931Zm6.296 5.618c-.61.566-1.804.303-2.614-.591-.837-.892-.994-2.086-.375-2.66.63-.566 1.787-.301 2.626.591.838.903 1 2.088.363 2.66Zm4.32 7.188c-.785.545-2.067.034-2.86-1.104-.784-1.138-.784-2.503.017-3.05.795-.547 2.058-.055 2.861 1.075.782 1.157.782 2.522-.019 3.08Zm7.304 8.325c-.701.774-2.196.566-3.29-.49-1.119-1.032-1.43-2.496-.726-3.27.71-.776 2.213-.558 3.315.49 1.11 1.03 1.45 2.505.701 3.27Zm9.442 2.81c-.31 1.003-1.75 1.459-3.199 1.033-1.448-.439-2.395-1.613-2.103-2.626.301-1.01 1.747-1.484 3.207-1.028 1.446.436 2.396 1.602 2.095 2.622Zm10.744 1.193c.036 1.055-1.193 1.93-2.715 1.95-1.53.034-2.769-.82-2.786-1.86 0-1.065 1.202-1.932 2.733-1.958 1.522-.03 2.768.818 2.768 1.868Zm10.555-.405c.182 1.03-.875 2.088-2.387 2.37-1.485.271-2.861-.365-3.05-1.386-.184-1.056.893-2.114 2.376-2.387 1.514-.263 2.868.356 3.061 1.403Z"/></svg></a></div></div></div></div></div></header><div id=__blog-post-container class=markdown><p>I both despise Javascript and am stunned by its success doing some really cool things. It's
<a href=https://www.destroyallsoftware.com/talks/the-birth-and-death-of-javascript target=_blank rel="noopener noreferrer">this duality</a> that's
led me to a couple of (very) late nights over the past weeks trying to reconcile myself as I
bootstrap a simple desktop application.</p>
<p>See, as much as
<a href=https://webassembly.org/docs/faq/#is-webassembly-trying-to-replace-javascript target=_blank rel="noopener noreferrer">Webassembly isn't trying to replace Javascript</a>,
<strong>I want Javascript gone</strong>. There are plenty of people who don't share my views, and they are
probably nicer and more fun at parties. But I cringe every time "Webpack" is mentioned, and I think
it's hilarious that the
<a href=https://ecma-international.org/publications/standards/Ecma-402.htm target=_blank rel="noopener noreferrer">language specification</a>
dramatically outpaces anyone's
<a href=https://kangax.github.io/compat-table/es2016plus/ target=_blank rel="noopener noreferrer">actual implementation</a>. The answer to this
conundrum is of course to recompile code from newer versions of the language to older versions <em>of
the same language</em> before running. At least <a href=https://babeljs.io/ target=_blank rel="noopener noreferrer">Babel</a> is a nice tongue-in-cheek reference.</p>
<p>Yet for as much hate as <a href=https://electronjs.org/ target=_blank rel="noopener noreferrer">Electron</a> receives, it does a stunningly good job at solving a really hard
problem: <em>how the hell do I put a button on the screen and react when the user clicks it</em>? GUI
programming is hard, straight up. But if browsers are already able to run everywhere, why don't we
take advantage of someone else solving the hard problems for us? I don't like that I have to use
Javascript for it, but I really don't feel inclined to whip out good ol' <a href=https://wxwidgets.org/ target=_blank rel="noopener noreferrer">wxWidgets</a>.</p>
<p>Now there are other native solutions (<a href=https://github.com/LeoTindall/libui-rs/ target=_blank rel="noopener noreferrer">libui-rs</a>, <a href=https://github.com/PistonDevelopers/conrod target=_blank rel="noopener noreferrer">conrod</a>, <a href=https://github.com/kenz-gelsoft/wxRust target=_blank rel="noopener noreferrer">oh hey wxWdidgets again!</a>), but
those also have their own issues with distribution, styling, etc. With Electron, I can
<code>yarn create electron-app my-app</code> and just get going, knowing that packaging/upgrades/etc. are built
in.</p>
<p>My question is: given recent innovations with WASM, <em>are we Electron yet</em>?</p>
<p>No, not really.</p>
<p>Instead, <strong>what would it take to get to a point where we can skip Javascript in Electron apps?</strong></p>
<p>Truth is, WASM/Webassembly is a pretty new technology and I'm a total beginner in this area. There
may already be solutions to the issues I discuss, but I'm totally unaware of them, so I'm going to
try and organize what I did manage to discover.</p>
<p>I should also mention that the content and things I'm talking about here are not intended to be
prescriptive, but more "if someone else is interested, what do we already know doesn't work?" <em>I
expect everything in this post to be obsolete within two months.</em> Even over the course of writing
this, <a href=https://mnt.io/2018/08/28/from-rust-to-beyond-the-asm-js-galaxy/ target=_blank rel="noopener noreferrer">a separate blog post</a> had
to be modified because <a href=https://github.com/WebAssembly/binaryen/pull/1642 target=_blank rel="noopener noreferrer">upstream changes</a> broke a
<a href=https://github.com/rustwasm/wasm-bindgen/pull/787 target=_blank rel="noopener noreferrer">Rust tool</a> the post tried to use. The post
ultimately
<a href=https://mnt.io/2018/08/28/from-rust-to-beyond-the-asm-js-galaxy/#comment-477 target=_blank rel="noopener noreferrer">got updated</a>, <strong>but
all this happened within the span of a week.</strong> Things are moving quickly.</p>
<p>I'll also note that we're going to skip <a href=http://asmjs.org/ target=_blank rel="noopener noreferrer">asm.js</a> and <a href=https://kripken.github.io/emscripten-site/ target=_blank rel="noopener noreferrer">emscripten</a>. Truth be told, I couldn't get
either of these to output anything, and so I'm just going to say
<a href=https://en.wikipedia.org/wiki/Here_be_dragons target=_blank rel="noopener noreferrer">here be dragons.</a> Everything I'm discussing here
uses the <code>wasm32-unknown-unknown</code> target.</p>
<p>The code that I <em>did</em> get running is available
<a href=https://github.com/speice-io/isomorphic-rust target=_blank rel="noopener noreferrer">over here</a>. Feel free to use it as a starting point,
but I'm mostly including the link as a reference for the things that were attempted.</p>
<h1>An Example Running Application</h1>
<p>So, I did <em>technically</em> get a running application:</p>
<p><img decoding=async loading=lazy alt="Electron app using WASM" src=/assets/images/electron-percy-wasm-9ccb2be15a9bed6da44486afc266bad5.png width=800 height=319 class=img_ev3q></p>
<p>...which you can also try out if you want:</p>
<div class="language-sh codeBlockContainer_Ckt0 theme-code-block" style="--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)"><div class=codeBlockContent_biex><pre tabindex=0 class="prism-code language-sh codeBlock_bY9V thin-scrollbar" style="background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)"><code class=codeBlockLines_e6Vv><span class=token-line style="color:hsl(230, 8%, 24%)"><span class="token function" style="color:hsl(221, 87%, 60%)">git</span><span class="token plain"> clone https://github.com/speice-io/isomorphic-rust.git</span><br></span><span class=token-line style="color:hsl(230, 8%, 24%)"><span class="token plain"></span><span class="token builtin class-name" style="color:hsl(35, 99%, 36%)">cd</span><span class="token plain"> isomorphic_rust/percy</span><br></span><span class=token-line style="color:hsl(230, 8%, 24%)"><span class="token plain"></span><span class="token function" style="color:hsl(221, 87%, 60%)">yarn</span><span class="token plain"> </span><span class="token function" style="color:hsl(221, 87%, 60%)">install</span><span class="token plain"> </span><span class="token operator" style="color:hsl(221, 87%, 60%)">&&</span><span class="token plain"> </span><span class="token function" style="color:hsl(221, 87%, 60%)">yarn</span><span class="token plain"> start</span><br></span></code></pre><div class=buttonGroup__atx><button type=button aria-label="Copy code to clipboard" title=Copy class=clean-btn><span class=copyButtonIcons_eSgA aria-hidden=true><svg viewBox="0 0 24 24" class=copyButtonIcon_y97N><path fill=currentColor d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"/></svg><svg viewBox="0 0 24 24" class=copyButtonSuccessIcon_LjdS><path fill=currentColor d=M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z /></svg></span></button></div></div></div>
<p>...but I wouldn't really call it a "high quality" starting point to base future work on. It's mostly
there to prove this is possible in the first place. And that's something to be proud of! There's a
huge amount of engineering that went into showing a window with the text "It's alive!".</p>
<p>There's also a lot of usability issues that prevent me from recommending anyone try Electron and
WASM apps at the moment, and I think that's the more important thing to discuss.</p>
<h1>Issue the First: Complicated Toolchains</h1>
<p>I quickly established that <a href=https://github.com/rustwasm/wasm-bindgen target=_blank rel="noopener noreferrer">wasm-bindgen</a> was necessary to "link" my Rust code to Javascript. At
that point you've got an Electron app that starts an HTML page which ultimately fetches your WASM
blob. To keep things simple, the goal was to package everything using <a href=https://webpack.js.org/ target=_blank rel="noopener noreferrer">webpack</a> so that I could just
load a <code>bundle.js</code> file on the page. That decision was to be the last thing that kinda worked in
this process.</p>
<p>The first issue
<a href=https://www.reddit.com/r/rust/comments/98lpun/unable_to_load_wasm_for_electron_application/ target=_blank rel="noopener noreferrer">I ran into</a>
while attempting to bundle everything via <code>webpack</code> is a detail in the WASM spec:</p>
<blockquote>
<p>This function accepts a Response object, or a promise for one, and ... <strong>[if > it] does not match
the <code>application/wasm</code> MIME type</strong>, the returned promise will be rejected with a TypeError;</p>
<p><a href=https://webassembly.org/docs/web/#additional-web-embedding-api target=_blank rel="noopener noreferrer">WebAssembly - Additional Web Embedding API</a></p>
</blockquote>
<p>Specifically, if you try and load a WASM blob without the MIME type set, you'll get an error. On the
web this isn't a huge issue, as the server can set MIME types when delivering the blob. With
Electron, you're resolving things with a <code>file://</code> URL and thus can't control the MIME type:</p>
<p><img decoding=async loading=lazy alt="TypeError: Incorrect response MIME type. Expected &amp;#39;application/wasm&amp;#39;." src=/assets/images/incorrect-MIME-type-a977835e8dcbfdb20fdda3c67ee4f76c.png width=795 height=301 class=img_ev3q></p>
<p>There are a couple of solutions depending on how far into the deep end you care to venture:</p>
<ul>
<li>Embed a static file server in your Electron application</li>
<li>Use a <a href=https://electronjs.org/docs/api/protocol target=_blank rel="noopener noreferrer">custom protocol</a> and custom protocol handler</li>
<li>Host your WASM blob on a website that you resolve at runtime</li>
</ul>
<p>But all these are pretty bad solutions and defeat the purpose of using WASM in the first place.
Instead, my workaround was to
<a href=https://github.com/webpack/webpack/issues/7918 target=_blank rel="noopener noreferrer">open a PR with <code>webpack</code></a> and use regex to remove
calls to <code>instantiateStreaming</code> in the
<a href=https://github.com/speice-io/isomorphic-rust/blob/master/percy/build.sh#L21-L25 target=_blank rel="noopener noreferrer">build script</a>:</p>
<div class="language-sh codeBlockContainer_Ckt0 theme-code-block" style="--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)"><div class=codeBlockContent_biex><pre tabindex=0 class="prism-code language-sh codeBlock_bY9V thin-scrollbar" style="background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)"><code class=codeBlockLines_e6Vv><span class=token-line style="color:hsl(230, 8%, 24%)"><span class="token function" style="color:hsl(221, 87%, 60%)">cargo</span><span class="token plain"> +nightly build </span><span class="token parameter variable" style="color:hsl(221, 87%, 60%)">--target</span><span class="token operator" style="color:hsl(221, 87%, 60%)">=</span><span class="token plain">wasm32-unknown-unknown </span><span class="token operator" style="color:hsl(221, 87%, 60%)">&&</span><span class="token plain"> </span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">\</span><span class="token plain"></span><br></span><span class=token-line style="color:hsl(230, 8%, 24%)"><span class="token plain"> wasm-bindgen </span><span class="token string" style="color:hsl(119, 34%, 47%)">"</span><span class="token string variable" style="color:hsl(221, 87%, 60%)">$WASM_DIR</span><span class="token string" style="color:hsl(119, 34%, 47%)">/debug/</span><span class="token string variable" style="color:hsl(221, 87%, 60%)">$WASM_NAME</span><span class="token string" style="color:hsl(119, 34%, 47%)">.wasm"</span><span class="token plain"> --out-dir </span><span class="token string" style="color:hsl(119, 34%, 47%)">"</span><span class="token string variable" style="color:hsl(221, 87%, 60%)">$APP_DIR</span><span class="token string" style="color:hsl(119, 34%, 47%)">"</span><span class="token plain"> --no-typescript </span><span class="token operator" style="color:hsl(221, 87%, 60%)">&&</span><span class="token plain"> </span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">\</span><span class="token plain"></span><br></span><span class=token-line style="color:hsl(230, 8%, 24%)"><span class="token plain"> </span><span class="token comment" style="color:hsl(230, 4%, 64%)"># Have to use --mode=development so we can patch out the call to instantiateStreaming</span><span class="token plain"></span><br></span><span class=token-line style="color:hsl(230, 8%, 24%)"><span class="token plain"> </span><span class="token string" style="color:hsl(119, 34%, 47%)">"</span><span class="token string variable" style="color:hsl(221, 87%, 60%)">$DIR</span><span class="token string" style="color:hsl(119, 34%, 47%)">/node_modules/webpack-cli/bin/cli.js"</span><span class="token plain"> </span><span class="token parameter variable" style="color:hsl(221, 87%, 60%)">--mode</span><span class="token operator" style="color:hsl(221, 87%, 60%)">=</span><span class="token plain">development </span><span class="token string" style="color:hsl(119, 34%, 47%)">"</span><span class="token string variable" style="color:hsl(221, 87%, 60%)">$APP_DIR</span><span class="token string" style="color:hsl(119, 34%, 47%)">/app_loader.js"</span><span class="token plain"> </span><span class="token parameter variable" style="color:hsl(221, 87%, 60%)">-o</span><span class="token plain"> </span><span class="token string" style="color:hsl(119, 34%, 47%)">"</span><span class="token string variable" style="color:hsl(221, 87%, 60%)">$APP_DIR</span><span class="token string" style="color:hsl(119, 34%, 47%)">/bundle.js"</span><span class="token plain"> </span><span class="token operator" style="color:hsl(221, 87%, 60%)">&&</span><span class="token plain"> </span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">\</span><span class="token plain"></span><br></span><span class=token-line style="color:hsl(230, 8%, 24%)"><span class="token plain"> </span><span class="token function" style="color:hsl(221, 87%, 60%)">sed</span><span class="token plain"> </span><span class="token parameter variable" style="color:hsl(221, 87%, 60%)">-i</span><span class="token plain"> </span><span class="token string" style="color:hsl(119, 34%, 47%)">'s/.*instantiateStreaming.*//g'</span><span class="token plain"> </span><span class="token string" style="color:hsl(119, 34%, 47%)">"</span><span class="token string variable" style="color:hsl(221, 87%, 60%)">$APP_DIR</span><span class="token string" style="color:hsl(119, 34%, 47%)">/bundle.js"</span><br></span></code></pre><div class=buttonGroup__atx><button type=button aria-label="Copy code to clipboard" title=Copy class=clean-btn><span class=copyButtonIcons_eSgA aria-hidden=true><svg viewBox="0 0 24 24" class=copyButtonIcon_y97N><path fill=currentColor d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"/></svg><svg viewBox="0 0 24 24" class=copyButtonSuccessIcon_LjdS><path fill=currentColor d=M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z /></svg></span></button></div></div></div>
<p>Once that lands, the
<a href=https://github.com/speice-io/isomorphic-rust/blob/master/percy_patched_webpack/build.sh#L24-L27 target=_blank rel="noopener noreferrer">build process</a>
becomes much simpler:</p>
<div class="language-sh codeBlockContainer_Ckt0 theme-code-block" style="--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)"><div class=codeBlockContent_biex><pre tabindex=0 class="prism-code language-sh codeBlock_bY9V thin-scrollbar" style="background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)"><code class=codeBlockLines_e6Vv><span class=token-line style="color:hsl(230, 8%, 24%)"><span class="token plain" style=display:inline-block></span><br></span><span class=token-line style="color:hsl(230, 8%, 24%)"><span class="token plain"></span><span class="token function" style="color:hsl(221, 87%, 60%)">cargo</span><span class="token plain"> +nightly build </span><span class="token parameter variable" style="color:hsl(221, 87%, 60%)">--target</span><span class="token operator" style="color:hsl(221, 87%, 60%)">=</span><span class="token plain">wasm32-unknown-unknown </span><span class="token operator" style="color:hsl(221, 87%, 60%)">&&</span><span class="token plain"> </span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">\</span><span class="token plain"></span><br></span><span class=token-line style="color:hsl(230, 8%, 24%)"><span class="token plain"> wasm-bindgen </span><span class="token string" style="color:hsl(119, 34%, 47%)">"</span><span class="token string variable" style="color:hsl(221, 87%, 60%)">$WASM_DIR</span><span class="token string" style="color:hsl(119, 34%, 47%)">/debug/</span><span class="token string variable" style="color:hsl(221, 87%, 60%)">$WASM_NAME</span><span class="token string" style="color:hsl(119, 34%, 47%)">.wasm"</span><span class="token plain"> --out-dir </span><span class="token string" style="color:hsl(119, 34%, 47%)">"</span><span class="token string variable" style="color:hsl(221, 87%, 60%)">$APP_DIR</span><span class="token string" style="color:hsl(119, 34%, 47%)">"</span><span class="token plain"> --no-typescript </span><span class="token operator" style="color:hsl(221, 87%, 60%)">&&</span><span class="token plain"> </span><span class="token punctuation" style="color:hsl(119, 34%, 47%)">\</span><span class="token plain"></span><br></span><span class=token-line style="color:hsl(230, 8%, 24%)"><span class="token plain"> </span><span class="token string" style="color:hsl(119, 34%, 47%)">"</span><span class="token string variable" style="color:hsl(221, 87%, 60%)">$DIR</span><span class="token string" style="color:hsl(119, 34%, 47%)">/node_modules/webpack-cli/bin/cli.js"</span><span class="token plain"> </span><span class="token parameter variable" style="color:hsl(221, 87%, 60%)">--mode</span><span class="token operator" style="color:hsl(221, 87%, 60%)">=</span><span class="token plain">production </span><span class="token string" style="color:hsl(119, 34%, 47%)">"</span><span class="token string variable" style="color:hsl(221, 87%, 60%)">$APP_DIR</span><span class="token string" style="color:hsl(119, 34%, 47%)">/app_loader.js"</span><span class="token plain"> </span><span class="token parameter variable" style="color:hsl(221, 87%, 60%)">-o</span><span class="token plain"> </span><span class="token string" style="color:hsl(119, 34%, 47%)">"</span><span class="token string variable" style="color:hsl(221, 87%, 60%)">$APP_DIR</span><span class="token string" style="color:hsl(119, 34%, 47%)">/bundle.js"</span><br></span></code></pre><div class=buttonGroup__atx><button type=button aria-label="Copy code to clipboard" title=Copy class=clean-btn><span class=copyButtonIcons_eSgA aria-hidden=true><svg viewBox="0 0 24 24" class=copyButtonIcon_y97N><path fill=currentColor d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"/></svg><svg viewBox="0 0 24 24" class=copyButtonSuccessIcon_LjdS><path fill=currentColor d=M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z /></svg></span></button></div></div></div>
<p>But we're not done yet! After we compile Rust into WASM and link WASM to Javascript (via
<code>wasm-bindgen</code> and <code>webpack</code>), we still have to make an Electron app. For this purpose I used a
starter app from <a href=https://electronforge.io/ target=_blank rel="noopener noreferrer">Electron Forge</a>, and then a
<a href=https://github.com/speice-io/isomorphic-rust/blob/master/percy/package.json#L8 target=_blank rel="noopener noreferrer"><code>prestart</code> script</a>
to actually handle starting the application.</p>
<p>The
<a href=https://github.com/speice-io/isomorphic-rust/blob/master/percy/package.json#L8 target=_blank rel="noopener noreferrer">final toolchain</a>
looks something like this:</p>
<ul>
<li><code>yarn start</code> triggers the <code>prestart</code> script</li>
<li><code>prestart</code> checks for missing tools (<code>wasm-bindgen-cli</code>, etc.) and then:<!-- -->
<ul>
<li>Uses <code>cargo</code> to compile the Rust code into WASM</li>
<li>Uses <code>wasm-bindgen</code> to link the WASM blob into a Javascript file with exported symbols</li>
<li>Uses <code>webpack</code> to bundle the page start script with the Javascript we just generated<!-- -->
<ul>
<li>Uses <code>babel</code> under the hood to compile the <code>wasm-bindgen</code> code down from ES6 into something
browser-compatible</li>
</ul>
</li>
</ul>
</li>
<li>The <code>start</code> script runs an Electron Forge handler to do some sanity checks</li>
<li>Electron actually starts</li>
</ul>
<p>...which is complicated. I think more work needs to be done to either build a high-quality starter
app that can manage these steps, or another tool that "just handles" the complexity of linking a
compiled WASM file into something the Electron browser can run.</p>
<h1>Issue the Second: WASM tools in Rust</h1>
<p>For as much as I didn't enjoy the Javascript tooling needed to interface with Rust, the Rust-only
bits aren't any better at the moment. I get it, a lot of projects are just starting off, and that
leads to a fragmented ecosystem. Here's what I can recommend as a starting point:</p>
<p>Don't check in your <code>Cargo.lock</code> files to version control. If there's a disagreement between the
version of <code>wasm-bindgen-cli</code> you have installed and the <code>wasm-bindgen</code> you're compiling with in
<code>Cargo.lock</code>, you get a nasty error:</p>
<div class="codeBlockContainer_Ckt0 theme-code-block" style="--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)"><div class=codeBlockContent_biex><pre tabindex=0 class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)"><code class=codeBlockLines_e6Vv><span class=token-line style="color:hsl(230, 8%, 24%)"><span class="token plain">it looks like the Rust project used to create this wasm file was linked against</span><br></span><span class=token-line style="color:hsl(230, 8%, 24%)"><span class="token plain">a different version of wasm-bindgen than this binary:</span><br></span><span class=token-line style="color:hsl(230, 8%, 24%)"><span class="token plain" style=display:inline-block></span><br></span><span class=token-line style="color:hsl(230, 8%, 24%)"><span class="token plain">rust wasm file: 0.2.21</span><br></span><span class=token-line style="color:hsl(230, 8%, 24%)"><span class="token plain"> this binary: 0.2.17</span><br></span><span class=token-line style="color:hsl(230, 8%, 24%)"><span class="token plain" style=display:inline-block></span><br></span><span class=token-line style="color:hsl(230, 8%, 24%)"><span class="token plain">Currently the bindgen format is unstable enough that these two version must</span><br></span><span class=token-line style="color:hsl(230, 8%, 24%)"><span class="token plain">exactly match, so it's required that these two version are kept in sync by</span><br></span><span class=token-line style="color:hsl(230, 8%, 24%)"><span class="token plain">either updating the wasm-bindgen dependency or this binary.</span><br></span></code></pre><div class=buttonGroup__atx><button type=button aria-label="Copy code to clipboard" title=Copy class=clean-btn><span class=copyButtonIcons_eSgA aria-hidden=true><svg viewBox="0 0 24 24" class=copyButtonIcon_y97N><path fill=currentColor d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"/></svg><svg viewBox="0 0 24 24" class=copyButtonSuccessIcon_LjdS><path fill=currentColor d=M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z /></svg></span></button></div></div></div>
<p>Not that I ever managed to run into this myself (<em>coughs nervously</em>).</p>
<p>There are two projects attempting to be "application frameworks": <a href=https://chinedufn.github.io/percy/ target=_blank rel="noopener noreferrer">percy</a> and <a href=https://github.com/DenisKolodin/yew target=_blank rel="noopener noreferrer">yew</a>. Between those,
I managed to get <a href=https://github.com/speice-io/isomorphic-rust/tree/master/percy target=_blank rel="noopener noreferrer">two</a>
<a href=https://github.com/speice-io/isomorphic-rust/tree/master/percy_patched_webpack target=_blank rel="noopener noreferrer">examples</a> running
using <code>percy</code>, but was unable to get an
<a href=https://github.com/speice-io/isomorphic-rust/tree/master/yew target=_blank rel="noopener noreferrer">example</a> running with <code>yew</code> because
of issues with "missing modules" during the <code>webpack</code> step:</p>
<div class="language-sh codeBlockContainer_Ckt0 theme-code-block" style="--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)"><div class=codeBlockContent_biex><pre tabindex=0 class="prism-code language-sh codeBlock_bY9V thin-scrollbar" style="background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)"><code class=codeBlockLines_e6Vv><span class=token-line style="color:hsl(230, 8%, 24%)"><span class="token plain">ERROR </span><span class="token keyword" style="color:hsl(301, 63%, 40%)">in</span><span class="token plain"> ./dist/electron_yew_wasm_bg.wasm</span><br></span><span class=token-line style="color:hsl(230, 8%, 24%)"><span class="token plain">Module not found: Error: Can</span><span class="token string" style="color:hsl(119, 34%, 47%)">'t resolve '</span><span class="token function" style="color:hsl(221, 87%, 60%)">env</span><span class="token string" style="color:hsl(119, 34%, 47%)">' in '</span><span class="token plain">/home/bspeice/Development/isomorphic_rust/yew/dist'</span><br></span><span class=token-line style="color:hsl(230, 8%, 24%)"><span class="token plain"> @ ./dist/electron_yew_wasm_bg.wasm</span><br></span><span class=token-line style="color:hsl(230, 8%, 24%)"><span class="token plain"> @ ./dist/electron_yew_wasm.js</span><br></span><span class=token-line style="color:hsl(230, 8%, 24%)"><span class="token plain"> @ ./dist/app.js</span><br></span><span class=token-line style="color:hsl(230, 8%, 24%)"><span class="token plain"> @ ./dist/app_loader.js</span><br></span></code></pre><div class=buttonGroup__atx><button type=button aria-label="Copy code to clipboard" title=Copy class=clean-btn><span class=copyButtonIcons_eSgA aria-hidden=true><svg viewBox="0 0 24 24" class=copyButtonIcon_y97N><path fill=currentColor d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"/></svg><svg viewBox="0 0 24 24" class=copyButtonSuccessIcon_LjdS><path fill=currentColor d=M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z /></svg></span></button></div></div></div>
<p>If you want to work with the browser APIs directly, your choices are <a href=https://crates.io/crates/percy-webapis target=_blank rel="noopener noreferrer">percy-webapis</a> or <a href=https://crates.io/crates/stdweb target=_blank rel="noopener noreferrer">stdweb</a> (or
eventually <a href=https://crates.io/crates/web-sys target=_blank rel="noopener noreferrer">web-sys</a>). See above for my <code>percy</code> examples, but when I tried
<a href=https://github.com/speice-io/isomorphic-rust/tree/master/stdweb target=_blank rel="noopener noreferrer">an example with <code>stdweb</code></a>, I was
unable to get it running:</p>
<div class="language-sh codeBlockContainer_Ckt0 theme-code-block" style="--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)"><div class=codeBlockContent_biex><pre tabindex=0 class="prism-code language-sh codeBlock_bY9V thin-scrollbar" style="background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)"><code class=codeBlockLines_e6Vv><span class=token-line style="color:hsl(230, 8%, 24%)"><span class="token plain">ERROR </span><span class="token keyword" style="color:hsl(301, 63%, 40%)">in</span><span class="token plain"> ./dist/stdweb_electron_bg.wasm</span><br></span><span class=token-line style="color:hsl(230, 8%, 24%)"><span class="token plain">Module not found: Error: Can</span><span class="token string" style="color:hsl(119, 34%, 47%)">'t resolve '</span><span class="token function" style="color:hsl(221, 87%, 60%)">env</span><span class="token string" style="color:hsl(119, 34%, 47%)">' in '</span><span class="token plain">/home/bspeice/Development/isomorphic_rust/stdweb/dist'</span><br></span><span class=token-line style="color:hsl(230, 8%, 24%)"><span class="token plain"> @ ./dist/stdweb_electron_bg.wasm</span><br></span><span class=token-line style="color:hsl(230, 8%, 24%)"><span class="token plain"> @ ./dist/stdweb_electron.js</span><br></span><span class=token-line style="color:hsl(230, 8%, 24%)"><span class="token plain"> @ ./dist/app_loader.js</span><br></span></code></pre><div class=buttonGroup__atx><button type=button aria-label="Copy code to clipboard" title=Copy class=clean-btn><span class=copyButtonIcons_eSgA aria-hidden=true><svg viewBox="0 0 24 24" class=copyButtonIcon_y97N><path fill=currentColor d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"/></svg><svg viewBox="0 0 24 24" class=copyButtonSuccessIcon_LjdS><path fill=currentColor d=M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z /></svg></span></button></div></div></div>
<p>At this point I'm pretty convinced that <code>stdweb</code> is causing issues for <code>yew</code> as well, but can't
prove it.</p>
<p>I did also get a <a href=https://github.com/speice-io/isomorphic-rust/tree/master/minimal target=_blank rel="noopener noreferrer">minimal example</a>
running that doesn't depend on any tools besides <code>wasm-bindgen</code>. However, it requires manually
writing "<code>extern C</code>" blocks for everything you need from the browser. Es no bueno.</p>
<p>Finally, from a tools and platform view, there are two up-and-coming packages that should be
mentioned: <a href=https://crates.io/crates/js-sys target=_blank rel="noopener noreferrer">js-sys</a> and <a href=https://crates.io/crates/web-sys target=_blank rel="noopener noreferrer">web-sys</a>. Their purpose is to be fundamental building blocks that exposes
the browser's APIs to Rust. If you're interested in building an app framework from scratch, these
should give you the most flexibility. I didn't touch either in my research, though I expect them to
be essential long-term.</p>
<p>So there's a lot in play from the Rust side of things, and it's just going to take some time to
figure out what works and what doesn't.</p>
<h1>Issue the Third: Known Unknowns</h1>
<p>Alright, so after I managed to get an application started, I stopped there. It was a good deal of
effort to chain together even a proof of concept, and at this point I'd rather learn <a href=https://www.typescriptlang.org/ target=_blank rel="noopener noreferrer">Typescript</a>
than keep trying to maintain an incredibly brittle pipeline. Blasphemy, I know...</p>
<p>The important point I want to make is that there's a lot unknown about how any of this holds up
outside proofs of concept. Things I didn't attempt:</p>
<ul>
<li>Testing</li>
<li>Packaging</li>
<li>Updates</li>
<li>Literally anything related to why I wanted to use Electron in the first place</li>
</ul>
<h1>What it Would Take</h1>
<p>Much as I don't like Javascript, the tools are too shaky for me to recommend mixing Electron and
WASM at the moment. There's a lot of innovation happening, so who knows? Someone might have an
application in production a couple months from now. But at the moment, I'm personally going to stay
away.</p>
<p>Let's finish with a wishlist then - here are the things that I think need to happen before
Electron/WASM/Rust can become a thing:</p>
<ul>
<li>Webpack still needs some updates. The necessary work is in progress, but hasn't landed yet
(<a href=https://github.com/webpack/webpack/pull/7983 target=_blank rel="noopener noreferrer">#7983</a>)</li>
<li>Browser API libraries (<code>web-sys</code> and <code>stdweb</code>) need to make sure they can support running in
Electron (see module error above)</li>
<li>Projects need to stabilize. There's talk of <code>stdweb</code> being turned into a Rust API
<a href=https://github.com/rustwasm/team/issues/226#issuecomment-418475778 target=_blank rel="noopener noreferrer">on top of web-sys</a>, and percy
<a href=https://github.com/chinedufn/percy/issues/24 target=_blank rel="noopener noreferrer">moving to web-sys</a>, both of which are big changes</li>
<li><code>wasm-bindgen</code> is great, but still in the "move fast and break things" phase</li>
<li>A good "boilerplate" app would dramatically simplify the start-up costs;
<a href=https://github.com/chentsulin/electron-react-boilerplate target=_blank rel="noopener noreferrer">electron-react-boilerplate</a> comes to
mind as a good project to imitate</li>
<li>More blog posts/contributors! I think Electron + Rust could be cool, but I have no idea what I'm
doing</li>
</ul></div></article><nav class="pagination-nav docusaurus-mt-lg" aria-label="Blog post page navigation"><a class="pagination-nav__link pagination-nav__link--prev" href=/2018/09/primitives-in-rust-are-weird><div class=pagination-nav__sublabel>Older post</div><div class=pagination-nav__label>Primitives in Rust are weird (and cool)</div></a><a class="pagination-nav__link pagination-nav__link--next" href=/2018/10/case-study-optimization><div class=pagination-nav__sublabel>Newer post</div><div class=pagination-nav__label>A case study in heaptrack</div></a></nav></main></div></div></div><footer class=footer><div class="container container-fluid"><div class="footer__bottom text--center"><div class=footer__copyright>Copyright © 2024 Bradlee Speice</div></div></div></footer></div>