mirror of
https://github.com/leptos-rs/leptos
synced 2024-11-10 06:44:17 +00:00
change: migrate Axum integration to use with_state
over layer(Extension)
(#1032)
This commit is contained in:
parent
904c2e8a67
commit
add13fd6a4
12 changed files with 76 additions and 45 deletions
|
@ -10,12 +10,12 @@ crate-type = ["cdylib", "rlib"]
|
|||
console_log = "1.0.0"
|
||||
console_error_panic_hook = "0.1.7"
|
||||
cfg-if = "1.0.0"
|
||||
leptos = { path = "../../../leptos/leptos", default-features = false, features = [
|
||||
leptos = { path = "../../leptos", default-features = false, features = [
|
||||
"serde",
|
||||
] }
|
||||
leptos_axum = { path = "../../../leptos/integrations/axum", default-features = false, optional = true }
|
||||
leptos_meta = { path = "../../../leptos/meta", default-features = false }
|
||||
leptos_router = { path = "../../../leptos/router", default-features = false }
|
||||
leptos_axum = { path = "../../integrations/axum", default-features = false, optional = true }
|
||||
leptos_meta = { path = "../../meta", default-features = false }
|
||||
leptos_router = { path = "../../router", default-features = false }
|
||||
log = "0.4.17"
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
simple_logger = "4.0.0"
|
||||
|
|
|
@ -3,7 +3,7 @@ use cfg_if::cfg_if;
|
|||
cfg_if! { if #[cfg(feature = "ssr")] {
|
||||
use axum::{
|
||||
body::{boxed, Body, BoxBody},
|
||||
extract::Extension,
|
||||
extract::State,
|
||||
response::IntoResponse,
|
||||
http::{Request, Response, StatusCode, Uri},
|
||||
};
|
||||
|
@ -14,7 +14,7 @@ cfg_if! { if #[cfg(feature = "ssr")] {
|
|||
use leptos::{LeptosOptions, view};
|
||||
use crate::landing::App;
|
||||
|
||||
pub async fn file_and_error_handler(uri: Uri, Extension(options): Extension<Arc<LeptosOptions>>, req: Request<Body>) -> AxumResponse {
|
||||
pub async fn file_and_error_handler(uri: Uri, State(options): State<Arc<LeptosOptions>>, req: Request<Body>) -> AxumResponse {
|
||||
let options = &*options;
|
||||
let root = options.site_root.clone();
|
||||
let res = get_static_file(uri.clone(), &root).await.unwrap();
|
||||
|
|
|
@ -5,7 +5,7 @@ cfg_if! { if #[cfg(feature = "ssr")] {
|
|||
use crate::landing::*;
|
||||
use axum::body::Body as AxumBody;
|
||||
use axum::{
|
||||
extract::{Extension, Path},
|
||||
extract::{State, Path},
|
||||
http::Request,
|
||||
response::{IntoResponse, Response},
|
||||
routing::{get, post},
|
||||
|
@ -21,7 +21,7 @@ cfg_if! { if #[cfg(feature = "ssr")] {
|
|||
#[cfg(feature = "ssr")]
|
||||
async fn custom_handler(
|
||||
Path(id): Path<String>,
|
||||
Extension(options): Extension<Arc<LeptosOptions>>,
|
||||
State(options): State<Arc<LeptosOptions>>,
|
||||
req: Request<AxumBody>,
|
||||
) -> Response {
|
||||
let handler = leptos_axum::render_app_to_stream_with_context(
|
||||
|
@ -44,7 +44,7 @@ async fn main() {
|
|||
|
||||
// Setting this to None means we'll be using cargo-leptos and its env vars
|
||||
let conf = get_configuration(None).await.unwrap();
|
||||
let leptos_options = conf.leptos_options;
|
||||
let leptos_options = Arc::new(conf.leptos_options);
|
||||
let addr = leptos_options.site_addr;
|
||||
let routes = generate_route_list(|cx| view! { cx, <App/> }).await;
|
||||
|
||||
|
@ -58,7 +58,7 @@ async fn main() {
|
|||
|cx| view! { cx, <App/> },
|
||||
)
|
||||
.fallback(file_and_error_handler)
|
||||
.layer(Extension(Arc::new(leptos_options)));
|
||||
.with_state(leptos_options);
|
||||
|
||||
// run our app with hyper
|
||||
// `axum::Server` is a re-export of `hyper::Server`
|
||||
|
|
|
@ -4,7 +4,7 @@ cfg_if! {
|
|||
if #[cfg(feature = "ssr")] {
|
||||
use axum::{
|
||||
body::{boxed, Body, BoxBody},
|
||||
extract::Extension,
|
||||
extract::State,
|
||||
response::IntoResponse,
|
||||
http::{Request, Response, StatusCode, Uri},
|
||||
};
|
||||
|
@ -15,7 +15,7 @@ if #[cfg(feature = "ssr")] {
|
|||
use leptos::{LeptosOptions};
|
||||
use crate::error_template::error_template;
|
||||
|
||||
pub async fn file_and_error_handler(uri: Uri, Extension(options): Extension<Arc<LeptosOptions>>, req: Request<Body>) -> AxumResponse {
|
||||
pub async fn file_and_error_handler(uri: Uri, State(options): State<Arc<LeptosOptions>>, req: Request<Body>) -> AxumResponse {
|
||||
let options = &*options;
|
||||
let root = options.site_root.clone();
|
||||
let res = get_static_file(uri.clone(), &root).await.unwrap();
|
||||
|
|
|
@ -7,7 +7,6 @@ if #[cfg(feature = "ssr")] {
|
|||
use axum::{
|
||||
Router,
|
||||
routing::get,
|
||||
extract::Extension,
|
||||
};
|
||||
use leptos_axum::{generate_route_list, LeptosRoutes};
|
||||
use std::sync::Arc;
|
||||
|
@ -18,7 +17,7 @@ if #[cfg(feature = "ssr")] {
|
|||
use hackernews_axum::*;
|
||||
|
||||
let conf = get_configuration(Some("Cargo.toml")).await.unwrap();
|
||||
let leptos_options = conf.leptos_options;
|
||||
let leptos_options = Arc::new(conf.leptos_options);
|
||||
let addr = leptos_options.site_addr;
|
||||
let routes = generate_route_list(|cx| view! { cx, <App/> }).await;
|
||||
|
||||
|
@ -29,7 +28,7 @@ if #[cfg(feature = "ssr")] {
|
|||
.route("/favicon.ico", get(file_and_error_handler))
|
||||
.leptos_routes(leptos_options.clone(), routes, |cx| view! { cx, <App/> } )
|
||||
.fallback(file_and_error_handler)
|
||||
.layer(Extension(Arc::new(leptos_options)));
|
||||
.with_state(leptos_options);
|
||||
|
||||
// run our app with hyper
|
||||
// `axum::Server` is a re-export of `hyper::Server`
|
||||
|
|
|
@ -4,7 +4,7 @@ cfg_if! {
|
|||
if #[cfg(feature = "ssr")] {
|
||||
use axum::{
|
||||
body::{boxed, Body, BoxBody},
|
||||
extract::Extension,
|
||||
extract::State,
|
||||
response::IntoResponse,
|
||||
http::{Request, Response, StatusCode, Uri},
|
||||
};
|
||||
|
@ -16,7 +16,7 @@ if #[cfg(feature = "ssr")] {
|
|||
use crate::error_template::ErrorTemplate;
|
||||
use crate::errors::TodoAppError;
|
||||
|
||||
pub async fn file_and_error_handler(uri: Uri, Extension(options): Extension<Arc<LeptosOptions>>, req: Request<Body>) -> AxumResponse {
|
||||
pub async fn file_and_error_handler(uri: Uri, State(options): State<Arc<LeptosOptions>>, req: Request<Body>) -> AxumResponse {
|
||||
let options = &*options;
|
||||
let root = options.site_root.clone();
|
||||
let res = get_static_file(uri.clone(), &root).await.unwrap();
|
||||
|
|
|
@ -6,7 +6,7 @@ if #[cfg(feature = "ssr")] {
|
|||
use axum::{
|
||||
response::{Response, IntoResponse},
|
||||
routing::get,
|
||||
extract::{Path, Extension, RawQuery},
|
||||
extract::{Path, State, Extension, RawQuery},
|
||||
http::{Request, header::HeaderMap},
|
||||
body::Body as AxumBody,
|
||||
Router,
|
||||
|
@ -33,7 +33,7 @@ if #[cfg(feature = "ssr")] {
|
|||
}, request).await
|
||||
}
|
||||
|
||||
async fn leptos_routes_handler(Extension(pool): Extension<SqlitePool>, auth_session: AuthSession, Extension(options): Extension<Arc<LeptosOptions>>, req: Request<AxumBody>) -> Response{
|
||||
async fn leptos_routes_handler(Extension(pool): Extension<SqlitePool>, auth_session: AuthSession, State(options): State<Arc<LeptosOptions>>, req: Request<AxumBody>) -> Response{
|
||||
let handler = leptos_axum::render_app_to_stream_with_context((*options).clone(),
|
||||
move |cx| {
|
||||
provide_context(cx, auth_session.clone());
|
||||
|
@ -68,7 +68,7 @@ if #[cfg(feature = "ssr")] {
|
|||
|
||||
// Setting this to None means we'll be using cargo-leptos and its env vars
|
||||
let conf = get_configuration(None).await.unwrap();
|
||||
let leptos_options = conf.leptos_options;
|
||||
let leptos_options = Arc::new(conf.leptos_options);
|
||||
let addr = leptos_options.site_addr;
|
||||
let routes = generate_route_list(|cx| view! { cx, <TodoApp/> }).await;
|
||||
|
||||
|
@ -80,8 +80,8 @@ if #[cfg(feature = "ssr")] {
|
|||
.layer(AuthSessionLayer::<User, i64, SessionSqlitePool, SqlitePool>::new(Some(pool.clone()))
|
||||
.with_config(auth_config))
|
||||
.layer(SessionLayer::new(session_store))
|
||||
.layer(Extension(Arc::new(leptos_options)))
|
||||
.layer(Extension(pool));
|
||||
.layer(Extension(pool))
|
||||
.with_state(leptos_options);
|
||||
|
||||
// run our app with hyper
|
||||
// `axum::Server` is a re-export of `hyper::Server`
|
||||
|
|
|
@ -3,7 +3,7 @@ use cfg_if::cfg_if;
|
|||
cfg_if! { if #[cfg(feature = "ssr")] {
|
||||
use axum::{
|
||||
body::{boxed, Body, BoxBody},
|
||||
extract::Extension,
|
||||
extract::State,
|
||||
response::IntoResponse,
|
||||
http::{Request, Response, StatusCode, Uri},
|
||||
};
|
||||
|
@ -14,7 +14,7 @@ cfg_if! { if #[cfg(feature = "ssr")] {
|
|||
use leptos::{LeptosOptions, view};
|
||||
use crate::app::App;
|
||||
|
||||
pub async fn file_and_error_handler(uri: Uri, Extension(options): Extension<Arc<LeptosOptions>>, req: Request<Body>) -> AxumResponse {
|
||||
pub async fn file_and_error_handler(uri: Uri, State(options): State<Arc<LeptosOptions>>, req: Request<Body>) -> AxumResponse {
|
||||
let options = &*options;
|
||||
let root = options.site_root.clone();
|
||||
let res = get_static_file(uri.clone(), &root).await.unwrap();
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#[cfg(feature = "ssr")]
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
use axum::{extract::Extension, routing::post, Router};
|
||||
use axum::{routing::post, Router};
|
||||
use leptos::*;
|
||||
use leptos_axum::{generate_route_list, LeptosRoutes};
|
||||
use ssr_modes_axum::{app::*, fallback::file_and_error_handler};
|
||||
|
@ -9,7 +9,7 @@ async fn main() {
|
|||
|
||||
let conf = get_configuration(None).await.unwrap();
|
||||
let addr = conf.leptos_options.site_addr;
|
||||
let leptos_options = conf.leptos_options;
|
||||
let leptos_options = Arc::new(conf.leptos_options);
|
||||
// Generate the list of routes in your Leptos App
|
||||
let routes = generate_route_list(|cx| view! { cx, <App/> }).await;
|
||||
|
||||
|
@ -24,7 +24,7 @@ async fn main() {
|
|||
|cx| view! { cx, <App/> },
|
||||
)
|
||||
.fallback(file_and_error_handler)
|
||||
.layer(Extension(Arc::new(leptos_options)));
|
||||
.with_state(leptos_options);
|
||||
|
||||
// run our app with hyper
|
||||
// `axum::Server` is a re-export of `hyper::Server`
|
||||
|
|
|
@ -4,7 +4,7 @@ cfg_if! {
|
|||
if #[cfg(feature = "ssr")] {
|
||||
use axum::{
|
||||
body::{boxed, Body, BoxBody},
|
||||
extract::Extension,
|
||||
extract::State,
|
||||
response::IntoResponse,
|
||||
http::{Request, Response, StatusCode, Uri},
|
||||
};
|
||||
|
@ -16,7 +16,7 @@ if #[cfg(feature = "ssr")] {
|
|||
use crate::error_template::ErrorTemplate;
|
||||
use crate::errors::TodoAppError;
|
||||
|
||||
pub async fn file_and_error_handler(uri: Uri, Extension(options): Extension<Arc<LeptosOptions>>, req: Request<Body>) -> AxumResponse {
|
||||
pub async fn file_and_error_handler(uri: Uri, State(options): State<Arc<LeptosOptions>>, req: Request<Body>) -> AxumResponse {
|
||||
let options = &*options;
|
||||
let root = options.site_root.clone();
|
||||
let res = get_static_file(uri.clone(), &root).await.unwrap();
|
||||
|
|
|
@ -5,7 +5,7 @@ cfg_if! {
|
|||
use leptos::*;
|
||||
use axum::{
|
||||
routing::{post, get},
|
||||
extract::{Extension, Path},
|
||||
extract::{State, Path},
|
||||
http::Request,
|
||||
response::{IntoResponse, Response},
|
||||
Router,
|
||||
|
@ -18,7 +18,7 @@ cfg_if! {
|
|||
use std::sync::Arc;
|
||||
|
||||
//Define a handler to test extractor with state
|
||||
async fn custom_handler(Path(id): Path<String>, Extension(options): Extension<Arc<LeptosOptions>>, req: Request<AxumBody>) -> Response{
|
||||
async fn custom_handler(Path(id): Path<String>, State(options): State<Arc<LeptosOptions>>, req: Request<AxumBody>) -> Response{
|
||||
let handler = leptos_axum::render_app_to_stream_with_context((*options).clone(),
|
||||
move |cx| {
|
||||
provide_context(cx, id.clone());
|
||||
|
@ -42,7 +42,7 @@ cfg_if! {
|
|||
|
||||
// Setting this to None means we'll be using cargo-leptos and its env vars
|
||||
let conf = get_configuration(None).await.unwrap();
|
||||
let leptos_options = conf.leptos_options;
|
||||
let leptos_options = Arc::new(conf.leptos_options);
|
||||
let addr = leptos_options.site_addr;
|
||||
let routes = generate_route_list(|cx| view! { cx, <TodoApp/> }).await;
|
||||
|
||||
|
@ -52,7 +52,7 @@ cfg_if! {
|
|||
.route("/special/:id", get(custom_handler))
|
||||
.leptos_routes(leptos_options.clone(), routes, |cx| view! { cx, <TodoApp/> } )
|
||||
.fallback(file_and_error_handler)
|
||||
.layer(Extension(Arc::new(leptos_options)));
|
||||
.with_state(leptos_options);
|
||||
|
||||
// run our app with hyper
|
||||
// `axum::Server` is a re-export of `hyper::Server`
|
||||
|
|
|
@ -1126,12 +1126,39 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
/// This trait allows one to use your custom struct in Axum's router, provided it can provide the
|
||||
/// `LeptosOptions` to use for the `LeptosRoutes` trait functions.
|
||||
pub trait LeptosOptionProvider {
|
||||
fn options(&self) -> LeptosOptions;
|
||||
}
|
||||
|
||||
/// Implement `LeptosOptionProvider` trait for `LeptosOptions` itself.
|
||||
impl LeptosOptionProvider for LeptosOptions {
|
||||
fn options(&self) -> LeptosOptions {
|
||||
self.clone()
|
||||
}
|
||||
}
|
||||
|
||||
/// Implement `LeptosOptionProvider` trait for any type wrapped in an Arc, if that type implements
|
||||
/// `LeptosOptionProvider` as states in axum are often provided wrapped in an Arc.
|
||||
impl<T> LeptosOptionProvider for Arc<T>
|
||||
where
|
||||
T: LeptosOptionProvider,
|
||||
{
|
||||
fn options(&self) -> LeptosOptions {
|
||||
(**self).options()
|
||||
}
|
||||
}
|
||||
|
||||
/// This trait allows one to pass a list of routes and a render function to Axum's router, letting us avoid
|
||||
/// having to use wildcards or manually define all routes in multiple places.
|
||||
pub trait LeptosRoutes {
|
||||
pub trait LeptosRoutes<OP>
|
||||
where
|
||||
OP: LeptosOptionProvider,
|
||||
{
|
||||
fn leptos_routes<IV>(
|
||||
self,
|
||||
options: LeptosOptions,
|
||||
options: OP,
|
||||
paths: Vec<RouteListing>,
|
||||
app_fn: impl Fn(leptos::Scope) -> IV + Clone + Send + 'static,
|
||||
) -> Self
|
||||
|
@ -1140,7 +1167,7 @@ pub trait LeptosRoutes {
|
|||
|
||||
fn leptos_routes_with_context<IV>(
|
||||
self,
|
||||
options: LeptosOptions,
|
||||
options: OP,
|
||||
paths: Vec<RouteListing>,
|
||||
additional_context: impl Fn(leptos::Scope) + 'static + Clone + Send,
|
||||
app_fn: impl Fn(leptos::Scope) -> IV + Clone + Send + 'static,
|
||||
|
@ -1154,16 +1181,20 @@ pub trait LeptosRoutes {
|
|||
handler: H,
|
||||
) -> Self
|
||||
where
|
||||
H: axum::handler::Handler<T, (), axum::body::Body>,
|
||||
H: axum::handler::Handler<T, OP, axum::body::Body>,
|
||||
T: 'static;
|
||||
}
|
||||
|
||||
/// The default implementation of `LeptosRoutes` which takes in a list of paths, and dispatches GET requests
|
||||
/// to those paths to Leptos's renderer.
|
||||
impl LeptosRoutes for axum::Router {
|
||||
impl<OP> LeptosRoutes<OP> for axum::Router<OP>
|
||||
where
|
||||
OP: LeptosOptionProvider + Clone + Send + Sync + 'static,
|
||||
{
|
||||
#[tracing::instrument(level = "info", fields(error), skip_all)]
|
||||
fn leptos_routes<IV>(
|
||||
self,
|
||||
options: LeptosOptions,
|
||||
options: OP,
|
||||
paths: Vec<RouteListing>,
|
||||
app_fn: impl Fn(leptos::Scope) -> IV + Clone + Send + 'static,
|
||||
) -> Self
|
||||
|
@ -1176,7 +1207,7 @@ impl LeptosRoutes for axum::Router {
|
|||
#[tracing::instrument(level = "trace", fields(error), skip_all)]
|
||||
fn leptos_routes_with_context<IV>(
|
||||
self,
|
||||
options: LeptosOptions,
|
||||
options: OP,
|
||||
paths: Vec<RouteListing>,
|
||||
additional_context: impl Fn(leptos::Scope) + 'static + Clone + Send,
|
||||
app_fn: impl Fn(leptos::Scope) -> IV + Clone + Send + 'static,
|
||||
|
@ -1194,7 +1225,7 @@ impl LeptosRoutes for axum::Router {
|
|||
match listing.mode() {
|
||||
SsrMode::OutOfOrder => {
|
||||
let s = render_app_to_stream_with_context(
|
||||
options.clone(),
|
||||
options.options(),
|
||||
additional_context.clone(),
|
||||
app_fn.clone(),
|
||||
);
|
||||
|
@ -1208,7 +1239,7 @@ impl LeptosRoutes for axum::Router {
|
|||
}
|
||||
SsrMode::PartiallyBlocked => {
|
||||
let s = render_app_to_stream_with_context_and_replace_blocks(
|
||||
options.clone(),
|
||||
options.options(),
|
||||
additional_context.clone(),
|
||||
app_fn.clone(),
|
||||
true
|
||||
|
@ -1223,7 +1254,7 @@ impl LeptosRoutes for axum::Router {
|
|||
}
|
||||
SsrMode::InOrder => {
|
||||
let s = render_app_to_stream_in_order_with_context(
|
||||
options.clone(),
|
||||
options.options(),
|
||||
additional_context.clone(),
|
||||
app_fn.clone(),
|
||||
);
|
||||
|
@ -1237,7 +1268,7 @@ impl LeptosRoutes for axum::Router {
|
|||
}
|
||||
SsrMode::Async => {
|
||||
let s = render_app_async_with_context(
|
||||
options.clone(),
|
||||
options.options(),
|
||||
additional_context.clone(),
|
||||
app_fn.clone(),
|
||||
);
|
||||
|
@ -1263,7 +1294,7 @@ impl LeptosRoutes for axum::Router {
|
|||
handler: H,
|
||||
) -> Self
|
||||
where
|
||||
H: axum::handler::Handler<T, (), axum::body::Body>,
|
||||
H: axum::handler::Handler<T, OP, axum::body::Body>,
|
||||
T: 'static,
|
||||
{
|
||||
let mut router = self;
|
||||
|
@ -1286,6 +1317,7 @@ impl LeptosRoutes for axum::Router {
|
|||
router
|
||||
}
|
||||
}
|
||||
|
||||
#[tracing::instrument(level = "trace", fields(error), skip_all)]
|
||||
fn get_leptos_pool() -> LocalPoolHandle {
|
||||
static LOCAL_POOL: OnceCell<LocalPoolHandle> = OnceCell::new();
|
||||
|
|
Loading…
Reference in a new issue