Skip to content

Commit

Permalink
feat: addInclude binding API (#8713)
Browse files Browse the repository at this point in the history
  • Loading branch information
SyMind authored Dec 16, 2024
1 parent d401dd9 commit de9c5ef
Show file tree
Hide file tree
Showing 12 changed files with 405 additions and 54 deletions.
5 changes: 5 additions & 0 deletions crates/node_binding/binding.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ export declare class JsCompilation {
addRuntimeModule(chunk: JsChunk, runtimeModule: JsAddingRuntimeModule): void
get moduleGraph(): JsModuleGraph
get chunkGraph(): JsChunkGraph
addInclude(args: [string, RawDependency, JsEntryOptions | undefined][], callback: (errMsg: Error | null, results: [string | null, JsModule][]) => void): void
}

export declare class JsContextModuleFactoryAfterResolveData {
Expand Down Expand Up @@ -1319,6 +1320,10 @@ export interface RawCssParserOptions {
namedExports?: boolean
}

export interface RawDependency {
request: string
}

export interface RawDllEntryPluginOptions {
context: string
entries: Array<string>
Expand Down
106 changes: 106 additions & 0 deletions crates/rspack_binding_values/src/compilation/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,12 @@ use napi_derive::napi;
use rspack_collections::{DatabaseItem, IdentifierSet};
use rspack_core::rspack_sources::BoxSource;
use rspack_core::AssetInfo;
use rspack_core::BoxDependency;
use rspack_core::Compilation;
use rspack_core::CompilationAsset;
use rspack_core::CompilationId;
use rspack_core::EntryDependency;
use rspack_core::EntryOptions;
use rspack_core::ModuleIdentifier;
use rspack_error::Diagnostic;
use rspack_napi::napi::bindgen_prelude::*;
Expand All @@ -23,6 +26,7 @@ use rspack_napi::OneShotRef;
use rspack_plugin_runtime::RuntimeModuleFromJs;

use super::{JsFilename, PathWithInfo};
use crate::entry::JsEntryOptions;
use crate::utils::callbackify;
use crate::JsAddingRuntimeModule;
use crate::JsChunk;
Expand All @@ -34,6 +38,7 @@ use crate::JsModuleGraph;
use crate::JsModuleWrapper;
use crate::JsStatsOptimizationBailout;
use crate::LocalJsFilename;
use crate::RawDependency;
use crate::ToJsCompatSource;
use crate::{JsAsset, JsAssetInfo, JsPathData, JsStats};
use crate::{JsRspackDiagnostic, JsRspackError};
Expand Down Expand Up @@ -717,6 +722,107 @@ impl JsCompilation {
let compilation = self.as_ref()?;
Ok(JsChunkGraph::new(compilation))
}

#[napi(
ts_args_type = "args: [string, RawDependency, JsEntryOptions | undefined][], callback: (errMsg: Error | null, results: [string | null, JsModule][]) => void"
)]
pub fn add_include(
&mut self,
env: Env,
js_args: Vec<(String, RawDependency, Option<JsEntryOptions>)>,
f: Function,
) -> napi::Result<()> {
let compilation = self.as_mut()?;

let args = js_args
.into_iter()
.map(|(js_context, js_dependency, js_options)| {
let layer = match &js_options {
Some(options) => options.layer.clone(),
None => None,
};
let dependency = Box::new(EntryDependency::new(
js_dependency.request,
js_context.into(),
layer,
false,
)) as BoxDependency;
let options = match js_options {
Some(js_opts) => js_opts.into(),
None => EntryOptions::default(),
};
(dependency, options)
})
.collect::<Vec<(BoxDependency, EntryOptions)>>();

callbackify(env, f, async move {
let dependency_ids = args
.iter()
.map(|(dependency, _)| *dependency.id())
.collect::<Vec<_>>();

compilation
.add_include(args)
.await
.map_err(|e| Error::new(napi::Status::GenericFailure, format!("{e}")))?;

let results = dependency_ids
.into_iter()
.map(|dependency_id| {
let module_graph = compilation.get_module_graph();
match module_graph.module_graph_module_by_dependency_id(&dependency_id) {
Some(module) => match module_graph.module_by_identifier(&module.module_identifier) {
Some(module) => {
let js_module =
JsModuleWrapper::new(module.as_ref(), compilation.id(), Some(compilation));
(Either::B(()), Either::B(js_module))
}
None => (
Either::A(format!(
"Module created by {:#?} cannot be found",
dependency_id
)),
Either::A(()),
),
},
None => (
Either::A(format!(
"Module created by {:#?} cannot be found",
dependency_id
)),
Either::A(()),
),
}
})
.collect::<Vec<(Either<String, ()>, Either<(), JsModuleWrapper>)>>();

Ok(JsAddIncludeCallbackArgs(results))
})
}
}

