|
1 | | -use std::path::PathBuf; |
| 1 | +use std::path::{Path, PathBuf}; |
| 2 | +use std::sync::Arc; |
2 | 3 |
|
3 | | -use rolldown::BundlerOptions; |
| 4 | +use rolldown::{ |
| 5 | + BundleFactory, BundleFactoryOptions, BundlerOptions, Platform, ResolveOptions, TsConfig, |
| 6 | +}; |
| 7 | +use rolldown_fs::MemoryFileSystem; |
| 8 | +use rolldown_resolver::Resolver; |
4 | 9 | use rolldown_workspace::root_dir; |
5 | 10 |
|
6 | 11 | pub fn join_by_workspace_root(path: &str) -> PathBuf { |
@@ -60,3 +65,86 @@ pub fn derive_benchmark_items( |
60 | 65 |
|
61 | 66 | ret |
62 | 67 | } |
| 68 | + |
| 69 | +/// Walk a directory recursively and load all files into a `MemoryFileSystem`. |
| 70 | +/// This is used in benchmarks to eliminate disk I/O from the timed section. |
| 71 | +pub fn preload_into_memory_fs(dir: &Path) -> MemoryFileSystem { |
| 72 | + let mut fs = MemoryFileSystem::default(); |
| 73 | + walk_and_load(dir, &mut fs); |
| 74 | + fs |
| 75 | +} |
| 76 | + |
| 77 | +fn walk_and_load(dir: &Path, fs: &mut MemoryFileSystem) { |
| 78 | + let entries = match std::fs::read_dir(dir) { |
| 79 | + Ok(entries) => entries, |
| 80 | + Err(_) => return, |
| 81 | + }; |
| 82 | + for entry in entries.flatten() { |
| 83 | + let path = entry.path(); |
| 84 | + if path.is_dir() { |
| 85 | + walk_and_load(&path, fs); |
| 86 | + } else if path.is_file() |
| 87 | + && let Ok(content) = std::fs::read(&path) |
| 88 | + { |
| 89 | + fs.add_file_bytes(&path, &content); |
| 90 | + } |
| 91 | + } |
| 92 | +} |
| 93 | + |
| 94 | +/// Precomputed benchmark context: factory, MemoryFileSystem, and resolver config. |
| 95 | +/// Created once per benchmark item (outside the timed loop). |
| 96 | +pub struct BenchContext { |
| 97 | + pub factory: BundleFactory, |
| 98 | + pub mem_fs: MemoryFileSystem, |
| 99 | + pub cwd: PathBuf, |
| 100 | + pub platform: Platform, |
| 101 | + pub tsconfig: TsConfig, |
| 102 | + pub raw_resolve: ResolveOptions, |
| 103 | +} |
| 104 | + |
| 105 | +impl BenchContext { |
| 106 | + /// Create a fresh resolver for each benchmark iteration to avoid cache warming bias. |
| 107 | + pub fn create_resolver(&self) -> Arc<Resolver<MemoryFileSystem>> { |
| 108 | + Arc::new(Resolver::new( |
| 109 | + self.mem_fs.clone(), |
| 110 | + self.cwd.clone(), |
| 111 | + self.platform, |
| 112 | + &self.tsconfig, |
| 113 | + self.raw_resolve.clone(), |
| 114 | + )) |
| 115 | + } |
| 116 | +} |
| 117 | + |
| 118 | +/// Create a `BenchContext` for a given set of bundler options. |
| 119 | +/// This performs all one-time setup (option normalization, FS preloading, resolver creation) |
| 120 | +/// so the timed loop only measures bundling work. |
| 121 | +pub fn create_bench_context(options: &BundlerOptions) -> BenchContext { |
| 122 | + let cwd = options |
| 123 | + .cwd |
| 124 | + .clone() |
| 125 | + .unwrap_or_else(|| std::env::current_dir().expect("Failed to get current dir")); |
| 126 | + let mem_fs = preload_into_memory_fs(&cwd); |
| 127 | + // Mirror the normalization in prepare_build_context: derive platform from format, |
| 128 | + // and add default condition_names for Browser/Node. |
| 129 | + let format = options.format.unwrap_or(rolldown::OutputFormat::Esm); |
| 130 | + let platform = options.platform.unwrap_or(match format { |
| 131 | + rolldown::OutputFormat::Cjs => Platform::Node, |
| 132 | + rolldown::OutputFormat::Esm | rolldown::OutputFormat::Iife | rolldown::OutputFormat::Umd => { |
| 133 | + Platform::Browser |
| 134 | + } |
| 135 | + }); |
| 136 | + let tsconfig = options.tsconfig.clone().map(|tc| tc.with_base(&cwd)).unwrap_or_default(); |
| 137 | + let mut raw_resolve = options.resolve.clone().unwrap_or_default(); |
| 138 | + if raw_resolve.condition_names.is_none() && matches!(platform, Platform::Browser | Platform::Node) |
| 139 | + { |
| 140 | + raw_resolve.condition_names = Some(vec!["module".to_string()]); |
| 141 | + } |
| 142 | + let factory = BundleFactory::new(BundleFactoryOptions { |
| 143 | + bundler_options: options.clone(), |
| 144 | + plugins: vec![], |
| 145 | + session: None, |
| 146 | + disable_tracing_setup: true, |
| 147 | + }) |
| 148 | + .expect("Failed to create bundle factory"); |
| 149 | + BenchContext { factory, mem_fs, cwd, platform, tsconfig, raw_resolve } |
| 150 | +} |
0 commit comments