Skip to content

Commit 6256796

Browse files
authored
fix: dynamic entry panic when disable build cache (#12696)
1 parent d02192f commit 6256796

File tree

8 files changed

+105
-38
lines changed

8 files changed

+105
-38
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/rspack_plugin_dynamic_entry/Cargo.toml

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,14 @@ version.workspace = true
88
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
99

1010
[dependencies]
11-
derive_more = { workspace = true, features = ["debug"] }
12-
futures = { workspace = true }
13-
rspack_core = { workspace = true }
14-
rspack_error = { workspace = true }
15-
rspack_hook = { workspace = true }
16-
rspack_util = { workspace = true }
17-
tracing = { workspace = true }
11+
atomic_refcell = { workspace = true }
12+
derive_more = { workspace = true, features = ["debug"] }
13+
futures = { workspace = true }
14+
rspack_core = { workspace = true }
15+
rspack_error = { workspace = true }
16+
rspack_hook = { workspace = true }
17+
rspack_util = { workspace = true }
18+
tracing = { workspace = true }
1819

1920
[package.metadata.cargo-shear]
2021
ignored = ["tracing"]

crates/rspack_plugin_dynamic_entry/src/lib.rs

Lines changed: 52 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
use std::sync::Arc;
22

3+
use atomic_refcell::AtomicRefCell;
34
use derive_more::Debug;
4-
use futures::{future::BoxFuture, lock::Mutex};
5+
use futures::future::BoxFuture;
56
use rspack_core::{
67
BoxDependency, Compilation, CompilationParams, CompilerCompilation, CompilerMake, Context,
78
DependencyId, DependencyType, EntryDependency, EntryOptions, Plugin,
9+
incremental::IncrementalPasses, internal,
810
};
911
use rspack_error::Result;
1012
use rspack_hook::{plugin, plugin_hook};
@@ -31,7 +33,7 @@ pub struct DynamicEntryPlugin {
3133
entry: EntryDynamic,
3234
// Need "cache" the dependency to tell incremental that this entry dependency is not changed
3335
// so it can be reused and skip the module make
34-
imported_dependencies: Mutex<FxHashMap<Arc<str>, FxHashMap<EntryOptions, DependencyId>>>,
36+
imported_dependencies: AtomicRefCell<FxHashMap<Arc<str>, FxHashMap<EntryOptions, DependencyId>>>,
3537
}
3638

3739
impl DynamicEntryPlugin {
@@ -55,45 +57,64 @@ async fn make(&self, compilation: &mut Compilation) -> Result<()> {
5557
let entry_fn = &self.entry;
5658
let decs = entry_fn().await?;
5759

58-
let mut imported_dependencies = self.imported_dependencies.lock().await;
59-
let mut next_imported_dependencies: FxHashMap<Arc<str>, FxHashMap<EntryOptions, DependencyId>> =
60-
Default::default();
60+
if compilation
61+
.incremental
62+
.mutations_readable(IncrementalPasses::MAKE)
63+
{
64+
let mut imported_dependencies = self.imported_dependencies.borrow_mut();
65+
let mut next_imported_dependencies: FxHashMap<Arc<str>, FxHashMap<EntryOptions, DependencyId>> =
66+
Default::default();
6167

62-
for EntryDynamicResult { import, options } in decs {
63-
for entry in import {
64-
let module_graph = compilation.get_module_graph();
68+
for EntryDynamicResult { import, options } in decs {
69+
for entry in import {
70+
let module_graph = compilation.get_module_graph();
6571

66-
let entry_dependency: BoxDependency = if let Some(map) =
67-
imported_dependencies.get(entry.as_str())
68-
&& let Some(dependency_id) = map.get(&options)
69-
{
70-
let dependency = module_graph.dependency_by_id(dependency_id);
71-
next_imported_dependencies
72-
.entry(entry.into())
73-
.or_default()
74-
.insert(options.clone(), *dependency_id);
75-
dependency.clone()
76-
} else {
77-
let dependency: BoxDependency = Box::new(EntryDependency::new(
72+
let entry_dependency: BoxDependency = if let Some(map) =
73+
imported_dependencies.get(entry.as_str())
74+
&& let Some(dependency_id) = map.get(&options)
75+
&& let Some(dependency) = internal::try_dependency_by_id(module_graph, dependency_id)
76+
{
77+
next_imported_dependencies
78+
.entry(entry.into())
79+
.or_default()
80+
.insert(options.clone(), *dependency_id);
81+
dependency.clone()
82+
} else {
83+
let dependency: BoxDependency = Box::new(EntryDependency::new(
84+
entry.clone(),
85+
self.context.clone(),
86+
options.layer.clone(),
87+
false,
88+
));
89+
next_imported_dependencies
90+
.entry(entry.into())
91+
.or_default()
92+
.insert(options.clone(), *dependency.id());
93+
dependency
94+
};
95+
compilation
96+
.add_entry(entry_dependency, options.clone())
97+
.await?;
98+
}
99+
}
100+
101+
*imported_dependencies = next_imported_dependencies;
102+
} else {
103+
for EntryDynamicResult { import, options } in decs {
104+
for entry in import {
105+
let entry_dependency: BoxDependency = Box::new(EntryDependency::new(
78106
entry.clone(),
79107
self.context.clone(),
80108
options.layer.clone(),
81109
false,
82110
));
83-
next_imported_dependencies
84-
.entry(entry.into())
85-
.or_default()
86-
.insert(options.clone(), *dependency.id());
87-
dependency
88-
};
89-
compilation
90-
.add_entry(entry_dependency, options.clone())
91-
.await?;
111+
compilation
112+
.add_entry(entry_dependency, options.clone())
113+
.await?;
114+
}
92115
}
93116
}
94117

95-
*imported_dependencies = next_imported_dependencies;
96-
97118
Ok(())
98119
}
99120

tests/rspack-test/watchCases/entries/dynamic-entries-no-cache/0/index0.js

Whitespace-only changes.

tests/rspack-test/watchCases/entries/dynamic-entries-no-cache/1/index0.js

Whitespace-only changes.

tests/rspack-test/watchCases/entries/dynamic-entries-no-cache/1/index1.js

Whitespace-only changes.
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
const path = require("path");
2+
const fs = require("fs");
3+
const rspack = require("@rspack/core");
4+
5+
let compiler;
6+
let step = 0;
7+
let entries;
8+
9+
/** @type {import("@rspack/core").Configuration} */
10+
module.exports = {
11+
entry: async () => {
12+
const context = compiler.context;
13+
if (step === 0) {
14+
const files = await fs.promises.readdir(context);
15+
entries = files.filter(f => f.startsWith("index"));
16+
entries.sort();
17+
} else if (step === 1) {
18+
} else {
19+
throw new Error(`unreachable step: ${step}`);
20+
}
21+
return entries.reduce((acc, e, i) => {
22+
acc[`bundle${i}`] = path.resolve(context, e);
23+
return acc;
24+
}, {});
25+
},
26+
output: {
27+
filename: "[name].js"
28+
},
29+
cache: false,
30+
plugins: [
31+
new rspack.experiments.RemoveDuplicateModulesPlugin(),
32+
function (c) {
33+
compiler = c;
34+
c.hooks.done.tap("test", () => {
35+
step += 1;
36+
});
37+
}
38+
]
39+
};
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
module.exports = {
2+
findBundle() {
3+
return [];
4+
}
5+
};

0 commit comments

Comments
 (0)