Rust library to generate static websites
5
fork

Configure Feed

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

fix: rework build

+137 -135
+137 -135
crates/maudit/src/build.rs
··· 41 41 async_runtime.block_on(async { build(routes, content_sources, options).await }) 42 42 } 43 43 44 + /// Represents a page to be built 45 + struct PageToBuild { 46 + /// The actual URL for this page (e.g., "/blog/my-post") 47 + url: String, 48 + /// The output file path 49 + file_path: PathBuf, 50 + /// Full page result for dynamic routes from get_pages (params, props, typed_params) 51 + page_result: Option<( 52 + PageParams, 53 + crate::route::PageProps, 54 + crate::route::PageTypedParams, 55 + )>, 56 + /// Optional variant ID 57 + variant_id: Option<String>, 58 + /// Tree depth for logging (0 = base, 1 = variant/dynamic page) 59 + tree_depth: usize, 60 + } 61 + 62 + impl PageToBuild { 63 + fn log_prefix(&self) -> &str { 64 + match self.tree_depth { 65 + 0 => "", 66 + 1 => "├─ ", 67 + _ => "│ ├─ ", 68 + } 69 + } 70 + } 71 + 44 72 pub async fn build( 45 73 routes: &[&dyn FullRoute], 46 74 content_sources: &mut ContentSources, ··· 133 161 134 162 trace!(target: "build", "Processing route: base='{}', variants={}", base_path, variants.len()); 135 163 136 - // Determine if we need to fetch dynamic pages 137 - let base_params = extract_params_from_raw_route(&base_path); 138 - 139 - // Collect logging data for structured output 140 - let mut base_log_line = String::new(); 141 - let mut variant_logs: Vec<String> = Vec::new(); 142 - let mut base_dynamic_logs: Vec<String> = Vec::new(); 164 + // Build list of pages to generate for this route 165 + let mut pages_to_build: Vec<PageToBuild> = Vec::new(); 143 166 144 - // Generate base route pages 167 + // Handle base route 145 168 if !base_path.is_empty() { 169 + let base_params = extract_params_from_raw_route(&base_path); 170 + 146 171 if base_params.is_empty() { 147 - // Static base route - generate one page 148 - let mut route_assets = 149 - RouteAssets::new(&route_assets_options, Some(image_cache.clone())); 172 + // Static base route 150 173 let params = PageParams::default(); 151 174 let url = cached_route.url(&params); 152 - 153 - let result = route.build(&mut PageContext::from_static_route( 154 - content_sources, 155 - &mut route_assets, 156 - &url, 157 - &options.base_url, 158 - None, 159 - ))?; 160 - 161 175 let file_path = cached_route.file_path(&params, &options.output_dir); 162 - write_route_file(&result, &file_path)?; 163 176 164 - base_log_line = format!("{} -> {}", url, file_path.to_string_lossy().dimmed()); 165 - 166 - build_pages_images.extend(route_assets.images); 167 - build_pages_scripts.extend(route_assets.scripts); 168 - build_pages_styles.extend(route_assets.styles); 169 - 170 - build_metadata.add_page( 171 - base_path.clone(), 172 - file_path.to_string_lossy().to_string(), 173 - None, 174 - ); 175 - 176 - page_count += 1; 177 + pages_to_build.push(PageToBuild { 178 + url, 179 + file_path, 180 + page_result: None, 181 + variant_id: None, 182 + tree_depth: 0, 183 + }); 177 184 } else { 178 - // Dynamic base route - just show the pattern 179 - base_log_line = base_path.clone(); 180 - 181 - // Fetch pages for base route with no variant 185 + // Dynamic base route - fetch pages 182 186 let mut page_assets = 183 187 RouteAssets::new(&route_assets_options, Some(image_cache.clone())); 184 188 let pages = route.get_pages(&mut DynamicRouteContext { ··· 190 194 if pages.is_empty() { 191 195 warn!(target: "build", "{} has dynamic parameters but Route::pages returned an empty Vec. No pages will be generated.", base_path.bold()); 192 196 } else { 193 - // Generate pages for each dynamic page (logging collected later) 197 + // Log the pattern first 198 + info!(target: "pages", "{}", base_path); 199 + 194 200 for page in pages { 195 201 let url = cached_route.url(&page.0); 196 - 197 - let content = route.build(&mut PageContext::from_dynamic_route( 198 - &page, 199 - content_sources, 200 - &mut page_assets, 201 - &url, 202 - &options.base_url, 203 - None, 204 - ))?; 205 - 206 202 let file_path = cached_route.file_path(&page.0, &options.output_dir); 207 - write_route_file(&content, &file_path)?; 208 203 209 - base_dynamic_logs.push(format!("{}", file_path.to_string_lossy().dimmed())); 210 - 211 - build_metadata.add_page( 212 - base_path.clone(), 213 - file_path.to_string_lossy().to_string(), 214 - Some(page.0.0.clone()), 215 - ); 216 - 217 - page_count += 1; 204 + pages_to_build.push(PageToBuild { 205 + url, 206 + file_path, 207 + page_result: Some(page), 208 + variant_id: None, 209 + tree_depth: 1, 210 + }); 218 211 } 219 212 } 220 213 ··· 222 215 build_pages_scripts.extend(page_assets.scripts); 223 216 build_pages_styles.extend(page_assets.styles); 224 217 } 225 - } else if !variants.is_empty() { 226 - // No base route, just variants 227 - base_log_line = "(variants only)".to_string(); 228 218 } 229 219 230 - // Generate variant pages 220 + // Handle variants 231 221 for (variant_id, variant_path) in variants { 232 222 let variant_params = extract_params_from_raw_route(&variant_path); 233 223 234 224 if variant_params.is_empty() { 235 - // Static variant - generate one page 236 - let mut route_assets = 237 - RouteAssets::new(&route_assets_options, Some(image_cache.clone())); 238 - 225 + // Static variant 239 226 let params = PageParams::default(); 240 227 let url = cached_route.variant_url(&params, &variant_id)?; 241 - 242 - let result = route.build(&mut PageContext::from_static_route( 243 - content_sources, 244 - &mut route_assets, 245 - &url, 246 - &options.base_url, 247 - Some(variant_id.clone()), 248 - ))?; 249 - 250 228 let file_path = 251 229 cached_route.variant_file_path(&params, &options.output_dir, &variant_id)?; 252 230 253 - write_route_file(&result, &file_path)?; 254 - 255 - variant_logs.push(format!( 256 - "├─ {} -> {}", 231 + pages_to_build.push(PageToBuild { 257 232 url, 258 - file_path.to_string_lossy().dimmed() 259 - )); 260 - 261 - build_pages_images.extend(route_assets.images); 262 - build_pages_scripts.extend(route_assets.scripts); 263 - build_pages_styles.extend(route_assets.styles); 264 - 265 - build_metadata.add_page( 266 - format!("{} ({})", base_path, variant_id), 267 - file_path.to_string_lossy().to_string(), 268 - None, 269 - ); 270 - 271 - page_count += 1; 233 + file_path, 234 + page_result: None, 235 + variant_id: Some(variant_id.clone()), 236 + tree_depth: 1, 237 + }); 272 238 } else { 273 - // Dynamic variant - show pattern then pages 274 - let variant_log = format!("├─ {}", variant_path); 275 - let mut variant_page_logs: Vec<String> = Vec::new(); 276 - 277 - // Fetch pages for this variant 239 + // Dynamic variant - fetch pages 278 240 let mut page_assets = 279 241 RouteAssets::new(&route_assets_options, Some(image_cache.clone())); 280 242 let pages = route.get_pages(&mut DynamicRouteContext { ··· 286 248 if pages.is_empty() { 287 249 warn!(target: "build", "Variant {} has dynamic parameters but Route::pages returned an empty Vec.", variant_id.bold()); 288 250 } else { 251 + // Log the variant pattern first 252 + info!(target: "pages", "├─ {}", variant_path); 253 + 289 254 for page in pages { 290 255 let url = cached_route.variant_url(&page.0, &variant_id)?; 291 - 292 - let content = route.build(&mut PageContext::from_dynamic_route( 293 - &page, 294 - content_sources, 295 - &mut page_assets, 296 - &url, 297 - &options.base_url, 298 - Some(variant_id.clone()), 299 - ))?; 300 - 301 256 let file_path = cached_route.variant_file_path( 302 257 &page.0, 303 258 &options.output_dir, 304 259 &variant_id, 305 260 )?; 306 261 307 - write_route_file(&content, &file_path)?; 308 - 309 - variant_page_logs 310 - .push(format!("│ ├─ {}", file_path.to_string_lossy().dimmed())); 311 - 312 - build_metadata.add_page( 313 - format!("{} ({})", base_path, variant_id), 314 - file_path.to_string_lossy().to_string(), 315 - Some(page.0.0.clone()), 316 - ); 317 - 318 - page_count += 1; 262 + pages_to_build.push(PageToBuild { 263 + url, 264 + file_path, 265 + page_result: Some(page), 266 + variant_id: Some(variant_id.clone()), 267 + tree_depth: 2, 268 + }); 319 269 } 320 270 } 321 271 322 - // Add variant pattern line 323 - variant_logs.push(variant_log); 324 - // Add all the variant's pages 325 - variant_logs.extend(variant_page_logs); 326 - 327 272 build_pages_images.extend(page_assets.images); 328 273 build_pages_scripts.extend(page_assets.scripts); 329 274 build_pages_styles.extend(page_assets.styles); 330 275 } 331 276 } 332 277 333 - // Output logging in hierarchical structure 334 - if !base_log_line.is_empty() { 335 - info!(target: "pages", "{}", base_log_line); 336 - } 337 - for variant_log in variant_logs { 338 - info!(target: "pages", "{}", variant_log); 339 - } 340 - for base_page_log in base_dynamic_logs { 341 - info!(target: "pages", "├─ {}", base_page_log); 278 + // Now build all pages for this route and log as we go 279 + for page_info in pages_to_build { 280 + let mut route_assets = 281 + RouteAssets::new(&route_assets_options, Some(image_cache.clone())); 282 + 283 + let content = if let Some(ref page_result) = page_info.page_result { 284 + // Build dynamic page 285 + route.build(&mut PageContext::from_dynamic_route( 286 + page_result, 287 + content_sources, 288 + &mut route_assets, 289 + &page_info.url, 290 + &options.base_url, 291 + page_info.variant_id.clone(), 292 + ))? 293 + } else { 294 + // Build static page 295 + route.build(&mut PageContext::from_static_route( 296 + content_sources, 297 + &mut route_assets, 298 + &page_info.url, 299 + &options.base_url, 300 + page_info.variant_id.clone(), 301 + ))? 302 + }; 303 + 304 + write_route_file(&content, &page_info.file_path)?; 305 + 306 + // Log immediately 307 + let log_line = if page_info.tree_depth == 0 { 308 + format!( 309 + "{} -> {}", 310 + page_info.url, 311 + page_info.file_path.to_string_lossy().dimmed() 312 + ) 313 + } else { 314 + format!( 315 + "{}{}", 316 + page_info.log_prefix(), 317 + page_info.file_path.to_string_lossy().dimmed() 318 + ) 319 + }; 320 + info!(target: "pages", "{}", log_line); 321 + 322 + // Add to metadata 323 + let metadata_route_name = if let Some(variant_id) = &page_info.variant_id { 324 + if base_path.is_empty() { 325 + format!("({})", variant_id) 326 + } else { 327 + format!("{} ({})", base_path, variant_id) 328 + } 329 + } else { 330 + base_path.clone() 331 + }; 332 + 333 + build_metadata.add_page( 334 + metadata_route_name, 335 + page_info.file_path.to_string_lossy().to_string(), 336 + page_info.page_result.as_ref().map(|pr| pr.0.0.clone()), 337 + ); 338 + 339 + build_pages_images.extend(route_assets.images); 340 + build_pages_scripts.extend(route_assets.scripts); 341 + build_pages_styles.extend(route_assets.styles); 342 + 343 + page_count += 1; 342 344 } 343 345 } 344 346