Releases: leptos-rs/leptos
v0.5.4
v0.5.4
v0.5.3
inadvertently introduced a regression in the <A/>
tag that broke [aria-current=page]
. Here's 0.5.4 with a fix!
0.5.3 release notes below:
Along with the usual set of bugfixes and small improvements, there are two noteworthy additions in this release.
Improved rust-analyzer support in #[component]
macro body
Good LSP support for proc macros is hard, because proc macros depend on parsing a stream of input into a valid Rust syntax tree, but while typing you are constantly creating a stream of new, invalid trees. This release tweaks how the #[component]
macro emits code in order to enable better rust-analyzer support within the body of components.
If you've disabled rust-analyzer inside #[component]
for better DX, try toggling that off and see if this is a better experience than it was before!
Apologies for any regressions this causes. Please report any issues that arise.
There is still additional work to be done to support rust-analyzer in the
view!
macro. The hoped-for improvements here are solely inside the#[component]
body.
Optional Context <Provider/>
Component
Since 0.5.0, there've been a couple instances of bugs or confusing behavior related to the fact that context now follows the reactive graph, not the component tree (see #1986, #2038).
This release includes a <Provider/>
component that provides a certain value via context only to its children:
#[component]
pub fn App() -> impl IntoView {
// each Provider will only provide the value to its children
view! {
<Provider value=1u8>
// correctly gets 1 from context
{use_context::<u8>().unwrap_or(0)}
</Provider>
<Provider value=2u8>
// correctly gets 2 from context
{use_context::<u8>().unwrap_or(0)}
</Provider>
// does not find any u8 in context
{use_context::<u8>().unwrap_or(0)}
}
}
provide_context
continues working as it has since 0.5.0, and if you're using it without problems you can ignore this, or use it if you prefer to aesthetics. If you're in a situation where you need to provide multiple context values of the same type and ensure that they are scoped correctly and that siblings do not overwrite one another, use <Provider/>
. If you have no idea what I mean, check the issues above for examples of the bugs this fixes.
What's Changed
- docs: make it easy to see how to run each example in its README by @gbj in #2085
- Fix
aria-current
attribute value by @alexisfontaine in #2089
Full Changelog: v0.5.3...v0.5.4
v0.5.3
v0.5.3
Along with the usual set of bugfixes and small improvements, there are two noteworthy additions in this release.
Improved rust-analyzer support in #[component]
macro body
Good LSP support for proc macros is hard, because proc macros depend on parsing a stream of input into a valid Rust syntax tree, but while typing you are constantly creating a stream of new, invalid trees. This release tweaks how the #[component]
macro emits code in order to enable better rust-analyzer support within the body of components.
If you've disabled rust-analyzer inside #[component]
for better DX, try toggling that off and see if this is a better experience than it was before!
Apologies for any regressions this causes. Please report any issues that arise.
There is still additional work to be done to support rust-analyzer in the
view!
macro. The hoped-for improvements here are solely inside the#[component]
body.
Optional Context <Provider/>
Component
Since 0.5.0, there've been a couple instances of bugs or confusing behavior related to the fact that context now follows the reactive graph, not the component tree (see #1986, #2038).
This release includes a <Provider/>
component that provides a certain value via context only to its children:
#[component]
pub fn App() -> impl IntoView {
// each Provider will only provide the value to its children
view! {
<Provider value=1u8>
// correctly gets 1 from context
{use_context::<u8>().unwrap_or(0)}
</Provider>
<Provider value=2u8>
// correctly gets 2 from context
{use_context::<u8>().unwrap_or(0)}
</Provider>
// does not find any u8 in context
{use_context::<u8>().unwrap_or(0)}
}
}
provide_context
continues working as it has since 0.5.0, and if you're using it without problems you can ignore this, or use it if you prefer to aesthetics. If you're in a situation where you need to provide multiple context values of the same type and ensure that they are scoped correctly and that siblings do not overwrite one another, use <Provider/>
. If you have no idea what I mean, check the issues above for examples of the bugs this fixes.
Complete Changelog
- fix: relax
'static
bound onas_child_of_current_owner
by @gbj in #1955 IntoView
andIntoAttribute
forstd::fmt::Arguments
improvements by @tqwewe in #1947- workflows: bump setup-node to version 4. by @martinfrances107 in #1944
- Minor: bumped tj-actions/changed-files to @39. by @martinfrances107 in #1942
- feat: add
new
method toTrigger
by @tqwewe in #1935 - feat: impl
IntoAttribute
forCow<'static, str>
by @tqwewe in #1945 - chore: Add server to procMacro for helix as well by @kerkmann in #1951
- Allow arbitrary attributes for anchor component by @koopa1338 in #1953
- fix: add
leptos_axum::build_static_routes
(closes #1843) by @gbj in #1855 - Implement
IntoAttribute
forTextProp
by @SleeplessOne1917 in #1925 - chore: fix clippy on
login_with_token_csr_only
by @gbj in #1965 - fix: router docs feature
stable
tonightly
by @chrisp60 in #1959 - chore: typed-builder and typed-builder-macro - bumped version numbers. by @martinfrances107 in #1958
- fix:
leptos_router::params_map!
by @chrisp60 in #1973 - docs: Fix 08_parent_child.md callback example code. by @gibbz00 in #1976
- Fix [] url in 12_transition.md by @gibbz00 in #1980
- book: point
leptos_server
docs.rs url to latest version. by @gibbz00 in #1982 - docs: clarify need to provide context in two places for server functions by @gbj in #1983
- fix: treat Suspense as containing a Set of resources, not a counter by @gbj in #1985
- examples: fix
hackernews_js_fetch
style.css
path (closes #1992) by @gbj in #1994 - fix: run
<ErrorBoundary/>
in a child so siblings don't collide (closes #1987) by @gbj in #1991 - examples: remove incorrect CSR information for
hackernews_js_fetch
example by @gbj in #1997 - fix: correctly reset island/not-island state of SSRed Suspense streaming into island (closes #1996) by @gbj in #2000
- book: Fix link in metadata.md by @gibbz00 in #1999
- docs: fix CodeSandbox for resources by @gbj in #2002
- docs: remove outdated
APP_ENVIRONMENT
variable by @gbj in #2013 - feat:
Action::new
andAction::server
by @chrisp60 in #1998 - chore: remove duplicate benchmarks in
leptos_reactive
by @gbj in #2014 - docs: add note about context shadowing (closes #1986) by @gbj in #2015
- re-export slice! by @blorbb in #2008
- fix: allow nested functions in
Attribute
(closes #2023) by @gbj in #2027 - fix: use
create_effect
for<Portal/>
to avoid hydration issues (closes #2010) by @gbj in #2029 - impl
Default
forTextProp
by @blorbb in #2016 - Docs:
ActionForm
examples for complex arguments by @chrisp60 in #2017 - fix document book input name query by @datewu in #2024
- Minor: stop using std::fmt, instead used core::fmt. by @martinfrances107 in #2033
- Updates to Leptos Book by @diversable in #2036
- examples: add CSR with server functions example (closes #1975) by @gbj in #2031
- Have fetch example conform to docs guidance around using and in conjunction by @MoonKraken in #2035
- feat:
<Provider/>
component to fix context shadowing (closes #2038) by @gbj in #2040 - updated axum session to latest 0.9 in examples by @genusistimelord in #2049
- ci(examples): fix portal test by @gbj in #2051
- docs: add warning for nested
Fn
in attribute (see #2023) by @gbj in #2045 - fix: correctly mark
Trigger
as clean when it is re-tracked (closes #1948, #2048) by @gbj in #2059 - Add instruction to install trunk to examples/README.md by @hpepper in #2064
- fix: dispose previous route or outlet before rendering new one (closes #2070) by @gbj in #2071
- ci(leptos): run ci on change instead of check by @agilarity in #2061
- fix: make prop serialization opt-in for devtools (closes #1952) by @gbj in #2081
- fix: improved rust-analyzer support in
#[component]
macro? by @gbj in #2075
New Contributors
- @gibbz00 made their first contribution in #1976
- @datewu made their first contribution in #2024
- @diversable made their first contribution in #2036
- @MoonKraken made their first contribution in #2035
- @hpepper made their first contribution in #2064
Full Changelog: v0.5.2...v0.5.3
v0.5.2
This has a bunch of bugfixes, small docs improvements, etc. but there are actually a bunch of cool new features, mostly from our growing body of contributors. See the full changelog below, but here are some highlights (apologies if I missed anything big)
Features
extractor()
function with better API
The extract
API is awkward due to closure. This adds an extractor
function which is a little more ergonomic.
#[derive(Deserialize, Serialize, Debug, Clone)]
pub struct Search {
q: String,
}
// Actix
#[server]
pub async fn query_extract() -> Result<Search, ServerFnError> {
use actix_web::web::Query;
use leptos_actix::extractor;
let Query(query) = extractor().await?;
Ok(query)
}
// Axum
#[server]
pub async fn data() -> Result<Search, ServerFnError> {
use axum::extract::Query;
use leptos_axum::extractor;
let Query(query) = extractor().await?;
Ok(query)
}
<Portal/>
Adds a portal component that lets you render some view mounted in a location other than where it appears in the view tree.
<Show when=show_overlay fallback=|| ()>
<div>Show</div>
<Portal mount=document().get_element_by_id("app").unwrap()>
<div style="position: fixed; z-index: 10; width: 100vw; height: 100vh; top: 0; left: 0; background: rgba(0, 0, 0, 0.8); color: white;">
<p>This is in the body element</p>
<button id="btn-hide" on:click=move |_| set_show_overlay(false)>
Close Overlay
</button>
<button id="btn-toggle" on:click=move |_| set_show_inside_overlay(!show_inside_overlay())>
Toggle inner
</button>
<Show when=show_inside_overlay fallback=|| view! { "Hidden" }>
Visible
</Show>
</div>
</Portal>
</Show>
Server Function Named Arguments
Now that we've made all server function arguments optional, this adds in the ability to pass in one or more named arguments:
#[server(endpoint = "/path/to/my/endpoint")]
pub async fn my_server_action() -> Result<(), ServerFnError> {
Ok(())
}
#[server(encoding = "GetJson")]
pub async fn my_server_action() -> Result<(), ServerFnError> {
Ok(())
}
Directives
Adds support for directive functions, which can be used with use:
in the view:
// This doesn't take an attribute value
fn my_directive(el: HtmlElement<AnyElement>) {
// do sth
}
// This requires an attribute value
fn another_directive(el: HtmlElement<AnyElement>, params: i32) {
// do sth
}
// ... in the view
view! {
<div use:my_directive></div>
<SomeComponent use:another_directive=5 />
}
slice!()
macro
Makes it easier to define slices. Expands to the same output as create_slice
:
#[derive(Default)]
pub struct State {
count: i32,
name: String,
}
let state = create_rw_signal(State::default());
let (count, set_count) = slice!(state.count);
What's Changed
- docs: clarify what "once per signal change" means by @arcstur in #1858
- fix: documentation in
leptos_reactive::Trigger
by @hiraginoyuki in #1844 - feat: add
extractor
functions with better API thanextract
by @gbj in #1859 - docs: add islands guide/demo to the docs by @gbj in #1861
- Remove extra "```rust" and add closing bracket to Testing docs by @he00741098 in #1870
- fix: Add missing argument name to WrapsChildren component in section 3.9 of the book by @johnnynotsolucky in #1866
- fix: Prop-drilling example in Parent-Child Communication section of the book by @johnnynotsolucky in #1865
- Fix: use placeholder in comments for empty component names by @flosse in #1850
- Portal by @maccesch in #1820
- Improvements for the book - Issue #1845 by @obioma in #1856
- fix: hydration ID clash with Suspense > Outlet > Suspense (closes #1863) by @gbj in #1864
- fix: correctly untrack in
.try_with_untracked
(closes #1880) by @gbj in #1881 - feat: Implement Default trait for RwSignal and StoredValue by @luoxiaozero in #1877
- fix munged markdown by @dandante in #1873
- docs: add some missing
#[must_use]
to avoid accidental()
rendering by @gbj in #1885 - Fix failing
cargo make lint
forhackernews_js_fetch
by @gbj in #1887 - feat: add reasonable fallback behavior for
ActionForm
in an island by @gbj in #1888 - fix: ensure there's no reactive tracking in an
on_cleanup
(closes #1882) by @gbj in #1889 - Custom attributes on head tags by @ymijorski in #1874
- refactor: tailwind examples by @azzamsa in #1875
- fix: properly handle trailing
/
in splat routes (closes #1764) by @gbj in #1890 - docs: update Dockerfile in deployment.md to work with [email protected] by @quanhua92 in #1898
- feat: add
new
method toNodeRef
by @tqwewe in #1896 - fix: bug with client-side routing no longer working due to different origin by @gbj in #1899
- Remove
Clone
requirement onSignalWith
forResource
by @Xendergo in #1895 - chore: tweak tracing levels by @gbj in #1901
- fix: properly handle trailing
/
in more routes by @PianoPrinter in #1900 - feat(router): Add the target attribute to the A component by @luoxiaozero in #1906
- fix: maintain hash when setting query signal (closes #1902) by @gbj in #1908
- docs: fix typo by @saikatdas0790 in #1910
- fix:
try_update()
andtry_set()
onResource
should not panic (closes #1915) by @gbj in #1916 - feat: optional named arguments for #[server] macro (closes #1621) by @safx in #1904
- feat: directives by @maccesch in #1821
- fix: router should still scroll to hash even if path didn't change (closes #1907) by @gbj in #1917
- docs: better document
default
andwasm
features onleptos_axum
(closes #1872) by @gbj in #1883 - docs: add chapter on nested reactivity and iteration by @gbj in #1920
- chore: please clippy by @gbj in #1924
- feat: Add local attribute for Await by @kerkmann in #1922
- Clippy: use .first() [not .get(0)] by @martinfrances107 in #1929
- docs: added Callback to documentation and examples. by @maccesch in #1926
- Add
replace
property to form component by @koopa1338 in #1923 - feat: add a derive macro for
create_slice()
by @SadraMoh in #1867 - chore: cargo doc -- removed lint warnings. by @martinfrances107 in #1936
- docs: Improve create_resource docs by @nikhilraojl in #1918
- chore: remove
wee_alloc
to make Dependabot happy by @gbj in #1938 - fix: misaligned
</head>
tags in streaming responses (closes #1930) by @gbj in #1932 - fix: use separate key in hydration ID for router outlets (closes #1909) by @gbj in #1939
- chore: fix SSR tests by @gbj in #1943
New Contributors
- @arcstur made their first contribution in #1858
- @hiraginoyuki made their first contribution in #1844
- @johnnynotsolucky made their first contribution in #1866
- @obioma made their first contribution in #1856
- @dandante made their first contribution in #1873
- @ymijorski made their first contribution in #1874
- @azzamsa made their first contribution in #1875
- @quanhua92 made their first contribution in #1898
- @Xendergo made their first contribution in #1895
- @PianoPrinter made their first contribution in #1900
- @saikatdas0790 made their first contribution in #1910
- @kerkmann made their first contribution in #1922
- @koopa1338 made their first contribution in #1923
- @nikhilraojl made their first contribution in #1...
v0.5.1
This is primarily a bugfix release, but it also includes a new feature: making the fallback
prop on Show
, Suspense
, and Transition
optional.
For 0.5 release notes in general, click here.
What's Changed
- docs: fix
For
view prop name (closes #1813) by @gbj in #1814 - Missing docs and
Copy
impl forCallback
by @gbj in #1818 - Fix template! cfg condition by @Dragonink in #1822
- Docs: DX improvements: add section about jetbrains
intellij-rust
by @sebadob in #1804 - made show fallback optional by @maccesch in #1817
- Fixes #1828, making SSR behavior match the Hydrate behavior. by @dgsantana in #1829
- fix: make explicit allowances for local-only suspense fragments in SSR/hydrate mode (closes #1823) by @gbj in #1824
- fix: correctly quote spread attributes in
{..attrs}
syntax (fixes #1826) by @gbj in #1831 - Allow disposing of Signal & StoredValue by @PaulWagener in #1849
- Make Async Mode return Content-Type header in Response by @benwis in #1851
- feat: support stored values in
with!
andupdate!
by @blorbb in #1836 - Removed warning in build artefacts. by @martinfrances107 in #1840
- fix: update log debug to use get_untracked for logged in user to resolve client side console error by @kevinold in #1834
- fix: panic during
generate_route_list
if you immediately dispatch an action (closes #1832) by @gbj in #1853 - fix:
clippy
"needless lifetimes" warning (closes #1825) by @gbj in #1852 - "#two" was being hidden. Added another # to unhide by @he00741098 in #1847
New Contributors
- @Dragonink made their first contribution in #1822
- @kevinold made their first contribution in #1834
- @he00741098 made their first contribution in #1847
Full Changelog: v0.5.0...v0.5.1
v0.5.0
v0.5.0
Goodbye, Scope
This long-awaited release changes the nature of the reactive system by removing the entire concept of explicit Scope
and the ubiquitous cx
variable.
The primary impetus behind this change is that it increases the correctness of the behavior of the reactive system, and fixes several persistent issues.
Click here for more details.
In order to provide signals that implement `Copy` are are `'static` and are therefore easy to use with closures and event listeners in 100% safe Rust, Leptos allocates memory for signals, memos, and effects in an arena. This raises the question: When is it safe to deallocate/dispose of these signals?From 0.0 to 0.4, Leptos allocated signals in a dedicated Scope
, which was ubiquitous in APIs. This had several drawbacks
- Ergonomics: It was annoying additional boilerplate to pass around.
- Trait implementations: Needing an additional
Scope
argument on many functions prevented us from implementing many traits that could not take an additional argument on signals, likeFrom
,Serialize
/Deserialize
. - Correctness: Two characteristics made this system somewhat broken
- The
Scope
was stored in a variable that was passed around, meaning that the βwrongβ scope could be passed into functions (most frequentlyResource::read()
). If, for example, a derived signal or memo read from a resource in the component body, and was called under aSuspense
lower in the tree, theScope
used would be from the parent component, not theSuspense
. This was just wrong, but involved wrapping the function in another closure to pass in the correctScope
. - It was relatively easy to create situations, that could leak memory unless child
Scope
s were manually created and disposed, or in whichon_cleanup
was never called. (See #802 and #918 for more background.)
The solution to this problem was to do what I should have been doing a year ago, and merge the memory allocation function of Scope
into the reactive graph itself, which already handles reactive unsubscriptions and cleanup. JavaScript doesnβt deal with memory management, but SolidJS handles its onCleanup
through a concept of reactive ownership; disposing of memory for our signals is really just a case of cleanup on an effect or memo rerunning.
Essentially, rather than being owned by a Scope
every signal, effect, or memo is now owned by its parent effect or memo. (If itβs in an untrack
, thereβs no reactive observer but the reactive owner remains.) Every time an effect or memo reruns, it disposes of everything βbeneathβ it in the tree. This makes sense: for a signal to be owned by an effect/memo, it must have been created during the previous run, and will be recreated as needed during the next run, so this is the perfect time to dispose of it.
It also has the fairly large benefit of removing the need to pass cx
or Scope
variables around at all, and allowing the implementation of a bunch of different traits on the various signal types.
Now that we don't need an extra Scope
argument to construct them, many of the signal types now implement Serialize
/Deserialize
directly, as well as From<T>
. This should make it significantly easier to do things like "reactively serialize a nested data structure in a create_effect
" β this removed literally dozens of lines of serialization/deserialization logic and a custom DTO from the todomvc
example. Serializing a signal simply serializes its value, in a reactive way; deserializing into a signal creates a new signal containing that deserialized value.
Migration is fairly easy. 95% of apps will migrate completely by making the following string replacements:
cx: Scope,
=> (empty string)cx: Scope
=> (empty string)cx,
=> (empty string)(cx)
=>()
|cx|
=>||
Scope,
=> (empty string)Scope
=> (empty string) as needed- You may have some
|_, _|
that become|_|
or|_|
that become||
, particularly for thefallback
props on<Show/>
and<ErrorBoundary/>
.
Basically, there is no longer a Scope
type, and anything that used to take it can simply be deleted.
For the 5%: if you were doing tricky things like storing a Scope
somewhere in a struct or variable and then reusing it, you should be able to achieve the same result by storing Owner::current()
somewhere and then later using it in with_owner(owner, move || { /* ... */ })
. If you have issues with this kind of migration, please let me know by opening an issue or discussion thread and we can work through the migration.
Islands
This release contains an initial, but very functional, implementation of the βislands architectureβ for Leptos.
This adds an experimental-islands
feature that opts you into a rendering mode that's different from the traditional server-rendered/client-hydrated model described here, in which the entire page requested is rendered to HTML on the server for the first request, and then runs on the client to hydrate this server-rendered HTML, and subsequent navigations take place by rendering pages in the browser.
The
experimental-
inexperimental-islands
means βparts of this API may need to change, and I wonβt guarantee that its APIs wonβt break during 0.5,β but I have no reasons to believe there are significant issues, and I have no planned API changes at present.
With this islands feature on, components are only rendered on the server, by default. Navigations follow the traditional/multi-page-app (MPA) style of navigating by fetching a new HTML page from the server. The name "islands" comes from the concept of the "islands architecture," in which you opt into small βislandsβ of interactivity in an βoceanβ of server-rendered, non-interactive HTML.
This allows reducing the WASM binary size by a lot (say ~80% for a typical demo app), making the time-to-interactive for a page load much faster. It also allows you to treat most components as βserver componentsβ and use server-only APIs, because those plain components will never need to be rendered in the browser.
I still need to write some guide-style docs for the book, but I tried to put a pretty good amount of information in the PR, which you should read if youβre interested in this topic or in trying out islands.
Thereβs significant additional exploration that will take place in this direction. Expect a longer treatment in an upcoming updated roadmap posted as a pinned issue.
Additional Reading
- Jason Miller, βIslands Architectureβ, Jason Miller
- Ryan Carniato, βIslands & Server Components & Resumability, Oh My!β
- βIslands Architecturesβ on patterns.dev
- Astro Islands
Static Site Generation
This release includes some preliminary work on building static site rendering directly into the framework, mostly as part of leptos_router
and the server integrations. Static site generation is built off of two key components, a new <StaticRoute />
component and the leptos_router::build_static_routes
function.
StaticRoute
defines a new static route. In order to be a static route, all parent routes must be static in order to ensure that complete URLs can be built as static pages. A βstatic routeβ means that a page can be rendered as a complete HTML page that is then cached and served on subsequent requests, rather than dynamically rendered, significantly reducing the serverβs workload per request.
StaticRoute
takes a path and view (like any Route
) and a static_params
prop. This is a function that returns a Future
, which is used to provide a map of all the possible values for each route param. These static params are generated on the server. This means you can do something like call a #[server]
function or access a database or the server filesystem. For example, if you have a /post/:id
path, you might query the database for a list of all blog posts and use that to generate a set of possible params.
StaticRoute
can be given an optional mode: StaticMode::Upfront
(the default) or StaticMode::Incremental
. Upfront
means that all given routes will be generated when you call build_static_routes
, and a 404 will be returned for any other pages. Incremental
means that all the options you give in static_params
will be generated up front, and additional pages will be generated when first requested and then cached.
Where our routes are defined, we can include a StaticRoute
:
view! {
<Routes>
<StaticRoute
mode=StaticMode::Incremental
path="/incr/:id"
view=StaticIdView
static_params=move || Box::pin(async move {
let mut map = StaticParamsMap::default();
map.insert("id".to_string(), vec![(1).to_string(), (2).to_string()]);
map
})
/>
</Routes>
}
In main.rs
, we build the static routes for the site on server startup:
let (routes, static_data_map) = generate_route_list_with_ssg(App);
build_static_routes(&conf.leptos_options, App, &routes, &static_data_map)
.await
.unwrap();
More to Come
There is additional work needed here as far as providing examples, and building out the story for things like invalidation (when to rebuild a page) and build hooks (when to build additional pages).
Other New Features in 0.5
attr:
on components, and spreading attributes
Makes it much easier to pass some set of attributes to be given to a component (with attr:
passed into a #[prop(attrs)]
prop), and then to spread them onto an element with {..attrs}
syntax.
#[...
v0.5.0-rc3
Most significant breaking change you might notice is that generate_route_list
in Axum is no longer async
and doesn't need .await
, as is already true for Actix.
Big features including static site generation included here, but I will wait for an actual release to write up notes because it's Friday afternoon!
What's Changed (since v0.5.0-rc2)
- fix(examples/error_boundary): ci error by @agilarity in #1739
- fix:
Callback
cloning by @lpotthast in #1744 - fix:
Resource::with()
pt. 2 β (closes #1742 without reopening #1711) by @gbj in #1750 - chore(server_fn_macro): improve docs by @fundon in #1733
- fix:
Resource::with()
(pt. 3!) β closes #1751 without breaking #1742 or #1711 by @gbj in #1752 - feat: make
Transition
set_pending
use#[prop(into)]
by @gbj in #1746 - 1742-2 by @gbj in #1753
- chore(server_fn): improve docs by @fundon in #1734
- feat: correctly
use_context
between islands by @gbj in #1747 - Fix Suspense issues on subsequent navigations by @gbj in #1758
- Support default values for annotated server_fn arguments by @g2p in #1762
- chore(leptos_router): improve docs by @fundon in #1769
- Better document the interaction of SsrModes with blocking resources by @g2p in #1765
- Reimplement
Oco
cloning by @DanikVitek in #1749 - feat: Static Site Generation by @mrvillage in #1649
- chore(leptos_marco): enhancement of document generation by @fundon in #1768
- chore(leptos_hot_reload): apply lints suggestions by @fundon in #1735
- fix: broken benchmarks (closes #1736) by @gbj in #1771
- Change leptos_axum generate_route_list function to not be async by @nicoburniske in #1485
- docs: error in
view!
macro if you usecx,
by @gbj in #1772
New Contributors
- @nicoburniske made their first contribution in #1485
Full Changelog: v0.5.0-rc2...v0.5.0-rc3
v0.5.0-rc2
What's Changed
- build(examples): make it easier to run examples by @agilarity in #1697
- fix: a few small fixes to rc1 by @gbj in #1704
- fix: impl
IntoView
forRc<dyn Fn() -> impl IntoView>
by @Baptistemontan in #1698 - feat: impl
From<HtmlElement<El>> for HtmlElement<AnyElement>
by @jquesada2016 in #1700 - doc(examples): reference run instructions by @agilarity in #1705
- feat: Callbacks: Manual Clone and Debug impl; Visibility fix by @lpotthast in #1703
- feat: impled LeptosRoutes for &mut ServiceConfig in integrations/actix by @cosmobrain0 in #1706
- docs: update possibly deprecated docs for
component
macro by @ChristopherPerry6060 in #1696 - fix: exclude markdown files from examples lists by @agilarity in #1716
- fix(examples/build): do not require stop to end trunk by @agilarity in #1713
- docs: fix a typo that prevented the latest appendix from appearing in the book by @g2p in #1719
- feat: support
move
onwith!
macros by @blorbb in #1717 - feat: implement
Serialize
andDeserialize
forOco<_>
by @gbj in #1720 - fix: document
#[prop(default = ...)]
as in Optional Props (closes #1710) by @gbj in #1721 - fix: correctly register
Resource::with()
(closes #1711) by @gbj in #1726 - fix: replace uses of
create_effect
internally withcreate_isomorphic_effect
(closes #1709) by @gbj in #1723 - fix: relax bounds on
LeptosRoutes
by @ChristopherPerry6060 in #1729 - feat: Allow component names to be paths by @mrvillage in #1725
- feat: use
attr:
syntax rather thanAdditionalAttributes
by @gbj in #1728
New Contributors
- @cosmobrain0 made their first contribution in #1706
- @g2p made their first contribution in #1719
Full Changelog: v0.5.0-rc1...v0.5.0-rc2
v0.5.0-rc1
I'm planning on releasing 0.5.0 proper toward the end of this week. However, we've continued having some really good new features and some changes, so I want to give it some additional time for testing rather than rushing and breaking things.
For overall 0.5.0 changes, see here.
New Features in this Release
attr:
on components, and spreading attributes
Makes it much easier to pass some set of attributes to be given to a component (with attr:
passed into a #[prop(attrs)]
prop), and then to spread them onto an element with {..attrs}
syntax.
#[component]
pub fn App() -> impl IntoView {
view! {
<Input attr:value="hello" attr:label="foo" />
<Input attr:type="number" attr:value="0" />
}
}
#[component]
pub fn Input(
#[prop(attrs)] attrs: Vec<(&'static str, Attribute)>,
) -> impl IntoView {
view! {
<input {..attrs} />
<pre>{format!("{attrs2:#?}")}</pre>
}
}
Generics on components in view
Newly added support for syntax that identifies a generic type for a component in the view
#[component]
pub fn GenericComponent<S>(#[prop(optional)] ty: PhantomData<S>) -> impl IntoView {
std::any::type_name::<S>()
}
#[component]
pub fn App() -> impl IntoView {
view! {
<GenericComponent<String>/>
<GenericComponent<usize>/>
<GenericComponent<i32>/>
}
}
Callback
types
These make it easier to add things like optional callback functions to components.
#[component]
pub fn App() -> impl IntoView {
view! {
<ShowOptFall when=|| { 5 < 3 } fallback=|_| view! { <p>"YES"</p> }>
<p>"NO"</p>
</ShowOptFall>
<ShowOptFall when=|| { 5 < 3 }>
<p>"NO"</p>
</ShowOptFall>
<ShowOptFall when=||{ 5 > 3 }>
<p>"YES"</p>
</ShowOptFall>
}
}
#[component]
pub fn ShowOptFall<W>(
/// The components Show wraps
children: Box<dyn Fn() -> Fragment>,
/// A closure that returns a bool that determines whether this thing runs
when: W,
/// A closure that returns what gets rendered if the when statement is false
#[prop(optional, into)]
fallback: Option<ViewCallback<()>>,
) -> impl IntoView
where
W: Fn() -> bool + 'static,
{
let memoized_when = create_memo(move |_| when());
move || match memoized_when.get() {
true => children().into_view(),
false => match fallback.as_ref() {
Some(fallback) => fallback.call(()).into_view(),
None => ().into_view(),
},
}
}
with!()
and update!()
macros
Nested .withI()
calls are a pain. Now you can do
let (first, _) = create_signal("Bob".to_string());
let (middle, _) = create_signal("J.".to_string());
let (last, _) = create_signal("Smith".to_string());
let name = move || with!(|first, middle, last| format!("{first} {middle} {last}"));
instead of
let name = move || {
first.with(|first| {
middle.with(|middle| last.with(|last| format!("{first} {middle} {last}")))
})
};
Rustier interfaces for signal types
This framework's origins as a Rust port of SolidJS mean we've inherited some functional-JS-isms. Combined with the need to pass cx
everywhere prior to 0.5 this has tended to mean we've gone with create_
and so on rather than Rusty ::new()
. This simply adds a few Rustier constructors like
let count = RwSignal::new(0);
let double_count = Memo::new(move |_| count() * 2);
Breaking Changes
- Renaming
.derived_signal()
and.mapped_signal_setter()
to the more idiomatic.into_signal()
and.into_signal_setter()
- Memoizing whether
Suspense
is ready yet or not in order to avoid over-re-rendering. Shouldn't break your app, but if something weird happens let me know. - Changes timing of
create_effect
so that it runs a tick after it is created, which solves a number of timing issues with effects that had previously led tocreate_effect(move || request_animation_frame(move || /* */))
What's Changed
- doc(examples): add fantoccini to test-runner-report (#1615) by @agilarity in #1616
- docs: Derived signals - Clarified derived signals by @martinfrances107 in #1614
- doc(book,deployment): update reference to binary in dockerfile by @SadraMoh in #1617
- docs: fix typo by @dpytaylo in #1618
- docs: remove extra space by @Lawqup in #1622
- docs(book): fix wrong variable name by @Gaareth in #1623
- feat: Callback proposal by @rambip in #1596
- Configuration for Hot-Reloading Websocket Protocol and enable ENV PROD selection by @Indrazar in #1613
- feat: implement simple spread attributes by @mrvillage in #1619
- fix: memoize Suspense readiness to avoid rerendering children/fallback by @gbj in #1642
- feat: add component generics by @mrvillage in #1636
- hide
get_property
by @jquesada2016 in #1638 - Into thing boxed by @jquesada2016 in #1639
- docs: cleanup by @Banzobotic in #1626
- fix: versioned resources never decrement Suspense (closes #1640) by @gbj in #1641
- Rename into signal traits by @jquesada2016 in #1637
- feat: start adding some Rustier interfaces for reactive types by @gbj in #1579
- test(error_boundary): add e2e testing by @agilarity in #1651
- fix: custom events on components by @liquidnya in #1648
- fix: compare path components to detect active link in router by @flo-at in #1656
- Tailwind example update by @SleeplessOne1917 in #1625
- refactor(examples): extract client process tasks (#1665) by @agilarity in #1666
- change: move logging macros into a
logging
module to avoid name conflicts withlog
andtracing
by @gbj in #1658 - Router version bump by @martinfrances107 in #1673
- Chore: Bump to actions/checkout@v4 by @martinfrances107 in #1672
Rc
backedChildrenFn
by @Baptistemontan in #1669- Remove (most) syn 1 dependencies by @blorbb in #1670
- chore: Removed resolver link warning. by @martinfrances107 in #1677
- examples: add note about potential for memory leaks with nested signals by @gbj in #1675
- feat: islands by @gbj in #1660
- Docs: a bunch of small improvements by @gbj in #1681
- Chore: Remove ambiguity surrounding version numbers. by @martinfrances107 in #1685
- fix: restore deleted
extract_with_state
function by @gbj in #1683 - fix: broken
mount_to_body
in CSR mode by @gbj in #1688 - Chore: cleared "cargo doc" issue. by @martinfrances107 in #1687
- Update interlude_projecting_children.md by @mjarvis9541 in #1690
- feat: Add dynamically resolved attributes by @mrvillage in #1628
- docs: add docs for
#[island]
macro by @gbj in #1691 - change: run effects after a tick by @gbj in #1680
- feat: with! macros by @blorbb in #1693
New Contributors
- @mrnossiom made their first contribution in #1532
- @lker-dev made their first contribution in #1557
- @Senzaki made their first contribution in #1564
- @flisky made their first contribution in #1571
- @rkuklik made their first contribution in #1444
- @rabidpug made their first contribution in #1548
- @Maneren made their first contribution in #1612
- @drdo made their first contribution in #1597
- @JonRCahill made their first contribution in #1604
- @realeinherjar made their first contribution in #1610
- @SadraMoh made their first contribution in #1617
- @dpytaylo made their first contribution in #1618
- @Lawqup made their first contribution in #1622
- @Gaareth made their first contribution in #1623
- @rambip made their first contribution in #1596
- @mrvillage made their first contribution in #1619
- @Banzobotic m...
v0.5.0-beta2
Just another beta release. I'm expecting to release 0.5.0 itself in the next couple weeks, there have just been a couple other small but breaking changes proposed that are working their way through, and I'd rather delay a bit than rush it and be stuck.
0.5.0-beta2
reflects the current state of the main
branch. The v0.5.0
in General section is copied and pasted from previous releases. New this Release reflects changes since 0.5.0-beta
(I think?).
New this Release
- Make all arguments to
#[server]
optional: change default prefix to/api
and default to generating aPascalCase
type name from the function name
// before
#[server(MyName, "/api")]
pub async fn my_name() /* ... */
// after
#[server]
pub async fn my_name /* ... */
create_effect
now returns anEffect
struct. This exists mostly so you can.dispose()
it early if you need. (This may require adding some missing semicolons, ascreate_effect
no longer returns()
.)- Support passing signals directly as attributes, classes, styles, and props on stable
- Signal traits now take an associated
Value
type rather than a generic (see #1578) - Many APIs that previously took
impl Into<Cow<'static, str>>
now takeimpl Into<Oco<'static, str>>
.Oco
(Owned Clones Once) is a new type designed to minimized the cost of cloning immutable string types, like the ones used in theView
. Essentially this makes it cheaper to clone text nodes and attribute nodes within the renderer, without imposing an additional cost when you don't need to. This shouldn't require changes to your application in most cases of normal usage. (See #1480 for additional discussion.)
v0.5.0
in General
Reactive System Changes
This long-awaited release significantly changes how the reactive system works. This should solve several correctness issues/rough edges that related to the manual use of cx
/Scope
and could create memory leaks. (See #918 for details)
It also has the fairly large DX change (improvement?) of removing the need to pass cx
or Scope
variables around at all.
Migration is fairly easy. 95% of apps will migrate completely by making the following string replacements:
cx: Scope,
=> (empty string)cx: Scope
=> (empty string)cx,
=> (empty string)(cx)
=>()
|cx|
=>||
Scope,
=> (empty string)Scope
=> (empty string) as needed- You may have some
|_, _|
that become|_|
or|_|
that become||
, particularly for thefallback
props on<Show/>
and<ErrorBoundary/>
Basically, there is no longer a Scope
type, and anything that used to take it can simply be deleted.
For the 5%: if you were doing tricky things like storing a Scope
somewhere in a struct or variable and then reusing it, you should be able to achieve the same result by storing Owner::current()
somewhere and then later using it in with_owner(owner, move || { /* ... */ })
.
There are no other big conceptual or API changes in this update: essentially all the same reactive, templating, and component concepts should still apply, just without cx
.
What's Changed
- change: shift from
Scope
-based ownership to reactive ownership by @gbj in #918 - refactor(workflows): extract calls by @agilarity in #1566
- refactor(verify-changed-examples): improve readability and runtime by @agilarity in #1556
- Remove Clone requirement for slots in Vec by @Senzaki in #1564
- fix: INFO is too high a level for this prop tracing by @gbj in #1570
- fix: suppress warning about non-reactivity when calling
.refetch()
(occurs in e.g., async blocks in actions) by @gbj in #1576 - fix: nightly warning in server macro for lifetime by @markcatley in #1580
- fix: runtime disposal time in
render_to_string_async
by @gbj in #1574 - feat: support passing signals directly as attributes, classes, styles, and props on stable by @gbj in #1577
- feat: make struct name and path optional for server functions by @gbj in #1573
- support effect dispose by @flisky in #1571
- fix(counters_stable): restore wasm tests (#1581) by @agilarity in #1582
- fix: fourth argument to server functions by @gbj in #1585
- feat: signal traits should take associated types instead of generics by @gbj in #1578
- refactor(check-stable): use matrix (#1543) by @agilarity in #1583
- feat: add
Fn
traits for resources on nightly by @gbj in #1587 - Convenient event handling with slots by @rkuklik in #1444
- fix: correct logic for resource loading signal when read outside suspense (closes #1457) by @gbj in #1586
- Update autoreload websocket connection to work outside of localhost by @rabidpug in #1548
- Some resource and transition fixes by @gbj in #1588
- fix: broken test with untrack in tracing props by @gbj in #1593
- feat: update to
typed-builder
0.16 (closes #1455) by @gbj in #1590 Oco
(Owned Clones Once) smart pointer by @DanikVitek in #1480- docs: add docs for builder syntax by @gbj in #1603
- chore(examples): improve cucumber support #1598 by @agilarity in #1599
- fix(ci): add new webkit dependency (#1607) by @agilarity in #1608
- fix(macro/params): clippy warning by @Maneren in #1612
- Improve server function client side error handling by @drdo in #1597
- Don't try to parse as JSON the result from a server function redirect by @JonRCahill in #1604
- fix: add docs on #[server] functions by @realeinherjar in #1610
New Contributors
- @Senzaki made their first contribution in #1564
- @flisky made their first contribution in #1571
- @rkuklik made their first contribution in #1444
- @rabidpug made their first contribution in #1548
- @Maneren made their first contribution in #1612
- @drdo made their first contribution in #1597
- @JonRCahill made their first contribution in #1604
- @realeinherjar made their first contribution in #1610
Full Changelog: v0.4.9...0.5.0-beta2
v0.4.9
I'm getting ready to merge the effect-cleanups
branch into main, as well as merging #1480 and #1485 in preparation for the release of 0.5.0, so this release is just a "final state of 0.4.x" release before the main branch switches over from being 0.4 to 0.5. It does include some notable work, though:
- refactored
view
macro with snapshot testing - improved hydration performance, avoiding browser work by reusing existing text nodes in certain cases
- including component props in
tracing
support - many small bugfixes and improvements to docs
What's Changed
- fix: js scoping by @mateusvmv in #1489
- refactor: refactor + snapshot tests by @vldm and @gbj in #1435
- fix: github links by @markcatley in #1493
- docs: typo: nightly is with a t by @stappersg in #1497
- perf: in hydration, reuse existing text node by @gbj in #1506
- fix: rkyv
copy
feature is now only enabled if nightly feature is enabled by @thestarmaker in #1503 - test(todo_app_sqlite): add e2e tests (#1448) by @agilarity in #1467
- fix: render empty dynamic text node in HTML as
- fix behavior of
create_query_signal
by @DanikVitek in #1508 - fix(suspense-tests): build errors (#1517) by @agilarity in #1518
- test(todo_app_sqlite_axum): add e2e tests (#1514) by @agilarity in #1515
- docs: additional random docs by @gbj in #1523
- docs: add
use_navigate
to router docs in guide by @gbj in #1524 - docs: typos in
NavigateOptions
docs by @gbj in #1525 - docs: expand on the need for
prop:value
by @gbj in #1526 - docs: advanced docs on reactive graph, and update testing docs by @gbj in #1529
- docs: give a compile error when trying to put a child inside a self-closing HTML tag (closes #1535) by @gbj in #1537
- chore: fixed lint warning seen while running
cargo doc
by @martinfrances107 in #1539 - examples: on_cleanup misorder? in fetch examples by @mrnossiom in #1532
- test(suspense-tests): add e2e tests (Closes #1519) by @agilarity in #1533
- chore(test_examples): remove obsolete directory by @agilarity in #1540
- perf(check-stable): only run workflow on leptos source change (#1541) by @agilarity in #1542
- docs: documentation update for by @lker-dev in #1557
- docs: tell where the source is by @stappersg in #1498
- feat: tracing component property by @luoxiaozero in #1531
- build(docs): only publish on new version tags by @gbj in #1562
New Contributors
- @mateusvmv made their first contribution in #1489
- @stappersg made their first contribution in #1497
- @mrnossiom made their first contribution in #1532
- @lker-dev made their first contribution in #1557
Full Changelog: v0.4.8...v0.4.9