Skip to content

Commit

Permalink
feat: support contextModuleFactory beforeResolve hook (#6420)
Browse files Browse the repository at this point in the history
* fix: contextModuleFactory afterResolve hook

* fix: js side logic

* fix: afterResolve in ContextModuleFactory should be AsyncSeriesWaterfallHook

* fix: refactor context module factory hooks

* fix: js side logic

* chore: update api.md

* fix: use AsyncSeriesWaterfallHook in js side

* fix: format js

* fix: cargo lint

* fix: context module factory afterResolve hook

* chore: update snapshot

* feat: new test case for context module factory before resolve hook
  • Loading branch information
SyMind committed May 10, 2024
1 parent 2f120fc commit 7e15f68
Show file tree
Hide file tree
Showing 24 changed files with 555 additions and 140 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions crates/node_binding/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ rspack_hook = { path = "../rspack_hook" }
rspack_identifier = { path = "../rspack_identifier" }
rspack_napi = { path = "../rspack_napi" }
rspack_tracing = { path = "../rspack_tracing" }
rspack_regex = { path = "../rspack_regex" }
tokio = { workspace = true, features = ["rt", "rt-multi-thread"] }

async-trait = { workspace = true }
Expand Down
16 changes: 14 additions & 2 deletions crates/node_binding/binding.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,18 @@ export interface JsCompatSource {
map?: Buffer
}

export interface JsContextModuleFactoryAfterResolveData {
resource: string
context: string
request: string
regExp?: string
}

export interface JsContextModuleFactoryBeforeResolveData {
context: string
request?: string
}

export interface JsCreateData {
request: string
userRequest: string
Expand Down Expand Up @@ -1415,8 +1427,8 @@ export interface RegisterJsTaps {
registerNormalModuleFactoryResolveForSchemeTaps: (stages: Array<number>) => Array<{ function: ((arg: JsResolveForSchemeArgs) => Promise<[boolean | undefined, JsResolveForSchemeArgs]>); stage: number; }>
registerNormalModuleFactoryAfterResolveTaps: (stages: Array<number>) => Array<{ function: ((arg: JsAfterResolveData) => Promise<[boolean | undefined, JsCreateData | undefined]>); stage: number; }>
registerNormalModuleFactoryCreateModuleTaps: (stages: Array<number>) => Array<{ function: ((arg: JsNormalModuleFactoryCreateModuleArgs) => Promise<void>); stage: number; }>
registerContextModuleFactoryBeforeResolveTaps: (stages: Array<number>) => Array<{ function: ((arg: JsBeforeResolveArgs) => Promise<[boolean | undefined, JsBeforeResolveArgs]>); stage: number; }>
registerContextModuleFactoryAfterResolveTaps: (stages: Array<number>) => Array<{ function: ((arg: JsAfterResolveData) => Promise<boolean | undefined>); stage: number; }>
registerContextModuleFactoryBeforeResolveTaps: (stages: Array<number>) => Array<{ function: ((arg: false | JsContextModuleFactoryBeforeResolveData) => Promise<false | JsContextModuleFactoryBeforeResolveData>); stage: number; }>
registerContextModuleFactoryAfterResolveTaps: (stages: Array<number>) => Array<{ function: ((arg: false | JsContextModuleFactoryAfterResolveData) => Promise<false | JsContextModuleFactoryAfterResolveData>); stage: number; }>
}

/** Builtin loader runner */
Expand Down
123 changes: 65 additions & 58 deletions crates/node_binding/src/plugins/interceptor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,15 @@ use napi::{
};
use rspack_binding_values::{
CompatSource, JsAfterResolveData, JsAfterResolveOutput, JsAssetEmittedArgs, JsBeforeResolveArgs,
JsBeforeResolveOutput, JsChunk, JsChunkAssetArgs, JsCompilation, JsCreateData,
JsBeforeResolveOutput, JsChunk, JsChunkAssetArgs, JsCompilation,
JsContextModuleFactoryAfterResolveData, JsContextModuleFactoryAfterResolveResult,
JsContextModuleFactoryBeforeResolveData, JsContextModuleFactoryBeforeResolveResult, JsCreateData,
JsExecuteModuleArg, JsModule, JsNormalModuleFactoryCreateModuleArgs, JsResolveForSchemeArgs,
JsResolveForSchemeOutput, JsRuntimeModule, JsRuntimeModuleArg, ToJsCompatSource, ToJsModule,
};
use rspack_core::{
rspack_sources::SourceExt, AssetEmittedInfo, BoxModule, Chunk, ChunkUkey, CodeGenerationResults,
rspack_sources::SourceExt, AfterResolveData, AfterResolveResult, AssetEmittedInfo,
BeforeResolveData, BeforeResolveResult, BoxModule, Chunk, ChunkUkey, CodeGenerationResults,
Compilation, CompilationAfterOptimizeModules, CompilationAfterOptimizeModulesHook,
CompilationAfterProcessAssets, CompilationAfterProcessAssetsHook, CompilationAfterSeal,
CompilationAfterSealHook, CompilationBuildModule, CompilationBuildModuleHook,
Expand All @@ -42,6 +45,7 @@ use rspack_core::{
use rspack_hook::{Hook, Interceptor};
use rspack_identifier::IdentifierSet;
use rspack_napi::threadsafe_function::ThreadsafeFunction;
use rspack_regex::RspackRegex;

#[napi(object)]
pub struct JsTap {
Expand Down Expand Up @@ -434,15 +438,19 @@ pub struct RegisterJsTaps {
pub register_normal_module_factory_create_module_taps:
RegisterFunction<JsNormalModuleFactoryCreateModuleArgs, Promise<()>>,
#[napi(
ts_type = "(stages: Array<number>) => Array<{ function: ((arg: JsBeforeResolveArgs) => Promise<[boolean | undefined, JsBeforeResolveArgs]>); stage: number; }>"
ts_type = "(stages: Array<number>) => Array<{ function: ((arg: false | JsContextModuleFactoryBeforeResolveData) => Promise<false | JsContextModuleFactoryBeforeResolveData>); stage: number; }>"
)]
pub register_context_module_factory_before_resolve_taps:
RegisterFunction<JsBeforeResolveArgs, Promise<JsBeforeResolveOutput>>,
pub register_context_module_factory_before_resolve_taps: RegisterFunction<
JsContextModuleFactoryBeforeResolveResult,
Promise<JsContextModuleFactoryBeforeResolveResult>,
>,
#[napi(
ts_type = "(stages: Array<number>) => Array<{ function: ((arg: JsAfterResolveData) => Promise<boolean | undefined>); stage: number; }>"
ts_type = "(stages: Array<number>) => Array<{ function: ((arg: false | JsContextModuleFactoryAfterResolveData) => Promise<false | JsContextModuleFactoryAfterResolveData>); stage: number; }>"
)]
pub register_context_module_factory_after_resolve_taps:
RegisterFunction<JsAfterResolveData, Promise<Option<bool>>>,
pub register_context_module_factory_after_resolve_taps: RegisterFunction<
JsContextModuleFactoryAfterResolveResult,
Promise<JsContextModuleFactoryAfterResolveResult>,
>,
}

/* Compiler Hooks */
Expand Down Expand Up @@ -662,15 +670,15 @@ define_register!(
/* ContextModuleFactory Hooks */
define_register!(
RegisterContextModuleFactoryBeforeResolveTaps,
tap = ContextModuleFactoryBeforeResolveTap<JsBeforeResolveArgs, Promise<JsBeforeResolveOutput>> @ ContextModuleFactoryBeforeResolveHook,
tap = ContextModuleFactoryBeforeResolveTap<JsContextModuleFactoryBeforeResolveResult, Promise<JsContextModuleFactoryBeforeResolveResult>> @ ContextModuleFactoryBeforeResolveHook,
cache = true,
sync = false,
kind = RegisterJsTapKind::ContextModuleFactoryBeforeResolve,
skip = true,
);
define_register!(
RegisterContextModuleFactoryAfterResolveTaps,
tap = ContextModuleFactoryAfterResolveTap<JsAfterResolveData, Promise<Option<bool>>> @ ContextModuleFactoryAfterResolveHook,
tap = ContextModuleFactoryAfterResolveTap<JsContextModuleFactoryAfterResolveResult, Promise<JsContextModuleFactoryAfterResolveResult>> @ ContextModuleFactoryAfterResolveHook,
cache = true,
sync = false,
kind = RegisterJsTapKind::ContextModuleFactoryAfterResolve,
Expand Down Expand Up @@ -1198,24 +1206,27 @@ impl NormalModuleFactoryCreateModule for NormalModuleFactoryCreateModuleTap {

#[async_trait]
impl ContextModuleFactoryBeforeResolve for ContextModuleFactoryBeforeResolveTap {
async fn run(&self, data: &mut ModuleFactoryCreateData) -> rspack_error::Result<Option<bool>> {
let dependency = data
.dependency
.as_context_dependency_mut()
.expect("should be context dependency");
match self
.function
.call_with_promise(JsBeforeResolveArgs {
request: dependency.request().to_string(),
context: data.context.to_string(),
})
.await
{
Ok((ret, resolve_data)) => {
dependency.set_request(resolve_data.request);
data.context = resolve_data.context.into();
Ok(ret)
async fn run(&self, result: BeforeResolveResult) -> rspack_error::Result<BeforeResolveResult> {
let js_result = match result {
BeforeResolveResult::Ignored => JsContextModuleFactoryBeforeResolveResult::A(false),
BeforeResolveResult::Data(d) => {
JsContextModuleFactoryBeforeResolveResult::B(JsContextModuleFactoryBeforeResolveData {
context: d.context,
request: d.request,
})
}
};
match self.function.call_with_promise(js_result).await {
Ok(js_result) => match js_result {
napi::bindgen_prelude::Either::A(_) => Ok(BeforeResolveResult::Ignored),
napi::bindgen_prelude::Either::B(d) => {
let data = BeforeResolveData {
context: d.context,
request: d.request,
};
Ok(BeforeResolveResult::Data(Box::new(data)))
}
},
Err(err) => Err(err),
}
}
Expand All @@ -1227,37 +1238,33 @@ impl ContextModuleFactoryBeforeResolve for ContextModuleFactoryBeforeResolveTap

#[async_trait]
impl ContextModuleFactoryAfterResolve for ContextModuleFactoryAfterResolveTap {
async fn run(&self, data: &mut ModuleFactoryCreateData) -> rspack_error::Result<Option<bool>> {
let dependency = data
.dependency
.as_context_dependency_mut()
.expect("should be context dependency");
self
.function
.call_with_promise(JsAfterResolveData {
request: dependency.request().to_string(),
context: data.context.to_string(),
file_dependencies: data
.file_dependencies
.clone()
.into_iter()
.map(|item| item.to_string_lossy().to_string())
.collect::<Vec<_>>(),
context_dependencies: data
.context_dependencies
.clone()
.into_iter()
.map(|item| item.to_string_lossy().to_string())
.collect::<Vec<_>>(),
missing_dependencies: data
.missing_dependencies
.clone()
.into_iter()
.map(|item| item.to_string_lossy().to_string())
.collect::<Vec<_>>(),
create_data: None,
})
.await
async fn run(&self, result: AfterResolveResult) -> rspack_error::Result<AfterResolveResult> {
let js_result = match result {
AfterResolveResult::Ignored => JsContextModuleFactoryAfterResolveResult::A(false),
AfterResolveResult::Data(d) => {
JsContextModuleFactoryAfterResolveResult::B(JsContextModuleFactoryAfterResolveData {
resource: d.resource.to_owned(),
context: d.context.to_owned(),
request: d.request.to_owned(),
reg_exp: d.reg_exp.clone().map(|r| r.to_string()),
})
}
};
match self.function.call_with_promise(js_result).await? {
napi::Either::A(_) => Ok(AfterResolveResult::Ignored),
napi::Either::B(d) => {
let data = AfterResolveData {
resource: d.resource,
context: d.context,
request: d.request,
reg_exp: match d.reg_exp {
Some(r) => Some(RspackRegex::new(&r)?),
None => None,
},
};
Ok(AfterResolveResult::Data(Box::new(data)))
}
}
}

fn stage(&self) -> i32 {
Expand Down
22 changes: 22 additions & 0 deletions crates/rspack_binding_values/src/context_module_factory.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
use napi::bindgen_prelude::Either;
use napi_derive::napi;

#[napi(object)]
pub struct JsContextModuleFactoryBeforeResolveData {
pub context: String,
pub request: Option<String>,
}

pub type JsContextModuleFactoryBeforeResolveResult =
Either<bool, JsContextModuleFactoryBeforeResolveData>;

#[napi(object)]
pub struct JsContextModuleFactoryAfterResolveData {
pub resource: String,
pub context: String,
pub request: String,
pub reg_exp: Option<String>,
}

pub type JsContextModuleFactoryAfterResolveResult =
Either<bool, JsContextModuleFactoryAfterResolveData>;
2 changes: 2 additions & 0 deletions crates/rspack_binding_values/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ mod chunk_graph;
mod chunk_group;
mod codegen_result;
mod compilation;
mod context_module_factory;
mod filename;
mod module;
mod normal_module_factory;
Expand All @@ -19,6 +20,7 @@ pub use chunk_graph::*;
pub use chunk_group::*;
pub use codegen_result::*;
pub use compilation::*;
pub use context_module_factory::*;
pub use filename::*;
pub use module::*;
pub use normal_module_factory::*;
Expand Down
2 changes: 1 addition & 1 deletion crates/rspack_core/src/context_module.rs
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ pub struct ContextOptions {
pub end: u32,
}

#[derive(Debug, PartialEq)]
#[derive(Debug, PartialEq, Clone)]
pub struct ContextModuleOptions {
pub addon: String,
pub resource: String,
Expand Down

2 comments on commit 7e15f68

@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-05-10 73c31ab) Current Change
10000_development-mode + exec 2.71 s ± 21 ms 2.71 s ± 23 ms -0.07 %
10000_development-mode_hmr + exec 697 ms ± 5.2 ms 711 ms ± 9.6 ms +2.06 %
10000_production-mode + exec 2.51 s ± 26 ms 2.51 s ± 23 ms +0.27 %
arco-pro_development-mode + exec 2.52 s ± 81 ms 2.49 s ± 78 ms -1.22 %
arco-pro_development-mode_hmr + exec 430 ms ± 2.2 ms 436 ms ± 1.6 ms +1.44 %
arco-pro_development-mode_hmr_intercept-plugin + exec 440 ms ± 1.7 ms 443 ms ± 2.3 ms +0.84 %
arco-pro_development-mode_intercept-plugin + exec 3.33 s ± 46 ms 3.26 s ± 178 ms -1.94 %
arco-pro_production-mode + exec 4 s ± 92 ms 4.07 s ± 89 ms +1.67 %
arco-pro_production-mode_intercept-plugin + exec 4.89 s ± 74 ms 4.9 s ± 91 ms +0.09 %
threejs_development-mode_10x + exec 1.99 s ± 16 ms 2 s ± 13 ms +0.41 %
threejs_development-mode_10x_hmr + exec 768 ms ± 12 ms 772 ms ± 6.6 ms +0.47 %
threejs_production-mode_10x + exec 5.2 s ± 21 ms 5.2 s ± 20 ms -0.04 %

@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, self-hosted, Linux, ci ✅ success
_selftest, ubuntu-latest ✅ success
nx, ubuntu-latest ✅ success
rspress, ubuntu-latest ✅ success
rsbuild, ubuntu-latest ✅ success
compat, ubuntu-latest ✅ success
examples, ubuntu-latest ✅ success

Please sign in to comment.