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: support dependencies in resolve hook callback #7949

Merged
merged 11 commits into from
Oct 10, 2024
Merged
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
33 changes: 21 additions & 12 deletions crates/node_binding/binding.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export class ExternalObject<T> {
}
}
export class DependenciesBlockDto {
get dependencies(): Array<DependencyDto>
get dependencies(): Array<JsDependency>
get blocks(): Array<DependenciesBlockDto>
}
export type DependenciesBlockDTO = DependenciesBlockDto
Expand All @@ -41,16 +41,9 @@ export class DependenciesDto {
}
export type DependenciesDTO = DependenciesDto

export class DependencyDto {
get type(): string
get category(): string
get request(): string | undefined
}
export type DependencyDTO = DependencyDto

export class EntryDataDto {
get dependencies(): Array<DependencyDTO>
get includeDependencies(): Array<DependencyDTO>
get dependencies(): Array<JsDependency>
get includeDependencies(): Array<JsDependency>
get options(): EntryOptionsDto
}
export type EntryDataDTO = EntryDataDto
Expand Down Expand Up @@ -132,6 +125,7 @@ export class JsContextModuleFactoryAfterResolveData {
set regExp(rawRegExp: RawRegex | undefined)
get recursive(): boolean
set recursive(recursive: boolean)
get dependencies(): Array<JsDependencyMut>
}

