Rust library to generate static websites
5
fork

Configure Feed

Select the types of activity you want to include in your feed.

feat: allow customizing output folder

+56 -25
+10 -7
crates/framework/src/assets.rs
··· 3 3 use maud::{html, Markup, Render}; 4 4 use rustc_hash::FxHashSet; 5 5 use std::hash::Hash; 6 + use std::path::Path; 6 7 use std::process::Command; 7 8 use std::time::SystemTime; 8 9 use std::{fs, path::PathBuf}; ··· 66 67 fn url(&self) -> Option<String>; 67 68 fn path(&self) -> &PathBuf; 68 69 69 - fn process(&self) -> Option<String> { 70 + fn process(&self, _dist_assets_dir: &Path, _tmp_dir: &Path) -> Option<String> { 70 71 None 71 72 } 72 73 fn hash(&self) -> [u8; 8]; ··· 97 98 &self.path 98 99 } 99 100 100 - fn process(&self) -> Option<String> { 101 + fn process(&self, dist_assets_dir: &Path, _: &Path) -> Option<String> { 101 102 fs::copy( 102 103 &self.path, 103 - "dist/_assets/".to_string() + self.path.file_name().unwrap().to_str().unwrap(), 104 + dist_assets_dir.join(self.path.file_name().unwrap()), 104 105 ) 105 106 .unwrap(); 106 107 ··· 169 170 &self.path 170 171 } 171 172 172 - fn process(&self) -> Option<String> { 173 + fn process(&self, _: &Path, tmp_dir: &Path) -> Option<String> { 173 174 // TODO: Detect tailwind automatically 174 175 if self.tailwind { 175 - let tmp_path = "dist/_tmp/tailwind.css"; 176 + let tmp_path = tmp_dir.join("tailwind.css"); 177 + let tmp_path_str = tmp_path.to_str().unwrap().to_string(); 178 + 176 179 let start_tailwind = SystemTime::now(); 177 180 let tailwind_output = Command::new("tailwindcss") // TODO: Allow custom tailwind binary path 181 + .args(["--output", &tmp_path_str]) 178 182 .arg("--minify") // TODO: Allow disabling minification 179 - .args(["--output", tmp_path]) 180 183 .output() 181 184 .expect("failed to execute process"); 182 185 183 186 info!("Tailwind took {:?}", start_tailwind.elapsed().unwrap()); 184 187 185 188 if tailwind_output.status.success() { 186 - return Some(tmp_path.into()); 189 + return Some(tmp_path_str); 187 190 } 188 191 } 189 192
+41 -16
crates/framework/src/lib.rs
··· 66 66 } 67 67 } 68 68 69 - pub fn coronate(routes: Vec<&dyn FullPage>) -> Result<BuildOutput, Box<dyn std::error::Error>> { 69 + pub struct BuildOptions { 70 + pub output_dir: String, 71 + pub assets_dir: String, 72 + } 73 + 74 + impl Default for BuildOptions { 75 + fn default() -> Self { 76 + Self { 77 + output_dir: "dist".to_string(), 78 + assets_dir: "_assets".to_string(), 79 + } 80 + } 81 + } 82 + 83 + pub fn coronate( 84 + routes: Vec<&dyn FullPage>, 85 + options: BuildOptions, 86 + ) -> Result<BuildOutput, Box<dyn std::error::Error>> { 70 87 tokio::runtime::Builder::new_multi_thread() 71 88 .enable_all() 72 89 .build() 73 90 .unwrap() 74 - .block_on(async { build(routes).await }) 91 + .block_on(async { build(routes, options).await }) 75 92 } 76 93 77 - pub async fn build(routes: Vec<&dyn FullPage>) -> Result<BuildOutput, Box<dyn std::error::Error>> { 94 + pub async fn build( 95 + routes: Vec<&dyn FullPage>, 96 + options: BuildOptions, 97 + ) -> Result<BuildOutput, Box<dyn std::error::Error>> { 78 98 let build_start = SystemTime::now(); 79 99 let logging_env = Env::default().filter_or("RUST_LOG", "info"); 80 100 Builder::from_env(logging_env) ··· 98 118 99 119 // Create a directory for the output 100 120 trace!(target: "build", "Setting up required directories..."); 101 - fs::remove_dir_all("dist").unwrap_or_default(); 102 - fs::create_dir_all("dist").unwrap(); 103 - fs::create_dir_all("dist/_assets").unwrap(); 121 + let dist_dir = PathBuf::from_str(&options.output_dir).unwrap(); 122 + let assets_dir = PathBuf::from_str(&options.output_dir) 123 + .unwrap() 124 + .join(&options.assets_dir); 125 + let tmp_dir = dist_dir.join("_tmp"); 126 + 127 + fs::remove_dir_all(&dist_dir).unwrap_or_default(); 128 + fs::create_dir_all(&dist_dir).unwrap(); 129 + fs::create_dir_all(&assets_dir).unwrap(); 104 130 105 131 print_title("generating pages"); 106 132 let pages_start = SystemTime::now(); ··· 147 173 assets: &mut page_assets, 148 174 }; 149 175 150 - let (file_path, mut file) = create_route_file(route, &ctx.params)?; 176 + let (file_path, mut file) = create_route_file(route, &ctx.params, &dist_dir)?; 151 177 let result = route.render(&mut ctx); 152 178 153 179 finish_route( ··· 180 206 let route_start = SystemTime::now(); 181 207 let mut ctx = RouteContext { params, assets: &mut pages_assets }; 182 208 183 - let (file_path, mut file) = create_route_file(route, &ctx.params).unwrap(); 209 + let (file_path, mut file) = create_route_file(route, &ctx.params, &dist_dir).unwrap(); 184 210 let result = route.render(&mut ctx); 185 211 186 212 build_metadata.pages.push(PageOutput { ··· 211 237 print_title("generating assets"); 212 238 213 239 build_pages_assets.iter().for_each(|asset| { 214 - asset.process(); 240 + asset.process(&assets_dir, &tmp_dir); 215 241 216 242 // TODO: Add outputted assets to build_metadata, might need dedicated fs methods for this 217 243 }); ··· 219 245 let css_inputs = build_pages_styles 220 246 .iter() 221 247 .map(|style| { 222 - let processed_path = style.process(); 248 + let processed_path = style.process(&assets_dir, &tmp_dir); 223 249 224 250 InputItem { 225 251 import: { ··· 247 273 let mut bundler = Bundler::new(BundlerOptions { 248 274 input: Some(bundler_inputs), 249 275 minify: Some(true), 250 - dir: Some("dist/_assets".to_string()), 276 + dir: Some(assets_dir.to_string_lossy().to_string()), 251 277 252 278 ..Default::default() 253 279 }); ··· 267 293 print_title("copying assets"); 268 294 269 295 // Copy the static directory to the dist directory 270 - copy_recursively("./static", "./dist", &mut build_metadata)?; 296 + copy_recursively("./static", &dist_dir, &mut build_metadata)?; 271 297 272 298 let formatted_elasped_time = 273 299 format_elapsed_time(assets_start.elapsed(), &FormatElapsedTimeOptions::default())?; ··· 275 301 } 276 302 277 303 // Remove temporary files 278 - remove_dir_all("dist/_tmp").unwrap_or_default(); 304 + remove_dir_all(&tmp_dir).unwrap_or_default(); 279 305 280 306 let formatted_elasped_time = 281 307 format_elapsed_time(build_start.elapsed(), &section_format_options)?; ··· 318 344 fn create_route_file( 319 345 route: &dyn page::FullPage, 320 346 params: &RouteParams, 347 + dist_dir: &Path, 321 348 ) -> Result<(PathBuf, File), Box<dyn std::error::Error>> { 322 - let file_path = PathBuf::from_str("./dist/") 323 - .unwrap() 324 - .join(route.file_path(params)); 349 + let file_path = dist_dir.join(route.file_path(params)); 325 350 326 351 // Create the parent directories if it doesn't exist 327 352 let parent_dir = Path::new(file_path.parent().unwrap());
+5 -2
crates/user-example/src/main.rs
··· 1 - use maudit::{coronate, generate_pages_mod, routes, BuildOutput}; 1 + use maudit::{coronate, generate_pages_mod, routes, BuildOptions, BuildOutput}; 2 2 3 3 generate_pages_mod!(); 4 4 5 5 fn main() -> Result<BuildOutput, Box<dyn std::error::Error>> { 6 - coronate(routes![Index, DynamicExample, Endpoint, HelloWorld]) 6 + coronate( 7 + routes![Index, DynamicExample, Endpoint, HelloWorld], 8 + BuildOptions::default(), 9 + ) 7 10 }