Compare commits

..

4 Commits

Author SHA1 Message Date
Greg Johnston
757413da3c fmt 2023-12-18 06:34:19 -05:00
Greg Johnston
3c6b247438 ok that was about a different thing 2023-12-17 21:23:40 -05:00
Greg Johnston
45c373ab3e suppress more stable feature warnings 2023-12-17 21:17:24 -05:00
Greg Johnston
dd0ca4754e chore: fix eager clone warning 2023-12-17 20:56:14 -05:00
62 changed files with 232 additions and 216 deletions

View File

@@ -4,31 +4,30 @@
The examples in this directory are all built and tested against the current `main` branch.
To the extent that new features have been released or breaking changes have been made since the previous release, the examples are compatible with the `main` branch and not the current release.
To the extent that new features have been released or breaking changes have been made since the previous release, the examples are compatible with the `main` branch but not the current release.
To see the examples as they were at the time of the `0.5.0` release, [click here](https://github.com/leptos-rs/leptos/tree/v0.5.0/examples).
## Cargo Make
[Cargo Make](https://sagiegurari.github.io/cargo-make/) is used to build, test, and run examples.
Here are the highlights.
- Extendable custom task files are located in the [cargo-make](./cargo-make/) directory
- Running a task will automatically install `cargo` dependencies
- Each `Makefile.toml` file must extend the [cargo-make/main.toml](./cargo-make/main.toml) file
- [cargo-make](./cargo-make/) files that end in `*-test.toml` configure web testing strategies
- Run `cargo make test-report` to learn which examples have web tests
## Getting Started
The simplest way to get started with any example is to use the “quick start” command found in the README for each example. Most of the examples use either [`trunk`](https://trunkrs.dev/) (a simple build system and dev server for client-side-rendered apps) or [`cargo-leptos`](https://github.com/leptos-rs/cargo-leptos) (a build system for server-rendered and client-hydrated apps).
## Using Cargo Make
You can also run any of the examples using [`cargo-make`](https://github.com/sagiegurari/cargo-make). Note that this is completely optional. We use it for CI, and it can be convenient for running the examples, but is not required.
Follow these steps to get any example up and running.
1. `cd` to the example root directory
2. Run `cargo make ci` to setup and test the example
3. Run `cargo make start` to run the example
4. Open the client URL in the console output (<http://127.0.0.1:8080> or <http://127.0.0.1:3000> by default)
5. Run `cargo make stop` to end any processes started by `cargo make start`.
Here are a few additional notes:
- Extendable custom task files are located in the [cargo-make](./cargo-make/) directory
- Running a task will automatically install `cargo` dependencies
- Each `Makefile.toml` file must extend the [cargo-make/main.toml](./cargo-make/main.toml) file
- [cargo-make](./cargo-make/) files that end in `*-test.toml` configure web testing strategies
- Run `cargo make test-report` to learn which examples have web tests
## Prerequisites

View File

@@ -1,2 +0,0 @@
[toolchain]
channel = "nightly"

View File

@@ -1,2 +0,0 @@
[toolchain]
channel = "nightly"

View File

@@ -1,2 +1,3 @@
[toolchain]
channel = "nightly"

View File

@@ -1,2 +1,3 @@
[toolchain]
channel = "nightly"

View File

@@ -1,2 +0,0 @@
[toolchain]
channel = "nightly"

View File

@@ -5,7 +5,3 @@ This example demonstrates how Leptos Errors can work with an Axum backend on a s
## Getting Started
See the [Examples README](../README.md) for setup and run instructions.
## Quick Start
Run `cargo leptos watch` to run this example.

View File

@@ -1,2 +0,0 @@
[toolchain]
channel = "nightly"

View File

@@ -1,2 +0,0 @@
[toolchain]
channel = "nightly"

View File

@@ -1,2 +0,0 @@
[toolchain]
channel = "nightly"

View File

@@ -1,2 +0,0 @@
[toolchain]
channel = "nightly"

View File

@@ -1,2 +0,0 @@
[toolchain]
channel = "nightly"

View File

@@ -1,2 +0,0 @@
[toolchain]
channel = "nightly"

View File

@@ -1,2 +1,3 @@
[toolchain]
channel = "nightly"

View File

@@ -1,2 +0,0 @@
[toolchain]
channel = "nightly"

View File

@@ -1,2 +0,0 @@
[toolchain]
channel = "nightly"

View File

@@ -1,2 +0,0 @@
[toolchain]
channel = "nightly"

View File

@@ -1,2 +0,0 @@
[toolchain]
channel = "nightly"

View File

@@ -1,2 +0,0 @@
[toolchain]
channel = "nightly"

View File

@@ -9,6 +9,11 @@ cfg_if! {
use crate::app::*;
use leptos_actix::{generate_route_list, LeptosRoutes};
#[get("/style.css")]
async fn css() -> impl Responder {
actix_files::NamedFile::open_async("./style/output.css").await
}
#[actix_web::main]
async fn main() -> std::io::Result<()> {
@@ -25,6 +30,7 @@ cfg_if! {
let site_root = &leptos_options.site_root;
let routes = &routes;
App::new()
.service(css)
.leptos_routes(leptos_options.to_owned(), routes.to_owned(), || view! { <App/> })
.service(Files::new("/", site_root))
.wrap(middleware::Compress::default())

View File

@@ -1,2 +1,3 @@
[toolchain]
channel = "nightly"

View File

@@ -1,2 +0,0 @@
[toolchain]
channel = "nightly"

View File

@@ -1,2 +0,0 @@
[toolchain]
channel = "nightly"

View File

@@ -1,2 +0,0 @@
[toolchain]
channel = "nightly"

View File

@@ -1,2 +0,0 @@
[toolchain]
channel = "nightly"

View File

@@ -1,2 +0,0 @@
[toolchain]
channel = "nightly"

View File

@@ -1,2 +0,0 @@
[toolchain]
channel = "nightly"

View File

@@ -457,7 +457,7 @@ pub type PinnedHtmlStream =
/// - [ResponseOptions]
/// - [MetaContext](leptos_meta::MetaContext)
/// - [RouterIntegrationContext](leptos_router::RouterIntegrationContext)
#[tracing::instrument(level = "trace", fields(error), skip_all)]
#[tracing::instrument(level = "info", fields(error), skip_all)]
pub fn render_app_to_stream<IV>(
options: LeptosOptions,
app_fn: impl Fn() -> IV + Clone + Send + 'static,
@@ -483,7 +483,7 @@ where
/// The difference between calling this and `render_app_to_stream_with_context()` is that this
/// one respects the `SsrMode` on each Route and thus requires `Vec<RouteListing>` for route checking.
/// This is useful if you are using `.leptos_routes_with_handler()`
#[tracing::instrument(level = "trace", fields(error), skip_all)]
#[tracing::instrument(level = "info", fields(error), skip_all)]
pub fn render_route<IV>(
options: LeptosOptions,
paths: Vec<RouteListing>,
@@ -558,7 +558,7 @@ where
/// - [ResponseOptions]
/// - [MetaContext](leptos_meta::MetaContext)
/// - [RouterIntegrationContext](leptos_router::RouterIntegrationContext)
#[tracing::instrument(level = "trace", fields(error), skip_all)]
#[tracing::instrument(level = "info", fields(error), skip_all)]
pub fn render_app_to_stream_in_order<IV>(
options: LeptosOptions,
app_fn: impl Fn() -> IV + Clone + Send + 'static,
@@ -604,7 +604,7 @@ where
/// - [ResponseOptions]
/// - [MetaContext](leptos_meta::MetaContext)
/// - [RouterIntegrationContext](leptos_router::RouterIntegrationContext)
#[tracing::instrument(level = "trace", fields(error), skip_all)]
#[tracing::instrument(level = "info", fields(error), skip_all)]
pub fn render_app_to_stream_with_context<IV>(
options: LeptosOptions,
additional_context: impl Fn() + 'static + Clone + Send,
@@ -636,7 +636,7 @@ where
/// The difference between calling this and `render_app_to_stream_with_context()` is that this
/// one respects the `SsrMode` on each Route, and thus requires `Vec<RouteListing>` for route checking.
/// This is useful if you are using `.leptos_routes_with_handler()`.
#[tracing::instrument(level = "trace", fields(error), skip_all)]
#[tracing::instrument(level = "info", fields(error), skip_all)]
pub fn render_route_with_context<IV>(
options: LeptosOptions,
paths: Vec<RouteListing>,
@@ -724,7 +724,7 @@ where
/// - [ResponseOptions]
/// - [MetaContext](leptos_meta::MetaContext)
/// - [RouterIntegrationContext](leptos_router::RouterIntegrationContext)
#[tracing::instrument(level = "trace", fields(error), skip_all)]
#[tracing::instrument(level = "info", fields(error), skip_all)]
pub fn render_app_to_stream_with_context_and_replace_blocks<IV>(
options: LeptosOptions,
additional_context: impl Fn() + 'static + Clone + Send,
@@ -787,7 +787,7 @@ where
}
}
#[tracing::instrument(level = "trace", fields(error), skip_all)]
#[tracing::instrument(level = "info", fields(error), skip_all)]
async fn generate_response(
res_options: ResponseOptions,
rx: Receiver<String>,
@@ -829,7 +829,7 @@ async fn generate_response(
}
res
}
#[tracing::instrument(level = "trace", fields(error), skip_all)]
#[tracing::instrument(level = "info", fields(error), skip_all)]
async fn forward_stream(
options: &LeptosOptions,
res_options2: ResponseOptions,
@@ -890,7 +890,7 @@ async fn forward_stream(
/// - [ResponseOptions]
/// - [MetaContext](leptos_meta::MetaContext)
/// - [RouterIntegrationContext](leptos_router::RouterIntegrationContext)
#[tracing::instrument(level = "trace", fields(error), skip_all)]
#[tracing::instrument(level = "info", fields(error), skip_all)]
pub fn render_app_to_stream_in_order_with_context<IV>(
options: LeptosOptions,
additional_context: impl Fn() + 'static + Clone + Send,
@@ -1026,7 +1026,7 @@ fn provide_contexts(
/// - [ResponseOptions]
/// - [MetaContext](leptos_meta::MetaContext)
/// - [RouterIntegrationContext](leptos_router::RouterIntegrationContext)
#[tracing::instrument(level = "trace", fields(error), skip_all)]
#[tracing::instrument(level = "info", fields(error), skip_all)]
pub fn render_app_async<IV>(
options: LeptosOptions,
app_fn: impl Fn() -> IV + Clone + Send + 'static,
@@ -1068,7 +1068,7 @@ where
/// - [ResponseOptions]
/// - [MetaContext](leptos_meta::MetaContext)
/// - [RouterIntegrationContext](leptos_router::RouterIntegrationContext)
#[tracing::instrument(level = "trace", fields(error), skip_all)]
#[tracing::instrument(level = "info", fields(error), skip_all)]
pub fn render_app_async_stream_with_context<IV>(
options: LeptosOptions,
additional_context: impl Fn() + 'static + Clone + Send,
@@ -1204,7 +1204,7 @@ where
/// - [ResponseOptions]
/// - [MetaContext](leptos_meta::MetaContext)
/// - [RouterIntegrationContext](leptos_router::RouterIntegrationContext)
#[tracing::instrument(level = "trace", fields(error), skip_all)]
#[tracing::instrument(level = "info", fields(error), skip_all)]
pub fn render_app_async_with_context<IV>(
options: LeptosOptions,
additional_context: impl Fn() + 'static + Clone + Send,
@@ -1677,7 +1677,7 @@ where
LeptosOptions: FromRef<S>,
S: Clone + Send + Sync + 'static,
{
#[tracing::instrument(level = "trace", fields(error), skip_all)]
#[tracing::instrument(level = "info", fields(error), skip_all)]
fn leptos_routes<IV>(
self,
options: &S,

View File

@@ -45,7 +45,7 @@ use leptos_reactive::{
/// ```
#[cfg_attr(
any(debug_assertions, feature = "ssr"),
tracing::instrument(level = "trace", skip_all)
tracing::instrument(level = "info", skip_all)
)]
#[component]
pub fn AnimatedShow(

View File

@@ -52,7 +52,7 @@ use std::hash::Hash;
/// ```
#[cfg_attr(
any(debug_assertions, feature = "ssr"),
tracing::instrument(level = "trace", skip_all)
tracing::instrument(level = "info", skip_all)
)]
#[component(transparent)]
pub fn For<IF, I, T, EF, N, KF, K>(

View File

@@ -57,8 +57,8 @@
//! [`todo_app_sqlite_axum`](https://github.com/leptos-rs/leptos/tree/main/examples/todo_app_sqlite_axum), and
//! [`todo_app_sqlite_viz`](https://github.com/leptos-rs/leptos/tree/main/examples/todo_app_sqlite_viz)
//! show how to build a full-stack app using server functions and database connections.
//! - [`tailwind`](https://github.com/leptos-rs/leptos/tree/main/examples/tailwind_csr) shows how to integrate
//! TailwindCSS with `trunk` for CSR.
//! - [`tailwind`](https://github.com/leptos-rs/leptos/tree/main/examples/tailwind) shows how to integrate
//! TailwindCSS with `cargo-leptos`.
//!
//! Details on how to run each example can be found in its README.
//!

View File

@@ -11,7 +11,7 @@ use leptos_macro::component;
/// Setting `use_shadow` to `true` places the element in a shadow root to isolate styles.
#[cfg_attr(
any(debug_assertions, feature = "ssr"),
tracing::instrument(level = "trace", skip_all)
tracing::instrument(level = "info", skip_all)
)]
#[component]
pub fn Portal(

View File

@@ -28,7 +28,7 @@ use leptos_reactive::{create_memo, signal_prelude::*};
/// ```
#[cfg_attr(
any(debug_assertions, feature = "ssr"),
tracing::instrument(level = "trace", skip_all)
tracing::instrument(level = "info", skip_all)
)]
#[component]
pub fn Show<W>(

View File

@@ -57,7 +57,7 @@ use std::rc::Rc;
/// ```
#[cfg_attr(
any(debug_assertions, feature = "ssr"),
tracing::instrument(level = "trace", skip_all)
tracing::instrument(level = "info", skip_all)
)]
#[component]
pub fn Suspense<V>(

View File

@@ -64,7 +64,7 @@ use std::{
/// ```
#[cfg_attr(
any(debug_assertions, feature = "ssr"),
tracing::instrument(level = "trace", skip_all)
tracing::instrument(level = "info", skip_all)
)]
#[component(transparent)]
pub fn Transition(
@@ -130,8 +130,7 @@ pub fn Transition(
}
if is_first_run(first_run, &suspense_context) {
let has_local_only = suspense_context.has_local_only()
|| cfg!(feature = "csr")
|| !HydrationCtx::is_hydrating();
|| cfg!(feature = "csr");
if (!has_local_only || child_runs.get() > 0)
&& !cfg!(feature = "csr")
{

View File

@@ -16,7 +16,7 @@ futures = "0.3"
getrandom = { version = "0.2", optional = true }
html-escape = "0.2"
indexmap = "2"
itertools = "0.12"
itertools = "0.10"
js-sys = "0.3"
leptos_reactive = { workspace = true }
server_fn = { workspace = true }

View File

@@ -158,7 +158,7 @@ impl From<ComponentRepr> for View {
}
impl IntoView for ComponentRepr {
#[cfg_attr(any(debug_assertions, feature = "ssr"), instrument(level = "trace", name = "<Component />", skip_all, fields(name = %self.name)))]
#[cfg_attr(any(debug_assertions, feature = "ssr"), instrument(level = "info", name = "<Component />", skip_all, fields(name = %self.name)))]
fn into_view(self) -> View {
self.into()
}

View File

@@ -158,7 +158,7 @@ where
{
#[cfg_attr(
any(debug_assertions, feature = "ssr"),
instrument(level = "trace", name = "<DynChild />", skip_all)
instrument(level = "info", name = "<DynChild />", skip_all)
)]
#[inline]
fn into_view(self) -> View {

View File

@@ -382,7 +382,7 @@ where
{
#[cfg_attr(
any(debug_assertions, feature = "ssr"),
instrument(level = "trace", name = "<Each />", skip_all)
instrument(level = "info", name = "<Each />", skip_all)
)]
fn into_view(self) -> crate::View {
let Self {

View File

@@ -15,7 +15,7 @@ where
{
#[cfg_attr(
any(debug_assertions, feature = "ssr"),
instrument(level = "trace", skip_all,)
instrument(level = "info", skip_all,)
)]
fn into_fragment(self) -> Fragment {
self.into_iter().map(|v| v.into_view()).collect()
@@ -110,7 +110,7 @@ impl Fragment {
}
impl IntoView for Fragment {
#[cfg_attr(debug_assertions, instrument(level = "trace", name = "</>", skip_all, fields(children = self.nodes.len())))]
#[cfg_attr(debug_assertions, instrument(level = "info", name = "</>", skip_all, fields(children = self.nodes.len())))]
fn into_view(self) -> View {
self.into()
}

View File

@@ -63,7 +63,7 @@ pub struct Unit;
impl IntoView for Unit {
#[cfg_attr(
any(debug_assertions, feature = "ssr"),
instrument(level = "trace", name = "<() />", skip_all)
instrument(level = "info", name = "<() />", skip_all)
)]
fn into_view(self) -> crate::View {
let component = UnitRepr::default();

View File

@@ -101,7 +101,7 @@ pub trait Mountable {
impl IntoView for () {
#[cfg_attr(
any(debug_assertions, feature = "ssr"),
instrument(level = "trace", name = "<() />", skip_all)
instrument(level = "info", name = "<() />", skip_all)
)]
fn into_view(self) -> View {
Unit.into_view()
@@ -114,7 +114,7 @@ where
{
#[cfg_attr(
any(debug_assertions, feature = "ssr"),
instrument(level = "trace", name = "Option<T>", skip_all)
instrument(level = "info", name = "Option<T>", skip_all)
)]
fn into_view(self) -> View {
if let Some(t) = self {
@@ -132,7 +132,7 @@ where
{
#[cfg_attr(
any(debug_assertions, feature = "ssr"),
instrument(level = "trace", name = "Fn() -> impl IntoView", skip_all)
instrument(level = "info", name = "Fn() -> impl IntoView", skip_all)
)]
#[track_caller]
fn into_view(self) -> View {
@@ -246,7 +246,7 @@ pub trait CollectView {
impl<I: IntoIterator<Item = T>, T: IntoView> CollectView for I {
#[cfg_attr(
any(debug_assertions, feature = "ssr"),
instrument(level = "trace", name = "#text", skip_all)
instrument(level = "info", name = "#text", skip_all)
)]
fn collect_view(self) -> View {
self.into_iter()
@@ -381,7 +381,7 @@ impl Element {
}
impl IntoView for Element {
#[cfg_attr(debug_assertions, instrument(level = "trace", name = "<Element />", skip_all, fields(tag = %self.name)))]
#[cfg_attr(debug_assertions, instrument(level = "info", name = "<Element />", skip_all, fields(tag = %self.name)))]
fn into_view(self) -> View {
View::Element(self)
}
@@ -501,7 +501,7 @@ impl fmt::Debug for Text {
}
impl IntoView for Text {
#[cfg_attr(debug_assertions, instrument(level = "trace", name = "#text", skip_all, fields(content = %self.content)))]
#[cfg_attr(debug_assertions, instrument(level = "info", name = "#text", skip_all, fields(content = %self.content)))]
fn into_view(self) -> View {
View::Text(self)
}
@@ -566,7 +566,7 @@ impl Default for View {
}
impl IntoView for View {
#[cfg_attr(debug_assertions, instrument(level = "trace", name = "Node", skip_all, fields(kind = self.kind_name())))]
#[cfg_attr(debug_assertions, instrument(level = "info", name = "Node", skip_all, fields(kind = self.kind_name())))]
fn into_view(self) -> View {
self
}
@@ -581,7 +581,7 @@ impl IntoView for &View {
impl<const N: usize> IntoView for [View; N] {
#[cfg_attr(
any(debug_assertions, feature = "ssr"),
instrument(level = "trace", name = "[Node; N]", skip_all)
instrument(level = "info", name = "[Node; N]", skip_all)
)]
fn into_view(self) -> View {
Fragment::new(self.into_iter().collect()).into_view()
@@ -1135,7 +1135,7 @@ api_planning! {
impl IntoView for String {
#[cfg_attr(
any(debug_assertions, feature = "ssr"),
instrument(level = "trace", name = "#text", skip_all)
instrument(level = "info", name = "#text", skip_all)
)]
#[inline(always)]
fn into_view(self) -> View {
@@ -1146,7 +1146,7 @@ impl IntoView for String {
impl IntoView for &'static str {
#[cfg_attr(
any(debug_assertions, feature = "ssr"),
instrument(level = "trace", name = "#text", skip_all)
instrument(level = "info", name = "#text", skip_all)
)]
#[inline(always)]
fn into_view(self) -> View {
@@ -1157,7 +1157,7 @@ impl IntoView for &'static str {
impl IntoView for Oco<'static, str> {
#[cfg_attr(
any(debug_assertions, feature = "ssr"),
instrument(level = "trace", name = "#text", skip_all)
instrument(level = "info", name = "#text", skip_all)
)]
#[inline(always)]
fn into_view(self) -> View {
@@ -1171,7 +1171,7 @@ where
{
#[cfg_attr(
any(debug_assertions, feature = "ssr"),
instrument(level = "trace", name = "#text", skip_all)
instrument(level = "info", name = "#text", skip_all)
)]
fn into_view(self) -> View {
self.into_iter()
@@ -1184,7 +1184,7 @@ where
impl IntoView for core::fmt::Arguments<'_> {
#[cfg_attr(
any(debug_assertions, feature = "ssr"),
instrument(level = "trace", name = "#text", skip_all)
instrument(level = "info", name = "#text", skip_all)
)]
fn into_view(self) -> View {
match self.as_str() {

View File

@@ -138,6 +138,15 @@ macro_rules! impl_into_attr_boxed {
};
}
impl IntoAttribute for Option<Attribute> {
#[inline(always)]
fn into_attribute(self) -> Attribute {
self.unwrap_or(Attribute::Option(None))
}
impl_into_attr_boxed! {}
}
impl IntoAttribute for String {
#[inline(always)]
fn into_attribute(self) -> Attribute {
@@ -192,10 +201,46 @@ impl IntoAttribute for bool {
impl_into_attr_boxed! {}
}
impl<T: IntoAttribute> IntoAttribute for Option<T> {
impl IntoAttribute for Option<String> {
#[inline(always)]
fn into_attribute(self) -> Attribute {
self.map_or(Attribute::Option(None), IntoAttribute::into_attribute)
Attribute::Option(self.map(Oco::Owned))
}
impl_into_attr_boxed! {}
}
impl IntoAttribute for Option<&'static str> {
#[inline(always)]
fn into_attribute(self) -> Attribute {
Attribute::Option(self.map(Oco::Borrowed))
}
impl_into_attr_boxed! {}
}
impl IntoAttribute for Option<Rc<str>> {
#[inline(always)]
fn into_attribute(self) -> Attribute {
Attribute::Option(self.map(Oco::Counted))
}
impl_into_attr_boxed! {}
}
impl IntoAttribute for Option<Cow<'static, str>> {
#[inline(always)]
fn into_attribute(self) -> Attribute {
Attribute::Option(self.map(Oco::from))
}
impl_into_attr_boxed! {}
}
impl IntoAttribute for Option<Oco<'static, str>> {
#[inline(always)]
fn into_attribute(self) -> Attribute {
Attribute::Option(self)
}
impl_into_attr_boxed! {}
@@ -265,6 +310,17 @@ macro_rules! attr_type {
self.into_attribute()
}
}
impl IntoAttribute for Option<$attr_type> {
fn into_attribute(self) -> Attribute {
Attribute::Option(self.map(|n| n.to_string().into()))
}
#[inline]
fn into_attribute_boxed(self: Box<Self>) -> Attribute {
self.into_attribute()
}
}
};
}
@@ -285,6 +341,24 @@ macro_rules! attr_signal_type {
};
}
macro_rules! attr_signal_type_optional {
($signal_type:ty) => {
#[cfg(not(feature = "nightly"))]
impl<T> IntoAttribute for $signal_type
where
T: Clone,
Option<T>: IntoAttribute,
{
fn into_attribute(self) -> Attribute {
let modified_fn = Rc::new(move || self.get().into_attribute());
Attribute::Fn(modified_fn)
}
impl_into_attr_boxed! {}
}
};
}
attr_type!(&String);
attr_type!(usize);
attr_type!(u8);
@@ -307,7 +381,7 @@ attr_signal_type!(RwSignal<T>);
attr_signal_type!(Memo<T>);
attr_signal_type!(Signal<T>);
attr_signal_type!(MaybeSignal<T>);
attr_signal_type!(MaybeProp<T>);
attr_signal_type_optional!(MaybeProp<T>);
#[cfg(all(target_arch = "wasm32", feature = "web"))]
#[doc(hidden)]

View File

@@ -69,6 +69,16 @@ impl IntoAttribute for Nonce {
}
}
impl IntoAttribute for Option<Nonce> {
fn into_attribute(self) -> Attribute {
Attribute::Option(self.map(|n| n.0.into()))
}
fn into_attribute_boxed(self: Box<Self>) -> Attribute {
Attribute::Option(self.map(|n| n.0.into()))
}
}
/// Accesses the nonce that has been generated during the current
/// server response. This can be added to inline `<script>` and
/// `<style>` tags for compatibility with a Content Security Policy.

View File

@@ -28,7 +28,7 @@ type PinnedFuture<T> = Pin<Box<dyn Future<Output = T>>>;
/// ```
#[cfg_attr(
any(debug_assertions, feature = "ssr"),
instrument(level = "trace", skip_all,)
instrument(level = "info", skip_all,)
)]
pub fn render_to_string<F, N>(f: F) -> Oco<'static, str>
where
@@ -59,7 +59,7 @@ where
/// read under that `<Suspense/>` resolve.
#[cfg_attr(
any(debug_assertions, feature = "ssr"),
instrument(level = "trace", skip_all,)
instrument(level = "info", skip_all,)
)]
pub fn render_to_stream(
view: impl FnOnce() -> View + 'static,
@@ -83,7 +83,7 @@ pub fn render_to_stream(
/// read under that `<Suspense/>` resolve.
#[cfg_attr(
any(debug_assertions, feature = "ssr"),
instrument(level = "trace", skip_all,)
instrument(level = "info", skip_all,)
)]
pub fn render_to_stream_with_prefix(
view: impl FnOnce() -> View + 'static,
@@ -112,7 +112,7 @@ pub fn render_to_stream_with_prefix(
/// read under that `<Suspense/>` resolve.
#[cfg_attr(
any(debug_assertions, feature = "ssr"),
instrument(level = "trace", skip_all,)
instrument(level = "info", skip_all,)
)]
pub fn render_to_stream_with_prefix_undisposed(
view: impl FnOnce() -> View + 'static,
@@ -138,7 +138,7 @@ pub fn render_to_stream_with_prefix_undisposed(
/// read under that `<Suspense/>` resolve.
#[cfg_attr(
any(debug_assertions, feature = "ssr"),
instrument(level = "trace", skip_all,)
instrument(level = "info", skip_all,)
)]
pub fn render_to_stream_with_prefix_undisposed_with_context(
view: impl FnOnce() -> View + 'static,
@@ -175,7 +175,7 @@ pub fn render_to_stream_with_prefix_undisposed_with_context(
/// read under that `<Suspense/>` resolve.
#[cfg_attr(
any(debug_assertions, feature = "ssr"),
instrument(level = "trace", skip_all,)
instrument(level = "info", skip_all,)
)]
pub fn render_to_stream_with_prefix_undisposed_with_context_and_block_replacement(
view: impl FnOnce() -> View + 'static,
@@ -365,7 +365,7 @@ impl View {
/// Consumes the node and renders it into an HTML string.
#[cfg_attr(
any(debug_assertions, feature = "ssr"),
instrument(level = "trace", skip_all,)
instrument(level = "info", skip_all,)
)]
pub fn render_to_string(self) -> Oco<'static, str> {
#[cfg(all(feature = "web", feature = "ssr"))]

View File

@@ -17,7 +17,7 @@ use std::collections::VecDeque;
/// Renders a view to HTML, waiting to return until all `async` [Resource](leptos_reactive::Resource)s
/// loaded in `<Suspense/>` elements have finished loading.
#[tracing::instrument(level = "trace", skip_all)]
#[tracing::instrument(level = "info", skip_all)]
pub async fn render_to_string_async(
view: impl FnOnce() -> View + 'static,
) -> String {
@@ -40,7 +40,7 @@ pub async fn render_to_string_async(
/// in order:
/// 1. HTML from the `view` in order, pausing to wait for each `<Suspense/>`
/// 2. any serialized [Resource](leptos_reactive::Resource)s
#[tracing::instrument(level = "trace", skip_all)]
#[tracing::instrument(level = "info", skip_all)]
pub fn render_to_stream_in_order(
view: impl FnOnce() -> View + 'static,
) -> impl Stream<Item = String> {

View File

@@ -15,7 +15,7 @@ proc-macro = true
attribute-derive = { version = "0.8", features = ["syn-full"] }
cfg-if = "1"
html-escape = "0.2"
itertools = "0.12"
itertools = "0.11"
prettyplease = "0.2.4"
proc-macro-error = { version = "1", default-features = false }
proc-macro2 = "1"

View File

@@ -38,7 +38,7 @@ pub fn TestComponent(
}
#[component]
fn TestMutCallback<F>(mut callback: F, value: &'static str) -> impl IntoView
fn TestMutCallback<'a, F>(mut callback: F, value: &'a str) -> impl IntoView
where
F: FnMut(u32) + 'static,
{

View File

@@ -190,7 +190,7 @@ impl ToTokens for Model {
#[allow(clippy::let_with_type_underscore)]
#[cfg_attr(
any(debug_assertions, feature="ssr"),
::leptos::leptos_dom::tracing::instrument(level = "trace", name = #trace_name, skip_all)
::leptos::leptos_dom::tracing::instrument(level = "info", name = #trace_name, skip_all)
)]
},
quote! {

View File

@@ -76,8 +76,7 @@ mod slot;
/// # runtime.dispose();
/// ```
///
/// 3. Components (functions annotated with `#[component]`) can be inserted as camel-cased tags. (Generics
/// on components are specified as `<Component<T>/>`, not the turbofish `<Component::<T>/>`.)
/// 3. Components (functions annotated with `#[component]`) can be inserted as camel-cased tags
/// ```rust
/// # use leptos::*;
/// # let runtime = create_runtime();
@@ -603,12 +602,10 @@ pub fn component(args: proc_macro::TokenStream, s: TokenStream) -> TokenStream {
false
};
let Ok(mut dummy) = syn::parse::<DummyModel>(s.clone()) else {
return s;
};
let mut dummy = syn::parse::<DummyModel>(s.clone());
let parse_result = syn::parse::<component::Model>(s);
if let (ref mut unexpanded, Ok(model)) = (&mut dummy, parse_result) {
if let (Ok(ref mut unexpanded), Ok(model)) = (&mut dummy, parse_result) {
let expanded = model.is_transparent(is_transparent).into_token_stream();
unexpanded.sig.ident =
unmodified_fn_name_from_fn_name(&unexpanded.sig.ident);
@@ -618,13 +615,15 @@ pub fn component(args: proc_macro::TokenStream, s: TokenStream) -> TokenStream {
#[allow(non_snake_case, dead_code, clippy::too_many_arguments)]
#unexpanded
}
} else {
} else if let Ok(mut dummy) = dummy {
dummy.sig.ident = unmodified_fn_name_from_fn_name(&dummy.sig.ident);
quote! {
#[doc(hidden)]
#[allow(non_snake_case, dead_code, clippy::too_many_arguments)]
#dummy
}
} else {
quote! {}
}
.into()
}
@@ -703,12 +702,10 @@ pub fn component(args: proc_macro::TokenStream, s: TokenStream) -> TokenStream {
#[proc_macro_error::proc_macro_error]
#[proc_macro_attribute]
pub fn island(_args: proc_macro::TokenStream, s: TokenStream) -> TokenStream {
let Ok(mut dummy) = syn::parse::<DummyModel>(s.clone()) else {
return s;
};
let mut dummy = syn::parse::<DummyModel>(s.clone());
let parse_result = syn::parse::<component::Model>(s);
if let (ref mut unexpanded, Ok(model)) = (&mut dummy, parse_result) {
if let (Ok(ref mut unexpanded), Ok(model)) = (&mut dummy, parse_result) {
let expanded = model.is_island().into_token_stream();
if !matches!(unexpanded.vis, Visibility::Public(_)) {
unexpanded.vis = Visibility::Public(Pub {
@@ -723,13 +720,15 @@ pub fn island(_args: proc_macro::TokenStream, s: TokenStream) -> TokenStream {
#[allow(non_snake_case, dead_code, clippy::too_many_arguments)]
#unexpanded
}
} else {
} else if let Ok(mut dummy) = dummy {
dummy.sig.ident = unmodified_fn_name_from_fn_name(&dummy.sig.ident);
quote! {
#[doc(hidden)]
#[allow(non_snake_case, dead_code, clippy::too_many_arguments)]
#dummy
}
} else {
quote! {}
}
.into()
}

View File

@@ -156,7 +156,7 @@ use std::any::{Any, TypeId};
/// ```
#[cfg_attr(
any(debug_assertions, feature = "ssr"),
instrument(level = "trace", skip_all,)
instrument(level = "debug", skip_all,)
)]
#[track_caller]
pub fn provide_context<T>(value: T)
@@ -230,7 +230,7 @@ where
/// ```
#[cfg_attr(
any(debug_assertions, feature = "ssr"),
instrument(level = "trace", skip_all,)
instrument(level = "debug", skip_all,)
)]
pub fn use_context<T>() -> Option<T>
where

View File

@@ -341,7 +341,7 @@ where
any(debug_assertions, feature = "ssr"),
instrument(
name = "Effect::run()",
level = "trace",
level = "debug",
skip_all,
fields(
defined_at = %self.defined_at,

View File

@@ -537,7 +537,7 @@ where
any(debug_assertions, feature = "ssr"),
instrument(
name = "Memo::run()",
level = "trace",
level = "debug",
skip_all,
fields(
defined_at = %self.defined_at,

View File

@@ -86,7 +86,7 @@ use std::{
#[cfg_attr(
any(debug_assertions, feature="ssr"),
instrument(
level = "trace",
level = "debug",
skip_all,
fields(
ty = %std::any::type_name::<T>(),
@@ -120,7 +120,7 @@ where
#[cfg_attr(
any(debug_assertions, feature="ssr"),
instrument(
level = "trace",
level = "debug",
skip_all,
fields(
ty = %std::any::type_name::<T>(),
@@ -169,7 +169,7 @@ where
#[cfg_attr(
any(debug_assertions, feature="ssr"),
instrument(
level = "trace",
level = "debug",
skip_all,
fields(
ty = %std::any::type_name::<T>(),
@@ -295,7 +295,7 @@ where
#[cfg_attr(
any(debug_assertions, feature="ssr"),
instrument(
level = "trace",
level = "debug",
skip_all,
fields(
ty = %std::any::type_name::<T>(),
@@ -328,7 +328,7 @@ where
#[cfg_attr(
any(debug_assertions, feature="ssr"),
instrument(
level = "trace",
level = "debug",
skip_all,
fields(
ty = %std::any::type_name::<T>(),
@@ -500,7 +500,7 @@ where
/// (`value.read()` is equivalent to `value.with(T::clone)`.)
#[cfg_attr(
any(debug_assertions, feature = "ssr"),
instrument(level = "trace", skip_all,)
instrument(level = "debug", skip_all,)
)]
#[track_caller]
#[deprecated = "You can now use .get() on resources."]
@@ -520,7 +520,7 @@ where
/// [`Resource::read`].
#[cfg_attr(
any(debug_assertions, feature = "ssr"),
instrument(level = "trace", skip_all,)
instrument(level = "debug", skip_all,)
)]
#[track_caller]
pub fn map<U>(&self, f: impl FnOnce(&T) -> U) -> Option<U> {

View File

@@ -951,11 +951,12 @@ impl RuntimeId {
false
};
let prev_observer = SetObserverOnDrop(runtime.observer.take());
let prev_observer =
SetObserverOnDrop(self, runtime.observer.take());
untracked_result = f();
runtime.observer.set(prev_observer.0);
runtime.observer.set(prev_observer.1);
std::mem::forget(prev_observer); // avoid Drop
#[cfg(debug_assertions)]
@@ -1370,12 +1371,12 @@ impl std::hash::Hash for Runtime {
}
}
struct SetObserverOnDrop(Option<NodeId>);
struct SetObserverOnDrop(RuntimeId, Option<NodeId>);
impl Drop for SetObserverOnDrop {
fn drop(&mut self) {
_ = with_runtime(|rt| {
rt.observer.set(self.0);
rt.observer.set(self.1);
});
}
}
@@ -1392,13 +1393,14 @@ impl Drop for SetObserverOnDrop {
)]
#[inline(always)]
pub fn batch<T>(f: impl FnOnce() -> T) -> T {
let runtime_id = Runtime::current();
with_runtime(move |runtime| {
let batching = SetBatchingOnDrop(runtime.batching.get());
let batching = SetBatchingOnDrop(runtime_id, runtime.batching.get());
runtime.batching.set(true);
let val = f();
runtime.batching.set(batching.0);
runtime.batching.set(batching.1);
std::mem::forget(batching);
runtime.run_effects();
@@ -1407,12 +1409,12 @@ pub fn batch<T>(f: impl FnOnce() -> T) -> T {
.expect("tried to run a batched update in a runtime that has been disposed")
}
struct SetBatchingOnDrop(bool);
struct SetBatchingOnDrop(RuntimeId, bool);
impl Drop for SetBatchingOnDrop {
fn drop(&mut self) {
_ = with_runtime(|rt| {
rt.batching.set(self.0);
rt.batching.set(self.1);
});
}
}

View File

@@ -30,7 +30,7 @@ wasm-bindgen = { version = "0.2" }
wasm-bindgen-futures = { version = "0.4" }
lru = { version = "0.11", optional = true }
serde_json = "1.0.96"
itertools = "0.12.0"
itertools = "0.11.0"
[dependencies.web-sys]
version = "0.3"

View File

@@ -59,7 +59,7 @@ where
/// different color if its a link to the page youre currently on.
#[cfg_attr(
any(debug_assertions, feature = "ssr"),
tracing::instrument(level = "trace", skip_all,)
tracing::instrument(level = "info", skip_all,)
)]
#[component]
pub fn A<H>(

View File

@@ -11,7 +11,7 @@ use web_sys::AnimationEvent;
/// that child route is displayed. Renders nothing if there is no nested child.
#[cfg_attr(
any(debug_assertions, feature = "ssr"),
tracing::instrument(level = "trace", skip_all,)
tracing::instrument(level = "info", skip_all,)
)]
#[component]
pub fn Outlet() -> impl IntoView {

View File

@@ -43,7 +43,7 @@ pub enum Method {
/// the element it should display, and data that should be loaded alongside the route.
#[cfg_attr(
any(debug_assertions, feature = "ssr"),
tracing::instrument(level = "trace", skip_all,)
tracing::instrument(level = "info", skip_all,)
)]
#[component(transparent)]
pub fn Route<E, F, P>(
@@ -91,7 +91,7 @@ where
/// redirects to `redirect_path` instead of displaying its `view`.
#[cfg_attr(
any(debug_assertions, feature = "ssr"),
tracing::instrument(level = "trace", skip_all,)
tracing::instrument(level = "info", skip_all,)
)]
#[component(transparent)]
pub fn ProtectedRoute<P, E, F, C>(
@@ -150,7 +150,7 @@ where
/// the element it should display, and data that should be loaded alongside the route.
#[cfg_attr(
any(debug_assertions, feature = "ssr"),
tracing::instrument(level = "trace", skip_all,)
tracing::instrument(level = "info", skip_all,)
)]
#[component(transparent)]
pub fn StaticRoute<E, F, P, S>(
@@ -198,7 +198,7 @@ where
#[cfg_attr(
any(debug_assertions, feature = "ssr"),
tracing::instrument(level = "trace", skip_all,)
tracing::instrument(level = "info", skip_all,)
)]
#[allow(clippy::too_many_arguments)]
pub(crate) fn define_route(
@@ -260,7 +260,7 @@ pub struct RouteContext {
impl RouteContext {
#[cfg_attr(
any(debug_assertions, feature = "ssr"),
tracing::instrument(level = "trace", skip_all,)
tracing::instrument(level = "info", skip_all,)
)]
pub(crate) fn new(
router: &RouterContext,

View File

@@ -8,17 +8,11 @@ use cfg_if::cfg_if;
use leptos::*;
#[cfg(feature = "transition")]
use leptos_reactive::use_transition;
use std::{
cell::RefCell,
rc::Rc,
sync::atomic::{AtomicUsize, Ordering},
};
use std::{cell::RefCell, rc::Rc};
use thiserror::Error;
#[cfg(not(feature = "ssr"))]
use wasm_bindgen::JsCast;
static GLOBAL_ROUTERS_COUNT: AtomicUsize = AtomicUsize::new(0);
/// Provides for client-side and server-side routing. This should usually be somewhere near
/// the root of the application.
#[component]
@@ -57,7 +51,6 @@ pub struct RouterContext {
pub(crate) inner: Rc<RouterContextInner>,
}
pub(crate) struct RouterContextInner {
id: usize,
pub location: Location,
pub base: RouteContext,
pub possible_routes: RefCell<Option<Vec<Branch>>>,
@@ -172,7 +165,6 @@ impl RouterContext {
});
let inner = Rc::new(RouterContextInner {
id: GLOBAL_ROUTERS_COUNT.fetch_add(1, Ordering::SeqCst),
base_path: base_path.into_owned(),
path_stack: store_value(vec![location.pathname.get_untracked()]),
location,
@@ -211,10 +203,6 @@ impl RouterContext {
self.inner.base.clone()
}
pub(crate) fn id(&self) -> usize {
self.inner.id
}
/// A list of all possible routes this router can match.
pub fn possible_branches(&self) -> Vec<Branch> {
self.inner

View File

@@ -8,7 +8,6 @@ use crate::{
};
use leptos::{leptos_dom::HydrationCtx, *};
use std::{
borrow::Cow,
cell::{Cell, RefCell},
cmp::Reverse,
collections::HashMap,
@@ -66,7 +65,7 @@ use std::{
/// ```
#[cfg_attr(
any(debug_assertions, feature = "ssr"),
tracing::instrument(level = "trace", skip_all,)
tracing::instrument(level = "info", skip_all,)
)]
#[component]
pub fn Routes(
@@ -77,16 +76,15 @@ pub fn Routes(
) -> impl IntoView {
let router = use_context::<RouterContext>()
.expect("<Routes/> component should be nested within a <Router/>.");
let router_id = router.id();
let base_route = router.base();
let base = base.unwrap_or_default();
Branches::initialize(router_id, &base, children());
Branches::initialize(&base, children());
#[cfg(feature = "ssr")]
if let Some(context) = use_context::<crate::PossibleBranchContext>() {
Branches::with(router_id, &base, |branches| {
Branches::with(&base, |branches| {
*context.0.borrow_mut() = branches.to_vec()
});
}
@@ -95,8 +93,7 @@ pub fn Routes(
let current_route = next_route;
let root_equal = Rc::new(Cell::new(true));
let route_states =
route_states(router_id, base, &router, current_route, &root_equal);
let route_states = route_states(base, &router, current_route, &root_equal);
provide_context(route_states);
let id = HydrationCtx::id();
@@ -159,16 +156,15 @@ pub fn AnimatedRoutes(
) -> impl IntoView {
let router = use_context::<RouterContext>()
.expect("<Routes/> component should be nested within a <Router/>.");
let router_id = router.id();
let base_route = router.base();
let base = base.unwrap_or_default();
Branches::initialize(router_id, &base, children());
Branches::initialize(&base, children());
#[cfg(feature = "ssr")]
if let Some(context) = use_context::<crate::PossibleBranchContext>() {
Branches::with(router_id, &base, |branches| {
Branches::with(&base, |branches| {
*context.0.borrow_mut() = branches.to_vec()
});
}
@@ -197,9 +193,8 @@ pub fn AnimatedRoutes(
let prev_matches = prev
.map(|(_, r)| r)
.cloned()
.map(|location| get_route_matches(router_id, &base, location));
let matches =
get_route_matches(router_id, &base, next_route.clone());
.map(|location| get_route_matches(&base, location));
let matches = get_route_matches(&base, next_route.clone());
let same_route = prev_matches
.and_then(|p| p.first().as_ref().map(|r| r.route.key.clone()))
== matches.first().as_ref().map(|r| r.route.key.clone());
@@ -226,8 +221,7 @@ pub fn AnimatedRoutes(
let current_route = create_memo(move |_| animation_and_route.get().1);
let root_equal = Rc::new(Cell::new(true));
let route_states =
route_states(router_id, base, &router, current_route, &root_equal);
let route_states = route_states(base, &router, current_route, &root_equal);
let root = root_route(base_route, route_states, root_equal);
let node_ref = create_node_ref::<html::Div>();
@@ -272,13 +266,12 @@ pub fn AnimatedRoutes(
pub(crate) struct Branches;
type BranchesCacheKey = (usize, Cow<'static, str>);
thread_local! {
static BRANCHES: RefCell<HashMap<BranchesCacheKey, Vec<Branch>>> = RefCell::new(HashMap::new());
static BRANCHES: RefCell<HashMap<String, Vec<Branch>>> = RefCell::new(HashMap::new());
}
impl Branches {
pub fn initialize(router_id: usize, base: &str, children: Fragment) {
pub fn initialize(base: &str, children: Fragment) {
BRANCHES.with(|branches| {
#[cfg(debug_assertions)]
{
@@ -293,7 +286,7 @@ impl Branches {
}
let mut current = branches.borrow_mut();
if !current.contains_key(&(router_id, Cow::from(base))) {
if !current.contains_key(base) {
let mut branches = Vec::new();
let children = children
.as_children()
@@ -323,19 +316,15 @@ impl Branches {
true,
base,
);
current.insert((router_id, Cow::Owned(base.into())), branches);
current.insert(base.to_string(), branches);
}
})
}
pub fn with<T>(
router_id: usize,
base: &str,
cb: impl FnOnce(&[Branch]) -> T,
) -> T {
pub fn with<T>(base: &str, cb: impl FnOnce(&[Branch]) -> T) -> T {
BRANCHES.with(|branches| {
let branches = branches.borrow();
let branches = branches.get(&(router_id, Cow::from(base))).expect(
let branches = branches.get(base).expect(
"Branches::initialize() should be called before \
Branches::with()",
);
@@ -345,16 +334,14 @@ impl Branches {
}
fn route_states(
router_id: usize,
base: String,
router: &RouterContext,
current_route: Memo<String>,
root_equal: &Rc<Cell<bool>>,
) -> Memo<RouterState> {
// whenever path changes, update matches
let matches = create_memo(move |_| {
get_route_matches(router_id, &base, current_route.get())
});
let matches =
create_memo(move |_| get_route_matches(&base, current_route.get()));
// iterate over the new matches, reusing old routes when they are the same
// and replacing them with new routes when they differ
@@ -630,7 +617,7 @@ pub(crate) fn create_branch(routes: &[RouteData], index: usize) -> Branch {
#[cfg_attr(
any(debug_assertions, feature = "ssr"),
tracing::instrument(level = "trace", skip_all,)
tracing::instrument(level = "info", skip_all,)
)]
fn create_routes(
route_def: &RouteDefinition,

View File

@@ -17,7 +17,6 @@ pub(crate) struct RouteMatch {
}
pub(crate) fn get_route_matches(
router_id: usize,
base: &str,
location: String,
) -> Rc<Vec<RouteMatch>> {
@@ -25,31 +24,24 @@ pub(crate) fn get_route_matches(
{
use lru::LruCache;
use std::{cell::RefCell, num::NonZeroUsize};
type RouteMatchCache = LruCache<(usize, String), Rc<Vec<RouteMatch>>>;
thread_local! {
static ROUTE_MATCH_CACHE: RefCell<RouteMatchCache> = RefCell::new(LruCache::new(NonZeroUsize::new(32).unwrap()));
static ROUTE_MATCH_CACHE: RefCell<LruCache<String, Rc<Vec<RouteMatch>>>> = RefCell::new(LruCache::new(NonZeroUsize::new(32).unwrap()));
}
ROUTE_MATCH_CACHE.with(|cache| {
let mut cache = cache.borrow_mut();
Rc::clone(
cache.get_or_insert((router_id, location.clone()), || {
build_route_matches(router_id, base, location)
}),
)
Rc::clone(cache.get_or_insert(location.clone(), || {
build_route_matches(base, location)
}))
})
}
#[cfg(not(feature = "ssr"))]
build_route_matches(router_id, base, location)
build_route_matches(base, location)
}
fn build_route_matches(
router_id: usize,
base: &str,
location: String,
) -> Rc<Vec<RouteMatch>> {
Rc::new(Branches::with(router_id, base, |branches| {
fn build_route_matches(base: &str, location: String) -> Rc<Vec<RouteMatch>> {
Rc::new(Branches::with(base, |branches| {
for branch in branches {
if let Some(matches) = branch.matcher(&location) {
return matches;