rustwasm / wasm-bindgen

Facilitating high-level interactions between Wasm modules and JavaScript

Home Page:https://rustwasm.github.io/docs/wasm-bindgen/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Uncaught TypeError: Cannot read properties of undefined (reading 'length')

callmeclover opened this issue · comments

Error message

Uncaught TypeError: Cannot read properties of undefined (reading 'length') in https://cloverdev.serv00.net/pkg/rwst.js at 68:19. TypeError: Cannot read properties of undefined (reading 'length')

I used wasm-pack build --target web to generate everything in the pkg folder. I am currently unable to provide the full error message, but you can navigate to https://cloverdev.serv00.net/index.html (index.html must be specified) to see it yourself in the console. I have console-panic-error-hook, but this looks like an issue with wasm-pack. Here's my code:

lib.rs
mod model;
use model::*;

use wasm_bindgen::prelude::*;
use web_sys::{window, Element};
use ewebsock::{Options, WsEvent, WsMessage::Text};
use serde_json;
use urlencoding::encode;

extern crate console_error_panic_hook;
use std::panic;
use web_sys_main_loop::FrameState;

#[wasm_bindgen]
pub fn main() {
    panic::set_hook(Box::new(console_error_panic_hook::hook));

    let window = window().expect("no global `window` exists");
    let document = window.document().expect("should have a document on window");
    let body = document.body().expect("document should have a body");

    let (mut sender, receiver) = ewebsock::connect("wss://cloverdev.serv00.net/ws", Options::default()).expect("");
    sender.send(ewebsock::WsMessage::Text(serde_json::to_string(&MessageSent { user: "test42".to_string(), msg: "hello".to_string(), time: None }).unwrap()));
    web_sys_main_loop::start(&window, move |_frame_state: FrameState|  {
        while let Some(WsEvent::Message(Text(event))) = receiver.try_recv() {
            match serde_json::from_str::<MessageTypes>(&event).unwrap() {
                MessageTypes::MessageSent(response) => {
                    /* MESSAGE TEMPLATE:

                        <div style='margin: 10px 0;'>
                            <div class="userDisplay">
                                ${jdenticon.toSvg(username[2], 26)}
                                <span>
                                    <a href='/profile/${encodeURIComponent(username)}'>
                                        username
                                    </a>
                                    <span class="msgTime">
                                        [at <time datetime="timeSent">
                                        timeSent
                                        </time>]
                                    </span>
                                </span>
                            </div>
                            <div id='message'>
                                <pre>
                                    message
                                </pre>
                            </div>
                        </div>

                    */
                    println!("Recieved event 'MessageSent' data (1/1) {:?}", response);
                    let _ = body.append_child(&create_message_element(response.clone()));
                },
                MessageTypes::RetrieveMessages(response) => {
                    let iterator = response.msgs.iter();
                    for (i, d) in iterator.clone().enumerate() {
                        println!("Recieved event 'RetrieveMessages' data ({}/{}) {:?}", i+1, iterator.len(), d);
                        let _ = body.append_child(&create_message_element(d.clone()));
                    }
                },
                MessageTypes::UserJoin(response) => {
                    println!("Recieved event 'UserJoin' data (1/1) {:?}", response);
                },
                MessageTypes::UserLeft(response) => {
                    println!("Recieved event 'UserLeft' data (1/1) {:?}", response);
                }
            } 
        }
    });
}

fn create_message_element(res: MessageSent) -> Element {
    // Get the document and create a new div element
    let document = window().unwrap().document().unwrap();
    let outer_div = document.create_element("div").unwrap();
    outer_div.set_attribute("style", "margin: 10px 0;").unwrap();

    // Create the inner div with the class "userDisplay"
    let user_display_div = document.create_element("div").unwrap();
    user_display_div.set_class_name("userDisplay");

    // Create and append the jdenticon element
    /*let jdenticon_svg = document.create_element("svg").unwrap();
    jdenticon_svg.set_inner_html(&format!("{}", jdenticon.to_svg(username[2], 26))); We'll wait for this...
    user_display_div.append_child(&jdenticon_svg).unwrap();*/

    // Create and append the anchor element
    let anchor = document.create_element("a").unwrap();
    anchor.set_attribute("href", &format!("/profile/{}", encode(&res.user))).unwrap();
    anchor.set_text_content(Some(&res.user));
    user_display_div.append_child(&anchor).unwrap();

    // Create and append the span element with class "msgTime"
    let time_span = document.create_element("span").unwrap();
    time_span.set_class_name("msgTime");
    time_span.set_inner_html(&format!(
        "[at <time datetime='{:?}'>{}</time>]",
        res.time, res.time.expect("no time when creating msg element").format("%x %r")
    ));
    user_display_div.append_child(&time_span).unwrap();

    outer_div.append_child(&user_display_div).unwrap();

    // Create the message div with id "message" and a pre element inside
    let message_div = document.create_element("div").unwrap();
    message_div.set_id("message");

    let pre_element = document.create_element("pre").unwrap();
    pre_element.set_text_content(Some(&res.msg));

    message_div.append_child(&pre_element).unwrap();

    outer_div.append_child(&message_div).unwrap();

    return outer_div;
}
model.rs
use serde::{Deserialize, Serialize};
use chrono::{DateTime, Utc};

#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(untagged)]
pub enum MessageTypes {
  MessageSent(MessageSent),
  RetrieveMessages(RetrieveMessages),
  UserJoin(UserJoin),
  UserLeft(UserLeft)
}

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct MessageSent {
    pub msg: String,
    pub user: String,
    #[serde(skip_serializing)]
    pub time: Option<DateTime<Utc>>
}
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct RetrieveMessages {
    pub msgs: Vec<MessageSent>
}

// User related messages
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct UserJoin {
    pub userjoin: String
}
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct UserLeft {
    pub userleft: String
}
Cargo.toml
[package]
name = "rwst"
version = "0.1.0"
edition = "2021"

[package.metadata.wasm-pack.profile.release]
wasm-opt = false

[lib]
crate-type = ["cdylib"]

[dependencies]
wasm-bindgen = "0.2.92"
ewebsock = "0.5.0"
chrono = { version = "0.4.37", features = ["serde", "wasmbind"] }
serde = { version = "1.0.197", features = ["derive"] }
serde_json = "1.0.115"
urlencoding = "2.1.3"
web-sys-main-loop = "0.1.8"
console_error_panic_hook = "0.1.7"

[dependencies.web-sys]
version = "0.3.4"
features = [
  'Document',
  'Element',
  'HtmlElement',
  'Node',
  'Window',
  'BinaryType',
  'Blob',
  'ErrorEvent',
  'FileReader',
  'MessageEvent',
  'ProgressEvent',
  'WebSocket',
]
index.html
<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <title>My Rust + Webpack project!</title>
  </head>
  <body>
    <script type="module">
      import init, { main } from "./pkg/rwst.js";
      window.onerror = (a,b,c,d,e) => { window.alert(`${a} in ${b} at ${c}:${d}. ${e}`) }
      init().then(() => {
        main();
      });
    </script>
  </body>
</html>

wasm-pack doesn't appear to generate any errors, so I don't know what could be going wrong. Any help would be nice, thank you all!