Skip to main content

leptos/
subsecond.rs

1use dioxus_devtools::DevserverMsg;
2use wasm_bindgen::{prelude::Closure, JsCast};
3use web_sys::{js_sys::JsString, MessageEvent, WebSocket};
4
5/// Sets up a websocket connect to the `dx` CLI, waiting for incoming hot-patching messages
6/// and patching the WASM binary appropriately.
7//
8//  Note: This is a stripped-down version of Dioxus's `make_ws` from `dioxus_web`
9//  It's essentially copy-pasted here because it's not pub there.
10//  Would love to just take a dependency on that to be able to use it and deduplicate.
11//
12//  https://github.com/DioxusLabs/dioxus/blob/main/packages/web/src/devtools.rs#L36
13pub fn connect_to_hot_patch_messages() {
14    // Get the location of the devserver, using the current location plus the /_dioxus path
15    // The idea here being that the devserver is always located on the /_dioxus behind a proxy
16    let location = web_sys::window().unwrap().location();
17    let url = format!(
18        "{protocol}//{host}/_dioxus?build_id={build_id}",
19        protocol = match location.protocol().unwrap() {
20            prot if prot == "https:" => "wss:",
21            _ => "ws:",
22        },
23        host = location.host().unwrap(),
24        build_id = dioxus_cli_config::build_id(),
25    );
26
27    let ws = WebSocket::new(&url).unwrap();
28
29    ws.set_onmessage(Some(
30        Closure::<dyn FnMut(MessageEvent)>::new(move |e: MessageEvent| {
31            let Ok(text) = e.data().dyn_into::<JsString>() else {
32                return;
33            };
34
35            // The devserver messages have some &'static strs in them, so we need to leak the source string
36            let string: String = text.into();
37            let string = Box::leak(string.into_boxed_str());
38
39            if let Ok(DevserverMsg::HotReload(msg)) =
40                serde_json::from_str::<DevserverMsg>(string)
41            {
42                if let Some(jump_table) = msg.jump_table.as_ref().cloned() {
43                    if msg.for_build_id == Some(dioxus_cli_config::build_id()) {
44                        let our_pid = if cfg!(target_family = "wasm") {
45                            None
46                        } else {
47                            Some(std::process::id())
48                        };
49
50                        if msg.for_pid == our_pid {
51                            unsafe { subsecond::apply_patch(jump_table) }
52                                .unwrap();
53                        }
54                    }
55                }
56            }
57        })
58        .into_js_value()
59        .as_ref()
60        .unchecked_ref(),
61    ));
62}