mirror of
https://github.com/leptos-rs/leptos.git
synced 2025-12-28 12:31:55 -05:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ef4c628994 |
26
Cargo.toml
26
Cargo.toml
@@ -25,23 +25,23 @@ members = [
|
||||
exclude = ["benchmarks", "examples"]
|
||||
|
||||
[workspace.package]
|
||||
version = "0.6.9"
|
||||
version = "0.6.6"
|
||||
rust-version = "1.75"
|
||||
|
||||
[workspace.dependencies]
|
||||
leptos = { path = "./leptos", version = "0.6.9" }
|
||||
leptos_dom = { path = "./leptos_dom", version = "0.6.9" }
|
||||
leptos_hot_reload = { path = "./leptos_hot_reload", version = "0.6.9" }
|
||||
leptos_macro = { path = "./leptos_macro", version = "0.6.9" }
|
||||
leptos_reactive = { path = "./leptos_reactive", version = "0.6.9" }
|
||||
leptos_server = { path = "./leptos_server", version = "0.6.9" }
|
||||
server_fn = { path = "./server_fn", version = "0.6.9" }
|
||||
server_fn_macro = { path = "./server_fn_macro", version = "0.6.9" }
|
||||
leptos = { path = "./leptos", version = "0.6.5" }
|
||||
leptos_dom = { path = "./leptos_dom", version = "0.6.5" }
|
||||
leptos_hot_reload = { path = "./leptos_hot_reload", version = "0.6.5" }
|
||||
leptos_macro = { path = "./leptos_macro", version = "0.6.5" }
|
||||
leptos_reactive = { path = "./leptos_reactive", version = "0.6.5" }
|
||||
leptos_server = { path = "./leptos_server", version = "0.6.5" }
|
||||
server_fn = { path = "./server_fn", version = "0.6.5" }
|
||||
server_fn_macro = { path = "./server_fn_macro", version = "0.6.5" }
|
||||
server_fn_macro_default = { path = "./server_fn/server_fn_macro_default", version = "0.6" }
|
||||
leptos_config = { path = "./leptos_config", version = "0.6.9" }
|
||||
leptos_router = { path = "./router", version = "0.6.9" }
|
||||
leptos_meta = { path = "./meta", version = "0.6.9" }
|
||||
leptos_integration_utils = { path = "./integrations/utils", version = "0.6.9" }
|
||||
leptos_config = { path = "./leptos_config", version = "0.6.5" }
|
||||
leptos_router = { path = "./router", version = "0.6.5" }
|
||||
leptos_meta = { path = "./meta", version = "0.6.5" }
|
||||
leptos_integration_utils = { path = "./integrations/utils", version = "0.6.5" }
|
||||
|
||||
[profile.release]
|
||||
codegen-units = 1
|
||||
|
||||
@@ -6,17 +6,9 @@ extend = [
|
||||
[tasks.integration-test]
|
||||
description = "Run integration test with automated start and stop of processes"
|
||||
env = { SPAWN_CLIENT_PROCESS = "1" }
|
||||
run_task = { name = ["start", "wait-test-stop"], parallel = true }
|
||||
dependencies = ["start", "wait-one", "test-playwright", "stop"]
|
||||
|
||||
[tasks.wait-test-stop]
|
||||
private = true
|
||||
dependencies = ["wait-server", "test-playwright", "stop"]
|
||||
|
||||
[tasks.wait-server]
|
||||
[tasks.wait-one]
|
||||
script = '''
|
||||
for run in {1..12}; do
|
||||
echo "Waiting to ensure server is started..."
|
||||
sleep 10
|
||||
done
|
||||
echo "Times up, running tests"
|
||||
sleep 1
|
||||
'''
|
||||
|
||||
@@ -7,8 +7,9 @@ pub struct Todos(pub Vec<Todo>);
|
||||
|
||||
const STORAGE_KEY: &str = "todos-leptos";
|
||||
|
||||
impl Default for Todos {
|
||||
fn default() -> Self {
|
||||
// Basic operations to manipulate the todo list: nothing really interesting here
|
||||
impl Todos {
|
||||
pub fn new() -> Self {
|
||||
let starting_todos =
|
||||
window()
|
||||
.local_storage()
|
||||
@@ -22,10 +23,7 @@ impl Default for Todos {
|
||||
.unwrap_or_default();
|
||||
Self(starting_todos)
|
||||
}
|
||||
}
|
||||
|
||||
// Basic operations to manipulate the todo list: nothing really interesting here
|
||||
impl Todos {
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.0.is_empty()
|
||||
}
|
||||
@@ -88,6 +86,12 @@ impl Todos {
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Todos {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)]
|
||||
pub struct Todo {
|
||||
pub id: Uuid,
|
||||
@@ -132,7 +136,7 @@ const ENTER_KEY: u32 = 13;
|
||||
#[component]
|
||||
pub fn TodoMVC() -> impl IntoView {
|
||||
// The `todos` are a signal, since we need to reactively update the list
|
||||
let (todos, set_todos) = create_signal(Todos::default());
|
||||
let (todos, set_todos) = create_signal(Todos::new());
|
||||
|
||||
// We provide a context that each <Todo/> component can use to update the list
|
||||
// Here, I'm just passing the `WriteSignal`; a <Todo/> doesn't need to read the whole list
|
||||
|
||||
@@ -79,17 +79,10 @@ impl ResponseParts {
|
||||
}
|
||||
|
||||
/// Allows you to override details of the HTTP response like the status code and add Headers/Cookies.
|
||||
///
|
||||
/// `ResponseOptions` is provided via context when you use most of the handlers provided in this
|
||||
/// crate, including [`.leptos_routes`](LeptosRoutes::leptos_routes),
|
||||
/// [`.leptos_routes_with_context`](LeptosRoutes::leptos_routes_with_context), [`handle_server_fns`], etc.
|
||||
/// You can find the full set of provided context types in each handler function.
|
||||
///
|
||||
/// If you provide your own handler, you will need to provide `ResponseOptions` via context
|
||||
/// yourself if you want to access it via context.
|
||||
/// ```rust,ignore
|
||||
/// ResponseOptions is stored in your server's context if you've called `.leptos_routes` on your router.
|
||||
/// ```rust
|
||||
/// #[server]
|
||||
/// pub async fn get_opts() -> Result<(), ServerFnError> {
|
||||
/// pub async fn get_opts() -> Result<(),ServerFnError> {
|
||||
/// let opts = expect_context::<leptos_axum::ResponseOptions>();
|
||||
/// Ok(())
|
||||
/// }
|
||||
|
||||
@@ -104,7 +104,7 @@ pub fn html_parts_separated(
|
||||
"() => mod.hydrate()"
|
||||
};
|
||||
|
||||
let (js_hash, wasm_hash, css_hash) = get_hashes(options);
|
||||
let (js_hash, wasm_hash, css_hash) = get_hashes(&options);
|
||||
|
||||
let head = head.replace(
|
||||
&format!("{output_name}.css"),
|
||||
@@ -150,7 +150,7 @@ fn get_hashes(options: &LeptosOptions) -> (String, String, String) {
|
||||
("css".to_string(), "".to_string()),
|
||||
]);
|
||||
|
||||
if options.hash_files {
|
||||
if options.frontend_files_content_hashes {
|
||||
let hash_path = env::current_exe()
|
||||
.map(|path| {
|
||||
path.parent().map(|p| p.to_path_buf()).unwrap_or_default()
|
||||
|
||||
@@ -173,9 +173,6 @@ where
|
||||
runtime,
|
||||
);
|
||||
|
||||
#[cfg(feature = "experimental-islands")]
|
||||
let prev_no_hydrate =
|
||||
SharedContext::no_hydrate();
|
||||
#[cfg(feature = "experimental-islands")]
|
||||
{
|
||||
SharedContext::set_no_hydrate(
|
||||
@@ -183,7 +180,7 @@ where
|
||||
);
|
||||
}
|
||||
|
||||
let rendered = with_owner(owner, {
|
||||
with_owner(owner, {
|
||||
move || {
|
||||
HydrationCtx::continue_from(
|
||||
current_id,
|
||||
@@ -197,15 +194,7 @@ where
|
||||
.render_to_string()
|
||||
.to_string()
|
||||
}
|
||||
});
|
||||
|
||||
#[cfg(feature = "experimental-islands")]
|
||||
SharedContext::set_no_hydrate(
|
||||
prev_no_hydrate,
|
||||
);
|
||||
|
||||
#[allow(clippy::let_and_return)]
|
||||
rendered
|
||||
})
|
||||
}
|
||||
},
|
||||
// in-order streaming
|
||||
@@ -216,9 +205,6 @@ where
|
||||
runtime,
|
||||
);
|
||||
|
||||
#[cfg(feature = "experimental-islands")]
|
||||
let prev_no_hydrate =
|
||||
SharedContext::no_hydrate();
|
||||
#[cfg(feature = "experimental-islands")]
|
||||
{
|
||||
SharedContext::set_no_hydrate(
|
||||
@@ -226,7 +212,7 @@ where
|
||||
);
|
||||
}
|
||||
|
||||
let rendered = with_owner(owner, {
|
||||
with_owner(owner, {
|
||||
move || {
|
||||
HydrationCtx::continue_from(
|
||||
current_id,
|
||||
@@ -239,15 +225,7 @@ where
|
||||
.into_view()
|
||||
.into_stream_chunks()
|
||||
}
|
||||
});
|
||||
|
||||
#[cfg(feature = "experimental-islands")]
|
||||
SharedContext::set_no_hydrate(
|
||||
prev_no_hydrate,
|
||||
);
|
||||
|
||||
#[allow(clippy::let_and_return)]
|
||||
rendered
|
||||
})
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
@@ -76,9 +76,9 @@ pub struct LeptosOptions {
|
||||
pub hash_file: String,
|
||||
/// If true, hashes will be generated for all files in the site_root and added to their file names.
|
||||
/// Defaults to `true`.
|
||||
#[builder(default = default_hash_files())]
|
||||
#[serde(default = "default_hash_files")]
|
||||
pub hash_files: bool,
|
||||
#[builder(default = default_frontend_files_content_hashes())]
|
||||
#[serde(default = "default_frontend_files_content_hashes")]
|
||||
pub frontend_files_content_hashes: bool,
|
||||
}
|
||||
|
||||
impl LeptosOptions {
|
||||
@@ -118,7 +118,14 @@ impl LeptosOptions {
|
||||
)?,
|
||||
not_found_path: env_w_default("LEPTOS_NOT_FOUND_PATH", "/404")?,
|
||||
hash_file: env_w_default("LEPTOS_HASH_FILE_NAME", "hash.txt")?,
|
||||
hash_files: env_w_default("LEPTOS_HASH_FILES", "false")?.parse()?,
|
||||
frontend_files_content_hashes: env_w_default(
|
||||
"LEPTOS_FRONTEND_FILES_CONTENT_HASHES",
|
||||
"ON",
|
||||
)?
|
||||
.to_uppercase()
|
||||
.replace("ON", "true")
|
||||
.replace("OFF", "false")
|
||||
.parse()?,
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -161,8 +168,8 @@ fn default_hash_file_name() -> String {
|
||||
"hash.txt".to_string()
|
||||
}
|
||||
|
||||
fn default_hash_files() -> bool {
|
||||
false
|
||||
fn default_frontend_files_content_hashes() -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn env_wo_default(key: &str) -> Result<Option<String>, LeptosConfigError> {
|
||||
|
||||
@@ -447,7 +447,7 @@ impl ToTokens for Model {
|
||||
};
|
||||
|
||||
quote! {
|
||||
#[::leptos::wasm_bindgen::prelude::wasm_bindgen(wasm_bindgen = ::leptos::wasm_bindgen)]
|
||||
#[::leptos::wasm_bindgen::prelude::wasm_bindgen]
|
||||
#[allow(non_snake_case)]
|
||||
pub fn #hydrate_fn_name(el: ::leptos::web_sys::HtmlElement) {
|
||||
if let Some(Ok(key)) = el.dataset().get(::leptos::wasm_bindgen::intern("hkc")).map(|key| std::str::FromStr::from_str(&key)) {
|
||||
|
||||
@@ -339,13 +339,11 @@ thread_local! {
|
||||
impl SharedContext {
|
||||
/// Whether the renderer should currently add hydration IDs.
|
||||
pub fn no_hydrate() -> bool {
|
||||
println!("no_hydrate == {}", NO_HYDRATE.with(Cell::get));
|
||||
NO_HYDRATE.with(Cell::get)
|
||||
}
|
||||
|
||||
/// Sets whether the renderer should not add hydration IDs.
|
||||
pub fn set_no_hydrate(hydrate: bool) {
|
||||
println!("set_no_hydrate == {}", hydrate);
|
||||
NO_HYDRATE.with(|cell| cell.set(hydrate));
|
||||
}
|
||||
|
||||
|
||||
@@ -165,7 +165,7 @@ pub fn create_owning_memo<T>(
|
||||
f: impl Fn(Option<T>) -> (T, bool) + 'static,
|
||||
) -> Memo<T>
|
||||
where
|
||||
T: 'static,
|
||||
T: PartialEq + 'static,
|
||||
{
|
||||
Runtime::current().create_owning_memo(f)
|
||||
}
|
||||
@@ -352,7 +352,7 @@ impl<T> Memo<T> {
|
||||
#[track_caller]
|
||||
pub fn new_owning(f: impl Fn(Option<T>) -> (T, bool) + 'static) -> Memo<T>
|
||||
where
|
||||
T: 'static,
|
||||
T: PartialEq + 'static,
|
||||
{
|
||||
create_owning_memo(f)
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "leptos_meta"
|
||||
version = "0.6.9"
|
||||
version = "0.6.6"
|
||||
edition = "2021"
|
||||
authors = ["Greg Johnston"]
|
||||
license = "MIT"
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
[package]
|
||||
name = "leptos_router"
|
||||
version = "0.6.9"
|
||||
version = "0.6.6"
|
||||
edition = "2021"
|
||||
authors = ["Greg Johnston", "Ben Wishovich"]
|
||||
authors = ["Greg Johnston"]
|
||||
license = "MIT"
|
||||
readme = "../README.md"
|
||||
repository = "https://github.com/leptos-rs/leptos"
|
||||
|
||||
@@ -54,7 +54,6 @@ rkyv = { version = "0.7", features = [
|
||||
"uuid",
|
||||
"strict",
|
||||
], optional = true }
|
||||
rmp-serde = { version = "1.1", optional = true }
|
||||
|
||||
# client
|
||||
gloo-net = { version = "0.5", optional = true }
|
||||
@@ -103,7 +102,6 @@ multipart = ["browser", "dep:multer"]
|
||||
url = ["dep:serde_qs"]
|
||||
cbor = ["dep:ciborium"]
|
||||
rkyv = ["dep:rkyv"]
|
||||
msgpack = ["dep:rmp-serde"]
|
||||
default-tls = ["reqwest?/default-tls"]
|
||||
rustls = ["reqwest?/rustls-tls"]
|
||||
reqwest = ["dep:reqwest"]
|
||||
|
||||
@@ -44,11 +44,6 @@ mod multipart;
|
||||
#[cfg(feature = "multipart")]
|
||||
pub use multipart::*;
|
||||
|
||||
#[cfg(feature = "msgpack")]
|
||||
mod msgpack;
|
||||
#[cfg(feature = "msgpack")]
|
||||
pub use msgpack::*;
|
||||
|
||||
mod stream;
|
||||
use crate::error::ServerFnError;
|
||||
use futures::Future;
|
||||
|
||||
@@ -1,74 +0,0 @@
|
||||
use super::{Encoding, FromReq, FromRes, IntoReq, IntoRes};
|
||||
use crate::{
|
||||
error::ServerFnError,
|
||||
request::{ClientReq, Req},
|
||||
response::{ClientRes, Res},
|
||||
};
|
||||
use bytes::Bytes;
|
||||
use http::Method;
|
||||
use serde::{de::DeserializeOwned, Serialize};
|
||||
|
||||
/// A codec for MessagePack.
|
||||
pub struct MsgPack;
|
||||
|
||||
impl Encoding for MsgPack {
|
||||
const CONTENT_TYPE: &'static str = "application/msgpack";
|
||||
const METHOD: Method = Method::POST;
|
||||
}
|
||||
|
||||
impl<T, Request, Err> IntoReq<MsgPack, Request, Err> for T
|
||||
where
|
||||
Request: ClientReq<Err>,
|
||||
T: Serialize,
|
||||
{
|
||||
fn into_req(
|
||||
self,
|
||||
path: &str,
|
||||
accepts: &str,
|
||||
) -> Result<Request, ServerFnError<Err>> {
|
||||
let data = rmp_serde::to_vec(&self)
|
||||
.map_err(|e| ServerFnError::Serialization(e.to_string()))?;
|
||||
Request::try_new_post_bytes(
|
||||
path,
|
||||
MsgPack::CONTENT_TYPE,
|
||||
accepts,
|
||||
Bytes::from(data),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, Request, Err> FromReq<MsgPack, Request, Err> for T
|
||||
where
|
||||
Request: Req<Err> + Send,
|
||||
T: DeserializeOwned,
|
||||
{
|
||||
async fn from_req(req: Request) -> Result<Self, ServerFnError<Err>> {
|
||||
let data = req.try_into_bytes().await?;
|
||||
rmp_serde::from_slice::<T>(&data)
|
||||
.map_err(|e| ServerFnError::Args(e.to_string()))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, Response, Err> IntoRes<MsgPack, Response, Err> for T
|
||||
where
|
||||
Response: Res<Err>,
|
||||
T: Serialize + Send,
|
||||
{
|
||||
async fn into_res(self) -> Result<Response, ServerFnError<Err>> {
|
||||
let data = rmp_serde::to_vec(&self)
|
||||
.map_err(|e| ServerFnError::Serialization(e.to_string()))?;
|
||||
Response::try_from_bytes(MsgPack::CONTENT_TYPE, Bytes::from(data))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, Response, Err> FromRes<MsgPack, Response, Err> for T
|
||||
where
|
||||
Response: ClientRes<Err> + Send,
|
||||
T: DeserializeOwned,
|
||||
{
|
||||
async fn from_res(res: Response) -> Result<Self, ServerFnError<Err>> {
|
||||
let data = res.try_into_bytes().await?;
|
||||
rmp_serde::from_slice(&data)
|
||||
.map_err(|e| ServerFnError::Deserialization(e.to_string()))
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user