Skip to content

Commit de9c5ef

Browse files
authored
feat: addInclude binding API (#8713)
1 parent d401dd9 commit de9c5ef

File tree

12 files changed

+405
-54
lines changed

12 files changed

+405
-54
lines changed

crates/node_binding/binding.d.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,7 @@ export declare class JsCompilation {
140140
addRuntimeModule(chunk: JsChunk, runtimeModule: JsAddingRuntimeModule): void
141141
get moduleGraph(): JsModuleGraph
142142
get chunkGraph(): JsChunkGraph
143+
addInclude(args: [string, RawDependency, JsEntryOptions | undefined][], callback: (errMsg: Error | null, results: [string | null, JsModule][]) => void): void
143144
}
144145

145146
export declare class JsContextModuleFactoryAfterResolveData {
@@ -1319,6 +1320,10 @@ export interface RawCssParserOptions {
13191320
namedExports?: boolean
13201321
}
13211322

1323+
export interface RawDependency {
1324+
request: string
1325+
}
1326+
13221327
export interface RawDllEntryPluginOptions {
13231328
context: string
13241329
entries: Array<string>

crates/rspack_binding_values/src/compilation/mod.rs

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,12 @@ use napi_derive::napi;
1212
use rspack_collections::{DatabaseItem, IdentifierSet};
1313
use rspack_core::rspack_sources::BoxSource;
1414
use rspack_core::AssetInfo;
15+
use rspack_core::BoxDependency;
1516
use rspack_core::Compilation;
1617
use rspack_core::CompilationAsset;
1718
use rspack_core::CompilationId;
19+
use rspack_core::EntryDependency;
20+
use rspack_core::EntryOptions;
1821
use rspack_core::ModuleIdentifier;
1922
use rspack_error::Diagnostic;
2023
use rspack_napi::napi::bindgen_prelude::*;
@@ -23,6 +26,7 @@ use rspack_napi::OneShotRef;
2326
use rspack_plugin_runtime::RuntimeModuleFromJs;
2427

2528
use super::{JsFilename, PathWithInfo};
29+
use crate::entry::JsEntryOptions;
2630
use crate::utils::callbackify;
2731
use crate::JsAddingRuntimeModule;
2832
use crate::JsChunk;
@@ -34,6 +38,7 @@ use crate::JsModuleGraph;
3438
use crate::JsModuleWrapper;
3539
use crate::JsStatsOptimizationBailout;
3640
use crate::LocalJsFilename;
41+
use crate::RawDependency;
3742
use crate::ToJsCompatSource;
3843
use crate::{JsAsset, JsAssetInfo, JsPathData, JsStats};
3944
use crate::{JsRspackDiagnostic, JsRspackError};
@@ -717,6 +722,107 @@ impl JsCompilation {
717722
let compilation = self.as_ref()?;
718723
Ok(JsChunkGraph::new(compilation))
719724
}
725+
726+
#[napi(
727+
ts_args_type = "args: [string, RawDependency, JsEntryOptions | undefined][], callback: (errMsg: Error | null, results: [string | null, JsModule][]) => void"
728+
)]
729+
pub fn add_include(
730+
&mut self,
731+
env: Env,
732+
js_args: Vec<(String, RawDependency, Option<JsEntryOptions>)>,
733+
f: Function,
734+
) -> napi::Result<()> {
735+
let compilation = self.as_mut()?;
736+
737+
let args = js_args
738+
.into_iter()
739+
.map(|(js_context, js_dependency, js_options)| {
740+
let layer = match &js_options {
741+
Some(options) => options.layer.clone(),
742+
None => None,
743+
};
744+
let dependency = Box::new(EntryDependency::new(
745+
js_dependency.request,
746+
js_context.into(),
747+
layer,
748+
false,
749+
)) as BoxDependency;
750+
let options = match js_options {
751+
Some(js_opts) => js_opts.into(),
752+
None => EntryOptions::default(),
753+
};
754+
(dependency, options)
755+
})
756+
.collect::<Vec<(BoxDependency, EntryOptions)>>();
757+
758+
callbackify(env, f, async move {
759+
let dependency_ids = args
760+
.iter()
761+
.map(|(dependency, _)| *dependency.id())
762+
.collect::<Vec<_>>();
763+
764+
compilation
765+
.add_include(args)
766+
.await
767+
.map_err(|e| Error::new(napi::Status::GenericFailure, format!("{e}")))?;
768+
769+
let results = dependency_ids
770+
.into_iter()
771+
.map(|dependency_id| {
772+
let module_graph = compilation.get_module_graph();
773+
match module_graph.module_graph_module_by_dependency_id(&dependency_id) {
774+
Some(module) => match module_graph.module_by_identifier(&module.module_identifier) {
775+
Some(module) => {
776+
let js_module =
777+
JsModuleWrapper::new(module.as_ref(), compilation.id(), Some(compilation));
778+
(Either::B(()), Either::B(js_module))
779+
}
780+
None => (
781+
Either::A(format!(
782+
"Module created by {:#?} cannot be found",
783+
dependency_id
784+
)),
785+
Either::A(()),
786+
),
787+
},
788+
None => (
789+
Either::A(format!(
790+
"Module created by {:#?} cannot be found",
791+
dependency_id
792+
)),
793+
Either::A(()),
794+
),
795+
}
796+
})
797+
.collect::<Vec<(Either<String, ()>, Either<(), JsModuleWrapper>)>>();
798+
799+
Ok(JsAddIncludeCallbackArgs(results))
800+
})
801+
}
802+
}
803+
804+
pub struct JsAddIncludeCallbackArgs(Vec<(Either<String, ()>, Either<(), JsModuleWrapper>)>);
805+
806+
impl ToNapiValue for JsAddIncludeCallbackArgs {
807+
unsafe fn to_napi_value(env: sys::napi_env, val: Self) -> Result<sys::napi_value> {
808+
let env_wrapper = Env::from_raw(env);
809+
let mut js_array = env_wrapper.create_array(0)?;
810+
for (error, module) in val.0 {
811+
let js_error = match error {
812+
Either::A(val) => env_wrapper.create_string(&val)?.into_unknown(),
813+
Either::B(_) => env_wrapper.get_undefined()?.into_unknown(),
814+
};
815+
let js_module = match module {
816+
Either::A(_) => env_wrapper.get_undefined()?.into_unknown(),
817+
Either::B(val) => {
818+
let napi_val = ToNapiValue::to_napi_value(env, val)?;
819+
Unknown::from_napi_value(env, napi_val)?
820+
}
821+
};
822+
js_array.insert(vec![js_error, js_module])?;
823+
}
824+
ToNapiValue::to_napi_value(env, js_array)
825+
}
720826
}
721827

