mirror of
https://github.com/tuono-labs/tuono
synced 2026-07-29 13:52:46 -07:00
feat: enable dynamic routes on frontend
This commit is contained in:
@@ -20,10 +20,11 @@ pub const AXUM_ENTRY_POINT: &str = r##"
|
||||
// File automatically generated
|
||||
// Do not manually change it
|
||||
|
||||
use axum::extract::Request;
|
||||
use axum::extract::{Path, Request};
|
||||
use axum::response::Html;
|
||||
use axum::{routing::get, Router};
|
||||
use tower_http::services::ServeDir;
|
||||
use std::collections::HashMap;
|
||||
use tuono_lib::{ssr, Ssr};
|
||||
use reqwest::Client;
|
||||
|
||||
@@ -44,11 +45,11 @@ async fn main() {
|
||||
axum::serve(listener, app).await.unwrap();
|
||||
}
|
||||
|
||||
async fn catch_all(request: Request) -> Html<String> {
|
||||
async fn catch_all(Path(params): Path<HashMap<String, String>>, request: Request) -> Html<String> {
|
||||
let pathname = &request.uri();
|
||||
let headers = &request.headers();
|
||||
|
||||
let req = tuono_lib::Request::new(pathname, headers);
|
||||
let req = tuono_lib::Request::new(pathname, headers, params);
|
||||
|
||||
|
||||
// TODO: remove unwrap
|
||||
|
||||
@@ -3,10 +3,11 @@ use std::collections::HashMap;
|
||||
|
||||
use axum::http::{HeaderMap, Uri};
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Request<'a> {
|
||||
uri: &'a Uri,
|
||||
headers: &'a HeaderMap,
|
||||
pub params: HashMap<String, String>,
|
||||
}
|
||||
|
||||
/// Location must match client side interface
|
||||
@@ -21,8 +22,16 @@ pub struct Location<'a> {
|
||||
}
|
||||
|
||||
impl<'a> Request<'a> {
|
||||
pub fn new(uri: &'a Uri, headers: &'a HeaderMap) -> Request<'a> {
|
||||
Request { uri, headers }
|
||||
pub fn new(
|
||||
uri: &'a Uri,
|
||||
headers: &'a HeaderMap,
|
||||
params: HashMap<String, String>,
|
||||
) -> Request<'a> {
|
||||
Request {
|
||||
uri,
|
||||
headers,
|
||||
params,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn location(&self) -> Location<'a> {
|
||||
|
||||
@@ -9,16 +9,21 @@ pub fn handler_core(_args: TokenStream, item: TokenStream) -> TokenStream {
|
||||
|
||||
quote! {
|
||||
use axum::response::{Html, IntoResponse};
|
||||
use axum::extract::State;
|
||||
use std::collections::HashMap;
|
||||
use axum::extract::{State, Path};
|
||||
use reqwest::Client;
|
||||
|
||||
#item
|
||||
|
||||
pub async fn route(State(client): State<Client>, request: axum::extract::Request) -> Html<String> {
|
||||
pub async fn route(
|
||||
Path(params): Path<HashMap<String, String>>,
|
||||
State(client): State<Client>,
|
||||
request: axum::extract::Request
|
||||
) -> Html<String> {
|
||||
let pathname = &request.uri();
|
||||
let headers = &request.headers();
|
||||
|
||||
let req = tuono_lib::Request::new(pathname, headers);
|
||||
let req = tuono_lib::Request::new(pathname, headers, params);
|
||||
|
||||
let local_response = #fn_name(req.clone(), client).await;
|
||||
|
||||
@@ -40,11 +45,15 @@ pub fn handler_core(_args: TokenStream, item: TokenStream) -> TokenStream {
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn api(State(client): State<Client>, request: axum::extract::Request) -> axum::response::Response {
|
||||
pub async fn api(
|
||||
Path(params): Path<HashMap<String, String>>,
|
||||
State(client): State<Client>,
|
||||
request: axum::extract::Request
|
||||
) -> axum::response::Response {
|
||||
let pathname = &request.uri();
|
||||
let headers = &request.headers();
|
||||
|
||||
let req = tuono_lib::Request::new(pathname, headers);
|
||||
let req = tuono_lib::Request::new(pathname, headers, params);
|
||||
|
||||
let local_response = #fn_name(req.clone(), client).await;
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { useState, useEffect, useRef } from 'react'
|
||||
import type { Route } from '../route'
|
||||
import { useRouterStore } from './useRouterStore'
|
||||
|
||||
const isServer = typeof document === 'undefined'
|
||||
|
||||
@@ -20,6 +21,7 @@ export function useServerSideProps(
|
||||
serverSideProps: any,
|
||||
): UseServerSidePropsReturn {
|
||||
const isFirstRendering = useRef<boolean>(true)
|
||||
const location = useRouterStore((st) => st.location)
|
||||
const [isLoading, setIsLoading] = useState<boolean>(
|
||||
// Force loading if has handler
|
||||
route.options.hasHandler &&
|
||||
@@ -41,15 +43,14 @@ export function useServerSideProps(
|
||||
return
|
||||
}
|
||||
// After client side routing load again the remote data
|
||||
if (route.options.hasHandler && !data) {
|
||||
if (route.options.hasHandler) {
|
||||
;(async (): Promise<void> => {
|
||||
setIsLoading(true)
|
||||
try {
|
||||
const path = route.path === '/' ? '' : route.path
|
||||
const res = await fetch(`/__tuono/data/${path}`)
|
||||
const res = await fetch(`/__tuono/data${location.pathname}`)
|
||||
setData(await res.json())
|
||||
} catch (error) {
|
||||
// Handle here error
|
||||
throw Error('Failed loading Server Side Data', { cause: error })
|
||||
} finally {
|
||||
setIsLoading(false)
|
||||
}
|
||||
@@ -60,7 +61,7 @@ export function useServerSideProps(
|
||||
return (): void => {
|
||||
setData(undefined)
|
||||
}
|
||||
}, [route.path])
|
||||
}, [location.pathname])
|
||||
|
||||
return { isLoading, data }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user