Skip to content

Commit 01374bb

Browse files
authored
fix: has async chunks (#9263)
1 parent 8b066ad commit 01374bb

File tree

5 files changed

+110
-1
lines changed

5 files changed

+110
-1
lines changed

crates/rspack_core/src/chunk.rs

Lines changed: 74 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -488,7 +488,80 @@ impl Chunk {
488488
}
489489

490490
pub fn has_async_chunks(&self, chunk_group_by_ukey: &ChunkGroupByUkey) -> bool {
491-
!self.get_all_async_chunks(chunk_group_by_ukey).is_empty()
491+
// The reason why we don't just return !self.get_all_async_chunks(chunk_group_by_ukey).is_empty() here is
492+
// get_all_async_chunks will check the whether the chunk is inside Entrypoint, which cause the chunk not return
493+
// as a async chunk, but has_async_chunks is used to check whether need to add the chunk loading runtime, which
494+
// is about loading the async chunks, so even the chunk is inside Entrypoint but loading it indeed need the
495+
// chunk loading runtime.
496+
// For a real case checkout the test: `rspack-test-tools/configCases/chunk-loading/depend-on-with-chunk-load`
497+
let mut queue = UkeyIndexSet::default();
498+
499+
let initial_chunks = self
500+
.groups
501+
.iter()
502+
.map(|chunk_group| chunk_group_by_ukey.expect_get(chunk_group))
503+
.map(|group| group.chunks.iter().copied().collect::<UkeySet<_>>())
504+
.reduce(|acc, prev| acc.intersection(&prev).copied().collect::<UkeySet<_>>())
505+
.unwrap_or_default();
506+
507+
let mut visit_chunk_groups = UkeySet::default();
508+
509+
for chunk_group_ukey in self.get_sorted_groups_iter(chunk_group_by_ukey) {
510+
if let Some(chunk_group) = chunk_group_by_ukey.get(chunk_group_ukey) {
511+
for child_ukey in chunk_group
512+
.children
513+
.iter()
514+
.sorted_by(|a, b| sort_group_by_index(a, b, chunk_group_by_ukey))
515+
{
516+
if let Some(chunk_group) = chunk_group_by_ukey.get(child_ukey) {
517+
queue.insert(chunk_group.ukey);
518+
}
519+
}
520+
}
521+
}
522+
523+
fn check_chunks(
524+
chunk_group_by_ukey: &ChunkGroupByUkey,
525+
initial_chunks: &UkeySet<ChunkUkey>,
526+
chunk_group_ukey: &ChunkGroupUkey,
527+
visit_chunk_groups: &mut UkeySet<ChunkGroupUkey>,
528+
) -> bool {
529+
let Some(chunk_group) = chunk_group_by_ukey.get(chunk_group_ukey) else {
530+
return false;
531+
};
532+
for chunk_ukey in chunk_group.chunks.iter() {
533+
if !initial_chunks.contains(chunk_ukey) {
534+
return true;
535+
}
536+
}
537+
for group_ukey in chunk_group.children.iter() {
538+
if !visit_chunk_groups.contains(group_ukey) {
539+
visit_chunk_groups.insert(*group_ukey);
540+
if check_chunks(
541+
chunk_group_by_ukey,
542+
initial_chunks,
543+
group_ukey,
544+
visit_chunk_groups,
545+
) {
546+
return true;
547+
}
548+
}
549+
}
550+
false
551+
}
552+
553+
for group_ukey in queue.iter() {
554+
if check_chunks(
555+
chunk_group_by_ukey,
556+
&initial_chunks,
557+
group_ukey,
558+
&mut visit_chunk_groups,
559+
) {
560+
return true;
561+
}
562+
}
563+
564+
false
492565
}
493566

494567
pub fn get_all_async_chunks(
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
it("should have runtime __webpack_require__.f.j", async () => {
2+
// Don't really call it, it will cause error in runtime
3+
() => {
4+
__webpack_chunk_load__("main");
5+
};
6+
const path = __non_webpack_require__("path");
7+
const fs = __non_webpack_require__("fs");
8+
const code = await fs.promises.readFile(path.resolve(__dirname, "runtime.js"), "utf-8");
9+
expect(code.includes("__webpack_require__.f.j")).toBe(true);
10+
})

packages/rspack-test-tools/tests/configCases/chunk-loading/depend-on-with-chunk-load/polyfill.js

Whitespace-only changes.
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
/** @type {import("@rspack/core").Configuration} */
2+
module.exports = {
3+
entry: {
4+
polyfill: "./polyfill.js",
5+
main: {
6+
dependOn: "polyfill",
7+
import: "./index.js",
8+
},
9+
},
10+
output: {
11+
filename: "[name].js",
12+
},
13+
target: "web",
14+
optimization: {
15+
runtimeChunk: { name: "runtime" },
16+
},
17+
node: {
18+
__dirname: false,
19+
}
20+
};
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
/** @type {import("../../../..").TConfigCaseConfig} */
2+
module.exports = {
3+
findBundle() {
4+
return ["runtime.js", "polyfill.js", "main.js"];
5+
}
6+
};

0 commit comments

Comments
 (0)