Skip to main content

rspack_plugin_ignore/
lib.rs

1use derive_more::Debug;
2use futures::future::BoxFuture;
3use rspack_core::{
4  BeforeResolveResult, ContextModuleFactoryBeforeResolve, ModuleFactoryCreateData,
5  NormalModuleFactoryBeforeResolve, Plugin,
6};
7use rspack_error::Result;
8use rspack_hook::{plugin, plugin_hook};
9use rspack_regex::RspackRegex;
10
11pub type CheckResourceFn =
12  Box<dyn for<'a> Fn(&'a str, &'a str) -> BoxFuture<'a, Result<bool>> + Sync + Send>;
13
14pub enum CheckResourceContent {
15  Fn(CheckResourceFn),
16}
17
18#[derive(Debug)]
19pub struct IgnorePluginOptions {
20  pub resource_reg_exp: Option<RspackRegex>,
21  pub context_reg_exp: Option<RspackRegex>,
22  #[debug(skip)]
23  pub check_resource: Option<CheckResourceContent>,
24}
25
26#[plugin]
27#[derive(Debug)]
28pub struct IgnorePlugin {
29  options: IgnorePluginOptions,
30}
31
32impl IgnorePlugin {
33  pub fn new(options: IgnorePluginOptions) -> Self {
34    Self::new_inner(options)
35  }
36
37  async fn check_ignore(&self, request: &str, context: &str) -> Result<Option<bool>> {
38    if let Some(check_resource) = &self.options.check_resource {
39      match check_resource {
40        CheckResourceContent::Fn(check) => match check(request, context).await {
41          Ok(true) => return Ok(Some(false)),
42          Err(err) => return Err(err.wrap_err("IgnorePlugin: failed to call `checkResource`")),
43          _ => {}
44        },
45      }
46    }
47
48    if let Some(resource_reg_exp) = &self.options.resource_reg_exp
49      && resource_reg_exp.test(request)
50    {
51      if let Some(context_reg_exp) = &self.options.context_reg_exp {
52        if context_reg_exp.test(context) {
53          return Ok(Some(false));
54        }
55      } else {
56        return Ok(Some(false));
57      }
58    }
59
60    Ok(None)
61  }
62}
63
64#[plugin_hook(NormalModuleFactoryBeforeResolve for IgnorePlugin)]
65async fn nmf_before_resolve(&self, data: &mut ModuleFactoryCreateData) -> Result<Option<bool>> {
66  self.check_ignore(&data.request, &data.context).await
67}
68
69#[plugin_hook(ContextModuleFactoryBeforeResolve for IgnorePlugin)]
70async fn cmf_before_resolve(&self, data: BeforeResolveResult) -> Result<BeforeResolveResult> {
71  match data {
72    BeforeResolveResult::Ignored => Ok(BeforeResolveResult::Ignored),
73    BeforeResolveResult::Data(d) => {
74      if let Some(false) = self.check_ignore(&d.request, &d.context).await? {
75        Ok(BeforeResolveResult::Ignored)
76      } else {
77        Ok(BeforeResolveResult::Data(d))
78      }
79    }
80  }
81}
82
83impl Plugin for IgnorePlugin {
84  fn name(&self) -> &'static str {
85    "IgnorePlugin"
86  }
87
88  fn apply(&self, ctx: &mut rspack_core::ApplyContext<'_>) -> Result<()> {
89    ctx
90      .normal_module_factory_hooks
91      .before_resolve
92      .tap(nmf_before_resolve::new(self));
93
94    ctx
95      .context_module_factory_hooks
96      .before_resolve
97      .tap(cmf_before_resolve::new(self));
98
99    Ok(())
100  }
101}