redirects, middleware, Transport, set/capture error status (#4751)

* wip: redirect

* redirect example

* fix file upload not in a form

* wip

* deny missing cfgs

* wip: add router fallback but it's not working

* fix suspense bug after rebuilds that queued work

* more cleanup

* add test for error codes

* add helpful comment

* bring back middleware annotation

* fix cfg

* add server feature

* fix doctest

* just disable liveview test for now

* fix liveview

* dont send init

* cache more playwright!

* add more pkgs to cache
This commit is contained in:
Jonathan Kelley authored and GitHub committed 2025-10-10 21:43:57 -07:00
1 parent 8a81475ba8
commit 9243ef4128
35 files changed
+935 -800

No files matched your search

+66 -19
View File
@@ -88,9 +88,9 @@ use syn::{
/// }
/// ```
#[proc_macro_attribute]
pub fn server(_attr: proc_macro::TokenStream, mut item: TokenStream) -> TokenStream {
pub fn server(attr: proc_macro::TokenStream, mut item: TokenStream) -> TokenStream {
// Parse the attribute list using the old server_fn arg parser.
let args = match syn::parse::<ServerFnArgs>(_attr) {
let args = match syn::parse::<ServerFnArgs>(attr) {
Ok(args) => args,
Err(err) => {
let err: TokenStream = err.to_compile_error().into();
@@ -202,7 +202,30 @@ fn route_impl_with_route(
method_from_macro: Option<Method>,
) -> syn::Result<TokenStream2> {
// Parse the route and function
let function = syn::parse::<ItemFn>(item)?;
let mut function = syn::parse::<ItemFn>(item)?;
let middleware_attrs = function
.attrs
.iter()
.filter(|attr| attr.path().is_ident("middleware"))
.cloned()
.collect::<Vec<_>>();
let middleware_inits = middleware_attrs
.into_iter()
.map(|f| match f.meta {
Meta::List(meta_list) => Ok(meta_list.tokens),
_ => Err(Error::new(
f.span(),
"Expected middleware attribute to be a list, e.g. #[middleware(MyLayer::new())]",
)),
})
.collect::<Result<Vec<_>>>()?;
// don't re-emit the middleware attribute on the inner
function
.attrs
.retain(|attr| !attr.path().is_ident("middleware"));
let server_args = route.server_args.clone();
let mut function_on_server = function.clone();
@@ -259,15 +282,7 @@ fn route_impl_with_route(
.iter()
.filter(|attr| attr.path().is_ident("doc"));
let __axum = quote! { dioxus_fullstack::axum };
let (aide_ident_docs, _inner_fn_call, _method_router_ty) = {
(
quote!(),
quote! { #__axum::routing::#http_method(__inner__function__ #ty_generics) },
quote! { #__axum::routing::MethodRouter },
)
};
let __axum = quote! { dioxus_server::axum };
let output_type = match &function.sig.output {
syn::ReturnType::Default => parse_quote! { () },
@@ -346,7 +361,7 @@ fn route_impl_with_route(
quote! {}
} else {
quote! {
let (#(#server_names,)*) = dioxus_fullstack::StreamingContext::extract::<(#(#server_types,)*), _>().await?;
let (#(#server_names,)*) = dioxus_fullstack::FullstackContext::extract::<(#(#server_types,)*), _>().await?;
}
};
@@ -418,9 +433,40 @@ fn route_impl_with_route(
}
};
let middleware_extra = middleware_inits
.iter()
.map(|init| {
quote! {
.layer(#init)
}
})
.collect::<Vec<_>>();
Ok(quote! {
#(#fn_docs)*
#route_docs
#[deny(
unexpected_cfgs,
reason = "
==========================================================================================
Using Dioxus Server Functions requires a `server` feature flag in your `Cargo.toml`.
Please add the following to your `Cargo.toml`:
```toml
[features]
server = [\"dioxus/server\"]
```
To enable better Rust-Analyzer support, you can make `server` a default feature:
```toml
[features]
default = [\"web\", \"server\"]
web = [\"dioxus/web\"]
server = [\"dioxus/server\"]
```
==========================================================================================
"
)]
#vis async fn #fn_name #impl_generics(
#original_inputs
) -> #out_ty #where_clause {
@@ -483,7 +529,6 @@ fn route_impl_with_route(
#function_on_server
#[allow(clippy::unused_unit)]
#aide_ident_docs
#asyncness fn __inner__function__ #impl_generics(
___state: #__axum::extract::State<DioxusServerState>,
#path_extractor
@@ -504,11 +549,13 @@ fn route_impl_with_route(
return response;
}
dioxus_fullstack::inventory::submit! {
dioxus_server::inventory::submit! {
ServerFunction::new(
dioxus_fullstack::http::Method::#method_ident,
dioxus_server::http::Method::#method_ident,
__ENDPOINT_PATH,
|| #__axum::routing::#http_method(__inner__function__ #ty_generics)
|| {
#__axum::routing::#http_method(__inner__function__ #ty_generics) #(#middleware_extra)*
}
)
}
@@ -688,14 +735,14 @@ impl CompiledRoute {
let idents = path_iter.clone().map(|item| item.0);
let types = path_iter.clone().map(|item| item.1);
quote! {
dioxus_fullstack::axum::extract::Path((#(#idents,)*)): dioxus_fullstack::axum::extract::Path<(#(#types,)*)>,
dioxus_server::axum::extract::Path((#(#idents,)*)): dioxus_server::axum::extract::Path<(#(#types,)*)>,
}
}
pub fn query_extractor(&self) -> TokenStream2 {
let idents = self.query_params.iter().map(|item| &item.0);
quote! {
dioxus_fullstack::axum::extract::Query(__QueryParams__ { #(#idents,)* }): dioxus_fullstack::axum::extract::Query<__QueryParams__>,
dioxus_server::axum::extract::Query(__QueryParams__ { #(#idents,)* }): dioxus_server::axum::extract::Query<__QueryParams__>,
}
}