mirror of
https://github.com/leptos-rs/leptos
synced 2024-11-10 14:54:16 +00:00
feat: add reload websocket configuration and enable env configuration (#1613)
This commit is contained in:
parent
f5b4b97c9b
commit
d9e83121c1
3 changed files with 109 additions and 23 deletions
|
@ -11,14 +11,17 @@ fn autoreload(nonce_str: &str, options: &LeptosOptions) -> String {
|
||||||
Some(val) => val,
|
Some(val) => val,
|
||||||
None => options.reload_port,
|
None => options.reload_port,
|
||||||
};
|
};
|
||||||
|
let protocol = match options.reload_ws_protocol {
|
||||||
|
leptos_config::ReloadWSProtocol::WS => "'ws://'",
|
||||||
|
leptos_config::ReloadWSProtocol::WSS => "'wss://'",
|
||||||
|
};
|
||||||
match std::env::var("LEPTOS_WATCH").is_ok() {
|
match std::env::var("LEPTOS_WATCH").is_ok() {
|
||||||
true => format!(
|
true => format!(
|
||||||
r#"
|
r#"
|
||||||
<script crossorigin=""{nonce_str}>(function () {{
|
<script crossorigin=""{nonce_str}>(function () {{
|
||||||
{}
|
{}
|
||||||
let protocol = window.location.protocol === 'https:' ? 'wss://' : 'ws://';
|
|
||||||
let host = window.location.hostname;
|
let host = window.location.hostname;
|
||||||
let ws = new WebSocket(protocol + host + ':{reload_port}/live_reload');
|
let ws = new WebSocket({protocol} + host + ':{reload_port}/live_reload');
|
||||||
ws.onmessage = (ev) => {{
|
ws.onmessage = (ev) => {{
|
||||||
let msg = JSON.parse(ev.data);
|
let msg = JSON.parse(ev.data);
|
||||||
if (msg.all) window.location.reload();
|
if (msg.all) window.location.reload();
|
||||||
|
|
|
@ -61,6 +61,11 @@ pub struct LeptosOptions {
|
||||||
#[builder(default)]
|
#[builder(default)]
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub reload_external_port: Option<u32>,
|
pub reload_external_port: Option<u32>,
|
||||||
|
/// The protocol the Websocket watcher uses on the client: `ws` in most cases, `wss` when behind a reverse https proxy.
|
||||||
|
/// Defaults to `ws`
|
||||||
|
#[builder(default)]
|
||||||
|
#[serde(default)]
|
||||||
|
pub reload_ws_protocol: ReloadWSProtocol,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LeptosOptions {
|
impl LeptosOptions {
|
||||||
|
@ -84,7 +89,7 @@ impl LeptosOptions {
|
||||||
output_name,
|
output_name,
|
||||||
site_root: env_w_default("LEPTOS_SITE_ROOT", "target/site")?,
|
site_root: env_w_default("LEPTOS_SITE_ROOT", "target/site")?,
|
||||||
site_pkg_dir: env_w_default("LEPTOS_SITE_PKG_DIR", "pkg")?,
|
site_pkg_dir: env_w_default("LEPTOS_SITE_PKG_DIR", "pkg")?,
|
||||||
env: Env::default(),
|
env: env_from_str(env_w_default("LEPTOS_ENV", "DEV")?.as_str())?,
|
||||||
site_addr: env_w_default("LEPTOS_SITE_ADDR", "127.0.0.1:3000")?
|
site_addr: env_w_default("LEPTOS_SITE_ADDR", "127.0.0.1:3000")?
|
||||||
.parse()?,
|
.parse()?,
|
||||||
reload_port: env_w_default("LEPTOS_RELOAD_PORT", "3001")?
|
reload_port: env_w_default("LEPTOS_RELOAD_PORT", "3001")?
|
||||||
|
@ -95,6 +100,9 @@ impl LeptosOptions {
|
||||||
Some(val) => Some(val.parse()?),
|
Some(val) => Some(val.parse()?),
|
||||||
None => None,
|
None => None,
|
||||||
},
|
},
|
||||||
|
reload_ws_protocol: ws_from_str(
|
||||||
|
env_w_default("LEPTOS_RELOAD_WS_PROTOCOL", "ws")?.as_str(),
|
||||||
|
)?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -151,45 +159,103 @@ impl Default for Env {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn from_str(input: &str) -> Result<Env, String> {
|
fn env_from_str(input: &str) -> Result<Env, LeptosConfigError> {
|
||||||
let sanitized = input.to_lowercase();
|
let sanitized = input.to_lowercase();
|
||||||
match sanitized.as_ref() {
|
match sanitized.as_ref() {
|
||||||
"dev" | "development" => Ok(Env::DEV),
|
"dev" | "development" => Ok(Env::DEV),
|
||||||
"prod" | "production" => Ok(Env::PROD),
|
"prod" | "production" => Ok(Env::PROD),
|
||||||
_ => Err(format!(
|
_ => Err(LeptosConfigError::EnvVarError(format!(
|
||||||
"{input} is not a supported environment. Use either `dev` or \
|
"{input} is not a supported environment. Use either `dev` or \
|
||||||
`production`.",
|
`production`.",
|
||||||
)),
|
))),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FromStr for Env {
|
impl FromStr for Env {
|
||||||
type Err = ();
|
type Err = ();
|
||||||
fn from_str(input: &str) -> Result<Self, Self::Err> {
|
fn from_str(input: &str) -> Result<Self, Self::Err> {
|
||||||
from_str(input).or_else(|_| Ok(Self::default()))
|
env_from_str(input).or_else(|_| Ok(Self::default()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<&str> for Env {
|
impl From<&str> for Env {
|
||||||
fn from(str: &str) -> Self {
|
fn from(str: &str) -> Self {
|
||||||
from_str(str).unwrap_or_else(|err| panic!("{}", err))
|
env_from_str(str).unwrap_or_else(|err| panic!("{}", err))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<&Result<String, VarError>> for Env {
|
impl From<&Result<String, VarError>> for Env {
|
||||||
fn from(input: &Result<String, VarError>) -> Self {
|
fn from(input: &Result<String, VarError>) -> Self {
|
||||||
match input {
|
match input {
|
||||||
Ok(str) => from_str(str).unwrap_or_else(|err| panic!("{}", err)),
|
Ok(str) => {
|
||||||
|
env_from_str(str).unwrap_or_else(|err| panic!("{}", err))
|
||||||
|
}
|
||||||
Err(_) => Self::default(),
|
Err(_) => Self::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFrom<String> for Env {
|
impl TryFrom<String> for Env {
|
||||||
type Error = String;
|
type Error = LeptosConfigError;
|
||||||
|
|
||||||
fn try_from(s: String) -> Result<Self, Self::Error> {
|
fn try_from(s: String) -> Result<Self, Self::Error> {
|
||||||
from_str(s.as_str())
|
env_from_str(s.as_str())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// An enum that can be used to define the websocket protocol Leptos uses for hotreloading
|
||||||
|
/// Defaults to `ws`.
|
||||||
|
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, PartialEq, Eq)]
|
||||||
|
pub enum ReloadWSProtocol {
|
||||||
|
WS,
|
||||||
|
WSS,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for ReloadWSProtocol {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::WS
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ws_from_str(input: &str) -> Result<ReloadWSProtocol, LeptosConfigError> {
|
||||||
|
let sanitized = input.to_lowercase();
|
||||||
|
match sanitized.as_ref() {
|
||||||
|
"ws" | "WS" => Ok(ReloadWSProtocol::WS),
|
||||||
|
"wss" | "WSS" => Ok(ReloadWSProtocol::WSS),
|
||||||
|
_ => Err(LeptosConfigError::EnvVarError(format!(
|
||||||
|
"{input} is not a supported websocket protocol. Use only `ws` or \
|
||||||
|
`wss`.",
|
||||||
|
))),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromStr for ReloadWSProtocol {
|
||||||
|
type Err = ();
|
||||||
|
fn from_str(input: &str) -> Result<Self, Self::Err> {
|
||||||
|
ws_from_str(input).or_else(|_| Ok(Self::default()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&str> for ReloadWSProtocol {
|
||||||
|
fn from(str: &str) -> Self {
|
||||||
|
ws_from_str(str).unwrap_or_else(|err| panic!("{}", err))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&Result<String, VarError>> for ReloadWSProtocol {
|
||||||
|
fn from(input: &Result<String, VarError>) -> Self {
|
||||||
|
match input {
|
||||||
|
Ok(str) => ws_from_str(str).unwrap_or_else(|err| panic!("{}", err)),
|
||||||
|
Err(_) => Self::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<String> for ReloadWSProtocol {
|
||||||
|
type Error = LeptosConfigError;
|
||||||
|
|
||||||
|
fn try_from(s: String) -> Result<Self, Self::Error> {
|
||||||
|
ws_from_str(s.as_str())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,18 +1,31 @@
|
||||||
use crate::{env_w_default, env_wo_default, from_str, Env, LeptosOptions};
|
use crate::{
|
||||||
|
env_from_str, env_w_default, env_wo_default, ws_from_str, Env,
|
||||||
|
LeptosOptions, ReloadWSProtocol,
|
||||||
|
};
|
||||||
use std::{net::SocketAddr, str::FromStr};
|
use std::{net::SocketAddr, str::FromStr};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn from_str_env() {
|
fn env_from_str_test() {
|
||||||
assert!(matches!(from_str("dev").unwrap(), Env::DEV));
|
assert!(matches!(env_from_str("dev").unwrap(), Env::DEV));
|
||||||
assert!(matches!(from_str("development").unwrap(), Env::DEV));
|
assert!(matches!(env_from_str("development").unwrap(), Env::DEV));
|
||||||
assert!(matches!(from_str("DEV").unwrap(), Env::DEV));
|
assert!(matches!(env_from_str("DEV").unwrap(), Env::DEV));
|
||||||
assert!(matches!(from_str("DEVELOPMENT").unwrap(), Env::DEV));
|
assert!(matches!(env_from_str("DEVELOPMENT").unwrap(), Env::DEV));
|
||||||
assert!(matches!(from_str("prod").unwrap(), Env::PROD));
|
assert!(matches!(env_from_str("prod").unwrap(), Env::PROD));
|
||||||
assert!(matches!(from_str("production").unwrap(), Env::PROD));
|
assert!(matches!(env_from_str("production").unwrap(), Env::PROD));
|
||||||
assert!(matches!(from_str("PROD").unwrap(), Env::PROD));
|
assert!(matches!(env_from_str("PROD").unwrap(), Env::PROD));
|
||||||
assert!(matches!(from_str("PRODUCTION").unwrap(), Env::PROD));
|
assert!(matches!(env_from_str("PRODUCTION").unwrap(), Env::PROD));
|
||||||
assert!(from_str("TEST").is_err());
|
assert!(env_from_str("TEST").is_err());
|
||||||
assert!(from_str("?").is_err());
|
assert!(env_from_str("?").is_err());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn ws_from_str_test() {
|
||||||
|
assert!(matches!(ws_from_str("ws").unwrap(), ReloadWSProtocol::WS));
|
||||||
|
assert!(matches!(ws_from_str("WS").unwrap(), ReloadWSProtocol::WS));
|
||||||
|
assert!(matches!(ws_from_str("wss").unwrap(), ReloadWSProtocol::WSS));
|
||||||
|
assert!(matches!(ws_from_str("WSS").unwrap(), ReloadWSProtocol::WSS));
|
||||||
|
assert!(ws_from_str("TEST").is_err());
|
||||||
|
assert!(ws_from_str("?").is_err());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -49,6 +62,8 @@ fn try_from_env_test() {
|
||||||
std::env::set_var("LEPTOS_SITE_ADDR", "0.0.0.0:80");
|
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_PORT", "8080");
|
||||||
std::env::set_var("LEPTOS_RELOAD_EXTERNAL_PORT", "8080");
|
std::env::set_var("LEPTOS_RELOAD_EXTERNAL_PORT", "8080");
|
||||||
|
std::env::set_var("LEPTOS_ENV", "PROD");
|
||||||
|
std::env::set_var("LEPTOS_RELOAD_WS_PROTOCOL", "WSS");
|
||||||
|
|
||||||
let config = LeptosOptions::try_from_env().unwrap();
|
let config = LeptosOptions::try_from_env().unwrap();
|
||||||
assert_eq!(config.output_name, "app_test");
|
assert_eq!(config.output_name, "app_test");
|
||||||
|
@ -61,4 +76,6 @@ fn try_from_env_test() {
|
||||||
);
|
);
|
||||||
assert_eq!(config.reload_port, 8080);
|
assert_eq!(config.reload_port, 8080);
|
||||||
assert_eq!(config.reload_external_port, Some(8080));
|
assert_eq!(config.reload_external_port, Some(8080));
|
||||||
|
assert_eq!(config.env, Env::PROD);
|
||||||
|
assert_eq!(config.reload_ws_protocol, ReloadWSProtocol::WSS)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue