feat: allow autoreload websocket connection to work outside of localhost (#1548)
* Updated client reloading to use window.location.protocol/host to determine websocket connection. Added optional config reload_external_port to provide further control of the client websocket connection. These changes allow reloading while accessing the served site from outside of localhost.
This commit is contained in:
parent
abeca70625
commit
a789100e22
|
@ -7,14 +7,18 @@ extern crate tracing;
|
|||
|
||||
#[tracing::instrument(level = "trace", fields(error), skip_all)]
|
||||
fn autoreload(nonce_str: &str, options: &LeptosOptions) -> String {
|
||||
let site_ip = &options.site_addr.ip().to_string();
|
||||
let reload_port = options.reload_port;
|
||||
let reload_port = match options.reload_external_port {
|
||||
Some(val) => val,
|
||||
None => options.reload_port,
|
||||
};
|
||||
match std::env::var("LEPTOS_WATCH").is_ok() {
|
||||
true => format!(
|
||||
r#"
|
||||
<script crossorigin=""{nonce_str}>(function () {{
|
||||
{}
|
||||
let ws = new WebSocket('ws://{site_ip}:{reload_port}/live_reload');
|
||||
let protocol = window.location.protocol === 'https:' ? 'wss://' : 'ws://';
|
||||
let host = window.location.hostname;
|
||||
let ws = new WebSocket(protocol + host + ':{reload_port}/live_reload');
|
||||
ws.onmessage = (ev) => {{
|
||||
let msg = JSON.parse(ev.data);
|
||||
if (msg.all) window.location.reload();
|
||||
|
|
|
@ -56,6 +56,11 @@ pub struct LeptosOptions {
|
|||
#[builder(default = default_reload_port())]
|
||||
#[serde(default = "default_reload_port")]
|
||||
pub reload_port: u32,
|
||||
/// The port the Websocket watcher listens on when on the client, e.g., when behind a reverse proxy.
|
||||
/// Defaults to match reload_port
|
||||
#[builder(default)]
|
||||
#[serde(default)]
|
||||
pub reload_external_port: Option<u32>,
|
||||
}
|
||||
|
||||
impl LeptosOptions {
|
||||
|
@ -84,6 +89,12 @@ impl LeptosOptions {
|
|||
.parse()?,
|
||||
reload_port: env_w_default("LEPTOS_RELOAD_PORT", "3001")?
|
||||
.parse()?,
|
||||
reload_external_port: match env_wo_default(
|
||||
"LEPTOS_RELOAD_EXTERNAL_PORT",
|
||||
)? {
|
||||
Some(val) => Some(val.parse()?),
|
||||
None => None,
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -107,7 +118,13 @@ fn default_site_addr() -> SocketAddr {
|
|||
fn default_reload_port() -> u32 {
|
||||
3001
|
||||
}
|
||||
|
||||
fn env_wo_default(key: &str) -> Result<Option<String>, LeptosConfigError> {
|
||||
match std::env::var(key) {
|
||||
Ok(val) => Ok(Some(val)),
|
||||
Err(VarError::NotPresent) => Ok(None),
|
||||
Err(e) => Err(LeptosConfigError::EnvVarError(format!("{key}: {e}"))),
|
||||
}
|
||||
}
|
||||
fn env_w_default(
|
||||
key: &str,
|
||||
default: &str,
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use crate::{env_w_default, from_str, Env, LeptosOptions};
|
||||
use crate::{env_w_default, env_wo_default, from_str, Env, LeptosOptions};
|
||||
use std::{net::SocketAddr, str::FromStr};
|
||||
|
||||
#[test]
|
||||
|
@ -29,6 +29,17 @@ fn env_w_default_test() {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn env_wo_default_test() {
|
||||
std::env::set_var("LEPTOS_CONFIG_ENV_TEST", "custom");
|
||||
assert_eq!(
|
||||
env_wo_default("LEPTOS_CONFIG_ENV_TEST").unwrap(),
|
||||
Some(String::from("custom"))
|
||||
);
|
||||
std::env::remove_var("LEPTOS_CONFIG_ENV_TEST");
|
||||
assert_eq!(env_wo_default("LEPTOS_CONFIG_ENV_TEST").unwrap(), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn try_from_env_test() {
|
||||
// Test config values from environment variables
|
||||
|
@ -37,6 +48,7 @@ fn try_from_env_test() {
|
|||
std::env::set_var("LEPTOS_SITE_PKG_DIR", "my_pkg");
|
||||
std::env::set_var("LEPTOS_SITE_ADDR", "0.0.0.0:80");
|
||||
std::env::set_var("LEPTOS_RELOAD_PORT", "8080");
|
||||
std::env::set_var("LEPTOS_RELOAD_EXTERNAL_PORT", "8080");
|
||||
|
||||
let config = LeptosOptions::try_from_env().unwrap();
|
||||
assert_eq!(config.output_name, "app_test");
|
||||
|
@ -48,4 +60,5 @@ fn try_from_env_test() {
|
|||
SocketAddr::from_str("0.0.0.0:80").unwrap()
|
||||
);
|
||||
assert_eq!(config.reload_port, 8080);
|
||||
assert_eq!(config.reload_external_port, Some(8080));
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@ site-root = "my_target/site"
|
|||
site-pkg-dir = "my_pkg"
|
||||
site-addr = "0.0.0.0:80"
|
||||
reload-port = "8080"
|
||||
reload-external-port = "8080"
|
||||
env = "PROD"
|
||||
"#;
|
||||
|
||||
|
@ -27,6 +28,7 @@ _site-root = "my_target/site"
|
|||
_site-pkg-dir = "my_pkg"
|
||||
_site-addr = "0.0.0.0:80"
|
||||
_reload-port = "8080"
|
||||
_reload-external-port = "8080"
|
||||
_env = "PROD"
|
||||
"#;
|
||||
|
||||
|
@ -54,6 +56,7 @@ async fn get_configuration_from_file_ok() {
|
|||
SocketAddr::from_str("0.0.0.0:80").unwrap()
|
||||
);
|
||||
assert_eq!(config.reload_port, 8080);
|
||||
assert_eq!(config.reload_external_port, Some(8080));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
|
@ -101,6 +104,7 @@ async fn get_config_from_file_ok() {
|
|||
SocketAddr::from_str("0.0.0.0:80").unwrap()
|
||||
);
|
||||
assert_eq!(config.reload_port, 8080);
|
||||
assert_eq!(config.reload_external_port, Some(8080));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
|
@ -136,6 +140,7 @@ fn get_config_from_str_content() {
|
|||
SocketAddr::from_str("0.0.0.0:80").unwrap()
|
||||
);
|
||||
assert_eq!(config.reload_port, 8080);
|
||||
assert_eq!(config.reload_external_port, Some(8080));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
|
@ -146,6 +151,7 @@ async fn get_config_from_env() {
|
|||
std::env::set_var("LEPTOS_SITE_PKG_DIR", "my_pkg");
|
||||
std::env::set_var("LEPTOS_SITE_ADDR", "0.0.0.0:80");
|
||||
std::env::set_var("LEPTOS_RELOAD_PORT", "8080");
|
||||
std::env::set_var("LEPTOS_RELOAD_EXTERNAL_PORT", "8080");
|
||||
|
||||
let config = get_configuration(None).await.unwrap().leptos_options;
|
||||
assert_eq!(config.output_name, "app-test");
|
||||
|
@ -157,12 +163,14 @@ async fn get_config_from_env() {
|
|||
SocketAddr::from_str("0.0.0.0:80").unwrap()
|
||||
);
|
||||
assert_eq!(config.reload_port, 8080);
|
||||
assert_eq!(config.reload_external_port, Some(8080));
|
||||
|
||||
// Test default config values
|
||||
std::env::remove_var("LEPTOS_SITE_ROOT");
|
||||
std::env::remove_var("LEPTOS_SITE_PKG_DIR");
|
||||
std::env::remove_var("LEPTOS_SITE_ADDR");
|
||||
std::env::remove_var("LEPTOS_RELOAD_PORT");
|
||||
std::env::set_var("LEPTOS_RELOAD_EXTERNAL_PORT", "443");
|
||||
|
||||
let config = get_configuration(None).await.unwrap().leptos_options;
|
||||
assert_eq!(config.site_root, "target/site");
|
||||
|
@ -172,6 +180,7 @@ async fn get_config_from_env() {
|
|||
SocketAddr::from_str("127.0.0.1:3000").unwrap()
|
||||
);
|
||||
assert_eq!(config.reload_port, 3001);
|
||||
assert_eq!(config.reload_external_port, Some(443));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -186,4 +195,5 @@ fn leptos_options_builder_default() {
|
|||
SocketAddr::from_str("127.0.0.1:3000").unwrap()
|
||||
);
|
||||
assert_eq!(conf.reload_port, 3001);
|
||||
assert_eq!(conf.reload_external_port, None);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue