mirror of
https://github.com/tuono-labs/tuono
synced 2026-07-25 12:52:47 -07:00
Refactor server (#9)
* refactor: move catch_all in tuono_lib * refactor: moved server to tuono_lib * refactor: move router and server into tuono_lib * refactor: reduce exports from examples * refactor: re-organize exports * refactor: removed mode set on project builder * feat: update version to v0.3.1
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "tuono"
|
||||
version = "0.3.0"
|
||||
version = "0.3.1"
|
||||
edition = "2021"
|
||||
authors = ["V. Ageno <valerioageno@yahoo.it>"]
|
||||
description = "The react/rust fullstack framework"
|
||||
|
||||
@@ -47,12 +47,7 @@ pub const AXUM_ENTRY_POINT: &str = r##"
|
||||
// File automatically generated
|
||||
// Do not manually change it
|
||||
|
||||
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, Mode, GLOBAL_MODE, manifest::load_manifest};
|
||||
use tuono_lib::{tokio, Mode, Server, axum::Router, axum::routing::get};
|
||||
use reqwest::Client;
|
||||
|
||||
const MODE: Mode = /*MODE*/;
|
||||
@@ -61,56 +56,18 @@ const MODE: Mode = /*MODE*/;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
Ssr::create_platform();
|
||||
|
||||
let fetch = Client::new();
|
||||
|
||||
GLOBAL_MODE.set(MODE).unwrap();
|
||||
|
||||
if MODE == Mode::Prod {
|
||||
load_manifest()
|
||||
}
|
||||
|
||||
let app = Router::new()
|
||||
let router = Router::new()
|
||||
// ROUTE_BUILDER
|
||||
.fallback_service(ServeDir::new("/*public_dir*/").fallback(get(catch_all)))
|
||||
.with_state(fetch);
|
||||
|
||||
let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap();
|
||||
|
||||
if MODE == Mode::Dev {
|
||||
println!("\nDevelopment app ready at http://localhost:3000/");
|
||||
} else {
|
||||
println!("\nProduction app ready at http://localhost:3000/");
|
||||
}
|
||||
axum::serve(listener, app).await.unwrap();
|
||||
}
|
||||
|
||||
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, params);
|
||||
|
||||
|
||||
// TODO: remove unwrap
|
||||
let payload = tuono_lib::Payload::new(&req, &"")
|
||||
.client_payload()
|
||||
.unwrap();
|
||||
|
||||
let result = ssr::Js::SSR.with(|ssr| ssr.borrow_mut().render_to_string(Some(&payload)));
|
||||
|
||||
match result {
|
||||
Ok(html) => Html(html),
|
||||
_ => Html("500 internal server error".to_string()),
|
||||
}
|
||||
Server::init(router, MODE).start().await
|
||||
}
|
||||
"##;
|
||||
|
||||
const ROOT_FOLDER: &str = "src/routes";
|
||||
const DEV_FOLDER: &str = ".tuono";
|
||||
const DEV_PUBLIC_DIR: &str = "public";
|
||||
const PROD_PUBLIC_DIR: &str = "out/client";
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
struct Route {
|
||||
@@ -254,12 +211,6 @@ pub fn bundle_axum_source(mode: Mode) -> io::Result<()> {
|
||||
}
|
||||
|
||||
fn generate_axum_source(source_builder: &SourceBuilder, mode: Mode) -> String {
|
||||
let public_dir = if mode == Mode::Prod {
|
||||
PROD_PUBLIC_DIR
|
||||
} else {
|
||||
DEV_PUBLIC_DIR
|
||||
};
|
||||
|
||||
AXUM_ENTRY_POINT
|
||||
.replace(
|
||||
"// ROUTE_BUILDER\n",
|
||||
@@ -269,7 +220,6 @@ fn generate_axum_source(source_builder: &SourceBuilder, mode: Mode) -> String {
|
||||
"// MODULE_IMPORTS\n",
|
||||
&create_modules_declaration(&source_builder.route_map),
|
||||
)
|
||||
.replace("/*public_dir*/", public_dir)
|
||||
.replace("/*MODE*/", mode.as_str())
|
||||
}
|
||||
|
||||
@@ -412,20 +362,4 @@ mod tests {
|
||||
assert_eq!(dev, "Mode::Dev");
|
||||
assert_eq!(prod, "Mode::Prod");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_replace_the_correct_public_folder_dev() {
|
||||
let source_builder = SourceBuilder::new();
|
||||
let source = generate_axum_source(&source_builder, Mode::Dev);
|
||||
|
||||
assert!(source.contains(r#"ServeDir::new("public")"#))
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_replace_the_correct_public_folder_prod() {
|
||||
let source_builder = SourceBuilder::new();
|
||||
let source = generate_axum_source(&source_builder, Mode::Prod);
|
||||
|
||||
assert!(source.contains(r#"ServeDir::new("out/client")"#))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "tuono_lib"
|
||||
version = "0.3.0"
|
||||
version = "0.3.1"
|
||||
edition = "2021"
|
||||
authors = ["V. Ageno <valerioageno@yahoo.it>"]
|
||||
description = "The react/rust fullstack framework"
|
||||
@@ -19,14 +19,16 @@ path = "src/lib.rs"
|
||||
|
||||
[dependencies]
|
||||
ssr_rs = "0.5.5"
|
||||
axum = "0.7.5"
|
||||
axum = {version = "0.7.5", features = ["json"]}
|
||||
tokio = { version = "1.37.0", features = ["full"] }
|
||||
serde = { version = "1.0.202", features = ["derive"] }
|
||||
erased-serde = "0.4.5"
|
||||
serde_json = "1.0"
|
||||
|
||||
tuono_lib_macros = {path = "../tuono_lib_macros", version = "0.3.0"}
|
||||
tuono_lib_macros = {path = "../tuono_lib_macros", version = "0.3.1"}
|
||||
once_cell = "1.19.0"
|
||||
lazy_static = "1.5.0"
|
||||
regex = "1.10.5"
|
||||
either = "1.13.0"
|
||||
tower-http = {version = "0.5.2", features = ["fs"]}
|
||||
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
use crate::{ssr::Js, Payload};
|
||||
use axum::extract::{Path, Request};
|
||||
use axum::response::Html;
|
||||
use std::collections::HashMap;
|
||||
|
||||
pub async fn catch_all(
|
||||
Path(params): Path<HashMap<String, String>>,
|
||||
request: Request,
|
||||
) -> Html<String> {
|
||||
let pathname = &request.uri();
|
||||
let headers = &request.headers();
|
||||
|
||||
let req = crate::Request::new(pathname, headers, params);
|
||||
|
||||
// TODO: remove unwrap
|
||||
let payload = Payload::new(&req, &"").client_payload().unwrap();
|
||||
|
||||
let result = Js::SSR.with(|ssr| ssr.borrow_mut().render_to_string(Some(&payload)));
|
||||
|
||||
match result {
|
||||
Ok(html) => Html(html),
|
||||
_ => Html("500 internal server error".to_string()),
|
||||
}
|
||||
}
|
||||
@@ -1,14 +1,19 @@
|
||||
pub mod manifest;
|
||||
mod catch_all;
|
||||
mod manifest;
|
||||
mod mode;
|
||||
mod payload;
|
||||
mod request;
|
||||
mod response;
|
||||
mod server;
|
||||
mod ssr;
|
||||
|
||||
pub mod ssr;
|
||||
|
||||
pub use mode::{Mode, GLOBAL_MODE};
|
||||
pub use mode::Mode;
|
||||
pub use payload::Payload;
|
||||
pub use request::Request;
|
||||
pub use response::{Props, Response};
|
||||
pub use ssr_rs::Ssr;
|
||||
pub use server::Server;
|
||||
pub use tuono_lib_macros::handler;
|
||||
|
||||
// Re-exports
|
||||
pub use axum;
|
||||
pub use tokio;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
use crate::{manifest::MANIFEST, Mode, GLOBAL_MODE};
|
||||
use crate::manifest::MANIFEST;
|
||||
use crate::mode::{Mode, GLOBAL_MODE};
|
||||
use erased_serde::Serialize;
|
||||
use regex::Regex;
|
||||
use serde::Serialize as SerdeSerialize;
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
use crate::mode::{Mode, GLOBAL_MODE};
|
||||
|
||||
use crate::manifest::load_manifest;
|
||||
use axum::routing::{get, Router};
|
||||
use ssr_rs::Ssr;
|
||||
use tower_http::services::ServeDir;
|
||||
|
||||
use crate::catch_all::catch_all;
|
||||
|
||||
const DEV_PUBLIC_DIR: &str = "public";
|
||||
const PROD_PUBLIC_DIR: &str = "out/client";
|
||||
|
||||
pub struct Server {
|
||||
router: Router,
|
||||
mode: Mode,
|
||||
}
|
||||
|
||||
impl Server {
|
||||
pub fn init(router: Router, mode: Mode) -> Server {
|
||||
Ssr::create_platform();
|
||||
|
||||
GLOBAL_MODE.set(mode).unwrap();
|
||||
|
||||
if mode == Mode::Prod {
|
||||
load_manifest()
|
||||
}
|
||||
|
||||
Server { router, mode }
|
||||
}
|
||||
|
||||
pub async fn start(&self) {
|
||||
let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap();
|
||||
|
||||
if self.mode == Mode::Dev {
|
||||
println!("\nDevelopment app ready at http://localhost:3000/");
|
||||
} else {
|
||||
println!("\nProduction app ready at http://localhost:3000/");
|
||||
}
|
||||
|
||||
let public_dir = if self.mode == Mode::Dev {
|
||||
DEV_PUBLIC_DIR
|
||||
} else {
|
||||
PROD_PUBLIC_DIR
|
||||
};
|
||||
|
||||
let router = self
|
||||
.router
|
||||
.to_owned()
|
||||
.fallback_service(ServeDir::new(public_dir).fallback(get(catch_all)));
|
||||
|
||||
axum::serve(listener, router).await.unwrap();
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
use crate::{Mode, GLOBAL_MODE};
|
||||
use crate::mode::{Mode, GLOBAL_MODE};
|
||||
use lazy_static::lazy_static;
|
||||
use ssr_rs::Ssr;
|
||||
use std::cell::RefCell;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "tuono_lib_macros"
|
||||
version = "0.3.0"
|
||||
version = "0.3.1"
|
||||
edition = "2021"
|
||||
description = "The react/rust fullstack framework"
|
||||
repository = "https://github.com/Valerioageno/tuono"
|
||||
|
||||
@@ -8,9 +8,9 @@ pub fn handler_core(_args: TokenStream, item: TokenStream) -> TokenStream {
|
||||
let fn_name = item.clone().sig.ident;
|
||||
|
||||
quote! {
|
||||
use axum::response::IntoResponse;
|
||||
use tuono_lib::axum::response::IntoResponse;
|
||||
use std::collections::HashMap;
|
||||
use axum::extract::{State, Path};
|
||||
use tuono_lib::axum::extract::{State, Path};
|
||||
use reqwest::Client;
|
||||
|
||||
#item
|
||||
@@ -18,7 +18,7 @@ pub fn handler_core(_args: TokenStream, item: TokenStream) -> TokenStream {
|
||||
pub async fn route(
|
||||
Path(params): Path<HashMap<String, String>>,
|
||||
State(client): State<Client>,
|
||||
request: axum::extract::Request
|
||||
request: tuono_lib::axum::extract::Request
|
||||
) -> impl IntoResponse {
|
||||
let pathname = &request.uri();
|
||||
let headers = &request.headers();
|
||||
@@ -31,7 +31,7 @@ pub fn handler_core(_args: TokenStream, item: TokenStream) -> TokenStream {
|
||||
pub async fn api(
|
||||
Path(params): Path<HashMap<String, String>>,
|
||||
State(client): State<Client>,
|
||||
request: axum::extract::Request
|
||||
request: tuono_lib::axum::extract::Request
|
||||
) -> impl IntoResponse{
|
||||
let pathname = &request.uri();
|
||||
let headers = &request.headers();
|
||||
|
||||
@@ -8,11 +8,5 @@ name = "tuono"
|
||||
path = ".tuono/main.rs"
|
||||
|
||||
[dependencies]
|
||||
axum = {version = "0.7.5", features = ["json"]}
|
||||
tokio = { version = "1.37.0", features = ["full"] }
|
||||
tower-http = {version = "0.5.2", features = ["fs"]}
|
||||
serde = { version = "1.0.202", features = ["derive"] }
|
||||
tuono_lib = { path = "../../crates/tuono_lib/"}
|
||||
serde_json = "1.0"
|
||||
reqwest = {version = "0.12.4", features = ["json"]}
|
||||
|
||||
|
||||
@@ -8,11 +8,7 @@ name = "tuono"
|
||||
path = ".tuono/main.rs"
|
||||
|
||||
[dependencies]
|
||||
axum = {version = "0.7.5", features = ["json"]}
|
||||
tokio = { version = "1.37.0", features = ["full"] }
|
||||
tower-http = {version = "0.5.2", features = ["fs"]}
|
||||
serde = { version = "1.0.202", features = ["derive"] }
|
||||
tuono_lib = { path = "../../crates/tuono_lib/"}
|
||||
serde_json = "1.0"
|
||||
serde = { version = "1.0.202", features = ["derive"] }
|
||||
reqwest = {version = "0.12.4", features = ["json"]}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "tuono-lazy-fn-vite-plugin",
|
||||
"version": "0.3.0",
|
||||
"version": "0.3.1",
|
||||
"description": "Plugin for the tuono's lazy fn. Tuono is the react/rust fullstack framework",
|
||||
"scripts": {
|
||||
"dev": "vite build --watch",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "tuono",
|
||||
"version": "0.3.0",
|
||||
"version": "0.3.1",
|
||||
"description": "The react/rust fullstack framework",
|
||||
"scripts": {
|
||||
"dev": "vite build --watch",
|
||||
|
||||
Reference in New Issue
Block a user