diff --git a/examples/router/e2e/tests/router.spec.ts b/examples/router/e2e/tests/router.spec.ts
index b90e0d13f6..5fffeb8607 100644
--- a/examples/router/e2e/tests/router.spec.ts
+++ b/examples/router/e2e/tests/router.spec.ts
@@ -5,6 +5,10 @@ test.describe("Test Router example", () => {
await page.goto("/");
});
+ test("Starts on correct home page", async({ page }) => {
+ await expect(page.getByText("Select a contact.")).toBeVisible();
+ });
+
const links = [
{ label: "Bill Smith", url: "/0" },
{ label: "Tim Jones", url: "/1" },
diff --git a/examples/ssr_modes/src/app.rs b/examples/ssr_modes/src/app.rs
index 9da69a2158..8d167d4f14 100644
--- a/examples/ssr_modes/src/app.rs
+++ b/examples/ssr_modes/src/app.rs
@@ -9,13 +9,12 @@ use thiserror::Error;
pub fn App() -> impl IntoView {
// Provides context that manages stylesheets, titles, meta tags, etc.
provide_meta_context();
- let fallback = || view! { "Page not found." }.into_view();
view! {
-
+
// We’ll load the home page with out-of-order streaming and
diff --git a/examples/ssr_modes_axum/src/app.rs b/examples/ssr_modes_axum/src/app.rs
index 6b24570f2b..4592375441 100644
--- a/examples/ssr_modes_axum/src/app.rs
+++ b/examples/ssr_modes_axum/src/app.rs
@@ -9,13 +9,12 @@ use thiserror::Error;
pub fn App() -> impl IntoView {
// Provides context that manages stylesheets, titles, meta tags, etc.
provide_meta_context();
- let fallback = || view! { "Page not found." }.into_view();
view! {
-
+
// We’ll load the home page with out-of-order streaming and
diff --git a/examples/todo_app_sqlite/src/todo.rs b/examples/todo_app_sqlite/src/todo.rs
index 1f9d2ca18d..74a5f862dc 100644
--- a/examples/todo_app_sqlite/src/todo.rs
+++ b/examples/todo_app_sqlite/src/todo.rs
@@ -22,6 +22,7 @@ cfg_if! {
}
}
+/// Server functions can be given doc comments.
#[server(GetTodos, "/api")]
pub async fn get_todos() -> Result, ServerFnError> {
// this is just an example of how to access server context injected in the handlers
diff --git a/integrations/actix/tests/extract_routes.rs b/integrations/actix/tests/extract_routes.rs
deleted file mode 100644
index 67765b187e..0000000000
--- a/integrations/actix/tests/extract_routes.rs
+++ /dev/null
@@ -1,148 +0,0 @@
-use leptos::*;
-use leptos_actix::generate_route_list;
-use leptos_router::{Route, Router, Routes, TrailingSlash};
-
-#[component]
-fn DefaultApp() -> impl IntoView {
- let view = || view! { "" };
- view! {
-
-
-
-
-
-
-
-
-
- }
-}
-
-#[test]
-fn test_default_app() {
- let routes = generate_route_list(DefaultApp);
-
- // We still have access to the original (albeit normalized) Leptos paths:
- assert_same(
- &routes,
- |r| r.leptos_path(),
- &["/bar", "/baz/*any", "/baz/:id", "/baz/:name", "/foo"],
- );
-
- // ... But leptos-actix has also reformatted "paths" to work for Actix.
- assert_same(
- &routes,
- |r| r.path(),
- &["/bar", "/baz/{id}", "/baz/{name}", "/baz/{tail:.*}", "/foo"],
- );
-}
-
-#[component]
-fn ExactApp() -> impl IntoView {
- let view = || view! { "" };
- let trailing_slash = TrailingSlash::Exact;
- view! {
-
-
-
-
-
-
-
-
-
- }
-}
-
-#[test]
-fn test_exact_app() {
- let routes = generate_route_list(ExactApp);
-
- // In Exact mode, the Leptos paths no longer have their trailing slashes stripped:
- assert_same(
- &routes,
- |r| r.leptos_path(),
- &["/bar/", "/baz/*any", "/baz/:id", "/baz/:name/", "/foo"],
- );
-
- // Actix paths also have trailing slashes as a result:
- assert_same(
- &routes,
- |r| r.path(),
- &[
- "/bar/",
- "/baz/{id}",
- "/baz/{name}/",
- "/baz/{tail:.*}",
- "/foo",
- ],
- );
-}
-
-#[component]
-fn RedirectApp() -> impl IntoView {
- let view = || view! { "" };
- let trailing_slash = TrailingSlash::Redirect;
- view! {
-
-
-
-
-
-
-
-
-
- }
-}
-
-#[test]
-fn test_redirect_app() {
- let routes = generate_route_list(RedirectApp);
-
- assert_same(
- &routes,
- |r| r.leptos_path(),
- &[
- "/bar",
- "/bar/",
- "/baz/*any",
- "/baz/:id",
- "/baz/:id/",
- "/baz/:name",
- "/baz/:name/",
- "/foo",
- "/foo/",
- ],
- );
-
- // ... But leptos-actix has also reformatted "paths" to work for Actix.
- assert_same(
- &routes,
- |r| r.path(),
- &[
- "/bar",
- "/bar/",
- "/baz/{id}",
- "/baz/{id}/",
- "/baz/{name}",
- "/baz/{name}/",
- "/baz/{tail:.*}",
- "/foo",
- "/foo/",
- ],
- );
-}
-
-fn assert_same<'t, T, F, U>(
- input: &'t Vec,
- mapper: F,
- expected_sorted_values: &[U],
-) where
- F: Fn(&'t T) -> U + 't,
- U: Ord + std::fmt::Debug,
-{
- let mut values: Vec = input.iter().map(mapper).collect();
- values.sort();
- assert_eq!(values, expected_sorted_values);
-}
diff --git a/leptos_dom/src/hydration.rs b/leptos_dom/src/hydration.rs
index 104ec175f8..91502da241 100644
--- a/leptos_dom/src/hydration.rs
+++ b/leptos_dom/src/hydration.rs
@@ -53,7 +53,7 @@ mod hydrate_only {
}
});
- pub static IS_HYDRATING: Cell = Cell::new(true);
+ pub static IS_HYDRATING: Cell = const { Cell::new(true) };
}
#[allow(unused)]
@@ -133,7 +133,7 @@ mod tests {
}
}
-thread_local!(static ID: RefCell = RefCell::new(HydrationKey { outlet: 0, fragment: 0, error: 0, id: 0 }));
+thread_local!(static ID: RefCell = const {RefCell::new(HydrationKey { outlet: 0, fragment: 0, error: 0, id: 0 })});
/// Control and utility methods for hydration.
pub struct HydrationCtx;
diff --git a/leptos_dom/src/macro_helpers/tracing_property.rs b/leptos_dom/src/macro_helpers/tracing_property.rs
index 55b30611bb..365cef56f2 100644
--- a/leptos_dom/src/macro_helpers/tracing_property.rs
+++ b/leptos_dom/src/macro_helpers/tracing_property.rs
@@ -117,13 +117,13 @@ fn match_primitive() {
assert_eq!(prop, r#"{"name": "test", "value": -1}"#);
// f64
- let test = 3.14;
+ let test = 3.25;
let prop = (&&Match {
name: stringify! {test},
value: std::cell::Cell::new(Some(&test)),
})
.spez();
- assert_eq!(prop, r#"{"name": "test", "value": 3.14}"#);
+ assert_eq!(prop, r#"{"name": "test", "value": 3.25}"#);
// bool
let test = true;
diff --git a/leptos_reactive/src/diagnostics.rs b/leptos_reactive/src/diagnostics.rs
index d026592b51..15e12c144d 100644
--- a/leptos_reactive/src/diagnostics.rs
+++ b/leptos_reactive/src/diagnostics.rs
@@ -26,7 +26,7 @@ cfg_if::cfg_if! {
use std::cell::Cell;
thread_local! {
- static IS_SPECIAL_ZONE: Cell = Cell::new(false);
+ static IS_SPECIAL_ZONE: Cell = const { Cell::new(false) };
}
}
}
diff --git a/leptos_reactive/src/hydration.rs b/leptos_reactive/src/hydration.rs
index 936e68f35f..c2166787ac 100644
--- a/leptos_reactive/src/hydration.rs
+++ b/leptos_reactive/src/hydration.rs
@@ -332,7 +332,7 @@ impl Default for SharedContext {
#[cfg(feature = "experimental-islands")]
thread_local! {
- pub static NO_HYDRATE: Cell = Cell::new(true);
+ pub static NO_HYDRATE: Cell = const { Cell::new(true) };
}
#[cfg(feature = "experimental-islands")]
diff --git a/leptos_reactive/src/resource.rs b/leptos_reactive/src/resource.rs
index 3d5e89839f..84acc41037 100644
--- a/leptos_reactive/src/resource.rs
+++ b/leptos_reactive/src/resource.rs
@@ -1518,7 +1518,7 @@ impl UnserializableResource for ResourceState {
}
thread_local! {
- static SUPPRESS_RESOURCE_LOAD: Cell = Cell::new(false);
+ static SUPPRESS_RESOURCE_LOAD: Cell = const { Cell::new(false) };
}
#[doc(hidden)]
diff --git a/leptos_reactive/src/stored_value.rs b/leptos_reactive/src/stored_value.rs
index 0ec2e95a62..5344831e1d 100644
--- a/leptos_reactive/src/stored_value.rs
+++ b/leptos_reactive/src/stored_value.rs
@@ -242,7 +242,7 @@ impl StoredValue {
with_runtime(|runtime| {
let n = {
let values = runtime.stored_values.borrow();
- values.get(self.id).map(Rc::clone)
+ values.get(self.id).cloned()
};
if let Some(n) = n {
diff --git a/router/src/components/route.rs b/router/src/components/route.rs
index d25355cb0b..1dcda396c4 100644
--- a/router/src/components/route.rs
+++ b/router/src/components/route.rs
@@ -1,7 +1,6 @@
use crate::{
matching::{resolve_path, PathMatch, RouteDefinition, RouteMatch},
ParamsMap, RouterContext, SsrMode, StaticData, StaticMode, StaticParamsMap,
- TrailingSlash,
};
use leptos::{leptos_dom::Transparent, *};
use std::{
@@ -15,17 +14,7 @@ use std::{
};
thread_local! {
- static ROUTE_ID: Cell = Cell::new(0);
-}
-
-// RouteDefinition.id is `pub` and required to be unique.
-// Should we make this public so users can generate unique IDs?
-pub(in crate::components) fn new_route_id() -> usize {
- ROUTE_ID.with(|id| {
- let next = id.get() + 1;
- id.set(next);
- next
- })
+ static ROUTE_ID: Cell = const { Cell::new(0) };
}
/// Represents an HTTP method that can be handled by this route.
@@ -76,11 +65,6 @@ pub fn Route(
/// accessed with [`use_route_data`](crate::use_route_data).
#[prop(optional, into)]
data: Option,
- /// How this route should handle trailing slashes in its path.
- /// Overrides any setting applied to [`crate::components::Router`].
- /// Serves as a default for any inner Routes.
- #[prop(optional)]
- trailing_slash: Option,
/// `children` may be empty or include nested routes.
#[prop(optional)]
children: Option,
@@ -99,7 +83,6 @@ where
data,
None,
None,
- trailing_slash,
)
}
@@ -132,11 +115,6 @@ pub fn ProtectedRoute
(
/// accessed with [`use_route_data`](crate::use_route_data).
#[prop(optional, into)]
data: Option,
- /// How this route should handle trailing slashes in its path.
- /// Overrides any setting applied to [`crate::components::Router`].
- /// Serves as a default for any inner Routes.
- #[prop(optional)]
- trailing_slash: Option,
/// `children` may be empty or include nested routes.
#[prop(optional)]
children: Option,
@@ -165,7 +143,6 @@ where
data,
None,
None,
- trailing_slash,
)
}
@@ -194,11 +171,6 @@ pub fn StaticRoute(
/// accessed with [`use_route_data`](crate::use_route_data).
#[prop(optional, into)]
data: Option,
- /// How this route should handle trailing slashes in its path.
- /// Overrides any setting applied to [`crate::components::Router`].
- /// Serves as a default for any inner Routes.
- #[prop(optional)]
- trailing_slash: Option,
/// `children` may be empty or include nested routes.
#[prop(optional)]
children: Option,
@@ -221,7 +193,6 @@ where
data,
Some(mode),
Some(Arc::new(static_params)),
- trailing_slash,
)
}
@@ -239,7 +210,6 @@ pub(crate) fn define_route(
data: Option,
static_mode: Option,
static_params: Option,
- trailing_slash: Option,
) -> RouteDefinition {
let children = children
.map(|children| {
@@ -256,8 +226,14 @@ pub(crate) fn define_route(
})
.unwrap_or_default();
+ let id = ROUTE_ID.with(|id| {
+ let next = id.get() + 1;
+ id.set(next);
+ next
+ });
+
RouteDefinition {
- id: new_route_id(),
+ id,
path,
children,
view,
@@ -266,7 +242,6 @@ pub(crate) fn define_route(
data,
static_mode,
static_params,
- trailing_slash,
}
}
diff --git a/router/src/components/router.rs b/router/src/components/router.rs
index 4ce714333d..0238821303 100644
--- a/router/src/components/router.rs
+++ b/router/src/components/router.rs
@@ -32,16 +32,13 @@ pub fn Router(
/// A signal that will be set while the navigation process is underway.
#[prop(optional, into)]
set_is_routing: Option>,
- /// How trailing slashes should be handled in [`Route`] paths.
- #[prop(optional)]
- trailing_slash: Option,
/// The `` should usually wrap your whole page. It can contain
/// any elements, and should include a [`Routes`](crate::Routes) component somewhere
/// to define and display [`Route`](crate::Route)s.
children: Children,
) -> impl IntoView {
// create a new RouterContext and provide it to every component beneath the router
- let router = RouterContext::new(base, fallback, trailing_slash);
+ let router = RouterContext::new(base, fallback);
provide_context(router);
provide_context(GlobalSuspenseContext::new());
if let Some(set_is_routing) = set_is_routing {
@@ -63,7 +60,6 @@ pub(crate) struct RouterContextInner {
id: usize,
pub location: Location,
pub base: RouteContext,
- trailing_slash: Option,
pub possible_routes: RefCell