Rust library to generate static websites
5
fork

Configure Feed

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

fix: I will fight for your right to make Maudit at home using Maudit

+89 -79
+25 -6
crates/maudit/src/assets.rs
··· 8 8 9 9 mod image; 10 10 pub mod image_cache; 11 - mod prefetch; 11 + pub mod prefetch; 12 12 mod sanitize_filename; 13 13 mod script; 14 14 mod style; ··· 60 60 image_cache, 61 61 ..Default::default() 62 62 } 63 + } 64 + 65 + pub fn with_default_assets( 66 + assets_options: &RouteAssetsOptions, 67 + image_cache: Option<ImageCache>, 68 + scripts: Vec<Script>, 69 + styles: Vec<Style>, 70 + ) -> Self { 71 + let mut route_assets = Self::new(assets_options, image_cache); 72 + 73 + for script in scripts { 74 + route_assets.scripts.insert(script); 75 + } 76 + 77 + for style in styles { 78 + route_assets.styles.insert(style); 79 + } 80 + 81 + route_assets 63 82 } 64 83 65 84 pub fn assets(&self) -> impl Iterator<Item = &dyn Asset> { ··· 401 420 implement_asset_trait!(Script); 402 421 implement_asset_trait!(Style); 403 422 404 - struct HashConfig<'a> { 405 - asset_type: HashAssetType<'a>, 406 - hashing_strategy: &'a AssetHashingStrategy, 423 + pub struct HashConfig<'a> { 424 + pub asset_type: HashAssetType<'a>, 425 + pub hashing_strategy: &'a AssetHashingStrategy, 407 426 } 408 427 409 - enum HashAssetType<'a> { 428 + pub enum HashAssetType<'a> { 410 429 Image(&'a ImageOptions), 411 430 Style(&'a StyleOptions), 412 431 Script, ··· 434 453 output_assets_dir.join(file_name) 435 454 } 436 455 437 - fn calculate_hash(path: &Path, options: Option<&HashConfig>) -> Result<String, AssetError> { 456 + pub fn calculate_hash(path: &Path, options: Option<&HashConfig>) -> Result<String, AssetError> { 438 457 let start_time = Instant::now(); 439 458 let content = if options 440 459 .is_some_and(|cfg| *cfg.hashing_strategy == AssetHashingStrategy::FastImprecise)
+11 -25
crates/maudit/src/assets/prefetch.rs
··· 1 - use std::path::PathBuf; 1 + use rolldown::plugin::{HookUsage, Plugin}; 2 2 3 - use rolldown::plugin::{HookUsage, Plugin}; 3 + pub const PREFETCH_PATH: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/js/prefetch.ts"); 4 + pub const PREFETCH_HOVER_PATH: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/js/prefetch/hover.ts"); 5 + pub const PREFETCH_TAP_PATH: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/js/prefetch/tap.ts"); 6 + pub const PREFETCH_VIEWPORT_PATH: &str = 7 + concat!(env!("CARGO_MANIFEST_DIR"), "/js/prefetch/viewport.ts"); 4 8 5 - /// Rolldown plugin to resolve prefetch modules to their actual file paths. 9 + /// Rolldown plugin to handle the maudit:prefetch specifier. 10 + /// Importing the actual prefetch.ts file from Maudit's crate is very cumbersome in JS, and TypeScript anyway won't enjoy finding the types there 11 + /// As such, this plugin resolves the maudit:prefetch specifier to the actual file path of prefetch.ts in the Maudit crate for the user. 6 12 #[derive(Debug)] 7 13 pub struct PrefetchPlugin; 8 14 9 - impl PrefetchPlugin { 10 - /// Get the base directory where the prefetch files are located. 11 - fn get_base_dir() -> PathBuf { 12 - PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("js") 13 - } 14 - 15 - /// Resolve a maudit:prefetch specifier to its actual file path. 16 - fn resolve_prefetch_path(specifier: &str) -> Option<PathBuf> { 17 - let base_dir = Self::get_base_dir(); 18 - 19 - match specifier { 20 - "maudit:prefetch" => Some(base_dir.join("prefetch.ts")), 21 - "maudit:prefetch:hover" => Some(base_dir.join("prefetch").join("hover.ts")), 22 - "maudit:prefetch:tap" => Some(base_dir.join("prefetch").join("tap.ts")), 23 - "maudit:prefetch:viewport" => Some(base_dir.join("prefetch").join("viewport.ts")), 24 - _ => None, 25 - } 26 - } 27 - } 28 - 29 15 impl Plugin for PrefetchPlugin { 30 16 fn name(&self) -> std::borrow::Cow<'static, str> { 31 17 "builtin:prefetch".into() ··· 40 26 _ctx: &rolldown::plugin::PluginContext, 41 27 args: &rolldown::plugin::HookResolveIdArgs<'_>, 42 28 ) -> rolldown::plugin::HookResolveIdReturn { 43 - if let Some(path) = Self::resolve_prefetch_path(args.specifier) { 29 + if args.specifier == "maudit:prefetch" { 44 30 return Ok(Some(rolldown::plugin::HookResolveIdOutput { 45 - id: path.to_string_lossy().to_string().into(), 31 + id: PREFETCH_PATH.into(), 46 32 ..Default::default() 47 33 })); 48 34 }
+53 -48
crates/maudit/src/build.rs
··· 10 10 11 11 use crate::{ 12 12 BuildOptions, BuildOutput, 13 - assets::{self, PrefetchPlugin, RouteAssets, Script, TailwindPlugin, image_cache::ImageCache}, 14 - build::images::process_image, 15 - build::options::PrefetchStrategy, 13 + assets::{ 14 + self, HashAssetType, HashConfig, RouteAssets, Script, TailwindPlugin, calculate_hash, 15 + image_cache::ImageCache, prefetch, 16 + }, 17 + build::{images::process_image, options::PrefetchStrategy}, 16 18 content::ContentSources, 17 19 is_dev, 18 20 logging::print_title, ··· 135 137 136 138 let prefetch_path = match options.prefetch.strategy { 137 139 PrefetchStrategy::None => None, 138 - PrefetchStrategy::Hover => Some("maudit:prefetch:hover"), 139 - PrefetchStrategy::Tap => Some("maudit:prefetch:tap"), 140 - PrefetchStrategy::Viewport => Some("maudit:prefetch:viewport"), 140 + PrefetchStrategy::Hover => Some(PathBuf::from(prefetch::PREFETCH_HOVER_PATH)), 141 + PrefetchStrategy::Tap => Some(PathBuf::from(prefetch::PREFETCH_TAP_PATH)), 142 + PrefetchStrategy::Viewport => Some(PathBuf::from(prefetch::PREFETCH_VIEWPORT_PATH)), 141 143 }; 142 144 143 145 if let Some(prefetch_path) = prefetch_path { 144 146 let prefetch_script = Script::new( 145 - PathBuf::from(prefetch_path), 147 + prefetch_path.clone(), 146 148 true, 147 - { 148 - use rapidhash::fast::RapidHasher; 149 - use std::hash::Hasher; 150 - 151 - let prefetch_content = include_str!("../js/prefetch.ts"); 152 - let mut buf = Vec::with_capacity(prefetch_content.len()); 153 - buf.extend_from_slice(include_str!("../js/prefetch.ts").as_bytes()); 154 - 155 - let mut hasher = RapidHasher::default(); 156 - hasher.write(&buf); 157 - 158 - let hash = hasher.finish(); 159 - let hex = format!("{:016x}", hash); 160 - hex[..5].to_string() 161 - }, 149 + calculate_hash( 150 + &prefetch_path, 151 + Some(&HashConfig { 152 + asset_type: HashAssetType::Script, 153 + hashing_strategy: &options.assets.hashing_strategy, 154 + }), 155 + )?, 162 156 &route_assets_options, 163 157 ); 164 158 default_scripts.push(prefetch_script); ··· 188 182 189 183 // Static base route 190 184 if base_params.is_empty() { 191 - let mut route_assets = 192 - RouteAssets::new(&route_assets_options, Some(image_cache.clone())); 193 - 194 - route_assets.scripts.extend(default_scripts.clone()); 185 + let mut route_assets = RouteAssets::with_default_assets( 186 + &route_assets_options, 187 + Some(image_cache.clone()), 188 + default_scripts.clone(), 189 + vec![], 190 + ); 195 191 196 192 let params = PageParams::default(); 197 193 let url = cached_route.url(&params); ··· 232 228 page_count += 1; 233 229 } else { 234 230 // Dynamic base route 235 - let mut route_assets = 236 - RouteAssets::new(&route_assets_options, Some(image_cache.clone())); 231 + let mut route_assets = RouteAssets::with_default_assets( 232 + &route_assets_options, 233 + Some(image_cache.clone()), 234 + default_scripts.clone(), 235 + vec![], 236 + ); 237 237 let pages = route.get_pages(&mut DynamicRouteContext { 238 238 content: content_sources, 239 239 assets: &mut route_assets, ··· 298 298 299 299 if variant_params.is_empty() { 300 300 // Static variant 301 - let mut route_assets = 302 - RouteAssets::new(&route_assets_options, Some(image_cache.clone())); 301 + let mut route_assets = RouteAssets::with_default_assets( 302 + &route_assets_options, 303 + Some(image_cache.clone()), 304 + default_scripts.clone(), 305 + vec![], 306 + ); 303 307 304 308 let params = PageParams::default(); 305 309 let url = cached_route.variant_url(&params, &variant_id)?; ··· 340 344 page_count += 1; 341 345 } else { 342 346 // Dynamic variant 343 - let mut route_assets = 344 - RouteAssets::new(&route_assets_options, Some(image_cache.clone())); 347 + let mut route_assets = RouteAssets::with_default_assets( 348 + &route_assets_options, 349 + Some(image_cache.clone()), 350 + default_scripts.clone(), 351 + vec![], 352 + ); 345 353 let pages = route.get_pages(&mut DynamicRouteContext { 346 354 content: content_sources, 347 355 assets: &mut route_assets, ··· 471 479 module_types: Some(module_types_hashmap), 472 480 ..Default::default() 473 481 }, 474 - vec![ 475 - Arc::new(TailwindPlugin { 476 - tailwind_path: options.assets.tailwind_binary_path.clone(), 477 - tailwind_entries: build_pages_styles 478 - .iter() 479 - .filter_map(|style| { 480 - if style.tailwind { 481 - Some(style.path().clone()) 482 - } else { 483 - None 484 - } 485 - }) 486 - .collect::<Vec<PathBuf>>(), 487 - }), 488 - Arc::new(PrefetchPlugin {}), 489 - ], 482 + vec![Arc::new(TailwindPlugin { 483 + tailwind_path: options.assets.tailwind_binary_path.clone(), 484 + tailwind_entries: build_pages_styles 485 + .iter() 486 + .filter_map(|style| { 487 + if style.tailwind { 488 + Some(style.path().clone()) 489 + } else { 490 + None 491 + } 492 + }) 493 + .collect::<Vec<PathBuf>>(), 494 + })], 490 495 )?; 491 496 492 497 let _result = bundler.write().await?;