diff --git a/Cargo.lock b/Cargo.lock index 40bcc236598a..ad65a4ced1a7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2751,15 +2751,17 @@ dependencies = [ [[package]] name = "napi" -version = "3.0.0-beta.2" +version = "3.0.0-beta.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3357a01f87a8c7a1b060067212436b0ab9d3b1f06084406edb926a64b7400985" +checksum = "2e0d1af803835267849e6816cc15ae1d53370e6bf8e1c721363ad50ca2ae1637" dependencies = [ "anyhow", "bitflags 2.9.1", "ctor", "napi-build", "napi-sys", + "nohash-hasher", + "rustc-hash 2.1.1", "serde", "serde_json", "tokio", @@ -2767,15 +2769,15 @@ dependencies = [ [[package]] name = "napi-build" -version = "2.2.0" +version = "3.0.0-beta.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03acbfa4f156a32188bfa09b86dc11a431b5725253fc1fc6f6df5bed273382c4" +checksum = "42908a235da4c4a18c481eb5a8bb38570daa18581a68c508ca8efab662e38bc6" [[package]] name = "napi-derive" -version = "3.0.0-beta.2" +version = "3.0.0-beta.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb71c236fe23004d7abf4a00ad5e86332ea3468f6c48935d283a5d71aa7cca0c" +checksum = "1c48e8ab579e603cb66e0f9048303d25fca9f4275f421c0af150a40080bd299d" dependencies = [ "convert_case 0.8.0", "ctor", @@ -2787,9 +2789,9 @@ dependencies = [ [[package]] name = "napi-derive-backend" -version = "2.0.0-beta.2" +version = "2.0.0-beta.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6aeebae33f1d5d0ad2b65d97e4fa1266d46454dd1a74dc4a9f1f406e7358f5eb" +checksum = "0a767a2d3aa9fe20f7032b9e90912e8061224dc48fcfd5a3e8716dbef8ba39a5" dependencies = [ "convert_case 0.8.0", "proc-macro2", @@ -2800,9 +2802,9 @@ dependencies = [ [[package]] name = "napi-sys" -version = "3.0.0-alpha.1" +version = "3.0.0-alpha.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cc061b99c514ad4b7abc99d4db1ca24b9542b7ff48b4760bd9f82b24611534d" +checksum = "c4401c63f866b42d673a8b213d5662c84a0701b0f6c3acff7e2b9fc439f1675d" dependencies = [ "libloading", ] @@ -2839,6 +2841,12 @@ dependencies = [ "smallvec", ] +[[package]] +name = "nohash-hasher" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bf50223579dc7cdcfb3bfcacf7069ff68243f8c363f62ffa99cf000a6b9c451" + [[package]] name = "nom" version = "5.1.3" diff --git a/Cargo.toml b/Cargo.toml index d17fa03fad4b..9c09fef95dd9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -88,9 +88,9 @@ ustr = { package = "ustr-fxhash", version = "1.0.1" } xxhash-rust = { version = "0.8.14" } # Pinned -napi = { version = "3.0.0-beta.2" } -napi-build = { version = "2.2.0" } -napi-derive = { version = "3.0.0-beta.2" } +napi = { version = "3.0.0-beta.5" } +napi-build = { version = "3.0.0-beta.0" } +napi-derive = { version = "3.0.0-beta.5" } # Serialize and Deserialize inventory = { version = "0.3.17" } diff --git a/crates/node_binding/package.json b/crates/node_binding/package.json index bd8822f3d64f..5775e2645d82 100644 --- a/crates/node_binding/package.json +++ b/crates/node_binding/package.json @@ -1,6 +1,6 @@ { "name": "@rspack/binding", - "version": "1.3.13", + "version": "1.3.15", "license": "MIT", "description": "Node binding for rspack", "main": "binding.js", diff --git a/crates/node_binding/src/exports_info.rs b/crates/node_binding/src/exports_info.rs index 13d5ef7b79fc..9f340586e259 100644 --- a/crates/node_binding/src/exports_info.rs +++ b/crates/node_binding/src/exports_info.rs @@ -2,7 +2,7 @@ use std::ptr::NonNull; use napi::Either; use napi_derive::napi; -use rspack_core::{Compilation, ExportsInfo, ModuleGraph, RuntimeSpec}; +use rspack_core::{Compilation, ExportsInfo, ExportsInfoGetter, ModuleGraph, RuntimeSpec}; use crate::JsRuntimeSpec; @@ -53,11 +53,11 @@ impl JsExportsInfo { Either::A(str) => std::iter::once(str).map(Into::into).collect(), Either::B(vec) => vec.into_iter().map(Into::into).collect(), }); - Ok( - self - .exports_info - .is_module_used(&module_graph, runtime.as_ref()), - ) + let exports_info = ExportsInfoGetter::prefetch(&self.exports_info, &module_graph, None); + Ok(ExportsInfoGetter::is_module_used( + &exports_info, + runtime.as_ref(), + )) } #[napi(ts_args_type = "runtime: string | string[] | undefined")] diff --git a/crates/node_binding/src/module.rs b/crates/node_binding/src/module.rs index 8f5c31ffa61c..96062b79a4d2 100644 --- a/crates/node_binding/src/module.rs +++ b/crates/node_binding/src/module.rs @@ -209,19 +209,35 @@ impl Module { } object.define_properties(&[ - Property::new("type")?.with_value(&env.create_string(module.module_type().as_str())?), - Property::new("context")?.with_getter(context_getter), - Property::new("layer")?.with_getter(layer_getter), - Property::new("useSourceMap")?.with_getter(use_source_map_getter), - Property::new("useSimpleSourceMap")?.with_getter(use_simple_source_map_getter), - Property::new("factoryMeta")? + Property::new() + .with_utf8_name("type")? + .with_value(&env.create_string(module.module_type().as_str())?), + Property::new() + .with_utf8_name("context")? + .with_getter(context_getter), + Property::new() + .with_utf8_name("layer")? + .with_getter(layer_getter), + Property::new() + .with_utf8_name("useSourceMap")? + .with_getter(use_source_map_getter), + Property::new() + .with_utf8_name("useSimpleSourceMap")? + .with_getter(use_simple_source_map_getter), + Property::new() + .with_utf8_name("factoryMeta")? .with_getter(factory_meta_getter) .with_setter(factory_meta_setter), - Property::new("_readableIdentifier")?.with_getter(readable_identifier_getter), - Property::new("buildInfo")? + Property::new() + .with_utf8_name("_readableIdentifier")? + .with_getter(readable_identifier_getter), + Property::new() + .with_utf8_name("buildInfo")? .with_getter(build_info_getter) .with_setter(build_info_setter), - Property::new("buildMeta")?.with_value(&Object::new(env)?), + Property::new() + .with_utf8_name("buildMeta")? + .with_value(&Object::new(env)?), ])?; MODULE_IDENTIFIER_SYMBOL.with(|once_cell| { diff --git a/crates/node_binding/src/modules/external_module.rs b/crates/node_binding/src/modules/external_module.rs index 3c3ceb638a8b..d5c9102dc982 100644 --- a/crates/node_binding/src/modules/external_module.rs +++ b/crates/node_binding/src/modules/external_module.rs @@ -14,7 +14,9 @@ impl ExternalModule { let (_, module) = self.as_ref()?; let user_request = env.create_string(module.user_request())?; - let properties = vec![napi::Property::new("userRequest")?.with_value(&user_request)]; + let properties = vec![napi::Property::new() + .with_utf8_name("userRequest")? + .with_value(&user_request)]; Self::new_inherited(self, env, properties) } diff --git a/crates/node_binding/src/modules/macros.rs b/crates/node_binding/src/modules/macros.rs index 06d3f8d05814..fa5f35d319ae 100644 --- a/crates/node_binding/src/modules/macros.rs +++ b/crates/node_binding/src/modules/macros.rs @@ -203,24 +203,51 @@ macro_rules! impl_module_methods { } properties.push( - napi::Property::new("type")? + napi::Property::new() + .with_utf8_name("type")? .with_value(&env.create_string(module.module_type().as_str())?), ); - properties.push(napi::Property::new("context")?.with_getter(context_getter)); - properties.push(napi::Property::new("layer")?.with_getter(layer_getter)); - properties.push(napi::Property::new("useSourceMap")?.with_getter(use_source_map_getter)); properties.push( - napi::Property::new("useSimpleSourceMap")?.with_getter(use_simple_source_map_getter), + napi::Property::new() + .with_utf8_name("context")? + .with_getter(context_getter) ); properties.push( - napi::Property::new("factoryMeta")? + napi::Property::new() + .with_utf8_name("layer")? + .with_getter(layer_getter) + ); + properties.push( + napi::Property::new() + .with_utf8_name("useSourceMap")? + .with_getter(use_source_map_getter) + ); + properties.push( + napi::Property::new() + .with_utf8_name("useSimpleSourceMap")? + .with_getter(use_simple_source_map_getter), + ); + properties.push( + napi::Property::new() + .with_utf8_name("factoryMeta")? .with_getter(factory_meta_getter) .with_setter(factory_meta_setter), ); - properties.push(napi::Property::new("buildInfo")?.with_getter(build_info_getter).with_setter(build_info_setter)); - properties.push(napi::Property::new("buildMeta")?.with_value(&napi::bindgen_prelude::Object::new(env)?)); properties.push( - napi::Property::new("_readableIdentifier")?.with_getter(readable_identifier_getter), + napi::Property::new() + .with_utf8_name("buildInfo")? + .with_getter(build_info_getter) + .with_setter(build_info_setter) + ); + properties.push( + napi::Property::new() + .with_utf8_name("buildMeta")? + .with_value(&napi::bindgen_prelude::Object::new(env)?) + ); + properties.push( + napi::Property::new() + .with_utf8_name("_readableIdentifier")? + .with_getter(readable_identifier_getter), ); object.define_properties(&properties)?; diff --git a/crates/node_binding/src/modules/normal_module.rs b/crates/node_binding/src/modules/normal_module.rs index 1ae63c678f31..ed536a5c1719 100644 --- a/crates/node_binding/src/modules/normal_module.rs +++ b/crates/node_binding/src/modules/normal_module.rs @@ -86,13 +86,26 @@ impl NormalModule { } let properties = vec![ - napi::Property::new("resource")?.with_value(&resource), - napi::Property::new("request")?.with_value(&request), - napi::Property::new("userRequest")?.with_value(&user_request), - napi::Property::new("rawRequest")?.with_value(&raw_request), - napi::Property::new("resourceResolveData")?.with_value(&resource_resolve_data), - napi::Property::new("loaders")?.with_value(&loaders), - napi::Property::new("matchResource")? + napi::Property::new() + .with_utf8_name("resource")? + .with_value(&resource), + napi::Property::new() + .with_utf8_name("request")? + .with_value(&request), + napi::Property::new() + .with_utf8_name("userRequest")? + .with_value(&user_request), + napi::Property::new() + .with_utf8_name("rawRequest")? + .with_value(&raw_request), + napi::Property::new() + .with_utf8_name("resourceResolveData")? + .with_value(&resource_resolve_data), + napi::Property::new() + .with_utf8_name("loaders")? + .with_value(&loaders), + napi::Property::new() + .with_utf8_name("matchResource")? .with_getter(match_resource_getter) .with_setter(match_resource_setter), ]; diff --git a/crates/node_binding/src/plugins/js_cleanup_plugin.rs b/crates/node_binding/src/plugins/js_cleanup_plugin.rs index 9bf156bc538e..546e29ef6e5e 100644 --- a/crates/node_binding/src/plugins/js_cleanup_plugin.rs +++ b/crates/node_binding/src/plugins/js_cleanup_plugin.rs @@ -2,7 +2,7 @@ use std::sync::atomic::{AtomicBool, Ordering}; use async_trait::async_trait; use derive_more::Debug; -use napi::{bindgen_prelude::External, threadsafe_function::ThreadsafeFunction}; +use napi::{bindgen_prelude::External, threadsafe_function::ThreadsafeFunction, Status}; use rspack_collections::IdentifierSet; use rspack_core::{ ApplyContext, Compilation, CompilationRevokedModules, CompilerFinishMake, CompilerMake, @@ -15,6 +15,7 @@ pub type CleanupRevokedModulesTsFn = ThreadsafeFunction< External>, (), External>, + Status, false, true, 1, diff --git a/crates/node_binding/src/plugins/js_loader/mod.rs b/crates/node_binding/src/plugins/js_loader/mod.rs index 9fdbdb9f52d5..0aebacf6813e 100644 --- a/crates/node_binding/src/plugins/js_loader/mod.rs +++ b/crates/node_binding/src/plugins/js_loader/mod.rs @@ -22,8 +22,15 @@ use tokio::sync::RwLock; use crate::{RspackResultToNapiResultExt, COMPILER_REFERENCES}; -pub type JsLoaderRunner = - ThreadsafeFunction, JsLoaderContext, false, true, 0>; +pub type JsLoaderRunner = ThreadsafeFunction< + JsLoaderContext, + Promise, + JsLoaderContext, + Status, + false, + true, + 0, +>; struct JsLoaderRunnerGetterData { compiler_id: CompilerId, diff --git a/crates/node_binding/src/resource_data.rs b/crates/node_binding/src/resource_data.rs index 5269991168bd..b4667e37285c 100644 --- a/crates/node_binding/src/resource_data.rs +++ b/crates/node_binding/src/resource_data.rs @@ -69,18 +69,34 @@ impl ToNapiValue for ReadonlyResourceDataWrapper { let resource_data = val.i; let mut properties = vec![]; let resource = env_wrapper.create_string(&resource_data.resource)?; - properties.push(Property::new("resource")?.with_value(&resource)); + properties.push( + Property::new() + .with_utf8_name("resource")? + .with_value(&resource), + ); if let Some(path) = &resource_data.resource_path { let path_str = env_wrapper.create_string(path.as_str())?; - properties.push(Property::new("path")?.with_value(&path_str)); + properties.push( + Property::new() + .with_utf8_name("path")? + .with_value(&path_str), + ); } if let Some(query) = &resource_data.resource_query { let query_str = env_wrapper.create_string(query)?; - properties.push(Property::new("query")?.with_value(&query_str)); + properties.push( + Property::new() + .with_utf8_name("query")? + .with_value(&query_str), + ); } if let Some(fragment) = &resource_data.resource_fragment { let fragment_str = env_wrapper.create_string(fragment)?; - properties.push(Property::new("fragment")?.with_value(&fragment_str)); + properties.push( + Property::new() + .with_utf8_name("fragment")? + .with_value(&fragment_str), + ); } let template = ReadonlyResourceData { diff --git a/crates/rspack_core/src/artifacts/cgm_hash_artifact.rs b/crates/rspack_core/src/artifacts/cgm_hash_artifact.rs index 6b1a75b4eebd..8959f6cf2dda 100644 --- a/crates/rspack_core/src/artifacts/cgm_hash_artifact.rs +++ b/crates/rspack_core/src/artifacts/cgm_hash_artifact.rs @@ -13,6 +13,13 @@ impl CgmHashArtifact { self.module_to_hashes.is_empty() } + pub fn get_runtime_map( + &self, + module: &ModuleIdentifier, + ) -> Option<&RuntimeSpecMap> { + self.module_to_hashes.get(module) + } + pub fn get(&self, module: &ModuleIdentifier, runtime: &RuntimeSpec) -> Option<&RspackHashDigest> { let hashes = self.module_to_hashes.get(module)?; hashes.get(runtime) diff --git a/crates/rspack_core/src/build_chunk_graph/new_code_splitter.rs b/crates/rspack_core/src/build_chunk_graph/new_code_splitter.rs index 0e61160a28c8..da9441f478f9 100644 --- a/crates/rspack_core/src/build_chunk_graph/new_code_splitter.rs +++ b/crates/rspack_core/src/build_chunk_graph/new_code_splitter.rs @@ -51,10 +51,7 @@ pub struct CacheableChunkItem { pub struct CodeSplitter { cache_chunk_desc: HashMap>, cache_chunks: UkeyMap, - pub module_deps: ModuleDeps, - pub module_deps_without_runtime: - IdentifierDashMap<(Vec, Vec)>, pub module_ordinal: IdentifierMap, } @@ -120,6 +117,13 @@ impl ChunkDesc { } } + pub(crate) fn chunk_modules(&self) -> &IdentifierSet { + match self { + ChunkDesc::Entry(entry) => &entry.chunk_modules, + ChunkDesc::Chunk(chunk) => &chunk.chunk_modules, + } + } + pub(crate) fn chunk_modules_ordinal(&self) -> &AvailableModules { match self { ChunkDesc::Entry(entry) => &entry.modules_ordinal, @@ -233,7 +237,7 @@ impl CreateChunkRoot { ) .filter_map(|dep_id| module_graph.module_identifier_by_dependency_id(dep_id)) { - splitter.fill_chunk_modules(*m, Some(runtime), &module_graph, &mut ctx); + splitter.fill_chunk_modules(*m, runtime, &module_graph, &mut ctx); } vec![ChunkDesc::Entry(Box::new(EntryChunkDesc { @@ -287,7 +291,7 @@ impl CreateChunkRoot { continue; }; - splitter.fill_chunk_modules(*m, Some(runtime), &module_graph, &mut ctx); + splitter.fill_chunk_modules(*m, runtime, &module_graph, &mut ctx); } if let Some(group_option) = block.get_group_options() @@ -375,14 +379,21 @@ impl CodeSplitter { cache_chunk_desc: Default::default(), cache_chunks: Default::default(), module_deps: Default::default(), - module_deps_without_runtime: Default::default(), module_ordinal, } } + fn invalidate_outgoing_cache(&mut self, module: ModuleIdentifier) { + // refresh module traversal result in the last compilation + for map in self.module_deps.values() { + map.remove(&module); + } + } + // modify the module ordinal for changed_modules pub fn invalidate(&mut self, changed_modules: impl Iterator) { let module_ordinal = &mut self.module_ordinal; + let mut invalidate_outgoing_module = IdentifierSet::default(); for module in changed_modules { // add ordinal for new modules @@ -390,12 +401,7 @@ impl CodeSplitter { module_ordinal.insert(module, module_ordinal.len() as u64); } - // refresh module traversal result in the last compilation - for map in self.module_deps.values() { - map.remove(&module); - } - - self.module_deps_without_runtime.remove(&module); + invalidate_outgoing_module.insert(module); // remove chunks that contains changed module self.cache_chunk_desc.retain(|_, chunks| { @@ -405,9 +411,19 @@ impl CodeSplitter { ChunkDesc::Chunk(normal_chunk_desc) => !normal_chunk_desc.chunk_modules.contains(&module), }); + if !can_reuse { + for chunk in chunks.iter() { + invalidate_outgoing_module.extend(chunk.chunk_desc.chunk_modules().iter().copied()); + } + } + can_reuse }); } + + for m in invalidate_outgoing_module { + self.invalidate_outgoing_cache(m); + } } #[instrument(skip_all)] @@ -485,7 +501,7 @@ impl CodeSplitter { continue; } - let guard = self.outgoings_modules(&module, Some(runtime.as_ref()), &module_graph); + let guard = self.outgoings_modules(&module, runtime.as_ref(), &module_graph); let (modules, blocks) = guard.value(); let blocks = blocks.clone(); for m in modules { @@ -731,14 +747,10 @@ impl CodeSplitter { pub fn outgoings_modules( &self, module: &ModuleIdentifier, - runtime: Option<&RuntimeSpec>, + runtime: &RuntimeSpec, module_graph: &ModuleGraph, ) -> Ref, Vec)> { - let module_map = if let Some(runtime) = runtime { - self.module_deps.get(runtime).expect("should have value") - } else { - &self.module_deps_without_runtime - }; + let module_map = self.module_deps.get(runtime).expect("should have value"); let guard = module_map.get(module); @@ -771,7 +783,7 @@ impl CodeSplitter { 'outer: for (m, conns) in outgoings.iter() { for conn in conns { - let conn_state = conn.active_state(module_graph, runtime); + let conn_state = conn.active_state(module_graph, Some(runtime)); match conn_state { crate::ConnectionState::Active(true) => { modules.insert(*m); @@ -797,7 +809,7 @@ impl CodeSplitter { fn fill_chunk_modules( &self, target_module: ModuleIdentifier, - runtime: Option<&RuntimeSpec>, + runtime: &RuntimeSpec, module_graph: &ModuleGraph, ctx: &mut FillCtx, ) { @@ -971,7 +983,7 @@ impl CodeSplitter { if !self.module_deps.contains_key(runtime) { self.module_deps.insert(runtime.clone(), Default::default()); } - let guard = self.outgoings_modules(&m, Some(runtime), &module_graph); + let guard = self.outgoings_modules(&m, runtime, &module_graph); let (modules, blocks) = guard.value(); for m in modules.iter().rev() { @@ -1113,6 +1125,10 @@ impl CodeSplitter { continue; } + if !reuse { + chunk_desc.chunk_modules(); + } + match chunk_desc { ChunkDesc::Entry(entry_desc) => { let box EntryChunkDesc { diff --git a/crates/rspack_core/src/compiler/compilation.rs b/crates/rspack_core/src/compiler/compilation.rs index fdf615620df4..479fd964b17c 100644 --- a/crates/rspack_core/src/compiler/compilation.rs +++ b/crates/rspack_core/src/compiler/compilation.rs @@ -55,7 +55,7 @@ use crate::{ DependencyId, DependencyTemplate, DependencyTemplateType, DependencyType, Entry, EntryData, EntryOptions, EntryRuntime, Entrypoint, ExecuteModuleId, Filename, ImportVarMap, Logger, ModuleFactory, ModuleGraph, ModuleGraphPartial, ModuleIdentifier, ModuleIdsArtifact, PathData, - ResolverFactory, RuntimeGlobals, RuntimeModule, RuntimeSpecMap, RuntimeTemplate, + ResolverFactory, RuntimeGlobals, RuntimeMode, RuntimeModule, RuntimeSpecMap, RuntimeTemplate, SharedPluginDriver, SideEffectsOptimizeArtifact, SourceType, Stats, }; @@ -1624,6 +1624,58 @@ impl Compilation { _ => {} } } + + // check if module runtime changes + for mi in mg.modules().keys() { + let module_runtimes = self + .chunk_graph + .get_module_runtimes(*mi, &self.chunk_by_ukey); + let module_runtime_keys = module_runtimes + .values() + .map(get_runtime_key) + .collect::>(); + + if let Some(runtime_map) = self.cgm_hash_artifact.get_runtime_map(mi) { + if module_runtimes.is_empty() { + // module has no runtime, skip + continue; + } + if module_runtimes.len() == 1 { + // single runtime + if !matches!(runtime_map.mode, RuntimeMode::SingleEntry) + || runtime_map + .single_runtime + .as_ref() + .expect("should have single runtime for single entry") + != module_runtimes + .values() + .next() + .expect("should have at least one runtime") + { + modules.insert(*mi); + } + } else { + // multiple runtimes + if matches!(runtime_map.mode, RuntimeMode::SingleEntry) { + modules.insert(*mi); + continue; + } + + if runtime_map.map.len() != module_runtimes.len() { + modules.insert(*mi); + continue; + } + + for runtime_key in runtime_map.map.keys() { + if !module_runtime_keys.contains(&runtime_key.as_str()) { + modules.insert(*mi); + break; + } + } + } + } + } + tracing::debug!(target: incremental::TRACING_TARGET, passes = %IncrementalPasses::MODULES_HASHES, %mutations, ?modules); let logger = self.get_logger("rspack.incremental.modulesHashes"); logger.log(format!( @@ -1631,6 +1683,7 @@ impl Compilation { modules.len(), mg.modules().len() )); + modules } else { self.get_module_graph().modules().keys().copied().collect() diff --git a/crates/rspack_core/src/exports/export_info.rs b/crates/rspack_core/src/exports/export_info.rs index 57b696af76d6..96dac0dd5431 100644 --- a/crates/rspack_core/src/exports/export_info.rs +++ b/crates/rspack_core/src/exports/export_info.rs @@ -38,14 +38,14 @@ impl ExportInfo { } pub fn create_nested_exports_info(&self, mg: &mut ModuleGraph) -> ExportsInfo { - let export_info = self.as_data(mg); + let export_info_mut = self.as_data_mut(mg); - if export_info.exports_info_owned { - return export_info + if export_info_mut.exports_info_owned { + return export_info_mut .exports_info .expect("should have exports_info when exports_info is true"); } - let export_info_mut = self.as_data_mut(mg); + export_info_mut.exports_info_owned = true; let other_exports_info = ExportInfoData::new(None, None); let side_effects_only_info = ExportInfoData::new(Some("*side effects only*".into()), None); @@ -67,11 +67,6 @@ impl ExportInfo { new_exports_info_id } - pub fn get_nested_exports_info(&self, mg: &ModuleGraph) -> Option { - let export_info = mg.get_export_info_by_id(self); - export_info.exports_info - } - pub fn set_has_use_info(&self, mg: &mut ModuleGraph) { let export_info = mg.get_export_info_mut_by_id(self); if !export_info.has_use_in_runtime_info { @@ -92,7 +87,7 @@ impl ExportInfo { if info.terminal_binding { return Some(TerminalBinding::ExportInfo(*self)); } - let target = self.get_target(mg)?; + let target = info.get_target(mg)?; let exports_info = mg.get_exports_info(&target.module); let Some(export) = target.export else { return Some(TerminalBinding::ExportsInfo(exports_info)); @@ -102,80 +97,6 @@ impl ExportInfo { .map(TerminalBinding::ExportInfo) } - pub fn get_target(&self, mg: &ModuleGraph) -> Option { - self.get_target_with_filter(mg, Rc::new(|_, _| true)) - } - - pub fn get_target_with_filter( - &self, - mg: &ModuleGraph, - resolve_filter: ResolveFilterFnTy, - ) -> Option { - match self.get_target_impl(mg, resolve_filter, &mut Default::default()) { - Some(ResolvedExportInfoTargetWithCircular::Circular) => None, - Some(ResolvedExportInfoTargetWithCircular::Target(target)) => Some(target), - None => None, - } - } - - fn get_target_impl( - &self, - mg: &ModuleGraph, - resolve_filter: ResolveFilterFnTy, - already_visited: &mut HashSet, - ) -> Option { - let data = self.as_data(mg); - if !data.target_is_set || data.target.is_empty() { - return None; - } - let hash_key = MaybeDynamicTargetExportInfoHashKey::ExportInfo(*self); - if already_visited.contains(&hash_key) { - return Some(ResolvedExportInfoTargetWithCircular::Circular); - } - already_visited.insert(hash_key); - data.get_target_impl(mg, resolve_filter, already_visited) - } - - fn get_max_target<'a>( - &self, - mg: &'a ModuleGraph, - ) -> Cow<'a, HashMap, ExportInfoTargetValue>> { - self.as_data(mg).get_max_target() - } - - pub fn find_target( - &self, - mg: &ModuleGraph, - valid_target_module_filter: Arc bool>, - ) -> FindTargetRetEnum { - self.find_target_impl(mg, valid_target_module_filter, &mut Default::default()) - } - - fn find_target_impl( - &self, - mg: &ModuleGraph, - valid_target_module_filter: Arc bool>, - visited: &mut HashSet, - ) -> FindTargetRetEnum { - self - .as_data(mg) - .find_target_impl(mg, valid_target_module_filter, visited) - } - - pub fn has_info( - &self, - mg: &ModuleGraph, - base_info: ExportInfo, - runtime: Option<&RuntimeSpec>, - ) -> bool { - let data = self.as_data(mg); - data.used_name.is_some() - || data.provided.is_some() - || data.terminal_binding - || (ExportInfoGetter::get_used(self.as_data(mg), runtime) - != ExportInfoGetter::get_used(base_info.as_data(mg), runtime)) - } - pub fn update_hash_with_visited( &self, mg: &ModuleGraph, @@ -287,29 +208,7 @@ impl ExportInfoData { self.id } - fn get_max_target(&self) -> Cow, ExportInfoTargetValue>> { - if self.target.len() <= 1 { - return Cow::Borrowed(&self.target); - } - let mut max_priority = u8::MIN; - let mut min_priority = u8::MAX; - for value in self.target.values() { - max_priority = max_priority.max(value.priority); - min_priority = min_priority.min(value.priority); - } - if max_priority == min_priority { - return Cow::Borrowed(&self.target); - } - let mut map = HashMap::default(); - for (k, v) in self.target.iter() { - if max_priority == v.priority { - map.insert(*k, v.clone()); - } - } - Cow::Owned(map) - } - - fn find_target_impl( + pub fn find_target_impl( &self, mg: &ModuleGraph, valid_target_module_filter: Arc bool>, @@ -318,8 +217,7 @@ impl ExportInfoData { if !self.target_is_set || self.target.is_empty() { return FindTargetRetEnum::Undefined; } - - let max_target = self.get_max_target(); + let max_target = ExportInfoGetter::get_max_target(self); let raw_target = max_target.values().next(); let Some(raw_target) = raw_target else { return FindTargetRetEnum::Undefined; @@ -380,13 +278,46 @@ impl ExportInfoData { } } - fn get_target_impl( + pub fn get_target(&self, mg: &ModuleGraph) -> Option { + self.get_target_with_filter(mg, Rc::new(|_, _| true)) + } + + pub fn get_target_with_filter( + &self, + mg: &ModuleGraph, + resolve_filter: ResolveFilterFnTy, + ) -> Option { + match self.get_target_impl(mg, resolve_filter, &mut Default::default()) { + Some(ResolvedExportInfoTargetWithCircular::Circular) => None, + Some(ResolvedExportInfoTargetWithCircular::Target(target)) => Some(target), + None => None, + } + } + + pub fn get_target_proxy( &self, mg: &ModuleGraph, resolve_filter: ResolveFilterFnTy, already_visited: &mut HashSet, ) -> Option { - let max_target = self.get_max_target(); + if !self.target_is_set || self.target.is_empty() { + return None; + } + let hash_key = MaybeDynamicTargetExportInfoHashKey::ExportInfo(self.id); + if already_visited.contains(&hash_key) { + return Some(ResolvedExportInfoTargetWithCircular::Circular); + } + already_visited.insert(hash_key); + self.get_target_impl(mg, resolve_filter, already_visited) + } + + pub fn get_target_impl( + &self, + mg: &ModuleGraph, + resolve_filter: ResolveFilterFnTy, + already_visited: &mut HashSet, + ) -> Option { + let max_target = ExportInfoGetter::get_max_target(self); let mut values = max_target .values() .map(|item| UnResolvedExportInfoTarget { @@ -501,7 +432,8 @@ impl MaybeDynamicTargetExportInfo { ) -> FindTargetRetEnum { match self { MaybeDynamicTargetExportInfo::Static(export_info) => { - export_info.find_target_impl(mg, valid_target_module_filter, visited) + let data = export_info.as_data(mg); + data.find_target_impl(mg, valid_target_module_filter, visited) } MaybeDynamicTargetExportInfo::Dynamic { data, .. } => { data.find_target_impl(mg, valid_target_module_filter, visited) @@ -529,7 +461,8 @@ impl MaybeDynamicTargetExportInfo { ) -> Option { match self { MaybeDynamicTargetExportInfo::Static(export_info) => { - export_info.get_target_impl(mg, resolve_filter, already_visited) + let export_info_data = export_info.as_data(mg); + export_info_data.get_target_proxy(mg, resolve_filter, already_visited) } MaybeDynamicTargetExportInfo::Dynamic { data, .. } => { if !data.target_is_set || data.target.is_empty() { @@ -550,19 +483,24 @@ impl MaybeDynamicTargetExportInfo { mg: &'a ModuleGraph, ) -> Cow<'a, HashMap, ExportInfoTargetValue>> { match self { - MaybeDynamicTargetExportInfo::Static(export_info) => export_info.get_max_target(mg), - MaybeDynamicTargetExportInfo::Dynamic { data, .. } => data.get_max_target(), + MaybeDynamicTargetExportInfo::Static(export_info) => { + let data = export_info.as_data(mg); + ExportInfoGetter::get_max_target(data) + } + MaybeDynamicTargetExportInfo::Dynamic { data, .. } => ExportInfoGetter::get_max_target(data), } } -} -impl MaybeDynamicTargetExportInfo { pub fn can_move_target( &self, mg: &ModuleGraph, resolve_filter: ResolveFilterFnTy, ) -> Option { - let target = self.get_target_with_filter(mg, resolve_filter)?; + let data = match self { + MaybeDynamicTargetExportInfo::Static(export_info) => export_info.as_data(mg), + MaybeDynamicTargetExportInfo::Dynamic { data, .. } => data, + }; + let target = data.get_target_with_filter(mg, resolve_filter)?; let max_target = self.get_max_target(mg); let original_target = max_target .values() diff --git a/crates/rspack_core/src/exports/export_info_getter.rs b/crates/rspack_core/src/exports/export_info_getter.rs index 06c9c8e32ab3..412911ccbcc9 100644 --- a/crates/rspack_core/src/exports/export_info_getter.rs +++ b/crates/rspack_core/src/exports/export_info_getter.rs @@ -4,8 +4,8 @@ use itertools::Itertools; use rspack_util::atom::Atom; use rustc_hash::FxHashMap as HashMap; -use super::{ExportInfoData, ExportProvided, ExportsInfo, UsageState}; -use crate::RuntimeSpec; +use super::{ExportInfoData, ExportInfoTargetValue, ExportProvided, ExportsInfo, UsageState}; +use crate::{DependencyId, RuntimeSpec}; pub struct ExportInfoGetter; @@ -222,4 +222,28 @@ impl ExportInfoGetter { pub fn has_used_name(info: &ExportInfoData) -> bool { info.used_name.is_some() } + + pub fn get_max_target( + info: &ExportInfoData, + ) -> Cow, ExportInfoTargetValue>> { + if info.target.len() <= 1 { + return Cow::Borrowed(&info.target); + } + let mut max_priority = u8::MIN; + let mut min_priority = u8::MAX; + for value in info.target.values() { + max_priority = max_priority.max(value.priority); + min_priority = min_priority.min(value.priority); + } + if max_priority == min_priority { + return Cow::Borrowed(&info.target); + } + let mut map = HashMap::default(); + for (k, v) in info.target.iter() { + if max_priority == v.priority { + map.insert(*k, v.clone()); + } + } + Cow::Owned(map) + } } diff --git a/crates/rspack_core/src/exports/exports_info.rs b/crates/rspack_core/src/exports/exports_info.rs index 8dd8d161c5e2..ae381abc91e2 100644 --- a/crates/rspack_core/src/exports/exports_info.rs +++ b/crates/rspack_core/src/exports/exports_info.rs @@ -60,6 +60,18 @@ impl ExportsInfo { mg.get_exports_info_by_id(self) } + pub fn as_data<'a>(&self, mg: &'a ModuleGraph) -> &'a ExportsInfoData { + mg.get_exports_info_by_id(self) + } + + fn as_exports_info_mut<'a>(&self, mg: &'a mut ModuleGraph) -> &'a mut ExportsInfoData { + mg.get_exports_info_mut_by_id(self) + } + + pub fn as_data_mut<'a>(&self, mg: &'a mut ModuleGraph) -> &'a mut ExportsInfoData { + mg.get_exports_info_mut_by_id(self) + } + pub fn is_export_provided(&self, mg: &ModuleGraph, names: &[Atom]) -> Option { let name = names.first()?; let info = self.get_read_only_export_info(mg, name); @@ -116,7 +128,7 @@ impl ExportsInfo { /// # Panic /// it will panic if you provide a export info that does not exists in the module graph pub fn set_has_provide_info(&self, mg: &mut ModuleGraph) { - let exports_info = mg.get_exports_info_by_id(self); + let exports_info = self.as_exports_info(mg); let redirect_id = exports_info.redirect_to; let other_exports_info_id = exports_info.other_exports_info; let export_id_list = exports_info.exports.values().copied().collect::>(); @@ -143,7 +155,7 @@ impl ExportsInfo { } pub fn set_redirect_name_to(&self, mg: &mut ModuleGraph, id: Option) -> bool { - let exports_info = mg.get_exports_info_mut_by_id(self); + let exports_info = self.as_exports_info_mut(mg); if exports_info.redirect_to == id { return false; } @@ -168,7 +180,7 @@ impl ExportsInfo { } } - let exports_info = mg.get_exports_info_by_id(self); + let exports_info = self.as_exports_info(mg); let redirect_to = exports_info.redirect_to; let other_exports_info = exports_info.other_exports_info; let exports_id_list = exports_info.exports.values().copied().collect::>(); @@ -263,7 +275,7 @@ impl ExportsInfo { } pub fn get_read_only_export_info(&self, mg: &ModuleGraph, name: &Atom) -> ExportInfo { - let exports_info = mg.get_exports_info_by_id(self); + let exports_info = self.as_exports_info(mg); let redirect_to = exports_info.redirect_to; let other_exports_info = exports_info.other_exports_info; let export_info = exports_info.exports.get(name); @@ -277,7 +289,7 @@ impl ExportsInfo { } pub fn get_export_info(&self, mg: &mut ModuleGraph, name: &Atom) -> ExportInfo { - let exports_info = mg.get_exports_info_by_id(self); + let exports_info: &ExportsInfoData = self.as_exports_info(mg); let redirect_id = exports_info.redirect_to; let other_exports_info_id = exports_info.other_exports_info; let export_info_id = exports_info.exports.get(name); @@ -288,12 +300,12 @@ impl ExportsInfo { return redirect_id.get_export_info(mg, name); } - let other_export_info = mg.get_export_info_by_id(&other_exports_info_id); + let other_export_info = other_exports_info_id.as_data(mg); let new_info = ExportInfoData::new(Some(name.clone()), Some(other_export_info)); let new_info_id = new_info.id; mg.set_export_info(new_info_id, new_info); - let exports_info = mg.get_exports_info_mut_by_id(self); + let exports_info = self.as_exports_info_mut(mg); exports_info.exports.insert(name.clone(), new_info_id); new_info_id } @@ -306,7 +318,7 @@ impl ExportsInfo { mg: &ModuleGraph, name: &Atom, ) -> MaybeDynamicTargetExportInfo { - let exports_info = mg.get_exports_info_by_id(self); + let exports_info = self.as_exports_info(mg); let redirect_id = exports_info.redirect_to; let other_exports_info_id = exports_info.other_exports_info; let export_info_id = exports_info.exports.get(name); @@ -345,7 +357,7 @@ impl ExportsInfo { } pub fn set_has_use_info(&self, mg: &mut ModuleGraph) { - let exports_info = mg.get_exports_info_by_id(self); + let exports_info = self.as_exports_info(mg); let side_effects_only_info_id = exports_info.side_effects_only_info; let redirect_to_id = exports_info.redirect_to; let other_exports_info_id = exports_info.other_exports_info; @@ -368,7 +380,7 @@ impl ExportsInfo { pub fn set_used_without_info(&self, mg: &mut ModuleGraph, runtime: Option<&RuntimeSpec>) -> bool { let mut changed = false; - let exports_info = mg.get_exports_info_mut_by_id(self); + let exports_info = self.as_exports_info_mut(mg); let redirect = exports_info.redirect_to; let other_exports_info_id = exports_info.other_exports_info; // avoid use ref and mut ref at the same time @@ -402,7 +414,7 @@ impl ExportsInfo { runtime: Option<&RuntimeSpec>, ) -> bool { let mut changed = false; - let exports_info = mg.get_exports_info_mut_by_id(self); + let exports_info = self.as_exports_info_mut(mg); let export_info_id_list = exports_info.exports.values().copied().collect::>(); for export_info_id in export_info_id_list { let export_info = export_info_id.as_data_mut(mg); @@ -420,7 +432,7 @@ impl ExportsInfo { runtime: Option<&RuntimeSpec>, ) -> bool { let mut changed = false; - let exports_info = mg.get_exports_info_by_id(self); + let exports_info = self.as_exports_info(mg); let export_info_id_list = exports_info.exports.values().copied().collect::>(); let redirect_to_id = exports_info.redirect_to; let other_exports_info_id = exports_info.other_exports_info; @@ -456,7 +468,7 @@ impl ExportsInfo { mg: &mut ModuleGraph, runtime: Option<&RuntimeSpec>, ) -> bool { - let exports_info = mg.get_exports_info_by_id(self); + let exports_info = self.as_exports_info(mg); let side_effects_only_info_id = exports_info.side_effects_only_info; ExportInfoSetter::set_used_conditionally( side_effects_only_info_id.as_data_mut(mg), @@ -776,7 +788,10 @@ impl ExportsInfo { visited.insert(*self); let data = self.as_exports_info(mg); for export_info in self.ordered_exports(mg) { - if export_info.has_info(mg, data.other_exports_info, runtime) { + let export_info_data = export_info.as_data(mg); + let base_info_data = data.other_exports_info.as_data(mg); + + if ExportInfoGetter::has_info(export_info_data, base_info_data, runtime) { export_info.update_hash_with_visited(mg, hasher, compilation, runtime, visited); } } diff --git a/crates/rspack_core/src/exports/exports_info_getter.rs b/crates/rspack_core/src/exports/exports_info_getter.rs new file mode 100644 index 000000000000..e9fc0bc7cb89 --- /dev/null +++ b/crates/rspack_core/src/exports/exports_info_getter.rs @@ -0,0 +1,299 @@ +use std::{collections::BTreeMap, sync::Arc}; + +use rspack_util::atom::Atom; +use rustc_hash::FxHashMap as HashMap; + +use super::{ExportInfoData, ExportInfoGetter, ExportProvided, ExportsInfo, UsageState}; +use crate::{ModuleGraph, RuntimeSpec}; + +/** + * Used to store data pre-fetched from Module Graph + * so that subsequent exports data reads don't need to access Module Graph + */ +#[derive(Debug, Clone)] +pub struct PrefetchedExportsInfoWrapper<'a> { + /** + * The exports info data that will be accessed from the entry + * stored in a map to prevent circular references + * When redirect, this data can be cloned to generate a new PrefetchedExportsInfoWrapper with a new entry + */ + pub exports: Arc>>, + /** + * The entry of the current exports info + */ + pub entry: ExportsInfo, +} + +impl<'a> PrefetchedExportsInfoWrapper<'a> { + /** + * Get the data of the current exports info + */ + pub fn data(&self) -> &PrefetchedExportsInfoData<'a> { + self + .exports + .get(&self.entry) + .expect("should have nested exports info") + } + + /** + * Generate a new PrefetchedExportsInfoWrapper with a new entry + */ + pub fn redirect(&self, entry: ExportsInfo) -> PrefetchedExportsInfoWrapper<'_> { + PrefetchedExportsInfoWrapper { + exports: self.exports.clone(), + entry, + } + } + + pub fn other_exports_info(&self) -> &ExportInfoData { + self.data().other_exports_info.inner + } + + pub fn side_effects_only_info(&self) -> &ExportInfoData { + self.data().side_effects_only_info.inner + } + + pub fn exports(&self) -> impl Iterator { + self + .data() + .exports + .iter() + .map(|(key, data)| (*key, data.inner)) + } + + pub fn get_read_only_export_info(&self, name: &Atom) -> &ExportInfoData { + self.get_read_only_export_info_impl(&self.entry, name) + } + + pub fn get_read_only_export_info_recursive(&self, names: &[Atom]) -> Option<&ExportInfoData> { + self.get_read_only_export_info_recursive_impl(&self.entry, names) + } + + pub fn get_nested_exports_info( + &self, + name: Option<&[Atom]>, + ) -> Option<&PrefetchedExportsInfoData> { + self.get_nested_exports_info_impl(&self.entry, name) + } + + fn get_nested_exports_info_impl( + &self, + exports_info: &ExportsInfo, + name: Option<&[Atom]>, + ) -> Option<&PrefetchedExportsInfoData> { + if let Some(name) = name + && !name.is_empty() + { + let info = self.get_read_only_export_info_impl(exports_info, &name[0]); + if let Some(exports_info) = &info.exports_info { + return self.get_nested_exports_info_impl(exports_info, Some(&name[1..])); + } else { + return None; + } + } + Some(self.data()) + } + + fn get_read_only_export_info_recursive_impl( + &self, + exports_info: &ExportsInfo, + names: &[Atom], + ) -> Option<&ExportInfoData> { + if names.is_empty() { + return None; + } + let export_info = self.get_read_only_export_info_impl(exports_info, &names[0]); + if names.len() == 1 { + return Some(export_info); + } + export_info + .exports_info + .as_ref() + .and_then(move |nested| self.get_read_only_export_info_recursive_impl(nested, &names[1..])) + } + + fn get_read_only_export_info_impl( + &self, + exports_info: &ExportsInfo, + name: &Atom, + ) -> &ExportInfoData { + let data = self + .exports + .get(exports_info) + .expect("should have nested exports info"); + if let Some(export_info) = data.exports.get(name) { + return export_info.inner; + } + if let Some(redirect) = &data.redirect_to { + return self.get_read_only_export_info_impl(redirect, name); + } + data.other_exports_info.inner + } +} + +#[derive(Debug, Clone)] +pub struct PrefetchedExportsInfoData<'a> { + pub(crate) exports: BTreeMap<&'a Atom, PrefetchedExportInfoData<'a>>, + pub(crate) other_exports_info: PrefetchedExportInfoData<'a>, + + pub(crate) side_effects_only_info: PrefetchedExportInfoData<'a>, + pub(crate) redirect_to: Option, + // pub(crate) id: ExportsInfo, +} + +#[derive(Debug, Clone)] +pub struct PrefetchedExportInfoData<'a> { + pub(crate) inner: &'a ExportInfoData, + // pub(crate) exports_info: Option, +} +pub struct ExportsInfoGetter; + +impl ExportsInfoGetter { + /** + * Generate a PrefetchedExportsInfoWrapper from the entry + * if names is provided, it will pre-fetch the exports info data of the export info items of specific names + * if names is not provided, it will not pre-fetch any export info item + */ + pub fn prefetch<'a>( + id: &ExportsInfo, + mg: &'a ModuleGraph, + names: Option<&[Atom]>, + ) -> PrefetchedExportsInfoWrapper<'a> { + fn prefetch_exports<'a>( + id: &ExportsInfo, + mg: &'a ModuleGraph, + res: &mut HashMap>, + names: Option<&[Atom]>, + ) { + if res.contains_key(id) { + return; + } + let exports_info = id.as_data(mg); + let mut exports = BTreeMap::new(); + for (key, value) in exports_info.exports.iter() { + let export_info_data = value.as_data(mg); + + if names + .and_then(|names| names.first()) + .map(|name| name == key) + .is_some_and(|is_match| is_match) + { + if let Some(nested_exports_info) = export_info_data.exports_info { + prefetch_exports( + &nested_exports_info, + mg, + res, + names.map(|names| &names[1..]), + ); + } + } + + exports.insert( + key, + PrefetchedExportInfoData { + inner: export_info_data, + // exports_info: export_info_data.exports_info, + }, + ); + } + let other_exports_info_data = exports_info.other_exports_info.as_data(mg); + if let Some(other_exports) = other_exports_info_data.exports_info { + prefetch_exports(&other_exports, mg, res, None); + } + + let side_effects_only_info_data = exports_info.side_effects_only_info.as_data(mg); + if let Some(side_exports) = side_effects_only_info_data.exports_info { + prefetch_exports(&side_exports, mg, res, None); + } + + if let Some(redirect_to) = exports_info.redirect_to { + prefetch_exports(&redirect_to, mg, res, names); + } + + res.insert( + *id, + PrefetchedExportsInfoData { + exports, + other_exports_info: PrefetchedExportInfoData { + inner: other_exports_info_data, + // exports_info: other_exports_info_data.exports_info, + }, + side_effects_only_info: PrefetchedExportInfoData { + inner: side_effects_only_info_data, + // exports_info: side_effects_only_info_data.exports_info, + }, + redirect_to: exports_info.redirect_to, + // id: *id, + }, + ); + } + + let mut res = HashMap::default(); + prefetch_exports(id, mg, &mut res, names); + PrefetchedExportsInfoWrapper { + exports: Arc::new(res), + entry: *id, + } + } + + pub fn is_module_used( + info: &PrefetchedExportsInfoWrapper, + runtime: Option<&RuntimeSpec>, + ) -> bool { + if Self::is_used(info, runtime) { + return true; + } + + if !matches!( + ExportInfoGetter::get_used(info.side_effects_only_info(), runtime), + UsageState::Unused + ) { + return true; + } + false + } + + pub fn is_used(info: &PrefetchedExportsInfoWrapper, runtime: Option<&RuntimeSpec>) -> bool { + if let Some(redirect) = &info.data().redirect_to { + let redirected = info.redirect(*redirect); + if Self::is_used(&redirected, runtime) { + return true; + } + } else if ExportInfoGetter::get_used(info.other_exports_info(), runtime) != UsageState::Unused { + return true; + } + + for (_, export_info) in info.exports() { + if ExportInfoGetter::get_used(export_info, runtime) != UsageState::Unused { + return true; + } + } + false + } + + pub fn is_export_provided( + info: &PrefetchedExportsInfoWrapper, + names: &[Atom], + ) -> Option { + let name = names.first()?; + let info_data = info.get_read_only_export_info(name); + if let Some(nested_exports_info) = &info_data.exports_info + && names.len() > 1 + { + let redirected = info.redirect(*nested_exports_info); + return Self::is_export_provided(&redirected, &names[1..]); + } + let provided = ExportInfoGetter::provided(info_data)?; + + match provided { + ExportProvided::Provided => { + if names.len() == 1 { + Some(ExportProvided::Provided) + } else { + None + } + } + _ => Some(*provided), + } + } +} diff --git a/crates/rspack_core/src/exports/exports_info_setter.rs b/crates/rspack_core/src/exports/exports_info_setter.rs new file mode 100644 index 000000000000..3e3ec985ba65 --- /dev/null +++ b/crates/rspack_core/src/exports/exports_info_setter.rs @@ -0,0 +1,5 @@ +pub struct ExportsInfoSetter; + +impl ExportsInfoSetter { + // TODO +} diff --git a/crates/rspack_core/src/exports/mod.rs b/crates/rspack_core/src/exports/mod.rs index 029b9f2a1895..53414868c7bd 100644 --- a/crates/rspack_core/src/exports/mod.rs +++ b/crates/rspack_core/src/exports/mod.rs @@ -2,10 +2,14 @@ mod export_info; mod export_info_getter; mod export_info_setter; mod exports_info; +mod exports_info_getter; +mod exports_info_setter; mod utils; pub use export_info::*; pub use export_info_getter::*; pub use export_info_setter::*; pub use exports_info::*; +pub use exports_info_getter::*; +pub use exports_info_setter::*; pub use utils::*; diff --git a/crates/rspack_core/src/module.rs b/crates/rspack_core/src/module.rs index 84a87f7f6283..94d1cdb1cf9b 100644 --- a/crates/rspack_core/src/module.rs +++ b/crates/rspack_core/src/module.rs @@ -437,13 +437,14 @@ fn get_exports_type_impl( if let Some(export_info) = mg.get_read_only_export_info(&identifier, Atom::from("__esModule")) { + let export_info_data = export_info.as_data(mg); if matches!( - ExportInfoGetter::provided(export_info.as_data(mg)), + ExportInfoGetter::provided(export_info_data), Some(ExportProvided::NotProvided) ) { handle_default(default_object) } else { - let Some(target) = export_info.get_target(mg) else { + let Some(target) = export_info_data.get_target(mg) else { return ExportsType::Dynamic; }; if target diff --git a/crates/rspack_core/src/module_graph/mod.rs b/crates/rspack_core/src/module_graph/mod.rs index d16792f8f1a3..318d654c235e 100644 --- a/crates/rspack_core/src/module_graph/mod.rs +++ b/crates/rspack_core/src/module_graph/mod.rs @@ -8,7 +8,7 @@ use swc_core::ecma::atoms::Atom; use crate::{ AsyncDependenciesBlock, AsyncDependenciesBlockIdentifier, Compilation, DependenciesBlock, - Dependency, ExportProvided, ProvidedExports, RuntimeSpec, UsedExports, + Dependency, ExportProvided, ExportsInfoGetter, ProvidedExports, RuntimeSpec, UsedExports, }; mod module; pub use module::*; @@ -1139,9 +1139,10 @@ impl<'a> ModuleGraph<'a> { id: &ModuleIdentifier, names: &[Atom], ) -> Option { - self - .module_graph_module_by_identifier(id) - .and_then(|mgm| mgm.exports.is_export_provided(self, names)) + self.module_graph_module_by_identifier(id).and_then(|mgm| { + let exports_info = ExportsInfoGetter::prefetch(&mgm.exports, self, Some(names)); + ExportsInfoGetter::is_export_provided(&exports_info, names) + }) } // todo remove it after module_graph_partial remove all of dependency_id_to_* diff --git a/crates/rspack_core/src/old_cache/local/code_splitting_cache.rs b/crates/rspack_core/src/old_cache/local/code_splitting_cache.rs index 0ae5adce4a72..f10b516db563 100644 --- a/crates/rspack_core/src/old_cache/local/code_splitting_cache.rs +++ b/crates/rspack_core/src/old_cache/local/code_splitting_cache.rs @@ -185,12 +185,7 @@ impl CodeSplittingCache { return false; } - if self.new_code_splitter.module_deps.is_empty() - && self - .new_code_splitter - .module_deps_without_runtime - .is_empty() - { + if self.new_code_splitter.module_deps.is_empty() { logger.log("no cache detected, rebuilding chunk graph"); return false; } @@ -259,18 +254,6 @@ impl CodeSplittingCache { } } - if let Some(outgoings) = self - .new_code_splitter - .module_deps_without_runtime - .get(&module) - { - newly_added_module = false; - let (outgoings, _blocks) = outgoings.value(); - for out in outgoings { - previous_outgoings.insert(*out); - } - } - if newly_added_module { logger.log(format!("new module: {module}")); return false; diff --git a/crates/rspack_napi/src/threadsafe_function.rs b/crates/rspack_napi/src/threadsafe_function.rs index fcf36ddb7528..a06d9fb2b157 100644 --- a/crates/rspack_napi/src/threadsafe_function.rs +++ b/crates/rspack_napi/src/threadsafe_function.rs @@ -8,7 +8,7 @@ use napi::{ bindgen_prelude::{FromNapiValue, JsValuesTupleIntoVec, Promise, TypeName, ValidateNapiValue}, sys::{self, napi_env}, threadsafe_function::{ThreadsafeFunction as RawThreadsafeFunction, ThreadsafeFunctionCallMode}, - Env, JsValue, Unknown, ValueType, + Env, JsValue, Status, Unknown, ValueType, }; use oneshot::Receiver; use rspack_error::{miette::IntoDiagnostic, Error, Result}; @@ -20,7 +20,7 @@ type ErrorResolver = dyn FnOnce(Env); static ERROR_RESOLVER: OnceLock>> = OnceLock::new(); pub struct ThreadsafeFunction { - inner: Arc, T, false, true>>, + inner: Arc, T, Status, false, true>>, env: napi_env, _data: PhantomData, } @@ -47,7 +47,7 @@ unsafe impl Send for ThreadsafeFunction FromNapiValue for ThreadsafeFunction { unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> napi::Result { let inner = unsafe { - as FromNapiValue>::from_napi_value( + as FromNapiValue>::from_napi_value( env, napi_val, ) }?; diff --git a/crates/rspack_plugin_javascript/src/dependency/esm/esm_export_imported_specifier_dependency.rs b/crates/rspack_plugin_javascript/src/dependency/esm/esm_export_imported_specifier_dependency.rs index 60bc08c79597..77c2620144e4 100644 --- a/crates/rspack_plugin_javascript/src/dependency/esm/esm_export_imported_specifier_dependency.rs +++ b/crates/rspack_plugin_javascript/src/dependency/esm/esm_export_imported_specifier_dependency.rs @@ -13,11 +13,11 @@ use rspack_core::{ DependencyCodeGeneration, DependencyCondition, DependencyConditionFn, DependencyId, DependencyLocation, DependencyRange, DependencyTemplate, DependencyTemplateType, DependencyType, ESMExportInitFragment, ExportInfo, ExportInfoGetter, ExportNameOrSpec, ExportPresenceMode, - ExportProvided, ExportSpec, ExportsInfo, ExportsOfExportsSpec, ExportsSpec, ExportsType, - ExtendedReferencedExport, FactorizeInfo, ImportAttributes, InitFragmentExt, InitFragmentKey, - InitFragmentStage, JavascriptParserOptions, ModuleDependency, ModuleGraph, ModuleIdentifier, - NormalInitFragment, RuntimeCondition, RuntimeGlobals, RuntimeSpec, SharedSourceMap, Template, - TemplateContext, TemplateReplaceSource, UsageState, UsedName, + ExportProvided, ExportSpec, ExportsInfo, ExportsInfoGetter, ExportsOfExportsSpec, ExportsSpec, + ExportsType, ExtendedReferencedExport, FactorizeInfo, ImportAttributes, InitFragmentExt, + InitFragmentKey, InitFragmentStage, JavascriptParserOptions, ModuleDependency, ModuleGraph, + ModuleIdentifier, NormalInitFragment, RuntimeCondition, RuntimeGlobals, RuntimeSpec, + SharedSourceMap, Template, TemplateContext, TemplateReplaceSource, UsageState, UsedName, }; use rspack_error::{ miette::{MietteDiagnostic, Severity}, @@ -144,7 +144,8 @@ impl ESMExportImportedSpecifierDependency { let is_name_unused = if let Some(ref name) = name { exports_info.get_used(module_graph, std::slice::from_ref(name), runtime) == UsageState::Unused } else { - !exports_info.is_used(module_graph, runtime) + let exports_info_data = ExportsInfoGetter::prefetch(&exports_info, module_graph, None); + !ExportsInfoGetter::is_used(&exports_info_data, runtime) }; if is_name_unused { let mut mode = ExportMode::new(ExportModeType::Unused); diff --git a/crates/rspack_plugin_javascript/src/dependency/esm/esm_import_dependency.rs b/crates/rspack_plugin_javascript/src/dependency/esm/esm_import_dependency.rs index dbbf014404e0..ec92b1a0a78d 100644 --- a/crates/rspack_plugin_javascript/src/dependency/esm/esm_import_dependency.rs +++ b/crates/rspack_plugin_javascript/src/dependency/esm/esm_import_dependency.rs @@ -330,7 +330,7 @@ pub fn esm_import_dependency_get_linking_error( ); return Some(create_error(msg)); } - maybe_exports_info = export_info.get_nested_exports_info(module_graph); + maybe_exports_info = ExportInfoGetter::exports_info(export_info.as_data(module_graph)); } let msg = format!( "export {} {} was not found in '{}'", diff --git a/crates/rspack_plugin_javascript/src/dependency/export_info_dependency.rs b/crates/rspack_plugin_javascript/src/dependency/export_info_dependency.rs index 68ee1b297d80..7f370a134ad5 100644 --- a/crates/rspack_plugin_javascript/src/dependency/export_info_dependency.rs +++ b/crates/rspack_plugin_javascript/src/dependency/export_info_dependency.rs @@ -5,7 +5,8 @@ use rspack_cacheable::{ }; use rspack_core::{ DependencyCodeGeneration, DependencyTemplate, DependencyTemplateType, ExportInfoGetter, - ExportProvided, TemplateContext, TemplateReplaceSource, UsageState, UsedExports, + ExportProvided, ExportsInfoGetter, TemplateContext, TemplateReplaceSource, UsageState, + UsedExports, }; use swc_core::ecma::atoms::Atom; @@ -72,6 +73,8 @@ impl ExportInfoDependency { } let exports_info = module_graph.get_exports_info(&module_identifier); + let exports_info_data = + ExportsInfoGetter::prefetch(&exports_info, &module_graph, Some(export_name)); match prop.to_string().as_str() { "canMangle" => { @@ -105,16 +108,16 @@ impl ExportInfoDependency { .to_owned(), ) } - "provideInfo" => exports_info - .is_export_provided(&module_graph, export_name) - .map(|provided| { + "provideInfo" => { + ExportsInfoGetter::is_export_provided(&exports_info_data, export_name).map(|provided| { (match provided { ExportProvided::Provided => "true", ExportProvided::NotProvided => "false", ExportProvided::Unknown => "null", }) .to_owned() - }), + }) + } _ => None, } } diff --git a/crates/rspack_plugin_javascript/src/plugin/flag_dependency_exports_plugin.rs b/crates/rspack_plugin_javascript/src/plugin/flag_dependency_exports_plugin.rs index 4130a1180b66..f752f87d89c7 100644 --- a/crates/rspack_plugin_javascript/src/plugin/flag_dependency_exports_plugin.rs +++ b/crates/rspack_plugin_javascript/src/plugin/flag_dependency_exports_plugin.rs @@ -307,7 +307,8 @@ impl<'a> FlagDependencyExportsState<'a> { } // Recalculate target exportsInfo - let target = export_info.get_target(self.mg); + let export_info_data = export_info.as_data(self.mg); + let target = export_info_data.get_target(self.mg); let mut target_exports_info: Option = None; if let Some(target) = target { diff --git a/crates/rspack_plugin_javascript/src/plugin/flag_dependency_usage_plugin.rs b/crates/rspack_plugin_javascript/src/plugin/flag_dependency_usage_plugin.rs index 3a088b0c5d92..8b12d5d72289 100644 --- a/crates/rspack_plugin_javascript/src/plugin/flag_dependency_usage_plugin.rs +++ b/crates/rspack_plugin_javascript/src/plugin/flag_dependency_usage_plugin.rs @@ -5,8 +5,8 @@ use rspack_core::{ get_entry_runtime, incremental::IncrementalPasses, is_exports_object_referenced, is_no_exports_referenced, AsyncDependenciesBlockIdentifier, BuildMetaExportsType, Compilation, CompilationOptimizeDependencies, ConnectionState, DependenciesBlock, DependencyId, - ExportInfoSetter, ExportsInfo, ExtendedReferencedExport, GroupOptions, ModuleIdentifier, Plugin, - ReferencedExport, RuntimeSpec, UsageState, + ExportInfoGetter, ExportInfoSetter, ExportsInfo, ExtendedReferencedExport, GroupOptions, + ModuleIdentifier, Plugin, ReferencedExport, RuntimeSpec, UsageState, }; use rspack_error::Result; use rspack_hook::{plugin, plugin_hook}; @@ -335,7 +335,7 @@ impl<'a> FlagDependencyUsagePluginProxy<'a> { } let last_one = i == len - 1; if !last_one { - let nested_info = export_info.get_nested_exports_info(&module_graph); + let nested_info = ExportInfoGetter::exports_info(export_info.as_data(&module_graph)); if let Some(nested_info) = nested_info { let changed_flag = ExportInfoSetter::set_used_conditionally( export_info.as_data_mut(&mut module_graph), diff --git a/crates/rspack_plugin_javascript/src/plugin/module_concatenation_plugin.rs b/crates/rspack_plugin_javascript/src/plugin/module_concatenation_plugin.rs index 0e9fcb6e30e4..b7839e75d254 100644 --- a/crates/rspack_plugin_javascript/src/plugin/module_concatenation_plugin.rs +++ b/crates/rspack_plugin_javascript/src/plugin/module_concatenation_plugin.rs @@ -14,9 +14,9 @@ use rspack_core::{ filter_runtime, incremental::IncrementalPasses, ApplyContext, Compilation, CompilationOptimizeChunkModules, CompilerOptions, ExportInfoGetter, - ExportProvided, ExtendedReferencedExport, LibIdentOptions, Logger, Module, ModuleExt, - ModuleGraph, ModuleGraphModule, ModuleIdentifier, Plugin, PluginContext, ProvidedExports, - RuntimeCondition, RuntimeSpec, SourceType, + ExportProvided, ExportsInfoGetter, ExtendedReferencedExport, LibIdentOptions, Logger, Module, + ModuleExt, ModuleGraph, ModuleGraphModule, ModuleIdentifier, Plugin, PluginContext, + ProvidedExports, RuntimeCondition, RuntimeSpec, SourceType, }; use rspack_error::Result; use rspack_hook::{plugin, plugin_hook}; @@ -828,8 +828,9 @@ impl ModuleConcatenationPlugin { let unknown_exports = relevant_exports .iter() .filter(|export_info| { - ExportInfoGetter::is_reexport(export_info.as_data(&module_graph)) - && export_info.get_target(&module_graph).is_none() + let export_info_data = export_info.as_data(&module_graph); + ExportInfoGetter::is_reexport(export_info_data) + && export_info_data.get_target(&module_graph).is_none() }) .copied() .collect::>(); @@ -971,7 +972,8 @@ impl ModuleConcatenationPlugin { let module_graph = compilation.get_module_graph(); let exports_info = module_graph.get_exports_info(current_root); let filtered_runtime = filter_runtime(Some(&chunk_runtime), |r| { - exports_info.is_module_used(&module_graph, r) + let exports_info_data = ExportsInfoGetter::prefetch(&exports_info, &module_graph, None); + ExportsInfoGetter::is_module_used(&exports_info_data, r) }); let active_runtime = match filtered_runtime { RuntimeCondition::Boolean(true) => Some(chunk_runtime.clone()), diff --git a/crates/rspack_plugin_module_info_header/src/lib.rs b/crates/rspack_plugin_module_info_header/src/lib.rs index 4b114e8576eb..20a995953c4d 100644 --- a/crates/rspack_plugin_module_info_header/src/lib.rs +++ b/crates/rspack_plugin_module_info_header/src/lib.rs @@ -75,7 +75,7 @@ fn print_exports_info_to_source( let usage_info = ExportInfoGetter::get_used_info(info); let rename_info = ExportInfoGetter::get_rename_info(info); - let target_desc = match export_info.get_target(module_graph) { + let target_desc = match info.get_target(module_graph) { Some(resolve_target) => { let target_module = request_shortener(&resolve_target.module); match resolve_target.export { @@ -117,7 +117,7 @@ fn print_exports_info_to_source( let other_exports_info = exports_info_id.other_exports_info(module_graph); let other_exports_info_data = other_exports_info.as_data(module_graph); - let target = other_exports_info.get_target(module_graph); + let target = other_exports_info_data.get_target(module_graph); if target.is_some() || !matches!( diff --git a/npm/darwin-arm64/package.json b/npm/darwin-arm64/package.json index 2e50096b6c79..b33194921a97 100644 --- a/npm/darwin-arm64/package.json +++ b/npm/darwin-arm64/package.json @@ -1,6 +1,6 @@ { "name": "@rspack/binding-darwin-arm64", - "version": "1.3.13", + "version": "1.3.15", "license": "MIT", "description": "Node binding for rspack", "main": "rspack.darwin-arm64.node", diff --git a/npm/darwin-x64/package.json b/npm/darwin-x64/package.json index aa84c65475cc..f2ef93088b9a 100644 --- a/npm/darwin-x64/package.json +++ b/npm/darwin-x64/package.json @@ -1,6 +1,6 @@ { "name": "@rspack/binding-darwin-x64", - "version": "1.3.13", + "version": "1.3.15", "license": "MIT", "description": "Node binding for rspack", "main": "rspack.darwin-x64.node", diff --git a/npm/linux-x64-gnu/package.json b/npm/linux-x64-gnu/package.json index af2172998ba6..096c0187b9a1 100644 --- a/npm/linux-x64-gnu/package.json +++ b/npm/linux-x64-gnu/package.json @@ -1,6 +1,6 @@ { "name": "@rspack/binding-linux-x64-gnu", - "version": "1.3.13", + "version": "1.3.15", "license": "MIT", "description": "Node binding for rspack", "main": "rspack.linux-x64-gnu.node", diff --git a/npm/wasm32-wasi/package.json b/npm/wasm32-wasi/package.json index 46f285d9633d..d85ab313bc8d 100644 --- a/npm/wasm32-wasi/package.json +++ b/npm/wasm32-wasi/package.json @@ -1,6 +1,6 @@ { "name": "@rspack/binding-wasm32-wasi", - "version": "1.3.13", + "version": "1.3.15", "license": "MIT", "description": "Node binding for rspack", "main": "rspack.wasi.cjs", diff --git a/npm/win32-x64-msvc/package.json b/npm/win32-x64-msvc/package.json index cdbfa49eacef..c3f089c38930 100644 --- a/npm/win32-x64-msvc/package.json +++ b/npm/win32-x64-msvc/package.json @@ -1,6 +1,6 @@ { "name": "@rspack/binding-win32-x64-msvc", - "version": "1.3.13", + "version": "1.3.15", "license": "MIT", "description": "Node binding for rspack", "main": "rspack.win32-x64-msvc.node", diff --git a/package.json b/package.json index 005113a191be..ef8034bf5df9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "monorepo", - "version": "1.3.13", + "version": "1.3.15", "license": "MIT", "description": "The fast Rust-based web bundler with webpack-compatible API", "private": true, @@ -87,7 +87,7 @@ "patchedDependencies": { "graceful-fs": "patches/graceful-fs.patch", "rollup-plugin-dts": "patches/rollup-plugin-dts.patch", - "webpack-sources@3.3.0": "patches/webpack-sources@3.3.0.patch" + "webpack-sources@3.3.2": "patches/webpack-sources@3.3.2.patch" }, "onlyBuiltDependencies": [ "@biomejs/biome", diff --git a/packages/create-rspack/package.json b/packages/create-rspack/package.json index b2a78e0d4ffc..68857ae5f26a 100644 --- a/packages/create-rspack/package.json +++ b/packages/create-rspack/package.json @@ -1,6 +1,6 @@ { "name": "create-rspack", - "version": "1.3.13", + "version": "1.3.15", "homepage": "https://rspack.rs", "bugs": "https://github.com/web-infra-dev/rspack/issues", "repository": { diff --git a/packages/rspack-cli/package.json b/packages/rspack-cli/package.json index 4b9d3b3e158b..38d2b124db02 100644 --- a/packages/rspack-cli/package.json +++ b/packages/rspack-cli/package.json @@ -1,6 +1,6 @@ { "name": "@rspack/cli", - "version": "1.3.13", + "version": "1.3.15", "description": "CLI for rspack", "homepage": "https://rspack.rs", "bugs": "https://github.com/web-infra-dev/rspack/issues", @@ -34,7 +34,7 @@ }, "dependencies": { "@discoveryjs/json-ext": "^0.5.7", - "@rspack/dev-server": "1.1.2", + "@rspack/dev-server": "~1.1.3", "colorette": "2.0.20", "exit-hook": "^4.0.0", "interpret": "^3.1.1", diff --git a/packages/rspack-test-tools/package.json b/packages/rspack-test-tools/package.json index d81b67dd177f..6e24bab0cafe 100644 --- a/packages/rspack-test-tools/package.json +++ b/packages/rspack-test-tools/package.json @@ -1,6 +1,6 @@ { "name": "@rspack/test-tools", - "version": "1.3.13", + "version": "1.3.15", "license": "MIT", "description": "Test tools for rspack", "main": "dist/index.js", @@ -66,7 +66,7 @@ "terser-webpack-plugin": "^5.3.14", "webpack": "5.99.9", "webpack-merge": "6.0.1", - "webpack-sources": "3.3.0" + "webpack-sources": "3.3.2" }, "devDependencies": { "@rspack/cli": "workspace:*", diff --git a/packages/rspack-test-tools/tests/NewIncremental-node.test.js b/packages/rspack-test-tools/tests/NewIncremental-node.test.js index 4222af96f5ad..55c897d6594d 100644 --- a/packages/rspack-test-tools/tests/NewIncremental-node.test.js +++ b/packages/rspack-test-tools/tests/NewIncremental-node.test.js @@ -20,11 +20,7 @@ describeByWalk( { source: path.resolve(__dirname, "./hotCases"), dist: path.resolve(__dirname, `./js/new-incremental/hot-async-node`), - exclude: [ - /^css$/, - /move-between-runtime/, - /require-disposed-module-warning/ - ] + exclude: [/^css$/, /require-disposed-module-warning/] } ); diff --git a/packages/rspack-test-tools/tests/NewIncremental-web.test.js b/packages/rspack-test-tools/tests/NewIncremental-web.test.js index 122a08c822ea..9380d423a57b 100644 --- a/packages/rspack-test-tools/tests/NewIncremental-web.test.js +++ b/packages/rspack-test-tools/tests/NewIncremental-web.test.js @@ -33,6 +33,6 @@ describeByWalk( { source: path.resolve(__dirname, "../../../tests/webpack-test/hotCases"), dist: path.resolve(__dirname, `./js/new-incremental/webpack-test/hot-web`), - exclude: [/move-between-runtime/, /require-disposed-module-warning/] + exclude: [/require-disposed-module-warning/] } ); diff --git a/packages/rspack-test-tools/tests/NewIncremental-webworker.test.js b/packages/rspack-test-tools/tests/NewIncremental-webworker.test.js index 4c16190cd2b0..9e3e5afd446f 100644 --- a/packages/rspack-test-tools/tests/NewIncremental-webworker.test.js +++ b/packages/rspack-test-tools/tests/NewIncremental-webworker.test.js @@ -20,11 +20,7 @@ describeByWalk( { source: path.resolve(__dirname, "./hotCases"), dist: path.resolve(__dirname, `./js/new-incremental/hot-worker`), - exclude: [ - /^css$/, - /move-between-runtime/, - /require-disposed-module-warning/ - ] + exclude: [/^css$/, /require-disposed-module-warning/] } ); diff --git a/packages/rspack-test-tools/tests/configCases/build-http/custom-http-client/rspack-http-lockfile.json b/packages/rspack-test-tools/tests/configCases/build-http/custom-http-client/rspack-http-lockfile.json index b3fa27c1db1a..3c53e3ae6f5c 100644 --- a/packages/rspack-test-tools/tests/configCases/build-http/custom-http-client/rspack-http-lockfile.json +++ b/packages/rspack-test-tools/tests/configCases/build-http/custom-http-client/rspack-http-lockfile.json @@ -1,16 +1,16 @@ { "version": 1, "entries": { - "http://test.rspack.rs/regex-module.js": { - "resolved": "http://test.rspack.rs/regex-module.js", - "integrity": "sha512-ZVAn+yi08gqdf+C4r9GnMG6VjHh/C78Dxz/hcLWnWi8n6GRQuyCmKQpMzm2hULI29yr8uu+jTaCfmP9ReNLzIQ==", + "http://test.rspack.rs/allowed-module.js": { + "resolved": "http://test.rspack.rs/allowed-module.js", + "integrity": "sha512-dR8lAM8R5IZDjP7VAvxO3eKJWcudeivg/hP1+duuc6SsL/wdeuMS9dn6tVYwphfzP5b23AuSDjowigl64q/wMw==", "content_type": "application/javascript", "valid_until": 0, "etag": null }, - "http://test.rspack.rs/allowed-module.js": { - "resolved": "http://test.rspack.rs/allowed-module.js", - "integrity": "sha512-dR8lAM8R5IZDjP7VAvxO3eKJWcudeivg/hP1+duuc6SsL/wdeuMS9dn6tVYwphfzP5b23AuSDjowigl64q/wMw==", + "http://test.rspack.rs/regex-module.js": { + "resolved": "http://test.rspack.rs/regex-module.js", + "integrity": "sha512-ZVAn+yi08gqdf+C4r9GnMG6VjHh/C78Dxz/hcLWnWi8n6GRQuyCmKQpMzm2hULI29yr8uu+jTaCfmP9ReNLzIQ==", "content_type": "application/javascript", "valid_until": 0, "etag": null diff --git a/packages/rspack/etc/core.api.md b/packages/rspack/etc/core.api.md index cf3fbc5cf613..b9cdee80fe8c 100644 --- a/packages/rspack/etc/core.api.md +++ b/packages/rspack/etc/core.api.md @@ -1069,7 +1069,7 @@ export class Compilation { Iterable ], void>; finishModules: liteTapable.AsyncSeriesHook<[Iterable], void>; - chunkHash: liteTapable.SyncHook<[Chunk, Hash_2], void>; + chunkHash: liteTapable.SyncHook<[Chunk, Hash], void>; chunkAsset: liteTapable.SyncHook<[Chunk, string], void>; processWarnings: liteTapable.SyncWaterfallHook<[Error[]]>; succeedModule: liteTapable.SyncHook<[Module], void>; @@ -1176,7 +1176,7 @@ export class Compilation { // @public (undocumented) type CompilationHooks = { - chunkHash: liteTapable.SyncHook<[Chunk, Hash_2]>; + chunkHash: liteTapable.SyncHook<[Chunk, Hash]>; }; // @public (undocumented) @@ -2924,15 +2924,7 @@ interface HasDecorator { } // @public (undocumented) -interface Hash { - // (undocumented) - digest: (encoding?: string) => string | Buffer_2; - // (undocumented) - update: (data: string | Buffer_2, inputEncoding?: string) => Hash; -} - -// @public (undocumented) -class Hash_2 { +class Hash { digest(): Buffer; digest(encoding: string): string; // (undocumented) @@ -2944,11 +2936,11 @@ class Hash_2 { // @public (undocumented) interface HashableObject { // (undocumented) - updateHash(hash: Hash_2): void; + updateHash(hash: Hash): void; } // @public (undocumented) -type HashConstructor = typeof Hash_2; +type HashConstructor = typeof Hash; // @public export type HashDigest = string; @@ -2959,6 +2951,14 @@ export type HashDigestLength = number; // @public export type HashFunction = "md4" | "xxhash64"; +// @public (undocumented) +interface HashLike { + // (undocumented) + digest: (encoding?: string) => string | Buffer_2; + // (undocumented) + update: (data: string | Buffer_2, inputEncoding?: string) => HashLike; +} + // @public export type HashSalt = string; @@ -4346,7 +4346,7 @@ export interface LoaderContext { utils: { absolutify: (context: string, request: string) => string; contextify: (context: string, request: string) => string; - createHash: (algorithm?: string) => Hash_2; + createHash: (algorithm?: string) => Hash; }; version: 2; } @@ -5798,8 +5798,12 @@ type Purge = (files?: string | string[] | Set) => void; // @public (undocumented) interface RawSourceMap { // (undocumented) + debugId?: string; + // (undocumented) file: string; // (undocumented) + ignoreList?: number[]; + // (undocumented) mappings: string; // (undocumented) names: string[]; @@ -6093,7 +6097,7 @@ class Resolver { // (undocumented) resolveSync(context: object, path: string, request: string): string | false; // (undocumented) - withOptions({ dependencyCategory, resolveToContext, ...resolve }: ResolveOptionsWithDependencyType_2): Resolver; + withOptions(options: ResolveOptionsWithDependencyType_2): Resolver; } // @public (undocumented) @@ -7165,7 +7169,7 @@ class Source { // (undocumented) sourceAndMap(options?: MapOptions): SourceAndMap; // (undocumented) - updateHash(hash: Hash): void; + updateHash(hash: HashLike): void; } // @public (undocumented) diff --git a/packages/rspack/package.json b/packages/rspack/package.json index 54ecec0efae0..d7aab3e547e2 100644 --- a/packages/rspack/package.json +++ b/packages/rspack/package.json @@ -1,6 +1,6 @@ { "name": "@rspack/core", - "version": "1.3.13", + "version": "1.3.15", "webpackVersion": "5.75.0", "license": "MIT", "description": "The fast Rust-based web bundler with webpack-compatible API", @@ -59,7 +59,7 @@ "tsx": "^4.19.4", "typescript": "^5.8.3", "watchpack": "^2.4.4", - "webpack-sources": "3.3.0", + "webpack-sources": "3.3.2", "zod": "^3.25.50", "zod-validation-error": "3.4.1" }, diff --git a/packages/rspack/src/Resolver.ts b/packages/rspack/src/Resolver.ts index 83e93c6a7f38..0a0a9b735dfe 100644 --- a/packages/rspack/src/Resolver.ts +++ b/packages/rspack/src/Resolver.ts @@ -15,6 +15,8 @@ export type ResolveRequest = ResourceData; export class Resolver { binding: binding.JsResolver; + #childCache: WeakMap, Resolver> = + new WeakMap(); constructor(binding: binding.JsResolver) { this.binding = binding; @@ -38,11 +40,13 @@ export class Resolver { ); } - withOptions({ - dependencyCategory, - resolveToContext, - ...resolve - }: ResolveOptionsWithDependencyType): Resolver { + withOptions(options: ResolveOptionsWithDependencyType): Resolver { + const cacheEntry = this.#childCache.get(options); + if (cacheEntry !== undefined) { + return cacheEntry; + } + + const { dependencyCategory, resolveToContext, ...resolve } = options; const rawResolve = getRawResolve(resolve); const binding = this.binding.withOptions({ @@ -50,6 +54,8 @@ export class Resolver { resolveToContext, ...rawResolve }); - return new Resolver(binding); + const resolver = new Resolver(binding); + this.#childCache.set(options, resolver); + return resolver; } } diff --git a/patches/webpack-sources@3.3.0.patch b/patches/webpack-sources@3.3.2.patch similarity index 65% rename from patches/webpack-sources@3.3.0.patch rename to patches/webpack-sources@3.3.2.patch index 08612561ce9f..e59a39791b0a 100644 --- a/patches/webpack-sources@3.3.0.patch +++ b/patches/webpack-sources@3.3.2.patch @@ -1,21 +1,20 @@ # Ensure the types.d.ts can be parsed by api-extractor diff --git a/types.d.ts b/types.d.ts -index 08fad8920a89c3af97a8f6f706c566634bcd6fc9..241925cb470f7a2ed1c3cb011d86d49037727601 100644 +index f58f6dfe6a2c2098385d1ccf33200baeb31b2166..b377c331e0684914bef1726ad41b42107ed574ee 100644 --- a/types.d.ts +++ b/types.d.ts -@@ -269,7 +269,7 @@ declare interface StreamChunksOptions { +@@ -271,7 +271,6 @@ declare interface StreamChunksOptions { finalSource?: boolean; columns?: boolean; } -declare namespace exports { -+ export namespace util { export namespace stringBufferUtils { export let disableDualStringBufferCaching: () => void; -@@ -318,6 +318,3 @@ declare namespace exports { +@@ -320,6 +319,4 @@ declare namespace exports { GeneratedSourceInfo, StreamChunksOptions }; -} -- + -export = exports; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 5db64226e460..8b13813bcfc1 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -11,9 +11,9 @@ patchedDependencies: rollup-plugin-dts: hash: bc3f29f4636a594eb84c5e3f2d8cbd29c2e6b845f376603b718fb2d41bee6de8 path: patches/rollup-plugin-dts.patch - webpack-sources@3.3.0: - hash: 6c5cd9744a1ff9c2374c7ffac6703e74ec00b56bd6d104fb27e6e3c10451cec7 - path: patches/webpack-sources@3.3.0.patch + webpack-sources@3.3.2: + hash: 488e04e10706980da34067f6ad8c408b1eb45e65c49685929419ebb9abf9b96e + path: patches/webpack-sources@3.3.2.patch importers: @@ -335,8 +335,8 @@ importers: specifier: ^2.4.4 version: 2.4.4 webpack-sources: - specifier: 3.3.0 - version: 3.3.0(patch_hash=6c5cd9744a1ff9c2374c7ffac6703e74ec00b56bd6d104fb27e6e3c10451cec7) + specifier: 3.3.2 + version: 3.3.2(patch_hash=488e04e10706980da34067f6ad8c408b1eb45e65c49685929419ebb9abf9b96e) zod: specifier: ^3.25.50 version: 3.25.50 @@ -350,8 +350,8 @@ importers: specifier: ^0.5.7 version: 0.5.7 '@rspack/dev-server': - specifier: 1.1.2 - version: 1.1.2(@rspack/core@packages+rspack)(@types/express@4.17.22)(webpack@5.99.9(@swc/core@1.11.29(@swc/helpers@0.5.17))) + specifier: ~1.1.3 + version: 1.1.3(@rspack/core@packages+rspack)(@types/express@4.17.22)(webpack@5.99.9(@swc/core@1.11.29(@swc/helpers@0.5.17))) colorette: specifier: 2.0.20 version: 2.0.20 @@ -480,8 +480,8 @@ importers: specifier: 6.0.1 version: 6.0.1 webpack-sources: - specifier: 3.3.0 - version: 3.3.0(patch_hash=6c5cd9744a1ff9c2374c7ffac6703e74ec00b56bd6d104fb27e6e3c10451cec7) + specifier: 3.3.2 + version: 3.3.2(patch_hash=488e04e10706980da34067f6ad8c408b1eb45e65c49685929419ebb9abf9b96e) devDependencies: '@rspack/cli': specifier: workspace:* @@ -683,8 +683,8 @@ importers: specifier: workspace:* version: link:../../packages/rspack '@rspack/dev-server': - specifier: 1.1.2 - version: 1.1.2(@rspack/core@packages+rspack)(@types/express@4.17.22)(webpack@5.99.9(@swc/core@1.11.29(@swc/helpers@0.5.17))) + specifier: ~1.1.3 + version: 1.1.3(@rspack/core@packages+rspack)(@types/express@4.17.22)(webpack@5.99.9(@swc/core@1.11.29(@swc/helpers@0.5.17))) '@rspack/plugin-react-refresh': specifier: ^1.4.3 version: 1.4.3(react-refresh@0.17.0) @@ -768,7 +768,7 @@ importers: version: 3.42.0 css-loader: specifier: ^7.1.2 - version: 7.1.2(@rspack/core@1.3.13(@swc/helpers@0.5.17))(webpack@5.99.9(@swc/core@1.11.29(@swc/helpers@0.5.17))) + version: 7.1.2(@rspack/core@1.3.14(@swc/helpers@0.5.17))(webpack@5.99.9(@swc/core@1.11.29(@swc/helpers@0.5.17))) date-fns: specifier: ^4.1.0 version: 4.1.0 @@ -833,8 +833,8 @@ importers: specifier: ^2.4.4 version: 2.4.4 webpack-sources: - specifier: 3.3.0 - version: 3.3.0(patch_hash=6c5cd9744a1ff9c2374c7ffac6703e74ec00b56bd6d104fb27e6e3c10451cec7) + specifier: 3.3.2 + version: 3.3.2(patch_hash=488e04e10706980da34067f6ad8c408b1eb45e65c49685929419ebb9abf9b96e) devDependencies: '@babel/preset-react': specifier: ^7.27.1 @@ -2538,8 +2538,8 @@ packages: cpu: [arm64] os: [darwin] - '@rspack/binding-darwin-arm64@1.3.13': - resolution: {integrity: sha512-1c+KC+TFaKRWu+SO4cJZ5oHKOFuDhTIitbSIG9boJpDRoZmJxHDmFyTTxVI2r2QUjxJaDdUlSFepybhhJ3UiPg==} + '@rspack/binding-darwin-arm64@1.3.14': + resolution: {integrity: sha512-uuVvHAJQZugr55Rmpccg0ZkGEBOLYs3a50cePMRXKi6ukcfKbDzEyUk9/eDtTJUW8671I2RGlIhI/Scg+8iIpQ==} cpu: [arm64] os: [darwin] @@ -2548,8 +2548,8 @@ packages: cpu: [x64] os: [darwin] - '@rspack/binding-darwin-x64@1.3.13': - resolution: {integrity: sha512-YBF+XjoGSjhJ5o/xOaCBd39BntMudMeup11j2Dz+rrTH+wG6TvH017HYIgDMT3UBVv66eNsQpzA0ZW5raJ0lbA==} + '@rspack/binding-darwin-x64@1.3.14': + resolution: {integrity: sha512-87UHXGAoGEsUW03aTavcA9QosSyzHPnNeN67m5+TP7rOVkui5FyVWusoMQt073b//IOJrm+UvnTiS56HkSVbWw==} cpu: [x64] os: [darwin] @@ -2558,8 +2558,8 @@ packages: cpu: [arm64] os: [linux] - '@rspack/binding-linux-arm64-gnu@1.3.13': - resolution: {integrity: sha512-II71Ez7Z0/5ZpcK+kCgvXFKK0AysS9La8LNQbqf2wmzxDJi5H8eVUiwkM5BabICxzOWYtTGJLZ89QbCYaFbqCg==} + '@rspack/binding-linux-arm64-gnu@1.3.14': + resolution: {integrity: sha512-bp6TnqmUmGOYY7rBY5YnPRpWSFyAs4AHlLsYK3vgZzSQ+PjxMeT3JQaYo/mXxKrxETCgvKV4az5wO4oOwvQKpg==} cpu: [arm64] os: [linux] @@ -2568,8 +2568,8 @@ packages: cpu: [arm64] os: [linux] - '@rspack/binding-linux-arm64-musl@1.3.13': - resolution: {integrity: sha512-JFFhqglKVjlWcmmVwdS80Kw6v35yY9xlQJup09mL8gMtiiFiT36wTyTujz15Iv+2+S/Dv0Z+UeUJ99KRbQxgcQ==} + '@rspack/binding-linux-arm64-musl@1.3.14': + resolution: {integrity: sha512-Sm8fCQbga9KByNfLsd3rnhqlkUNFQWuL+YMAOzd4mbhe5XYTdcVh+KJ8d4gzHei8mgUkel8REuIww6Rcu9m0tA==} cpu: [arm64] os: [linux] @@ -2578,8 +2578,8 @@ packages: cpu: [x64] os: [linux] - '@rspack/binding-linux-x64-gnu@1.3.13': - resolution: {integrity: sha512-ogm4rt+PMQHkMg/0mA9VTjfGE3c+YaHZQT8KrFgTsoj2YCW9WO2J/RjdMc6STG4Y10BWO9Ar2azLxxHrKb+8UQ==} + '@rspack/binding-linux-x64-gnu@1.3.14': + resolution: {integrity: sha512-adgzfZACCLfyv2XNLwzMtMuf+3bLaTkMtKVZoFUBxTrqSO9PaeDs08n1qNdHCUmfYo7nRuAtwUYsf2yZBhRe4A==} cpu: [x64] os: [linux] @@ -2588,8 +2588,8 @@ packages: cpu: [x64] os: [linux] - '@rspack/binding-linux-x64-musl@1.3.13': - resolution: {integrity: sha512-8icDyXhg1iMKhQ3X2FTgAGQTQqnli9FyqHCuRIBauxy1V4W478Mp9Y+V+ErVUY1YxbZEUrkt3a59hssjGeDEeg==} + '@rspack/binding-linux-x64-musl@1.3.14': + resolution: {integrity: sha512-nfvaKn+gyEZGXQfFRueQYbn4ec0uXwrdIjrXled7UEQHI08+6mb5ZTgtLlLn6yEuxK1ICvKnef5PPDuA1FYLtA==} cpu: [x64] os: [linux] @@ -2598,8 +2598,8 @@ packages: cpu: [arm64] os: [win32] - '@rspack/binding-win32-arm64-msvc@1.3.13': - resolution: {integrity: sha512-y5XxwxDW4DrPKy+8P6t7I7IbA7B/iXjLoaS0jP/EwjSHWf/EnZzq9MgWqdop1km8Mwx6s1zcj+0qs73jL2N98w==} + '@rspack/binding-win32-arm64-msvc@1.3.14': + resolution: {integrity: sha512-lZR95QwXJmD1M/k4+BSUXztx68Y2WuyaZljhdnSFQkvnMqsTvBMWtAtMHAzKM9t6vfCpEQ3cGkkQncNuvAQFzQ==} cpu: [arm64] os: [win32] @@ -2608,8 +2608,8 @@ packages: cpu: [ia32] os: [win32] - '@rspack/binding-win32-ia32-msvc@1.3.13': - resolution: {integrity: sha512-n24sznsZe3lC8ok6MgsT1nG4lVx3SQ/lZ0g23i2BGMRN8/p+kaC2eoPaHe/4m9Liz/W4Z5LhZCCvg4DQMEzeLA==} + '@rspack/binding-win32-ia32-msvc@1.3.14': + resolution: {integrity: sha512-vvylRZ8x0MgYyISXcTMBGWnMR+NTz8X01+7F0+NzyWK3NWGh799LWhCecmG7YofstcwxwlPzFh1dhvWwvMIFbg==} cpu: [ia32] os: [win32] @@ -2618,16 +2618,16 @@ packages: cpu: [x64] os: [win32] - '@rspack/binding-win32-x64-msvc@1.3.13': - resolution: {integrity: sha512-CLyTNo0OrOD7xFKusFciKKG+8CXPowjPz+tcdkkrKYqGzAPzOcszblikITJhMbc7DLMzdTRSZUTkKLRydYH9sw==} + '@rspack/binding-win32-x64-msvc@1.3.14': + resolution: {integrity: sha512-HOq8BbiN25p00aWCbZ9HFZJDNJywtWoFHqE4eterevYgUNCToa4Z3TjYHI7iZCARc0hqNJq2VG3trRYtg2B73Q==} cpu: [x64] os: [win32] '@rspack/binding@1.3.12': resolution: {integrity: sha512-4Ic8lV0+LCBfTlH5aIOujIRWZOtgmG223zC4L3o8WY/+ESAgpdnK6lSSMfcYgRanYLAy3HOmFIp20jwskMpbAg==} - '@rspack/binding@1.3.13': - resolution: {integrity: sha512-BdM6tfLCP7/0H5uGc+okG6AYsU9JEnR5bRHq4YuGaS4tb+N5ct0czm0LprGMZ7zRAnIql/zoLn/bHlheNxZw3g==} + '@rspack/binding@1.3.14': + resolution: {integrity: sha512-NbyTh4FiDgHWIHKZ2gbw8DrZvzIeD10vGLMDK67ekuByvwR2yyR83COtKU48y1Aotm7p0XEk0eWL1qMfwH8U3Q==} '@rspack/core@1.3.12': resolution: {integrity: sha512-mAPmV4LPPRgxpouUrGmAE4kpF1NEWJGyM5coebsjK/zaCMSjw3mkdxiU2b5cO44oIi0Ifv5iGkvwbdrZOvMyFA==} @@ -2638,8 +2638,8 @@ packages: '@swc/helpers': optional: true - '@rspack/core@1.3.13': - resolution: {integrity: sha512-j9jsNzKeEN14yraqX4jAFrM/nMfX5YEPgEMPlp4g5NAu3siaBa8gDF5brbdNq6TDXnTHK1MwwjaMdKA+3YeBKQ==} + '@rspack/core@1.3.14': + resolution: {integrity: sha512-FmxhpXKx9nZBbezgmNPwz7gLbLBZ8zrQEpUnnVCs69qx1mvCUVlh5XhoQxQH642QBr9ujPwo/a218/y/63LS6Q==} engines: {node: '>=16.0.0'} peerDependencies: '@swc/helpers': '>=0.5.1' @@ -2647,8 +2647,8 @@ packages: '@swc/helpers': optional: true - '@rspack/dev-server@1.1.2': - resolution: {integrity: sha512-YNzXxWn6DV3X9yeJZ9bqX77wuhm2ko3sGavilBGi1MWuNihhWfhh9dlbipudPyoiwLl0lbioxA/hevosr+ajLg==} + '@rspack/dev-server@1.1.3': + resolution: {integrity: sha512-jWPeyiZiGpbLYGhwHvwxhaa4rsr8CQvsWkWslqeMLb2uXwmyy3UWjUR1q+AhAPnf0gs3lZoFZ1hjBQVecHKUvg==} engines: {node: '>= 18.12.0'} peerDependencies: '@rspack/core': '*' @@ -7665,8 +7665,8 @@ packages: webpack: optional: true - webpack-dev-server@5.2.0: - resolution: {integrity: sha512-90SqqYXA2SK36KcT6o1bvwvZfJFcmoamqeJY7+boioffX9g9C0wjjJRGUrQIuh43pb0ttX7+ssavmj/WN2RHtA==} + webpack-dev-server@5.2.2: + resolution: {integrity: sha512-QcQ72gh8a+7JO63TAx/6XZf/CWhgMzu5m0QirvPfGvptOusAxG12w2+aua1Jkjr7hzaWDnJ2n6JFeexMHI+Zjg==} engines: {node: '>= 18.12.0'} hasBin: true peerDependencies: @@ -7682,8 +7682,8 @@ packages: resolution: {integrity: sha512-hXXvrjtx2PLYx4qruKl+kyRSLc52V+cCvMxRjmKwoA+CBbbF5GfIBtR6kCvl0fYGqTUPKB+1ktVmTHqMOzgCBg==} engines: {node: '>=18.0.0'} - webpack-sources@3.3.0: - resolution: {integrity: sha512-77R0RDmJfj9dyv5p3bM5pOHa+X8/ZkO9c7kpDstigkC4nIDobadsfSGCwB4bKhMVxqAok8tajaoR8rirM7+VFQ==} + webpack-sources@3.3.2: + resolution: {integrity: sha512-ykKKus8lqlgXX/1WjudpIEjqsafjOTcOJqxnAbMLAu/KCsDCJ6GBtvscewvTkrn24HsnvFwrSCbenFrhtcCsAA==} engines: {node: '>=10.13.0'} webpack@5.99.9: @@ -9550,55 +9550,55 @@ snapshots: '@rspack/binding-darwin-arm64@1.3.12': optional: true - '@rspack/binding-darwin-arm64@1.3.13': + '@rspack/binding-darwin-arm64@1.3.14': optional: true '@rspack/binding-darwin-x64@1.3.12': optional: true - '@rspack/binding-darwin-x64@1.3.13': + '@rspack/binding-darwin-x64@1.3.14': optional: true '@rspack/binding-linux-arm64-gnu@1.3.12': optional: true - '@rspack/binding-linux-arm64-gnu@1.3.13': + '@rspack/binding-linux-arm64-gnu@1.3.14': optional: true '@rspack/binding-linux-arm64-musl@1.3.12': optional: true - '@rspack/binding-linux-arm64-musl@1.3.13': + '@rspack/binding-linux-arm64-musl@1.3.14': optional: true '@rspack/binding-linux-x64-gnu@1.3.12': optional: true - '@rspack/binding-linux-x64-gnu@1.3.13': + '@rspack/binding-linux-x64-gnu@1.3.14': optional: true '@rspack/binding-linux-x64-musl@1.3.12': optional: true - '@rspack/binding-linux-x64-musl@1.3.13': + '@rspack/binding-linux-x64-musl@1.3.14': optional: true '@rspack/binding-win32-arm64-msvc@1.3.12': optional: true - '@rspack/binding-win32-arm64-msvc@1.3.13': + '@rspack/binding-win32-arm64-msvc@1.3.14': optional: true '@rspack/binding-win32-ia32-msvc@1.3.12': optional: true - '@rspack/binding-win32-ia32-msvc@1.3.13': + '@rspack/binding-win32-ia32-msvc@1.3.14': optional: true '@rspack/binding-win32-x64-msvc@1.3.12': optional: true - '@rspack/binding-win32-x64-msvc@1.3.13': + '@rspack/binding-win32-x64-msvc@1.3.14': optional: true '@rspack/binding@1.3.12': @@ -9613,17 +9613,17 @@ snapshots: '@rspack/binding-win32-ia32-msvc': 1.3.12 '@rspack/binding-win32-x64-msvc': 1.3.12 - '@rspack/binding@1.3.13': + '@rspack/binding@1.3.14': optionalDependencies: - '@rspack/binding-darwin-arm64': 1.3.13 - '@rspack/binding-darwin-x64': 1.3.13 - '@rspack/binding-linux-arm64-gnu': 1.3.13 - '@rspack/binding-linux-arm64-musl': 1.3.13 - '@rspack/binding-linux-x64-gnu': 1.3.13 - '@rspack/binding-linux-x64-musl': 1.3.13 - '@rspack/binding-win32-arm64-msvc': 1.3.13 - '@rspack/binding-win32-ia32-msvc': 1.3.13 - '@rspack/binding-win32-x64-msvc': 1.3.13 + '@rspack/binding-darwin-arm64': 1.3.14 + '@rspack/binding-darwin-x64': 1.3.14 + '@rspack/binding-linux-arm64-gnu': 1.3.14 + '@rspack/binding-linux-arm64-musl': 1.3.14 + '@rspack/binding-linux-x64-gnu': 1.3.14 + '@rspack/binding-linux-x64-musl': 1.3.14 + '@rspack/binding-win32-arm64-msvc': 1.3.14 + '@rspack/binding-win32-ia32-msvc': 1.3.14 + '@rspack/binding-win32-x64-msvc': 1.3.14 optional: true '@rspack/core@1.3.12(@swc/helpers@0.5.17)': @@ -9635,22 +9635,22 @@ snapshots: optionalDependencies: '@swc/helpers': 0.5.17 - '@rspack/core@1.3.13(@swc/helpers@0.5.17)': + '@rspack/core@1.3.14(@swc/helpers@0.5.17)': dependencies: '@module-federation/runtime-tools': 0.14.3 - '@rspack/binding': 1.3.13 + '@rspack/binding': 1.3.14 '@rspack/lite-tapable': 1.0.1 optionalDependencies: '@swc/helpers': 0.5.17 optional: true - '@rspack/dev-server@1.1.2(@rspack/core@packages+rspack)(@types/express@4.17.22)(webpack@5.99.9(@swc/core@1.11.29(@swc/helpers@0.5.17)))': + '@rspack/dev-server@1.1.3(@rspack/core@packages+rspack)(@types/express@4.17.22)(webpack@5.99.9(@swc/core@1.11.29(@swc/helpers@0.5.17)))': dependencies: '@rspack/core': link:packages/rspack chokidar: 3.6.0 http-proxy-middleware: 2.0.9(@types/express@4.17.22) p-retry: 6.2.1 - webpack-dev-server: 5.2.0(webpack@5.99.9(@swc/core@1.11.29(@swc/helpers@0.5.17))) + webpack-dev-server: 5.2.2(webpack@5.99.9(@swc/core@1.11.29(@swc/helpers@0.5.17))) ws: 8.18.2 transitivePeerDependencies: - '@types/express' @@ -11200,7 +11200,7 @@ snapshots: cspell-ban-words@0.0.4: {} - css-loader@7.1.2(@rspack/core@1.3.13(@swc/helpers@0.5.17))(webpack@5.99.9(@swc/core@1.11.29(@swc/helpers@0.5.17))): + css-loader@7.1.2(@rspack/core@1.3.14(@swc/helpers@0.5.17))(webpack@5.99.9(@swc/core@1.11.29(@swc/helpers@0.5.17))): dependencies: icss-utils: 5.1.0(postcss@8.5.4) postcss: 8.5.4 @@ -11211,7 +11211,7 @@ snapshots: postcss-value-parser: 4.2.0 semver: 7.7.2 optionalDependencies: - '@rspack/core': 1.3.13(@swc/helpers@0.5.17) + '@rspack/core': 1.3.14(@swc/helpers@0.5.17) webpack: 5.99.9(@swc/core@1.11.29(@swc/helpers@0.5.17)) css-loader@7.1.2(@rspack/core@packages+rspack)(webpack@5.99.9(@swc/core@1.11.29(@swc/helpers@0.5.17))): @@ -15643,11 +15643,12 @@ snapshots: optionalDependencies: webpack: 5.99.9(@swc/core@1.11.29(@swc/helpers@0.5.17)) - webpack-dev-server@5.2.0(webpack@5.99.9(@swc/core@1.11.29(@swc/helpers@0.5.17))): + webpack-dev-server@5.2.2(webpack@5.99.9(@swc/core@1.11.29(@swc/helpers@0.5.17))): dependencies: '@types/bonjour': 3.5.13 '@types/connect-history-api-fallback': 1.5.4 '@types/express': 4.17.22 + '@types/express-serve-static-core': 4.19.6 '@types/serve-index': 1.9.4 '@types/serve-static': 1.15.7 '@types/sockjs': 0.3.36 @@ -15686,7 +15687,7 @@ snapshots: flat: 5.0.2 wildcard: 2.0.1 - webpack-sources@3.3.0(patch_hash=6c5cd9744a1ff9c2374c7ffac6703e74ec00b56bd6d104fb27e6e3c10451cec7): {} + webpack-sources@3.3.2(patch_hash=488e04e10706980da34067f6ad8c408b1eb45e65c49685929419ebb9abf9b96e): {} webpack@5.99.9(@swc/core@1.11.29(@swc/helpers@0.5.17)): dependencies: @@ -15713,7 +15714,7 @@ snapshots: tapable: 2.2.2 terser-webpack-plugin: 5.3.14(@swc/core@1.11.29(@swc/helpers@0.5.17))(webpack@5.99.9(@swc/core@1.11.29(@swc/helpers@0.5.17))) watchpack: 2.4.4 - webpack-sources: 3.3.0(patch_hash=6c5cd9744a1ff9c2374c7ffac6703e74ec00b56bd6d104fb27e6e3c10451cec7) + webpack-sources: 3.3.2(patch_hash=488e04e10706980da34067f6ad8c408b1eb45e65c49685929419ebb9abf9b96e) transitivePeerDependencies: - '@swc/core' - esbuild diff --git a/tests/e2e/package.json b/tests/e2e/package.json index cc89702db90b..ed461e2d6747 100644 --- a/tests/e2e/package.json +++ b/tests/e2e/package.json @@ -12,7 +12,7 @@ "@playwright/test": "1.47.0", "core-js": "3.42.0", "@rspack/core": "workspace:*", - "@rspack/dev-server": "1.1.2", + "@rspack/dev-server": "~1.1.3", "@rspack/plugin-react-refresh": "^1.4.3", "@swc/helpers": "0.5.17", "@types/fs-extra": "11.0.4", diff --git a/tests/webpack-test/package.json b/tests/webpack-test/package.json index 72f7ad44efaf..fe4008778c83 100644 --- a/tests/webpack-test/package.json +++ b/tests/webpack-test/package.json @@ -54,7 +54,7 @@ "tapable": "2.2.2", "wast-loader": "^1.14.1", "watchpack": "^2.4.4", - "webpack-sources": "3.3.0", + "webpack-sources": "3.3.2", "toml": "^3.0.0" } } \ No newline at end of file diff --git a/website/docs/en/config/devtool.mdx b/website/docs/en/config/devtool.mdx index 26d05b9428d6..146f5b92816e 100644 --- a/website/docs/en/config/devtool.mdx +++ b/website/docs/en/config/devtool.mdx @@ -32,28 +32,28 @@ type Devtool = 'string' | false; - Extremely fast build speed - **Full source code mapping needed** → Proceed to [Step 3](#step-3-configure-sourcemap) -### Step 3: Configure SourceMap +### Step 3: Configure source map -Set `devtool: 'source-map'`, A full SourceMap is emitted as a separate file. It adds a `//# sourceMapURL` comment to the bundle so development tools know where to find it. +Set `devtool: 'source-map'`, A full source map is emitted as a separate file. It adds a `//# sourceMapURL` comment to the bundle so development tools know where to find it. -It also supports combination with the following modifiers to improve performance and control SourceMap generation. +It also supports combination with the following modifiers to improve performance and control source map generation. Performance optimization modifiers, to speed up the build, usually used in development environments: -| Modifier | Effect | Performance improvement | -| -------- | -------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------- | -| eval | Each module is executed with `eval()` and a SourceMap is added as a DataUrl to the `eval()`, avoiding chunk-level multiple SourceMap concate | ⚡⚡⚡ | -| cheap | Maps line numbers only (no columns), ignores source maps from loaders | ⚡⚡ | -| module | Processes source maps from loaders to map to original code (line-only mapping) | ⚡ | +| Modifier | Effect | Performance improvement | +| -------- | ---------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------- | +| eval | Each module is executed with `eval()` and a source map is added as a DataUrl to the `eval()`, avoiding chunk-level multiple source map concate | ⚡⚡⚡ | +| cheap | Maps line numbers only (no columns), ignores source maps from loaders | ⚡⚡ | +| module | Processes source maps from loaders to map to original code (line-only mapping) | ⚡ | -Functional modifiers, to control SourceMap generation, usually used in production environments: +Functional modifiers, to control source map generation, usually used in production environments: -| Modifier | Effect | -| --------- | ------------------------------------------------------------------------------------------------------------------------------------------- | -| hidden | SourceMap is emitted as a separate file, but no `//# sourceMappingURL=[url]` comment is added to the bundle, protecting source code privacy | -| inline | SourceMap is added as a DataUrl to the bundle | -| nosources | SourceMap is created without the `sourcesContent` in it | -| debugids | SourceMap is created with the `debugId` in it | +| Modifier | Effect | +| --------- | -------------------------------------------------------------------------------------------------------------------------------------------- | +| hidden | source map is emitted as a separate file, but no `//# sourceMappingURL=[url]` comment is added to the bundle, protecting source code privacy | +| inline | source map is added as a DataUrl to the bundle | +| nosources | source map is created without the `sourcesContent` in it | +| debugids | source map is created with the `debugId` in it | We expect a certain pattern when validate devtool name, pay attention and don't mix up the sequence of devtool string. The pattern is: `[inline-|hidden-|eval-][nosources-][cheap-[module-]]source-map[-debugids]`. @@ -63,34 +63,26 @@ We expect a certain pattern when validate devtool name, pay attention and don't The following options are ideal for development: -`eval` - Each module is executed with `eval()` and `//# sourceURL`. This is pretty fast. The main disadvantage is that it doesn't display line numbers correctly since it gets mapped to transpiled code instead of the original code (No Source Maps from Loaders). +`eval` - Each module is executed with `eval()` and `//# sourceURL`. This is pretty fast. The main disadvantage is that it doesn't display line numbers correctly since it gets mapped to transpiled code instead of the original code (No source maps from Loaders). -`eval-source-map` - Each module is executed with `eval()` and a SourceMap is added as a DataUrl to the `eval()`. Initially it is slow, but it provides fast rebuild speed and yields real files. Line numbers are correctly mapped since it gets mapped to the original code. It yields the best quality SourceMaps for development. +`eval-source-map` - Each module is executed with `eval()` and a source map is added as a DataUrl to the `eval()`. Initially it is slow, but it provides fast rebuild speed and yields real files. Line numbers are correctly mapped since it gets mapped to the original code. It yields the best quality source maps for development. -`eval-cheap-source-map` - Similar to `eval-source-map`, each module is executed with `eval()`. It is "cheap" because it doesn't have column mappings, it only maps line numbers. It ignores SourceMaps from Loaders and only display transpiled code similar to the eval devtool. +`eval-cheap-source-map` - Similar to `eval-source-map`, each module is executed with `eval()`. It is "cheap" because it doesn't have column mappings, it only maps line numbers. It ignores source maps from Loaders and only display transpiled code similar to the eval devtool. -`eval-cheap-module-source-map` - Similar to `eval-cheap-source-map`, however, in this case Source Maps from Loaders are processed for better results. However Loader Source Maps are simplified to a single mapping per line. +`eval-cheap-module-source-map` - Similar to `eval-cheap-source-map`, however, in this case source maps from Loaders are processed for better results. However Loader source maps are simplified to a single mapping per line. ### Production These options are typically used in production: -'false' - No SourceMap is emitted. This is a good option to start with. +'false' - No source map is emitted. This is a good option to start with. -`source-map` - A full SourceMap is emitted as a separate file. It adds a reference comment to the bundle so development tools know where to find it. +`source-map` - A full source map is emitted as a separate file. It adds a reference comment to the bundle so development tools know where to find it. -:::warning -You should configure your server to disallow access to the Source Map file for normal users! -::: - -`hidden-source-map` - Same as `source-map`, but doesn't add a reference comment to the bundle. Useful if you only want SourceMaps to map error stack traces from error reports, but don't want to expose your SourceMap for the browser development tools. - -:::warning -You should not deploy the Source Map file to the webserver. Instead only use it for error report tooling. -::: +`hidden-source-map` - Same as `source-map`, but doesn't add a reference comment to the bundle. Useful if you only want source maps to map error stack traces from error reports, but don't want to expose your source map for the browser development tools. -`nosources-source-map` - A SourceMap is created without the `sourcesContent` in it. It can be used to map stack traces on the client without exposing all of the source code. You can deploy the Source Map file to the webserver. +`nosources-source-map` - A source map is created without the `sourcesContent` (the original source code) in it. It still exposes the original filenames and structure and can be used to map stack traces on the client without exposing the source code. This kind of source map can be deployed to the web server if you can accept the file name being exposed. :::warning -It still exposes original filenames and structure, but it doesn't expose the original code. +When using `source-map` or `hidden-source-map`, do not deploy the source maps (`.map` file) to the public web server or CDN. Public source maps will expose your source code and may bring security risks. ::: diff --git a/website/docs/en/config/optimization.mdx b/website/docs/en/config/optimization.mdx index 3cc07130d5d6..3b86c523235e 100644 --- a/website/docs/en/config/optimization.mdx +++ b/website/docs/en/config/optimization.mdx @@ -427,6 +427,14 @@ Here we assign the `value` to `value2`. Both `value2` and `value` are accessed w Tells Rspack to find segments of the module graph which can be safely concatenated into a single module. Depends on [optimization.providedExports](#optimizationprovidedexports) and [optimization.usedExports](#optimizationusedexports). By default `optimization.concatenateModules` is enabled in `production` mode and disabled elsewise. +```js title="rspack.config.mjs" +export default { + optimization: { + concatenateModules: false, + }, +}; +``` + ## optimization.nodeEnv