From 44996f37fe616b672ba324db871500a17e7482a6 Mon Sep 17 00:00:00 2001 From: Bradlee Speice Date: Fri, 24 Jul 2020 11:56:05 -0400 Subject: [PATCH 1/7] Typo fix --- _posts/2018-09-15-isomorphic-apps.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_posts/2018-09-15-isomorphic-apps.md b/_posts/2018-09-15-isomorphic-apps.md index abc0dcb..00a926c 100644 --- a/_posts/2018-09-15-isomorphic-apps.md +++ b/_posts/2018-09-15-isomorphic-apps.md @@ -98,7 +98,7 @@ The first issue [I ran into](https://www.reddit.com/r/rust/comments/98lpun/unable_to_load_wasm_for_electron_application/) while attempting to bundle everything via `webpack` is a detail in the WASM spec: -> This function accepts a Response object, or a promise for one, and ... **[if > it] does not match +> This function accepts a Response object, or a promise for one, and ... **[if it] does not match > the `application/wasm` MIME type**, the returned promise will be rejected with a TypeError; > > [WebAssembly - Additional Web Embedding API](https://webassembly.org/docs/web/#additional-web-embedding-api) From 343b33435788adf227d58de562580d625ea063d7 Mon Sep 17 00:00:00 2001 From: Bradlee Speice Date: Fri, 24 Jul 2020 18:01:23 -0400 Subject: [PATCH 2/7] First draft of Isomorphic apps in 2020 --- _posts/2020-07-24-isomorphic-apps copy.md | 92 +++++++++++++++++++++++ 1 file changed, 92 insertions(+) create mode 100644 _posts/2020-07-24-isomorphic-apps copy.md diff --git a/_posts/2020-07-24-isomorphic-apps copy.md b/_posts/2020-07-24-isomorphic-apps copy.md new file mode 100644 index 0000000..a8a6053 --- /dev/null +++ b/_posts/2020-07-24-isomorphic-apps copy.md @@ -0,0 +1,92 @@ +--- +layout: post +title: "More Isomorphic Desktop Apps with Rust" +description: "They suck less now." +category: +tags: [rust, javascript, webassembly] +--- + +I wasn't expecting to write this, but it's 2020 and we could all use a win. When last I addressed +using WASM + Electron to write desktop applications in Rust, there were ultimately too many issues +to recommend this combination as feasible. Since then, there's been a lot of progress, and after +finding out [the biggest problem] has been addressed, I decided it was time to take another look at +where things stand. + +# Loading local WASM blobs + +Previously, the most significant issue was trying to actually load WASM blobs in Electron. This +problem was the result of a combination of factors: + +1. When using streaming WASM blobs + ([`WebAssembly.instantiateStreaming()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/instantiateStreaming)), + the blob must be returned with a `Content-Type` header of `application/wasm`. + - If the full WASM blob is loaded into memory first, the MIME type restriction does not apply. +2. When Chrome loads `file://` URLs, the `Content-Type` is unset. +3. Webpack prioritizes streaming WASM whenever available, and if it fails, has no graceful fallback. +4. When building Rust WASM binaries using `wasm-bindgen`, webpack is used to generate JS bindings + for the WASM blob. + +Putting all this together: + +- Electron loads the JS created by `wasm-bindgen`/webpack +- This JS file calls attempts to load the WASM blob, which just so happens to be located on disk +- Because the MIME type isn't set, loading fails + +This was a well-known issue; +[emscripten](https://github.com/emscripten-core/emscripten/blob/8914c5cd5e4ac35a806430e8c77c88cd8c65b234/src/preamble.js#L2295) +even included a graceful fallback for this scneario. It was possible to tweak the JS created by +`wasm-bindgen` to load WASM, but using `sed` to edit generated code will eventually lead to madness. + +I'm unable to figure out when exactly it changed, but requesting WASM blobs from `file://` URLs in +Chrome now sets the MIME type, and thus the blob is loaded correctly. Additionally, recent changes +to be released in Webpack 5 (specifically the `asyncWebAssembly` and `importAsync` +[experiments](https://webpack.js.org/configuration/experiments/)) enable loading WASM without a +separate launcher script. + +# The evolution of Rust + +Rust as a language has also made a great deal of progress since late 2018. Previously, some +widely-used crates (like `stdweb`) required a `nightly` Rust compiler to function. Now, nearly +everything compiles on `stable`. In addition, now that Rust supports `async/await`, it's much easier +to interact with Javascript. It's still necessary to use some crates like `wasm_bindgen` to assist +the interaction, but Rust can now make use of the same asynchronous paradigms that have proven to be +incredibly effective in Javascript. + +There's also been great progress on some crates to interact directly with the browser; `web-sys` and +`js-sys` enable easier interoperation with the browser, where previously users didn't have these +options available. + +The tooling and documentation has improved as well. `wasm-pack` has proven itself as a reliable "one +stop shop" tool for managing WASM projects. While using `wasm-bindgen` and `webpack` directly are +still necessary for building Electron apps (due to Webpack v5 not yet released), this should change +in the near future as well. + +# New examples + +(need to put some screenshots and link to the new examples here) + +# Outstanding issues + +While I haven't been directly involved in any of the progress made to improve Rust + WASM, it's +incredibly encouraging to see just how far everything has come. Seeing where the ecosystem stands +now, I think using Electron + Rust to build desktop applications is _feasible_. Not necessarily a +_good_ idea, not that it offers any specific benefit over using Javascript/Typescript, just that +it's now _feasible_. + +Looking forward, the things I think could be beneficial to address are: + +- Template/starter project examples + - Being able to `yarn create` a project and have it already set up with two-way JS to Rust + bindings would go a long way towards reducing the currently painful setup using either + `wasm-bindgen` or `wasm-pack`. +- Comparisons to Typescript and Neon + - Is there a development or performance benefit that comes from using Rust instead of Typescript? + WASM might execute faster, but Rust might be more tedious to develop. It would be useful to port + an existing (small) application to Rust and see what the differences are. That said, while + benchmarking WASM vs. Javascript is at least theoretically possible to do in a systematic + manner, evaluating the developer experience is like a case-by-case determination. + - Instead of embedding Rust in Electron by way of WASM, [Neon] can be used to develop extensions + that run natively and are "glued" to Electron via Javascript. Further investigation to clarify + the pros/cons of each approach would be helpful; are there situations in which WASM offers + benefits over Neon? Vice-versa? Both WASM and Neon already require more complex setups than + typical JS/TS setups. From fc502e10bc9285688a663135095d83c3006c2d23 Mon Sep 17 00:00:00 2001 From: Bradlee Speice Date: Fri, 24 Jul 2020 18:10:50 -0400 Subject: [PATCH 3/7] More notes on Typescript comparison --- _posts/2020-07-24-isomorphic-apps copy.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/_posts/2020-07-24-isomorphic-apps copy.md b/_posts/2020-07-24-isomorphic-apps copy.md index a8a6053..682fdf4 100644 --- a/_posts/2020-07-24-isomorphic-apps copy.md +++ b/_posts/2020-07-24-isomorphic-apps copy.md @@ -81,10 +81,10 @@ Looking forward, the things I think could be beneficial to address are: `wasm-bindgen` or `wasm-pack`. - Comparisons to Typescript and Neon - Is there a development or performance benefit that comes from using Rust instead of Typescript? - WASM might execute faster, but Rust might be more tedious to develop. It would be useful to port - an existing (small) application to Rust and see what the differences are. That said, while - benchmarking WASM vs. Javascript is at least theoretically possible to do in a systematic - manner, evaluating the developer experience is like a case-by-case determination. + Took some time to learn Typescript since the last post, and while it's possible that WASM might + execute faster, I'm not sure that Rust offers enough of a benefit to justify the significantly + more complex setup. It would be useful to port an existing (small) application to Rust so that + other developers can see a representative example of each and make a decision for themselves. - Instead of embedding Rust in Electron by way of WASM, [Neon] can be used to develop extensions that run natively and are "glued" to Electron via Javascript. Further investigation to clarify the pros/cons of each approach would be helpful; are there situations in which WASM offers From e8a2c794f94b10dc5ad549ecbc300b446ca532ae Mon Sep 17 00:00:00 2001 From: Bradlee Speice Date: Fri, 21 Aug 2020 14:28:15 -0400 Subject: [PATCH 4/7] Further updates --- _posts/2020-07-24-isomorphic-apps copy.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/_posts/2020-07-24-isomorphic-apps copy.md b/_posts/2020-07-24-isomorphic-apps copy.md index 682fdf4..5216c6f 100644 --- a/_posts/2020-07-24-isomorphic-apps copy.md +++ b/_posts/2020-07-24-isomorphic-apps copy.md @@ -75,6 +75,9 @@ it's now _feasible_. Looking forward, the things I think could be beneficial to address are: +Put another way, these are the things that would be necessary for me to consider moving away from +Typescript: + - Template/starter project examples - Being able to `yarn create` a project and have it already set up with two-way JS to Rust bindings would go a long way towards reducing the currently painful setup using either @@ -89,4 +92,8 @@ Looking forward, the things I think could be beneficial to address are: that run natively and are "glued" to Electron via Javascript. Further investigation to clarify the pros/cons of each approach would be helpful; are there situations in which WASM offers benefits over Neon? Vice-versa? Both WASM and Neon already require more complex setups than - typical JS/TS setups. + typical JS/TS setups. Using Rust stdlib instead of Node API's for system access is nice, being + forced into loose coupling is nice, but maybe the penalty associated with + bundling/distribution/etc. only makes sense for projects as large as Rust-analyzer, etc. +- Automatically generate bindings from TS definition files. Alternately, something like the JS + "@types" as a group to supervise maintenance of TS to Rust bindings? From 29fb26951bfbc2e24634c59d9e41060e7663210d Mon Sep 17 00:00:00 2001 From: Bradlee Speice Date: Sat, 3 Oct 2020 21:53:50 -0400 Subject: [PATCH 5/7] Different idea for an opening line --- _posts/2020-07-24-isomorphic-apps copy.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/_posts/2020-07-24-isomorphic-apps copy.md b/_posts/2020-07-24-isomorphic-apps copy.md index 5216c6f..f4c66b6 100644 --- a/_posts/2020-07-24-isomorphic-apps copy.md +++ b/_posts/2020-07-24-isomorphic-apps copy.md @@ -6,6 +6,9 @@ category: tags: [rust, javascript, webassembly] --- +In honor of Webpack 5.0 being released and dramatically easing integration of WebAssembly, it's time +to revisit previous work done to use Electron as a backend for Rust GUI applications. + I wasn't expecting to write this, but it's 2020 and we could all use a win. When last I addressed using WASM + Electron to write desktop applications in Rust, there were ultimately too many issues to recommend this combination as feasible. Since then, there's been a lot of progress, and after From 891dce905fbabb71624ea4b860ab011678ae2ed0 Mon Sep 17 00:00:00 2001 From: Bradlee Speice Date: Mon, 5 Oct 2020 00:06:41 -0400 Subject: [PATCH 6/7] Slightly more structure --- _posts/2020-07-24-isomorphic-apps copy.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/_posts/2020-07-24-isomorphic-apps copy.md b/_posts/2020-07-24-isomorphic-apps copy.md index f4c66b6..ae6ebe8 100644 --- a/_posts/2020-07-24-isomorphic-apps copy.md +++ b/_posts/2020-07-24-isomorphic-apps copy.md @@ -9,6 +9,17 @@ tags: [rust, javascript, webassembly] In honor of Webpack 5.0 being released and dramatically easing integration of WebAssembly, it's time to revisit previous work done to use Electron as a backend for Rust GUI applications. +Structure: + +- Why did I want to do this?: Potential to use Electron+WASM as Rust GUI; not truly native, but at + least experimenting with. +- Problems: Hard to use ecosystem, crates don't compile, MIME types, async loading +- What changed?: Webpack makes WASM loading asynchronous and easy in v5, Chrome now sets MIME type +- Demonstration and screenshots +- Closing thoughts: is it worth it? + +--- + I wasn't expecting to write this, but it's 2020 and we could all use a win. When last I addressed using WASM + Electron to write desktop applications in Rust, there were ultimately too many issues to recommend this combination as feasible. Since then, there's been a lot of progress, and after From 2d47b1e45c224cdf3443cb1ddfe142327a4497aa Mon Sep 17 00:00:00 2001 From: Bradlee Speice Date: Sun, 10 Nov 2024 16:02:20 -0500 Subject: [PATCH 7/7] Revert --- _posts/2018-09-15-isomorphic-apps.md | 2 +- _posts/2020-07-24-isomorphic-apps copy.md | 113 ---------------------- 2 files changed, 1 insertion(+), 114 deletions(-) delete mode 100644 _posts/2020-07-24-isomorphic-apps copy.md diff --git a/_posts/2018-09-15-isomorphic-apps.md b/_posts/2018-09-15-isomorphic-apps.md index 00a926c..abc0dcb 100644 --- a/_posts/2018-09-15-isomorphic-apps.md +++ b/_posts/2018-09-15-isomorphic-apps.md @@ -98,7 +98,7 @@ The first issue [I ran into](https://www.reddit.com/r/rust/comments/98lpun/unable_to_load_wasm_for_electron_application/) while attempting to bundle everything via `webpack` is a detail in the WASM spec: -> This function accepts a Response object, or a promise for one, and ... **[if it] does not match +> This function accepts a Response object, or a promise for one, and ... **[if > it] does not match > the `application/wasm` MIME type**, the returned promise will be rejected with a TypeError; > > [WebAssembly - Additional Web Embedding API](https://webassembly.org/docs/web/#additional-web-embedding-api) diff --git a/_posts/2020-07-24-isomorphic-apps copy.md b/_posts/2020-07-24-isomorphic-apps copy.md deleted file mode 100644 index ae6ebe8..0000000 --- a/_posts/2020-07-24-isomorphic-apps copy.md +++ /dev/null @@ -1,113 +0,0 @@ ---- -layout: post -title: "More Isomorphic Desktop Apps with Rust" -description: "They suck less now." -category: -tags: [rust, javascript, webassembly] ---- - -In honor of Webpack 5.0 being released and dramatically easing integration of WebAssembly, it's time -to revisit previous work done to use Electron as a backend for Rust GUI applications. - -Structure: - -- Why did I want to do this?: Potential to use Electron+WASM as Rust GUI; not truly native, but at - least experimenting with. -- Problems: Hard to use ecosystem, crates don't compile, MIME types, async loading -- What changed?: Webpack makes WASM loading asynchronous and easy in v5, Chrome now sets MIME type -- Demonstration and screenshots -- Closing thoughts: is it worth it? - ---- - -I wasn't expecting to write this, but it's 2020 and we could all use a win. When last I addressed -using WASM + Electron to write desktop applications in Rust, there were ultimately too many issues -to recommend this combination as feasible. Since then, there's been a lot of progress, and after -finding out [the biggest problem] has been addressed, I decided it was time to take another look at -where things stand. - -# Loading local WASM blobs - -Previously, the most significant issue was trying to actually load WASM blobs in Electron. This -problem was the result of a combination of factors: - -1. When using streaming WASM blobs - ([`WebAssembly.instantiateStreaming()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/instantiateStreaming)), - the blob must be returned with a `Content-Type` header of `application/wasm`. - - If the full WASM blob is loaded into memory first, the MIME type restriction does not apply. -2. When Chrome loads `file://` URLs, the `Content-Type` is unset. -3. Webpack prioritizes streaming WASM whenever available, and if it fails, has no graceful fallback. -4. When building Rust WASM binaries using `wasm-bindgen`, webpack is used to generate JS bindings - for the WASM blob. - -Putting all this together: - -- Electron loads the JS created by `wasm-bindgen`/webpack -- This JS file calls attempts to load the WASM blob, which just so happens to be located on disk -- Because the MIME type isn't set, loading fails - -This was a well-known issue; -[emscripten](https://github.com/emscripten-core/emscripten/blob/8914c5cd5e4ac35a806430e8c77c88cd8c65b234/src/preamble.js#L2295) -even included a graceful fallback for this scneario. It was possible to tweak the JS created by -`wasm-bindgen` to load WASM, but using `sed` to edit generated code will eventually lead to madness. - -I'm unable to figure out when exactly it changed, but requesting WASM blobs from `file://` URLs in -Chrome now sets the MIME type, and thus the blob is loaded correctly. Additionally, recent changes -to be released in Webpack 5 (specifically the `asyncWebAssembly` and `importAsync` -[experiments](https://webpack.js.org/configuration/experiments/)) enable loading WASM without a -separate launcher script. - -# The evolution of Rust - -Rust as a language has also made a great deal of progress since late 2018. Previously, some -widely-used crates (like `stdweb`) required a `nightly` Rust compiler to function. Now, nearly -everything compiles on `stable`. In addition, now that Rust supports `async/await`, it's much easier -to interact with Javascript. It's still necessary to use some crates like `wasm_bindgen` to assist -the interaction, but Rust can now make use of the same asynchronous paradigms that have proven to be -incredibly effective in Javascript. - -There's also been great progress on some crates to interact directly with the browser; `web-sys` and -`js-sys` enable easier interoperation with the browser, where previously users didn't have these -options available. - -The tooling and documentation has improved as well. `wasm-pack` has proven itself as a reliable "one -stop shop" tool for managing WASM projects. While using `wasm-bindgen` and `webpack` directly are -still necessary for building Electron apps (due to Webpack v5 not yet released), this should change -in the near future as well. - -# New examples - -(need to put some screenshots and link to the new examples here) - -# Outstanding issues - -While I haven't been directly involved in any of the progress made to improve Rust + WASM, it's -incredibly encouraging to see just how far everything has come. Seeing where the ecosystem stands -now, I think using Electron + Rust to build desktop applications is _feasible_. Not necessarily a -_good_ idea, not that it offers any specific benefit over using Javascript/Typescript, just that -it's now _feasible_. - -Looking forward, the things I think could be beneficial to address are: - -Put another way, these are the things that would be necessary for me to consider moving away from -Typescript: - -- Template/starter project examples - - Being able to `yarn create` a project and have it already set up with two-way JS to Rust - bindings would go a long way towards reducing the currently painful setup using either - `wasm-bindgen` or `wasm-pack`. -- Comparisons to Typescript and Neon - - Is there a development or performance benefit that comes from using Rust instead of Typescript? - Took some time to learn Typescript since the last post, and while it's possible that WASM might - execute faster, I'm not sure that Rust offers enough of a benefit to justify the significantly - more complex setup. It would be useful to port an existing (small) application to Rust so that - other developers can see a representative example of each and make a decision for themselves. - - Instead of embedding Rust in Electron by way of WASM, [Neon] can be used to develop extensions - that run natively and are "glued" to Electron via Javascript. Further investigation to clarify - the pros/cons of each approach would be helpful; are there situations in which WASM offers - benefits over Neon? Vice-versa? Both WASM and Neon already require more complex setups than - typical JS/TS setups. Using Rust stdlib instead of Node API's for system access is nice, being - forced into loose coupling is nice, but maybe the penalty associated with - bundling/distribution/etc. only makes sense for projects as large as Rust-analyzer, etc. -- Automatically generate bindings from TS definition files. Alternately, something like the JS - "@types" as a group to supervise maintenance of TS to Rust bindings?