Skip to content

Commit e875ced

Browse files
authored
perf: avoid create new dependency for add include (#9505)
1 parent 04fd686 commit e875ced

File tree

6 files changed

+114
-23
lines changed

6 files changed

+114
-23
lines changed

crates/node_binding/src/compilation/mod.rs

Lines changed: 44 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ use rspack_napi::napi::bindgen_prelude::*;
2222
use rspack_napi::NapiResultExt;
2323
use rspack_napi::OneShotRef;
2424
use rspack_plugin_runtime::RuntimeModuleFromJs;
25+
use rustc_hash::FxHashMap;
2526

2627
use super::{JsFilename, PathWithInfo};
2728
use crate::entry::JsEntryOptions;
@@ -38,6 +39,7 @@ use crate::JsStatsOptimizationBailout;
3839
use crate::LocalJsFilename;
3940
use crate::RawDependency;
4041
use crate::ToJsCompatSource;
42+
use crate::COMPILER_REFERENCES;
4143
use crate::{AssetInfo, JsAsset, JsPathData, JsStats};
4244
use crate::{JsRspackDiagnostic, JsRspackError};
4345

@@ -700,23 +702,52 @@ impl JsCompilation {
700702
) -> napi::Result<()> {
701703
let compilation = self.as_mut()?;
702704

705+
let Some(compiler_reference) = COMPILER_REFERENCES.with(|ref_cell| {
706+
let references = ref_cell.borrow();
707+
references.get(&compilation.compiler_id()).cloned()
708+
}) else {
709+
return Err(napi::Error::from_reason(
710+
"Unable to addInclude now. The Compiler has been garbage collected by JavaScript.",
711+
));
712+
};
713+
let Some(js_compiler) = compiler_reference.get() else {
714+
return Err(napi::Error::from_reason(
715+
"Unable to addInclude now. The Compiler has been garbage collected by JavaScript.",
716+
));
717+
};
718+
let include_dependencies_map = &js_compiler.include_dependencies_map;
719+
703720
let args = js_args
704721
.into_iter()
705722
.map(|(js_context, js_dependency, js_options)| {
706723
let layer = match &js_options {
707724
Some(options) => options.layer.clone(),
708725
None => None,
709726
};
710-
let dependency = Box::new(EntryDependency::new(
711-
js_dependency.request,
712-
js_context.into(),
713-
layer,
714-
false,
715-
)) as BoxDependency;
716727
let options = match js_options {
717728
Some(js_opts) => js_opts.into(),
718729
None => EntryOptions::default(),
719730
};
731+
let dependency = if let Some(map) = include_dependencies_map.get(&js_dependency.request)
732+
&& let Some(dependency) = map.get(&options)
733+
{
734+
dependency.clone()
735+
} else {
736+
let dependency: BoxDependency = Box::new(EntryDependency::new(
737+
js_dependency.request.clone(),
738+
js_context.into(),
739+
layer,
740+
false,
741+
));
742+
if let Some(mut map) = include_dependencies_map.get_mut(&js_dependency.request) {
743+
map.insert(options.clone(), dependency.clone());
744+
} else {
745+
let mut map = FxHashMap::default();
746+
map.insert(options.clone(), dependency.clone());
747+
include_dependencies_map.insert(js_dependency.request, map);
748+
}
749+
dependency
750+
};
720751
(dependency, options)
721752
})
722753
.collect::<Vec<(BoxDependency, EntryOptions)>>();
@@ -736,24 +767,15 @@ impl JsCompilation {
736767
.into_iter()
737768
.map(|dependency_id| {
738769
let module_graph = compilation.get_module_graph();
739-
match module_graph.module_graph_module_by_dependency_id(&dependency_id) {
740-
Some(module) => match module_graph.module_by_identifier(&module.module_identifier) {
741-
Some(module) => {
742-
let js_module =
743-
JsModuleWrapper::new(module.identifier(), None, compilation.compiler_id());
744-
(Either::B(()), Either::B(js_module))
745-
}
746-
None => (
747-
Either::A(format!(
748-
"Module created by {:#?} cannot be found",
749-
dependency_id
750-
)),
751-
Either::A(()),
752-
),
753-
},
770+
match module_graph.get_module_by_dependency_id(&dependency_id) {
771+
Some(module) => {
772+
let js_module =
773+
JsModuleWrapper::new(module.identifier(), None, compilation.compiler_id());
774+
(Either::B(()), Either::B(js_module))
775+
}
754776
None => (
755777
Either::A(format!(
756-
"Module created by {:#?} cannot be found",
778+
"Module created by {:?} cannot be found",
757779
dependency_id
758780
)),
759781
Either::A(()),

crates/node_binding/src/lib.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,9 @@ use std::sync::{Arc, Mutex};
1313
use compiler::{Compiler, CompilerState, CompilerStateGuard};
1414
use napi::{bindgen_prelude::*, CallContext};
1515
use rspack_collections::UkeyMap;
16-
use rspack_core::{Compilation, CompilerId, ModuleIdentifier, PluginExt};
16+
use rspack_core::{
17+
BoxDependency, Compilation, CompilerId, EntryOptions, ModuleIdentifier, PluginExt,
18+
};
1719
use rspack_error::Diagnostic;
1820
use rspack_fs::IntermediateFileSystem;
1921
use rspack_fs_node::{NodeFileSystem, ThreadsafeNodeFS};
@@ -85,7 +87,9 @@ use resolver_factory::*;
8587
pub use resource_data::*;
8688
pub use rsdoctor::*;
8789
use rspack_tracing::{ChromeTracer, OtelTracer, StdoutTracer, Tracer};
90+
use rspack_util::fx_hash::FxDashMap;
8891
pub use runtime::*;
92+
use rustc_hash::FxHashMap;
8993
pub use source::*;
9094
pub use stats::*;
9195
use swc_core::common::util::take::Take;
@@ -112,6 +116,7 @@ pub struct JsCompiler {
112116
js_hooks_plugin: JsHooksAdapterPlugin,
113117
compiler: Pin<Box<Compiler>>,
114118
state: CompilerState,
119+
include_dependencies_map: FxDashMap<String, FxHashMap<EntryOptions, BoxDependency>>,
115120
}
116121

117122
#[napi]
@@ -187,6 +192,7 @@ impl JsCompiler {
187192
compiler: Box::pin(Compiler::from(rspack)),
188193
state: CompilerState::init(),
189194
js_hooks_plugin,
195+
include_dependencies_map: Default::default(),
190196
})
191197
}
192198

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
STATE.foo = 42;
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
__webpack_require__("./foo.js");
2+
3+
it("should addInclude foo.js", () => {
4+
expect(STATE.foo).toBe(42);
5+
const builtModules = Object.fromEntries(__STATS__.modules.map(m => [m.name, m.built]));
6+
expect(builtModules).toEqual({ "./index.js": true, "./foo.js": true });
7+
});
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
__webpack_require__("./foo.js");
2+
3+
it("should addInclude foo.js", () => {
4+
expect(STATE.foo).toBe(42);
5+
const builtModules = Object.fromEntries(__STATS__.modules.map(m => [m.name, m.built]));
6+
expect(builtModules).toEqual({ "./index.js": true, "./foo.js": false });
7+
});
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
let step = 0;
2+
let factorizeRequests = [];
3+
4+
/** @type {import("@rspack/core").Configuration} */
5+
module.exports = {
6+
plugins: [
7+
function (compiler) {
8+
const PLUGIN_NAME = "TEST_PLUGIN";
9+
const { EntryPlugin } = compiler.webpack;
10+
compiler.hooks.finishMake.tapPromise(PLUGIN_NAME, compilation => {
11+
return new Promise((resolve, reject) => {
12+
compilation.addInclude(
13+
compiler.context,
14+
EntryPlugin.createDependency("./foo.js"),
15+
{},
16+
err => {
17+
if (err) return reject(err);
18+
return resolve();
19+
}
20+
);
21+
});
22+
});
23+
24+
compiler.hooks.compilation.tap(
25+
PLUGIN_NAME,
26+
(compilation, { normalModuleFactory }) => {
27+
normalModuleFactory.hooks.factorize.tap(PLUGIN_NAME, data => {
28+
factorizeRequests.push(data.request);
29+
});
30+
}
31+
);
32+
compiler.hooks.done.tap(PLUGIN_NAME, () => {
33+
if (step === 0) {
34+
expect(factorizeRequests.length).toBe(2);
35+
expect(factorizeRequests.includes("./index.js")).toBe(true);
36+
expect(factorizeRequests.includes("./foo.js")).toBe(true);
37+
} else if (step === 1) {
38+
expect(factorizeRequests.length).toBe(1);
39+
expect(factorizeRequests.includes("./index.js")).toBe(true);
40+
} else {
41+
throw new Error("Unexpected step");
42+
}
43+
step += 1;
44+
factorizeRequests = [];
45+
});
46+
}
47+
]
48+
};

0 commit comments

Comments
 (0)