pub(crate) fn connect_to_reload_server(live_reload_tx: Sender<()>) {
    // We have to do this to assert that it's only used once, allowing us to use it in the `Closure::wrap()` (see https://github.com/rustwasm/wasm-bindgen/issues/1269#issuecomment-465184149)
    let mut live_reload_tx = Some(live_reload_tx);

    // Get the host and port
    let host = get_window_var("__PERSEUS_RELOAD_SERVER_HOST");
    let port = get_window_var("__PERSEUS_RELOAD_SERVER_PORT");
    let (host, port) = match (host, port) {
        (Some(host), Some(port)) => (host, port),
        // If either the host or port weren't set, the server almost certainly isn't online, so we
        // won't connect
        _ => return,
    };

    // Connect to the server (it's expected that the host does not include a
    // protocol)
    let ws = match WebSocket::new(&format!("ws://{}:{}/receive", host, port)) {
        Ok(ws) => ws,
        Err(err) => return log(&format!("Connection failed: {:?}.", err)),
    };
    // This is apparently more efficient for small binary messages
    ws.set_binary_type(web_sys::BinaryType::Arraybuffer);

    // Set up a message handler
    let onmessage_callback = Closure::wrap(Box::new(move |_| {
        // With this server, if we receive any message it will be telling us to reload,
        // so we'll do so
        log("Reloading...");
        // Signal the rest of the code that we need to reload (and potentially freeze
        // state if HSR is enabled)
        match live_reload_tx.take() {
            Some(tx) => { tx.send(()).unwrap(); },
            None => log("Reload sender already invoked. It's likely that multiple reload events have occurred in too rapid succession. If the page does not reload in a matter of seconds, you should manually reload.")
        }
    }) as Box<dyn FnMut(MessageEvent)>);
    ws.set_onmessage(Some(onmessage_callback.as_ref().unchecked_ref()));
    // To keep the closure alive, we need to forget about it
    onmessage_callback.forget();

    // We should log to the console about errors from the server
    let onerror_callback = Closure::wrap(Box::new(move |err: ErrorEvent| {
        log(&format!("Error: {:?}.", err));
    }) as Box<dyn FnMut(ErrorEvent)>);
    ws.set_onerror(Some(onerror_callback.as_ref().unchecked_ref()));
    onerror_callback.forget();

    // We'll just log when the connection is successfully established for
    // informational purposes
    let onopen_callback = Closure::wrap(Box::new(move |_| {
        log("Connected.");
    }) as Box<dyn FnMut(JsValue)>);
    ws.set_onopen(Some(onopen_callback.as_ref().unchecked_ref()));
    onopen_callback.forget();
}
Connects to the reload server if it's online. This takes a flip-flop
`RcSignal` that it can use to signal other parts of the code to perform
actual reloading (we can't do that here because we don't have access to the
render context for freezing and thawing).

We need to use an `RcSignal` here due to the requirements of closure
wrapping (lifetime scopes do not work there).
packages/perseus/src/state/live_reload.rs