Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: infer async modules when incremental enabled #7927

Merged
merged 6 commits into from
Sep 20, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
98 changes: 37 additions & 61 deletions crates/rspack_core/src/compiler/compilation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,14 +34,14 @@ use crate::{
get_chunk_from_ukey, get_mut_chunk_from_ukey, is_source_equal,
old_cache::{use_code_splitting_cache, Cache as OldCache, CodeSplittingCache},
to_identifier,
unaffected_cache::UnaffectedModulesCache,
unaffected_cache::{Mutation, Mutations, UnaffectedModulesCache},
BoxDependency, BoxModule, CacheCount, CacheOptions, Chunk, ChunkByUkey, ChunkContentHash,
ChunkGraph, ChunkGroupByUkey, ChunkGroupUkey, ChunkKind, ChunkUkey, CodeGenerationJob,
CodeGenerationResult, CodeGenerationResults, CompilationLogger, CompilationLogging,
CompilerOptions, DependencyId, DependencyType, Entry, EntryData, EntryOptions, EntryRuntime,
Entrypoint, ExecuteModuleId, Filename, ImportVarMap, LocalFilenameFn, Logger, Module,
ModuleFactory, ModuleGraph, ModuleGraphPartial, ModuleIdentifier, PathData, ResolverFactory,
RuntimeGlobals, RuntimeModule, RuntimeSpecMap, SharedPluginDriver, SourceType, Stats,
Entrypoint, ExecuteModuleId, Filename, ImportVarMap, LocalFilenameFn, Logger, ModuleFactory,
ModuleGraph, ModuleGraphPartial, ModuleIdentifier, PathData, ResolverFactory, RuntimeGlobals,
RuntimeModule, RuntimeSpecMap, SharedPluginDriver, SourceType, Stats,
};

