refactor: SourceBuilder (#678)

This commit is contained in:
Valerio Ageno
2025-03-30 14:11:32 +02:00
committed by GitHub
parent abb12e7b3d
commit 3b3f601ff1
2 changed files with 69 additions and 76 deletions
+7 -4
View File
@@ -116,7 +116,7 @@ pub async fn watch(source_builder: SourceBuilder) -> Result<()> {
// Remove the spinner
sp.stop();
term.clear_line().unwrap();
_ = term.clear_line();
let wx = Watchexec::new(move |mut action| {
let mut should_reload_ssr_bundle = false;
@@ -126,6 +126,8 @@ pub async fn watch(source_builder: SourceBuilder) -> Result<()> {
for path in event.paths() {
let file_path = path.0.to_string_lossy();
if file_path.ends_with(".rs") {
// TODO: only the new file show trigger a axum refresh.
// Update of existing file should just reload the server.
should_reload_rust_server = true
}
@@ -138,9 +140,10 @@ pub async fn watch(source_builder: SourceBuilder) -> Result<()> {
if should_reload_rust_server {
println!(" Reloading...");
rust_server.stop();
let mut builder = source_builder.write().unwrap();
builder.app.collect_routes();
_ = builder.refresh_axum_source();
if let Ok(mut builder) = source_builder.write() {
builder.app.collect_routes();
_ = builder.refresh_axum_source();
}
rust_server.start();
}
+62 -72
View File
@@ -1,4 +1,3 @@
use std::collections::HashMap;
use std::fs;
use std::io;
use std::io::prelude::*;
@@ -77,8 +76,6 @@ impl SourceBuilder {
let base_path = std::env::current_dir()?;
create_client_entry_files()?;
Ok(Self {
app,
mode,
@@ -91,11 +88,14 @@ impl SourceBuilder {
let Self { mode, .. } = &self;
self.refresh_axum_source()?;
let dev_folder = Path::new(DEV_FOLDER);
self.create_file(dev_folder.join("server-main.tsx"), SERVER_ENTRY_DATA)?;
self.create_file(dev_folder.join("client-main.tsx"), CLIENT_ENTRY_DATA)?;
if mode == &Mode::Dev {
self.app.build_tuono_config()?;
let fallback_html = create_html_fallback(&self.app);
self.create_file(FALLBACK_HTML_PATH, &fallback_html)?;
let fallback_html = self.build_html_fallback();
self.create_file(PathBuf::from(FALLBACK_HTML_PATH), &fallback_html)?;
}
Ok(())
@@ -106,14 +106,8 @@ impl SourceBuilder {
let src = AXUM_ENTRY_POINT
.replace("\r", "")
.replace(
"// ROUTE_BUILDER\n",
&create_routes_declaration(&app.route_map),
)
.replace(
"// MODULE_IMPORTS\n",
&create_modules_declaration(&app.route_map),
)
.replace("// ROUTE_BUILDER\n", &self.create_routes_declaration())
.replace("// MODULE_IMPORTS\n", &self.create_modules_declaration())
.replace("/*VERSION*/", crate_version!())
.replace("/*MODE*/", mode.as_str())
.replace(
@@ -158,97 +152,87 @@ impl SourceBuilder {
pub fn refresh_axum_source(&self) -> io::Result<()> {
let axum_source = self.generate_axum_source();
self.create_file(MAIN_FILE_PATH, &axum_source)?;
self.create_file(PathBuf::from(MAIN_FILE_PATH), &axum_source)?;
Ok(())
}
fn create_file(&self, path: &str, content: &str) -> io::Result<()> {
fn create_file(&self, path: PathBuf, content: &str) -> io::Result<()> {
let mut data_file = fs::File::create(self.base_path.join(path))?;
data_file.write_all(content.as_bytes())?;
Ok(())
}
}
fn create_routes_declaration(routes: &HashMap<String, Route>) -> String {
let mut route_declarations = String::from("// ROUTE_BUILDER\n");
fn create_routes_declaration(&self) -> String {
let routes = &self.app.route_map;
let mut route_declarations = String::from("// ROUTE_BUILDER\n");
for (_, route) in routes.iter() {
let Route { axum_info, .. } = &route;
for (_, route) in routes.iter() {
let Route { axum_info, .. } = &route;
if axum_info.is_some() {
let AxumInfo {
axum_route,
module_import,
} = axum_info.as_ref().unwrap();
if axum_info.is_some() {
let AxumInfo {
axum_route,
module_import,
} = axum_info.as_ref().unwrap();
if !route.is_api() {
route_declarations.push_str(&format!(
r#".route("{axum_route}", get({module_import}::tuono_internal_route))"#
));
route_declarations.push_str(&format!(
r#".route("/__tuono/data{axum_route}", get({module_import}::tuono_internal_api))"#
));
} else {
for method in route.api_data.as_ref().unwrap().methods.clone() {
let method = method.to_string().to_lowercase();
if !route.is_api() {
route_declarations.push_str(&format!(
r#".route("{axum_route}", {method}({module_import}::{method}_tuono_internal_api))"#
r#".route("{axum_route}", get({module_import}::tuono_internal_route))"#
));
route_declarations.push_str(&format!(
r#".route("/__tuono/data{axum_route}", get({module_import}::tuono_internal_api))"#
));
} else {
for method in route.api_data.as_ref().unwrap().methods.clone() {
let method = method.to_string().to_lowercase();
route_declarations.push_str(&format!(
r#".route("{axum_route}", {method}({module_import}::{method}_tuono_internal_api))"#
));
}
}
}
}
route_declarations
}
route_declarations
}
fn create_modules_declaration(&self) -> String {
let routes = &self.app.route_map;
let mut route_declarations = String::from("// MODULE_IMPORTS\n");
fn create_modules_declaration(routes: &HashMap<String, Route>) -> String {
let mut route_declarations = String::from("// MODULE_IMPORTS\n");
for (path, route) in routes.iter() {
if route.axum_info.is_some() {
let AxumInfo { module_import, .. } = route.axum_info.as_ref().unwrap();
for (path, route) in routes.iter() {
if route.axum_info.is_some() {
let AxumInfo { module_import, .. } = route.axum_info.as_ref().unwrap();
route_declarations.push_str(&format!(
r#"#[path="../{ROUTE_FOLDER}{path}.rs"]
route_declarations.push_str(&format!(
r#"#[path="../{ROUTE_FOLDER}{path}.rs"]
mod {module_import};
"#
))
))
}
}
route_declarations
}
route_declarations
}
fn create_html_fallback(app: &App) -> String {
if let Some(config) = app.config.as_ref() {
if let Some(origin) = &config.server.origin {
FALLBACK_HTML.replace("[BASE_URL]", origin)
fn build_html_fallback(&self) -> String {
if let Some(config) = &self.app.config.as_ref() {
if let Some(origin) = &config.server.origin {
FALLBACK_HTML.replace("[BASE_URL]", origin)
} else {
let url = format!("http://{}:{}", config.server.host, config.server.port);
FALLBACK_HTML.replace("[BASE_URL]", url.as_str())
}
} else {
let url = format!("http://{}:{}", config.server.host, config.server.port);
FALLBACK_HTML.replace("[BASE_URL]", url.as_str())
"".to_string()
}
} else {
"".to_string()
}
}
pub fn create_client_entry_files() -> io::Result<()> {
let dev_folder = Path::new(DEV_FOLDER);
let mut server_entry = fs::File::create(dev_folder.join("server-main.tsx"))?;
let mut client_entry = fs::File::create(dev_folder.join("client-main.tsx"))?;
server_entry.write_all(SERVER_ENTRY_DATA.as_bytes())?;
client_entry.write_all(CLIENT_ENTRY_DATA.as_bytes())?;
Ok(())
}
#[cfg(test)]
mod tests {
@@ -312,7 +296,13 @@ mod tests {
let mut app = App::new();
app.config = Some(Default::default());
let fallback_html = create_html_fallback(&app);
let source_builder = SourceBuilder {
app,
mode: Mode::Dev,
base_path: PathBuf::new(),
};
let fallback_html = source_builder.build_html_fallback();
assert!(fallback_html.contains("http://localhost:3000/vite-server/@react-refresh"));
assert!(fallback_html.contains("http://localhost:3000/vite-server/@vite/client"));