722828
thread_local! {

crates/rspack_binding_values/src/dependency.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,3 +180,8 @@ impl ToNapiValue for JsDependencyWrapper {
180180
}
181181

182182
pub type JsRuntimeSpec = Either<String, Vec<String>>;
183+
184+
#[napi(object)]
185+
pub struct RawDependency {
186+
pub request: String,
187+
}

crates/rspack_core/src/compiler/compilation.rs

Lines changed: 61 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,10 @@ use std::{
22
collections::{hash_map, VecDeque},
33
fmt::Debug,
44
hash::{BuildHasherDefault, Hash},
5-
sync::{atomic::AtomicU32, Arc},
5+
sync::{
6+
atomic::{AtomicBool, AtomicU32, Ordering},
7+
Arc,
8+
},
69
};
710

811
use dashmap::DashSet;
@@ -13,7 +16,10 @@ use rspack_cacheable::cacheable;
1316
use rspack_collections::{
1417
DatabaseItem, Identifiable, IdentifierDashMap, IdentifierMap, IdentifierSet, UkeyMap, UkeySet,
1518
};
16-
use rspack_error::{error, miette::diagnostic, Diagnostic, DiagnosticExt, Result, Severity};
19+
use rspack_error::{
20+
error, miette::diagnostic, Diagnostic, DiagnosticExt, InternalError, Result, RspackSeverity,
21+
Severity,
22+
};
1723
use rspack_fs::{FileSystem, IntermediateFileSystem, WritableFileSystem};
1824
use rspack_futures::FuturesResults;
1925
use rspack_hash::{RspackHash, RspackHashDigest};
@@ -140,6 +146,7 @@ impl Default for CompilationId {
140146
type ValueCacheVersions = HashMap<String, String>;
141147

142148
static COMPILATION_ID: AtomicU32 = AtomicU32::new(0);
149+
143150
#[derive(Debug)]
144151
pub struct Compilation {
145152
/// get_compilation_hooks(compilation.id)
@@ -215,11 +222,13 @@ pub struct Compilation {
215222
import_var_map: IdentifierDashMap<ImportVarMap>,
216223

217224
pub module_executor: Option<ModuleExecutor>,
225+
in_finish_make: AtomicBool,
218226

219227
pub modified_files: HashSet<ArcPath>,
220228
pub removed_files: HashSet<ArcPath>,
221229
pub make_artifact: MakeArtifact,
222230
pub input_filesystem: Arc<dyn FileSystem>,
231+
223232
pub intermediate_filesystem: Arc<dyn IntermediateFileSystem>,
224233
pub output_filesystem: Arc<dyn WritableFileSystem>,
225234
}
@@ -321,11 +330,13 @@ impl Compilation {
321330
import_var_map: IdentifierDashMap::default(),
322331

323332
module_executor,
333+
in_finish_make: AtomicBool::new(false),
324334

325335
make_artifact: Default::default(),
326336
modified_files,
327337
removed_files,
328338
input_filesystem,
339+
329340
intermediate_filesystem,
330341
output_filesystem,
331342
}
@@ -544,24 +555,54 @@ impl Compilation {
544555
Ok(())
545556
}
546557

547-
pub async fn add_include(&mut self, entry: BoxDependency, options: EntryOptions) -> Result<()> {
548-
let entry_id = *entry.id();
549-
self.get_module_graph_mut().add_dependency(entry);
550-
if let Some(name) = options.name.clone() {
551-
if let Some(data) = self.entries.get_mut(&name) {
552-
data.include_dependencies.push(entry_id);
558+
pub async fn add_include(&mut self, args: Vec<(BoxDependency, EntryOptions)>) -> Result<()> {
559+
if !self.in_finish_make.load(Ordering::Acquire) {
560+
return Err(
561+
InternalError::new(
562+
"You can only call `add_include` during the finish make stage".to_string(),
563+
RspackSeverity::Error,
564+
)
565+
.into(),
566+
);
567+
}
568+
569+
for (entry, options) in args {
570+
let entry_id = *entry.id();
571+
self.get_module_graph_mut().add_dependency(entry);
572+
if let Some(name) = options.name.clone() {
573+
if let Some(data) = self.entries.get_mut(&name) {
574+
data.include_dependencies.push(entry_id);
575+
} else {
576+
let data = EntryData {
577+
dependencies: vec![],
578+
include_dependencies: vec![entry_id],
579+
options,
580+
};
581+
self.entries.insert(name, data);
582+
}
553583
} else {
554-
let data = EntryData {
555-
dependencies: vec![],
556-
include_dependencies: vec![entry_id],
557-
options,
558-
};
559-
self.entries.insert(name, data);
584+
self.global_entry.include_dependencies.push(entry_id);
560585
}
561-
} else {
562-
self.global_entry.include_dependencies.push(entry_id);
563586
}
564587

588+
// Recheck entry and clean useless entry
589+
// This should before finish_modules hook is called, ensure providedExports effects on new added modules
590+
let make_artifact = std::mem::take(&mut self.make_artifact);
591+
self.make_artifact = update_module_graph(
592+
self,
593+
make_artifact,
594+
vec![MakeParam::BuildEntryAndClean(
595+
self
596+
.entries
597+
.values()
598+
.flat_map(|item| item.all_dependencies())
599+
.chain(self.global_entry.all_dependencies())
600+
.copied()
601+
.collect(),
602+
)],
603+
)
604+
.await?;
605+
565606
Ok(())
566607
}
567608

@@ -783,6 +824,9 @@ impl Compilation {
783824

784825
let artifact = std::mem::take(&mut self.make_artifact);
785826
self.make_artifact = make_module_graph(self, artifact).await?;
827+
828+
self.in_finish_make.store(true, Ordering::Release);
829+
786830
Ok(())
787831
}
788832

@@ -1128,23 +1172,7 @@ impl Compilation {
11281172
pub async fn finish(&mut self, plugin_driver: SharedPluginDriver) -> Result<()> {
11291173
let logger = self.get_logger("rspack.Compilation");
11301174

1131-
// Recheck entry and clean useless entry
1132-
// This should before finish_modules hook is called, ensure providedExports effects on new added modules
1133-
let make_artifact = std::mem::take(&mut self.make_artifact);
1134-
self.make_artifact = update_module_graph(
1135-
self,
1136-
make_artifact,
1137-
vec![MakeParam::BuildEntryAndClean(
1138-
self
1139-
.entries
1140-
.values()
1141-
.flat_map(|item| item.all_dependencies())
1142-
.chain(self.global_entry.all_dependencies())
1143-
.copied()
1144-
.collect(),
1145-
)],
1146-
)
1147-
.await?;
1175+
self.in_finish_make.store(false, Ordering::Release);
11481176

11491177
// sync assets to compilation from module_executor
11501178
if let Some(module_executor) = &mut self.module_executor {

crates/rspack_plugin_mf/src/sharing/provide_shared_plugin.rs

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@ use std::{fmt, sync::Arc};
44
use async_trait::async_trait;
55
use regex::Regex;
66
use rspack_core::{
7-
ApplyContext, BoxModule, Compilation, CompilationParams, CompilerCompilation, CompilerFinishMake,
8-
CompilerOptions, DependencyType, EntryOptions, ModuleFactoryCreateData, NormalModuleCreateData,
9-
NormalModuleFactoryModule, Plugin, PluginContext,
7+
ApplyContext, BoxDependency, BoxModule, Compilation, CompilationParams, CompilerCompilation,
8+
CompilerFinishMake, CompilerOptions, DependencyType, EntryOptions, ModuleFactoryCreateData,
9+
NormalModuleCreateData, NormalModuleFactoryModule, Plugin, PluginContext,
1010
};
1111
use rspack_error::{Diagnostic, Result};
1212
use rspack_hook::{plugin, plugin_hook};
@@ -185,9 +185,13 @@ async fn compilation(
185185

186186
#[plugin_hook(CompilerFinishMake for ProvideSharedPlugin)]
187187
async fn finish_make(&self, compilation: &mut Compilation) -> Result<()> {
188-
for (resource, config) in self.resolved_provide_map.read().await.iter() {
189-
compilation
190-
.add_include(
188+
let entries = self
189+
.resolved_provide_map
190+
.read()
191+
.await
192+
.iter()
193+
.map(|(resource, config)| {
194+
(
191195
Box::new(ProvideSharedDependency::new(
192196
config.share_scope.to_string(),
193197
config.share_key.to_string(),
@@ -197,14 +201,15 @@ async fn finish_make(&self, compilation: &mut Compilation) -> Result<()> {
197201
config.singleton,
198202
config.required_version.clone(),
199203
config.strict_version,
200-
)),
204+
)) as BoxDependency,
201205
EntryOptions {
202206
name: None,
203207
..Default::default()
204208
},
205209
)
206-
.await?;
207-
}
210+
})
211+
.collect::<Vec<_>>();
212+
compilation.add_include(entries).await?;
208213
Ok(())
209214
}
210215

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export const bar = "bar";
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export const foo = "foo";
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import fs from "fs";
2+
import path from "path";
3+
4+
it("should ensure proper module requirement functionality using the manifest's mapping", () => {
5+
const manifest = JSON.parse(fs.readFileSync(path.join(__dirname, "manifest.json"), "utf-8"));
6+
expect(__webpack_require__(manifest["foo"]).foo).toBe("foo");
7+
expect(__webpack_require__(manifest["bar"]).bar).toBe("bar");
8+
});

0 commit comments

Comments
 (0)