Skip to content

Commit

Permalink
fix recursion cycle when having a cycle of dynamic imports (vercel/tu…
Browse files Browse the repository at this point in the history
…rborepo#7941)

### Description

<!--
  ✍️ Write a short summary of your work.
  If necessary, include relevant screenshots.
-->

### Testing Instructions

<!--
  Give a quick description of steps to test your changes.
-->


Closes PACK-2938
  • Loading branch information
sokra authored Apr 11, 2024
1 parent f2ed753 commit 8c1451d
Show file tree
Hide file tree
Showing 4 changed files with 34 additions and 6 deletions.
21 changes: 15 additions & 6 deletions crates/turbopack-core/src/chunk/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,7 @@ enum ChunkContentGraphNode {
},
// Async module that is referenced from the chunk group
AsyncModule {
item: Vc<Box<dyn ChunkItem>>,
module: Vc<Box<dyn ChunkableModule>>,
},
// ModuleReferences that are not placed in the current chunk group
Expand Down Expand Up @@ -275,7 +276,9 @@ async fn graph_node_to_referenced_nodes_with_available_chunk_items(
let edges = graph_node_to_referenced_nodes(node, chunking_context);
let edges_ref = edges.await?;
for (unchanged, edge) in edges_ref.iter().enumerate() {
if let ChunkContentGraphNode::ChunkItem { item, .. } = edge.node {
if let ChunkContentGraphNode::ChunkItem { item, .. }
| ChunkContentGraphNode::AsyncModule { item, .. } = edge.node
{
if let Some(info) = *available_chunk_items.get(item).await? {
let mut new_edges = Vec::with_capacity(edges_ref.len());
new_edges.extend(edges_ref[0..unchanged].iter().cloned());
Expand All @@ -289,6 +292,11 @@ async fn graph_node_to_referenced_nodes_with_available_chunk_items(
continue;
}
}
ChunkContentGraphNode::AsyncModule { item, module: _ } => {
if available_chunk_items.get(item).await?.is_some() {
continue;
}
}
ChunkContentGraphNode::InheritAsyncInfo {
item,
ref references,
Expand Down Expand Up @@ -442,11 +450,11 @@ async fn graph_node_to_referenced_nodes(
ChunkingType::Async => {
let chunk_loading =
chunking_context.environment().chunk_loading().await?;
let chunk_item = chunkable_module
.as_chunk_item(chunking_context)
.resolve()
.await?;
if matches!(*chunk_loading, ChunkLoading::None) {
let chunk_item = chunkable_module
.as_chunk_item(chunking_context)
.resolve()
.await?;
Ok((
Some(ChunkGraphEdge {
key: Some(module),
Expand All @@ -462,6 +470,7 @@ async fn graph_node_to_referenced_nodes(
Some(ChunkGraphEdge {
key: None,
node: ChunkContentGraphNode::AsyncModule {
item: chunk_item,
module: chunkable_module,
},
}),
Expand Down Expand Up @@ -639,7 +648,7 @@ async fn chunk_content_internal_parallel(
ChunkContentGraphNode::ChunkItem { item, .. } => {
chunk_items.insert(item);
}
ChunkContentGraphNode::AsyncModule { module } => {
ChunkContentGraphNode::AsyncModule { module, .. } => {
let module = module.resolve().await?;
async_modules.insert(module);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export function test() {
return import("./b.js");
}

export const ok = "a";
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export function test() {
return import("./a.js");
}

export const ok = "b";
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
it("should not crash on dynamic import cycle", async () => {
const a1 = await import("./a.js");
expect(a1.ok).toBe("a");
const b1 = await a1.test();
expect(b1.ok).toBe("b");
const a2 = await b1.test();
expect(a2.ok).toBe("a");
expect(a2).toBe(a1);
});

0 comments on commit 8c1451d

Please sign in to comment.