Skip to content

Commit 9b0a248

Browse files
authored
feat(incremental): named chunk ids (#8652)
1 parent f8c0056 commit 9b0a248

File tree

65 files changed

+775
-448
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

65 files changed

+775
-448
lines changed

crates/rspack_binding_values/src/chunk.rs

+10-5
Original file line numberDiff line numberDiff line change
@@ -40,17 +40,22 @@ impl JsChunk {
4040

4141
#[napi(getter)]
4242
pub fn id(&self) -> napi::Result<Either<&str, ()>> {
43-
let (_, chunk) = self.as_ref()?;
44-
Ok(match chunk.id() {
45-
Some(id) => Either::A(id),
43+
let (compilation, chunk) = self.as_ref()?;
44+
Ok(match chunk.id(&compilation.chunk_ids) {
45+
Some(id) => Either::A(id.as_str()),
4646
None => Either::B(()),
4747
})
4848
}
4949

5050
#[napi(getter)]
5151
pub fn ids(&self) -> napi::Result<Vec<&str>> {
52-
let (_, chunk) = self.as_ref()?;
53-
Ok(chunk.id().map(|id| vec![id]).unwrap_or_default())
52+
let (compilation, chunk) = self.as_ref()?;
53+
Ok(
54+
chunk
55+
.id(&compilation.chunk_ids)
56+
.map(|id| vec![id.as_str()])
57+
.unwrap_or_default(),
58+
)
5459
}
5560

5661
#[napi(getter)]

crates/rspack_core/src/chunk.rs

+34-23
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use rspack_error::Diagnostic;
99
use rspack_hash::{RspackHash, RspackHashDigest};
1010
use rustc_hash::{FxHashMap as HashMap, FxHashSet as HashSet, FxHasher};
1111

12+
use crate::chunk_graph_chunk::ChunkId;
1213
use crate::{
1314
compare_chunk_group, merge_runtime, sort_group_by_index, ChunkGraph, ChunkGroupOrderKey,
1415
RenderManifestEntry,
@@ -58,7 +59,6 @@ pub struct Chunk {
5859
// - The name of chunks create by dynamic import is `None` unless users use
5960
// magic comment like `import(/* webpackChunkName: "someChunk" * / './someModule.js')` to specify it.
6061
name: Option<String>,
61-
id: Option<String>,
6262
id_name_hints: HashSet<String>,
6363
filename_template: Option<Filename>,
6464
css_filename_template: Option<Filename>,
@@ -108,12 +108,23 @@ impl Chunk {
108108
self.css_filename_template = filename_template;
109109
}
110110

111-
pub fn id(&self) -> Option<&str> {
112-
self.id.as_deref()
111+
pub fn id<'a>(&self, chunk_ids: &'a UkeyMap<ChunkUkey, ChunkId>) -> Option<&'a ChunkId> {
112+
ChunkGraph::get_chunk_id(chunk_ids, &self.ukey)
113113
}
114114

115-
pub fn set_id(&mut self, id: Option<String>) {
116-
self.id = id;
115+
pub fn expect_id<'a>(&self, chunk_ids: &'a UkeyMap<ChunkUkey, ChunkId>) -> &'a ChunkId {
116+
self
117+
.id(chunk_ids)
118+
.expect("Should set id before calling expect_id")
119+
}
120+
121+
pub fn set_id(
122+
&self,
123+
chunk_ids: &mut UkeyMap<ChunkUkey, ChunkId>,
124+
id: impl Into<ChunkId>,
125+
) -> bool {
126+
let id = id.into();
127+
ChunkGraph::set_chunk_id(chunk_ids, self.ukey, id)
117128
}
118129

119130
pub fn prevent_integration(&self) -> bool {
@@ -263,7 +274,6 @@ impl Chunk {
263274
filename_template: None,
264275
css_filename_template: None,
265276
ukey: ChunkUkey::new(),
266-
id: None,
267277
id_name_hints: Default::default(),
268278
prevent_integration: false,
269279
files: Default::default(),
@@ -578,18 +588,14 @@ impl Chunk {
578588
chunks
579589
}
580590

581-
pub fn expect_id(&self) -> &str {
582-
self
583-
.id
584-
.as_ref()
585-
.expect("Should set id before calling expect_id")
586-
}
587-
588-
pub fn name_for_filename_template(&self) -> Option<&str> {
591+
pub fn name_for_filename_template<'a>(
592+
&'a self,
593+
chunk_ids: &'a UkeyMap<ChunkUkey, ChunkId>,
594+
) -> Option<&'a str> {
589595
if self.name.is_some() {
590596
self.name.as_deref()
591597
} else {
592-
self.id.as_deref()
598+
self.id(chunk_ids).map(|id| id.as_str())
593599
}
594600
}
595601

@@ -602,7 +608,7 @@ impl Chunk {
602608
}
603609

604610
pub fn update_hash(&self, hasher: &mut RspackHash, compilation: &Compilation) {
605-
self.id.hash(hasher);
611+
self.id(&compilation.chunk_ids).hash(hasher);
606612
for module in compilation
607613
.chunk_graph
608614
.get_ordered_chunk_modules(&self.ukey, &compilation.get_module_graph())
@@ -716,16 +722,20 @@ impl Chunk {
716722
&self,
717723
order: &ChunkGroupOrderKey,
718724
compilation: &Compilation,
719-
) -> Option<Vec<String>> {
725+
) -> Option<Vec<ChunkId>> {
720726
self
721727
.get_children_of_type_in_order(order, compilation, true)
722728
.map(|order_children| {
723729
order_children
724730
.iter()
725731
.flat_map(|(_, child_chunks)| {
726-
child_chunks
727-
.iter()
728-
.filter_map(|chunk_ukey| compilation.chunk_by_ukey.expect_get(chunk_ukey).id.clone())
732+
child_chunks.iter().filter_map(|chunk_ukey| {
733+
compilation
734+
.chunk_by_ukey
735+
.expect_get(chunk_ukey)
736+
.id(&compilation.chunk_ids)
737+
.cloned()
738+
})
729739
})
730740
.collect_vec()
731741
})
@@ -735,21 +745,22 @@ impl Chunk {
735745
&self,
736746
include_direct_children: bool,
737747
compilation: &Compilation,
738-
) -> HashMap<ChunkGroupOrderKey, IndexMap<String, Vec<String>, BuildHasherDefault<FxHasher>>> {
748+
) -> HashMap<ChunkGroupOrderKey, IndexMap<ChunkId, Vec<ChunkId>, BuildHasherDefault<FxHasher>>>
749+
{
739750
let mut result = HashMap::default();
740751

741752
fn add_child_ids_by_orders_to_map(
742753
chunk_ukey: &ChunkUkey,
743754
order: &ChunkGroupOrderKey,
744755
result: &mut HashMap<
745756
ChunkGroupOrderKey,
746-
IndexMap<String, Vec<String>, BuildHasherDefault<FxHasher>>,
757+
IndexMap<ChunkId, Vec<ChunkId>, BuildHasherDefault<FxHasher>>,
747758
>,
748759
compilation: &Compilation,
749760
) {
750761
let chunk = compilation.chunk_by_ukey.expect_get(chunk_ukey);
751762
if let (Some(chunk_id), Some(child_chunk_ids)) = (
752-
chunk.id.clone(),
763+
chunk.id(&compilation.chunk_ids).cloned(),
753764
chunk.get_child_ids_by_order(order, compilation),
754765
) {
755766
result

crates/rspack_core/src/chunk_graph/chunk_graph_chunk.rs

+77-2
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,18 @@
11
//! There are methods whose verb is `ChunkGraphChunk`
22
3+
use std::borrow::Borrow;
4+
use std::fmt;
5+
use std::sync::Arc;
6+
37
use hashlink::LinkedHashMap;
48
use indexmap::IndexSet;
59
use itertools::Itertools;
6-
use rspack_collections::{DatabaseItem, IdentifierLinkedMap, IdentifierMap, IdentifierSet};
10+
use rspack_cacheable::cacheable;
11+
use rspack_collections::{
12+
DatabaseItem, IdentifierLinkedMap, IdentifierMap, IdentifierSet, UkeyMap,
13+
};
714
use rustc_hash::{FxHashMap as HashMap, FxHashSet};
15+
use serde::{Serialize, Serializer};
816

917
use crate::{
1018
find_graph_roots, merge_runtime, BoxModule, Chunk, ChunkByUkey, ChunkGraphModule,
@@ -21,6 +29,51 @@ pub struct ChunkSizeOptions {
2129
pub entry_chunk_multiplicator: Option<f64>,
2230
}
2331

32+
#[cacheable]
33+
#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
34+
pub struct ChunkId {
35+
inner: Arc<str>,
36+
}
37+
38+
impl From<String> for ChunkId {
39+
fn from(s: String) -> Self {
40+
Self { inner: s.into() }
41+
}
42+
}
43+
44+
impl From<&str> for ChunkId {
45+
fn from(s: &str) -> Self {
46+
Self { inner: s.into() }
47+
}
48+
}
49+
50+
impl fmt::Display for ChunkId {
51+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
52+
write!(f, "{}", self.as_str())
53+
}
54+
}
55+
56+
impl Serialize for ChunkId {
57+
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
58+
where
59+
S: Serializer,
60+
{
61+
serializer.serialize_str(self.as_str())
62+
}
63+
}
64+
65+
impl Borrow<str> for ChunkId {
66+
fn borrow(&self) -> &str {
67+
self.as_str()
68+
}
69+
}
70+
71+
impl ChunkId {
72+
pub fn as_str(&self) -> &str {
73+
&self.inner
74+
}
75+
}
76+
2477
#[derive(Debug, Clone, Default)]
2578
pub struct ChunkGraphChunk {
2679
/// URI of modules => ChunkGroupUkey
@@ -550,7 +603,10 @@ impl ChunkGraph {
550603
.iter()
551604
{
552605
let chunk = compilation.chunk_by_ukey.expect_get(c);
553-
map.insert(chunk.expect_id().to_string(), filter(c, compilation));
606+
map.insert(
607+
chunk.expect_id(&compilation.chunk_ids).to_string(),
608+
filter(c, compilation),
609+
);
554610
}
555611

556612
map
@@ -912,4 +968,23 @@ impl ChunkGraph {
912968
})
913969
.unwrap_or(module.source_types().iter().copied().collect())
914970
}
971+
972+
pub fn get_chunk_id<'a>(
973+
chunk_ids: &'a UkeyMap<ChunkUkey, ChunkId>,
974+
chunk_ukey: &ChunkUkey,
975+
) -> Option<&'a ChunkId> {
976+
chunk_ids.get(chunk_ukey)
977+
}
978+
979+
pub fn set_chunk_id(
980+
chunk_ids: &mut UkeyMap<ChunkUkey, ChunkId>,
981+
chunk_ukey: ChunkUkey,
982+
id: ChunkId,
983+
) -> bool {
984+
if let Some(old_id) = chunk_ids.insert(chunk_ukey, id.clone()) {
985+
old_id != id
986+
} else {
987+
true
988+
}
989+
}
915990
}

crates/rspack_core/src/chunk_group.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -265,7 +265,7 @@ impl ChunkGroup {
265265
compilation
266266
.chunk_by_ukey
267267
.get(chunk)
268-
.and_then(|item| item.id())
268+
.and_then(|item| item.id(&compilation.chunk_ids))
269269
})
270270
.join("+")
271271
}

crates/rspack_core/src/compiler/compilation.rs

+16-5
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ use crate::{
3434
cache::Cache,
3535
cgm_hash_results::CgmHashResults,
3636
cgm_runtime_requirement_results::CgmRuntimeRequirementsResults,
37+
chunk_graph_chunk::ChunkId,
3738
chunk_graph_module::ModuleId,
3839
get_runtime_key,
3940
incremental::{Incremental, IncrementalPasses, Mutation},
@@ -181,6 +182,8 @@ pub struct Compilation {
181182
pub dependencies_diagnostics: IdentifierMap<Vec<Diagnostic>>,
182183
// artifact for module_ids
183184
pub module_ids: IdentifierMap<ModuleId>,
185+
// artifact for chunk_ids
186+
pub chunk_ids: UkeyMap<ChunkUkey, ChunkId>,
184187
// artifact for code_generation
185188
pub code_generation_results: CodeGenerationResults,
186189
// artifact for create_module_hashes
@@ -201,7 +204,6 @@ pub struct Compilation {
201204
pub incremental: Incremental,
202205

203206
pub hash: Option<RspackHashDigest>,
204-
pub used_chunk_ids: HashSet<String>,
205207

206208
pub file_dependencies: IndexSet<ArcPath, BuildHasherDefault<FxHasher>>,
207209
pub context_dependencies: IndexSet<ArcPath, BuildHasherDefault<FxHasher>>,
@@ -289,6 +291,7 @@ impl Compilation {
289291
async_modules: Default::default(),
290292
dependencies_diagnostics: Default::default(),
291293
module_ids: Default::default(),
294+
chunk_ids: Default::default(),
292295
code_generation_results: Default::default(),
293296
cgm_hash_results: Default::default(),
294297
cgm_runtime_requirements_results: Default::default(),
@@ -301,8 +304,8 @@ impl Compilation {
301304
old_cache,
302305
incremental,
303306
code_splitting_cache: Default::default(),
307+
304308
hash: None,
305-
used_chunk_ids: Default::default(),
306309

307310
file_dependencies: Default::default(),
308311
context_dependencies: Default::default(),
@@ -1502,6 +1505,7 @@ impl Compilation {
15021505
entrypoint_ukey: &ChunkGroupUkey,
15031506
chunk_group_by_ukey: &ChunkGroupByUkey,
15041507
chunk_by_ukey: &ChunkByUkey,
1508+
chunk_ids: &UkeyMap<ChunkUkey, ChunkId>,
15051509
chunk_graph: &mut ChunkGraph,
15061510
) {
15071511
let entrypoint = chunk_group_by_ukey.expect_get(entrypoint_ukey);
@@ -1517,14 +1521,15 @@ impl Compilation {
15171521
runtime,
15181522
chunk_by_ukey.get(&entrypoint.get_runtime_chunk(chunk_group_by_ukey)),
15191523
) {
1520-
chunk_graph.set_runtime_id(runtime, chunk.id().map(ToOwned::to_owned));
1524+
chunk_graph.set_runtime_id(runtime, chunk.id(chunk_ids).map(|id| id.to_string()));
15211525
}
15221526
}
15231527
for i in self.entrypoints.iter() {
15241528
process_entrypoint(
15251529
i.1,
15261530
&self.chunk_group_by_ukey,
15271531
&self.chunk_by_ukey,
1532+
&self.chunk_ids,
15281533
&mut self.chunk_graph,
15291534
)
15301535
}
@@ -1533,6 +1538,7 @@ impl Compilation {
15331538
i,
15341539
&self.chunk_group_by_ukey,
15351540
&self.chunk_by_ukey,
1541+
&self.chunk_ids,
15361542
&mut self.chunk_graph,
15371543
)
15381544
}
@@ -1862,11 +1868,16 @@ impl Compilation {
18621868
.filter(|(_, (_, remaining))| *remaining != 0)
18631869
.map(|(chunk_ukey, _)| self.chunk_by_ukey.expect_get(chunk_ukey))
18641870
.collect();
1865-
circular.sort_unstable_by(|a, b| a.id().cmp(&b.id()));
1871+
circular.sort_unstable_by(|a, b| a.id(&self.chunk_ids).cmp(&b.id(&self.chunk_ids)));
18661872
runtime_chunks.extend(circular.iter().map(|chunk| chunk.ukey()));
18671873
let circular_names = circular
18681874
.iter()
1869-
.map(|chunk| chunk.name().or(chunk.id()).unwrap_or("no id chunk"))
1875+
.map(|chunk| {
1876+
chunk
1877+
.name()
1878+
.or(chunk.id(&self.chunk_ids).map(|id| id.as_str()))
1879+
.unwrap_or("no id chunk")
1880+
})
18701881
.join(", ");
18711882
self.push_diagnostic(diagnostic!(severity = Severity::Warn, "Circular dependency between chunks with runtime ({})\nThis prevents using hashes of each other and should be avoided.", circular_names).boxed().into());
18721883
}

0 commit comments

Comments
 (0)