pub type BuildDependency = (
Expand Down Expand Up @@ -173,6 +173,7 @@ pub struct Compilation {
pub old_cache: Arc<OldCache>,
pub code_splitting_cache: CodeSplittingCache,
pub unaffected_modules_cache: Arc<UnaffectedModulesCache>,
pub mutations: Option<Mutations>,

pub hash: Option<RspackHashDigest>,
pub used_chunk_ids: HashSet<String>,
Expand Down Expand Up @@ -227,6 +228,7 @@ impl Compilation {
modified_files: HashSet<PathBuf>,
removed_files: HashSet<PathBuf>,
) -> Self {
let mutations = options.new_incremental_enabled().then(Mutations::default);
Self {
id: CompilationId::new(),
hot_index: 0,
Expand Down Expand Up @@ -262,6 +264,7 @@ impl Compilation {
build_time_executed_modules: Default::default(),
old_cache,
unaffected_modules_cache,
mutations,
code_splitting_cache: Default::default(),
hash: None,
used_chunk_ids: Default::default(),
Expand Down Expand Up @@ -757,57 +760,30 @@ impl Compilation {
.collect::<Vec<_>>()))
}

#[instrument(name = "compilation:code_generation", skip(self))]
fn code_generation(&mut self) -> Result<()> {
#[instrument(name = "compilation:code_generation", skip_all)]
fn code_generation(&mut self, modules: IdentifierSet) -> Result<()> {
let logger = self.get_logger("rspack.Compilation");
let mut codegen_cache_counter = match self.options.cache {
CacheOptions::Disabled => None,
_ => Some(logger.cache("module code generation cache")),
};

fn run_iteration(
compilation: &mut Compilation,
cache_counter: &mut Option<CacheCount>,
filter_op: impl Fn(&(ModuleIdentifier, &Box<dyn Module>)) -> bool + Sync + Send,
) -> Result<()> {
let module_graph = compilation.get_module_graph();
let modules: IdentifierSet = if compilation.options.new_incremental_enabled() {
let affected_modules = compilation
.unaffected_modules_cache
.get_affected_modules_with_chunk_graph()
.lock()
.expect("should lock")
.clone();
affected_modules
.into_iter()
.map(|module_identifier| {
let module = module_graph
.module_by_identifier(&module_identifier)
.expect("should have module");
(module_identifier, module)
})
.filter(filter_op)
.map(|(id, _)| id)
.collect()
let module_graph = self.get_module_graph();
let mut no_codegen_dependencies_modules = IdentifierSet::default();
let mut has_codegen_dependencies_modules = IdentifierSet::default();
for module_identifier in modules {
let module = module_graph
.module_by_identifier(&module_identifier)
.expect("should have module");
if module.get_code_generation_dependencies().is_none() {
no_codegen_dependencies_modules.insert(module_identifier);
} else {
compilation
.get_module_graph()
.modules()
.into_iter()
.filter(filter_op)
.map(|(id, _)| id)
.collect()
};
compilation.code_generation_modules(cache_counter, modules)
has_codegen_dependencies_modules.insert(module_identifier);
}
}

run_iteration(self, &mut codegen_cache_counter, |(_, module)| {
module.get_code_generation_dependencies().is_none()
})?;

run_iteration(self, &mut codegen_cache_counter, |(_, module)| {
module.get_code_generation_dependencies().is_some()
})?;
self.code_generation_modules(&mut codegen_cache_counter, no_codegen_dependencies_modules)?;
self.code_generation_modules(&mut codegen_cache_counter, has_codegen_dependencies_modules)?;

if let Some(counter) = codegen_cache_counter {
logger.cache_end(counter);
Expand Down Expand Up @@ -1216,16 +1192,25 @@ impl Compilation {
.compute_affected_modules_with_chunk_graph(self);
}

self.create_module_hashes(if self.options.new_incremental_enabled() {
self
let modules = if self.options.new_incremental_enabled()
&& let Some(mutations) = &self.mutations
{
let mut modules = self
.unaffected_modules_cache
.get_affected_modules_with_chunk_graph()
.lock()
.expect("should lock")
.clone()
.clone();
modules.extend(mutations.iter().filter_map(|mutation| match mutation {
Mutation::ModuleGraphModuleSetAsync { module } => Some(module),
_ => None,
}));
modules
} else {
self.get_module_graph().modules().keys().copied().collect()
})?;
};

self.create_module_hashes(modules.clone())?;

let start = logger.time("optimize code generation");
plugin_driver
Expand All @@ -1235,22 +1220,13 @@ impl Compilation {
logger.time_end(start);

let start = logger.time("code generation");
self.code_generation()?;
self.code_generation(modules.clone())?;
logger.time_end(start);

let start = logger.time("runtime requirements");
self
.process_runtime_requirements(
if self.options.new_incremental_enabled() {
self
.unaffected_modules_cache
.get_affected_modules_with_chunk_graph()
.lock()
.expect("should lock")
.clone()
} else {
self.get_module_graph().modules().keys().copied().collect()
},
modules,
self
.chunk_by_ukey
.keys()
Expand Down
2 changes: 1 addition & 1 deletion crates/rspack_core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ mod cgm_hash_results;
mod cgm_runtime_requirement_results;
mod dependencies_block;
pub mod diagnostics;
mod unaffected_cache;
pub mod unaffected_cache;
pub use dependencies_block::{
AsyncDependenciesBlock, AsyncDependenciesBlockIdentifier, DependenciesBlock,
};
Expand Down
2 changes: 1 addition & 1 deletion crates/rspack_core/src/module.rs
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ pub struct BuildMeta {
}

// webpack build info
#[derive(Debug, Default, Clone)]
#[derive(Debug, Default)]
pub struct BuildResult {
/// Whether the result is cacheable, i.e shared between builds.
pub build_meta: BuildMeta,
Expand Down
10 changes: 7 additions & 3 deletions crates/rspack_core/src/module_graph/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -985,10 +985,14 @@ impl<'a> ModuleGraph<'a> {
.map(|mgm| mgm.is_async)
}

pub fn set_async(&mut self, module_id: &ModuleIdentifier) {
if let Some(mgm) = self.module_graph_module_by_identifier_mut(module_id) {
mgm.is_async = true
pub fn set_async(&mut self, module_id: &ModuleIdentifier, is_async: bool) -> bool {
if let Some(mgm) = self.module_graph_module_by_identifier_mut(module_id)
&& mgm.is_async != is_async
{
mgm.is_async = is_async;
return true;
}
false
}

pub fn get_outgoing_connections(
Expand Down
3 changes: 3 additions & 0 deletions crates/rspack_core/src/unaffected_cache/mod.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
mod mutations;

use std::{
hash::{BuildHasherDefault, Hash, Hasher},
sync::Mutex,
};

pub use mutations::{Mutation, Mutations};
use rayon::iter::{IntoParallelIterator, IntoParallelRefIterator, ParallelIterator};
use rspack_collections::{IdentifierDashMap, IdentifierHasher, IdentifierMap, IdentifierSet};
use rspack_util::fx_hash::FxIndexSet;
Expand Down
53 changes: 53 additions & 0 deletions crates/rspack_core/src/unaffected_cache/mutations.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
use crate::ModuleIdentifier;

#[derive(Debug, Default)]
pub struct Mutations {
inner: Vec<Mutation>,
}

#[derive(Debug)]
pub enum Mutation {
ModuleGraphModuleSetAsync { module: ModuleIdentifier },
PlaceholderForExtendable,
}

impl Mutations {
pub fn add(&mut self, mutation: Mutation) {
self.inner.push(mutation);
}
}

impl Mutations {
pub fn iter(&self) -> std::slice::Iter<Mutation> {
self.inner.iter()
}
}

pub struct IntoIter {
inner: std::vec::IntoIter<Mutation>,
}

impl Iterator for IntoIter {
type Item = Mutation;

fn next(&mut self) -> Option<Self::Item> {
self.inner.next()
}
}

impl IntoIterator for Mutations {
type Item = Mutation;
type IntoIter = IntoIter;

fn into_iter(self) -> Self::IntoIter {
IntoIter {
inner: self.inner.into_iter(),
}
}
}

impl Extend<Mutation> for Mutations {
fn extend<T: IntoIterator<Item = Mutation>>(&mut self, iter: T) {
self.inner.extend(iter);
}
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
use std::collections::HashSet;

use linked_hash_set::LinkedHashSet;
use rspack_collections::Identifier;
use rspack_collections::IdentifierSet;
use rspack_core::{
ApplyContext, Compilation, CompilationFinishModules, CompilerOptions, DependencyType, Plugin,
PluginContext,
unaffected_cache::{Mutation, Mutations},
ApplyContext, Compilation, CompilationFinishModules, CompilerOptions, DependencyType,
ModuleIdentifier, Plugin, PluginContext,
};
use rspack_error::Result;
use rspack_hook::{plugin, plugin_hook};
Expand All @@ -15,30 +14,64 @@ pub struct InferAsyncModulesPlugin;

#[plugin_hook(CompilationFinishModules for InferAsyncModulesPlugin)]
async fn finish_modules(&self, compilation: &mut Compilation) -> Result<()> {
// fix: mut for-in
let mut queue = LinkedHashSet::new();
let mut uniques = HashSet::new();
let module_graph = compilation.get_module_graph();
let modules: IdentifierSet = if compilation.options.new_incremental_enabled() {
compilation
.unaffected_modules_cache
.get_affected_modules_with_module_graph()
.lock()
.expect("should lock")
.clone()
} else {
module_graph.modules().keys().copied().collect()
};

let mut sync_modules = LinkedHashSet::new();
let mut async_modules = LinkedHashSet::new();
for module_identifier in modules {
let module = module_graph
.module_by_identifier(&module_identifier)
.expect("should have module");
let build_meta = module.build_meta().expect("should have build meta");
if build_meta.has_top_level_await {
async_modules.insert(module_identifier);
} else {
sync_modules.insert(module_identifier);
}
}

let mut modules: Vec<Identifier> = compilation
.get_module_graph()
.modules()
.values()
.filter(|m| {
if let Some(meta) = &m.build_meta() {
meta.has_top_level_await
} else {
false
}
})
.map(|m| m.identifier())
.collect();
let mut mutations = compilation
.options
.new_incremental_enabled()
.then(Mutations::default);

modules.retain(|m| queue.insert(*m));
set_async_modules(compilation, sync_modules, false, &mut mutations);
set_async_modules(compilation, async_modules, true, &mut mutations);

if let Some(compilation_mutations) = &mut compilation.mutations
&& let Some(mutations) = mutations
{
compilation_mutations.extend(mutations);
}

Ok(())
}

fn set_async_modules(
compilation: &mut Compilation,
modules: LinkedHashSet<ModuleIdentifier>,
is_async: bool,
mutations: &mut Option<Mutations>,
) {
let mut uniques = IdentifierSet::from_iter(modules.iter().copied());
let mut queue = modules;
let mut module_graph = compilation.get_module_graph_mut();

while let Some(module) = queue.pop_front() {
module_graph.set_async(&module);
let changed = module_graph.set_async(&module, is_async);
if changed && let Some(mutations) = mutations {
mutations.add(Mutation::ModuleGraphModuleSetAsync { module });
}
module_graph
.get_incoming_connections(&module)
.iter()
Expand All @@ -60,7 +93,6 @@ async fn finish_modules(&self, compilation: &mut Compilation) -> Result<()> {
}
});
}
Ok(())
}

impl Plugin for InferAsyncModulesPlugin {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
import "./b"
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export const b = 1;
globalThis.b = b;
Loading
Loading