siku2 / rust-monaco

Rust WASM bindings for the Monaco Editor
Apache License 2.0
76 stars 25 forks source link

Uncaught Error: Unexpected usage #54

Open madser123 opened 3 months ago

madser123 commented 3 months ago

When using a modified version of the yew_events_keymapping example, i get the following error messages whenever the editor is updated (Scrolling, keyevents and alike):

Uncaught (in promise) Error: Unexpected usage
    at EditorSimpleWorker.loadForeignModule (3ee02a56-2661-4101-9e85-07319f48ff9f:11101:35)
    at SimpleWorkerServer._handleMessage (3ee02a56-2661-4101-9e85-07319f48ff9f:1630:69)
    at Object.handleMessage (3ee02a56-2661-4101-9e85-07319f48ff9f:1615:55)
    at SimpleWorkerProtocol._handleRequestMessage (3ee02a56-2661-4101-9e85-07319f48ff9f:1520:40)
    at SimpleWorkerProtocol._handleMessage (3ee02a56-2661-4101-9e85-07319f48ff9f:1489:33)
    at SimpleWorkerProtocol.handleMessage (3ee02a56-2661-4101-9e85-07319f48ff9f:1482:18)
    at SimpleWorkerServer.onmessage (3ee02a56-2661-4101-9e85-07319f48ff9f:1620:28)
    at self.onmessage (3ee02a56-2661-4101-9e85-07319f48ff9f:11141:26)
Uncaught Error: Unexpected usage

Error: Unexpected usage
    at EditorSimpleWorker.loadForeignModule (3ee02a56-2661-4101-9e85-07319f48ff9f:11101:35)
    at SimpleWorkerServer._handleMessage (3ee02a56-2661-4101-9e85-07319f48ff9f:1630:69)
    at Object.handleMessage (3ee02a56-2661-4101-9e85-07319f48ff9f:1615:55)
    at SimpleWorkerProtocol._handleRequestMessage (3ee02a56-2661-4101-9e85-07319f48ff9f:1520:40)
    at SimpleWorkerProtocol._handleMessage (3ee02a56-2661-4101-9e85-07319f48ff9f:1489:33)
    at SimpleWorkerProtocol.handleMessage (3ee02a56-2661-4101-9e85-07319f48ff9f:1482:18)
    at SimpleWorkerServer.onmessage (3ee02a56-2661-4101-9e85-07319f48ff9f:1620:28)
    at self.onmessage (3ee02a56-2661-4101-9e85-07319f48ff9f:11141:26)
    at editor.js:3484:27

The code in question is like so:

use crate::prelude::*;
use monaco::{
    api::{CodeEditorOptions, TextModel},
    sys::editor::{BuiltinTheme, IStandaloneCodeEditor},
    yew::{CodeEditor, CodeEditorLink},
};

const CONTENT: &str = include_str!("../../example.js");

fn get_options(init_code: String) -> CodeEditorOptions {
    CodeEditorOptions::default()
        .with_language("javascript".to_owned())
        .with_value(init_code)
        .with_builtin_theme(BuiltinTheme::VsDark)
        .with_automatic_layout(true)
}

fn save_content(content: String) {
    console_log!("Content: {}", content);
}

#[derive(PartialEq, Properties)]
pub struct CustomEditorProps {
    on_editor_created: Callback<CodeEditorLink>,
    text_model: TextModel,
}

#[function_component]
pub fn CustomEditor(props: &CustomEditorProps) -> Html {
    let CustomEditorProps {
        on_editor_created,
        text_model,
    } = props;

    let code = text_model.get_value();

    html! {
        <CodeEditor classes={"full-height"} options={ get_options(code).to_sys_options() } {on_editor_created} model={text_model.clone()} />
    }
}

#[derive(PartialEq, Properties)]
pub struct EditorProps {
    #[prop_or(String::from(CONTENT))]
    code: String,
}

#[function_component]
pub fn Editor(props: &EditorProps) -> Html {
    // We need to create a new text model, so we can pass it to Monaco.
    // We use use_state_eq, as this allows us to only use it when it changes.
    let text_model = use_state_eq(|| {
        TextModel::create(&props.code, Some("javascript"), None)
            .expect("Failed to create TextModel")
    });

    // Here we setup the Callback for when the editor is created.
    let on_editor_created = {
        // We need to clone the text_model/code so we can use them.
        let text_model = text_model.clone();

        // This is a javascript closure, used to pass to Monaco, using wasm-bindgen.
        let js_closure = {
            let text_model = text_model.clone();

            // We update the code state when the Monaco model changes.
            // See https://yew.rs/docs/0.20.0/concepts/function-components/pre-defined-hooks
            Closure::<dyn Fn()>::new(move || save_content(text_model.get_value()))
        };

        // Here we define our callback, we use use_callback as we want to re-render when dependencies change.
        // See https://yew.rs/docs/concepts/function-components/state#general-view-of-how-to-store-state
        use_callback(
            text_model,
            move |editor_link: CodeEditorLink, _text_model| {
                editor_link.with_editor(|editor| {
                    // Registers Ctrl/Cmd + Enter hotkey
                    let keycode = monaco::sys::KeyCode::KeyS.to_value()
                        | (monaco::sys::KeyMod::ctrl_cmd() as u32);
                    let raw_editor: &IStandaloneCodeEditor = editor.as_ref();

                    raw_editor.add_command(
                        keycode.into(),
                        js_closure.as_ref().unchecked_ref(),
                        None,
                    );
                });
            },
        )
    };
    html! {
        <CustomEditor {on_editor_created} text_model={(*text_model).clone()} />
    }
}

I'm using the main branch, as the yew 21.0 update isn't on crates.io yet.

Import in Cargo.toml:

monaco = { git = "ssh://git@github.com/siku2/rust-monaco.git", features = ["yew-components"], branch = "main" }

After reading issues on the monaco github, it seems to relate to the way the editor is set up, but i might be wrong. Is there something i can do to resolve this? Or is this an issue with the way the editor is set up in the library?

Edit: Everything else works, it's just the errors that are the "issue".

Edit: I also can confirm that the example i derived this from, does work exactly as intended, without any errors. I just don't see how the code in question actually changes anything related to throwing the error.

madser123 commented 3 months ago

Update: This, seemingly, happens when i switch to using Javascript instead of Rust as the langauge.

Datron commented 1 month ago

@madser123 This is happening because the typescript/javascript worker for monaco is missing in the build. You can add it manually as I have. That solved this issue for me.

@siku2 should I raise a PR to add support for Typescript/Javascript?

siku2 commented 1 month ago

should I raise a PR to add support for Typescript/Javascript?

please do, @Datron, your changes look good.