export class JsContextModuleFactoryBeforeResolveData {
Expand All @@ -145,6 +139,21 @@ export class JsContextModuleFactoryBeforeResolveData {
set recursive(recursive: boolean)
}

export class JsDependency {
get type(): string
get category(): string
get request(): string | undefined
get critical(): boolean
}

export class JsDependencyMut {
get type(): string
get category(): string
get request(): string | undefined
get critical(): boolean
set critical(val: boolean)
}

export class JsEntries {
clear(): void
get size(): number
Expand Down Expand Up @@ -526,8 +535,8 @@ export interface JsDiagnosticLocation {
}

export interface JsEntryData {
dependencies: Array<DependencyDTO>
includeDependencies: Array<DependencyDTO>
dependencies: Array<JsDependency>
includeDependencies: Array<JsDependency>
options: JsEntryOptions
}

Expand Down
45 changes: 21 additions & 24 deletions crates/rspack_binding_values/src/compilation/entries.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use napi_derive::napi;
use rspack_core::{ChunkLoading, Compilation, EntryData, EntryOptions, EntryRuntime};
use rspack_napi::napi::bindgen_prelude::*;

use crate::{dependency::DependencyDTO, entry::JsEntryOptions, library::JsLibraryOptions};
use crate::{dependency::JsDependency, entry::JsEntryOptions, library::JsLibraryOptions};

#[napi]
pub struct EntryOptionsDTO(EntryOptions);
Expand Down Expand Up @@ -152,8 +152,8 @@ impl EntryOptionsDTO {

#[napi(object, object_to_js = false)]
pub struct JsEntryData {
pub dependencies: Vec<ClassInstance<DependencyDTO>>,
pub include_dependencies: Vec<ClassInstance<DependencyDTO>>,
pub dependencies: Vec<ClassInstance<JsDependency>>,
pub include_dependencies: Vec<ClassInstance<JsDependency>>,
pub options: JsEntryOptions,
}

Expand All @@ -163,12 +163,12 @@ impl From<JsEntryData> for EntryData {
dependencies: value
.dependencies
.into_iter()
.map(|dep| dep.dependency_id)
.map(|dep| *dep.id())
.collect::<Vec<_>>(),
include_dependencies: value
.include_dependencies
.into_iter()
.map(|dep| dep.dependency_id)
.map(|dep| *dep.id())
.collect::<Vec<_>>(),
options: value.options.into(),
}
Expand All @@ -184,36 +184,33 @@ pub struct EntryDataDTO {
#[napi]
impl EntryDataDTO {
#[napi(getter)]
pub fn dependencies(&'static self, env: Env) -> Result<Vec<ClassInstance<DependencyDTO>>> {
pub fn dependencies(&'static self) -> Vec<JsDependency> {
let module_graph = self.compilation.get_module_graph();
self
.entry_data
.dependencies
.clone()
.into_iter()
.map(|id| {
let js_dep = DependencyDTO::new(id, self.compilation);
let instance = js_dep.into_instance(env)?;
Ok(instance)
.iter()
.map(|dependency_id| {
#[allow(clippy::unwrap_used)]
let dep = module_graph.dependency_by_id(dependency_id).unwrap();
JsDependency::new(dep)
})
.collect::<Result<Vec<ClassInstance<DependencyDTO>>>>()
.collect::<Vec<_>>()
}

#[napi(getter)]
pub fn include_dependencies(
&'static self,
env: Env,
) -> Result<Vec<ClassInstance<DependencyDTO>>> {
pub fn include_dependencies(&'static self) -> Vec<JsDependency> {
let module_graph = self.compilation.get_module_graph();
self
.entry_data
.include_dependencies
.clone()
.into_iter()
.map(|id| {
let js_dep = DependencyDTO::new(id, self.compilation);
let instance = js_dep.into_instance(env)?;
Ok(instance)
.iter()
.map(|dependency_id| {
#[allow(clippy::unwrap_used)]
let dep = module_graph.dependency_by_id(dependency_id).unwrap();
JsDependency::new(dep)
})
.collect::<Result<Vec<ClassInstance<DependencyDTO>>>>()
.collect::<Vec<_>>()
}

#[napi(getter)]
Expand Down
12 changes: 11 additions & 1 deletion crates/rspack_binding_values/src/context_module_factory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use napi::bindgen_prelude::{
use napi_derive::napi;
use rspack_core::{AfterResolveData, BeforeResolveData};

use crate::RawRegex;
use crate::{JsDependencyMut, RawRegex};

#[napi]
pub struct JsContextModuleFactoryBeforeResolveData(Box<BeforeResolveData>);
Expand Down Expand Up @@ -173,6 +173,16 @@ impl JsContextModuleFactoryAfterResolveData {
pub fn set_recursive(&mut self, recursive: bool) {
self.0.recursive = recursive;
}

#[napi(getter)]
pub fn dependencies(&mut self) -> Vec<JsDependencyMut> {
self
.0
.dependencies
.iter_mut()
.map(JsDependencyMut::new)
.collect::<Vec<_>>()
}
}

pub struct JsContextModuleFactoryAfterResolveDataWrapper(Box<AfterResolveData>);
Expand Down
111 changes: 81 additions & 30 deletions crates/rspack_binding_values/src/dependency.rs
Original file line number Diff line number Diff line change
@@ -1,57 +1,108 @@
use napi_derive::napi;
use rspack_core::{Compilation, Dependency, DependencyId, ModuleDependency, ModuleGraph};
use rspack_core::{BoxDependency, DependencyId};

// JsDependency allows JS-side access to a Dependency instance that has already
// been processed and stored in the Compilation.
#[napi]
pub struct DependencyDTO {
pub(crate) dependency_id: DependencyId,
pub(crate) compilation: &'static Compilation,
pub struct JsDependency(&'static BoxDependency);

impl JsDependency {
pub(crate) fn new(dependency: &BoxDependency) -> Self {
// SAFETY:
// The lifetime of the &mut BoxDependency reference is extended to 'static.
// Accessing fields and methods on the Rust object from the JS side after the Rust object's
// lifetime has ended is undefined behavior, which we currently disregard.
let dependency =
unsafe { std::mem::transmute::<&BoxDependency, &'static BoxDependency>(dependency) };
Self(dependency)
}

pub(crate) fn id(&self) -> &DependencyId {
self.0.id()
}
}

impl DependencyDTO {
pub(crate) fn new(dependency_id: DependencyId, compilation: &'static Compilation) -> Self {
Self {
dependency_id,
compilation,
#[napi]
impl JsDependency {
#[napi(getter)]
pub fn get_type(&self) -> &str {
self.0.dependency_type().as_str()
}

#[napi(getter)]
pub fn category(&self) -> &str {
self.0.category().as_str()
}

#[napi(getter)]
pub fn request(&self) -> napi::Either<&str, ()> {
match self.0.as_module_dependency() {
Some(dep) => napi::Either::A(dep.request()),
None => napi::Either::B(()),
}
}

fn dependency<'a>(&self, module_graph: &'a ModuleGraph) -> &'a dyn Dependency {
module_graph
.dependency_by_id(&self.dependency_id)
.unwrap_or_else(|| panic!("Failed to get dependency by id = {:?}", &self.dependency_id))
.as_ref()
#[napi(getter)]
pub fn critical(&self) -> bool {
match self.0.as_context_dependency() {
Some(dep) => dep.critical().is_some(),
None => false,
}
}
}

fn module_dependency<'a>(
&self,
module_graph: &'a ModuleGraph,
) -> Option<&'a dyn ModuleDependency> {
self.dependency(module_graph).as_module_dependency()
// JsDependency represents a Dependency instance that is currently being processed.
// It is in the make stage and has not yet been added to the Compilation.
#[napi]
pub struct JsDependencyMut(&'static mut BoxDependency);

impl JsDependencyMut {
pub(crate) fn new(dependency: &mut BoxDependency) -> Self {
// SAFETY:
// The lifetime of the &mut BoxDependency reference is extended to 'static.
// Accessing fields and methods on the Rust object from the JS side after the Rust object's
// lifetime has ended is undefined behavior, which we currently disregard.
let dependency =
unsafe { std::mem::transmute::<&mut BoxDependency, &'static mut BoxDependency>(dependency) };
Self(dependency)
}
}

#[napi]
impl DependencyDTO {
impl JsDependencyMut {
#[napi(getter)]
pub fn get_type(&self) -> &str {
let module_graph = self.compilation.get_module_graph();
let dep = self.dependency(&module_graph);
dep.dependency_type().as_str()
self.0.dependency_type().as_str()
}

#[napi(getter)]
pub fn category(&self) -> &str {
let module_graph = self.compilation.get_module_graph();
let dep = self.dependency(&module_graph);
dep.category().as_str()
self.0.category().as_str()
}

#[napi(getter)]
pub fn request(&self) -> napi::Either<String, ()> {
let module_graph = self.compilation.get_module_graph();
match self.module_dependency(&module_graph) {
Some(dep) => napi::Either::A(dep.request().to_string()),
pub fn request(&self) -> napi::Either<&str, ()> {
match self.0.as_module_dependency() {
Some(dep) => napi::Either::A(dep.request()),
None => napi::Either::B(()),
}
}

#[napi(getter)]
pub fn critical(&self) -> bool {
match self.0.as_context_dependency() {
Some(dep) => dep.critical().is_some(),
None => false,
}
}

#[napi(setter)]
pub fn set_critical(&mut self, val: bool) {
if let Some(dep) = self.0.as_context_dependency_mut() {
let critical = dep.critical_mut();
if !val {
*critical = None;
}
}
}
}
2 changes: 1 addition & 1 deletion crates/rspack_binding_values/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ pub use chunk_group::*;
pub use codegen_result::*;
pub use compilation::*;
pub use context_module_factory::*;
pub use dependency::DependencyDTO;
pub use dependency::*;
pub use filename::*;
pub use html::*;
pub use module::*;
Expand Down
11 changes: 7 additions & 4 deletions crates/rspack_binding_values/src/module.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use rustc_hash::FxHashMap as HashMap;
use sys::napi_env;

use super::{JsCompatSource, ToJsCompatSource};
use crate::{DependencyDTO, JsChunk, JsCodegenerationResults};
use crate::{JsChunk, JsCodegenerationResults, JsDependency};

#[derive(Default)]
#[napi(object)]
Expand Down Expand Up @@ -52,14 +52,17 @@ impl DependenciesBlockDTO {
#[napi]
impl DependenciesBlockDTO {
#[napi(getter)]
pub fn dependencies(&self) -> Vec<DependencyDTO> {
pub fn dependencies(&self) -> Vec<JsDependency> {
let module_graph = self.compilation.get_module_graph();
let block = self.block(&module_graph);
block
.get_dependencies()
.iter()
.cloned()
.map(|dep_id| DependencyDTO::new(dep_id, self.compilation))
.map(|dependency_id| {
#[allow(clippy::unwrap_used)]
let dep = module_graph.dependency_by_id(dependency_id).unwrap();
JsDependency::new(dep)
})
.collect::<Vec<_>>()
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,15 @@ class Plugin {
resolveData.regExp = /[/\\](en(\.js)?|zh(\.js)?)$/;
return resolveData;
}
for (const d of resolveData.dependencies) {
if (d.critical) d.critical = false;
}
});
}
);
}
}

/**@type {import("@rspack/core").Configuration}*/
module.exports = {
context: __dirname,
Expand Down
Loading
Loading