#[cfg(feature = "experimental")]
use super::Bundler;
#[cfg(feature = "experimental")]
use crate::hmr::hmr_stage::{HmrStage, HmrStageInput};
#[cfg(feature = "experimental")]
use arcstr::ArcStr;
#[cfg(feature = "experimental")]
use rolldown_common::WatcherChangeKind;
#[cfg(feature = "experimental")]
use rolldown_common::{
ClientHmrInput, ClientHmrUpdate, HmrLazyChunkOutput, HmrStampTable, ImportKind, Module,
};
#[cfg(feature = "experimental")]
use rolldown_error::BuildResult;
#[cfg(feature = "experimental")]
use rolldown_utils::indexmap::FxIndexMap;
#[cfg(feature = "experimental")]
use rustc_hash::FxHashMap;
#[cfg(feature = "experimental")]
use std::sync::{Arc, atomic::AtomicU32};
#[cfg(feature = "experimental")]
impl Bundler {
#[tracing::instrument(level = "debug", skip_all)]
pub async fn compute_hmr_update_for_file_changes(
&mut self,
changed_file_paths: &FxIndexMap<String, WatcherChangeKind>,
clients: &[ClientHmrInput<'_>],
stamp_table: &mut HmrStampTable,
next_hmr_patch_id: Arc<AtomicU32>,
) -> BuildResult<Vec<ClientHmrUpdate>> {
crate::utils::defer_drop::drain();
let Some(plugin_driver) = self.last_bundle_handle.as_ref().map(|ctx| &ctx.plugin_driver) else {
return Err(anyhow::format_err!(
"HMR requires to run at least one bundle before invalidation"
))?;
};
let mut hmr_stage = HmrStage::new(HmrStageInput {
fs: self.bundle_factory.fs.clone(),
options: Arc::clone(&self.bundle_factory.options),
resolver: Arc::clone(&self.bundle_factory.resolver),
plugin_driver: Arc::clone(plugin_driver),
cache: &mut self.cache,
next_hmr_patch_id,
});
hmr_stage.compute_hmr_update_for_file_changes(changed_file_paths, clients, stamp_table).await
}
pub fn compute_top_level_evaluated_modules(
&self,
stamp_table: &HmrStampTable,
) -> FxHashMap<ArcStr, u32> {
let Some(snapshot) = self.cache.snapshot() else {
return FxHashMap::default();
};
if snapshot.user_defined_entry_modules.len() != 1 {
return FxHashMap::default();
}
let modules = &snapshot.module_table.modules;
let mut evaluated = FxHashMap::default();
let mut stack: Vec<_> = snapshot.user_defined_entry_modules.iter().copied().collect();
while let Some(module_idx) = stack.pop() {
let Module::Normal(module) = &modules[module_idx] else {
continue;
};
let stable_id = module.stable_id.as_arc_str();
if evaluated.contains_key(stable_id) {
continue;
}
evaluated.insert(stable_id.clone(), stamp_table.render_time_stamp(stable_id.as_str()));
for rec in &module.import_records {
if rec.kind == ImportKind::Import
&& let Some(dep_idx) = rec.resolved_module
{
stack.push(dep_idx);
}
}
}
evaluated
}
pub async fn compile_lazy_entry(
&mut self,
module_id: String,
client_id: &str,
shipped: &FxHashMap<ArcStr, u32>,
evaluated: &FxHashMap<ArcStr, u32>,
stamp_table: &HmrStampTable,
next_hmr_patch_id: Arc<AtomicU32>,
) -> BuildResult<HmrLazyChunkOutput> {
crate::utils::defer_drop::drain();
let Some(plugin_driver) = self.last_bundle_handle.as_ref().map(|ctx| &ctx.plugin_driver) else {
panic!("Lazy compilation requires at least one bundle to be built first");
};
let mut hmr_stage = HmrStage::new(HmrStageInput {
fs: self.bundle_factory.fs.clone(),
options: Arc::clone(&self.bundle_factory.options),
resolver: Arc::clone(&self.bundle_factory.resolver),
plugin_driver: Arc::clone(plugin_driver),
cache: &mut self.cache,
next_hmr_patch_id,
});
hmr_stage.compile_lazy_entry(&module_id, client_id, shipped, evaluated, stamp_table).await
}
}