diff --git a/Cargo.lock b/Cargo.lock index 51ebb4c1ba2..e895e700a8a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2944,6 +2944,7 @@ version = "0.1.0" dependencies = [ "async-trait", "derivative", + "futures", "glob", "napi-derive", "napi-h", @@ -2964,6 +2965,7 @@ dependencies = [ "rspack_paths", "rspack_plugin_asset", "rspack_plugin_banner", + "rspack_plugin_context_replacement", "rspack_plugin_copy", "rspack_plugin_css", "rspack_plugin_devtool", diff --git a/crates/node_binding/src/plugins/interceptor.rs b/crates/node_binding/src/plugins/interceptor.rs index a3f0f9b3f46..83910c62046 100644 --- a/crates/node_binding/src/plugins/interceptor.rs +++ b/crates/node_binding/src/plugins/interceptor.rs @@ -53,6 +53,7 @@ use rspack_core::{ NormalModuleFactoryResolveHook, NormalModuleFactoryResolveResult, ResourceData, RuntimeGlobals, Scheme, }; +use rspack_error::miette::IntoDiagnostic; use rspack_hash::RspackHash; use rspack_hook::{Hook, Interceptor}; use rspack_napi::threadsafe_function::ThreadsafeFunction; @@ -1507,9 +1508,15 @@ impl ContextModuleFactoryBeforeResolve for ContextModuleFactoryBeforeResolveTap let js_result = match result { BeforeResolveResult::Ignored => JsContextModuleFactoryBeforeResolveResult::A(false), BeforeResolveResult::Data(d) => { + let reg_exp = match d.reg_exp { + Some(js_regex) => Some(js_regex.try_into().into_diagnostic()?), + None => None, + }; JsContextModuleFactoryBeforeResolveResult::B(JsContextModuleFactoryBeforeResolveData { context: d.context, request: d.request, + reg_exp, + recursive: d.recursive, }) } }; @@ -1517,9 +1524,15 @@ impl ContextModuleFactoryBeforeResolve for ContextModuleFactoryBeforeResolveTap Ok(js_result) => match js_result { napi::bindgen_prelude::Either::A(_) => Ok(BeforeResolveResult::Ignored), napi::bindgen_prelude::Either::B(d) => { + let reg_exp = match d.reg_exp { + Some(js_regex) => Some(js_regex.try_into()?), + None => None, + }; let data = BeforeResolveData { context: d.context, request: d.request, + reg_exp, + recursive: d.recursive, }; Ok(BeforeResolveResult::Data(Box::new(data))) } @@ -1544,6 +1557,7 @@ impl ContextModuleFactoryAfterResolve for ContextModuleFactoryAfterResolveTap { context: d.context.to_owned(), request: d.request.to_owned(), reg_exp: d.reg_exp.clone().map(|r| r.into()), + recursive: d.recursive, }) } }; @@ -1558,7 +1572,7 @@ impl ContextModuleFactoryAfterResolve for ContextModuleFactoryAfterResolveTap { Some(r) => Some(r.try_into()?), None => None, }, - recursive: todo!(), + recursive: d.recursive, }; Ok(AfterResolveResult::Data(Box::new(data))) } diff --git a/crates/rspack_binding_options/Cargo.toml b/crates/rspack_binding_options/Cargo.toml index c84ccb06143..375e8fae3de 100644 --- a/crates/rspack_binding_options/Cargo.toml +++ b/crates/rspack_binding_options/Cargo.toml @@ -15,6 +15,7 @@ ignored = ["tracing"] [dependencies] async-trait = { workspace = true } derivative = { workspace = true } +futures = { workspace = true } glob = { workspace = true } napi = { workspace = true, features = ["async", "tokio_rt", "serde-json", "anyhow"] } napi-derive = { workspace = true } @@ -35,6 +36,7 @@ rspack_napi_macros = { version = "0.1.0", path = "../rspack_n rspack_paths = { version = "0.1.0", path = "../rspack_paths" } rspack_plugin_asset = { version = "0.1.0", path = "../rspack_plugin_asset" } rspack_plugin_banner = { version = "0.1.0", path = "../rspack_plugin_banner" } +rspack_plugin_context_replacement = { version = "0.1.0", path = "../rspack_plugin_context_replacement" } rspack_plugin_copy = { version = "0.1.0", path = "../rspack_plugin_copy" } rspack_plugin_css = { version = "0.1.0", path = "../rspack_plugin_css" } rspack_plugin_devtool = { version = "0.1.0", path = "../rspack_plugin_devtool" } diff --git a/crates/rspack_binding_options/src/options/raw_builtins/mod.rs b/crates/rspack_binding_options/src/options/raw_builtins/mod.rs index ff430963ebe..8ebb6a896af 100644 --- a/crates/rspack_binding_options/src/options/raw_builtins/mod.rs +++ b/crates/rspack_binding_options/src/options/raw_builtins/mod.rs @@ -26,6 +26,7 @@ use rspack_ids::{ use rspack_napi::NapiResultExt; use rspack_plugin_asset::AssetPlugin; use rspack_plugin_banner::BannerPlugin; +use rspack_plugin_context_replacement::ContextReplacementPlugin; use rspack_plugin_copy::{CopyRspackPlugin, CopyRspackPluginOptions}; use rspack_plugin_css::CssPlugin; use rspack_plugin_devtool::{ @@ -92,9 +93,9 @@ use self::{ }; use crate::{ plugins::{CssExtractRspackAdditionalDataPlugin, JsLoaderRspackPlugin}, - JsLoaderRunner, RawDynamicEntryPluginOptions, RawEvalDevToolModulePluginOptions, - RawExternalItemWrapper, RawExternalsPluginOptions, RawHttpExternalsRspackPluginOptions, - RawSourceMapDevToolPluginOptions, RawSplitChunksOptions, + JsLoaderRunner, RawContextReplacementPluginOptions, RawDynamicEntryPluginOptions, + RawEvalDevToolModulePluginOptions, RawExternalItemWrapper, RawExternalsPluginOptions, + RawHttpExternalsRspackPluginOptions, RawSourceMapDevToolPluginOptions, RawSplitChunksOptions, }; #[napi(string_enum)] @@ -162,6 +163,7 @@ pub enum BuiltinPluginName { RuntimeChunkPlugin, SizeLimitsPlugin, NoEmitOnErrorsPlugin, + ContextReplacementPlugin, // rspack specific plugins // naming format follow XxxRspackPlugin @@ -507,6 +509,11 @@ impl BuiltinPlugin { BuiltinPluginName::NoEmitOnErrorsPlugin => { plugins.push(NoEmitOnErrorsPlugin::default().boxed()); } + BuiltinPluginName::ContextReplacementPlugin => { + let raw_options = downcast_into::(self.options)?; + let options = raw_options.try_into()?; + plugins.push(ContextReplacementPlugin::new(options).boxed()); + } } Ok(()) } diff --git a/crates/rspack_binding_options/src/plugins/context_replacement.rs b/crates/rspack_binding_options/src/plugins/context_replacement.rs new file mode 100644 index 00000000000..49b586e4ad2 --- /dev/null +++ b/crates/rspack_binding_options/src/plugins/context_replacement.rs @@ -0,0 +1,37 @@ +use napi_derive::napi; +use rspack_binding_values::RawRegex; +use rspack_error::Error; +use rspack_plugin_context_replacement::ContextReplacementPluginOptions; +use rspack_regex::RspackRegex; + +#[napi(object, object_to_js = false)] +pub struct RawContextReplacementPluginOptions { + pub resource_reg_exp: RawRegex, + pub new_content_resource: Option, + pub new_content_recursive: Option, + pub new_content_reg_exp: Option, + // new_content_callback +} + +impl TryFrom for ContextReplacementPluginOptions { + type Error = Error; + + fn try_from(val: RawContextReplacementPluginOptions) -> Result { + let new_content_reg_exp = match val.new_content_reg_exp { + Some(js_regex) => { + let regex = RspackRegex::with_flags(&js_regex.source, &js_regex.flags)?; + Some(regex) + } + None => None, + }; + Ok(Self { + resource_reg_exp: RspackRegex::with_flags( + &val.resource_reg_exp.source, + &val.resource_reg_exp.flags, + )?, + new_content_resource: val.new_content_resource, + new_content_recursive: val.new_content_recursive, + new_content_reg_exp, + }) + } +} diff --git a/crates/rspack_binding_options/src/plugins/mod.rs b/crates/rspack_binding_options/src/plugins/mod.rs index 06ac0bd3f1b..f935883dc33 100644 --- a/crates/rspack_binding_options/src/plugins/mod.rs +++ b/crates/rspack_binding_options/src/plugins/mod.rs @@ -1,4 +1,7 @@ +mod context_replacement; mod css_extract_additional_data; mod js_loader; + +pub use context_replacement::*; pub(super) use css_extract_additional_data::CssExtractRspackAdditionalDataPlugin; pub(super) use js_loader::{JsLoaderRspackPlugin, JsLoaderRunner}; diff --git a/crates/rspack_binding_values/src/context_module_factory.rs b/crates/rspack_binding_values/src/context_module_factory.rs index 53efd945cc3..1e05ae18ad6 100644 --- a/crates/rspack_binding_values/src/context_module_factory.rs +++ b/crates/rspack_binding_values/src/context_module_factory.rs @@ -7,6 +7,8 @@ use crate::RawRegex; pub struct JsContextModuleFactoryBeforeResolveData { pub context: String, pub request: Option, + pub reg_exp: Option, + pub recursive: bool, } pub type JsContextModuleFactoryBeforeResolveResult = @@ -18,6 +20,7 @@ pub struct JsContextModuleFactoryAfterResolveData { pub context: String, pub request: String, pub reg_exp: Option, + pub recursive: bool, } pub type JsContextModuleFactoryAfterResolveResult = diff --git a/crates/rspack_plugin_context_replacement/src/lib.rs b/crates/rspack_plugin_context_replacement/src/lib.rs index 79927900053..7f7fe9ea0cb 100644 --- a/crates/rspack_plugin_context_replacement/src/lib.rs +++ b/crates/rspack_plugin_context_replacement/src/lib.rs @@ -1,5 +1,4 @@ use derivative::Derivative; -use futures::future::BoxFuture; use rspack_core::{ AfterResolveResult, ApplyContext, BeforeResolveResult, CompilerOptions, ContextModuleFactoryAfterResolve, ContextModuleFactoryBeforeResolve, Plugin, PluginContext, @@ -8,20 +7,11 @@ use rspack_error::Result; use rspack_hook::{plugin, plugin_hook}; use rspack_regex::RspackRegex; -enum ResolveResult { - Before(BeforeResolveResult), - After(AfterResolveResult), -} - -pub type ContentCallback = - Box BoxFuture<'static, Result<()>> + Sync + Send>; - pub struct ContextReplacementPluginOptions { - resource_reg_exp: RspackRegex, - new_content_resource: Option, - new_content_recursive: Option, - new_content_reg_exp: Option, - new_content_callback: Option, + pub resource_reg_exp: RspackRegex, + pub new_content_resource: Option, + pub new_content_recursive: Option, + pub new_content_reg_exp: Option, } #[plugin] @@ -32,8 +22,6 @@ pub struct ContextReplacementPlugin { new_content_resource: Option, new_content_recursive: Option, new_content_reg_exp: Option, - #[derivative(Debug = "ignore")] - new_content_callback: Option, } impl ContextReplacementPlugin { @@ -43,7 +31,6 @@ impl ContextReplacementPlugin { options.new_content_resource, options.new_content_recursive, options.new_content_reg_exp, - options.new_content_callback, ) } } @@ -61,13 +48,13 @@ async fn cmf_before_resolve(&self, mut result: BeforeResolveResult) -> Result Result Fn(PathData) -> BoxFuture<'static, Result> + Sync + Send>; +type AppendFn = Box BoxFuture<'static, Result> + Sync + Send>; pub enum Append { String(String),