Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: implement CircularDependencyRspackPlugin #8876

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 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 Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ rspack_napi_macros = { version = "0.2.0", path = "crates/rsp
rspack_paths = { version = "0.2.0", path = "crates/rspack_paths" }
rspack_plugin_asset = { version = "0.2.0", path = "crates/rspack_plugin_asset" }
rspack_plugin_banner = { version = "0.2.0", path = "crates/rspack_plugin_banner" }
rspack_plugin_circular_dependencies = { version = "0.2.0", path = "crates/rspack_plugin_circular_dependencies" }
rspack_plugin_context_replacement = { version = "0.2.0", path = "crates/rspack_plugin_context_replacement" }
rspack_plugin_copy = { version = "0.2.0", path = "crates/rspack_plugin_copy" }
rspack_plugin_css = { version = "0.2.0", path = "crates/rspack_plugin_css" }
Expand Down
12 changes: 12 additions & 0 deletions crates/node_binding/binding.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -363,6 +363,7 @@ export declare enum BuiltinPluginName {
LightningCssMinimizerRspackPlugin = 'LightningCssMinimizerRspackPlugin',
BundlerInfoRspackPlugin = 'BundlerInfoRspackPlugin',
CssExtractRspackPlugin = 'CssExtractRspackPlugin',
CircularDependencyRspackPlugin = 'CircularDependencyRspackPlugin',
JsLoaderRspackPlugin = 'JsLoaderRspackPlugin',
LazyCompilationPlugin = 'LazyCompilationPlugin'
}
Expand Down Expand Up @@ -1211,6 +1212,17 @@ export interface RawCacheOptions {
type: string
}

export interface RawCircularDependencyRspackPluginOptions {
failOnError?: boolean
allowAsyncCycles?: boolean
exclude?: RspackRegex
ignoredConnections?: Array<[ConnectionPattern, ConnectionPattern]>
onDetected?: (entrypoint: Module, modules: string[], compilation: Compilation) => void
onIgnored?: (entrypoint: Module, modules: string[], compilation: Compilation) => void
onStart?: (compilation: Compilation) => void
onEnd?: (compilation: Compilation) => void
}

export interface RawConsumeOptions {
key: string
import?: string
Expand Down
1 change: 1 addition & 0 deletions crates/rspack_binding_values/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ rspack_loader_swc = { workspace = true }
rspack_loader_testing = { workspace = true }
rspack_plugin_asset = { workspace = true }
rspack_plugin_banner = { workspace = true }
rspack_plugin_circular_dependencies = { workspace = true }
rspack_plugin_context_replacement = { workspace = true }
rspack_plugin_copy = { workspace = true }
rspack_plugin_css = { workspace = true }
Expand Down
10 changes: 10 additions & 0 deletions crates/rspack_binding_values/src/raw_options/raw_builtins/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
mod raw_banner;
mod raw_bundle_info;
mod raw_circular_dependency;
mod raw_copy;
mod raw_css_extract;
mod raw_dll;
Expand Down Expand Up @@ -29,6 +30,7 @@ use rspack_ids::{
use rspack_napi::NapiResultExt;
use rspack_plugin_asset::AssetPlugin;
use rspack_plugin_banner::BannerPlugin;
use rspack_plugin_circular_dependencies::CircularDependencyRspackPlugin;
use rspack_plugin_context_replacement::ContextReplacementPlugin;
use rspack_plugin_copy::{CopyRspackPlugin, CopyRspackPluginOptions};
use rspack_plugin_css::CssPlugin;
Expand Down Expand Up @@ -85,6 +87,7 @@ use rspack_plugin_worker::WorkerPlugin;

pub use self::{
raw_banner::RawBannerPluginOptions,
raw_circular_dependency::RawCircularDependencyRspackPluginOptions,
raw_copy::RawCopyRspackPluginOptions,
raw_dll::{RawDllEntryPluginOptions, RawLibManifestPluginOptions},
raw_html::RawHtmlRspackPluginOptions,
Expand Down Expand Up @@ -192,6 +195,7 @@ pub enum BuiltinPluginName {
LightningCssMinimizerRspackPlugin,
BundlerInfoRspackPlugin,
CssExtractRspackPlugin,
CircularDependencyRspackPlugin,

// rspack js adapter plugins
// naming format follow XxxRspackPlugin
Expand Down Expand Up @@ -514,6 +518,12 @@ impl BuiltinPlugin {
.boxed();
plugins.push(plugin);
}
BuiltinPluginName::CircularDependencyRspackPlugin => plugins.push(
CircularDependencyRspackPlugin::new(
downcast_into::<RawCircularDependencyRspackPluginOptions>(self.options)?.into(),
)
.boxed(),
),
BuiltinPluginName::JsLoaderRspackPlugin => {
plugins
.push(JsLoaderRspackPlugin::new(downcast_into::<JsLoaderRunner>(self.options)?).boxed());
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
use std::sync::Arc;

use napi::{Either, JsUnknown};
use napi_derive::napi;
use rspack_napi::threadsafe_function::ThreadsafeFunction;
use rspack_plugin_circular_dependencies::{
CircularDependencyIgnoredConnection, CircularDependencyIgnoredConnectionEntry,
CircularDependencyRspackPluginOptions, CompilationHookFn, CycleHandlerFn,
};
use rspack_regex::RspackRegex;

use crate::JsCompilationWrapper;

fn ignore_pattern_to_entry(
pattern: Either<String, RspackRegex>,
) -> CircularDependencyIgnoredConnectionEntry {
match pattern {
Either::A(string) => CircularDependencyIgnoredConnectionEntry::String(string),
Either::B(pattern) => CircularDependencyIgnoredConnectionEntry::Pattern(pattern),
}
}

type ConnectionPattern = Either<String, RspackRegex>;
type CycleHookParams = (String, Vec<String>, JsCompilationWrapper);

#[derive(Debug)]
#[napi(object, object_to_js = false)]
pub struct RawCircularDependencyRspackPluginOptions {
pub fail_on_error: Option<bool>,
pub allow_async_cycles: Option<bool>,
pub exclude: Option<RspackRegex>,
pub ignored_connections: Option<Vec<(ConnectionPattern, ConnectionPattern)>>,
#[napi(ts_type = "(entrypoint: Module, modules: string[], compilation: Compilation) => void")]
pub on_detected: Option<ThreadsafeFunction<CycleHookParams, JsUnknown>>,
#[napi(ts_type = "(entrypoint: Module, modules: string[], compilation: Compilation) => void")]
pub on_ignored: Option<ThreadsafeFunction<CycleHookParams, JsUnknown>>,
#[napi(ts_type = "(compilation: Compilation) => void")]
pub on_start: Option<ThreadsafeFunction<JsCompilationWrapper, JsUnknown>>,
#[napi(ts_type = "(compilation: Compilation) => void")]
pub on_end: Option<ThreadsafeFunction<JsCompilationWrapper, JsUnknown>>,
}

impl From<RawCircularDependencyRspackPluginOptions> for CircularDependencyRspackPluginOptions {
fn from(value: RawCircularDependencyRspackPluginOptions) -> Self {
// This explicit cast is needed because Rust otherwise infers an incompatible type
// for the closure compared to the field in the options object.
let on_detected: Option<CycleHandlerFn> = match value.on_detected {
Some(callback) => Some(Arc::new(move |entrypoint, modules, compilation| {
callback.blocking_call_with_sync((
entrypoint,
modules,
JsCompilationWrapper::new(compilation),
))?;
Ok(())
})),
_ => None,
};
let on_ignored: Option<CycleHandlerFn> = match value.on_ignored {
Some(callback) => Some(Arc::new(move |entrypoint, modules, compilation| {
callback.blocking_call_with_sync((
entrypoint,
modules,
JsCompilationWrapper::new(compilation),
))?;
Ok(())
})),
_ => None,
};
let on_start: Option<CompilationHookFn> = match value.on_start {
Some(callback) => Some(Arc::new(move |compilation| {
callback.blocking_call_with_sync(JsCompilationWrapper::new(compilation))?;
Ok(())
})),
_ => None,
};
let on_end: Option<CompilationHookFn> = match value.on_end {
Some(callback) => Some(Arc::new(move |compilation| {
callback.blocking_call_with_sync(JsCompilationWrapper::new(compilation))?;
Ok(())
})),
_ => None,
};

Self {
fail_on_error: value.fail_on_error.unwrap_or(false),
allow_async_cycles: value.allow_async_cycles.unwrap_or(false),
exclude: value.exclude,
ignored_connections: value.ignored_connections.map(|connections| {
connections
.into_iter()
.map(|(from, to)| {
CircularDependencyIgnoredConnection(
ignore_pattern_to_entry(from),
ignore_pattern_to_entry(to),
)
})
.collect()
}),
on_detected,
on_ignored,
on_start,
on_end,
}
}
}
20 changes: 20 additions & 0 deletions crates/rspack_plugin_circular_dependencies/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
[package]
description = "rspack circular dependency detection plugin"
edition = "2021"
license = "MIT"
name = "rspack_plugin_circular_dependencies"
repository = "https://github.com/web-infra-dev/rspack"
version = "0.2.0"

[dependencies]
derive_more = { workspace = true, features = ["debug"] }
itertools = { workspace = true }
rspack_collections = { workspace = true }
rspack_core = { workspace = true }
rspack_error = { workspace = true }
rspack_hook = { workspace = true }
rspack_regex = { workspace = true }
tracing = { workspace = true }

[package.metadata.cargo-shear]
ignored = ["tracing"]
Loading
Loading