Last active
July 30, 2023 03:48
Revisions
-
craftyc0der revised this gist
Nov 27, 2022 . 1 changed file with 0 additions and 811 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,811 +0,0 @@ -
craftyc0der renamed this gist
Nov 27, 2022 . 1 changed file with 0 additions and 0 deletions.There are no files selected for viewing
File renamed without changes. -
craftyc0der revised this gist
Nov 27, 2022 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -189,7 +189,7 @@ The `update` function is responsible for processing the messages sent from the J The rest of the code is just for rendering the data returned from Firebase.  ## Run this *gist* -
craftyc0der revised this gist
Nov 27, 2022 . 1 changed file with 0 additions and 2 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,2 +0,0 @@ -
craftyc0der revised this gist
Nov 27, 2022 . 6 changed files with 15 additions and 14 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -5,6 +5,10 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [[bin]] name = "gist-yew-firebase" path = "main.rs" [dependencies] yew = { version = "0.20.0", features = ["csr"] } wasm-bindgen = {version = "^0.2"} This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -58,7 +58,9 @@ You can find my `index.html` below in this *gist*. The critical thing to include The sample website we will build here will query a Firebase database for a list of rows that contain an object that contains a haiku poem. We will then render these data in the DOM using Yew. Because the Firebase SDK provided by Google is written in JavaScript, we will need `wasm-bindgen` to bridge the gap between Rust and JavaScript. In order to squeeze this into a *gist*, I've flattened the directory structure. Normally the `.rs` files would be in a `src` directory. #### Create main.rs You can find my `main.rs` below in this *gist*. @@ -81,7 +83,7 @@ For this example, the critical pieces are in `create` and `update`. We query Fir #### Write JavaScript code to interact with Firebase You can find my `index.js` below in this *gist*. ```javascript const app = initializeApp(firebaseConfig); @@ -110,24 +112,24 @@ export function getHaiku(fnHaikuClear, fnHaikuAdd) { #### Setup `wasm-bindgen` for the JavaScript code You can find my `caller.rs` below in this *gist*. ```rust use wasm_bindgen::prelude::*; // wasm-bindgen will automatically take care of including this script #[wasm_bindgen(module = "/index.js")] extern "C" { #[wasm_bindgen(js_name = "getHaiku")] pub fn get_haiku(callbackClear: JsValue, callbackAdd: JsValue); } ``` This basically tells `wasm-bindgen` to include the `index.js` file in the final wasm file it creates and to expose the `getHaiku` function to Rust as `get_haiku(callbackClear: JsValue, callbackAdd: JsValue)`. #### Bring it all together in main.rs You can find my `main.rs` below in this *gist*. The `create` function is responsible for querying Firebase and setting up the callbacks to process the data returned from Firebase. Note we do not manage the closures in the Rust compiler. We are cheating a little here and just using the `.into_js_value()` method to convert the closures to a `JsValue` which calls `drop()` on the closure so that we can call it multiple times in JavaScript land. This is not ideal, but it works for this example. This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,7 +1,7 @@ use wasm_bindgen::prelude::*; // wasm-bindgen will automatically take care of including this script #[wasm_bindgen(module = "/index.js")] extern "C" { #[wasm_bindgen(js_name = "getHaiku")] pub fn get_haiku(callbackClear: JsValue, callbackAdd: JsValue); File renamed without changes.This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,11 +1,7 @@ use yew::prelude::*; use yew::{Component, Context, Html}; use wasm_bindgen::{JsValue, closure::Closure}; mod caller; pub enum Msg { HaikuClear, This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1 +0,0 @@ -
craftyc0der revised this gist
Nov 27, 2022 . 1 changed file with 6 additions and 0 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -189,6 +189,12 @@ The rest of the code is just for rendering the data returned from Firebase.  ## Run this *gist* ```bash trunk serve ``` ## Future Work It would be a much better experience if we used `wasm-bindgen` to control the Firebase SDK directly rather than using the JavaScript SDK. This would allow us to use Rust types and memory management rather than having to convert everything to `JsValue` and back again. We could take that a step further and build idiomatic Rust wrappers around the Firebase SDK to make it more intuitive to use. -
craftyc0der revised this gist
Nov 27, 2022 . No changes.There are no files selected for viewing
-
craftyc0der created this gist
Nov 27, 2022 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,2 @@ /target /dist This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,811 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. version = 3 [[package]] name = "anymap2" version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d301b3b94cb4b2f23d7917810addbbaff90738e0ca2be692bd027e70d7e0330c" [[package]] name = "autocfg" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" [[package]] name = "bincode" version = "1.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" dependencies = [ "serde", ] [[package]] name = "boolinator" version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cfa8873f51c92e232f9bac4065cddef41b714152812bfc5f7672ba16d6ef8cd9" [[package]] name = "bumpalo" version = "3.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "572f695136211188308f16ad2ca5c851a712c464060ae6974944458eb83880ba" [[package]] name = "cfg-if" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "console_error_panic_hook" version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc" dependencies = [ "cfg-if", "wasm-bindgen", ] [[package]] name = "fnv" version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] name = "form_urlencoded" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a9c384f161156f5260c24a097c56119f9be8c798586aecc13afbcbe7b7e26bf8" dependencies = [ "percent-encoding", ] [[package]] name = "futures" version = "0.3.25" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "38390104763dc37a5145a53c29c63c1290b5d316d6086ec32c293f6736051bb0" dependencies = [ "futures-channel", "futures-core", "futures-io", "futures-sink", "futures-task", "futures-util", ] [[package]] name = "futures-channel" version = "0.3.25" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "52ba265a92256105f45b719605a571ffe2d1f0fea3807304b522c1d778f79eed" dependencies = [ "futures-core", "futures-sink", ] [[package]] name = "futures-core" version = "0.3.25" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04909a7a7e4633ae6c4a9ab280aeb86da1236243a77b694a49eacd659a4bd3ac" [[package]] name = "futures-io" version = "0.3.25" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "00f5fb52a06bdcadeb54e8d3671f8888a39697dcb0b81b23b55174030427f4eb" [[package]] name = "futures-macro" version = "0.3.25" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bdfb8ce053d86b91919aad980c220b1fb8401a9394410e1c289ed7e66b61835d" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "futures-sink" version = "0.3.25" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39c15cf1a4aa79df40f1bb462fb39676d0ad9e366c2a33b590d7c66f4f81fcf9" [[package]] name = "futures-task" version = "0.3.25" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2ffb393ac5d9a6eaa9d3fdf37ae2776656b706e200c8e16b1bdb227f5198e6ea" [[package]] name = "futures-util" version = "0.3.25" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "197676987abd2f9cadff84926f410af1c183608d36641465df73ae8211dc65d6" dependencies = [ "futures-channel", "futures-core", "futures-io", "futures-macro", "futures-sink", "futures-task", "memchr", "pin-project-lite", "pin-utils", "slab", ] [[package]] name = "gist-yew-firebase" version = "0.1.0" dependencies = [ "wasm-bindgen", "yew", ] [[package]] name = "gloo" version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3a4bef6b277b3ab073253d4bca60761240cf8d6998f4bd142211957b69a61b20" dependencies = [ "gloo-console", "gloo-dialogs", "gloo-events", "gloo-file", "gloo-history", "gloo-net", "gloo-render", "gloo-storage", "gloo-timers", "gloo-utils", "gloo-worker", ] [[package]] name = "gloo-console" version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "82b7ce3c05debe147233596904981848862b068862e9ec3e34be446077190d3f" dependencies = [ "gloo-utils", "js-sys", "serde", "wasm-bindgen", "web-sys", ] [[package]] name = "gloo-dialogs" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "67062364ac72d27f08445a46cab428188e2e224ec9e37efdba48ae8c289002e6" dependencies = [ "wasm-bindgen", "web-sys", ] [[package]] name = "gloo-events" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68b107f8abed8105e4182de63845afcc7b69c098b7852a813ea7462a320992fc" dependencies = [ "wasm-bindgen", "web-sys", ] [[package]] name = "gloo-file" version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8d5564e570a38b43d78bdc063374a0c3098c4f0d64005b12f9bbe87e869b6d7" dependencies = [ "gloo-events", "js-sys", "wasm-bindgen", "web-sys", ] [[package]] name = "gloo-history" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f81af52c0d31e86242eecefe1ed4d066deb79cfb80f9f7da0847fac417396bfe" dependencies = [ "gloo-events", "gloo-utils", "serde", "serde-wasm-bindgen", "serde_urlencoded", "thiserror", "wasm-bindgen", "web-sys", ] [[package]] name = "gloo-net" version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec897194fb9ac576c708f63d35604bc58f2a262b8cec0fabfed26f3991255f21" dependencies = [ "futures-channel", "futures-core", "futures-sink", "gloo-utils", "js-sys", "pin-project", "serde", "serde_json", "thiserror", "wasm-bindgen", "wasm-bindgen-futures", "web-sys", ] [[package]] name = "gloo-render" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2fd9306aef67cfd4449823aadcd14e3958e0800aa2183955a309112a84ec7764" dependencies = [ "wasm-bindgen", "web-sys", ] [[package]] name = "gloo-storage" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5d6ab60bf5dbfd6f0ed1f7843da31b41010515c745735c970e821945ca91e480" dependencies = [ "gloo-utils", "js-sys", "serde", "serde_json", "thiserror", "wasm-bindgen", "web-sys", ] [[package]] name = "gloo-timers" version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5fb7d06c1c8cc2a29bee7ec961009a0b2caa0793ee4900c2ffb348734ba1c8f9" dependencies = [ "js-sys", "wasm-bindgen", ] [[package]] name = "gloo-utils" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "40913a05c8297adca04392f707b1e73b12ba7b8eab7244a4961580b1fd34063c" dependencies = [ "js-sys", "serde", "serde_json", "wasm-bindgen", "web-sys", ] [[package]] name = "gloo-worker" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13471584da78061a28306d1359dd0178d8d6fc1c7c80e5e35d27260346e0516a" dependencies = [ "anymap2", "bincode", "gloo-console", "gloo-utils", "js-sys", "serde", "wasm-bindgen", "wasm-bindgen-futures", "web-sys", ] [[package]] name = "hashbrown" version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" [[package]] name = "hermit-abi" version = "0.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" dependencies = [ "libc", ] [[package]] name = "implicit-clone" version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a937e630d3907d421944abd8edb5288936f1fde83aaaf1a8c6c89bb4222f0677" dependencies = [ "indexmap", ] [[package]] name = "indexmap" version = "1.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399" dependencies = [ "autocfg", "hashbrown", ] [[package]] name = "itoa" version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4217ad341ebadf8d8e724e264f13e593e0648f5b3e94b3896a5df283be015ecc" [[package]] name = "js-sys" version = "0.3.60" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49409df3e3bf0856b916e2ceaca09ee28e6871cf7d9ce97a692cacfdb2a25a47" dependencies = [ "wasm-bindgen", ] [[package]] name = "libc" version = "0.2.137" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc7fcc620a3bff7cdd7a365be3376c97191aeaccc2a603e600951e452615bf89" [[package]] name = "log" version = "0.4.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" dependencies = [ "cfg-if", ] [[package]] name = "memchr" version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" [[package]] name = "num_cpus" version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f6058e64324c71e02bc2b150e4f3bc8286db6c83092132ffa3f6b1eab0f9def5" dependencies = [ "hermit-abi", "libc", ] [[package]] name = "once_cell" version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860" [[package]] name = "percent-encoding" version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" [[package]] name = "pin-project" version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ad29a609b6bcd67fee905812e544992d216af9d755757c05ed2d0e15a74c6ecc" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "069bdb1e05adc7a8990dce9cc75370895fbe4e3d58b9b73bf1aee56359344a55" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "pin-project-lite" version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" [[package]] name = "pin-utils" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "pinned" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a829027bd95e54cfe13e3e258a1ae7b645960553fb82b75ff852c29688ee595b" dependencies = [ "futures", "rustversion", "thiserror", ] [[package]] name = "prettyplease" version = "0.1.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c142c0e46b57171fe0c528bee8c5b7569e80f0c17e377cd0e30ea57dbc11bb51" dependencies = [ "proc-macro2", "syn", ] [[package]] name = "proc-macro-error" version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" dependencies = [ "proc-macro-error-attr", "proc-macro2", "quote", "syn", "version_check", ] [[package]] name = "proc-macro-error-attr" version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" dependencies = [ "proc-macro2", "quote", "version_check", ] [[package]] name = "proc-macro2" version = "1.0.47" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5ea3d908b0e36316caf9e9e2c4625cdde190a7e6f440d794667ed17a1855e725" dependencies = [ "unicode-ident", ] [[package]] name = "prokio" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "03b55e106e5791fa5a13abd13c85d6127312e8e09098059ca2bc9b03ca4cf488" dependencies = [ "futures", "gloo", "num_cpus", "once_cell", "pin-project", "pinned", "tokio", "tokio-stream", "wasm-bindgen-futures", ] [[package]] name = "quote" version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179" dependencies = [ "proc-macro2", ] [[package]] name = "rustversion" version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "97477e48b4cf8603ad5f7aaf897467cf42ab4218a38ef76fb14c2d6773a6d6a8" [[package]] name = "ryu" version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4501abdff3ae82a1c1b477a17252eb69cee9e66eb915c1abaa4f44d873df9f09" [[package]] name = "serde" version = "1.0.147" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d193d69bae983fc11a79df82342761dfbf28a99fc8d203dca4c3c1b590948965" dependencies = [ "serde_derive", ] [[package]] name = "serde-wasm-bindgen" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "618365e8e586c22123d692b72a7d791d5ee697817b65a218cdf12a98870af0f7" dependencies = [ "fnv", "js-sys", "serde", "wasm-bindgen", ] [[package]] name = "serde_derive" version = "1.0.147" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4f1d362ca8fc9c3e3a7484440752472d68a6caa98f1ab81d99b5dfe517cec852" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "serde_json" version = "1.0.89" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "020ff22c755c2ed3f8cf162dbb41a7268d934702f3ed3631656ea597e08fc3db" dependencies = [ "itoa", "ryu", "serde", ] [[package]] name = "serde_urlencoded" version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" dependencies = [ "form_urlencoded", "itoa", "ryu", "serde", ] [[package]] name = "slab" version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4614a76b2a8be0058caa9dbbaf66d988527d86d003c11a94fbd335d7661edcef" dependencies = [ "autocfg", ] [[package]] name = "syn" version = "1.0.103" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a864042229133ada95abf3b54fdc62ef5ccabe9515b64717bcb9a1919e59445d" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] [[package]] name = "thiserror" version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "10deb33631e3c9018b9baf9dcbbc4f737320d2b576bac10f6aefa048fa407e3e" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "982d17546b47146b28f7c22e3d08465f6b8903d0ea13c1660d9d84a6e7adcdbb" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "tokio" version = "1.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d76ce4a75fb488c605c54bf610f221cea8b0dafb53333c1a67e8ee199dcd2ae3" dependencies = [ "autocfg", "pin-project-lite", ] [[package]] name = "tokio-stream" version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d660770404473ccd7bc9f8b28494a811bc18542b915c0855c51e8f419d5223ce" dependencies = [ "futures-core", "pin-project-lite", "tokio", ] [[package]] name = "tracing" version = "0.1.37" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" dependencies = [ "cfg-if", "pin-project-lite", "tracing-attributes", "tracing-core", ] [[package]] name = "tracing-attributes" version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4017f8f45139870ca7e672686113917c71c7a6e02d4924eda67186083c03081a" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "tracing-core" version = "0.1.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24eb03ba0eab1fd845050058ce5e616558e8f8d8fca633e6b163fe25c797213a" dependencies = [ "once_cell", ] [[package]] name = "unicode-ident" version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3" [[package]] name = "version_check" version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "wasm-bindgen" version = "0.2.83" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eaf9f5aceeec8be17c128b2e93e031fb8a4d469bb9c4ae2d7dc1888b26887268" dependencies = [ "cfg-if", "serde", "serde_json", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" version = "0.2.83" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c8ffb332579b0557b52d268b91feab8df3615f265d5270fec2a8c95b17c1142" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", "syn", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" version = "0.4.33" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "23639446165ca5a5de86ae1d8896b737ae80319560fbaa4c2887b7da6e7ebd7d" dependencies = [ "cfg-if", "js-sys", "wasm-bindgen", "web-sys", ] [[package]] name = "wasm-bindgen-macro" version = "0.2.83" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "052be0f94026e6cbc75cdefc9bae13fd6052cdcaf532fa6c45e7ae33a1e6c810" dependencies = [ "quote", "wasm-bindgen-macro-support", ] [[package]] name = "wasm-bindgen-macro-support" version = "0.2.83" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "07bc0c051dc5f23e307b13285f9d75df86bfdf816c5721e573dec1f9b8aa193c" dependencies = [ "proc-macro2", "quote", "syn", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" version = "0.2.83" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1c38c045535d93ec4f0b4defec448e4291638ee608530863b1e2ba115d4fff7f" [[package]] name = "web-sys" version = "0.3.60" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bcda906d8be16e728fd5adc5b729afad4e444e106ab28cd1c7256e54fa61510f" dependencies = [ "js-sys", "wasm-bindgen", ] [[package]] name = "yew" version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5dbecfe44343b70cc2932c3eb445425969ae21754a8ab3a0966981c1cf7af1cc" dependencies = [ "console_error_panic_hook", "futures", "gloo", "implicit-clone", "indexmap", "js-sys", "prokio", "rustversion", "serde", "slab", "thiserror", "tokio", "tracing", "wasm-bindgen", "wasm-bindgen-futures", "web-sys", "yew-macro", ] [[package]] name = "yew-macro" version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b64c253c1d401f1ea868ca9988db63958cfa15a69f739101f338d6f05eea8301" dependencies = [ "boolinator", "once_cell", "prettyplease", "proc-macro-error", "proc-macro2", "quote", "syn", ] This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,10 @@ [package] name = "gist-yew-firebase" version = "0.1.0" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] yew = { version = "0.20.0", features = ["csr"] } wasm-bindgen = {version = "^0.2"} This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,198 @@ # Firebase & Yew ## Motivation I often use [Firebase](https://firebase.google.com/docs/reference/js) to store data for small projects. I've been using `wasm-bindgen` to build web tools for a while now (both in production and for personal use). Until now, I have not tried Yew to build a web app. If Yew works well with Firebase, I thought I might give it a shot for the next single page app (SPA) I build. ## Goals - Create basic Yew page - Add Firebase JS SDK - Write minimal JS code to interact with Firebase and do all rendering in Rust/Yew via callbacks ## Steps ### [Setup Yew](https://yew.rs/docs/getting-started/introduction) #### Setup Rust environment for wasm32-unknown-unknown target: ```bash rustup target add wasm32-unknown-unknown ``` #### Install Trunk (packaging tool) ```bash cargo install --locked trunk ``` ### [Setup Sample Yew App](https://yew.rs/docs/getting-started/build-a-sample-app) #### Create a new Yew project ```bash cargo new yew-app cd yew-app ``` #### Update Cargo.toml to use Yew and wasm-bindgen ```toml ... [dependencies] yew = { version = "0.20.0", features = ["csr"] } wasm-bindgen = {version = "^0.2"} ``` #### Create index.html You can find my `index.html` below in this *gist*. The critical thing to include is the hint for `trunk` to render the wasm files it creates. ```html <head> ... <link data-trunk rel="rust" /> </head> ``` ### Website Premise The sample website we will build here will query a Firebase database for a list of rows that contain an object that contains a haiku poem. We will then render these data in the DOM using Yew. Because the Firebase SDK provided by Google is written in JavaScript, we will need `wasm-bindgen` to bridge the gap between Rust and JavaScript. #### Create src/main.rs You can find my `main.rs` below in this *gist*. Things of note: - `Msg` enum is used to define messages that can be sent to the `HaikuPage` struct which is the main component of the app - `Msg::HaikuClear` is used to send a message to the `HaikuPage` to clear the haiku data - `Msg::HaikuRecord(Haiku)` is used to send a message to the `HaikuPage` to add a new haiku to the list - `Haiku` struct stores a single haiku row from Firebase - Firebase stores three fields for each haiku 1. `int64` id 2. `int64` featured 3. `string` text - `HaikuPage` struct is the main component of the app - `haikus` is a vector of `Haiku` structs You should read the [Yew Documentation on Lifecycles](https://yew.rs/docs/advanced-topics/struct-components/lifecycle) to understand how the `create`, `update`, `view`, and `changed` functions work. For this example, the critical pieces are in `create` and `update`. We query Firebase in the `create` function and process the callbacks from Javascript land within the `update` function. #### Write JavaScript code to interact with Firebase You can find my `src/js/index.js` below in this *gist*. ```javascript const app = initializeApp(firebaseConfig); const database = getDatabase(app); // query Firebase for Haiku // `fnHaikuClear` and `fnHaikuAdd` are closures defined in Rust // that emit `Msg` messages to the `HaikuPage` `update` function export function getHaiku(fnHaikuClear, fnHaikuAdd) { const haikuRef = query(ref(database, 'haiku/'), orderByChild("featured")); onValue(haikuRef, (snapshot) => { // when data is returned, clear the current haiku list by // calling a closure passed in from the Rust fnHaikuClear(); // then loop over the returned data snapshot.forEach((childSnapshot) => { var childKey = childSnapshot.key; var childData = childSnapshot.val(); // and send each haiku to the Rust closure passed in above fnHaikuAdd(childKey, childData.featured, childData.text); }); }); console.log("Get Haiku"); } ``` #### Setup `wasm-bindgen` for the JavaScript code You can find my `src/js/caller.rs` below in this *gist*. ```rust use wasm_bindgen::prelude::*; // wasm-bindgen will automatically take care of including this script #[wasm_bindgen(module = "/src/js/index.js")] extern "C" { #[wasm_bindgen(js_name = "getHaiku")] pub fn get_haiku(callbackClear: JsValue, callbackAdd: JsValue); } ``` This basically tells `wasm-bindgen` to include the `src/js/index.js` file in the final wasm file it creates and to expose the `getHaiku` function to Rust as `get_haiku(callbackClear: JsValue, callbackAdd: JsValue)`. #### Bring it all together in src/main.rs You can find my `src/main.rs` below in this *gist*. The `create` function is responsible for querying Firebase and setting up the callbacks to process the data returned from Firebase. Note we do not manage the closures in the Rust compiler. We are cheating a little here and just using the `.into_js_value()` method to convert the closures to a `JsValue` which calls `drop()` on the closure so that we can call it multiple times in JavaScript land. This is not ideal, but it works for this example. ```rust fn create(ctx: &Context<Self>) -> Self { // define callback for clearing the haiku list let callback_clear = ctx.link().callback(|_| Msg::HaikuClear); // define closure for clearing the haiku list let closure_clear = Closure::wrap(Box::new(move || { // call the clear callback // we want to clear the data array before we update all the data callback_clear.emit(()); }) as Box<dyn FnMut()>); // define callback for adding a haiku to the list let callback_add = ctx.link().callback(Msg::HaikuRecord); // define closure for adding a haiku to the list let closure_add = Closure::wrap(Box::new(move |key: JsValue, featured: JsValue, text: JsValue| { let key_str = key.as_string().unwrap(); let featured_int = featured.as_f64().unwrap() as i64; let key_int = key_str.parse::<i64>().unwrap(); let haiku = Haiku { id: key_int, featured: featured_int, content: text.as_string().unwrap(), }; callback_add.emit(haiku); }) as Box<dyn FnMut(JsValue, JsValue, JsValue)>); // call the get_haiku function in index.js // we use `into_js_value()` to convert the closures into javacript managed closures // they are no longer managed by rust // an unfortunate side effect of needing to use these more than once in JS land caller::get_haiku(closure_clear.into_js_value(), closure_add.into_js_value()); Self { haikus: Vec::new(), } } ``` The `update` function is responsible for processing the messages sent from the JavaScript land via the closures defined above. ```rust fn update(&mut self, _ctx: &Context<Self>, msg: Self::Message) -> bool { match msg { Msg::HaikuClear => { // clear the haiku list self.haikus.clear(); true } Msg::HaikuRecord(haiku) => { // add a haiku to the list self.haikus.push(haiku); true } } } ``` The rest of the code is just for rendering the data returned from Firebase.  ## Future Work It would be a much better experience if we used `wasm-bindgen` to control the Firebase SDK directly rather than using the JavaScript SDK. This would allow us to use Rust types and memory management rather than having to convert everything to `JsValue` and back again. We could take that a step further and build idiomatic Rust wrappers around the Firebase SDK to make it more intuitive to use. ## Conclusion Yew is an interesting framework. I am more accustomed to using [Lit](https://lit.dev/) and [Angular](https://angular.io/) for web development. I would be happier if Yew had first class debugging support. I think the solution is to build a lib around all the business logic so that you can debug that independently from the wasm code. But, that is a topic for another day. This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,20 @@ <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1" /> <title>Firebase & Yew</title> <base data-trunk-public-url /> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bulma@0.9.0/css/bulma.min.css" /> <link data-trunk rel="sass" href="index.scss" /> <link data-trunk rel="rust" /> </head> <body> </body> </html> This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,18 @@ .hero { &.has-background { position: relative; overflow: hidden; } &-background { position: absolute; object-fit: cover; object-position: bottom; width: 100%; height: 100%; &.is-transparent { opacity: 0.3; } } } LoadingSorry, something went wrong. Reload?Sorry, we cannot display this file.Sorry, this file is invalid so it cannot be displayed.This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,8 @@ use wasm_bindgen::prelude::*; // wasm-bindgen will automatically take care of including this script #[wasm_bindgen(module = "/src/js/index.js")] extern "C" { #[wasm_bindgen(js_name = "getHaiku")] pub fn get_haiku(callbackClear: JsValue, callbackAdd: JsValue); } This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,37 @@ // import Firebase 9.14.0 SDK import { initializeApp } from "https://www.gstatic.com/firebasejs/9.14.0/firebase-app.js"; import { getDatabase, query, onValue, orderByChild, ref } from "https://www.gstatic.com/firebasejs/9.14.0/firebase-database.js"; // Initialize Firebase const firebaseConfig = { apiKey: "AIzaSyDM0TICdsfwD0Mj3j__oULR5EQg__hFTl0", authDomain: "craftycoder-e95a2.firebaseapp.com", databaseURL: "https://craftycoder-e95a2.firebaseio.com", projectId: "craftycoder-e95a2", storageBucket: "craftycoder-e95a2.appspot.com", messagingSenderId: "605879826235", appId: "1:605879826235:web:59773e7c77b01c6b6b691e", measurementId: "G-JS38X3LLBK" }; const app = initializeApp(firebaseConfig); const database = getDatabase(app); // query Firebase for Haiku // `fnHaikuClear` and `fnHaikuAdd` are closures defined in Rust // that emit `Msg` messages to the `HaikuPage` `update` function export function getHaiku(fnHaikuClear, fnHaikuAdd) { const haikuRef = query(ref(database, 'haiku/'), orderByChild("featured")); onValue(haikuRef, (snapshot) => { // when data is returned, clear the current haiku list by // calling a closure passed in from the Rust fnHaikuClear(); // then loop over the returned data snapshot.forEach((childSnapshot) => { var childKey = childSnapshot.key; var childData = childSnapshot.val(); // and send each haiku to the Rust closure passed in above fnHaikuAdd(childKey, childData.featured, childData.text); }); }); console.log("Get Haiku"); } This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1 @@ pub mod caller; This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,140 @@ use yew::prelude::*; use yew::{Component, Context, Html}; use wasm_bindgen::{JsValue, closure::Closure}; mod js; use crate::{ js::caller }; pub enum Msg { HaikuClear, HaikuRecord(Haiku), } #[derive(Clone, Debug, Eq, PartialEq)] pub struct Haiku { pub id: i64, pub featured: i64, pub content: String, } pub struct HaikuPage { haikus: Vec<Haiku>, } impl Component for HaikuPage { type Message = Msg; type Properties = (); fn create(ctx: &Context<Self>) -> Self { // define callback for clearing the haiku list let callback_clear = ctx.link().callback(|_| Msg::HaikuClear); // define closure for clearing the haiku list let closure_clear = Closure::wrap(Box::new(move || { // call the clear callback // we want to clear the data array before we update all the data callback_clear.emit(()); }) as Box<dyn FnMut()>); // define callback for adding a haiku to the list let callback_add = ctx.link().callback(Msg::HaikuRecord); // define closure for adding a haiku to the list let closure_add = Closure::wrap(Box::new(move |key: JsValue, featured: JsValue, text: JsValue| { let key_str = key.as_string().unwrap(); let featured_int = featured.as_f64().unwrap() as i64; let key_int = key_str.parse::<i64>().unwrap(); let haiku = Haiku { id: key_int, featured: featured_int, content: text.as_string().unwrap(), }; callback_add.emit(haiku); }) as Box<dyn FnMut(JsValue, JsValue, JsValue)>); // call the get_haiku function in index.js // we use `into_js_value()` to convert the closures into javacript managed closures // they are no longer managed by rust // an unfortunate side effect of needing to use these more than once in JS land caller::get_haiku(closure_clear.into_js_value(), closure_add.into_js_value()); Self { haikus: Vec::new(), } } fn changed(&mut self, _ctx: &Context<Self>, _old_props: &Self::Properties) -> bool { true } fn update(&mut self, _ctx: &Context<Self>, msg: Self::Message) -> bool { match msg { Msg::HaikuClear => { // clear the haiku list // log::info!("clear"); self.haikus.clear(); true } Msg::HaikuRecord(haiku) => { // add a haiku to the list // log::info!("value: {:?}", value); self.haikus.push(haiku); true } } } fn view(&self, _ctx: &Context<Self>) -> Html { html! { <> <section class="hero is-small is-light has-background"> <div class="hero-body"> <div class="container"> <h1 class="title"> { "Haiku" } </h1> </div> </div> </section> <div class="section container"> { self.view_content() } </div> </> } } } impl HaikuPage { fn view_content(&self) -> Html { html! { <div class="columns is-multiline is-mobile"> // loop through the haiku list { for self.haikus.iter().map(|haiku| { //split haiku into array on <br> let haiku_array: Vec<&str> = haiku.content.split("<br>").collect(); html! { <div class="column is-half"> <div class="card"> <div class="card-content"> <div class="content"> <h5 style="text-align: center;"> { for haiku_array.iter().map(|line| { html! { <div> { line } </div> } }) } </h5> </div> </div> </div> </div> }}) } </div> } } } fn main() { yew::Renderer::<HaikuPage>::new().render(); } -
craftyc0der created this gist
Nov 27, 2022 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,198 @@ # Firebase & Yew ## Motivation I often use [Firebase](https://firebase.google.com/docs/reference/js) to store data for small projects. I've been using `wasm-bindgen` to build web tools for a while now (both in production and for personal use). Until now, I have not tried Yew to build a web app. If Yew works well with Firebase, I thought I might give it a shot for the next single page app (SPA) I build. ## Goals - Create basic Yew page - Add Firebase JS SDK - Write minimal JS code to interact with Firebase and do all rendering in Rust/Yew via callbacks ## Steps ### [Setup Yew](https://yew.rs/docs/getting-started/introduction) #### Setup Rust environment for wasm32-unknown-unknown target: ```bash rustup target add wasm32-unknown-unknown ``` #### Install Trunk (packaging tool) ```bash cargo install --locked trunk ``` ### [Setup Sample Yew App](https://yew.rs/docs/getting-started/build-a-sample-app) #### Create a new Yew project ```bash cargo new yew-app cd yew-app ``` #### Update Cargo.toml to use Yew and wasm-bindgen ```toml ... [dependencies] yew = { version = "0.20.0", features = ["csr"] } wasm-bindgen = {version = "^0.2"} ``` #### Create index.html You can find my `index.html` below in this *gist*. The critical thing to include is the hint for `trunk` to render the wasm files it creates. ```html <head> ... <link data-trunk rel="rust" /> </head> ``` ### Website Premise The sample website we will build here will query a Firebase database for a list of rows that contain an object that contains a haiku poem. We will then render these data in the DOM using Yew. Because the Firebase SDK provided by Google is written in JavaScript, we will need `wasm-bindgen` to bridge the gap between Rust and JavaScript. #### Create src/main.rs You can find my `main.rs` below in this *gist*. Things of note: - `Msg` enum is used to define messages that can be sent to the `HaikuPage` struct which is the main component of the app - `Msg::HaikuClear` is used to send a message to the `HaikuPage` to clear the haiku data - `Msg::HaikuRecord(Haiku)` is used to send a message to the `HaikuPage` to add a new haiku to the list - `Haiku` struct stores a single haiku row from Firebase - Firebase stores three fields for each haiku 1. `int64` id 2. `int64` featured 3. `string` text - `HaikuPage` struct is the main component of the app - `haikus` is a vector of `Haiku` structs You should read the [Yew Documentation on Lifecycles](https://yew.rs/docs/advanced-topics/struct-components/lifecycle) to understand how the `create`, `update`, `view`, and `changed` functions work. For this example, the critical pieces are in `create` and `update`. We query Firebase in the `create` function and process the callbacks from Javascript land within the `update` function. #### Write JavaScript code to interact with Firebase You can find my `src/js/index.js` below in this *gist*. ```javascript const app = initializeApp(firebaseConfig); const database = getDatabase(app); // query Firebase for Haiku // `fnHaikuClear` and `fnHaikuAdd` are closures defined in Rust // that emit `Msg` messages to the `HaikuPage` `update` function export function getHaiku(fnHaikuClear, fnHaikuAdd) { const haikuRef = query(ref(database, 'haiku/'), orderByChild("featured")); onValue(haikuRef, (snapshot) => { // when data is returned, clear the current haiku list by // calling a closure passed in from the Rust fnHaikuClear(); // then loop over the returned data snapshot.forEach((childSnapshot) => { var childKey = childSnapshot.key; var childData = childSnapshot.val(); // and send each haiku to the Rust closure passed in above fnHaikuAdd(childKey, childData.featured, childData.text); }); }); console.log("Get Haiku"); } ``` #### Setup `wasm-bindgen` for the JavaScript code You can find my `src/js/caller.rs` below in this *gist*. ```rust use wasm_bindgen::prelude::*; // wasm-bindgen will automatically take care of including this script #[wasm_bindgen(module = "/src/js/index.js")] extern "C" { #[wasm_bindgen(js_name = "getHaiku")] pub fn get_haiku(callbackClear: JsValue, callbackAdd: JsValue); } ``` This basically tells `wasm-bindgen` to include the `src/js/index.js` file in the final wasm file it creates and to expose the `getHaiku` function to Rust as `get_haiku(callbackClear: JsValue, callbackAdd: JsValue)`. #### Bring it all together in src/main.rs You can find my `src/main.rs` below in this *gist*. The `create` function is responsible for querying Firebase and setting up the callbacks to process the data returned from Firebase. Note we do not manage the closures in the Rust compiler. We are cheating a little here and just using the `.into_js_value()` method to convert the closures to a `JsValue` which calls `drop()` on the closure so that we can call it multiple times in JavaScript land. This is not ideal, but it works for this example. ```rust fn create(ctx: &Context<Self>) -> Self { // define callback for clearing the haiku list let callback_clear = ctx.link().callback(|_| Msg::HaikuClear); // define closure for clearing the haiku list let closure_clear = Closure::wrap(Box::new(move || { // call the clear callback // we want to clear the data array before we update all the data callback_clear.emit(()); }) as Box<dyn FnMut()>); // define callback for adding a haiku to the list let callback_add = ctx.link().callback(Msg::HaikuRecord); // define closure for adding a haiku to the list let closure_add = Closure::wrap(Box::new(move |key: JsValue, featured: JsValue, text: JsValue| { let key_str = key.as_string().unwrap(); let featured_int = featured.as_f64().unwrap() as i64; let key_int = key_str.parse::<i64>().unwrap(); let haiku = Haiku { id: key_int, featured: featured_int, content: text.as_string().unwrap(), }; callback_add.emit(haiku); }) as Box<dyn FnMut(JsValue, JsValue, JsValue)>); // call the get_haiku function in index.js // we use `into_js_value()` to convert the closures into javacript managed closures // they are no longer managed by rust // an unfortunate side effect of needing to use these more than once in JS land caller::get_haiku(closure_clear.into_js_value(), closure_add.into_js_value()); Self { haikus: Vec::new(), } } ``` The `update` function is responsible for processing the messages sent from the JavaScript land via the closures defined above. ```rust fn update(&mut self, _ctx: &Context<Self>, msg: Self::Message) -> bool { match msg { Msg::HaikuClear => { // clear the haiku list self.haikus.clear(); true } Msg::HaikuRecord(haiku) => { // add a haiku to the list self.haikus.push(haiku); true } } } ``` The rest of the code is just for rendering the data returned from Firebase.  ## Future Work It would be a much better experience if we used `wasm-bindgen` to control the Firebase SDK directly rather than using the JavaScript SDK. This would allow us to use Rust types and memory management rather than having to convert everything to `JsValue` and back again. We could take that a step further and build idiomatic Rust wrappers around the Firebase SDK to make it more intuitive to use. ## Conclusion Yew is an interesting framework. I am more accustomed to using [Lit](https://lit.dev/) and [Angular](https://angular.io/) for web development. I would be happier if Yew had first class debugging support. I think the solution is to build a lib around all the business logic so that you can debug that independently from the wasm code. But, that is a topic for another day.