Skip to content

Commit 970baf2

Browse files
committed
perf: improve bundle splitting
1 parent d192032 commit 970baf2

File tree

6 files changed

+157
-68
lines changed

6 files changed

+157
-68
lines changed

crates/rspack_binding_api/src/raw_options/raw_split_chunks/raw_split_chunk_chunks.rs

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,23 +2,26 @@ use std::sync::Arc;
22

33
use napi::{JsString, bindgen_prelude::Either3};
44
use rspack_napi::{string::JsStringExt, threadsafe_function::ThreadsafeFunction};
5+
use rspack_plugin_split_chunks::{
6+
ChunkFilter, create_chunk_filter_from_str, create_regex_chunk_filter_from_str,
7+
};
58
use rspack_regex::RspackRegex;
69

710
use crate::chunk::ChunkWrapper;
811

912
pub type Chunks<'a> = Either3<RspackRegex, JsString<'a>, ThreadsafeFunction<ChunkWrapper, bool>>;
1013

11-
pub fn create_chunks_filter(raw: Chunks) -> rspack_plugin_split_chunks::ChunkFilter {
14+
pub fn create_chunks_filter(raw: Chunks) -> ChunkFilter {
1215
match raw {
13-
Either3::A(regex) => rspack_plugin_split_chunks::create_regex_chunk_filter_from_str(regex),
16+
Either3::A(regex) => create_regex_chunk_filter_from_str(regex),
1417
Either3::B(js_str) => {
1518
let js_str = js_str.into_string();
16-
rspack_plugin_split_chunks::create_chunk_filter_from_str(&js_str)
19+
create_chunk_filter_from_str(&js_str)
1720
}
18-
Either3::C(f) => Arc::new(move |chunk_ukey, compilation| {
21+
Either3::C(f) => ChunkFilter::Func(Arc::new(move |chunk_ukey, compilation| {
1922
let f = f.clone();
2023
let chunk_wrapper = ChunkWrapper::new(*chunk_ukey, compilation);
2124
Box::pin(async move { f.call_with_sync(chunk_wrapper).await })
22-
}),
25+
})),
2326
}
2427
}

crates/rspack_plugin_split_chunks/src/common.rs

Lines changed: 50 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,57 @@ use std::{
55

66
use derive_more::Debug;
77
use futures::future::BoxFuture;
8-
use rspack_collections::IdentifierMap;
8+
use rspack_collections::{IdentifierMap, UkeySet};
99
use rspack_core::{ChunkUkey, Compilation, Module, SourceType};
1010
use rspack_error::Result;
1111
use rspack_regex::RspackRegex;
1212
use rustc_hash::{FxHashMap, FxHashSet};
1313

14-
pub type ChunkFilter =
14+
pub type ChunkFilterFunc =
1515
Arc<dyn Fn(&ChunkUkey, &Compilation) -> BoxFuture<'static, Result<bool>> + Sync + Send>;
16+
17+
#[derive(Clone)]
18+
pub enum ChunkFilter {
19+
Func(ChunkFilterFunc),
20+
All,
21+
Regex(RspackRegex),
22+
Async,
23+
Initial,
24+
}
25+
26+
impl ChunkFilter {
27+
pub fn is_func(&self) -> bool {
28+
matches!(self, ChunkFilter::Func(_))
29+
}
30+
31+
pub async fn test_func(&self, chunk_ukey: &ChunkUkey, compilation: &Compilation) -> Result<bool> {
32+
if let ChunkFilter::Func(func) = self {
33+
func(chunk_ukey, compilation).await
34+
} else {
35+
panic!("ChunkFilter is not a function");
36+
}
37+
}
38+
39+
pub fn test_internal(&self, chunk_ukey: &ChunkUkey, compilation: &Compilation) -> bool {
40+
match self {
41+
ChunkFilter::Func(_) => panic!("ChunkFilter is a function"),
42+
ChunkFilter::All => true,
43+
ChunkFilter::Regex(re) => {
44+
let chunk = compilation.chunk_by_ukey.expect_get(chunk_ukey);
45+
chunk.name().is_some_and(|name| re.test(name))
46+
}
47+
ChunkFilter::Async => {
48+
let chunk = compilation.chunk_by_ukey.expect_get(chunk_ukey);
49+
!chunk.can_be_initial(&compilation.chunk_group_by_ukey)
50+
}
51+
ChunkFilter::Initial => {
52+
let chunk = compilation.chunk_by_ukey.expect_get(chunk_ukey);
53+
chunk.can_be_initial(&compilation.chunk_group_by_ukey)
54+
}
55+
}
56+
}
57+
}
58+
1659
pub type ModuleTypeFilter = Arc<dyn Fn(&dyn Module) -> bool + Send + Sync>;
1760
pub type ModuleLayerFilter =
1861
Arc<dyn Fn(Option<String>) -> BoxFuture<'static, Result<bool>> + Send + Sync>;
@@ -26,23 +69,15 @@ pub fn create_default_module_layer_filter() -> ModuleLayerFilter {
2669
}
2770

2871
pub fn create_async_chunk_filter() -> ChunkFilter {
29-
Arc::new(|chunk_ukey, compilation| {
30-
let chunk = compilation.chunk_by_ukey.expect_get(chunk_ukey);
31-
let can_be_initial = chunk.can_be_initial(&compilation.chunk_group_by_ukey);
32-
Box::pin(async move { Ok(!can_be_initial) })
33-
})
72+
ChunkFilter::Async
3473
}
3574

3675
pub fn create_initial_chunk_filter() -> ChunkFilter {
37-
Arc::new(|chunk_ukey, compilation| {
38-
let chunk = compilation.chunk_by_ukey.expect_get(chunk_ukey);
39-
let can_be_initial = chunk.can_be_initial(&compilation.chunk_group_by_ukey);
40-
Box::pin(async move { Ok(can_be_initial) })
41-
})
76+
ChunkFilter::Initial
4277
}
4378

4479
pub fn create_all_chunk_filter() -> ChunkFilter {
45-
Arc::new(|_chunk, _compilation| Box::pin(async move { Ok(true) }))
80+
ChunkFilter::All
4681
}
4782

4883
pub fn create_chunk_filter_from_str(chunks: &str) -> ChunkFilter {
@@ -55,11 +90,7 @@ pub fn create_chunk_filter_from_str(chunks: &str) -> ChunkFilter {
5590
}
5691

5792
pub fn create_regex_chunk_filter_from_str(re: RspackRegex) -> ChunkFilter {
58-
Arc::new(move |chunk_ukey, compilation| {
59-
let chunk = compilation.chunk_by_ukey.expect_get(chunk_ukey);
60-
let res = chunk.name().is_some_and(|name| re.test(name));
61-
Box::pin(async move { Ok(res) })
62-
})
93+
ChunkFilter::Regex(re)
6394
}
6495

6596
#[derive(Debug, Default, Clone)]
@@ -171,3 +202,4 @@ pub struct FallbackCacheGroup {
171202
}
172203

173204
pub(crate) type ModuleSizes = IdentifierMap<FxHashMap<SourceType, f64>>;
205+
pub(crate) type ModuleChunks = IdentifierMap<UkeySet<ChunkUkey>>;

crates/rspack_plugin_split_chunks/src/plugin/chunk.rs

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1-
use rspack_collections::{DatabaseItem, UkeySet};
2-
use rspack_core::{Chunk, ChunkUkey, Compilation, incremental::Mutation};
1+
use rayon::prelude::*;
2+
use rspack_collections::{DatabaseItem, IdentifierMap, UkeySet};
3+
use rspack_core::{Chunk, ChunkUkey, Compilation, ModuleIdentifier, incremental::Mutation};
34

4-
use crate::{SplitChunksPlugin, module_group::ModuleGroup};
5+
use crate::{SplitChunksPlugin, common::ModuleChunks, module_group::ModuleGroup};
56

67
fn put_split_chunk_reason(
78
chunk_reason: &mut Option<String>,
@@ -21,6 +22,16 @@ fn put_split_chunk_reason(
2122
}
2223

2324
impl SplitChunksPlugin {
25+
pub(crate) fn get_module_chunks(
26+
all_modules: &[ModuleIdentifier],
27+
compilation: &Compilation,
28+
) -> ModuleChunks {
29+
let chunk_graph = &compilation.chunk_graph;
30+
all_modules
31+
.par_iter()
32+
.map(|module| (*module, chunk_graph.get_module_chunks(*module).clone()))
33+
.collect::<IdentifierMap<_>>()
34+
}
2435
/// Affected by `splitChunks.cacheGroups.{cacheGroup}.reuseExistingChunk`
2536
///
2637
/// If there is a code splitting chunk that the contains the same modules as the current `ModuleGroup`,

crates/rspack_plugin_split_chunks/src/plugin/max_size.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -515,7 +515,11 @@ impl SplitChunksPlugin {
515515
);
516516

517517
if max_size_setting.is_none()
518-
&& !(fallback_cache_group.chunks_filter)(&chunk.ukey(), compilation).await?
518+
&& !(if fallback_cache_group.chunks_filter.is_func() {
519+
fallback_cache_group.chunks_filter.test_func(&chunk.ukey(), compilation).await?
520+
} else {
521+
fallback_cache_group.chunks_filter.test_internal(&chunk.ukey(), compilation)
522+
})
519523
{
520524
tracing::debug!("Chunk({:?}) skips `maxSize` checking. Reason: max_size_setting.is_none() and chunks_filter is false", chunk.chunk_reason());
521525
return Ok(None);

crates/rspack_plugin_split_chunks/src/plugin/mod.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,9 +54,10 @@ impl SplitChunksPlugin {
5454
.collect::<Vec<_>>();
5555

5656
let module_sizes = Self::get_module_sizes(&all_modules, compilation);
57+
let module_chunks = Self::get_module_chunks(&all_modules, compilation);
5758

5859
let mut module_group_map = self
59-
.prepare_module_group_map(&all_modules, compilation, &module_sizes)
60+
.prepare_module_group_map(&all_modules, compilation, &module_sizes, &module_chunks)
6061
.await?;
6162
tracing::trace!("prepared module_group_map {:#?}", module_group_map);
6263
logger.time_end(start);

0 commit comments

Comments
 (0)