From e03536a5b907aa7b4073d3c9dae739507d481de5 Mon Sep 17 00:00:00 2001 From: Cong-Cong Date: Tue, 24 Dec 2024 11:50:55 +0800 Subject: [PATCH 01/37] feat: getBlockChunkGroup --- crates/node_binding/binding.d.ts | 1 + .../rspack_binding_values/src/chunk_graph.rs | 18 +++++++++++++++++- .../src/dependency_block.rs | 2 +- packages/rspack/src/ChunkGraph.ts | 9 +++++++++ 4 files changed, 28 insertions(+), 2 deletions(-) diff --git a/crates/node_binding/binding.d.ts b/crates/node_binding/binding.d.ts index d6cc6d81944..970bf3be3b2 100644 --- a/crates/node_binding/binding.d.ts +++ b/crates/node_binding/binding.d.ts @@ -76,6 +76,7 @@ export declare class JsChunkGraph { getChunkModulesIterableBySourceType(chunk: JsChunk, sourceType: string): JsModule[] getModuleChunks(module: JsModule): JsChunk[] getModuleId(jsModule: JsModule): string | null + getBlockChunkGroup(jsBlock: JsDependenciesBlock): JsChunkGroup | null } export declare class JsChunkGroup { diff --git a/crates/rspack_binding_values/src/chunk_graph.rs b/crates/rspack_binding_values/src/chunk_graph.rs index ab071c75df1..f9e10045e83 100644 --- a/crates/rspack_binding_values/src/chunk_graph.rs +++ b/crates/rspack_binding_values/src/chunk_graph.rs @@ -4,7 +4,9 @@ use napi::Result; use napi_derive::napi; use rspack_core::{ChunkGraph, Compilation, SourceType}; -use crate::{JsChunk, JsChunkWrapper, JsModule, JsModuleWrapper}; +use crate::{ + JsChunk, JsChunkGroupWrapper, JsChunkWrapper, JsDependenciesBlock, JsModule, JsModuleWrapper, +}; #[napi] pub struct JsChunkGraph { @@ -127,4 +129,18 @@ impl JsChunkGraph { .map(|module_id| module_id.as_str()), ) } + + #[napi(ts_return_type = "JsChunkGroup | null")] + pub fn get_block_chunk_group( + &self, + js_block: &JsDependenciesBlock, + ) -> napi::Result> { + let compilation = self.as_ref()?; + Ok( + compilation + .chunk_graph + .get_block_chunk_group(&js_block.block_id, &compilation.chunk_group_by_ukey) + .map(|chunk_group| JsChunkGroupWrapper::new(chunk_group.ukey, compilation)), + ) + } } diff --git a/crates/rspack_binding_values/src/dependency_block.rs b/crates/rspack_binding_values/src/dependency_block.rs index 3103ef75026..8165b7633cb 100644 --- a/crates/rspack_binding_values/src/dependency_block.rs +++ b/crates/rspack_binding_values/src/dependency_block.rs @@ -12,7 +12,7 @@ use crate::JsDependencyWrapper; #[napi] pub struct JsDependenciesBlock { - block_id: AsyncDependenciesBlockIdentifier, + pub(crate) block_id: AsyncDependenciesBlockIdentifier, compilation: NonNull, } diff --git a/packages/rspack/src/ChunkGraph.ts b/packages/rspack/src/ChunkGraph.ts index 9a43f0b5d7d..656868890b4 100644 --- a/packages/rspack/src/ChunkGraph.ts +++ b/packages/rspack/src/ChunkGraph.ts @@ -2,6 +2,8 @@ import type { JsChunkGraph } from "@rspack/binding"; import { Chunk } from "./Chunk"; import { Module } from "./Module"; +import { DependenciesBlock } from "./DependenciesBlock"; +import { ChunkGroup } from "./ChunkGroup"; export class ChunkGraph { #inner: JsChunkGraph; @@ -65,4 +67,11 @@ export class ChunkGraph { getModuleId(module: Module): string | null { return this.#inner.getModuleId(Module.__to_binding(module)); } + + getBlockChunkGroup(depBlock: DependenciesBlock): ChunkGroup | null { + const binding = this.#inner.getBlockChunkGroup( + DependenciesBlock.__to_binding(depBlock) + ); + return binding ? ChunkGroup.__from_binding(binding) : null; + } } From 7b7ff44df9b036f5d3fb9d731b1e031ed6edc473 Mon Sep 17 00:00:00 2001 From: Cong-Cong Date: Tue, 24 Dec 2024 11:58:29 +0800 Subject: [PATCH 02/37] feat: getParentModule --- crates/node_binding/binding.d.ts | 1 + crates/rspack_binding_values/src/module_graph.rs | 16 ++++++++++++++++ packages/rspack/src/ModuleGraph.ts | 7 +++++++ 3 files changed, 24 insertions(+) diff --git a/crates/node_binding/binding.d.ts b/crates/node_binding/binding.d.ts index 970bf3be3b2..b04845a4af7 100644 --- a/crates/node_binding/binding.d.ts +++ b/crates/node_binding/binding.d.ts @@ -244,6 +244,7 @@ export declare class JsModuleGraph { getConnection(dependency: JsDependency): JsModuleGraphConnection | null getOutgoingConnections(module: JsModule): JsModuleGraphConnection[] getIncomingConnections(module: JsModule): JsModuleGraphConnection[] + getParentModule(jsDependency: JsDependency): JsModule | null } export declare class JsModuleGraphConnection { diff --git a/crates/rspack_binding_values/src/module_graph.rs b/crates/rspack_binding_values/src/module_graph.rs index 408c6d86b47..531a98d3a82 100644 --- a/crates/rspack_binding_values/src/module_graph.rs +++ b/crates/rspack_binding_values/src/module_graph.rs @@ -155,4 +155,20 @@ impl JsModuleGraph { .collect::>(), ) } + + #[napi(ts_return_type = "JsModule | null")] + pub fn get_parent_module( + &self, + js_dependency: &JsDependency, + ) -> napi::Result> { + let (compilation, module_graph) = self.as_ref()?; + Ok( + match module_graph.get_parent_module(&js_dependency.dependency_id) { + Some(identifier) => compilation + .module_by_identifier(identifier) + .map(|module| JsModuleWrapper::new(module.as_ref(), compilation.id(), Some(compilation))), + None => None, + }, + ) + } } diff --git a/packages/rspack/src/ModuleGraph.ts b/packages/rspack/src/ModuleGraph.ts index bc7e87fc1c8..793bf3da457 100644 --- a/packages/rspack/src/ModuleGraph.ts +++ b/packages/rspack/src/ModuleGraph.ts @@ -27,6 +27,13 @@ export default class ModuleGraph { return binding ? Module.__from_binding(binding) : null; } + getParentModule(dependency: Dependency): Module | null { + const binding = this.#inner.getParentModule( + Dependency.__to_binding(dependency) + ); + return binding ? Module.__from_binding(binding) : null; + } + getIssuer(module: Module): Module | null { const binding = this.#inner.getIssuer(Module.__to_binding(module)); return binding ? Module.__from_binding(binding) : null; From 7080cef89a16e8381a3b7d2a154e608123c1303c Mon Sep 17 00:00:00 2001 From: Cong-Cong Date: Tue, 24 Dec 2024 14:30:49 +0800 Subject: [PATCH 03/37] fix: namedChunks --- crates/node_binding/binding.d.ts | 2 +- crates/rspack_binding_values/src/compilation/mod.rs | 2 +- packages/rspack/src/Compilation.ts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/node_binding/binding.d.ts b/crates/node_binding/binding.d.ts index 1690f5b6c03..f40a291df70 100644 --- a/crates/node_binding/binding.d.ts +++ b/crates/node_binding/binding.d.ts @@ -100,7 +100,7 @@ export declare class JsCompilation { getOptimizationBailout(): Array getChunks(): JsChunk[] getNamedChunkKeys(): Array - getNamedChunk(name: string): JsChunk + getNamedChunk(name: string): JsChunk | null getNamedChunkGroupKeys(): Array getNamedChunkGroup(name: string): JsChunkGroup setAssetSource(name: string, source: JsCompatSource): void diff --git a/crates/rspack_binding_values/src/compilation/mod.rs b/crates/rspack_binding_values/src/compilation/mod.rs index 1b879d92a6f..5b6a5f3e7c7 100644 --- a/crates/rspack_binding_values/src/compilation/mod.rs +++ b/crates/rspack_binding_values/src/compilation/mod.rs @@ -240,7 +240,7 @@ impl JsCompilation { Ok(compilation.named_chunks.keys().cloned().collect::>()) } - #[napi(ts_return_type = "JsChunk")] + #[napi(ts_return_type = "JsChunk | null")] pub fn get_named_chunk(&self, name: String) -> Result> { let compilation = self.as_ref()?; diff --git a/packages/rspack/src/Compilation.ts b/packages/rspack/src/Compilation.ts index 4b997c5457c..3e002947646 100644 --- a/packages/rspack/src/Compilation.ts +++ b/packages/rspack/src/Compilation.ts @@ -487,7 +487,7 @@ BREAKING CHANGE: Asset processing hooks in Compilation has been merged into a si get: (property: unknown) => { if (typeof property === "string") { const binding = this.#inner.getNamedChunk(property); - return Chunk.__from_binding(binding); + return binding ? Chunk.__from_binding(binding) : undefined; } } }); From 44c32f1de639cda6dd29fc125a0d3a4c3e938e5b Mon Sep 17 00:00:00 2001 From: Cong-Cong Date: Tue, 24 Dec 2024 16:02:50 +0800 Subject: [PATCH 04/37] fix: path join --- crates/rspack_core/src/compiler/mod.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/crates/rspack_core/src/compiler/mod.rs b/crates/rspack_core/src/compiler/mod.rs index c5dc2642121..9f37197a82e 100644 --- a/crates/rspack_core/src/compiler/mod.rs +++ b/crates/rspack_core/src/compiler/mod.rs @@ -354,7 +354,15 @@ impl Compiler { ) -> Result<()> { if let Some(source) = asset.get_source() { let (target_file, query) = filename.split_once('?').unwrap_or((filename, "")); - let file_path = output_path.join(target_file); + let file_path = { + let target_path = Utf8Path::new(target_file); + if target_path.is_absolute() { + output_path.join(target_path.strip_prefix("/").unwrap()) + } else { + output_path.join(target_path) + } + }; + self .output_filesystem .create_dir_all( From dc31e041b8a447d8baafa0cef6d873c17f7b8021 Mon Sep 17 00:00:00 2001 From: Cong-Cong Date: Tue, 24 Dec 2024 18:18:44 +0800 Subject: [PATCH 05/37] fix: global generator --- .../rspack_core/src/normal_module_factory.rs | 54 +++++++++++-------- 1 file changed, 33 insertions(+), 21 deletions(-) diff --git a/crates/rspack_core/src/normal_module_factory.rs b/crates/rspack_core/src/normal_module_factory.rs index 60ff0f7e479..81b0000e0dd 100644 --- a/crates/rspack_core/src/normal_module_factory.rs +++ b/crates/rspack_core/src/normal_module_factory.rs @@ -686,7 +686,7 @@ impl NormalModuleFactory { &self, module_type: &ModuleType, parser: Option, - generator: Option, + mut generator: Option, ) -> (Option, Option) { let global_parser = self .options @@ -714,12 +714,7 @@ impl NormalModuleFactory { } _ => p.get(module_type.as_str()).cloned(), }); - let global_generator = self - .options - .module - .generator - .as_ref() - .and_then(|g| g.get(module_type.as_str()).cloned()); + let parser = rspack_util::merge_from_optional_with( global_parser, parser.as_ref(), @@ -741,21 +736,38 @@ impl NormalModuleFactory { (global, _) => global, }, ); - let generator = rspack_util::merge_from_optional_with( - global_generator, - generator.as_ref(), - |global, local| match (&global, local) { - (GeneratorOptions::Asset(_), GeneratorOptions::Asset(_)) - | (GeneratorOptions::AssetInline(_), GeneratorOptions::AssetInline(_)) - | (GeneratorOptions::AssetResource(_), GeneratorOptions::AssetResource(_)) - | (GeneratorOptions::Css(_), GeneratorOptions::Css(_)) - | (GeneratorOptions::CssAuto(_), GeneratorOptions::CssAuto(_)) - | (GeneratorOptions::CssModule(_), GeneratorOptions::CssModule(_)) => { - global.merge_from(local) + + { + let module_type = module_type.as_str(); + for (index, c) in module_type.as_bytes().iter().enumerate() { + if *c == b'/' || index == module_type.len() - 1 { + let current = &module_type[..index]; + let global_generator = self + .options + .module + .generator + .as_ref() + .and_then(|g| g.get(current).cloned()); + + generator = rspack_util::merge_from_optional_with( + global_generator, + generator.as_ref(), + |global, local| match (&global, local) { + (GeneratorOptions::Asset(_), GeneratorOptions::Asset(_)) + | (GeneratorOptions::AssetInline(_), GeneratorOptions::AssetInline(_)) + | (GeneratorOptions::AssetResource(_), GeneratorOptions::AssetResource(_)) + | (GeneratorOptions::Css(_), GeneratorOptions::Css(_)) + | (GeneratorOptions::CssAuto(_), GeneratorOptions::CssAuto(_)) + | (GeneratorOptions::CssModule(_), GeneratorOptions::CssModule(_)) => { + global.merge_from(local) + } + _ => global, + }, + ); } - _ => global, - }, - ); + } + } + (parser, generator) } From 2ff8e89b329663b77413f8a7d96932d95be62520 Mon Sep 17 00:00:00 2001 From: Cong-Cong Date: Tue, 24 Dec 2024 20:28:34 +0800 Subject: [PATCH 06/37] feat: support module.libIdent --- crates/node_binding/binding.d.ts | 5 +++++ crates/rspack_binding_values/src/module.rs | 26 +++++++++++++++++++++- packages/rspack/src/Module.ts | 11 +++++++++ 3 files changed, 41 insertions(+), 1 deletion(-) diff --git a/crates/node_binding/binding.d.ts b/crates/node_binding/binding.d.ts index f40a291df70..5c792d2ca3c 100644 --- a/crates/node_binding/binding.d.ts +++ b/crates/node_binding/binding.d.ts @@ -233,6 +233,7 @@ export declare class JsModule { size(ty?: string | undefined | null): number get modules(): JsModule[] | undefined get useSourceMap(): boolean + libIdent(options: JsLibIdentOptions): string | null } export declare class JsModuleGraph { @@ -687,6 +688,10 @@ export interface JsHtmlPluginTag { asset?: string } +export interface JsLibIdentOptions { + context: string +} + export interface JsLibraryAuxiliaryComment { root?: string commonjs?: string diff --git a/crates/rspack_binding_values/src/module.rs b/crates/rspack_binding_values/src/module.rs index 7132f4dd432..b460d2cfd2f 100644 --- a/crates/rspack_binding_values/src/module.rs +++ b/crates/rspack_binding_values/src/module.rs @@ -1,10 +1,12 @@ use std::{cell::RefCell, ptr::NonNull, sync::Arc}; +use napi::JsString; use napi_derive::napi; use rspack_collections::IdentifierMap; use rspack_core::{ BuildMeta, BuildMetaDefaultObject, BuildMetaExportsType, Compilation, CompilationId, - ExportsArgument, Module, ModuleArgument, ModuleIdentifier, RuntimeModuleStage, SourceType, + ExportsArgument, LibIdentOptions, Module, ModuleArgument, ModuleIdentifier, RuntimeModuleStage, + SourceType, }; use rspack_napi::{napi::bindgen_prelude::*, threadsafe_function::ThreadsafeFunction, OneShotRef}; use rspack_plugin_runtime::RuntimeModuleFromJs; @@ -17,6 +19,11 @@ use crate::{ JsDependencyWrapper, ToJsCompatSource, }; +#[napi(object)] +pub struct JsLibIdentOptions { + pub context: String, +} + #[derive(Default)] #[napi(object)] pub struct JsFactoryMeta { @@ -276,6 +283,23 @@ impl JsModule { let module = self.as_ref()?; Ok(module.get_source_map_kind().source_map()) } + + #[napi] + pub fn lib_ident( + &mut self, + env: Env, + options: JsLibIdentOptions, + ) -> napi::Result> { + let module = self.as_ref()?; + Ok( + match module.lib_ident(LibIdentOptions { + context: &options.context, + }) { + Some(lib_ident) => Some(env.create_string(lib_ident.as_ref())?), + None => None, + }, + ) + } } type ModuleInstanceRefs = IdentifierMap>; diff --git a/packages/rspack/src/Module.ts b/packages/rspack/src/Module.ts index a36cb2d8205..bdf6d86126e 100644 --- a/packages/rspack/src/Module.ts +++ b/packages/rspack/src/Module.ts @@ -36,6 +36,13 @@ export type ResolveData = { createData?: CreateData; }; +export interface LibIdentOptions { + /** + * absolute context path to which lib ident is relative to + */ + context: string; +} + export class ContextModuleFactoryBeforeResolveData { #inner: JsContextModuleFactoryBeforeResolveData; @@ -367,6 +374,10 @@ export class Module { } return 0; } + + libIdent(options: LibIdentOptions): string | null { + return this.#inner.libIdent(options); + } } export class CodeGenerationResult { From c07560d173c096f9b75326a5b27536bc5f701e87 Mon Sep 17 00:00:00 2001 From: Cong-Cong Date: Wed, 25 Dec 2024 12:22:49 +0800 Subject: [PATCH 07/37] feat: layer support function --- .../src/raw_options/raw_split_chunks/mod.rs | 23 ++++++++++--------- .../rspack_plugin_split_chunks/src/common.rs | 4 ++-- .../src/plugin/module_group.rs | 2 +- 3 files changed, 15 insertions(+), 14 deletions(-) diff --git a/crates/rspack_binding_values/src/raw_options/raw_split_chunks/mod.rs b/crates/rspack_binding_values/src/raw_options/raw_split_chunks/mod.rs index 6740b3fa4d5..02327655505 100644 --- a/crates/rspack_binding_values/src/raw_options/raw_split_chunks/mod.rs +++ b/crates/rspack_binding_values/src/raw_options/raw_split_chunks/mod.rs @@ -6,6 +6,7 @@ mod raw_split_chunk_size; use std::sync::Arc; use derive_more::Debug; +use napi::bindgen_prelude::Either3; use napi::{Either, JsString}; use napi_derive::napi; use raw_split_chunk_name::normalize_raw_chunk_name; @@ -13,7 +14,7 @@ use raw_split_chunk_name::RawChunkOptionName; use rspack_core::Filename; use rspack_core::SourceType; use rspack_core::DEFAULT_DELIMITER; -use rspack_napi::string::JsStringExt; +use rspack_napi::{string::JsStringExt, threadsafe_function::ThreadsafeFunction}; use rspack_plugin_split_chunks::ChunkNameGetter; use rspack_regex::RspackRegex; @@ -76,7 +77,7 @@ pub struct RawCacheGroupOptions { pub r#type: Option>, #[napi(ts_type = "RegExp | string")] #[debug(skip)] - pub layer: Option>, + pub layer: Option, bool>>>, pub automatic_name_delimiter: Option, // pub max_async_requests: usize, // pub max_initial_requests: usize, @@ -130,6 +131,7 @@ impl From for rspack_plugin_split_chunks::PluginOptions { let overall_min_size = create_sizes(raw_opts.min_size); + println!("overall_min_size {:#?}", overall_min_size); let overall_max_size = create_sizes(raw_opts.max_size); let overall_max_async_size = create_sizes(raw_opts.max_async_size).merge(&overall_max_size); @@ -153,6 +155,7 @@ impl From for rspack_plugin_split_chunks::PluginOptions { } else { &overall_min_size }); + println!("min_size {:#?}", &min_size); let max_size = create_sizes(v.max_size); @@ -293,18 +296,15 @@ fn create_module_type_filter( } fn create_module_layer_filter( - raw: Either, + raw: Either3, bool>>, ) -> rspack_plugin_split_chunks::ModuleLayerFilter { match raw { - Either::A(regex) => Arc::new(move |m| { - m.get_layer() - .map(|layer| regex.test(layer)) - .unwrap_or_default() - }), - Either::B(js_str) => { + Either3::A(regex) => { + Arc::new(move |layer| layer.map(|layer| regex.test(&layer)).unwrap_or_default()) + } + Either3::B(js_str) => { let test = js_str.into_string(); - Arc::new(move |m| { - let layer = m.get_layer(); + Arc::new(move |layer| { if let Some(layer) = layer { layer.starts_with(&test) } else { @@ -312,5 +312,6 @@ fn create_module_layer_filter( } }) } + Either3::C(ts_fn) => Arc::new(move |layer| ts_fn.blocking_call_with_sync(layer).unwrap()), } } diff --git a/crates/rspack_plugin_split_chunks/src/common.rs b/crates/rspack_plugin_split_chunks/src/common.rs index 1b2f15a003a..742142408bf 100644 --- a/crates/rspack_plugin_split_chunks/src/common.rs +++ b/crates/rspack_plugin_split_chunks/src/common.rs @@ -9,13 +9,13 @@ use rustc_hash::{FxHashMap, FxHashSet}; pub type ChunkFilter = Arc Result + Send + Sync>; pub type ModuleTypeFilter = Arc bool + Send + Sync>; -pub type ModuleLayerFilter = Arc bool + Send + Sync>; +pub type ModuleLayerFilter = Arc) -> bool + Send + Sync>; pub fn create_default_module_type_filter() -> ModuleTypeFilter { Arc::new(|_| true) } -pub fn create_default_module_layer_filter() -> ModuleTypeFilter { +pub fn create_default_module_layer_filter() -> ModuleLayerFilter { Arc::new(|_| true) } diff --git a/crates/rspack_plugin_split_chunks/src/plugin/module_group.rs b/crates/rspack_plugin_split_chunks/src/plugin/module_group.rs index f88a7cfb730..46a973e7d16 100644 --- a/crates/rspack_plugin_split_chunks/src/plugin/module_group.rs +++ b/crates/rspack_plugin_split_chunks/src/plugin/module_group.rs @@ -337,7 +337,7 @@ impl SplitChunksPlugin { CacheGroupTest::Enabled => true, }; let is_match_the_type: bool = (cache_group.r#type)(module); - let is_match_the_layer: bool = (cache_group.layer)(module); + let is_match_the_layer: bool = (cache_group.layer)(module.get_layer().map(ToString::to_string)); let is_match = is_match_the_test && is_match_the_type && is_match_the_layer; if !is_match { tracing::trace!( From aa6ce641f961af9d2c00c2c228c7e80010057483 Mon Sep 17 00:00:00 2001 From: Cong-Cong Date: Wed, 25 Dec 2024 13:15:15 +0800 Subject: [PATCH 08/37] fix: get_resolved_module --- crates/rspack_binding_values/src/module_graph.rs | 9 +++------ .../src/raw_options/raw_split_chunks/mod.rs | 2 -- crates/rspack_core/src/module_graph/connection.rs | 2 ++ 3 files changed, 5 insertions(+), 8 deletions(-) diff --git a/crates/rspack_binding_values/src/module_graph.rs b/crates/rspack_binding_values/src/module_graph.rs index 531a98d3a82..454c6d03027 100644 --- a/crates/rspack_binding_values/src/module_graph.rs +++ b/crates/rspack_binding_values/src/module_graph.rs @@ -49,12 +49,9 @@ impl JsModuleGraph { let (compilation, module_graph) = self.as_ref()?; Ok( match module_graph.connection_by_dependency_id(&js_dependency.dependency_id) { - Some(connection) => match connection.resolved_original_module_identifier { - Some(identifier) => compilation.module_by_identifier(&identifier).map(|module| { - JsModuleWrapper::new(module.as_ref(), compilation.id(), Some(compilation)) - }), - None => None, - }, + Some(connection) => module_graph + .module_by_identifier(&connection.resolved_module) + .map(|module| JsModuleWrapper::new(module.as_ref(), compilation.id(), Some(compilation))), None => None, }, ) diff --git a/crates/rspack_binding_values/src/raw_options/raw_split_chunks/mod.rs b/crates/rspack_binding_values/src/raw_options/raw_split_chunks/mod.rs index 02327655505..fc735a9652e 100644 --- a/crates/rspack_binding_values/src/raw_options/raw_split_chunks/mod.rs +++ b/crates/rspack_binding_values/src/raw_options/raw_split_chunks/mod.rs @@ -131,7 +131,6 @@ impl From for rspack_plugin_split_chunks::PluginOptions { let overall_min_size = create_sizes(raw_opts.min_size); - println!("overall_min_size {:#?}", overall_min_size); let overall_max_size = create_sizes(raw_opts.max_size); let overall_max_async_size = create_sizes(raw_opts.max_async_size).merge(&overall_max_size); @@ -155,7 +154,6 @@ impl From for rspack_plugin_split_chunks::PluginOptions { } else { &overall_min_size }); - println!("min_size {:#?}", &min_size); let max_size = create_sizes(v.max_size); diff --git a/crates/rspack_core/src/module_graph/connection.rs b/crates/rspack_core/src/module_graph/connection.rs index a12b5756cae..839171065cc 100644 --- a/crates/rspack_core/src/module_graph/connection.rs +++ b/crates/rspack_core/src/module_graph/connection.rs @@ -11,6 +11,7 @@ pub struct ModuleGraphConnection { /// The referencing module identifier pub original_module_identifier: Option, pub resolved_original_module_identifier: Option, + pub resolved_module: ModuleIdentifier, /// The referenced module identifier module_identifier: ModuleIdentifier, @@ -46,6 +47,7 @@ impl ModuleGraphConnection { active, conditional, resolved_original_module_identifier: original_module_identifier, + resolved_module: module_identifier, } } From efd841507d91db32723c06f89b74d6306d63beaa Mon Sep 17 00:00:00 2001 From: Cong-Cong Date: Wed, 25 Dec 2024 13:49:44 +0800 Subject: [PATCH 09/37] feat: getParentBlockIndex --- crates/node_binding/binding.d.ts | 1 + crates/rspack_binding_values/src/module_graph.rs | 11 +++++++++++ .../cache/persistent/occasion/make/module_graph.rs | 3 ++- crates/rspack_core/src/compiler/make/repair/build.rs | 3 ++- crates/rspack_core/src/module_graph/mod.rs | 8 ++++++++ packages/rspack/src/ModuleGraph.ts | 4 ++++ 6 files changed, 28 insertions(+), 2 deletions(-) diff --git a/crates/node_binding/binding.d.ts b/crates/node_binding/binding.d.ts index 5c792d2ca3c..01fa30056ff 100644 --- a/crates/node_binding/binding.d.ts +++ b/crates/node_binding/binding.d.ts @@ -246,6 +246,7 @@ export declare class JsModuleGraph { getOutgoingConnections(module: JsModule): JsModuleGraphConnection[] getIncomingConnections(module: JsModule): JsModuleGraphConnection[] getParentModule(jsDependency: JsDependency): JsModule | null + getParentBlockIndex(jsDependency: JsDependency): number } export declare class JsModuleGraphConnection { diff --git a/crates/rspack_binding_values/src/module_graph.rs b/crates/rspack_binding_values/src/module_graph.rs index 454c6d03027..6235ffb1ec1 100644 --- a/crates/rspack_binding_values/src/module_graph.rs +++ b/crates/rspack_binding_values/src/module_graph.rs @@ -168,4 +168,15 @@ impl JsModuleGraph { }, ) } + + #[napi] + pub fn get_parent_block_index(&self, js_dependency: &JsDependency) -> napi::Result { + let (_, module_graph) = self.as_ref()?; + Ok( + match module_graph.get_parent_block_index(&js_dependency.dependency_id) { + Some(block_index) => block_index as i64, + None => -1, + }, + ) + } } diff --git a/crates/rspack_core/src/cache/persistent/occasion/make/module_graph.rs b/crates/rspack_core/src/cache/persistent/occasion/make/module_graph.rs index d5a9b3f40d3..7c473ee5a76 100644 --- a/crates/rspack_core/src/cache/persistent/occasion/make/module_graph.rs +++ b/crates/rspack_core/src/cache/persistent/occasion/make/module_graph.rs @@ -133,12 +133,13 @@ pub async fn recovery_module_graph( for (_, v) in storage.load(SCOPE).await? { let mut node: Node = from_bytes(&v, context).expect("unexpected module graph deserialize failed"); - for (dep, parent_block) in node.dependencies { + for (index_in_block, (dep, parent_block)) in node.dependencies.into_iter().enumerate() { mg.set_parents( *dep.id(), DependencyParents { block: parent_block, module: node.module.identifier(), + index_in_block, }, ); mg.add_dependency(dep); diff --git a/crates/rspack_core/src/compiler/make/repair/build.rs b/crates/rspack_core/src/compiler/make/repair/build.rs index 7ab85f2b7d5..325b556c2f4 100644 --- a/crates/rspack_core/src/compiler/make/repair/build.rs +++ b/crates/rspack_core/src/compiler/make/repair/build.rs @@ -155,7 +155,7 @@ impl Task for BuildResultTask { blocks: Vec>, current_block: Option>| -> Vec> { - for dependency in dependencies { + for (index_in_block, dependency) in dependencies.into_iter().enumerate() { let dependency_id = *dependency.id(); if current_block.is_none() { module.add_dependency_id(dependency_id); @@ -166,6 +166,7 @@ impl Task for BuildResultTask { DependencyParents { block: current_block.as_ref().map(|block| block.identifier()), module: module.identifier(), + index_in_block, }, ); module_graph.add_dependency(dependency); diff --git a/crates/rspack_core/src/module_graph/mod.rs b/crates/rspack_core/src/module_graph/mod.rs index 19236df33c8..4321ae59dca 100644 --- a/crates/rspack_core/src/module_graph/mod.rs +++ b/crates/rspack_core/src/module_graph/mod.rs @@ -34,6 +34,7 @@ pub struct DependencyExtraMeta { pub struct DependencyParents { pub block: Option, pub module: ModuleIdentifier, + pub index_in_block: usize, } #[derive(Debug, Default)] @@ -548,6 +549,13 @@ impl<'a> ModuleGraph<'a> { .as_ref() } + pub fn get_parent_block_index(&self, dependency_id: &DependencyId) -> Option { + self + .loop_partials(|p| p.dependency_id_to_parents.get(dependency_id))? + .as_ref() + .map(|p| p.index_in_block) + } + pub fn block_by_id( &self, block_id: &AsyncDependenciesBlockIdentifier, diff --git a/packages/rspack/src/ModuleGraph.ts b/packages/rspack/src/ModuleGraph.ts index 793bf3da457..e3e36970bf0 100644 --- a/packages/rspack/src/ModuleGraph.ts +++ b/packages/rspack/src/ModuleGraph.ts @@ -57,4 +57,8 @@ export default class ModuleGraph { .getOutgoingConnections(Module.__to_binding(module)) .map(binding => ModuleGraphConnection.__from_binding(binding)); } + + getParentBlockIndex(dependency: Dependency): number { + return this.#inner.getParentBlockIndex(Dependency.__to_binding(dependency)); + } } From f8d092a81182fbb9d9037867d74dc262099dd1e1 Mon Sep 17 00:00:00 2001 From: Cong-Cong Date: Wed, 25 Dec 2024 14:42:55 +0800 Subject: [PATCH 10/37] feat: dependency supports inheriting hierarchical information --- packages/rspack/src/Compilation.ts | 10 +-- packages/rspack/src/DependenciesBlock.ts | 6 +- packages/rspack/src/Dependency.ts | 67 ++++++++++++++----- packages/rspack/src/EntryDependency.ts | 7 ++ packages/rspack/src/Module.ts | 8 ++- packages/rspack/src/ModuleDependency.ts | 10 +++ packages/rspack/src/ModuleGraph.ts | 46 ++++++++----- packages/rspack/src/ModuleGraphConnection.ts | 7 +- .../rspack/src/builtin-plugin/EntryPlugin.ts | 10 +-- 9 files changed, 118 insertions(+), 53 deletions(-) create mode 100644 packages/rspack/src/EntryDependency.ts create mode 100644 packages/rspack/src/ModuleDependency.ts diff --git a/packages/rspack/src/Compilation.ts b/packages/rspack/src/Compilation.ts index 3e002947646..ed3bac96f86 100644 --- a/packages/rspack/src/Compilation.ts +++ b/packages/rspack/src/Compilation.ts @@ -24,7 +24,7 @@ import { ChunkGraph } from "./ChunkGraph"; import { ChunkGroup } from "./ChunkGroup"; import type { Compiler } from "./Compiler"; import type { ContextModuleFactory } from "./ContextModuleFactory"; -import { Dependency } from "./Dependency"; +import { bindingDependencyFactory, Dependency } from "./Dependency"; import { Entrypoint } from "./Entrypoint"; import { cutOffLoaderExecution } from "./ErrorHelpers"; import { type CodeGenerationResult, Module } from "./Module"; @@ -1352,9 +1352,11 @@ export class EntryData { } private constructor(binding: binding.JsEntryData) { - this.dependencies = binding.dependencies.map(Dependency.__from_binding); - this.includeDependencies = binding.includeDependencies.map( - Dependency.__from_binding + this.dependencies = binding.dependencies.map(d => + bindingDependencyFactory.create(Dependency, d) + ); + this.includeDependencies = binding.includeDependencies.map(d => + bindingDependencyFactory.create(Dependency, d) ); this.options = binding.options; } diff --git a/packages/rspack/src/DependenciesBlock.ts b/packages/rspack/src/DependenciesBlock.ts index 4ae6fbea569..941656ba688 100644 --- a/packages/rspack/src/DependenciesBlock.ts +++ b/packages/rspack/src/DependenciesBlock.ts @@ -1,5 +1,5 @@ import type { JsDependenciesBlock } from "@rspack/binding"; -import { Dependency } from "./Dependency"; +import { bindingDependencyFactory, Dependency } from "./Dependency"; export class DependenciesBlock { #binding: JsDependenciesBlock; @@ -22,7 +22,9 @@ export class DependenciesBlock { dependencies: { enumerable: true, get(): Dependency[] { - return binding.dependencies.map(d => Dependency.__from_binding(d)); + return binding.dependencies.map(d => + bindingDependencyFactory.create(Dependency, d) + ); } }, blocks: { diff --git a/packages/rspack/src/Dependency.ts b/packages/rspack/src/Dependency.ts index 4ce2d79eaea..06acc8151b2 100644 --- a/packages/rspack/src/Dependency.ts +++ b/packages/rspack/src/Dependency.ts @@ -1,50 +1,81 @@ import type { JsDependency } from "@rspack/binding"; -export class Dependency { - #inner: JsDependency; +const TO_BINDING_MAPPINGS = new WeakMap(); +const BINDING_MAPPINGS = new WeakMap(); - declare readonly type: string; - declare readonly category: string; - declare readonly request: string | undefined; - declare critical: boolean; +// internal object +export const bindingDependencyFactory = { + getBinding(dependency: Dependency): JsDependency | undefined { + return TO_BINDING_MAPPINGS.get(dependency); + }, - static __from_binding(binding: JsDependency): Dependency { - return new Dependency(binding); - } + setBinding(dependency: Dependency, binding: JsDependency) { + BINDING_MAPPINGS.set(binding, dependency); + TO_BINDING_MAPPINGS.set(dependency, binding); + }, - static __to_binding(data: Dependency): JsDependency { - return data.#inner; + create(ctor: typeof Dependency, binding: JsDependency): Dependency { + if (BINDING_MAPPINGS.has(binding)) { + return BINDING_MAPPINGS.get(binding)!; + } + const dependency = Object.create(ctor); + BINDING_MAPPINGS.set(binding, dependency); + TO_BINDING_MAPPINGS.set(dependency, binding); + return dependency; } +}; - private constructor(binding: JsDependency) { - this.#inner = binding; +export class Dependency { + declare readonly type: string; + declare readonly category: string; + declare readonly request: string | undefined; + declare critical: boolean; + constructor() { Object.defineProperties(this, { type: { enumerable: true, get(): string { - return binding.type; + const binding = bindingDependencyFactory.getBinding(this); + if (binding) { + return binding.type; + } + return "unknown"; } }, category: { enumerable: true, get(): string { - return binding.category; + const binding = bindingDependencyFactory.getBinding(this); + if (binding) { + return binding.category; + } + return "unknown"; } }, request: { enumerable: true, get(): string | undefined { - return binding.request; + const binding = bindingDependencyFactory.getBinding(this); + if (binding) { + return binding.request; + } } }, critical: { enumerable: true, get(): boolean { - return binding.critical; + const binding = bindingDependencyFactory.getBinding(this); + if (binding) { + return binding.critical; + } + return false; }, set(val: boolean) { - binding.critical = val; + const binding = bindingDependencyFactory.getBinding(this); + if (binding) { + binding.critical = val; + } } } }); diff --git a/packages/rspack/src/EntryDependency.ts b/packages/rspack/src/EntryDependency.ts new file mode 100644 index 00000000000..cefb9aae20d --- /dev/null +++ b/packages/rspack/src/EntryDependency.ts @@ -0,0 +1,7 @@ +import { ModuleDependency } from "./ModuleDependency"; + +export class EntryDependency extends ModuleDependency { + constructor(request: string) { + super(request); + } +} diff --git a/packages/rspack/src/Module.ts b/packages/rspack/src/Module.ts index bdf6d86126e..8485a168a46 100644 --- a/packages/rspack/src/Module.ts +++ b/packages/rspack/src/Module.ts @@ -10,7 +10,7 @@ import type { Source } from "webpack-sources"; import type { Compilation } from "./Compilation"; import { DependenciesBlock } from "./DependenciesBlock"; -import { Dependency } from "./Dependency"; +import { bindingDependencyFactory, Dependency } from "./Dependency"; import { JsSource } from "./util/source"; export type ResourceData = { @@ -182,7 +182,7 @@ export class ContextModuleFactoryAfterResolveData { enumerable: true, get(): Dependency[] { return binding.dependencies.map(dep => - Dependency.__from_binding(dep) + bindingDependencyFactory.create(Dependency, dep) ); } } @@ -336,7 +336,9 @@ export class Module { enumerable: true, get(): Dependency[] { if ("dependencies" in module) { - return module.dependencies.map(d => Dependency.__from_binding(d)); + return module.dependencies.map(d => + bindingDependencyFactory.create(Dependency, d) + ); } return []; } diff --git a/packages/rspack/src/ModuleDependency.ts b/packages/rspack/src/ModuleDependency.ts new file mode 100644 index 00000000000..ba3f1f3c9d8 --- /dev/null +++ b/packages/rspack/src/ModuleDependency.ts @@ -0,0 +1,10 @@ +import { Dependency } from "./Dependency"; + +export class ModuleDependency extends Dependency { + request: string; + + constructor(request: string) { + super(); + this.request = request; + } +} diff --git a/packages/rspack/src/ModuleGraph.ts b/packages/rspack/src/ModuleGraph.ts index e3e36970bf0..a849b90ef55 100644 --- a/packages/rspack/src/ModuleGraph.ts +++ b/packages/rspack/src/ModuleGraph.ts @@ -1,5 +1,5 @@ import type { JsModuleGraph } from "@rspack/binding"; -import { Dependency } from "./Dependency"; +import { bindingDependencyFactory, Dependency } from "./Dependency"; import { ExportsInfo } from "./ExportsInfo"; import { Module } from "./Module"; import { ModuleGraphConnection } from "./ModuleGraphConnection"; @@ -16,22 +16,30 @@ export default class ModuleGraph { } getModule(dependency: Dependency): Module | null { - const binding = this.#inner.getModule(Dependency.__to_binding(dependency)); - return binding ? Module.__from_binding(binding) : null; + const depBinding = bindingDependencyFactory.getBinding(dependency); + if (depBinding) { + const binding = this.#inner.getModule(depBinding); + return binding ? Module.__from_binding(binding) : null; + } + return null; } getResolvedModule(dependency: Dependency): Module | null { - const binding = this.#inner.getResolvedModule( - Dependency.__to_binding(dependency) - ); - return binding ? Module.__from_binding(binding) : null; + const depBinding = bindingDependencyFactory.getBinding(dependency); + if (depBinding) { + const binding = this.#inner.getResolvedModule(depBinding); + return binding ? Module.__from_binding(binding) : null; + } + return null; } getParentModule(dependency: Dependency): Module | null { - const binding = this.#inner.getParentModule( - Dependency.__to_binding(dependency) - ); - return binding ? Module.__from_binding(binding) : null; + const depBinding = bindingDependencyFactory.getBinding(dependency); + if (depBinding) { + const binding = this.#inner.getParentModule(depBinding); + return binding ? Module.__from_binding(binding) : null; + } + return null; } getIssuer(module: Module): Module | null { @@ -46,10 +54,12 @@ export default class ModuleGraph { } getConnection(dependency: Dependency): ModuleGraphConnection | null { - const binding = this.#inner.getConnection( - Dependency.__to_binding(dependency) - ); - return binding ? ModuleGraphConnection.__from_binding(binding) : null; + const depBinding = bindingDependencyFactory.getBinding(dependency); + if (depBinding) { + const binding = this.#inner.getConnection(depBinding); + return binding ? ModuleGraphConnection.__from_binding(binding) : null; + } + return null; } getOutgoingConnections(module: Module): ModuleGraphConnection[] { @@ -59,6 +69,10 @@ export default class ModuleGraph { } getParentBlockIndex(dependency: Dependency): number { - return this.#inner.getParentBlockIndex(Dependency.__to_binding(dependency)); + const depBinding = bindingDependencyFactory.getBinding(dependency); + if (depBinding) { + return this.#inner.getParentBlockIndex(depBinding); + } + return -1; } } diff --git a/packages/rspack/src/ModuleGraphConnection.ts b/packages/rspack/src/ModuleGraphConnection.ts index 6e7b634b8e8..3adac81e49b 100644 --- a/packages/rspack/src/ModuleGraphConnection.ts +++ b/packages/rspack/src/ModuleGraphConnection.ts @@ -1,5 +1,5 @@ import type { JsModuleGraphConnection } from "@rspack/binding"; -import { Dependency } from "./Dependency"; +import { bindingDependencyFactory, Dependency } from "./Dependency"; import { Module } from "./Module"; const MODULE_GRAPH_CONNECTION_MAPPINGS = new WeakMap< @@ -40,7 +40,10 @@ export class ModuleGraphConnection { dependency: { enumerable: true, get(): Dependency { - return Dependency.__from_binding(binding.dependency); + return bindingDependencyFactory.create( + Dependency, + binding.dependency + ); } } }); diff --git a/packages/rspack/src/builtin-plugin/EntryPlugin.ts b/packages/rspack/src/builtin-plugin/EntryPlugin.ts index d363aa6487b..8464714e101 100644 --- a/packages/rspack/src/builtin-plugin/EntryPlugin.ts +++ b/packages/rspack/src/builtin-plugin/EntryPlugin.ts @@ -6,6 +6,7 @@ import { import type { EntryDescriptionNormalized } from "../config"; import { create } from "./base"; +import { EntryDependency } from "../EntryDependency"; /** * Options for the `EntryPlugin`. @@ -41,11 +42,6 @@ const OriginEntryPlugin = create( "make" ); -// TODO: Currently, the Rspack framework does not support the inheritance hierarchy of Dependency. -interface EntryDependency { - request: string; -} - type EntryPluginType = typeof OriginEntryPlugin & { createDependency(entry: string): EntryDependency; }; @@ -53,9 +49,7 @@ type EntryPluginType = typeof OriginEntryPlugin & { export const EntryPlugin = OriginEntryPlugin as EntryPluginType; EntryPlugin.createDependency = request => { - return { - request - }; + return new EntryDependency(request); }; export function getRawEntryOptions(entry: EntryOptions): JsEntryOptions { From fff46b383ccea829ec1eda9d9787a6e10f14c62c Mon Sep 17 00:00:00 2001 From: Cong-Cong Date: Wed, 25 Dec 2024 14:47:37 +0800 Subject: [PATCH 11/37] feat: support moduleGraph.isAsync --- crates/node_binding/binding.d.ts | 1 + crates/rspack_binding_values/src/module_graph.rs | 6 ++++++ packages/rspack/src/ModuleGraph.ts | 4 ++++ 3 files changed, 11 insertions(+) diff --git a/crates/node_binding/binding.d.ts b/crates/node_binding/binding.d.ts index 01fa30056ff..5c81246438f 100644 --- a/crates/node_binding/binding.d.ts +++ b/crates/node_binding/binding.d.ts @@ -247,6 +247,7 @@ export declare class JsModuleGraph { getIncomingConnections(module: JsModule): JsModuleGraphConnection[] getParentModule(jsDependency: JsDependency): JsModule | null getParentBlockIndex(jsDependency: JsDependency): number + isAsync(module: JsModule): boolean } export declare class JsModuleGraphConnection { diff --git a/crates/rspack_binding_values/src/module_graph.rs b/crates/rspack_binding_values/src/module_graph.rs index 6235ffb1ec1..132b2f2ffea 100644 --- a/crates/rspack_binding_values/src/module_graph.rs +++ b/crates/rspack_binding_values/src/module_graph.rs @@ -179,4 +179,10 @@ impl JsModuleGraph { }, ) } + + #[napi] + pub fn is_async(&self, module: &JsModule) -> napi::Result { + let (compilation, _) = self.as_ref()?; + Ok(ModuleGraph::is_async(compilation, &module.identifier)) + } } diff --git a/packages/rspack/src/ModuleGraph.ts b/packages/rspack/src/ModuleGraph.ts index a849b90ef55..b822a055729 100644 --- a/packages/rspack/src/ModuleGraph.ts +++ b/packages/rspack/src/ModuleGraph.ts @@ -75,4 +75,8 @@ export default class ModuleGraph { } return -1; } + + isAsync(module: Module): boolean { + return this.#inner.isAsync(Module.__to_binding(module)); + } } From 9edc31536dcfb3e195d59e0ef83132de486e67dd Mon Sep 17 00:00:00 2001 From: Cong-Cong Date: Wed, 25 Dec 2024 15:26:02 +0800 Subject: [PATCH 12/37] feat: chunkGroup.childrenIterable --- crates/node_binding/binding.d.ts | 1 + crates/rspack_binding_values/src/chunk_group.rs | 14 +++++++++++--- crates/rspack_core/src/chunk_group.rs | 4 ++++ packages/rspack/src/ChunkGroup.ts | 9 +++++++++ 4 files changed, 25 insertions(+), 3 deletions(-) diff --git a/crates/node_binding/binding.d.ts b/crates/node_binding/binding.d.ts index 5c81246438f..704def55c53 100644 --- a/crates/node_binding/binding.d.ts +++ b/crates/node_binding/binding.d.ts @@ -84,6 +84,7 @@ export declare class JsChunkGroup { get index(): number | undefined get name(): string | undefined get origins(): Array + get childrenIterable(): JsChunkGroup[] isInitial(): boolean getParents(): JsChunkGroup[] getRuntimeChunk(): JsChunk diff --git a/crates/rspack_binding_values/src/chunk_group.rs b/crates/rspack_binding_values/src/chunk_group.rs index e8e63c1d0ac..89c3ce1af5a 100644 --- a/crates/rspack_binding_values/src/chunk_group.rs +++ b/crates/rspack_binding_values/src/chunk_group.rs @@ -83,10 +83,18 @@ impl JsChunkGroup { Ok(js_origins) } -} -#[napi] -impl JsChunkGroup { + #[napi(getter, ts_return_type = "JsChunkGroup[]")] + pub fn children_iterable(&self) -> napi::Result> { + let (compilation, chunk_graph) = self.as_ref()?; + Ok( + chunk_graph + .children_iterable() + .map(|ukey| JsChunkGroupWrapper::new(*ukey, compilation)) + .collect::>(), + ) + } + #[napi] pub fn is_initial(&self) -> napi::Result { let (_, chunk_graph) = self.as_ref()?; diff --git a/crates/rspack_core/src/chunk_group.rs b/crates/rspack_core/src/chunk_group.rs index f03412d277a..f1c65cdce1e 100644 --- a/crates/rspack_core/src/chunk_group.rs +++ b/crates/rspack_core/src/chunk_group.rs @@ -76,6 +76,10 @@ impl ChunkGroup { self.parents.iter() } + pub fn children_iterable(&self) -> impl Iterator { + self.children.iter() + } + pub fn module_post_order_index(&self, module_identifier: &ModuleIdentifier) -> Option { // A module could split into another ChunkGroup, which doesn't have the module_post_order_indices of the module self diff --git a/packages/rspack/src/ChunkGroup.ts b/packages/rspack/src/ChunkGroup.ts index 59614ff6781..b507ceaabf9 100644 --- a/packages/rspack/src/ChunkGroup.ts +++ b/packages/rspack/src/ChunkGroup.ts @@ -10,6 +10,7 @@ export class ChunkGroup { declare readonly index?: number; declare readonly name?: string; declare readonly origins: ReadonlyArray; + declare readonly childrenIterable: Set; #inner: JsChunkGroup; @@ -57,6 +58,14 @@ export class ChunkGroup { request: origin.request })); } + }, + childrenIterable: { + enumerable: true, + get: () => { + return this.#inner.childrenIterable.map(child => + ChunkGroup.__from_binding(child) + ); + } } }); } From f815aebd358c61210a7419d0dfdd74211ffaaccb Mon Sep 17 00:00:00 2001 From: Cong-Cong Date: Wed, 25 Dec 2024 15:48:21 +0800 Subject: [PATCH 13/37] fix: dependency and bindingDependencyFactory --- packages/rspack/src/Dependency.ts | 89 ++++++++++--------------- packages/rspack/src/ModuleDependency.ts | 8 ++- 2 files changed, 42 insertions(+), 55 deletions(-) diff --git a/packages/rspack/src/Dependency.ts b/packages/rspack/src/Dependency.ts index 06acc8151b2..40eb19a5823 100644 --- a/packages/rspack/src/Dependency.ts +++ b/packages/rspack/src/Dependency.ts @@ -18,7 +18,7 @@ export const bindingDependencyFactory = { if (BINDING_MAPPINGS.has(binding)) { return BINDING_MAPPINGS.get(binding)!; } - const dependency = Object.create(ctor); + const dependency = new ctor(); BINDING_MAPPINGS.set(binding, dependency); TO_BINDING_MAPPINGS.set(dependency, binding); return dependency; @@ -26,58 +26,41 @@ export const bindingDependencyFactory = { }; export class Dependency { - declare readonly type: string; - declare readonly category: string; - declare readonly request: string | undefined; - declare critical: boolean; + get type(): string { + const binding = bindingDependencyFactory.getBinding(this); + if (binding) { + return binding.type; + } + return "unknown"; + } + + get category(): string { + const binding = bindingDependencyFactory.getBinding(this); + if (binding) { + return binding.category; + } + return "unknown"; + } + + get request(): string | undefined { + const binding = bindingDependencyFactory.getBinding(this); + if (binding) { + return binding.request; + } + } + + get critical(): boolean { + const binding = bindingDependencyFactory.getBinding(this); + if (binding) { + return binding.critical; + } + return false; + } - constructor() { - Object.defineProperties(this, { - type: { - enumerable: true, - get(): string { - const binding = bindingDependencyFactory.getBinding(this); - if (binding) { - return binding.type; - } - return "unknown"; - } - }, - category: { - enumerable: true, - get(): string { - const binding = bindingDependencyFactory.getBinding(this); - if (binding) { - return binding.category; - } - return "unknown"; - } - }, - request: { - enumerable: true, - get(): string | undefined { - const binding = bindingDependencyFactory.getBinding(this); - if (binding) { - return binding.request; - } - } - }, - critical: { - enumerable: true, - get(): boolean { - const binding = bindingDependencyFactory.getBinding(this); - if (binding) { - return binding.critical; - } - return false; - }, - set(val: boolean) { - const binding = bindingDependencyFactory.getBinding(this); - if (binding) { - binding.critical = val; - } - } - } - }); + set critical(val: boolean) { + const binding = bindingDependencyFactory.getBinding(this); + if (binding) { + binding.critical = val; + } } } diff --git a/packages/rspack/src/ModuleDependency.ts b/packages/rspack/src/ModuleDependency.ts index ba3f1f3c9d8..4b705fe2c0e 100644 --- a/packages/rspack/src/ModuleDependency.ts +++ b/packages/rspack/src/ModuleDependency.ts @@ -1,10 +1,14 @@ import { Dependency } from "./Dependency"; export class ModuleDependency extends Dependency { - request: string; + #request: string; constructor(request: string) { super(); - this.request = request; + this.#request = request; + } + + get request(): string { + return this.#request; } } From 69ec00ea3602c73bdd3fdf5d4163b27c8590d870 Mon Sep 17 00:00:00 2001 From: Cong-Cong Date: Wed, 25 Dec 2024 16:21:21 +0800 Subject: [PATCH 14/37] fix: setbinding for ModuleDependency in addInclude --- crates/node_binding/binding.d.ts | 2 +- .../src/compilation/mod.rs | 62 ++++++++++--------- packages/rspack/src/Compilation.ts | 20 +++--- 3 files changed, 47 insertions(+), 37 deletions(-) diff --git a/crates/node_binding/binding.d.ts b/crates/node_binding/binding.d.ts index 704def55c53..68fb77948c4 100644 --- a/crates/node_binding/binding.d.ts +++ b/crates/node_binding/binding.d.ts @@ -142,7 +142,7 @@ export declare class JsCompilation { addRuntimeModule(chunk: JsChunk, runtimeModule: JsAddingRuntimeModule): void get moduleGraph(): JsModuleGraph get chunkGraph(): JsChunkGraph - addInclude(args: [string, RawDependency, JsEntryOptions | undefined][], callback: (errMsg: Error | null, results: [string | null, JsModule][]) => void): void + addInclude(args: [string, RawDependency, JsEntryOptions | undefined][], callback: (errMsg: Error | null, results: [string | null, JsDependency | null, JsModule | null][]) => void): void } export declare class JsContextModuleFactoryAfterResolveData { diff --git a/crates/rspack_binding_values/src/compilation/mod.rs b/crates/rspack_binding_values/src/compilation/mod.rs index 5b6a5f3e7c7..cb38e5a3467 100644 --- a/crates/rspack_binding_values/src/compilation/mod.rs +++ b/crates/rspack_binding_values/src/compilation/mod.rs @@ -34,6 +34,7 @@ use crate::JsChunkGraph; use crate::JsChunkGroupWrapper; use crate::JsChunkWrapper; use crate::JsCompatSource; +use crate::JsDependencyWrapper; use crate::JsModuleGraph; use crate::JsModuleWrapper; use crate::JsStatsOptimizationBailout; @@ -724,7 +725,7 @@ impl JsCompilation { } #[napi( - ts_args_type = "args: [string, RawDependency, JsEntryOptions | undefined][], callback: (errMsg: Error | null, results: [string | null, JsModule][]) => void" + ts_args_type = "args: [string, RawDependency, JsEntryOptions | undefined][], callback: (errMsg: Error | null, results: [string | null, JsDependency | null, JsModule | null][]) => void" )] pub fn add_include( &mut self, @@ -766,61 +767,66 @@ impl JsCompilation { .await .map_err(|e| Error::new(napi::Status::GenericFailure, format!("{e}")))?; + let module_graph = compilation.get_module_graph(); let results = dependency_ids .into_iter() .map(|dependency_id| { - let module_graph = compilation.get_module_graph(); match module_graph.module_graph_module_by_dependency_id(&dependency_id) { Some(module) => match module_graph.module_by_identifier(&module.module_identifier) { Some(module) => { + let dependency = module_graph.dependency_by_id(&dependency_id).unwrap(); + let js_dependency = JsDependencyWrapper::new( + dependency.as_ref(), + compilation.id(), + Some(&compilation), + ); let js_module = JsModuleWrapper::new(module.as_ref(), compilation.id(), Some(compilation)); - (Either::B(()), Either::B(js_module)) + Either::B((js_dependency, js_module)) } - None => ( - Either::A(format!( - "Module created by {:#?} cannot be found", - dependency_id - )), - Either::A(()), - ), - }, - None => ( - Either::A(format!( + None => Either::A(format!( "Module created by {:#?} cannot be found", dependency_id )), - Either::A(()), - ), + }, + None => Either::A(format!( + "Module created by {:#?} cannot be found", + dependency_id + )), } }) - .collect::, Either<(), JsModuleWrapper>)>>(); + .collect::>>(); Ok(JsAddIncludeCallbackArgs(results)) }) } } -pub struct JsAddIncludeCallbackArgs(Vec<(Either, Either<(), JsModuleWrapper>)>); +pub struct JsAddIncludeCallbackArgs(Vec>); impl ToNapiValue for JsAddIncludeCallbackArgs { unsafe fn to_napi_value(env: sys::napi_env, val: Self) -> Result { let env_wrapper = Env::from_raw(env); let mut js_array = env_wrapper.create_array(0)?; - for (error, module) in val.0 { - let js_error = match error { - Either::A(val) => env_wrapper.create_string(&val)?.into_unknown(), - Either::B(_) => env_wrapper.get_undefined()?.into_unknown(), - }; - let js_module = match module { - Either::A(_) => env_wrapper.get_undefined()?.into_unknown(), - Either::B(val) => { - let napi_val = ToNapiValue::to_napi_value(env, val)?; - Unknown::from_napi_value(env, napi_val)? + for result in val.0 { + let args = match result { + Either::A(err) => vec![env_wrapper.create_string(&err)?.into_unknown()], + Either::B((js_dependency, js_module)) => { + let js_err = env_wrapper.get_undefined()?.into_unknown(); + let js_dependency = { + let napi_val = ToNapiValue::to_napi_value(env, js_dependency)?; + Unknown::from_napi_value(env, napi_val)? + }; + let js_module = { + let napi_val = ToNapiValue::to_napi_value(env, js_module)?; + Unknown::from_napi_value(env, napi_val)? + }; + vec![js_err, js_dependency, js_module] } }; - js_array.insert(vec![js_error, js_module])?; + js_array.insert(args)?; } + ToNapiValue::to_napi_value(env, js_array) } } diff --git a/packages/rspack/src/Compilation.ts b/packages/rspack/src/Compilation.ts index ed3bac96f86..6b27f991282 100644 --- a/packages/rspack/src/Compilation.ts +++ b/packages/rspack/src/Compilation.ts @@ -60,6 +60,7 @@ import type { InputFileSystem } from "./util/fs"; import type Hash from "./util/hash"; import { memoizeValue } from "./util/memoize"; import { JsSource } from "./util/source"; +import { ModuleDependency } from "./ModuleDependency"; export type { AssetInfo } from "./util/AssetInfo"; export type Assets = Record; @@ -1163,7 +1164,7 @@ BREAKING CHANGE: Asset processing hooks in Compilation has been merged into a si context: string, dependency: ReturnType, options: EntryOptions, - callback: (err?: null | WebpackError, module?: Module) => void + callback: (err: WebpackError | null, module: Module | null) => void ) { this.#addIncludeDispatcher.call(context, dependency, options, callback); } @@ -1286,9 +1287,8 @@ BREAKING CHANGE: Asset processing hooks in Compilation has been merged into a si class AddIncludeDispatcher { #inner: binding.JsCompilation["addInclude"]; #running: boolean; - #args: [string, binding.RawDependency, binding.JsEntryOptions | undefined][] = - []; - #cbs: ((err?: null | WebpackError, module?: Module) => void)[] = []; + #args: [string, ModuleDependency, binding.JsEntryOptions | undefined][] = []; + #cbs: ((err: WebpackError | null, module: Module | null) => void)[] = []; #execute = () => { if (this.#running) { @@ -1307,16 +1307,20 @@ class AddIncludeDispatcher { if (wholeErr) { const webpackError = new WebpackError(wholeErr.message); for (const cb of cbs) { - cb(webpackError); + cb(webpackError, null); } return; } for (let i = 0; i < results.length; i++) { - const [errMsg, moduleBinding] = results[i]; + const [errMsg, dependencyBinding, moduleBinding] = results[i]; const cb = cbs[i]; + const [_, dependency] = args[i]; + if (dependencyBinding) { + bindingDependencyFactory.setBinding(dependency, dependencyBinding); + } cb( errMsg ? new WebpackError(errMsg) : null, - Module.__from_binding(moduleBinding) + moduleBinding ? Module.__from_binding(moduleBinding) : null ); } }); @@ -1331,7 +1335,7 @@ class AddIncludeDispatcher { context: string, dependency: ReturnType, options: EntryOptions, - callback: (err?: null | WebpackError, module?: Module) => void + callback: (err: WebpackError | null, module: Module | null) => void ) { if (this.#args.length === 0) { queueMicrotask(this.#execute); From 1ad707427a93db6c30e0cd67f194369120b5967a Mon Sep 17 00:00:00 2001 From: Cong-Cong Date: Thu, 26 Dec 2024 08:23:38 +0800 Subject: [PATCH 15/37] fix: buildinfo --- .../src/compilation/mod.rs | 10 +++-- packages/rspack/src/Compilation.ts | 36 ++-------------- packages/rspack/src/Compiler.ts | 12 ++---- packages/rspack/src/Module.ts | 41 ++++++------------- .../src/builtin-plugin/SplitChunksPlugin.ts | 6 +-- packages/rspack/src/loader-runner/index.ts | 5 +-- 6 files changed, 28 insertions(+), 82 deletions(-) diff --git a/crates/rspack_binding_values/src/compilation/mod.rs b/crates/rspack_binding_values/src/compilation/mod.rs index cb38e5a3467..b028637a4e0 100644 --- a/crates/rspack_binding_values/src/compilation/mod.rs +++ b/crates/rspack_binding_values/src/compilation/mod.rs @@ -762,10 +762,12 @@ impl JsCompilation { .map(|(dependency, _)| *dependency.id()) .collect::>(); - compilation - .add_include(args) - .await - .map_err(|e| Error::new(napi::Status::GenericFailure, format!("{e}")))?; + for arg in args { + compilation + .add_include(vec![arg]) + .await + .map_err(|e| Error::new(napi::Status::GenericFailure, format!("{e}")))?; + } let module_graph = compilation.get_module_graph(); let results = dependency_ids diff --git a/packages/rspack/src/Compilation.ts b/packages/rspack/src/Compilation.ts index 6b27f991282..761ac7ce098 100644 --- a/packages/rspack/src/Compilation.ts +++ b/packages/rspack/src/Compilation.ts @@ -264,23 +264,11 @@ export class Compilation { }; needAdditionalPass: boolean; - /** - * Records the dynamically added fields for Module on the JavaScript side, using the Module identifier for association. - * These fields are generally used within a plugin, so they do not need to be passed back to the Rust side. - */ - #customModules: Record< - string, - { - buildInfo: Record; - buildMeta: Record; - } - >; #addIncludeDispatcher: AddIncludeDispatcher; constructor(compiler: Compiler, inner: JsCompilation) { this.#inner = inner; this.#shutdown = false; - this.#customModules = {}; const processAssetsHook = new liteTapable.AsyncSeriesHook([ "assets" @@ -458,15 +446,13 @@ BREAKING CHANGE: Asset processing hooks in Compilation has been merged into a si get modules(): ReadonlySet { return new Set( - this.#inner.modules.map(module => Module.__from_binding(module, this)) + this.#inner.modules.map(module => Module.__from_binding(module)) ); } get builtModules(): ReadonlySet { return new Set( - this.#inner.builtModules.map(module => - Module.__from_binding(module, this) - ) + this.#inner.builtModules.map(module => Module.__from_binding(module)) ); } @@ -542,22 +528,6 @@ BREAKING CHANGE: Asset processing hooks in Compilation has been merged into a si ); } - /** - * Note: This is not a webpack public API, maybe removed in future. - * - * @internal - */ - __internal__getCustomModule(moduleIdentifier: string) { - let module = this.#customModules[moduleIdentifier]; - if (!module) { - module = this.#customModules[moduleIdentifier] = { - buildInfo: {}, - buildMeta: {} - }; - } - return module; - } - getCache(name: string) { return this.compiler.getCache(name); } @@ -1138,7 +1108,7 @@ BREAKING CHANGE: Asset processing hooks in Compilation has been merged into a si for (const [id, callback] of args) { const m = modules.find(item => item.moduleIdentifier === id); if (m) { - callback(err, Module.__from_binding(m, compilation)); + callback(err, Module.__from_binding(m)); } else { callback(err || new Error("module no found"), null as any); } diff --git a/packages/rspack/src/Compiler.ts b/packages/rspack/src/Compiler.ts index f3f60dc8f6a..0b756246173 100644 --- a/packages/rspack/src/Compiler.ts +++ b/packages/rspack/src/Compiler.ts @@ -1011,9 +1011,7 @@ class Compiler { function (queried) { return function (m: binding.JsModule) { - return queried.call( - Module.__from_binding(m, that.deref()!.#compilation) - ); + return queried.call(Module.__from_binding(m)); }; } ), @@ -1026,9 +1024,7 @@ class Compiler { function (queried) { return function (m: binding.JsModule) { - return queried.call( - Module.__from_binding(m, that.deref()!.#compilation) - ); + return queried.call(Module.__from_binding(m)); }; } ), @@ -1041,9 +1037,7 @@ class Compiler { function (queried) { return function (m: binding.JsModule) { - return queried.call( - Module.__from_binding(m, that.deref()!.#compilation) - ); + return queried.call(Module.__from_binding(m)); }; } ), diff --git a/packages/rspack/src/Module.ts b/packages/rspack/src/Module.ts index 8485a168a46..6c1da07c84d 100644 --- a/packages/rspack/src/Module.ts +++ b/packages/rspack/src/Module.ts @@ -207,30 +207,31 @@ export class Module { declare readonly type: string; declare readonly layer: null | string; declare readonly factoryMeta?: JsFactoryMeta; + + declare readonly modules: Module[] | undefined; + declare readonly blocks: DependenciesBlock[]; + declare readonly dependencies: Dependency[]; + declare readonly useSourceMap: boolean; + /** * Records the dynamically added fields for Module on the JavaScript side. * These fields are generally used within a plugin, so they do not need to be passed back to the Rust side. - * @see {@link Compilation#customModules} */ - declare readonly buildInfo: Record; + buildInfo: Record; /** * Records the dynamically added fields for Module on the JavaScript side. * These fields are generally used within a plugin, so they do not need to be passed back to the Rust side. * @see {@link Compilation#customModules} */ - declare readonly buildMeta: Record; - declare readonly modules: Module[] | undefined; - declare readonly blocks: DependenciesBlock[]; - declare readonly dependencies: Dependency[]; - declare readonly useSourceMap: boolean; + buildMeta: Record; - static __from_binding(binding: JsModule, compilation?: Compilation) { + static __from_binding(binding: JsModule) { let module = MODULE_MAPPINGS.get(binding); if (module) { return module; } - module = new Module(binding, compilation); + module = new Module(binding); MODULE_MAPPINGS.set(binding, module); return module; } @@ -239,8 +240,10 @@ export class Module { return module.#inner; } - constructor(module: JsModule, compilation?: Compilation) { + constructor(module: JsModule) { this.#inner = module; + this.buildInfo = {}; + this.buildMeta = {}; Object.defineProperties(this, { type: { @@ -305,24 +308,6 @@ export class Module { return undefined; } }, - buildInfo: { - enumerable: true, - get(): Record { - const customModule = compilation?.__internal__getCustomModule( - module.moduleIdentifier - ); - return customModule?.buildInfo || {}; - } - }, - buildMeta: { - enumerable: true, - get(): Record { - const customModule = compilation?.__internal__getCustomModule( - module.moduleIdentifier - ); - return customModule?.buildMeta || {}; - } - }, blocks: { enumerable: true, get(): DependenciesBlock[] { diff --git a/packages/rspack/src/builtin-plugin/SplitChunksPlugin.ts b/packages/rspack/src/builtin-plugin/SplitChunksPlugin.ts index 9601ccd93f9..5874faee223 100644 --- a/packages/rspack/src/builtin-plugin/SplitChunksPlugin.ts +++ b/packages/rspack/src/builtin-plugin/SplitChunksPlugin.ts @@ -51,7 +51,7 @@ function toRawSplitChunksOptions( return name(undefined); } return name( - Module.__from_binding(ctx.module, compiler._lastCompilation), + Module.__from_binding(ctx.module), getChunks(ctx.chunks), ctx.cacheGroupKey ); @@ -70,9 +70,7 @@ function toRawSplitChunksOptions( if (typeof ctx.module === "undefined") { return test(undefined); } - return test( - Module.__from_binding(ctx.module, compiler._lastCompilation) - ); + return test(Module.__from_binding(ctx.module)); }; } return test; diff --git a/packages/rspack/src/loader-runner/index.ts b/packages/rspack/src/loader-runner/index.ts index 4f8e2fe5dfc..d91c62cccdb 100644 --- a/packages/rspack/src/loader-runner/index.ts +++ b/packages/rspack/src/loader-runner/index.ts @@ -747,10 +747,7 @@ export async function runLoaders( loaderContext._compiler = compiler; loaderContext._compilation = compiler._lastCompilation!; - loaderContext._module = Module.__from_binding( - context._module, - compiler._lastCompilation - ); + loaderContext._module = Module.__from_binding(context._module); loaderContext.getOptions = () => { const loader = getCurrentLoader(loaderContext); From 3f22b9ebae0804c1def0b968307d639a92b7051f Mon Sep 17 00:00:00 2001 From: Cong-Cong Date: Thu, 26 Dec 2024 08:32:52 +0800 Subject: [PATCH 16/37] feat: resolvedModule and originModule in connection --- crates/node_binding/binding.d.ts | 2 ++ .../src/module_graph_connection.rs | 32 +++++++++++++++++++ packages/rspack/src/ModuleGraphConnection.ts | 16 ++++++++++ 3 files changed, 50 insertions(+) diff --git a/crates/node_binding/binding.d.ts b/crates/node_binding/binding.d.ts index 68fb77948c4..d4d0d8f5bb4 100644 --- a/crates/node_binding/binding.d.ts +++ b/crates/node_binding/binding.d.ts @@ -254,6 +254,8 @@ export declare class JsModuleGraph { export declare class JsModuleGraphConnection { get dependency(): JsDependency get module(): JsModule | null + get resolvedModule(): JsModule | null + get originModule(): JsModule | null } export declare class JsResolver { diff --git a/crates/rspack_binding_values/src/module_graph_connection.rs b/crates/rspack_binding_values/src/module_graph_connection.rs index d1278ce264e..1be29f758ee 100644 --- a/crates/rspack_binding_values/src/module_graph_connection.rs +++ b/crates/rspack_binding_values/src/module_graph_connection.rs @@ -55,6 +55,38 @@ impl JsModuleGraphConnection { ))) } } + + #[napi(getter, ts_return_type = "JsModule | null")] + pub fn resolved_module(&self) -> napi::Result> { + let (compilation, module_graph) = self.as_ref()?; + if let Some(connection) = module_graph.connection_by_dependency_id(&self.dependency_id) { + let module = module_graph.module_by_identifier(&connection.resolved_module); + Ok(module.map(|m| JsModuleWrapper::new(m.as_ref(), compilation.id(), Some(compilation)))) + } else { + Err(napi::Error::from_reason(format!( + "Unable to access ModuleGraphConnection with id = {:#?} now. The ModuleGraphConnection have been removed on the Rust side.", + self.dependency_id + ))) + } + } + + #[napi(getter, ts_return_type = "JsModule | null")] + pub fn origin_module(&self) -> napi::Result> { + let (compilation, module_graph) = self.as_ref()?; + if let Some(connection) = module_graph.connection_by_dependency_id(&self.dependency_id) { + Ok(match connection.original_module_identifier { + Some(original_module_identifier) => module_graph + .module_by_identifier(&original_module_identifier) + .map(|m| JsModuleWrapper::new(m.as_ref(), compilation.id(), Some(compilation))), + None => None, + }) + } else { + Err(napi::Error::from_reason(format!( + "Unable to access ModuleGraphConnection with id = {:#?} now. The ModuleGraphConnection have been removed on the Rust side.", + self.dependency_id + ))) + } + } } type ModuleGraphConnectionRefs = HashMap>; diff --git a/packages/rspack/src/ModuleGraphConnection.ts b/packages/rspack/src/ModuleGraphConnection.ts index 3adac81e49b..abda403c6f5 100644 --- a/packages/rspack/src/ModuleGraphConnection.ts +++ b/packages/rspack/src/ModuleGraphConnection.ts @@ -45,6 +45,22 @@ export class ModuleGraphConnection { binding.dependency ); } + }, + resolvedModule: { + enumerable: true, + get(): Module | null { + return binding.resolvedModule + ? Module.__from_binding(binding.resolvedModule) + : null; + } + }, + originModule: { + enumerable: true, + get(): Module | null { + return binding.originModule + ? Module.__from_binding(binding.originModule) + : null; + } } }); } From 751225fd533e2036d8af9eab14154ef34595beb3 Mon Sep 17 00:00:00 2001 From: Cong-Cong Date: Thu, 26 Dec 2024 14:59:32 +0800 Subject: [PATCH 17/37] feat: support issuerLayer in external function --- crates/node_binding/binding.d.ts | 1 + .../src/compilation/mod.rs | 36 ++++++++++--------- .../src/options/entry.rs | 2 +- .../src/raw_options/raw_external.rs | 2 ++ crates/rspack_core/src/options/externals.rs | 1 + crates/rspack_plugin_externals/src/plugin.rs | 1 + 6 files changed, 25 insertions(+), 18 deletions(-) diff --git a/crates/node_binding/binding.d.ts b/crates/node_binding/binding.d.ts index d4d0d8f5bb4..3dec601848f 100644 --- a/crates/node_binding/binding.d.ts +++ b/crates/node_binding/binding.d.ts @@ -379,6 +379,7 @@ export declare function cleanupGlobalTrace(): void export interface ContextInfo { issuer: string + issuerLayer?: string } export declare function formatDiagnostic(diagnostic: JsDiagnostic): ExternalObject<'Diagnostic'> diff --git a/crates/rspack_binding_values/src/compilation/mod.rs b/crates/rspack_binding_values/src/compilation/mod.rs index b028637a4e0..a66669843c5 100644 --- a/crates/rspack_binding_values/src/compilation/mod.rs +++ b/crates/rspack_binding_values/src/compilation/mod.rs @@ -53,28 +53,30 @@ pub struct JsCompilation { impl JsCompilation { fn as_ref(&self) -> napi::Result<&'static Compilation> { let compilation = unsafe { self.inner.as_ref() }; - if compilation.id() == self.id { - return Ok(compilation); - } + return Ok(compilation); + // if compilation.id() == self.id { + // return Ok(compilation); + // } - Err(napi::Error::from_reason(format!( - "Unable to access compilation with id = {:?} now. The compilation have been removed on the Rust side. The latest compilation id is {:?}", - self.id, - compilation.id() - ))) + // Err(napi::Error::from_reason(format!( + // "Unable to access compilation with id = {:?} now. The compilation have been removed on the Rust side. The latest compilation id is {:?}", + // self.id, + // compilation.id() + // ))) } fn as_mut(&mut self) -> napi::Result<&'static mut Compilation> { let compilation = unsafe { self.inner.as_mut() }; - if compilation.id() == self.id { - return Ok(compilation); - } - - Err(napi::Error::from_reason(format!( - "Unable to access compilation with id = {:?} now. The compilation have been removed on the Rust side. The latest compilation id is {:?}", - self.id, - compilation.id() - ))) + return Ok(compilation); + // if compilation.id() == self.id { + // return Ok(compilation); + // } + + // Err(napi::Error::from_reason(format!( + // "Unable to access compilation with id = {:?} now. The compilation have been removed on the Rust side. The latest compilation id is {:?}", + // self.id, + // compilation.id() + // ))) } } diff --git a/crates/rspack_binding_values/src/options/entry.rs b/crates/rspack_binding_values/src/options/entry.rs index 36f3bd46737..48315f8312d 100644 --- a/crates/rspack_binding_values/src/options/entry.rs +++ b/crates/rspack_binding_values/src/options/entry.rs @@ -28,7 +28,7 @@ impl From for EntryRuntime { } } -#[derive(Debug)] +#[derive(Debug, Default)] #[napi(object, object_to_js = false)] pub struct JsEntryOptions { pub name: Option, diff --git a/crates/rspack_binding_values/src/raw_options/raw_external.rs b/crates/rspack_binding_values/src/raw_options/raw_external.rs index bb35d530c0c..dd2e0a3b40f 100644 --- a/crates/rspack_binding_values/src/raw_options/raw_external.rs +++ b/crates/rspack_binding_values/src/raw_options/raw_external.rs @@ -69,6 +69,7 @@ impl From for ExternalItemFnResult { #[napi(object)] pub struct ContextInfo { pub issuer: String, + pub issuer_layer: Option, } #[derive(Debug)] @@ -120,6 +121,7 @@ impl From for RawExternalItemFnCtx { context: value.context, context_info: ContextInfo { issuer: value.context_info.issuer, + issuer_layer: value.context_info.issuer_layer, }, resolve_options_with_dependency_type: value.resolve_options_with_dependency_type, resolver_factory: value.resolver_factory, diff --git a/crates/rspack_core/src/options/externals.rs b/crates/rspack_core/src/options/externals.rs index 480234eece8..7021ef10b5b 100644 --- a/crates/rspack_core/src/options/externals.rs +++ b/crates/rspack_core/src/options/externals.rs @@ -21,6 +21,7 @@ pub type ExternalItemObject = HashMap; pub struct ContextInfo { pub issuer: String, + pub issuer_layer: Option, } pub struct ExternalItemFnCtx { diff --git a/crates/rspack_plugin_externals/src/plugin.rs b/crates/rspack_plugin_externals/src/plugin.rs index 6efa2f352c0..49c7c2bc339 100644 --- a/crates/rspack_plugin_externals/src/plugin.rs +++ b/crates/rspack_plugin_externals/src/plugin.rs @@ -181,6 +181,7 @@ async fn factorize(&self, data: &mut ModuleFactoryCreateData) -> Result Date: Thu, 26 Dec 2024 17:29:47 +0800 Subject: [PATCH 18/37] fix: remove memoizeValue --- packages/rspack/src/Compilation.ts | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/packages/rspack/src/Compilation.ts b/packages/rspack/src/Compilation.ts index 761ac7ce098..3fa866aa74d 100644 --- a/packages/rspack/src/Compilation.ts +++ b/packages/rspack/src/Compilation.ts @@ -58,7 +58,6 @@ import { createReadonlyMap } from "./util/createReadonlyMap"; import { createFakeCompilationDependencies } from "./util/fake"; import type { InputFileSystem } from "./util/fs"; import type Hash from "./util/hash"; -import { memoizeValue } from "./util/memoize"; import { JsSource } from "./util/source"; import { ModuleDependency } from "./ModuleDependency"; export type { AssetInfo } from "./util/AssetInfo"; @@ -400,27 +399,24 @@ BREAKING CHANGE: Asset processing hooks in Compilation has been merged into a si * Get a map of all assets. */ get assets(): Record { - return memoizeValue(() => this.#createCachedAssets()); + return this.#createCachedAssets(); } /** * Get a map of all entrypoints. */ get entrypoints(): ReadonlyMap { - return memoizeValue( - () => - new Map( - Object.entries(this.#inner.entrypoints).map(([n, e]) => [ - n, - Entrypoint.__from_binding(e) - ]) - ) + return new Map( + Object.entries(this.#inner.entrypoints).map(([n, e]) => [ + n, + Entrypoint.__from_binding(e) + ]) ); } get chunkGroups(): ReadonlyArray { - return memoizeValue(() => - this.#inner.chunkGroups.map(binding => ChunkGroup.__from_binding(binding)) + return this.#inner.chunkGroups.map(binding => + ChunkGroup.__from_binding(binding) ); } @@ -457,7 +453,7 @@ BREAKING CHANGE: Asset processing hooks in Compilation has been merged into a si } get chunks(): ReadonlySet { - return memoizeValue(() => new Set(this.__internal__getChunks())); + return new Set(this.__internal__getChunks()); } /** From 25669cf34679985ac3e5135922a29ac575c64d5e Mon Sep 17 00:00:00 2001 From: Cong-Cong Date: Fri, 27 Dec 2024 14:13:35 +0800 Subject: [PATCH 19/37] fix: alias priority --- crates/rspack_core/src/normal_module_factory.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/crates/rspack_core/src/normal_module_factory.rs b/crates/rspack_core/src/normal_module_factory.rs index 81b0000e0dd..f76586db338 100644 --- a/crates/rspack_core/src/normal_module_factory.rs +++ b/crates/rspack_core/src/normal_module_factory.rs @@ -644,7 +644,8 @@ impl NormalModuleFactory { fn calculate_resolve_options(&self, module_rules: &[&ModuleRuleEffect]) -> Option> { let mut resolved: Option = None; - for rule in module_rules { + // TODO: 为了 alias 的优先级临时修改,之后修改 + for rule in module_rules.iter().rev() { if let Some(rule_resolve) = &rule.resolve { if let Some(r) = resolved { resolved = Some(r.merge(rule_resolve.to_owned())); From 1b19786cd1a63b4dd5aaf18c607b4b0ab4c2dfbd Mon Sep 17 00:00:00 2001 From: Cong-Cong Date: Fri, 27 Dec 2024 19:44:20 +0800 Subject: [PATCH 20/37] feat: dependency.ids --- crates/node_binding/binding.d.ts | 1 + .../rspack_binding_values/src/dependency.rs | 58 ++++++++++++++++--- packages/rspack/src/Dependency.ts | 7 +++ 3 files changed, 58 insertions(+), 8 deletions(-) diff --git a/crates/node_binding/binding.d.ts b/crates/node_binding/binding.d.ts index b7cfbb52822..7e71eff3709 100644 --- a/crates/node_binding/binding.d.ts +++ b/crates/node_binding/binding.d.ts @@ -196,6 +196,7 @@ export declare class JsDependency { get request(): string | undefined get critical(): boolean set critical(val: boolean) + get ids(): Array | undefined } export declare class JsEntries { diff --git a/crates/rspack_binding_values/src/dependency.rs b/crates/rspack_binding_values/src/dependency.rs index abad6bdfdd0..4381cf7b346 100644 --- a/crates/rspack_binding_values/src/dependency.rs +++ b/crates/rspack_binding_values/src/dependency.rs @@ -1,9 +1,13 @@ use std::{cell::RefCell, ptr::NonNull}; -use napi::{bindgen_prelude::ToNapiValue, Either}; +use napi::{bindgen_prelude::ToNapiValue, Either, Env, JsString}; use napi_derive::napi; use rspack_core::{Compilation, CompilationId, Dependency, DependencyId}; use rspack_napi::OneShotRef; +use rspack_plugin_javascript::dependency::{ + CommonJsExportRequireDependency, ESMExportImportedSpecifierDependency, + ESMImportSpecifierDependency, +}; use rustc_hash::FxHashMap as HashMap; // JsDependency allows JS-side access to a Dependency instance that has already @@ -16,7 +20,7 @@ pub struct JsDependency { } impl JsDependency { - fn as_ref(&mut self) -> napi::Result<&dyn Dependency> { + fn as_ref(&mut self) -> napi::Result<(&dyn Dependency, Option<&Compilation>)> { if let Some(compilation) = self.compilation { let compilation = unsafe { compilation.as_ref() }; let module_graph = compilation.get_module_graph(); @@ -25,7 +29,7 @@ impl JsDependency { #[allow(clippy::unwrap_used)] NonNull::new(dependency.as_ref() as *const dyn Dependency as *mut dyn Dependency).unwrap() }; - Ok(unsafe { self.dependency.as_ref() }) + Ok((unsafe { self.dependency.as_ref() }, Some(compilation))) } else { Err(napi::Error::from_reason(format!( "Unable to access dependency with id = {:?} now. The dependency have been removed on the Rust side.", @@ -36,7 +40,7 @@ impl JsDependency { // SAFETY: // We need to make users aware in the documentation that values obtained within the JS hook callback should not be used outside the scope of the callback. // We do not guarantee that the memory pointed to by the pointer remains valid when used outside the scope. - Ok(unsafe { self.dependency.as_ref() }) + Ok((unsafe { self.dependency.as_ref() }, None)) } } @@ -52,21 +56,21 @@ impl JsDependency { impl JsDependency { #[napi(getter)] pub fn get_type(&mut self) -> napi::Result<&str> { - let dependency = self.as_ref()?; + let (dependency, _) = self.as_ref()?; Ok(dependency.dependency_type().as_str()) } #[napi(getter)] pub fn category(&mut self) -> napi::Result<&str> { - let dependency = self.as_ref()?; + let (dependency, _) = self.as_ref()?; Ok(dependency.category().as_str()) } #[napi(getter)] pub fn request(&mut self) -> napi::Result> { - let dependency = self.as_ref()?; + let (dependency, _) = self.as_ref()?; Ok(match dependency.as_module_dependency() { Some(dep) => napi::Either::A(dep.request()), @@ -76,7 +80,7 @@ impl JsDependency { #[napi(getter)] pub fn critical(&mut self) -> napi::Result { - let dependency = self.as_ref()?; + let (dependency, _) = self.as_ref()?; Ok(match dependency.as_context_dependency() { Some(dep) => dep.critical().is_some(), @@ -96,6 +100,44 @@ impl JsDependency { } Ok(()) } + + #[napi(getter)] + pub fn ids(&mut self, env: Env) -> napi::Result, ()>> { + let (dependency, compilation) = self.as_ref()?; + + Ok(match compilation { + Some(compilation) => { + let module_graph = compilation.get_module_graph(); + if let Some(dependency) = dependency.downcast_ref::() { + let ids = dependency + .get_ids(&module_graph) + .into_iter() + .map(|atom| env.create_string(atom.as_str())) + .collect::>>()?; + Either::A(ids) + } else if let Some(dependency) = + dependency.downcast_ref::() + { + let ids = dependency + .get_ids(&module_graph) + .into_iter() + .map(|atom| env.create_string(atom.as_str())) + .collect::>>()?; + Either::A(ids) + } else if let Some(dependency) = dependency.downcast_ref::() { + let ids = dependency + .get_ids(&module_graph) + .into_iter() + .map(|atom| env.create_string(atom.as_str())) + .collect::>>()?; + Either::A(ids) + } else { + Either::B(()) + } + } + None => Either::B(()), + }) + } } type DependencyInstanceRefs = HashMap>; diff --git a/packages/rspack/src/Dependency.ts b/packages/rspack/src/Dependency.ts index 40eb19a5823..0e86b221d08 100644 --- a/packages/rspack/src/Dependency.ts +++ b/packages/rspack/src/Dependency.ts @@ -63,4 +63,11 @@ export class Dependency { binding.critical = val; } } + + get ids(): string[] | undefined { + const binding = bindingDependencyFactory.getBinding(this); + if (binding) { + return binding.ids; + } + } } From fd62ae70445c59f583eeb113980047c69427666b Mon Sep 17 00:00:00 2001 From: Cong-Cong Date: Fri, 27 Dec 2024 19:56:53 +0800 Subject: [PATCH 21/37] feat: module.resourceResolveData --- crates/node_binding/binding.d.ts | 1 + crates/rspack_binding_values/src/module.rs | 11 ++++++++++- .../commonjs/common_js_export_require_dependency.rs | 2 +- packages/rspack/src/Module.ts | 6 ++++++ 4 files changed, 18 insertions(+), 2 deletions(-) diff --git a/crates/node_binding/binding.d.ts b/crates/node_binding/binding.d.ts index 7e71eff3709..c198a185b01 100644 --- a/crates/node_binding/binding.d.ts +++ b/crates/node_binding/binding.d.ts @@ -236,6 +236,7 @@ export declare class JsModule { get modules(): JsModule[] | undefined get useSourceMap(): boolean libIdent(options: JsLibIdentOptions): string | null + get resourceResolveData(): JsResourceData | undefined } export declare class JsModuleGraph { diff --git a/crates/rspack_binding_values/src/module.rs b/crates/rspack_binding_values/src/module.rs index b460d2cfd2f..ec86c65be90 100644 --- a/crates/rspack_binding_values/src/module.rs +++ b/crates/rspack_binding_values/src/module.rs @@ -16,7 +16,7 @@ use rustc_hash::FxHashMap as HashMap; use super::JsCompatSourceOwned; use crate::{ JsChunkWrapper, JsCodegenerationResults, JsCompatSource, JsDependenciesBlockWrapper, - JsDependencyWrapper, ToJsCompatSource, + JsDependencyWrapper, JsResourceData, ToJsCompatSource, }; #[napi(object)] @@ -300,6 +300,15 @@ impl JsModule { }, ) } + + #[napi(getter)] + pub fn resource_resolve_data(&mut self) -> napi::Result> { + let module = self.as_ref()?; + Ok(match module.as_normal_module() { + Some(module) => Either::A(module.resource_resolved_data().into()), + None => Either::B(()), + }) + } } type ModuleInstanceRefs = IdentifierMap>; diff --git a/crates/rspack_plugin_javascript/src/dependency/commonjs/common_js_export_require_dependency.rs b/crates/rspack_plugin_javascript/src/dependency/commonjs/common_js_export_require_dependency.rs index 403cd172676..2301d1d9af8 100644 --- a/crates/rspack_plugin_javascript/src/dependency/commonjs/common_js_export_require_dependency.rs +++ b/crates/rspack_plugin_javascript/src/dependency/commonjs/common_js_export_require_dependency.rs @@ -165,7 +165,7 @@ impl CommonJsExportRequireDependency { Some(exports) } - fn get_ids<'a>(&'a self, mg: &'a ModuleGraph) -> &'a [Atom] { + pub fn get_ids<'a>(&'a self, mg: &'a ModuleGraph) -> &'a [Atom] { mg.get_dep_meta_if_existing(&self.id) .map(|meta| meta.ids.as_slice()) .unwrap_or_else(|| self.ids.as_slice()) diff --git a/packages/rspack/src/Module.ts b/packages/rspack/src/Module.ts index 84ef9a1c008..a162f584dc4 100644 --- a/packages/rspack/src/Module.ts +++ b/packages/rspack/src/Module.ts @@ -334,6 +334,12 @@ export class Module { get(): boolean { return module.useSourceMap; } + }, + resourceResolveData: { + enumerable: true, + get(): ResolveData | undefined { + return module.resourceResolveData as any; + } } }); } From 7bb8cb7862e7e7e7e1a054be705691d1487ce80f Mon Sep 17 00:00:00 2001 From: Cong-Cong Date: Mon, 30 Dec 2024 09:29:32 +0800 Subject: [PATCH 22/37] feat: match_resource --- crates/node_binding/binding.d.ts | 2 ++ crates/rspack_binding_values/src/module.rs | 28 ++++++++++++++++++++++ packages/rspack/src/Module.ts | 6 +++++ 3 files changed, 36 insertions(+) diff --git a/crates/node_binding/binding.d.ts b/crates/node_binding/binding.d.ts index c198a185b01..57fc21c75b0 100644 --- a/crates/node_binding/binding.d.ts +++ b/crates/node_binding/binding.d.ts @@ -237,6 +237,8 @@ export declare class JsModule { get useSourceMap(): boolean libIdent(options: JsLibIdentOptions): string | null get resourceResolveData(): JsResourceData | undefined + get matchResource(): string | undefined + get loaders(): Array | undefined } export declare class JsModuleGraph { diff --git a/crates/rspack_binding_values/src/module.rs b/crates/rspack_binding_values/src/module.rs index ec86c65be90..a7d1f42eeed 100644 --- a/crates/rspack_binding_values/src/module.rs +++ b/crates/rspack_binding_values/src/module.rs @@ -309,6 +309,34 @@ impl JsModule { None => Either::B(()), }) } + + #[napi(getter)] + pub fn match_resource(&mut self) -> napi::Result> { + let module = self.as_ref()?; + Ok(match module.as_normal_module() { + Some(module) => match &module.match_resource() { + Some(match_resource) => Either::A(&match_resource.resource), + None => Either::B(()), + }, + None => Either::B(()), + }) + } + + #[napi(getter)] + pub fn loaders(&mut self) -> napi::Result, ()>> { + let module = self.as_ref()?; + Ok(match module.as_normal_module() { + Some(module) => { + let ids = module + .loaders() + .iter() + .map(|loader| loader.identifier().as_str()) + .collect::>(); + Either::A(ids) + } + None => Either::B(()), + }) + } } type ModuleInstanceRefs = IdentifierMap>; diff --git a/packages/rspack/src/Module.ts b/packages/rspack/src/Module.ts index a162f584dc4..538d176aad6 100644 --- a/packages/rspack/src/Module.ts +++ b/packages/rspack/src/Module.ts @@ -340,6 +340,12 @@ export class Module { get(): ResolveData | undefined { return module.resourceResolveData as any; } + }, + matchResource: { + enumerable: true, + get(): string | undefined { + return module.matchResource; + } } }); } From 88e89b2bf5b422371e5cc2524dcd69785539c7ea Mon Sep 17 00:00:00 2001 From: Cong-Cong Date: Mon, 30 Dec 2024 12:11:06 +0800 Subject: [PATCH 23/37] feat: set dependencies and includeDependencies in EntryData --- crates/node_binding/binding.d.ts | 35 +-- .../src/compilation/entries.rs | 226 +++++++++++------- .../src/compilation/mod.rs | 36 ++- packages/rspack/src/Compilation.ts | 56 ++++- 4 files changed, 230 insertions(+), 123 deletions(-) diff --git a/crates/node_binding/binding.d.ts b/crates/node_binding/binding.d.ts index 57fc21c75b0..bafd90ed991 100644 --- a/crates/node_binding/binding.d.ts +++ b/crates/node_binding/binding.d.ts @@ -19,13 +19,6 @@ export declare class ExternalObject { [K: symbol]: T } } -export declare class EntryDataDto { - get dependencies(): JsDependency[] - get includeDependencies(): JsDependency[] - get options(): EntryOptionsDto -} -export type EntryDataDTO = EntryDataDto - export declare class EntryOptionsDto { get name(): string | undefined set name(name: string | undefined) @@ -142,7 +135,7 @@ export declare class JsCompilation { addRuntimeModule(chunk: JsChunk, runtimeModule: JsAddingRuntimeModule): void get moduleGraph(): JsModuleGraph get chunkGraph(): JsChunkGraph - addInclude(args: [string, RawDependency, JsEntryOptions | undefined][], callback: (errMsg: Error | null, results: [string | null, JsDependency | null, JsModule | null][]) => void): void + addInclude(args: [string, RawDependency, RawEntryOptions | undefined][], callback: (errMsg: Error | null, results: [string | null, JsDependency | null, JsModule | null][]) => void): void } export declare class JsContextModuleFactoryAfterResolveData { @@ -203,11 +196,19 @@ export declare class JsEntries { clear(): void get size(): number has(key: string): boolean - set(key: string, value: JsEntryData | EntryDataDto): void + set(key: string, value: RawEntryData): void delete(key: string): boolean - get(key: string): EntryDataDto | undefined + get(key: string): JsEntryData | undefined keys(): Array - values(): Array + values(): Array +} + +export declare class JsEntryData { + get dependencies(): JsDependency[] + set dependencies(dependencies: Array) + get includeDependencies(): JsDependency[] + set includeDependencies(dependencies: Array) + get options(): EntryOptionsDto } export declare class JsExportsInfo { @@ -625,12 +626,6 @@ export interface JsDiagnosticLocation { length: number } -export interface JsEntryData { - dependencies: Array - includeDependencies: Array - options: JsEntryOptions -} - export interface JsEntryOptions { name?: string runtime?: false | string @@ -1377,6 +1372,12 @@ export interface RawDynamicEntryPluginOptions { entry: () => Promise } +export interface RawEntryData { + dependencies: Array + includeDependencies: Array + options: JsEntryOptions +} + export interface RawEntryDynamicResult { import: Array options: JsEntryOptions diff --git a/crates/rspack_binding_values/src/compilation/entries.rs b/crates/rspack_binding_values/src/compilation/entries.rs index 2fa3902e401..e6fdfd1613f 100644 --- a/crates/rspack_binding_values/src/compilation/entries.rs +++ b/crates/rspack_binding_values/src/compilation/entries.rs @@ -1,3 +1,5 @@ +use std::ptr::NonNull; + use napi_derive::napi; use rspack_core::{ChunkLoading, Compilation, EntryData, EntryOptions, EntryRuntime}; use rspack_napi::napi::bindgen_prelude::*; @@ -157,14 +159,14 @@ impl EntryOptionsDTO { } #[napi(object, object_to_js = false)] -pub struct JsEntryData { +pub struct RawEntryData { pub dependencies: Vec>, pub include_dependencies: Vec>, pub options: JsEntryOptions, } -impl From for EntryData { - fn from(value: JsEntryData) -> Self { +impl From for EntryData { + fn from(value: RawEntryData) -> Self { Self { dependencies: value .dependencies @@ -182,41 +184,97 @@ impl From for EntryData { } #[napi] -pub struct EntryDataDTO { - compilation: &'static mut Compilation, - entry_data: EntryData, +pub struct JsEntryData { + compilation: NonNull, + key: String, +} + +impl JsEntryData { + fn as_ref(&self) -> napi::Result<(&'static EntryData, &'static Compilation)> { + let compilation = unsafe { self.compilation.as_ref() }; + if let Some(entry_data) = compilation.entries.get(&self.key) { + Ok((entry_data, compilation)) + } else { + Err(napi::Error::from_reason(format!( + "Unable to access EntryData with key = {} now. The EntryData have been removed on the Rust side.", + self.key + ))) + } + } + + fn as_mut(&mut self) -> napi::Result<&'static mut EntryData> { + let compilation = unsafe { self.compilation.as_mut() }; + if let Some(entry_data) = compilation.entries.get_mut(&self.key) { + Ok(entry_data) + } else { + Err(napi::Error::from_reason(format!( + "Unable to access EntryData with key = {} now. The EntryData have been removed on the Rust side.", + self.key + ))) + } + } } #[napi] -impl EntryDataDTO { +impl JsEntryData { #[napi(getter, ts_return_type = "JsDependency[]")] - pub fn dependencies(&'static self) -> Vec { - let module_graph = self.compilation.get_module_graph(); - self - .entry_data - .dependencies - .iter() - .map(|dependency_id| { - #[allow(clippy::unwrap_used)] - let dep = module_graph.dependency_by_id(dependency_id).unwrap(); - JsDependencyWrapper::new(dep.as_ref(), self.compilation.id(), Some(self.compilation)) - }) - .collect::>() + pub fn dependencies(&self) -> Result> { + let (entry_data, compilation) = self.as_ref()?; + let module_graph = compilation.get_module_graph(); + Ok( + entry_data + .dependencies + .iter() + .map(|dependency_id| { + #[allow(clippy::unwrap_used)] + let dep = module_graph.dependency_by_id(dependency_id).unwrap(); + JsDependencyWrapper::new(dep.as_ref(), compilation.id(), Some(compilation)) + }) + .collect::>(), + ) + } + + #[napi(setter)] + pub fn set_dependencies( + &mut self, + dependencies: Vec>, + ) -> Result<()> { + let entry_data = self.as_mut()?; + entry_data.dependencies = dependencies + .into_iter() + .map(|js_dep| js_dep.dependency_id) + .collect::>(); + Ok(()) } #[napi(getter, ts_return_type = "JsDependency[]")] - pub fn include_dependencies(&'static self) -> Vec { - let module_graph = self.compilation.get_module_graph(); - self - .entry_data - .include_dependencies - .iter() - .map(|dependency_id| { - #[allow(clippy::unwrap_used)] - let dep = module_graph.dependency_by_id(dependency_id).unwrap(); - JsDependencyWrapper::new(dep.as_ref(), self.compilation.id(), Some(self.compilation)) - }) - .collect::>() + pub fn include_dependencies(&'static self) -> Result> { + let (entry_data, compilation) = self.as_ref()?; + let module_graph = compilation.get_module_graph(); + Ok( + entry_data + .include_dependencies + .iter() + .map(|dependency_id| { + #[allow(clippy::unwrap_used)] + let dep = module_graph.dependency_by_id(dependency_id).unwrap(); + JsDependencyWrapper::new(dep.as_ref(), compilation.id(), Some(compilation)) + }) + .collect::>(), + ) + } + + #[napi(setter)] + pub fn set_include_dependencies( + &mut self, + dependencies: Vec>, + ) -> Result<()> { + let entry_data = self.as_mut()?; + entry_data.include_dependencies = dependencies + .into_iter() + .map(|js_dep| js_dep.dependency_id) + .collect::>(); + Ok(()) } #[napi(getter)] @@ -224,64 +282,76 @@ impl EntryDataDTO { &self, env: &'scope Env, ) -> Result> { - EntryOptionsDTO::new(self.entry_data.options.clone()).into_instance(env) + let (entry_data, _) = self.as_ref()?; + EntryOptionsDTO::new(entry_data.options.clone()).into_instance(env) } } #[napi] pub struct JsEntries { - compilation: &'static mut Compilation, + compilation: NonNull, } impl JsEntries { - pub fn new(compilation: &'static mut Compilation) -> Self { - Self { compilation } + pub fn new(compilation: &Compilation) -> Self { + #[allow(clippy::unwrap_used)] + Self { + compilation: NonNull::new(compilation as *const Compilation as *mut Compilation).unwrap(), + } + } + + fn as_ref(&self) -> Result<&'static Compilation> { + let compilation = unsafe { self.compilation.as_ref() }; + Ok(compilation) + } + + fn as_mut(&mut self) -> Result<&'static mut Compilation> { + let compilation = unsafe { self.compilation.as_mut() }; + Ok(compilation) } } #[napi] impl JsEntries { #[napi] - pub fn clear(&mut self) { - self.compilation.entries.drain(..); + pub fn clear(&mut self) -> Result<()> { + let compilation = self.as_mut()?; + compilation.entries.drain(..); + Ok(()) } #[napi(getter)] - pub fn size(&mut self) -> u32 { - self.compilation.entries.len() as u32 + pub fn size(&mut self) -> Result { + let compilation = self.as_ref()?; + Ok(compilation.entries.len() as u32) } #[napi] - pub fn has(&self, key: String) -> bool { - self.compilation.entries.contains_key(&key) + pub fn has(&self, key: String) -> Result { + let compilation = self.as_ref()?; + Ok(compilation.entries.contains_key(&key)) } #[napi] - pub fn set(&mut self, key: String, value: Either>) { - let entry_data = match value { - Either::A(js) => js.into(), - Either::B(dto) => { - assert!( - std::ptr::eq(dto.compilation, self.compilation), - "The set() method cannot accept entry data from a different compilation instance." - ); - dto.entry_data.clone() - } - }; - self.compilation.entries.insert(key, entry_data); + pub fn set(&mut self, key: String, value: RawEntryData) -> Result<()> { + let compilation = self.as_mut()?; + compilation.entries.insert(key, value.into()); + Ok(()) } #[napi] - pub fn delete(&mut self, key: String) -> bool { - let r = self.compilation.entries.swap_remove(&key); - r.is_some() + pub fn delete(&mut self, key: String) -> Result { + let compilation = self.as_mut()?; + let r = compilation.entries.swap_remove(&key); + Ok(r.is_some()) } #[napi] - pub fn get(&'static mut self, key: String) -> Result> { - Ok(match self.compilation.entries.get(&key) { - Some(entry_data) => Either::A(EntryDataDTO { - entry_data: entry_data.clone(), + pub fn get(&self, key: String) -> Result> { + let compilation = self.as_ref()?; + Ok(match compilation.entries.get(&key) { + Some(_) => Either::A(JsEntryData { + key, compilation: self.compilation, }), None => Either::B(()), @@ -289,28 +359,24 @@ impl JsEntries { } #[napi] - pub fn keys(&self) -> Vec<&String> { - self.compilation.entries.keys().collect() + pub fn keys(&self) -> Result> { + let compilation = self.as_ref()?; + Ok(compilation.entries.keys().collect()) } #[napi] - pub fn values(&'static self) -> Vec { - self - .compilation - .entries - .values() - .cloned() - .map(|value| { - // To resolve the lifetime issue, `&'static self` is converted to `&'static mut self`. - // Since JS is single-threaded, data races theoretically should not occur, making this safe. - // However, this approach is highly hacky. It is recommended to look for a better solution in the future. - let compilation_ptr = self.compilation as *const Compilation as *mut Compilation; - let compilation = unsafe { &mut *compilation_ptr }; - EntryDataDTO { - entry_data: value, - compilation, - } - }) - .collect() + pub fn values(&self) -> Result> { + let compilation = self.as_ref()?; + Ok( + compilation + .entries + .keys() + .cloned() + .map(|value| JsEntryData { + key: value, + compilation: self.compilation, + }) + .collect(), + ) } } diff --git a/crates/rspack_binding_values/src/compilation/mod.rs b/crates/rspack_binding_values/src/compilation/mod.rs index 8b243717b1c..0426e227ecd 100644 --- a/crates/rspack_binding_values/src/compilation/mod.rs +++ b/crates/rspack_binding_values/src/compilation/mod.rs @@ -53,30 +53,28 @@ pub struct JsCompilation { impl JsCompilation { fn as_ref(&self) -> napi::Result<&'static Compilation> { let compilation = unsafe { self.inner.as_ref() }; - return Ok(compilation); - // if compilation.id() == self.id { - // return Ok(compilation); - // } + if compilation.id() == self.id { + return Ok(compilation); + } - // Err(napi::Error::from_reason(format!( - // "Unable to access compilation with id = {:?} now. The compilation have been removed on the Rust side. The latest compilation id is {:?}", - // self.id, - // compilation.id() - // ))) + Err(napi::Error::from_reason(format!( + "Unable to access compilation with id = {:?} now. The compilation have been removed on the Rust side. The latest compilation id is {:?}", + self.id, + compilation.id() + ))) } fn as_mut(&mut self) -> napi::Result<&'static mut Compilation> { let compilation = unsafe { self.inner.as_mut() }; - return Ok(compilation); - // if compilation.id() == self.id { - // return Ok(compilation); - // } + if compilation.id() == self.id { + return Ok(compilation); + } - // Err(napi::Error::from_reason(format!( - // "Unable to access compilation with id = {:?} now. The compilation have been removed on the Rust side. The latest compilation id is {:?}", - // self.id, - // compilation.id() - // ))) + Err(napi::Error::from_reason(format!( + "Unable to access compilation with id = {:?} now. The compilation have been removed on the Rust side. The latest compilation id is {:?}", + self.id, + compilation.id() + ))) } } @@ -728,7 +726,7 @@ impl JsCompilation { } #[napi( - ts_args_type = "args: [string, RawDependency, JsEntryOptions | undefined][], callback: (errMsg: Error | null, results: [string | null, JsDependency | null, JsModule | null][]) => void" + ts_args_type = "args: [string, RawDependency, RawEntryOptions | undefined][], callback: (errMsg: Error | null, results: [string | null, JsDependency | null, JsModule | null][]) => void" )] pub fn add_include( &mut self, diff --git a/packages/rspack/src/Compilation.ts b/packages/rspack/src/Compilation.ts index 3fa866aa74d..5e3443dbad0 100644 --- a/packages/rspack/src/Compilation.ts +++ b/packages/rspack/src/Compilation.ts @@ -1313,8 +1313,7 @@ class AddIncludeDispatcher { } export class EntryData { - dependencies: Dependency[]; - includeDependencies: Dependency[]; + #binding: binding.JsEntryData; options: binding.JsEntryOptions; static __from_binding(binding: binding.JsEntryData): EntryData { @@ -1322,13 +1321,57 @@ export class EntryData { } private constructor(binding: binding.JsEntryData) { - this.dependencies = binding.dependencies.map(d => + this.#binding = binding; + this.options = binding.options; + } + + get dependencies(): Dependency[] { + const array = this.#binding.dependencies.map(d => bindingDependencyFactory.create(Dependency, d) ); - this.includeDependencies = binding.includeDependencies.map(d => + return new Proxy(array, { + deleteProperty: (target, propertyKey) => { + Reflect.deleteProperty(target, propertyKey); + this.dependencies = array; + return true; + }, + set: (target, propertyKey, value) => { + Reflect.set(target, propertyKey, value); + this.dependencies = array; + return true; + } + }); + } + + set dependencies(dependencies: Dependency[]) { + this.#binding.dependencies = dependencies.map( + dependency => bindingDependencyFactory.getBinding(dependency)! + ); + } + + get includeDependencies(): Dependency[] { + const array = this.#binding.includeDependencies.map(d => bindingDependencyFactory.create(Dependency, d) ); - this.options = binding.options; + const proxy = new Proxy(array, { + deleteProperty: (target, propertyKey) => { + Reflect.deleteProperty(target, propertyKey); + this.includeDependencies = array; + return true; + }, + set: (target, propertyKey, value) => { + Reflect.set(target, propertyKey, value); + this.includeDependencies = array; + return true; + } + }); + return proxy; + } + + set includeDependencies(dependencies: Dependency[]) { + this.#binding.includeDependencies = dependencies.map( + dependency => bindingDependencyFactory.getBinding(dependency)! + ); } } @@ -1351,8 +1394,7 @@ export class Entries implements Map { ) => void, thisArg?: any ): void { - for (const [key, binding] of this) { - const value = EntryData.__from_binding(binding); + for (const [key, value] of this) { callback.call(thisArg, value, key, this); } } From aad9dce21d0cf58200f27a76b461dec2914ad10d Mon Sep 17 00:00:00 2001 From: Cong-Cong Date: Fri, 3 Jan 2025 11:52:50 +0800 Subject: [PATCH 24/37] fix: hack to fix buildInfo in module --- packages/rspack/src/Module.ts | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/packages/rspack/src/Module.ts b/packages/rspack/src/Module.ts index 538d176aad6..6bce9a9212e 100644 --- a/packages/rspack/src/Module.ts +++ b/packages/rspack/src/Module.ts @@ -197,6 +197,9 @@ export type ContextModuleFactoryAfterResolveResult = const MODULE_MAPPINGS = new WeakMap(); +const BUILD_INFO_MAPPINGS = new Map>(); +const BUILD_META_MAPPINGS = new Map>(); + export class Module { #inner: JsModule; @@ -243,8 +246,19 @@ export class Module { constructor(module: JsModule) { this.#inner = module; - this.buildInfo = {}; - this.buildMeta = {}; + if (BUILD_INFO_MAPPINGS.has(this.#inner.moduleIdentifier)) { + this.buildInfo = BUILD_INFO_MAPPINGS.get(this.#inner.moduleIdentifier)!; + } else { + this.buildInfo = {}; + BUILD_INFO_MAPPINGS.set(this.#inner.moduleIdentifier, this.buildInfo)!; + } + + if (BUILD_META_MAPPINGS.has(this.#inner.moduleIdentifier)) { + this.buildMeta = BUILD_META_MAPPINGS.get(this.#inner.moduleIdentifier)!; + } else { + this.buildMeta = {}; + BUILD_META_MAPPINGS.set(this.#inner.moduleIdentifier, this.buildMeta)!; + } Object.defineProperties(this, { type: { From e42020c66445d42e8a75466815e4d2abe95b167e Mon Sep 17 00:00:00 2001 From: ahabhgk Date: Fri, 3 Jan 2025 15:37:35 +0800 Subject: [PATCH 25/37] feat: add contextInfo.issuerLayer for nmf resolve hooks --- crates/node_binding/binding.d.ts | 4 ++++ crates/node_binding/src/plugins/interceptor.rs | 4 ++++ .../src/normal_module_factory.rs | 4 ++++ packages/rspack/src/Compiler.ts | 12 ++++++++---- packages/rspack/src/Module.ts | 2 +- 5 files changed, 21 insertions(+), 5 deletions(-) diff --git a/crates/node_binding/binding.d.ts b/crates/node_binding/binding.d.ts index bafd90ed991..4e5368265fd 100644 --- a/crates/node_binding/binding.d.ts +++ b/crates/node_binding/binding.d.ts @@ -415,6 +415,7 @@ export interface JsAfterResolveData { request: string context: string issuer: string + issuerLayer?: string fileDependencies: Array contextDependencies: Array missingDependencies: Array @@ -517,6 +518,7 @@ export interface JsBeforeResolveArgs { request: string context: string issuer: string + issuerLayer?: string } export interface JsBuildMeta { @@ -667,6 +669,7 @@ export interface JsFactorizeArgs { request: string context: string issuer: string + issuerLayer?: string } export interface JsFactoryMeta { @@ -802,6 +805,7 @@ export interface JsResolveArgs { request: string context: string issuer: string + issuerLayer?: string } export interface JsResolveForSchemeArgs { diff --git a/crates/node_binding/src/plugins/interceptor.rs b/crates/node_binding/src/plugins/interceptor.rs index 38484881901..b057dc56b13 100644 --- a/crates/node_binding/src/plugins/interceptor.rs +++ b/crates/node_binding/src/plugins/interceptor.rs @@ -1388,6 +1388,7 @@ impl NormalModuleFactoryBeforeResolve for NormalModuleFactoryBeforeResolveTap { .as_ref() .map(|issuer| issuer.to_string()) .unwrap_or_default(), + issuer_layer: data.issuer_layer.clone(), }) .await { @@ -1424,6 +1425,7 @@ impl NormalModuleFactoryFactorize for NormalModuleFactoryFactorizeTap { .as_ref() .map(|issuer| issuer.to_string()) .unwrap_or_default(), + issuer_layer: data.issuer_layer.clone(), }) .await { @@ -1461,6 +1463,7 @@ impl NormalModuleFactoryResolve for NormalModuleFactoryResolveTap { .as_ref() .map(|issuer| issuer.to_string()) .unwrap_or_default(), + issuer_layer: data.issuer_layer.clone(), }) .await { @@ -1523,6 +1526,7 @@ impl NormalModuleFactoryAfterResolve for NormalModuleFactoryAfterResolveTap { .as_ref() .map(|issuer| issuer.to_string()) .unwrap_or_default(), + issuer_layer: data.issuer_layer.clone(), file_dependencies: data .file_dependencies .clone() diff --git a/crates/rspack_binding_values/src/normal_module_factory.rs b/crates/rspack_binding_values/src/normal_module_factory.rs index 0e4ea37ad19..db6c1575ed1 100644 --- a/crates/rspack_binding_values/src/normal_module_factory.rs +++ b/crates/rspack_binding_values/src/normal_module_factory.rs @@ -16,6 +16,7 @@ pub struct JsBeforeResolveArgs { pub request: String, pub context: String, pub issuer: String, + pub issuer_layer: Option, } pub type JsBeforeResolveOutput = (Option, JsBeforeResolveArgs); @@ -25,6 +26,7 @@ pub struct JsFactorizeArgs { pub request: String, pub context: String, pub issuer: String, + pub issuer_layer: Option, } pub type JsFactorizeOutput = JsFactorizeArgs; @@ -34,6 +36,7 @@ pub struct JsResolveArgs { pub request: String, pub context: String, pub issuer: String, + pub issuer_layer: Option, } pub type JsResolveOutput = JsResolveArgs; @@ -50,6 +53,7 @@ pub struct JsAfterResolveData { pub request: String, pub context: String, pub issuer: String, + pub issuer_layer: Option, pub file_dependencies: Vec, pub context_dependencies: Vec, pub missing_dependencies: Vec, diff --git a/packages/rspack/src/Compiler.ts b/packages/rspack/src/Compiler.ts index 66f7cf06128..220b525a259 100644 --- a/packages/rspack/src/Compiler.ts +++ b/packages/rspack/src/Compiler.ts @@ -1295,7 +1295,8 @@ class Compiler { return async function (resolveData: binding.JsBeforeResolveArgs) { const normalizedResolveData: ResolveData = { contextInfo: { - issuer: resolveData.issuer + issuer: resolveData.issuer, + issuerLayer: resolveData.issuerLayer ?? null, }, request: resolveData.request, context: resolveData.context, @@ -1322,7 +1323,8 @@ class Compiler { return async function (resolveData: binding.JsFactorizeArgs) { const normalizedResolveData: ResolveData = { contextInfo: { - issuer: resolveData.issuer + issuer: resolveData.issuer, + issuerLayer: resolveData.issuerLayer ?? null, }, request: resolveData.request, context: resolveData.context, @@ -1349,7 +1351,8 @@ class Compiler { return async function (resolveData: binding.JsFactorizeArgs) { const normalizedResolveData: ResolveData = { contextInfo: { - issuer: resolveData.issuer + issuer: resolveData.issuer, + issuerLayer: resolveData.issuerLayer ?? null, }, request: resolveData.request, context: resolveData.context, @@ -1394,7 +1397,8 @@ class Compiler { return async function (arg: binding.JsAfterResolveData) { const data: ResolveData = { contextInfo: { - issuer: arg.issuer + issuer: arg.issuer, + issuerLayer: arg.issuerLayer ?? null, }, request: arg.request, context: arg.context, diff --git a/packages/rspack/src/Module.ts b/packages/rspack/src/Module.ts index 6bce9a9212e..5c80563658b 100644 --- a/packages/rspack/src/Module.ts +++ b/packages/rspack/src/Module.ts @@ -25,7 +25,7 @@ export type ResourceDataWithData = ResourceData & { export type CreateData = Partial; export type ContextInfo = { issuer: string; - issuerLayer?: string; + issuerLayer?: string | null; }; export type ResolveData = { contextInfo: ContextInfo; From 23025294a6bc833500124b087482d14e152e51d6 Mon Sep 17 00:00:00 2001 From: Cong-Cong Date: Fri, 3 Jan 2025 18:16:43 +0800 Subject: [PATCH 26/37] fix: alias prioity --- .../rspack_core/src/normal_module_factory.rs | 3 +-- .../src/options/resolve/clever_merge.rs | 20 +++++++++---------- 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/crates/rspack_core/src/normal_module_factory.rs b/crates/rspack_core/src/normal_module_factory.rs index f76586db338..81b0000e0dd 100644 --- a/crates/rspack_core/src/normal_module_factory.rs +++ b/crates/rspack_core/src/normal_module_factory.rs @@ -644,8 +644,7 @@ impl NormalModuleFactory { fn calculate_resolve_options(&self, module_rules: &[&ModuleRuleEffect]) -> Option> { let mut resolved: Option = None; - // TODO: 为了 alias 的优先级临时修改,之后修改 - for rule in module_rules.iter().rev() { + for rule in module_rules { if let Some(rule_resolve) = &rule.resolve { if let Some(r) = resolved { resolved = Some(r.merge(rule_resolve.to_owned())); diff --git a/crates/rspack_core/src/options/resolve/clever_merge.rs b/crates/rspack_core/src/options/resolve/clever_merge.rs index 79b4b165463..d68fd6e93da 100644 --- a/crates/rspack_core/src/options/resolve/clever_merge.rs +++ b/crates/rspack_core/src/options/resolve/clever_merge.rs @@ -451,19 +451,19 @@ fn normalize_string_array(a: &[String], b: Vec) -> Vec { } fn extend_alias(a: &Alias, b: Alias) -> Alias { - let mut b = b; - // FIXME: I think this clone can be removed - b.extend(a.clone()); - b.dedup(); - b + // FIXME: I think this to_vec can be removed + let mut a = a.to_vec(); + a.extend(b); + a.dedup(); + a } fn extend_extension_alias(a: &ExtensionAlias, b: ExtensionAlias) -> ExtensionAlias { - let mut b = b; - // FIXME: I think this clone can be removed - b.extend(a.clone()); - b.dedup(); - b + // FIXME: I think this to_vec can be removed + let mut a = a.to_vec(); + a.extend(b); + a.dedup(); + a } #[cfg(test)] From 611bd6a462640e59bcdfbbfa23d0fb4609459862 Mon Sep 17 00:00:00 2001 From: Cong-Cong Date: Fri, 3 Jan 2025 19:03:50 +0800 Subject: [PATCH 27/37] fix: override alias --- crates/rspack_core/src/options/resolve/clever_merge.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/crates/rspack_core/src/options/resolve/clever_merge.rs b/crates/rspack_core/src/options/resolve/clever_merge.rs index d68fd6e93da..7f1ae9ec165 100644 --- a/crates/rspack_core/src/options/resolve/clever_merge.rs +++ b/crates/rspack_core/src/options/resolve/clever_merge.rs @@ -453,8 +453,13 @@ fn normalize_string_array(a: &[String], b: Vec) -> Vec { fn extend_alias(a: &Alias, b: Alias) -> Alias { // FIXME: I think this to_vec can be removed let mut a = a.to_vec(); - a.extend(b); - a.dedup(); + for (key, value) in b { + if let Some((_, v)) = a.iter_mut().find(|(k, _)| *k == key) { + *v = value; + } else { + a.push((key, value)); + } + } a } From 43406b7833b5e7dfacc3989cc53070530ff66043 Mon Sep 17 00:00:00 2001 From: ahabhgk Date: Fri, 3 Jan 2025 19:07:25 +0800 Subject: [PATCH 28/37] add test for override alias --- .../src/options/resolve/clever_merge.rs | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/crates/rspack_core/src/options/resolve/clever_merge.rs b/crates/rspack_core/src/options/resolve/clever_merge.rs index 7f1ae9ec165..3e7533b5e11 100644 --- a/crates/rspack_core/src/options/resolve/clever_merge.rs +++ b/crates/rspack_core/src/options/resolve/clever_merge.rs @@ -2277,4 +2277,31 @@ mod test { } ) } + + #[test] + fn test_merge_resolver_options_20() { + let first = Resolve { + alias: Some(vec![("c".to_string(), vec![AliasMap::Ignore])]), + ..Default::default() + }; + + let second = Resolve { + alias: Some(vec![( + "c".to_string(), + vec![AliasMap::Path("ccc".to_string())], + )]), + ..Default::default() + }; + + pretty_assertions::assert_eq!( + merge_resolve(first, second), + Resolve { + alias: Some(vec![( + "c".to_string(), + vec![AliasMap::Path("ccc".to_string())], + )]), + ..Default::default() + } + ) + } } From 0de93202610b451ae1764cd8386accb5cca455b4 Mon Sep 17 00:00:00 2001 From: ahabhgk Date: Sat, 4 Jan 2025 16:32:57 +0800 Subject: [PATCH 29/37] entrypoints should ordered --- crates/node_binding/binding.d.ts | 2 +- crates/rspack_binding_values/src/compilation/mod.rs | 13 ++++--------- packages/rspack/src/Compilation.ts | 8 ++++---- 3 files changed, 9 insertions(+), 14 deletions(-) diff --git a/crates/node_binding/binding.d.ts b/crates/node_binding/binding.d.ts index 4e5368265fd..2c659b3814b 100644 --- a/crates/node_binding/binding.d.ts +++ b/crates/node_binding/binding.d.ts @@ -105,7 +105,7 @@ export declare class JsCompilation { emitAsset(filename: string, source: JsCompatSource, assetInfo: JsAssetInfo): void deleteAsset(filename: string): void renameAsset(filename: string, newName: string): void - get entrypoints(): Record + get entrypoints(): JsChunkGroup[] get chunkGroups(): JsChunkGroup[] get hash(): string | null dependencies(): JsDependencies diff --git a/crates/rspack_binding_values/src/compilation/mod.rs b/crates/rspack_binding_values/src/compilation/mod.rs index 0426e227ecd..96634d6bd5c 100644 --- a/crates/rspack_binding_values/src/compilation/mod.rs +++ b/crates/rspack_binding_values/src/compilation/mod.rs @@ -379,20 +379,15 @@ impl JsCompilation { Ok(()) } - #[napi(getter, ts_return_type = "Record")] - pub fn entrypoints(&self) -> Result> { + #[napi(getter, ts_return_type = "JsChunkGroup[]")] + pub fn entrypoints(&self) -> Result> { let compilation = self.as_ref()?; Ok( compilation .entrypoints() - .iter() - .map(|(n, _)| { - ( - n, - JsChunkGroupWrapper::new(compilation.entrypoint_by_name(n).ukey, compilation), - ) - }) + .values() + .map(|ukey| JsChunkGroupWrapper::new(*ukey, compilation)) .collect(), ) } diff --git a/packages/rspack/src/Compilation.ts b/packages/rspack/src/Compilation.ts index 5e3443dbad0..09c72fd03ff 100644 --- a/packages/rspack/src/Compilation.ts +++ b/packages/rspack/src/Compilation.ts @@ -407,10 +407,10 @@ BREAKING CHANGE: Asset processing hooks in Compilation has been merged into a si */ get entrypoints(): ReadonlyMap { return new Map( - Object.entries(this.#inner.entrypoints).map(([n, e]) => [ - n, - Entrypoint.__from_binding(e) - ]) + this.#inner.entrypoints.map((binding) => { + const entrypoint = Entrypoint.__from_binding(binding); + return [entrypoint.name!, entrypoint] + }) ); } From 16534d889e4c8142119995c886b853bed70e85ef Mon Sep 17 00:00:00 2001 From: Cong-Cong Date: Mon, 6 Jan 2025 12:13:19 +0800 Subject: [PATCH 30/37] fix: add_include clean entry --- crates/rspack_core/src/compiler/compilation.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/rspack_core/src/compiler/compilation.rs b/crates/rspack_core/src/compiler/compilation.rs index b78ddc54c4b..82a88b8bdb0 100644 --- a/crates/rspack_core/src/compiler/compilation.rs +++ b/crates/rspack_core/src/compiler/compilation.rs @@ -593,7 +593,7 @@ impl Compilation { self.make_artifact = update_module_graph( self, make_artifact, - vec![MakeParam::BuildEntryAndClean( + vec![MakeParam::BuildEntry( self .entries .values() From f82d3d6cd393dfd22661bb1afdfd8f018b451e47 Mon Sep 17 00:00:00 2001 From: Cong-Cong Date: Mon, 6 Jan 2025 18:53:09 +0800 Subject: [PATCH 31/37] feat: add constructor name for concatenated module --- crates/node_binding/binding.d.ts | 1 + crates/rspack_binding_values/src/module.rs | 6 ++++++ crates/rspack_core/src/concatenated_module.rs | 4 ++++ crates/rspack_core/src/module.rs | 4 ++++ 4 files changed, 15 insertions(+) diff --git a/crates/node_binding/binding.d.ts b/crates/node_binding/binding.d.ts index 2c659b3814b..3ac0f01bc9e 100644 --- a/crates/node_binding/binding.d.ts +++ b/crates/node_binding/binding.d.ts @@ -219,6 +219,7 @@ export declare class JsExportsInfo { } export declare class JsModule { + get constructorName(): string get context(): string | undefined get originalSource(): JsCompatSource | undefined get resource(): string | undefined diff --git a/crates/rspack_binding_values/src/module.rs b/crates/rspack_binding_values/src/module.rs index a7d1f42eeed..1325fbfe18c 100644 --- a/crates/rspack_binding_values/src/module.rs +++ b/crates/rspack_binding_values/src/module.rs @@ -68,6 +68,12 @@ impl JsModule { #[napi] impl JsModule { + #[napi(getter)] + pub fn constructor_name(&mut self) -> napi::Result { + let module = self.as_ref()?; + Ok(module.constructor_name().to_string()) + } + #[napi(getter)] pub fn context(&mut self) -> napi::Result> { let module = self.as_ref()?; diff --git a/crates/rspack_core/src/concatenated_module.rs b/crates/rspack_core/src/concatenated_module.rs index 4b87057d969..08ca0624f44 100644 --- a/crates/rspack_core/src/concatenated_module.rs +++ b/crates/rspack_core/src/concatenated_module.rs @@ -472,6 +472,10 @@ impl DependenciesBlock for ConcatenatedModule { #[cacheable_dyn] #[async_trait::async_trait] impl Module for ConcatenatedModule { + fn constructor_name(&self) -> &'static str { + "ConcatenatedModule" + } + fn module_type(&self) -> &ModuleType { // https://github.com/webpack/webpack/blob/1f99ad6367f2b8a6ef17cce0e058f7a67fb7db18/lib/optimize/ConcatenatedModule.js#L688 &ModuleType::JsEsm diff --git a/crates/rspack_core/src/module.rs b/crates/rspack_core/src/module.rs index df3d2ee7b5f..25af2e15398 100644 --- a/crates/rspack_core/src/module.rs +++ b/crates/rspack_core/src/module.rs @@ -210,6 +210,10 @@ pub trait Module: + Diagnosable + ModuleSourceMapConfig { + fn constructor_name(&self) -> &'static str { + "Module" + } + /// Defines what kind of module this is. fn module_type(&self) -> &ModuleType; From f696097264a20b94bc91ec01d5e3ff6d713fbc9b Mon Sep 17 00:00:00 2001 From: Cong-Cong Date: Tue, 7 Jan 2025 16:50:04 +0800 Subject: [PATCH 32/37] perf: one shot ref for class instance --- .../rspack_binding_values/src/dependency.rs | 12 +- crates/rspack_binding_values/src/module.rs | 14 ++- crates/rspack_napi/src/js_values/mod.rs | 1 + .../src/js_values/one_shot_instance_ref.rs | 106 ++++++++++++++++++ crates/rspack_napi/src/lib.rs | 1 + 5 files changed, 122 insertions(+), 12 deletions(-) create mode 100644 crates/rspack_napi/src/js_values/one_shot_instance_ref.rs diff --git a/crates/rspack_binding_values/src/dependency.rs b/crates/rspack_binding_values/src/dependency.rs index 4381cf7b346..5bbc84d0dc1 100644 --- a/crates/rspack_binding_values/src/dependency.rs +++ b/crates/rspack_binding_values/src/dependency.rs @@ -3,7 +3,7 @@ use std::{cell::RefCell, ptr::NonNull}; use napi::{bindgen_prelude::ToNapiValue, Either, Env, JsString}; use napi_derive::napi; use rspack_core::{Compilation, CompilationId, Dependency, DependencyId}; -use rspack_napi::OneShotRef; +use rspack_napi::OneShotInstanceRef; use rspack_plugin_javascript::dependency::{ CommonJsExportRequireDependency, ESMExportImportedSpecifierDependency, ESMImportSpecifierDependency, @@ -140,7 +140,7 @@ impl JsDependency { } } -type DependencyInstanceRefs = HashMap>; +type DependencyInstanceRefs = HashMap>; type DependencyInstanceRefsByCompilationId = RefCell>; @@ -199,9 +199,9 @@ impl ToNapiValue for JsDependencyWrapper { }; match refs.entry(val.dependency_id) { - std::collections::hash_map::Entry::Occupied(occupied_entry) => { - let r = occupied_entry.get(); - let instance = r.from_napi_mut_ref()?; + std::collections::hash_map::Entry::Occupied(mut occupied_entry) => { + let r = occupied_entry.get_mut(); + let instance = &mut **r; instance.compilation = val.compilation; instance.dependency = val.dependency; @@ -213,7 +213,7 @@ impl ToNapiValue for JsDependencyWrapper { dependency_id: val.dependency_id, dependency: val.dependency, }; - let r = vacant_entry.insert(OneShotRef::new(env, js_dependency)?); + let r = vacant_entry.insert(OneShotInstanceRef::new(env, js_dependency)?); ToNapiValue::to_napi_value(env, r) } } diff --git a/crates/rspack_binding_values/src/module.rs b/crates/rspack_binding_values/src/module.rs index 1325fbfe18c..71f4bce98ea 100644 --- a/crates/rspack_binding_values/src/module.rs +++ b/crates/rspack_binding_values/src/module.rs @@ -8,7 +8,9 @@ use rspack_core::{ ExportsArgument, LibIdentOptions, Module, ModuleArgument, ModuleIdentifier, RuntimeModuleStage, SourceType, }; -use rspack_napi::{napi::bindgen_prelude::*, threadsafe_function::ThreadsafeFunction, OneShotRef}; +use rspack_napi::{ + napi::bindgen_prelude::*, threadsafe_function::ThreadsafeFunction, OneShotInstanceRef, +}; use rspack_plugin_runtime::RuntimeModuleFromJs; use rspack_util::source_map::SourceMapKind; use rustc_hash::FxHashMap as HashMap; @@ -345,7 +347,7 @@ impl JsModule { } } -type ModuleInstanceRefs = IdentifierMap>; +type ModuleInstanceRefs = IdentifierMap>; type ModuleInstanceRefsByCompilationId = RefCell>; @@ -418,9 +420,9 @@ impl ToNapiValue for JsModuleWrapper { }; match refs.entry(module.identifier()) { - std::collections::hash_map::Entry::Occupied(entry) => { - let r = entry.get(); - let instance = r.from_napi_mut_ref()?; + std::collections::hash_map::Entry::Occupied(mut entry) => { + let r = entry.get_mut(); + let instance = &mut **r; instance.compilation = val.compilation; instance.module = val.module; ToNapiValue::to_napi_value(env, r) @@ -432,7 +434,7 @@ impl ToNapiValue for JsModuleWrapper { compilation_id: val.compilation_id, compilation: val.compilation, }; - let r = entry.insert(OneShotRef::new(env, js_module)?); + let r = entry.insert(OneShotInstanceRef::new(env, js_module)?); ToNapiValue::to_napi_value(env, r) } } diff --git a/crates/rspack_napi/src/js_values/mod.rs b/crates/rspack_napi/src/js_values/mod.rs index e63b3ddf498..a1dfd46a1e5 100644 --- a/crates/rspack_napi/src/js_values/mod.rs +++ b/crates/rspack_napi/src/js_values/mod.rs @@ -1,3 +1,4 @@ pub mod js_value_ref; +pub mod one_shot_instance_ref; pub mod one_shot_value_ref; pub mod value_ref; diff --git a/crates/rspack_napi/src/js_values/one_shot_instance_ref.rs b/crates/rspack_napi/src/js_values/one_shot_instance_ref.rs new file mode 100644 index 00000000000..b4f3db58e99 --- /dev/null +++ b/crates/rspack_napi/src/js_values/one_shot_instance_ref.rs @@ -0,0 +1,106 @@ +#![allow(clippy::not_unsafe_ptr_arg_deref)] + +use std::cell::{Cell, RefCell}; +use std::marker::PhantomData; +use std::ops::{Deref, DerefMut}; +use std::ptr; + +use napi::bindgen_prelude::{check_status, JavaScriptClassExt, ToNapiValue}; +use napi::sys::{self, napi_env}; +use napi::{CleanupEnvHook, Env, Result}; + +thread_local! { + static CLEANUP_ENV_HOOK: RefCell>> = Default::default(); + + // cleanup references to be executed when the JS thread exits normally + static GLOBAL_CLEANUP_FLAG: Cell = const { Cell::new(false) }; +} + +// A RAII (Resource Acquisition Is Initialization) style wrapper around `Ref` that ensures the +// reference is unreferenced when it goes out of scope. This struct maintains a single reference +// count and automatically cleans up when it is dropped. +pub struct OneShotInstanceRef { + env: napi_env, + napi_ref: sys::napi_ref, + inner: *mut T, + ty: PhantomData, +} + +impl OneShotInstanceRef { + pub fn new(env: napi_env, val: T) -> Result { + let env_wrapper = Env::from_raw(env); + let mut instance = val.into_instance(&env_wrapper)?; + + let mut napi_ref = ptr::null_mut(); + check_status!(unsafe { sys::napi_create_reference(env, instance.value, 1, &mut napi_ref) })?; + + CLEANUP_ENV_HOOK.with(|ref_cell| { + if ref_cell.borrow().is_none() { + let result = env_wrapper.add_env_cleanup_hook((), move |_| { + CLEANUP_ENV_HOOK.with_borrow_mut(|cleanup_env_hook| *cleanup_env_hook = None); + GLOBAL_CLEANUP_FLAG.set(true); + }); + if let Ok(cleanup_env_hook) = result { + *ref_cell.borrow_mut() = Some(cleanup_env_hook); + } + } + }); + + Ok(Self { + env, + napi_ref, + inner: &mut *instance, + ty: PhantomData, + }) + } +} + +impl Drop for OneShotInstanceRef { + fn drop(&mut self) { + if !GLOBAL_CLEANUP_FLAG.get() { + unsafe { sys::napi_delete_reference(self.env, self.napi_ref) }; + } + } +} + +impl ToNapiValue for &OneShotInstanceRef { + unsafe fn to_napi_value(env: sys::napi_env, val: Self) -> Result { + let mut result = ptr::null_mut(); + check_status!( + unsafe { sys::napi_get_reference_value(env, val.napi_ref, &mut result) }, + "Failed to get reference value" + )?; + Ok(result) + } +} + +impl ToNapiValue for &mut OneShotInstanceRef { + unsafe fn to_napi_value(env: sys::napi_env, val: Self) -> Result { + let mut result = ptr::null_mut(); + check_status!( + unsafe { sys::napi_get_reference_value(env, val.napi_ref, &mut result) }, + "Failed to get reference value" + )?; + Ok(result) + } +} + +impl Deref for OneShotInstanceRef { + type Target = T; + + fn deref(&self) -> &Self::Target { + unsafe { &*self.inner } + } +} + +impl DerefMut for OneShotInstanceRef { + fn deref_mut(&mut self) -> &mut T { + unsafe { &mut *self.inner } + } +} + +impl AsRef for OneShotInstanceRef { + fn as_ref(&self) -> &T { + unsafe { &*self.inner } + } +} diff --git a/crates/rspack_napi/src/lib.rs b/crates/rspack_napi/src/lib.rs index 0f3a5b53f6e..4bedbab602f 100644 --- a/crates/rspack_napi/src/lib.rs +++ b/crates/rspack_napi/src/lib.rs @@ -24,5 +24,6 @@ pub mod napi { pub use napi::*; } +pub use js_values::one_shot_instance_ref::*; pub use js_values::one_shot_value_ref::*; pub use js_values::value_ref::*; From 8ded34b69cf725071e00580f6fd71d1bd332dda5 Mon Sep 17 00:00:00 2001 From: Cong-Cong Date: Tue, 7 Jan 2025 17:06:21 +0800 Subject: [PATCH 33/37] perf: add_include --- crates/rspack_binding_values/src/compilation/mod.rs | 10 ++++------ packages/rspack/src/Compilation.ts | 5 +++-- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/crates/rspack_binding_values/src/compilation/mod.rs b/crates/rspack_binding_values/src/compilation/mod.rs index 96634d6bd5c..ad322ac0694 100644 --- a/crates/rspack_binding_values/src/compilation/mod.rs +++ b/crates/rspack_binding_values/src/compilation/mod.rs @@ -758,12 +758,10 @@ impl JsCompilation { .map(|(dependency, _)| *dependency.id()) .collect::>(); - for arg in args { - compilation - .add_include(vec![arg]) - .await - .map_err(|e| Error::new(napi::Status::GenericFailure, format!("{e}")))?; - } + compilation + .add_include(args) + .await + .map_err(|e| Error::new(napi::Status::GenericFailure, format!("{e}")))?; let module_graph = compilation.get_module_graph(); let results = dependency_ids diff --git a/packages/rspack/src/Compilation.ts b/packages/rspack/src/Compilation.ts index 09c72fd03ff..97507e57cb4 100644 --- a/packages/rspack/src/Compilation.ts +++ b/packages/rspack/src/Compilation.ts @@ -407,9 +407,9 @@ BREAKING CHANGE: Asset processing hooks in Compilation has been merged into a si */ get entrypoints(): ReadonlyMap { return new Map( - this.#inner.entrypoints.map((binding) => { + this.#inner.entrypoints.map(binding => { const entrypoint = Entrypoint.__from_binding(binding); - return [entrypoint.name!, entrypoint] + return [entrypoint.name!, entrypoint]; }) ); } @@ -1265,6 +1265,7 @@ class AddIncludeDispatcher { this.#args = []; const cbs = this.#cbs; this.#cbs = []; + console.log("args.length", args.length); this.#inner(args, (wholeErr, results) => { if (this.#args.length !== 0) { queueMicrotask(this.#execute); From 0496ac8d0257a819d81bbea2cbd299ad21503577 Mon Sep 17 00:00:00 2001 From: Cong-Cong Date: Tue, 7 Jan 2025 17:48:15 +0800 Subject: [PATCH 34/37] perf: cache immutable js field --- crates/node_binding/binding.d.ts | 14 ++-- crates/rspack_binding_values/src/module.rs | 44 +++++------ packages/rspack/src/Dependency.ts | 23 ++++-- packages/rspack/src/Module.ts | 82 ++++++++++++++------ packages/rspack/src/ModuleGraph.ts | 53 ++++++++++++- packages/rspack/src/ModuleGraphConnection.ts | 18 ++++- 6 files changed, 166 insertions(+), 68 deletions(-) diff --git a/crates/node_binding/binding.d.ts b/crates/node_binding/binding.d.ts index 3ac0f01bc9e..58e87ff92fd 100644 --- a/crates/node_binding/binding.d.ts +++ b/crates/node_binding/binding.d.ts @@ -220,26 +220,26 @@ export declare class JsExportsInfo { export declare class JsModule { get constructorName(): string - get context(): string | undefined + get context(): string | null get originalSource(): JsCompatSource | undefined - get resource(): string | undefined + get resource(): string | null get moduleIdentifier(): string get nameForCondition(): string | undefined - get request(): string | undefined + get request(): string | null get userRequest(): string | undefined set userRequest(val: string) - get rawRequest(): string | undefined + get rawRequest(): string | null get factoryMeta(): JsFactoryMeta | undefined get type(): string - get layer(): string | undefined + get layer(): string | null get blocks(): JsDependenciesBlock[] get dependencies(): JsDependency[] size(ty?: string | undefined | null): number get modules(): JsModule[] | undefined get useSourceMap(): boolean libIdent(options: JsLibIdentOptions): string | null - get resourceResolveData(): JsResourceData | undefined - get matchResource(): string | undefined + get resourceResolveData(): JsResourceData | null + get matchResource(): string | null get loaders(): Array | undefined } diff --git a/crates/rspack_binding_values/src/module.rs b/crates/rspack_binding_values/src/module.rs index 71f4bce98ea..e9f6cf45a5d 100644 --- a/crates/rspack_binding_values/src/module.rs +++ b/crates/rspack_binding_values/src/module.rs @@ -77,12 +77,12 @@ impl JsModule { } #[napi(getter)] - pub fn context(&mut self) -> napi::Result> { + pub fn context(&mut self) -> napi::Result> { let module = self.as_ref()?; Ok(match module.get_context() { - Some(ctx) => Either::A(ctx.to_string()), - None => Either::B(()), + Some(ctx) => Some(ctx.to_string()), + None => None, }) } @@ -103,12 +103,12 @@ impl JsModule { } #[napi(getter)] - pub fn resource(&mut self) -> napi::Result> { + pub fn resource(&mut self) -> napi::Result> { let module = self.as_ref()?; Ok(match module.try_as_normal_module() { - Ok(normal_module) => Either::A(&normal_module.resource_resolved_data().resource), - Err(_) => Either::B(()), + Ok(normal_module) => Some(&normal_module.resource_resolved_data().resource), + Err(_) => None, }) } @@ -130,12 +130,12 @@ impl JsModule { } #[napi(getter)] - pub fn request(&mut self) -> napi::Result> { + pub fn request(&mut self) -> napi::Result> { let module = self.as_ref()?; Ok(match module.try_as_normal_module() { - Ok(normal_module) => Either::A(normal_module.request()), - Err(_) => Either::B(()), + Ok(normal_module) => Some(normal_module.request()), + Err(_) => None, }) } @@ -160,12 +160,12 @@ impl JsModule { } #[napi(getter)] - pub fn raw_request(&mut self) -> napi::Result> { + pub fn raw_request(&mut self) -> napi::Result> { let module = self.as_ref()?; Ok(match module.try_as_normal_module() { - Ok(normal_module) => Either::A(normal_module.raw_request()), - Err(_) => Either::B(()), + Ok(normal_module) => Some(normal_module.raw_request()), + Err(_) => None, }) } @@ -192,12 +192,12 @@ impl JsModule { } #[napi(getter)] - pub fn layer(&mut self) -> napi::Result> { + pub fn layer(&mut self) -> napi::Result> { let module = self.as_ref()?; Ok(match module.get_layer() { - Some(layer) => Either::A(layer), - None => Either::B(()), + Some(layer) => Some(layer), + None => None, }) } @@ -310,23 +310,23 @@ impl JsModule { } #[napi(getter)] - pub fn resource_resolve_data(&mut self) -> napi::Result> { + pub fn resource_resolve_data(&mut self) -> napi::Result> { let module = self.as_ref()?; Ok(match module.as_normal_module() { - Some(module) => Either::A(module.resource_resolved_data().into()), - None => Either::B(()), + Some(module) => Some(module.resource_resolved_data().into()), + None => None, }) } #[napi(getter)] - pub fn match_resource(&mut self) -> napi::Result> { + pub fn match_resource(&mut self) -> napi::Result> { let module = self.as_ref()?; Ok(match module.as_normal_module() { Some(module) => match &module.match_resource() { - Some(match_resource) => Either::A(&match_resource.resource), - None => Either::B(()), + Some(match_resource) => Some(&match_resource.resource), + None => None, }, - None => Either::B(()), + None => None, }) } diff --git a/packages/rspack/src/Dependency.ts b/packages/rspack/src/Dependency.ts index 0e86b221d08..6bfd3f1a7c1 100644 --- a/packages/rspack/src/Dependency.ts +++ b/packages/rspack/src/Dependency.ts @@ -26,20 +26,27 @@ export const bindingDependencyFactory = { }; export class Dependency { + #type: string | undefined; + #category: string | undefined; + get type(): string { - const binding = bindingDependencyFactory.getBinding(this); - if (binding) { - return binding.type; + if (this.#type === undefined) { + const binding = bindingDependencyFactory.getBinding(this); + if (binding) { + this.#type = binding.type; + } } - return "unknown"; + return this.#type || "unknown"; } get category(): string { - const binding = bindingDependencyFactory.getBinding(this); - if (binding) { - return binding.category; + if (this.#category === undefined) { + const binding = bindingDependencyFactory.getBinding(this); + if (binding) { + this.#category = binding.category; + } } - return "unknown"; + return this.#category || "unknown"; } get request(): string | undefined { diff --git a/packages/rspack/src/Module.ts b/packages/rspack/src/Module.ts index 5c80563658b..0f191be177a 100644 --- a/packages/rspack/src/Module.ts +++ b/packages/rspack/src/Module.ts @@ -202,14 +202,23 @@ const BUILD_META_MAPPINGS = new Map>(); export class Module { #inner: JsModule; - - declare readonly context?: string; - declare readonly resource?: string; - declare readonly request?: string; + #identifier: string | undefined; + #type: string | undefined; + #layer: string | undefined | null; + #context: string | undefined | null; + #resource: string | undefined | null; + #request: string | undefined | null; + #rawRequest: string | undefined | null; + #resourceResolveData: ResolveData | undefined | null; + #matchResource: string | undefined | null; + + declare readonly context: string | null; + declare readonly resource: string | null; + declare readonly request: string | null; declare userRequest?: string; - declare readonly rawRequest?: string; + declare readonly rawRequest: string | null; declare readonly type: string; - declare readonly layer: null | string; + declare readonly layer: string | null; declare readonly factoryMeta?: JsFactoryMeta; declare readonly modules: Module[] | undefined; @@ -263,32 +272,47 @@ export class Module { Object.defineProperties(this, { type: { enumerable: true, - get(): string | null { - return module.type || null; + get: (): string => { + if (this.#type === undefined) { + this.#type = module.type; + } + return this.#type; } }, layer: { enumerable: true, - get(): string | undefined { - return module.layer; + get: (): string | null => { + if (this.#layer === undefined) { + this.#layer = module.layer; + } + return this.#layer; } }, context: { enumerable: true, - get(): string | undefined { - return module.context; + get: (): string | null => { + if (this.#context === undefined) { + this.#context = module.context; + } + return this.#context; } }, resource: { enumerable: true, - get(): string | undefined { - return module.resource; + get: (): string | null => { + if (this.#resource === undefined) { + this.#resource = module.resource; + } + return this.#resource; } }, request: { enumerable: true, - get(): string | undefined { - return module.request; + get: (): string | null => { + if (this.#request === undefined) { + this.#request = module.request; + } + return this.#request; } }, userRequest: { @@ -302,8 +326,11 @@ export class Module { }, rawRequest: { enumerable: true, - get(): string | undefined { - return module.rawRequest; + get: (): string | null => { + if (this.#rawRequest === undefined) { + this.#rawRequest = module.rawRequest; + } + return this.#rawRequest; } }, factoryMeta: { @@ -351,14 +378,20 @@ export class Module { }, resourceResolveData: { enumerable: true, - get(): ResolveData | undefined { - return module.resourceResolveData as any; + get: (): ResolveData | null => { + if (this.#resourceResolveData === undefined) { + this.#resourceResolveData = module.resourceResolveData as any; + } + return this.#resourceResolveData!; } }, matchResource: { enumerable: true, - get(): string | undefined { - return module.matchResource; + get: (): string | null => { + if (this.#matchResource === undefined) { + this.#matchResource = module.matchResource; + } + return this.#matchResource; } } }); @@ -372,7 +405,10 @@ export class Module { } identifier(): string { - return this.#inner.moduleIdentifier; + if (this.#identifier === undefined) { + this.#identifier = this.#inner.moduleIdentifier; + } + return this.#identifier; } nameForCondition(): string | null { diff --git a/packages/rspack/src/ModuleGraph.ts b/packages/rspack/src/ModuleGraph.ts index b822a055729..fc115b3f433 100644 --- a/packages/rspack/src/ModuleGraph.ts +++ b/packages/rspack/src/ModuleGraph.ts @@ -4,12 +4,37 @@ import { ExportsInfo } from "./ExportsInfo"; import { Module } from "./Module"; import { ModuleGraphConnection } from "./ModuleGraphConnection"; +class VolatileCache { + #map = new Map(); + + get(key: K): V | undefined { + return this.#map.get(key); + } + + set(key: K, value: V) { + if (this.#map.size === 0) { + queueMicrotask(() => { + this.#map.clear(); + }); + } + this.#map.set(key, value); + } + + has(key: K): boolean { + return this.#map.has(key); + } +} + export default class ModuleGraph { static __from_binding(binding: JsModuleGraph) { return new ModuleGraph(binding); } #inner: JsModuleGraph; + #resolvedModuleMappings = new VolatileCache(); + #outgoingConnectionsMappings = new VolatileCache(); + #parentBlockIndexMappings = new VolatileCache(); + #isAsyncCache = new VolatileCache(); private constructor(binding: JsModuleGraph) { this.#inner = binding; @@ -25,10 +50,15 @@ export default class ModuleGraph { } getResolvedModule(dependency: Dependency): Module | null { + if (this.#resolvedModuleMappings.get(dependency)) { + return this.#resolvedModuleMappings.get(dependency)!; + } const depBinding = bindingDependencyFactory.getBinding(dependency); if (depBinding) { const binding = this.#inner.getResolvedModule(depBinding); - return binding ? Module.__from_binding(binding) : null; + const module = binding ? Module.__from_binding(binding) : null; + this.#resolvedModuleMappings.set(dependency, module); + return module; } return null; } @@ -63,20 +93,35 @@ export default class ModuleGraph { } getOutgoingConnections(module: Module): ModuleGraphConnection[] { - return this.#inner + if (this.#outgoingConnectionsMappings.get(module)) { + return this.#outgoingConnectionsMappings.get(module)!; + } + const connections = this.#inner .getOutgoingConnections(Module.__to_binding(module)) .map(binding => ModuleGraphConnection.__from_binding(binding)); + this.#outgoingConnectionsMappings.set(module, connections); + return connections; } getParentBlockIndex(dependency: Dependency): number { + if (this.#parentBlockIndexMappings.get(dependency)) { + return this.#parentBlockIndexMappings.get(dependency)!; + } const depBinding = bindingDependencyFactory.getBinding(dependency); if (depBinding) { - return this.#inner.getParentBlockIndex(depBinding); + const index = this.#inner.getParentBlockIndex(depBinding); + this.#parentBlockIndexMappings.set(dependency, index); + return index; } return -1; } isAsync(module: Module): boolean { - return this.#inner.isAsync(Module.__to_binding(module)); + if (this.#isAsyncCache.get(module)) { + return this.#isAsyncCache.get(module)!; + } + const result = this.#inner.isAsync(Module.__to_binding(module)); + this.#isAsyncCache.set(module, result); + return result; } } diff --git a/packages/rspack/src/ModuleGraphConnection.ts b/packages/rspack/src/ModuleGraphConnection.ts index abda403c6f5..1e6b18d8986 100644 --- a/packages/rspack/src/ModuleGraphConnection.ts +++ b/packages/rspack/src/ModuleGraphConnection.ts @@ -12,6 +12,8 @@ export class ModuleGraphConnection { declare readonly dependency: Dependency; #inner: JsModuleGraphConnection; + #dependency: Dependency | undefined; + #resolvedModule: Module | undefined | null; static __from_binding(binding: JsModuleGraphConnection) { let connection = MODULE_GRAPH_CONNECTION_MAPPINGS.get(binding); @@ -39,19 +41,27 @@ export class ModuleGraphConnection { }, dependency: { enumerable: true, - get(): Dependency { - return bindingDependencyFactory.create( + get: (): Dependency => { + if (this.#dependency !== undefined) { + return this.#dependency; + } + this.#dependency = bindingDependencyFactory.create( Dependency, binding.dependency ); + return this.#dependency; } }, resolvedModule: { enumerable: true, - get(): Module | null { - return binding.resolvedModule + get: (): Module | null => { + if (this.#resolvedModule !== undefined) { + return this.#resolvedModule; + } + this.#resolvedModule = binding.resolvedModule ? Module.__from_binding(binding.resolvedModule) : null; + return this.#resolvedModule; } }, originModule: { From 81c1a2ef088b6deeb6152a09eaaed1f58ffc4005 Mon Sep 17 00:00:00 2001 From: Cong-Cong Date: Wed, 8 Jan 2025 14:41:57 +0800 Subject: [PATCH 35/37] perf: js source map --- crates/node_binding/binding.d.ts | 16 ++- .../src/plugins/js_loader/context.rs | 126 +++++++++++++++--- .../src/plugins/js_loader/scheduler.rs | 16 +-- packages/rspack/src/loader-runner/index.ts | 22 +-- 4 files changed, 131 insertions(+), 49 deletions(-) diff --git a/crates/node_binding/binding.d.ts b/crates/node_binding/binding.d.ts index 58e87ff92fd..0f69cfa97a0 100644 --- a/crates/node_binding/binding.d.ts +++ b/crates/node_binding/binding.d.ts @@ -733,15 +733,13 @@ export interface JsLibraryOptions { export interface JsLoaderContext { resourceData: Readonly - /** Will be deprecated. Use module.module_identifier instead */ - _moduleIdentifier: Readonly _module: JsModule hot: Readonly /** Content maybe empty in pitching stage */ - content: null | Buffer + content: null | Buffer | string additionalData?: any __internal__parseMeta: Record - sourceMap?: Buffer + sourceMap?: JsSourceMap cacheable: boolean fileDependencies: Array contextDependencies: Array @@ -870,6 +868,16 @@ export interface JsRuntimeRequirementInTreeResult { runtimeRequirements: JsRuntimeGlobals } +export interface JsSourceMap { + version: number + file?: string + sources: Array + sourcesContent?: Array + names: Array + mappings: string + sourceRoot?: string +} + export interface JsStatsAsset { type: string name: string diff --git a/crates/rspack_binding_values/src/plugins/js_loader/context.rs b/crates/rspack_binding_values/src/plugins/js_loader/context.rs index 44c629fcadb..a8e2c3aa05f 100644 --- a/crates/rspack_binding_values/src/plugins/js_loader/context.rs +++ b/crates/rspack_binding_values/src/plugins/js_loader/context.rs @@ -2,13 +2,109 @@ use std::collections::HashMap; use napi::bindgen_prelude::*; use napi_derive::napi; -use rspack_core::{LoaderContext, RunnerContext}; -use rspack_error::error; +use rspack_core::{rspack_sources::SourceMap, LoaderContext, RunnerContext}; use rspack_loader_runner::{LoaderItem, State as LoaderState}; -use rspack_napi::threadsafe_js_value_ref::ThreadsafeJsValueRef; +use rspack_napi::{ + napi::JsString, string::JsStringExt, threadsafe_js_value_ref::ThreadsafeJsValueRef, +}; use crate::{JsModuleWrapper, JsResourceData, JsRspackError}; +#[napi(object)] +pub struct JsSourceMap { + pub version: u8, + pub file: Option, + pub sources: Vec, + pub sources_content: Option>, + pub names: Vec, + pub mappings: JsString, + pub source_root: Option, +} + +pub struct JsSourceMapWrapper(SourceMap); + +impl JsSourceMapWrapper { + pub fn new(source_map: SourceMap) -> Self { + Self(source_map) + } + + pub fn take(self) -> SourceMap { + self.0 + } +} + +impl ToNapiValue for JsSourceMapWrapper { + unsafe fn to_napi_value(env: sys::napi_env, val: Self) -> Result { + let env_wrapper = Env::from_raw(env); + + let file = match val.0.file() { + Some(s) => Some(env_wrapper.create_string(s)?), + None => None, + }; + let mut sources = Vec::with_capacity(val.0.sources().len()); + for source in val.0.sources() { + sources.push(env_wrapper.create_string(source)?); + } + let mut sources_content = Vec::with_capacity(val.0.sources_content().len()); + for source_content in val.0.sources_content() { + sources_content.push(env_wrapper.create_string(source_content)?); + } + let mut names = Vec::with_capacity(val.0.sources_content().len()); + for name in val.0.names() { + names.push(env_wrapper.create_string(name)?); + } + let mappings = env_wrapper.create_string(val.0.mappings())?; + let source_root = match val.0.source_root() { + Some(s) => Some(env_wrapper.create_string(s)?), + None => None, + }; + + let js_source_map = JsSourceMap { + version: 3, + file, + sources, + sources_content: if sources_content.is_empty() { + None + } else { + Some(sources_content) + }, + names, + mappings, + source_root, + }; + ToNapiValue::to_napi_value(env, js_source_map) + } +} + +impl FromNapiValue for JsSourceMapWrapper { + unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> Result { + let js_source_map: JsSourceMap = FromNapiValue::from_napi_value(env, napi_val)?; + + let sources_content = match js_source_map.sources_content { + Some(sources_content) => sources_content + .into_iter() + .map(|source| source.into_string()) + .collect::>(), + None => vec![], + }; + + Ok(JsSourceMapWrapper(SourceMap::new( + js_source_map.mappings.into_string(), + js_source_map + .sources + .into_iter() + .map(|source| source.into_string()) + .collect::>(), + sources_content, + js_source_map + .names + .into_iter() + .map(|source| source.into_string()) + .collect::>(), + ))) + } +} + #[napi(object)] pub struct JsLoaderItem { pub request: String, @@ -57,21 +153,19 @@ impl From for JsLoaderState { pub struct JsLoaderContext { #[napi(ts_type = "Readonly")] pub resource_data: JsResourceData, - /// Will be deprecated. Use module.module_identifier instead - #[napi(js_name = "_moduleIdentifier", ts_type = "Readonly")] - pub module_identifier: String, #[napi(js_name = "_module", ts_type = "JsModule")] pub module: JsModuleWrapper, #[napi(ts_type = "Readonly")] pub hot: bool, /// Content maybe empty in pitching stage - pub content: Either, + pub content: Either3, #[napi(ts_type = "any")] pub additional_data: Option>, #[napi(js_name = "__internal__parseMeta")] pub parse_meta: HashMap, - pub source_map: Option, + #[napi(ts_type = "JsSourceMap")] + pub source_map: Option, pub cacheable: bool, pub file_dependencies: Vec, pub context_dependencies: Vec, @@ -96,25 +190,21 @@ impl TryFrom<&mut LoaderContext> for JsLoaderContext { Ok(JsLoaderContext { resource_data: cx.resource_data.as_ref().into(), - module_identifier: module.identifier().to_string(), module: JsModuleWrapper::new(module, cx.context.compilation_id, None), hot: cx.hot, content: match cx.content() { - Some(c) => Either::B(c.to_owned().into_bytes().into()), - None => Either::A(Null), + Some(c) => match c { + rspack_core::Content::String(s) => Either3::C(s.to_string()), + rspack_core::Content::Buffer(vec) => Either3::B(vec.clone().into()), + }, + None => Either3::A(Null), }, parse_meta: cx.parse_meta.clone().into_iter().collect(), additional_data: cx .additional_data() .and_then(|data| data.get::>()) .cloned(), - source_map: cx - .source_map() - .cloned() - .map(|v| v.to_json()) - .transpose() - .map_err(|e| error!(e.to_string()))? - .map(|v| v.into_bytes().into()), + source_map: cx.source_map().cloned().map(JsSourceMapWrapper::new), cacheable: cx.cacheable, file_dependencies: cx .file_dependencies diff --git a/crates/rspack_binding_values/src/plugins/js_loader/scheduler.rs b/crates/rspack_binding_values/src/plugins/js_loader/scheduler.rs index 49f72259d72..f128ba29d8e 100644 --- a/crates/rspack_binding_values/src/plugins/js_loader/scheduler.rs +++ b/crates/rspack_binding_values/src/plugins/js_loader/scheduler.rs @@ -1,9 +1,9 @@ -use napi::Either; +use napi::bindgen_prelude::Either3; use rspack_core::{ diagnostics::CapturedLoaderError, AdditionalData, LoaderContext, NormalModuleLoaderShouldYield, NormalModuleLoaderStartYielding, RunnerContext, BUILTIN_LOADER_PREFIX, }; -use rspack_error::{error, Result}; +use rspack_error::Result; use rspack_hook::plugin_hook; use rspack_loader_runner::State as LoaderState; @@ -78,15 +78,11 @@ pub(crate) fn merge_loader_context( .collect(); let content = match from.content { - Either::A(_) => None, - Either::B(c) => Some(rspack_core::Content::from(Into::>::into(c))), + Either3::A(_) => None, + Either3::B(c) => Some(rspack_core::Content::from(Into::>::into(c))), + Either3::C(s) => Some(rspack_core::Content::from(s)), }; - let source_map = from - .source_map - .as_ref() - .map(|s| rspack_core::rspack_sources::SourceMap::from_slice(s)) - .transpose() - .map_err(|e| error!(e.to_string()))?; + let source_map = from.source_map.map(|s| s.take()); let additional_data = from.additional_data.take().map(|data| { let mut additional = AdditionalData::default(); additional.insert(data); diff --git a/packages/rspack/src/loader-runner/index.ts b/packages/rspack/src/loader-runner/index.ts index a90e5116721..b81a834532e 100644 --- a/packages/rspack/src/loader-runner/index.ts +++ b/packages/rspack/src/loader-runner/index.ts @@ -42,10 +42,8 @@ import { import { concatErrorMsgAndStack, isNil, - serializeObject, stringifyLoaderObject, - toBuffer, - toObject + toBuffer } from "../util"; import { createHash } from "../util/createHash"; import { @@ -222,16 +220,6 @@ export class LoaderObject { } } -class JsSourceMap { - static __from_binding(map?: Buffer) { - return isNil(map) ? undefined : toObject(map); - } - - static __to_binding(map?: object) { - return serializeObject(map); - } -} - const loadLoaderAsync: (loaderObject: LoaderObject) => Promise = promisify(loadLoader); @@ -679,7 +667,7 @@ export async function runLoaders( name, source!, assetInfo!, - context._moduleIdentifier + context._module.moduleIdentifier ); }; loaderContext.fs = compiler.inputFileSystem; @@ -823,7 +811,7 @@ export async function runLoaders( if (hasArg) { const [content, sourceMap, additionalData] = args; context.content = isNil(content) ? null : toBuffer(content); - context.sourceMap = serializeObject(sourceMap); + context.sourceMap = sourceMap; context.additionalData = additionalData; break; } @@ -833,7 +821,7 @@ export async function runLoaders( } case JsLoaderState.Normal: { let content = context.content; - let sourceMap = JsSourceMap.__from_binding(context.sourceMap); + let sourceMap = context.sourceMap; let additionalData = context.additionalData; while (loaderContext.loaderIndex >= 0) { @@ -857,7 +845,7 @@ export async function runLoaders( } context.content = isNil(content) ? null : toBuffer(content); - context.sourceMap = JsSourceMap.__to_binding(sourceMap); + context.sourceMap = sourceMap; context.additionalData = additionalData; break; From 7969ce013e41b5c693d3362d1bec73df4575e251 Mon Sep 17 00:00:00 2001 From: ahabhgk Date: Wed, 8 Jan 2025 21:23:40 +0800 Subject: [PATCH 36/37] fix incremental forget new entries --- crates/rspack_core/src/build_chunk_graph/mod.rs | 11 +++++++++++ packages/rspack/src/Compilation.ts | 1 - 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/crates/rspack_core/src/build_chunk_graph/mod.rs b/crates/rspack_core/src/build_chunk_graph/mod.rs index ad4a2d23681..64a1e44470c 100644 --- a/crates/rspack_core/src/build_chunk_graph/mod.rs +++ b/crates/rspack_core/src/build_chunk_graph/mod.rs @@ -1,6 +1,7 @@ // use rspack_core::Bundle; // use rspack_core::ChunkGraph; +use incremental::ChunkReCreation; use tracing::instrument; use crate::{incremental::IncrementalPasses, Compilation}; @@ -23,6 +24,16 @@ pub(crate) fn build_chunk_graph(compilation: &mut Compilation) -> rspack_error:: if !enable_incremental || splitter.chunk_group_infos.is_empty() { let inputs = splitter.prepare_input_entrypoints_and_modules(compilation)?; splitter.prepare_entries(inputs, compilation)?; + } else if compilation.entries.len() > compilation.entrypoints.len() { + let more_entries = compilation + .entries + .keys() + .filter(|entry| !compilation.entrypoints.contains_key(entry.as_str())) + .map(|entry| ChunkReCreation::Entry(entry.to_owned())) + .collect::>(); + for entry in more_entries { + entry.rebuild(&mut splitter, compilation)?; + } } splitter.split(compilation)?; diff --git a/packages/rspack/src/Compilation.ts b/packages/rspack/src/Compilation.ts index 97507e57cb4..21cde60a88a 100644 --- a/packages/rspack/src/Compilation.ts +++ b/packages/rspack/src/Compilation.ts @@ -1265,7 +1265,6 @@ class AddIncludeDispatcher { this.#args = []; const cbs = this.#cbs; this.#cbs = []; - console.log("args.length", args.length); this.#inner(args, (wholeErr, results) => { if (this.#args.length !== 0) { queueMicrotask(this.#execute); From a4d9759143fa6d10a458d72308352c97993677b3 Mon Sep 17 00:00:00 2001 From: ahabhgk Date: Thu, 9 Jan 2025 17:13:35 +0800 Subject: [PATCH 37/37] fix module rule use entry func arguments --- crates/rspack_core/src/normal_module_factory.rs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/crates/rspack_core/src/normal_module_factory.rs b/crates/rspack_core/src/normal_module_factory.rs index 81b0000e0dd..860424f661d 100644 --- a/crates/rspack_core/src/normal_module_factory.rs +++ b/crates/rspack_core/src/normal_module_factory.rs @@ -417,13 +417,16 @@ impl NormalModuleFactory { let rule_use = match &rule.r#use { ModuleRuleUse::Array(array_use) => Cow::Borrowed(array_use), ModuleRuleUse::Func(func_use) => { + let resource_data_for_rules = match_resource_data.as_ref().unwrap_or(&resource_data); let context = FuncUseCtx { // align with webpack https://github.com/webpack/webpack/blob/899f06934391baede59da3dcd35b5ef51c675dbe/lib/NormalModuleFactory.js#L576 - // resource shouldn't contain query otherwise it will cause duplicate query in https://github.com/unjs/unplugin/blob/62fdc5ae361d86a6ec39eaef5d8f01e12c6a794d/src/utils.ts#L58 - resource: resource_data.resource_path.clone().map(|x| x.to_string()), - real_resource: Some(user_request.clone()), + resource: resource_data_for_rules + .resource_path + .as_ref() + .map(|x| x.to_string()), + resource_query: resource_data_for_rules.resource_query.clone(), + real_resource: resource_data.resource_path.as_ref().map(|p| p.to_string()), issuer: data.issuer.clone(), - resource_query: resource_data.resource_query.clone(), }; Cow::Owned(func_use(context).await?) }