pub struct JsAddIncludeCallbackArgs(Vec<(Either<String, ()>, Either<(), JsModuleWrapper>)>);

impl ToNapiValue for JsAddIncludeCallbackArgs {
unsafe fn to_napi_value(env: sys::napi_env, val: Self) -> Result<sys::napi_value> {
let env_wrapper = Env::from_raw(env);
let mut js_array = env_wrapper.create_array(0)?;
for (error, module) in val.0 {
let js_error = match error {
Either::A(val) => env_wrapper.create_string(&val)?.into_unknown(),
Either::B(_) => env_wrapper.get_undefined()?.into_unknown(),
};
let js_module = match module {
Either::A(_) => env_wrapper.get_undefined()?.into_unknown(),
Either::B(val) => {
let napi_val = ToNapiValue::to_napi_value(env, val)?;
Unknown::from_napi_value(env, napi_val)?
}
};
js_array.insert(vec![js_error, js_module])?;
}
ToNapiValue::to_napi_value(env, js_array)
}
}

thread_local! {
Expand Down
5 changes: 5 additions & 0 deletions crates/rspack_binding_values/src/dependency.rs
Original file line number Diff line number Diff line change
Expand Up @@ -180,3 +180,8 @@ impl ToNapiValue for JsDependencyWrapper {
}

pub type JsRuntimeSpec = Either<String, Vec<String>>;

#[napi(object)]
pub struct RawDependency {
pub request: String,
}
94 changes: 61 additions & 33 deletions crates/rspack_core/src/compiler/compilation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@ use std::{
collections::{hash_map, VecDeque},
fmt::Debug,
hash::{BuildHasherDefault, Hash},
sync::{atomic::AtomicU32, Arc},
sync::{
atomic::{AtomicBool, AtomicU32, Ordering},
Arc,
},
};

use dashmap::DashSet;
Expand All @@ -13,7 +16,10 @@ use rspack_cacheable::cacheable;
use rspack_collections::{
DatabaseItem, Identifiable, IdentifierDashMap, IdentifierMap, IdentifierSet, UkeyMap, UkeySet,
};
use rspack_error::{error, miette::diagnostic, Diagnostic, DiagnosticExt, Result, Severity};
use rspack_error::{
error, miette::diagnostic, Diagnostic, DiagnosticExt, InternalError, Result, RspackSeverity,
Severity,
};
use rspack_fs::{FileSystem, IntermediateFileSystem, WritableFileSystem};
use rspack_futures::FuturesResults;
use rspack_hash::{RspackHash, RspackHashDigest};
Expand Down Expand Up @@ -140,6 +146,7 @@ impl Default for CompilationId {
type ValueCacheVersions = HashMap<String, String>;

static COMPILATION_ID: AtomicU32 = AtomicU32::new(0);

#[derive(Debug)]
pub struct Compilation {
/// get_compilation_hooks(compilation.id)
Expand Down Expand Up @@ -215,11 +222,13 @@ pub struct Compilation {
import_var_map: IdentifierDashMap<ImportVarMap>,

pub module_executor: Option<ModuleExecutor>,
in_finish_make: AtomicBool,

pub modified_files: HashSet<ArcPath>,
pub removed_files: HashSet<ArcPath>,
pub make_artifact: MakeArtifact,
pub input_filesystem: Arc<dyn FileSystem>,

pub intermediate_filesystem: Arc<dyn IntermediateFileSystem>,
pub output_filesystem: Arc<dyn WritableFileSystem>,
}
Expand Down Expand Up @@ -321,11 +330,13 @@ impl Compilation {
import_var_map: IdentifierDashMap::default(),

module_executor,
in_finish_make: AtomicBool::new(false),

make_artifact: Default::default(),
modified_files,
removed_files,
input_filesystem,

intermediate_filesystem,
output_filesystem,
}
Expand Down Expand Up @@ -544,24 +555,54 @@ impl Compilation {
Ok(())
}

pub async fn add_include(&mut self, entry: BoxDependency, options: EntryOptions) -> Result<()> {
let entry_id = *entry.id();
self.get_module_graph_mut().add_dependency(entry);
if let Some(name) = options.name.clone() {
if let Some(data) = self.entries.get_mut(&name) {
data.include_dependencies.push(entry_id);
pub async fn add_include(&mut self, args: Vec<(BoxDependency, EntryOptions)>) -> Result<()> {
if !self.in_finish_make.load(Ordering::Acquire) {
return Err(
InternalError::new(
"You can only call `add_include` during the finish make stage".to_string(),
RspackSeverity::Error,
)
.into(),
);
}

for (entry, options) in args {
let entry_id = *entry.id();
self.get_module_graph_mut().add_dependency(entry);
if let Some(name) = options.name.clone() {
if let Some(data) = self.entries.get_mut(&name) {
data.include_dependencies.push(entry_id);
} else {
let data = EntryData {
dependencies: vec![],
include_dependencies: vec![entry_id],
options,
};
self.entries.insert(name, data);
}
} else {
let data = EntryData {
dependencies: vec![],
include_dependencies: vec![entry_id],
options,
};
self.entries.insert(name, data);
self.global_entry.include_dependencies.push(entry_id);
}
} else {
self.global_entry.include_dependencies.push(entry_id);
}

// Recheck entry and clean useless entry
// This should before finish_modules hook is called, ensure providedExports effects on new added modules
let make_artifact = std::mem::take(&mut self.make_artifact);
self.make_artifact = update_module_graph(
self,
make_artifact,
vec![MakeParam::BuildEntryAndClean(
self
.entries
.values()
.flat_map(|item| item.all_dependencies())
.chain(self.global_entry.all_dependencies())
.copied()
.collect(),
)],
)
.await?;

Ok(())
}

Expand Down Expand Up @@ -783,6 +824,9 @@ impl Compilation {

let artifact = std::mem::take(&mut self.make_artifact);
self.make_artifact = make_module_graph(self, artifact).await?;

self.in_finish_make.store(true, Ordering::Release);

Ok(())
}

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

// Recheck entry and clean useless entry
// This should before finish_modules hook is called, ensure providedExports effects on new added modules
let make_artifact = std::mem::take(&mut self.make_artifact);
self.make_artifact = update_module_graph(
self,
make_artifact,
vec![MakeParam::BuildEntryAndClean(
self
.entries
.values()
.flat_map(|item| item.all_dependencies())
.chain(self.global_entry.all_dependencies())
.copied()
.collect(),
)],
)
.await?;
self.in_finish_make.store(false, Ordering::Release);

// sync assets to compilation from module_executor
if let Some(module_executor) = &mut self.module_executor {
Expand Down
23 changes: 14 additions & 9 deletions crates/rspack_plugin_mf/src/sharing/provide_shared_plugin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ use std::{fmt, sync::Arc};
use async_trait::async_trait;
use regex::Regex;
use rspack_core::{
ApplyContext, BoxModule, Compilation, CompilationParams, CompilerCompilation, CompilerFinishMake,
CompilerOptions, DependencyType, EntryOptions, ModuleFactoryCreateData, NormalModuleCreateData,
NormalModuleFactoryModule, Plugin, PluginContext,
ApplyContext, BoxDependency, BoxModule, Compilation, CompilationParams, CompilerCompilation,
CompilerFinishMake, CompilerOptions, DependencyType, EntryOptions, ModuleFactoryCreateData,
NormalModuleCreateData, NormalModuleFactoryModule, Plugin, PluginContext,
};
use rspack_error::{Diagnostic, Result};
use rspack_hook::{plugin, plugin_hook};
Expand Down Expand Up @@ -185,9 +185,13 @@ async fn compilation(

#[plugin_hook(CompilerFinishMake for ProvideSharedPlugin)]
async fn finish_make(&self, compilation: &mut Compilation) -> Result<()> {
for (resource, config) in self.resolved_provide_map.read().await.iter() {
compilation
.add_include(
let entries = self
.resolved_provide_map
.read()
.await
.iter()
.map(|(resource, config)| {
(
Box::new(ProvideSharedDependency::new(
config.share_scope.to_string(),
config.share_key.to_string(),
Expand All @@ -197,14 +201,15 @@ async fn finish_make(&self, compilation: &mut Compilation) -> Result<()> {
config.singleton,
config.required_version.clone(),
config.strict_version,
)),
)) as BoxDependency,
EntryOptions {
name: None,
..Default::default()
},
)
.await?;
}
})
.collect::<Vec<_>>();
compilation.add_include(entries).await?;
Ok(())
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const bar = "bar";
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const foo = "foo";
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import fs from "fs";
import path from "path";

it("should ensure proper module requirement functionality using the manifest's mapping", () => {
const manifest = JSON.parse(fs.readFileSync(path.join(__dirname, "manifest.json"), "utf-8"));
expect(__webpack_require__(manifest["foo"]).foo).toBe("foo");
expect(__webpack_require__(manifest["bar"]).bar).toBe("bar");
});
Loading

2 comments on commit de9c5ef

@rspack-bot
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📝 Ran ecosystem CI: Open

suite result
modernjs ❌ failure
_selftest ✅ success
rsdoctor ❌ failure
rspress ✅ success
rslib ✅ success
rsbuild ❌ failure
examples ❌ failure
devserver ✅ success
nuxt ✅ success

@rspack-bot
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📝 Benchmark detail: Open

Name Base (2024-12-16 2f4992b) Current Change
10000_big_production-mode_disable-minimize + exec 38.4 s ± 586 ms 38.2 s ± 438 ms -0.58 %
10000_development-mode + exec 1.89 s ± 64 ms 1.84 s ± 25 ms -2.40 %
10000_development-mode_hmr + exec 690 ms ± 23 ms 683 ms ± 4.7 ms -0.90 %
10000_production-mode + exec 2.49 s ± 47 ms 2.44 s ± 23 ms -2.05 %
arco-pro_development-mode + exec 1.77 s ± 76 ms 1.79 s ± 113 ms +1.22 %
arco-pro_development-mode_hmr + exec 379 ms ± 1.4 ms 378 ms ± 0.49 ms -0.16 %
arco-pro_production-mode + exec 3.33 s ± 128 ms 3.31 s ± 159 ms -0.52 %
arco-pro_production-mode_generate-package-json-webpack-plugin + exec 3.41 s ± 149 ms 3.35 s ± 105 ms -1.81 %
arco-pro_production-mode_traverse-chunk-modules + exec 3.34 s ± 90 ms 3.34 s ± 117 ms -0.04 %
threejs_development-mode_10x + exec 1.62 s ± 14 ms 1.62 s ± 11 ms +0.14 %
threejs_development-mode_10x_hmr + exec 787 ms ± 10 ms 791 ms ± 25 ms +0.58 %
threejs_production-mode_10x + exec 5.42 s ± 77 ms 5.43 s ± 177 ms +0.28 %
10000_big_production-mode_disable-minimize + rss memory 9499 MiB ± 255 MiB 9412 MiB ± 46.3 MiB -0.92 %
10000_development-mode + rss memory 629 MiB ± 18.3 MiB 684 MiB ± 32.9 MiB +8.89 %
10000_development-mode_hmr + rss memory 1515 MiB ± 164 MiB 1607 MiB ± 37.7 MiB +6.12 %
10000_production-mode + rss memory 590 MiB ± 18 MiB 640 MiB ± 30.6 MiB +8.37 %
arco-pro_development-mode + rss memory 570 MiB ± 26.4 MiB 587 MiB ± 51.7 MiB +3.05 %
arco-pro_development-mode_hmr + rss memory 640 MiB ± 39 MiB 589 MiB ± 52.8 MiB -8.00 %
arco-pro_production-mode + rss memory 690 MiB ± 48.5 MiB 748 MiB ± 36.7 MiB +8.31 %
arco-pro_production-mode_generate-package-json-webpack-plugin + rss memory 736 MiB ± 73.2 MiB 730 MiB ± 46.1 MiB -0.81 %
arco-pro_production-mode_traverse-chunk-modules + rss memory 728 MiB ± 34.9 MiB 743 MiB ± 36 MiB +2.11 %
threejs_development-mode_10x + rss memory 590 MiB ± 19.2 MiB 633 MiB ± 26.9 MiB +7.14 %
threejs_development-mode_10x_hmr + rss memory 1125 MiB ± 168 MiB 1167 MiB ± 221 MiB +3.70 %
threejs_production-mode_10x + rss memory 896 MiB ± 52.9 MiB 929 MiB ± 73.2 MiB +3.64 %

Please sign in to comment.