Skip to content

Commit

Permalink
feat: init Rust side ContextReplacementPlugin
Browse files Browse the repository at this point in the history
  • Loading branch information
SyMind committed Sep 9, 2024
1 parent 56e2041 commit f113b53
Show file tree
Hide file tree
Showing 5 changed files with 202 additions and 1 deletion.
25 changes: 25 additions & 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/src/plugins/interceptor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1558,6 +1558,7 @@ impl ContextModuleFactoryAfterResolve for ContextModuleFactoryAfterResolveTap {
Some(r) => Some(r.try_into()?),
None => None,
},
recursive: todo!(),
};
Ok(AfterResolveResult::Data(Box::new(data)))
}
Expand Down
14 changes: 13 additions & 1 deletion crates/rspack_core/src/context_module_factory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ pub struct BeforeResolveData {
// context_dependencies
// create_data
// cacheable
pub recursive: bool,
pub reg_exp: Option<RspackRegex>,
}

#[derive(Clone)]
Expand All @@ -52,7 +54,7 @@ pub struct AfterResolveData {
// context_dependencies: HashSet<String>,
pub request: String,
// mode
// recursive: bool,
pub recursive: bool,
pub reg_exp: Option<RspackRegex>,
// namespace_object
// addon: String,
Expand Down Expand Up @@ -118,9 +120,18 @@ impl ContextModuleFactory {
&self,
data: &mut ModuleFactoryCreateData,
) -> Result<Option<ModuleFactoryResult>> {
let dependency = data
.dependency
.as_context_dependency()
.expect("should be context dependency");

let dependency_options = dependency.options();

let before_resolve_data = BeforeResolveData {
context: data.context.to_string(),
request: data.request().map(|r| r.to_string()),
recursive: dependency_options.recursive,
reg_exp: dependency_options.reg_exp.clone(),
};

match self
Expand Down Expand Up @@ -286,6 +297,7 @@ impl ContextModuleFactory {
context: context_options.context.clone(),
request: context_options.request.clone(),
reg_exp: context_options.reg_exp.clone(),
recursive: context_options.recursive,
};

match self
Expand Down
30 changes: 30 additions & 0 deletions crates/rspack_plugin_context_replacement/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
[package]
description = "rspack context replacement plugin"
edition = "2021"
license = "MIT"
name = "rspack_plugin_context_replacement"
repository = "https://github.com/web-infra-dev/rspack"
version = "0.1.0"
[dependencies]
dashmap = { workspace = true }
derivative = { workspace = true }
futures = { workspace = true }
glob = { workspace = true }
lazy_static = "1.4.0"
pathdiff = { workspace = true, features = ["camino"] }
regex = { workspace = true }
rspack_core = { version = "0.1.0", path = "../rspack_core" }
rspack_error = { version = "0.1.0", path = "../rspack_error" }
rspack_futures = { version = "0.1.0", path = "../rspack_futures" }
rspack_hash = { version = "0.1.0", path = "../rspack_hash" }
rspack_hook = { version = "0.1.0", path = "../rspack_hook" }
rspack_paths = { version = "0.1.0", path = "../rspack_paths" }
rspack_regex = { version = "0.1.0", path = "../rspack_regex" }
rspack_util = { version = "0.1.0", path = "../rspack_util" }
rustc-hash = { workspace = true }
sugar_path = { workspace = true }
tokio = { workspace = true, features = ["fs"] }
tracing = { workspace = true }

[package.metadata.cargo-shear]
ignored = ["tracing"]
133 changes: 133 additions & 0 deletions crates/rspack_plugin_context_replacement/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
use derivative::Derivative;
use futures::future::BoxFuture;
use rspack_core::{
AfterResolveResult, ApplyContext, BeforeResolveResult, CompilerOptions,
ContextModuleFactoryAfterResolve, ContextModuleFactoryBeforeResolve, Plugin, PluginContext,
};
use rspack_error::Result;
use rspack_hook::{plugin, plugin_hook};
use rspack_regex::RspackRegex;

enum ResolveResult {
Before(BeforeResolveResult),
After(AfterResolveResult),
}

pub type ContentCallback =
Box<dyn Fn(&mut ResolveResult) -> BoxFuture<'static, Result<()>> + Sync + Send>;

pub struct ContextReplacementPluginOptions {
resource_reg_exp: RspackRegex,
new_content_resource: Option<String>,
new_content_recursive: Option<bool>,
new_content_reg_exp: Option<RspackRegex>,
new_content_callback: Option<ContentCallback>,
}

#[plugin]
#[derive(Derivative)]
#[derivative(Debug)]
pub struct ContextReplacementPlugin {
resource_reg_exp: RspackRegex,
new_content_resource: Option<String>,
new_content_recursive: Option<bool>,
new_content_reg_exp: Option<RspackRegex>,
#[derivative(Debug = "ignore")]
new_content_callback: Option<ContentCallback>,
}

impl ContextReplacementPlugin {
pub fn new(options: ContextReplacementPluginOptions) -> Self {
Self::new_inner(
options.resource_reg_exp,
options.new_content_resource,
options.new_content_recursive,
options.new_content_reg_exp,
options.new_content_callback,
)
}
}

#[plugin_hook(ContextModuleFactoryBeforeResolve for ContextReplacementPlugin)]
async fn cmf_before_resolve(&self, mut result: BeforeResolveResult) -> Result<BeforeResolveResult> {
if let BeforeResolveResult::Data(data) = &mut result {
if let Some(request) = &data.request {
if self.resource_reg_exp.test(request) {
data.request = self.new_content_resource.clone();
}
if let Some(new_content_recursive) = self.new_content_recursive {
data.recursive = new_content_recursive;
}
if let Some(new_content_reg_exp) = &self.new_content_reg_exp {
data.reg_exp = Some(new_content_reg_exp.clone());
}
if let Some(new_content_callback) = &self.new_content_callback {
// new_content_callback(&mut result).await?;
} else {
// for (const d of result.dependencies) {
// if (d.critical) d.critical = false;
// }
}
}
}

Ok(result)
}

#[plugin_hook(ContextModuleFactoryAfterResolve for ContextReplacementPlugin)]
async fn cmf_after_resolve(&self, mut result: AfterResolveResult) -> Result<AfterResolveResult> {
if let AfterResolveResult::Data(data) = &mut result {
if self.resource_reg_exp.test(data.resource.as_str()) {
if let Some(new_content_resource) = &self.new_content_resource {
if new_content_resource.starts_with('/') || new_content_resource.chars().nth(1) == Some(':')
{
data.resource = new_content_resource.clone().into();
} else {
// result.resource = join(
// /** @type {InputFileSystem} */ (compiler.inputFileSystem),
// result.resource,
// newContentResource
// );
}
}
if let Some(new_content_recursive) = self.new_content_recursive {
data.recursive = new_content_recursive;
}
if let Some(new_content_reg_exp) = &self.new_content_reg_exp {
data.reg_exp = Some(new_content_reg_exp.clone());
}
if let Some(new_content_callback) = &self.new_content_callback {
// new_content_callback(&mut result).await?;
} else {
// for (const d of result.dependencies) {
// if (d.critical) d.critical = false;
// }
}
}
}
Ok(result)
}

impl Plugin for ContextReplacementPlugin {
fn name(&self) -> &'static str {
"rspack.ContextReplacementPlugin"
}

fn apply(
&self,
ctx: PluginContext<&mut ApplyContext>,
_options: &mut CompilerOptions,
) -> Result<()> {
ctx
.context
.context_module_factory_hooks
.before_resolve
.tap(cmf_before_resolve::new(self));
ctx
.context
.context_module_factory_hooks
.after_resolve
.tap(cmf_after_resolve::new(self));
Ok(())
}
}

0 comments on commit f113b53

Please sign in to comment.