use async_trait::async_trait;
use super::*;
use crate::{cache::Cache, compilation::pass::PassExt, logger::Logger};
pub struct CreateModuleHashesPass;
#[async_trait]
impl PassExt for CreateModuleHashesPass {
fn name(&self) -> &'static str {
"create module hashes"
}
async fn before_pass(&self, compilation: &mut Compilation, cache: &mut dyn Cache) {
cache.before_modules_hashes(compilation).await;
}
async fn run_pass(&self, compilation: &mut Compilation) -> Result<()> {
create_module_hashes_pass_impl(compilation).await
}
async fn after_pass(&self, compilation: &mut Compilation, cache: &mut dyn Cache) {
cache.after_modules_hashes(compilation).await;
}
}
async fn create_module_hashes_pass_impl(compilation: &mut Compilation) -> Result<()> {
if !compilation
.incremental
.passes_enabled(IncrementalPasses::MODULES_HASHES)
{
compilation.cgm_hash_artifact.clear();
}
let create_module_hashes_modules = if let Some(mutations) = compilation
.incremental
.mutations_read(IncrementalPasses::MODULES_HASHES)
&& !compilation.cgm_hash_artifact.is_empty()
{
let revoked_modules = mutations.iter().filter_map(|mutation| match mutation {
Mutation::ModuleRemove { module } => Some(*module),
_ => None,
});
for revoked_module in revoked_modules {
compilation.cgm_hash_artifact.remove(&revoked_module);
}
let mut modules = mutations.get_affected_modules_with_chunk_graph(compilation);
let mg = compilation.get_module_graph();
for mi in mg.modules_keys() {
let module_runtimes = compilation
.build_chunk_graph_artifact
.chunk_graph
.get_module_runtimes(*mi, &compilation.build_chunk_graph_artifact.chunk_by_ukey);
let module_runtime_keys = module_runtimes
.values()
.map(get_runtime_key)
.collect::<HashSet<_>>();
if let Some(runtime_map) = compilation.cgm_hash_artifact.get_runtime_map(mi) {
if module_runtimes.is_empty() {
continue;
}
if module_runtimes.len() == 1 {
if !matches!(runtime_map.mode, RuntimeMode::SingleEntry)
|| runtime_map
.single_runtime
.as_ref()
.expect("should have single runtime for single entry")
!= module_runtimes
.values()
.next()
.expect("should have at least one runtime")
{
modules.insert(*mi);
}
} else {
if matches!(runtime_map.mode, RuntimeMode::SingleEntry) {
modules.insert(*mi);
continue;
}
if runtime_map.map.len() != module_runtimes.len() {
modules.insert(*mi);
continue;
}
for runtime_key in runtime_map.map.keys() {
if !module_runtime_keys.contains(runtime_key) {
modules.insert(*mi);
break;
}
}
}
}
}
tracing::debug!(target: incremental::TRACING_TARGET, passes = %IncrementalPasses::MODULES_HASHES, %mutations, ?modules);
let logger = compilation.get_logger("rspack.incremental.modulesHashes");
logger.log(format!(
"{} modules are affected, {} in total",
modules.len(),
mg.modules_len()
));
modules
} else {
compilation
.get_module_graph()
.modules_keys()
.copied()
.collect()
};
create_module_hashes(compilation, create_module_hashes_modules).await
}
#[instrument("Compilation:create_module_hashes", skip_all)]
pub async fn create_module_hashes(
compilation: &mut Compilation,
modules: IdentifierSet,
) -> Result<()> {
let mg = compilation.get_module_graph();
let chunk_graph = &compilation.build_chunk_graph_artifact.chunk_graph;
let chunk_by_ukey = &compilation.build_chunk_graph_artifact.chunk_by_ukey;
let compilation_ref = &*compilation;
let results = rspack_parallel::scope::<_, Result<_>>(|token| {
for module_identifier in modules {
let s = unsafe { token.used((compilation_ref, &mg, chunk_graph, chunk_by_ukey)) };
s.spawn(
move |(compilation, mg, chunk_graph, chunk_by_ukey)| async move {
let mut hashes = RuntimeSpecMap::new();
let module = mg
.module_by_identifier(&module_identifier)
.expect("should have module");
for runtime in chunk_graph.get_module_runtimes_iter(module_identifier, chunk_by_ukey) {
let hash = module.get_runtime_hash(compilation, Some(runtime)).await?;
hashes.set(runtime.clone(), hash);
}
Ok((module_identifier, hashes))
},
);
}
})
.await
.into_iter()
.map(|r| r.to_rspack_result())
.collect::<Result<Vec<_>>>()?;
for result in results {
let (module, hashes) = result?;
if ChunkGraph::set_module_hashes(compilation, module, hashes)
&& let Some(mut mutations) = compilation.incremental.mutations_write()
{
mutations.add(Mutation::ModuleSetHashes { module });
}
}
Ok(())
}