From e05a545efbdcb919edb27958b0bff1326fabfd42 Mon Sep 17 00:00:00 2001 From: Fy <1114550440@qq.com> Date: Sun, 26 Jul 2026 02:05:25 +0800 Subject: [PATCH 01/13] Optimize direct CommonJS external requires in ESM output --- crates/rspack_core/src/external_module.rs | 62 +-- .../src/dependency/commonjs_external.rs | 411 ++++++++++++++++++ .../src/dependency/mod.rs | 1 + .../rspack_plugin_esm_library/src/plugin.rs | 54 ++- .../common_js_export_require_dependency.rs | 12 + .../common_js_full_require_dependency.rs | 12 + .../commonjs/common_js_require_dependency.rs | 4 + .../commonjs/require_header_dependency.rs | 4 + .../__snapshots__/esm.snap.txt | 0 .../runtimeModeSnapshot/esm.snap.txt | 0 .../commonjs-require-conditional/index.js | 11 + .../commonjs-require-conditional/local.cjs | 1 + .../rspack.config.js | 6 + .../test.config.js | 27 ++ .../commonjs-require-conditional/warnings.js | 3 + .../__snapshots__/esm.snap.txt | 0 .../runtimeModeSnapshot/esm.snap.txt | 0 .../commonjs-require-direct/index.js | 4 + .../commonjs-require-direct/reexport.cjs | 1 + .../commonjs-require-direct/rspack.config.js | 5 + .../commonjs-require-direct/test.config.js | 33 ++ .../__snapshots__/esm.snap.txt | 26 +- .../runtimeModeSnapshot/esm.snap.txt | 26 +- .../modern-module-explicit-node/index.js | 1 + .../test.config.mjs | 7 +- .../__snapshots__/esm.snap.txt | 49 +-- .../runtimeModeSnapshot/esm.snap.txt | 47 +- 27 files changed, 638 insertions(+), 169 deletions(-) create mode 100644 crates/rspack_plugin_esm_library/src/dependency/commonjs_external.rs create mode 100644 tests/rspack-test/esmOutputCases/externals/commonjs-require-conditional/__snapshots__/esm.snap.txt create mode 100644 tests/rspack-test/esmOutputCases/externals/commonjs-require-conditional/__snapshots__/runtimeModeSnapshot/esm.snap.txt create mode 100644 tests/rspack-test/esmOutputCases/externals/commonjs-require-conditional/index.js create mode 100644 tests/rspack-test/esmOutputCases/externals/commonjs-require-conditional/local.cjs create mode 100644 tests/rspack-test/esmOutputCases/externals/commonjs-require-conditional/rspack.config.js create mode 100644 tests/rspack-test/esmOutputCases/externals/commonjs-require-conditional/test.config.js create mode 100644 tests/rspack-test/esmOutputCases/externals/commonjs-require-conditional/warnings.js create mode 100644 tests/rspack-test/esmOutputCases/externals/commonjs-require-direct/__snapshots__/esm.snap.txt create mode 100644 tests/rspack-test/esmOutputCases/externals/commonjs-require-direct/__snapshots__/runtimeModeSnapshot/esm.snap.txt create mode 100644 tests/rspack-test/esmOutputCases/externals/commonjs-require-direct/index.js create mode 100644 tests/rspack-test/esmOutputCases/externals/commonjs-require-direct/reexport.cjs create mode 100644 tests/rspack-test/esmOutputCases/externals/commonjs-require-direct/rspack.config.js create mode 100644 tests/rspack-test/esmOutputCases/externals/commonjs-require-direct/test.config.js diff --git a/crates/rspack_core/src/external_module.rs b/crates/rspack_core/src/external_module.rs index e1cc5fb49e13..9bbf87c9af67 100644 --- a/crates/rspack_core/src/external_module.rs +++ b/crates/rspack_core/src/external_module.rs @@ -11,7 +11,7 @@ use rustc_hash::FxHashMap as HashMap; use serde::Serialize; use crate::{ - BoxModule, BuildContext, BuildInfo, BuildMeta, BuildMetaExportsType, ChunkGraph, + BoxChunkInitFragment, BoxModule, BuildContext, BuildInfo, BuildMeta, BuildMetaExportsType, ChunkGraph, ChunkInitFragments, ChunkUkey, CodeGenerationDataChunkInitFragments, CodeGenerationDataUrl, CodeGenerationResultBuilder, Compilation, ConcatenationScope, Context, CssLayer, CssModuleRenderCondition, DependenciesBlock, DependenciesBlockData, DependencyRef, @@ -140,6 +140,36 @@ fn get_source_for_commonjs(module_and_specifiers: Option<&ExternalRequestValue>) format!("require({}){}", json_stringify_str(module_name), properties) } +pub fn create_node_commonjs_init_fragment(compilation: &Compilation) -> BoxChunkInitFragment { + let need_prefix = compilation + .options + .output + .environment + .supports_node_prefix_for_core_modules(); + + NormalInitFragment::new( + format!( + "import {{ createRequire as __rspack_createRequire }} from \"{}\";\n{} __rspack_createRequire_require = __rspack_createRequire({}.url);\n", + if need_prefix { "node:module" } else { "module" }, + if compilation.options.output.environment.supports_const() { + "const" + } else { + "var" + }, + compilation.options.output.import_meta_name + ), + InitFragmentStage::StageESMImports, + 0, + InitFragmentKey::ModuleExternal("node-commonjs".to_string()), + None, + ) + .with_top_level_decl_symbols(vec![ + "__rspack_createRequire".into(), + "__rspack_createRequire_require".into(), + ]) + .boxed() +} + fn get_source_for_import( module_and_specifiers: Option<&ExternalRequestValue>, compilation: &Compilation, @@ -633,36 +663,8 @@ impl ExternalModule { ) } "node-commonjs" => { - let need_prefix = compilation - .options - .output - .environment - .supports_node_prefix_for_core_modules(); - if compilation.options.output.module { - chunk_init_fragments.push( - NormalInitFragment::new( - format!( - "import {{ createRequire as __rspack_createRequire }} from \"{}\";\n{} __rspack_createRequire_require = __rspack_createRequire({}.url);\n", - if need_prefix { "node:module" } else { "module" }, - if compilation.options.output.environment.supports_const() { - "const" - } else { - "var" - }, - compilation.options.output.import_meta_name - ), - InitFragmentStage::StageESMImports, - 0, - InitFragmentKey::ModuleExternal("node-commonjs".to_string()), - None, - ) - .with_top_level_decl_symbols(vec![ - "__rspack_createRequire".into(), - "__rspack_createRequire_require".into(), - ]) - .boxed(), - ); + chunk_init_fragments.push(create_node_commonjs_init_fragment(compilation)); let (request, specifiers) = if let Some(request) = request { ( json_stringify_str(request.primary()), diff --git a/crates/rspack_plugin_esm_library/src/dependency/commonjs_external.rs b/crates/rspack_plugin_esm_library/src/dependency/commonjs_external.rs new file mode 100644 index 000000000000..fdca15c8318e --- /dev/null +++ b/crates/rspack_plugin_esm_library/src/dependency/commonjs_external.rs @@ -0,0 +1,411 @@ +use std::sync::Arc; + +use atomic_refcell::AtomicRefCell; +use rspack_core::{ + BuildModuleGraphArtifact, Dependency, DependencyCodeGeneration, DependencyId, DependencyRange, + DependencyTemplate, TemplateContext, TemplateReplaceSource, UsedName, + create_node_commonjs_init_fragment, property_access, +}; +use rspack_plugin_javascript::dependency::{ + CommonJsExportRequireDependency, CommonJsFullRequireDependency, CommonJsRequireDependency, + RequireHeaderDependency, +}; +use rspack_util::{ + fx_hash::{FxHashMap, FxHashSet}, + json_stringify_str, +}; + +pub type DirectCommonJsExternalDependencies = Arc>>>; + +#[derive(Debug, Clone, Copy)] +enum DirectRequireKind { + CommonJs, + NodeCommonJs, +} + +#[derive(Debug, Clone)] +struct DirectExternalRequireHeaders(Vec<(DependencyRange, DirectRequireKind)>); + +fn direct_require_kind(external_type: &str) -> Option { + match external_type { + "commonjs" | "commonjs2" | "commonjs-module" | "commonjs-static" => { + Some(DirectRequireKind::CommonJs) + } + "node-commonjs" => Some(DirectRequireKind::NodeCommonJs), + _ => None, + } +} + +pub fn cutout_commonjs_externals( + build_module_graph_artifact: &mut BuildModuleGraphArtifact, +) -> FxHashSet { + let module_graph = build_module_graph_artifact.get_module_graph(); + let mut direct_dependencies = FxHashSet::default(); + + for (_, module) in module_graph.modules() { + let require_header_ranges = module + .get_presentational_dependencies() + .into_iter() + .flatten() + .filter_map(|dependency| { + dependency + .as_any() + .downcast_ref::() + .map(RequireHeaderDependency::range) + }) + .collect::>(); + let mut dependencies_by_range = FxHashMap::::default(); + let mut self_rendering_require_dependencies = Vec::new(); + + for dependency_id in module.get_dependencies() { + let dependency = module_graph.dependency_by_id(dependency_id); + if dependency.as_any().is::() + || dependency.as_any().is::() + { + self_rendering_require_dependencies.push(*dependency_id); + continue; + } + let Some(dependency) = dependency + .as_any() + .downcast_ref::() + else { + continue; + }; + if dependency.get_context().is_some() { + continue; + } + let Some(expression_range) = dependency.range() else { + continue; + }; + + let entry = dependencies_by_range + .entry(expression_range) + .or_insert((*dependency_id, 0)); + entry.1 += 1; + } + + let direct_require_candidates = dependencies_by_range + .into_values() + .filter_map(|(dependency_id, count)| { + if count != 1 { + return None; + } + let expression_range = module_graph + .dependency_by_id(&dependency_id) + .range() + .expect("grouped CommonJS require should have an expression range"); + require_header_ranges + .iter() + .any(|header_range| { + expression_range.start <= header_range.start && header_range.end <= expression_range.end + }) + .then_some(dependency_id) + }) + .chain(self_rendering_require_dependencies); + for dependency_id in direct_require_candidates { + let Some(external_module) = module_graph + .module_identifier_by_dependency_id(&dependency_id) + .and_then(|module_id| module_graph.module_by_identifier(module_id)) + .and_then(|module| module.as_external_module()) + else { + continue; + }; + + if direct_require_kind(external_module.resolve_external_type()).is_some() + && !external_module.get_request().has_rest() + { + direct_dependencies.insert(dependency_id); + } + } + } + + let module_graph = build_module_graph_artifact.get_module_graph_mut(); + for dependency_id in &direct_dependencies { + module_graph + .connection_by_dependency_id_mut(dependency_id) + .expect("direct CommonJS external should have a module graph connection") + .force_inactive(); + } + + direct_dependencies +} + +fn get_direct_external_require( + dependency_id: &DependencyId, + expression_range: DependencyRange, + direct_dependencies: &DirectCommonJsExternalDependencies, + context: &TemplateContext, +) -> Option<(String, DependencyRange, DirectRequireKind)> { + if !direct_dependencies.borrow().contains(dependency_id) { + return None; + } + + let module_graph = context.compilation.get_module_graph(); + let external_module = module_graph + .module_identifier_by_dependency_id(dependency_id) + .and_then(|module_id| module_graph.module_by_identifier(module_id)) + .and_then(|module| module.as_external_module())?; + + Some(( + external_module.get_request().primary().to_string(), + expression_range, + direct_require_kind(external_module.resolve_external_type())?, + )) +} + +fn render_direct_require( + request: &str, + properties: &[rspack_util::atom::Atom], + kind: DirectRequireKind, + context: &mut TemplateContext, +) -> String { + let require = match kind { + DirectRequireKind::CommonJs => "require", + DirectRequireKind::NodeCommonJs => "__rspack_createRequire_require", + }; + + if matches!(kind, DirectRequireKind::NodeCommonJs) { + let init_fragment = create_node_commonjs_init_fragment(context.compilation); + context.chunk_init_fragments().push(init_fragment); + } + + format!( + "{require}({}){}", + json_stringify_str(request), + property_access(properties, 0) + ) +} + +#[derive(Debug)] +pub struct DirectCommonJsRequireDependencyTemplate { + pub direct_dependencies: DirectCommonJsExternalDependencies, + pub template: Option>, +} + +impl DependencyTemplate for DirectCommonJsRequireDependencyTemplate { + fn render( + &self, + dependency: &dyn DependencyCodeGeneration, + source: &mut TemplateReplaceSource, + context: &mut TemplateContext, + ) { + let dependency = dependency + .as_any() + .downcast_ref::() + .expect( + "DirectCommonJsRequireDependencyTemplate should only be used for CommonJsRequireDependency", + ); + + let Some(expression_range) = dependency.range() else { + if let Some(template) = &self.template { + template.render(dependency, source, context); + } + return; + }; + let Some((request, expression_range, kind)) = get_direct_external_require( + dependency.id(), + expression_range, + &self.direct_dependencies, + context, + ) else { + if let Some(template) = &self.template { + template.render(dependency, source, context); + } + return; + }; + + let request_range = dependency.request_range(); + source.replace( + request_range.start, + request_range.end, + json_stringify_str(&request), + None, + ); + + if context.data.get::().is_none() { + context + .data + .insert(DirectExternalRequireHeaders(Vec::new())); + } + context + .data + .get_mut::() + .expect("direct external require headers should be initialized") + .0 + .push((expression_range, kind)); + } +} + +#[derive(Debug)] +pub struct DirectCommonJsExportRequireDependencyTemplate { + pub direct_dependencies: DirectCommonJsExternalDependencies, + pub template: Option>, +} + +impl DependencyTemplate for DirectCommonJsExportRequireDependencyTemplate { + fn render( + &self, + dependency: &dyn DependencyCodeGeneration, + source: &mut TemplateReplaceSource, + context: &mut TemplateContext, + ) { + let dependency = dependency + .as_any() + .downcast_ref::() + .expect( + "DirectCommonJsExportRequireDependencyTemplate should only be used for CommonJsExportRequireDependency", + ); + let range = dependency.range(); + let Some((request, _, kind)) = + get_direct_external_require(dependency.id(), range, &self.direct_dependencies, context) + else { + if let Some(template) = &self.template { + template.render(dependency, source, context); + } + return; + }; + + let module_graph = context.compilation.get_module_graph(); + let module = module_graph + .module_by_identifier(&context.module.identifier()) + .expect("CommonJS export require should have a module graph module"); + let base = dependency.base(); + let base = if base.is_exports() { + context + .runtime_template + .render_exports_argument(module.get_exports_argument()) + } else if base.is_module_exports() { + format!( + "{}.exports", + context + .runtime_template + .render_module_argument(module.get_module_argument()) + ) + } else if base.is_this() { + context.runtime_template.render_this_exports() + } else { + unreachable!("CommonJS export require should use an expression base") + }; + let used = context + .compilation + .exports_info_artifact + .get_exports_info_data(&module.identifier()) + .get_used_name( + &context.compilation.exports_info_artifact, + context.runtime, + dependency.names(), + ); + let require_expression = + render_direct_require(&request, dependency.get_ids(module_graph), kind, context); + + let expression = match used { + Some(UsedName::Normal(used)) => { + format!("{base}{} = {require_expression}", property_access(used, 0)) + } + Some(UsedName::Inlined(_)) => { + format!("/* inlined reexport */ {require_expression}") + } + None => format!("/* unused reexport */ {require_expression}"), + }; + source.replace(range.start, range.end, expression, None); + } +} + +#[derive(Debug)] +pub struct DirectCommonJsFullRequireDependencyTemplate { + pub direct_dependencies: DirectCommonJsExternalDependencies, + pub template: Option>, +} + +impl DependencyTemplate for DirectCommonJsFullRequireDependencyTemplate { + fn render( + &self, + dependency: &dyn DependencyCodeGeneration, + source: &mut TemplateReplaceSource, + context: &mut TemplateContext, + ) { + let dependency = dependency + .as_any() + .downcast_ref::() + .expect( + "DirectCommonJsFullRequireDependencyTemplate should only be used for CommonJsFullRequireDependency", + ); + let range = dependency.range(); + let Some((request, _, kind)) = + get_direct_external_require(dependency.id(), range, &self.direct_dependencies, context) + else { + if let Some(template) = &self.template { + template.render(dependency, source, context); + } + return; + }; + + let mut expression = render_direct_require(&request, dependency.names(), kind, context); + if dependency.asi_safe() { + expression = format!("({expression})"); + } + source.replace(range.start, range.end, expression, None); + } +} + +#[derive(Debug)] +pub struct DirectRequireHeaderDependencyTemplate { + pub template: Option>, +} + +impl DependencyTemplate for DirectRequireHeaderDependencyTemplate { + fn render( + &self, + dependency: &dyn DependencyCodeGeneration, + source: &mut TemplateReplaceSource, + context: &mut TemplateContext, + ) { + let dependency = dependency + .as_any() + .downcast_ref::() + .expect( + "DirectRequireHeaderDependencyTemplate should only be used for RequireHeaderDependency", + ); + let header_range = dependency.range(); + let direct_require_kind = + context + .data + .get::() + .and_then(|headers| { + headers + .0 + .iter() + .find(|(expression_range, _)| { + expression_range.start <= header_range.start + && header_range.end <= expression_range.end + }) + .map(|(_, kind)| *kind) + }); + + match direct_require_kind { + Some(DirectRequireKind::CommonJs) => { + source.replace( + header_range.start, + header_range.end, + "require".to_string(), + None, + ); + } + Some(DirectRequireKind::NodeCommonJs) => { + source.replace( + header_range.start, + header_range.end, + "__rspack_createRequire_require".to_string(), + None, + ); + let init_fragment = create_node_commonjs_init_fragment(context.compilation); + context.chunk_init_fragments().push(init_fragment); + } + None => { + if let Some(template) = &self.template { + template.render(dependency, source, context); + } + } + } + } +} diff --git a/crates/rspack_plugin_esm_library/src/dependency/mod.rs b/crates/rspack_plugin_esm_library/src/dependency/mod.rs index 5c8aa564ca14..4079c6574cb8 100644 --- a/crates/rspack_plugin_esm_library/src/dependency/mod.rs +++ b/crates/rspack_plugin_esm_library/src/dependency/mod.rs @@ -1 +1,2 @@ +pub mod commonjs_external; pub mod dyn_import; diff --git a/crates/rspack_plugin_esm_library/src/plugin.rs b/crates/rspack_plugin_esm_library/src/plugin.rs index 1f0c88464f20..c7ed1db91b59 100644 --- a/crates/rspack_plugin_esm_library/src/plugin.rs +++ b/crates/rspack_plugin_esm_library/src/plugin.rs @@ -28,7 +28,11 @@ use rspack_hook::{plugin, plugin_hook}; use rspack_intern::Atom; use rspack_plugin_javascript::{ JavascriptModulesRenderChunkContent, JsPlugin, RenderSource, - dependency::ImportDependencyTemplate, parser_and_generator::JavaScriptParserAndGenerator, + dependency::{ + CommonJsExportRequireDependencyTemplate, CommonJsFullRequireDependencyTemplate, + CommonJsRequireDependencyTemplate, ImportDependencyTemplate, RequireHeaderDependencyTemplate, + }, + parser_and_generator::JavaScriptParserAndGenerator, }; use rspack_plugin_rslib::{ dyn_import_external::cutout_dyn_import_externals, @@ -41,7 +45,14 @@ use tokio::sync::RwLock; use crate::{ chunk_link::ChunkLinkContext, - dependency::dyn_import::DynamicImportDependencyTemplate, + dependency::{ + commonjs_external::{ + DirectCommonJsExportRequireDependencyTemplate, DirectCommonJsExternalDependencies, + DirectCommonJsFullRequireDependencyTemplate, DirectCommonJsRequireDependencyTemplate, + DirectRequireHeaderDependencyTemplate, cutout_commonjs_externals, + }, + dyn_import::DynamicImportDependencyTemplate, + }, esm_lib_parser_plugin::EsmLibParserPlugin, optimize_chunks::{ analyze_dyn_import_targets, assign_dyn_import_chunk_short_names, ensure_entry_exports, @@ -73,6 +84,7 @@ pub struct EsmLibraryPlugin { pub(crate) strict_export_chunks: AtomicRefCell>, pub(crate) all_dyn_targets: AtomicRefCell, pub(crate) namespace_targets: AtomicRefCell, + pub(crate) direct_commonjs_external_dependencies: DirectCommonJsExternalDependencies, /// module_id → namespace export name in the chunk, for modules whose exports /// were renamed in a multi-module chunk. Written during link, read during code generation. pub(crate) dyn_import_ns_map: Arc>>, @@ -91,6 +103,7 @@ impl EsmLibraryPlugin { Default::default(), Default::default(), Default::default(), + Default::default(), ) } @@ -282,6 +295,41 @@ async fn compilation( dyn_import_ns_map: self.dyn_import_ns_map.clone(), }), ); + let commonjs_require_template = + compilation.get_dependency_template(CommonJsRequireDependencyTemplate::template_type()); + compilation.set_dependency_template( + CommonJsRequireDependencyTemplate::template_type(), + Arc::new(DirectCommonJsRequireDependencyTemplate { + direct_dependencies: self.direct_commonjs_external_dependencies.clone(), + template: commonjs_require_template, + }), + ); + let commonjs_export_require_template = + compilation.get_dependency_template(CommonJsExportRequireDependencyTemplate::template_type()); + compilation.set_dependency_template( + CommonJsExportRequireDependencyTemplate::template_type(), + Arc::new(DirectCommonJsExportRequireDependencyTemplate { + direct_dependencies: self.direct_commonjs_external_dependencies.clone(), + template: commonjs_export_require_template, + }), + ); + let commonjs_full_require_template = + compilation.get_dependency_template(CommonJsFullRequireDependencyTemplate::template_type()); + compilation.set_dependency_template( + CommonJsFullRequireDependencyTemplate::template_type(), + Arc::new(DirectCommonJsFullRequireDependencyTemplate { + direct_dependencies: self.direct_commonjs_external_dependencies.clone(), + template: commonjs_full_require_template, + }), + ); + let require_header_template = + compilation.get_dependency_template(RequireHeaderDependencyTemplate::template_type()); + compilation.set_dependency_template( + RequireHeaderDependencyTemplate::template_type(), + Arc::new(DirectRequireHeaderDependencyTemplate { + template: require_header_template, + }), + ); let worker_template = compilation.get_dependency_template( rspack_core::DependencyTemplateType::Dependency(DependencyType::NewWorker), ); @@ -798,6 +846,8 @@ async fn optimize_dependencies( exports_info_artifact: &mut ExportsInfoArtifact, _diagnostics: &mut Vec, ) -> Result> { + *self.direct_commonjs_external_dependencies.borrow_mut() = + Arc::new(cutout_commonjs_externals(build_module_graph_artifact)); cutout_dyn_import_externals( false, compilation.options.output.module, diff --git a/crates/rspack_plugin_javascript/src/dependency/commonjs/common_js_export_require_dependency.rs b/crates/rspack_plugin_javascript/src/dependency/commonjs/common_js_export_require_dependency.rs index 829811a90e35..a01795e917c7 100644 --- a/crates/rspack_plugin_javascript/src/dependency/commonjs/common_js_export_require_dependency.rs +++ b/crates/rspack_plugin_javascript/src/dependency/commonjs/common_js_export_require_dependency.rs @@ -54,6 +54,18 @@ impl CommonJsExportRequireDependency { result_used, } } + + pub fn range(&self) -> DependencyRange { + self.range + } + + pub fn base(&self) -> ExportsBase { + self.base + } + + pub fn names(&self) -> &[Atom] { + &self.names + } } impl CommonJsExportRequireDependency { diff --git a/crates/rspack_plugin_javascript/src/dependency/commonjs/common_js_full_require_dependency.rs b/crates/rspack_plugin_javascript/src/dependency/commonjs/common_js_full_require_dependency.rs index ba548f865ebf..5494bd7a50d8 100644 --- a/crates/rspack_plugin_javascript/src/dependency/commonjs/common_js_full_require_dependency.rs +++ b/crates/rspack_plugin_javascript/src/dependency/commonjs/common_js_full_require_dependency.rs @@ -52,6 +52,18 @@ impl CommonJsFullRequireDependency { loc, } } + + pub fn names(&self) -> &[Atom] { + &self.names + } + + pub fn range(&self) -> DependencyRange { + self.range + } + + pub fn asi_safe(&self) -> bool { + self.asi_safe + } } #[cacheable_dyn] diff --git a/crates/rspack_plugin_javascript/src/dependency/commonjs/common_js_require_dependency.rs b/crates/rspack_plugin_javascript/src/dependency/commonjs/common_js_require_dependency.rs index 587a88196dc0..9241bb6c87d1 100644 --- a/crates/rspack_plugin_javascript/src/dependency/commonjs/common_js_require_dependency.rs +++ b/crates/rspack_plugin_javascript/src/dependency/commonjs/common_js_require_dependency.rs @@ -90,6 +90,10 @@ impl CommonJsRequireDependency { None => guard, }); } + + pub fn request_range(&self) -> DependencyRange { + self.range + } } #[cacheable_dyn] diff --git a/crates/rspack_plugin_javascript/src/dependency/commonjs/require_header_dependency.rs b/crates/rspack_plugin_javascript/src/dependency/commonjs/require_header_dependency.rs index 2d2253b4d758..8528b321616d 100644 --- a/crates/rspack_plugin_javascript/src/dependency/commonjs/require_header_dependency.rs +++ b/crates/rspack_plugin_javascript/src/dependency/commonjs/require_header_dependency.rs @@ -21,6 +21,10 @@ impl RequireHeaderDependency { loc, } } + + pub fn range(&self) -> DependencyRange { + self.range + } } #[cacheable_dyn] diff --git a/tests/rspack-test/esmOutputCases/externals/commonjs-require-conditional/__snapshots__/esm.snap.txt b/tests/rspack-test/esmOutputCases/externals/commonjs-require-conditional/__snapshots__/esm.snap.txt new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/tests/rspack-test/esmOutputCases/externals/commonjs-require-conditional/__snapshots__/runtimeModeSnapshot/esm.snap.txt b/tests/rspack-test/esmOutputCases/externals/commonjs-require-conditional/__snapshots__/runtimeModeSnapshot/esm.snap.txt new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/tests/rspack-test/esmOutputCases/externals/commonjs-require-conditional/index.js b/tests/rspack-test/esmOutputCases/externals/commonjs-require-conditional/index.js new file mode 100644 index 000000000000..542027def77f --- /dev/null +++ b/tests/rspack-test/esmOutputCases/externals/commonjs-require-conditional/index.js @@ -0,0 +1,11 @@ +const selected = require( + globalThis.__USE_EXTERNAL_OS__ ? "external-os" : "./local.cjs" +); +const mixed = require( + globalThis.__USE_EXTERNAL_OS__ + ? "external-os" + : "./" + globalThis.__LOCAL_MODULE__ +); + +export const platform = selected.platform(); +export const mixedPlatform = mixed.platform; diff --git a/tests/rspack-test/esmOutputCases/externals/commonjs-require-conditional/local.cjs b/tests/rspack-test/esmOutputCases/externals/commonjs-require-conditional/local.cjs new file mode 100644 index 000000000000..cdec022116d6 --- /dev/null +++ b/tests/rspack-test/esmOutputCases/externals/commonjs-require-conditional/local.cjs @@ -0,0 +1 @@ +exports.platform = () => "local"; diff --git a/tests/rspack-test/esmOutputCases/externals/commonjs-require-conditional/rspack.config.js b/tests/rspack-test/esmOutputCases/externals/commonjs-require-conditional/rspack.config.js new file mode 100644 index 000000000000..003601ecdc23 --- /dev/null +++ b/tests/rspack-test/esmOutputCases/externals/commonjs-require-conditional/rspack.config.js @@ -0,0 +1,6 @@ +module.exports = { + externalsType: 'modern-module', + externals: { + 'external-os': 'os', + }, +}; diff --git a/tests/rspack-test/esmOutputCases/externals/commonjs-require-conditional/test.config.js b/tests/rspack-test/esmOutputCases/externals/commonjs-require-conditional/test.config.js new file mode 100644 index 000000000000..2383cefeb8a5 --- /dev/null +++ b/tests/rspack-test/esmOutputCases/externals/commonjs-require-conditional/test.config.js @@ -0,0 +1,27 @@ +const fs = require("fs"); +const path = require("path"); + +function readOutput(options) { + return fs + .readdirSync(options.output.path) + .filter(file => file.endsWith(".mjs")) + .map(file => fs.readFileSync(path.join(options.output.path, file), "utf-8")) + .join("\n"); +} + +module.exports = { + findBundle() { + return []; + }, + snapshotFileFilter() { + return false; + }, + afterExecute(options) { + const source = readOutput(options); + + expect(source).toContain('external "os"'); + expect(source).toMatch( + /(?:__webpack_require__|__rspack_context\.r)\s*\(/ + ); + } +}; diff --git a/tests/rspack-test/esmOutputCases/externals/commonjs-require-conditional/warnings.js b/tests/rspack-test/esmOutputCases/externals/commonjs-require-conditional/warnings.js new file mode 100644 index 000000000000..a96e46cf5ef9 --- /dev/null +++ b/tests/rspack-test/esmOutputCases/externals/commonjs-require-conditional/warnings.js @@ -0,0 +1,3 @@ +module.exports = [ + /Critical dependency: the request of a dependency is an expression/ +]; diff --git a/tests/rspack-test/esmOutputCases/externals/commonjs-require-direct/__snapshots__/esm.snap.txt b/tests/rspack-test/esmOutputCases/externals/commonjs-require-direct/__snapshots__/esm.snap.txt new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/tests/rspack-test/esmOutputCases/externals/commonjs-require-direct/__snapshots__/runtimeModeSnapshot/esm.snap.txt b/tests/rspack-test/esmOutputCases/externals/commonjs-require-direct/__snapshots__/runtimeModeSnapshot/esm.snap.txt new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/tests/rspack-test/esmOutputCases/externals/commonjs-require-direct/index.js b/tests/rspack-test/esmOutputCases/externals/commonjs-require-direct/index.js new file mode 100644 index 000000000000..93d724dbee6b --- /dev/null +++ b/tests/rspack-test/esmOutputCases/externals/commonjs-require-direct/index.js @@ -0,0 +1,4 @@ +const external = require("external"); +const reexported = require("./reexport.cjs"); + +export const value = external.value + reexported.value; diff --git a/tests/rspack-test/esmOutputCases/externals/commonjs-require-direct/reexport.cjs b/tests/rspack-test/esmOutputCases/externals/commonjs-require-direct/reexport.cjs new file mode 100644 index 000000000000..0f9cd4f1c1df --- /dev/null +++ b/tests/rspack-test/esmOutputCases/externals/commonjs-require-direct/reexport.cjs @@ -0,0 +1 @@ +module.exports = require("external"); diff --git a/tests/rspack-test/esmOutputCases/externals/commonjs-require-direct/rspack.config.js b/tests/rspack-test/esmOutputCases/externals/commonjs-require-direct/rspack.config.js new file mode 100644 index 000000000000..0bbeab3fab92 --- /dev/null +++ b/tests/rspack-test/esmOutputCases/externals/commonjs-require-direct/rspack.config.js @@ -0,0 +1,5 @@ +module.exports = { + externals: { + external: 'commonjs external', + }, +}; diff --git a/tests/rspack-test/esmOutputCases/externals/commonjs-require-direct/test.config.js b/tests/rspack-test/esmOutputCases/externals/commonjs-require-direct/test.config.js new file mode 100644 index 000000000000..08174bcd7c65 --- /dev/null +++ b/tests/rspack-test/esmOutputCases/externals/commonjs-require-direct/test.config.js @@ -0,0 +1,33 @@ +const fs = require("fs"); +const path = require("path"); + +function readOutput(options) { + return fs + .readdirSync(options.output.path) + .filter(file => file.endsWith(".mjs")) + .map(file => fs.readFileSync(path.join(options.output.path, file), "utf-8")) + .join("\n"); +} + +module.exports = { + findBundle() { + return []; + }, + snapshotFileFilter() { + return false; + }, + afterExecute(options) { + const source = readOutput(options); + + expect(source).toMatch( + /const\s+external\s*=\s*require\s*\(\s*["']external["']\s*\)/ + ); + expect(source).toMatch( + /module\.exports\s*=\s*require\s*\(\s*["']external["']\s*\)/ + ); + expect(source).not.toContain('external "external"'); + expect(source).not.toMatch( + /(?:__webpack_require__|__rspack_context\.r)\s*\(\s*[^)]*["']external["']/ + ); + } +}; diff --git a/tests/rspack-test/esmOutputCases/externals/esm-node-target-alias/__snapshots__/esm.snap.txt b/tests/rspack-test/esmOutputCases/externals/esm-node-target-alias/__snapshots__/esm.snap.txt index e5a11dcfb69b..7a13a9bbe52e 100644 --- a/tests/rspack-test/esmOutputCases/externals/esm-node-target-alias/__snapshots__/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/externals/esm-node-target-alias/__snapshots__/esm.snap.txt @@ -6,41 +6,25 @@ import { __webpack_require__ } from "./runtime.mjs"; import { createRequire as __rspack_createRequire } from "node:module"; const __rspack_createRequire_require = __rspack_createRequire(import.meta.url); __webpack_require__.add({ -"node:fs?435f" -/*!****************************!*\ - !*** external "node:path" ***! - \****************************/ -(module) { -module.exports = __rspack_createRequire_require("node:path"); - -}, -"node:url?b4ec" -/*!***************************!*\ - !*** external "node:url" ***! - \***************************/ -(module) { -module.exports = __rspack_createRequire_require("node:url"); - -}, "./cjs-consumer.cjs" /*!**************************!*\ !*** ./cjs-consumer.cjs ***! \**************************/ -(__unused_rspack_module, exports, __webpack_require__) { +(__unused_rspack_module, exports) { // CJS require of "module" type external — should be downgraded to node-commonjs -const nodePath = __webpack_require__(/*! node:fs */ "node:fs?435f"); +const nodePath = __rspack_createRequire_require("node:path"); exports.n = nodePath.resolve; // CJS require of "module-import" type external — should also be downgraded -const nodeUrl = __webpack_require__(/*! node:url */ "node:url?b4ec"); +const nodeUrl = __rspack_createRequire_require("node:url"); exports.g = nodeUrl.parse; }, }); -// node:fs?16c7 +// node:fs -// node:url?e0e4 +// node:url // ./index.js const cjs_consumer = __webpack_require__("./cjs-consumer.cjs"); diff --git a/tests/rspack-test/esmOutputCases/externals/esm-node-target-alias/__snapshots__/runtimeModeSnapshot/esm.snap.txt b/tests/rspack-test/esmOutputCases/externals/esm-node-target-alias/__snapshots__/runtimeModeSnapshot/esm.snap.txt index 70b559971ef1..64c8527493d5 100644 --- a/tests/rspack-test/esmOutputCases/externals/esm-node-target-alias/__snapshots__/runtimeModeSnapshot/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/externals/esm-node-target-alias/__snapshots__/runtimeModeSnapshot/esm.snap.txt @@ -6,41 +6,25 @@ import { parse } from "node:url"; import { createRequire as __rspack_createRequire } from "node:module"; const __rspack_createRequire_require = __rspack_createRequire(import.meta.url); moduleFactories.add({ -"node:fs?435f" -/*!****************************!*\ - !*** external "node:path" ***! - \****************************/ -(module) { -module.exports = __rspack_createRequire_require("node:path"); - -}, -"node:url?b4ec" -/*!***************************!*\ - !*** external "node:url" ***! - \***************************/ -(module) { -module.exports = __rspack_createRequire_require("node:url"); - -}, "./cjs-consumer.cjs" /*!**************************!*\ !*** ./cjs-consumer.cjs ***! \**************************/ (__unused_rspack_module, exports) { // CJS require of "module" type external — should be downgraded to node-commonjs -const nodePath = rspackRequire(/*! node:fs */ "node:fs?435f"); +const nodePath = __rspack_createRequire_require("node:path"); exports.n = nodePath.resolve; // CJS require of "module-import" type external — should also be downgraded -const nodeUrl = rspackRequire(/*! node:url */ "node:url?b4ec"); +const nodeUrl = __rspack_createRequire_require("node:url"); exports.g = nodeUrl.parse; }, }); -// node:fs?16c7 +// node:fs -// node:url?e0e4 +// node:url // ./index.js const cjs_consumer = rspackRequire("./cjs-consumer.cjs"); @@ -110,4 +94,4 @@ moduleFactories.add = function registerModules(modules) { Object.assign(moduleFa ; -``` \ No newline at end of file +``` diff --git a/tests/rspack-test/esmOutputCases/externals/modern-module-explicit-node/index.js b/tests/rspack-test/esmOutputCases/externals/modern-module-explicit-node/index.js index a68a55be1df9..8c634237df44 100644 --- a/tests/rspack-test/esmOutputCases/externals/modern-module-explicit-node/index.js +++ b/tests/rspack-test/esmOutputCases/externals/modern-module-explicit-node/index.js @@ -3,6 +3,7 @@ import { resolve } from "path"; const fs = require("fs"); export const readFile = fs.readFile; +export const stat = require("fs").stat; export const pathResolve = resolve; export async function loadPlatform() { diff --git a/tests/rspack-test/esmOutputCases/externals/modern-module-explicit-node/test.config.mjs b/tests/rspack-test/esmOutputCases/externals/modern-module-explicit-node/test.config.mjs index 2412beceb400..5c33d8ee8047 100644 --- a/tests/rspack-test/esmOutputCases/externals/modern-module-explicit-node/test.config.mjs +++ b/tests/rspack-test/esmOutputCases/externals/modern-module-explicit-node/test.config.mjs @@ -23,7 +23,12 @@ export default { expect(source).toMatch(/import\s*\(\s*["']os["']\s*\)/); expect(source).toMatch(/createRequire\s+as\s+__rspack_createRequire/); expect(source).toMatch( - /__rspack_createRequire_require\s*\(\s*["']fs["']\s*\)/ + /const\s+fs\s*=\s*__rspack_createRequire_require\s*\(\s*["']fs["']\s*\)/ + ); + expect(source).not.toContain('external "fs"'); + expect(source).not.toMatch(/__webpack_require__\s*\(\s*[^)]*["']fs["']/); + expect(source).toMatch( + /__rspack_createRequire_require\s*\(\s*["']fs["']\s*\)\.stat/ ); } }; diff --git a/tests/rspack-test/esmOutputCases/externals/node-commonjs-helper-name-collision/__snapshots__/esm.snap.txt b/tests/rspack-test/esmOutputCases/externals/node-commonjs-helper-name-collision/__snapshots__/esm.snap.txt index 08cd3f9bb7dd..08e3e6bfa052 100644 --- a/tests/rspack-test/esmOutputCases/externals/node-commonjs-helper-name-collision/__snapshots__/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/externals/node-commonjs-helper-name-collision/__snapshots__/esm.snap.txt @@ -1,21 +1,9 @@ ```mjs title=main.mjs -import { __webpack_require__ } from "./runtime.mjs"; - import {fileURLToPath as __rspack_fileURLToPath} from "node:url"; import {dirname as __rspack_dirname} from "node:path"; var __rspack_import_meta_dirname__ = __rspack_dirname(__rspack_fileURLToPath(import.meta.url)); import { createRequire as __rspack_createRequire } from "node:module"; const __rspack_createRequire_require = __rspack_createRequire(import.meta.url); -__webpack_require__.add({ -"fs" -/*!*********************!*\ - !*** external "fs" ***! - \*********************/ -(module) { -module.exports = __rspack_createRequire_require("fs"); - -}, -}); // node:module const external_node_module_namespaceObject = __rspack_createRequire_require("node:module"); // ./index.js @@ -27,7 +15,7 @@ const external_fs_namespaceObject = index_rspack_createRequire_require("fs"); const sourceCreateRequireRequire = index_rspack_createRequire_require; const sourceReadFile = external_fs_namespaceObject.readFile; -const sourceRequireReadFile = (__webpack_require__(/*! fs */ "fs")/* .readFile */.readFile); +const sourceRequireReadFile = (index_rspack_createRequire_require("fs").readFile); it("should deconflict source bindings that already use the node-commonjs helper names", async () => { const mod = await import(/* webpackIgnore: true */ "./main.mjs"); @@ -50,39 +38,4 @@ it("should deconflict source bindings that already use the node-commonjs helper export { sourceCreateRequireRequire, sourceReadFile, sourceRequireReadFile }; -``` - -```mjs title=runtime.mjs - -var __webpack_modules__ = {}; -// The module cache -var __webpack_module_cache__ = {}; -// The require function -function __webpack_require__(moduleId) { -// Check if module is in cache -var cachedModule = __webpack_module_cache__[moduleId]; -if (cachedModule !== undefined) { -return cachedModule.exports; -} -// Create a new module (and put it into the cache) -var module = (__webpack_module_cache__[moduleId] = { -exports: {} -}); -// Execute the module function -__webpack_modules__[moduleId](module, module.exports, __webpack_require__); - -// Return the exports of the module -return module.exports; -} -// expose the modules object (__webpack_modules__) -__webpack_require__.m = __webpack_modules__; - -// webpack/runtime/esm_register_module -(() => { -__webpack_require__.add = function registerModules(modules) { Object.assign(__webpack_require__.m, modules) } - -})(); - -export { __webpack_require__ }; - ``` \ No newline at end of file diff --git a/tests/rspack-test/esmOutputCases/externals/node-commonjs-helper-name-collision/__snapshots__/runtimeModeSnapshot/esm.snap.txt b/tests/rspack-test/esmOutputCases/externals/node-commonjs-helper-name-collision/__snapshots__/runtimeModeSnapshot/esm.snap.txt index fcaedecb87ef..3e352f74cb81 100644 --- a/tests/rspack-test/esmOutputCases/externals/node-commonjs-helper-name-collision/__snapshots__/runtimeModeSnapshot/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/externals/node-commonjs-helper-name-collision/__snapshots__/runtimeModeSnapshot/esm.snap.txt @@ -1,20 +1,9 @@ ```mjs title=main.mjs -import { rspackRequire, moduleFactories } from "./runtime.mjs"; import {fileURLToPath as __rspack_fileURLToPath} from "node:url"; import {dirname as __rspack_dirname} from "node:path"; var __rspack_import_meta_dirname__ = __rspack_dirname(__rspack_fileURLToPath(import.meta.url)); import { createRequire as __rspack_createRequire } from "node:module"; const __rspack_createRequire_require = __rspack_createRequire(import.meta.url); -moduleFactories.add({ -"fs" -/*!*********************!*\ - !*** external "fs" ***! - \*********************/ -(module) { -module.exports = __rspack_createRequire_require("fs"); - -}, -}); // node:module const external_node_module_namespaceObject = __rspack_createRequire_require("node:module"); // ./index.js @@ -26,7 +15,7 @@ const external_fs_namespaceObject = index_rspack_createRequire_require("fs"); const sourceCreateRequireRequire = index_rspack_createRequire_require; const sourceReadFile = external_fs_namespaceObject.readFile; -const sourceRequireReadFile = (rspackRequire(/*! fs */ "fs")/* .readFile */.readFile); +const sourceRequireReadFile = (index_rspack_createRequire_require("fs").readFile); it("should deconflict source bindings that already use the node-commonjs helper names", async () => { const mod = await import(/* webpackIgnore: true */ "./main.mjs"); @@ -50,37 +39,3 @@ it("should deconflict source bindings that already use the node-commonjs helper export { sourceCreateRequireRequire, sourceReadFile, sourceRequireReadFile }; ``` - -```mjs title=runtime.mjs - -var modules = {}; -// The module cache -var moduleCache = {}; -// The require function -function rspackRequire(moduleId) { -// Check if module is in cache -var cachedModule = moduleCache[moduleId]; -if (cachedModule !== undefined) { -return cachedModule.exports; -} -// Create a new module (and put it into the cache) -var module = (moduleCache[moduleId] = { -exports: {} -}); -// Execute the module function -modules[moduleId](module, module.exports, rspackRequire); - -// Return the exports of the module -return module.exports; -} -export { rspackRequire }; -// expose the modules object (modules) -var moduleFactories = modules; -export { moduleFactories }; - -// rspack/runtime/esm_register_module -moduleFactories.add = function registerModules(modules) { Object.assign(moduleFactories, modules) } -; - - -``` \ No newline at end of file From 9286c35709a8ef7ea92c63c8fce3d55e3e3f8a84 Mon Sep 17 00:00:00 2001 From: Fy <1114550440@qq.com> Date: Wed, 19 Aug 2026 11:49:11 +0800 Subject: [PATCH 02/13] fix: preserve CommonJS external semantics in modern-module --- Cargo.lock | 1 + crates/rspack_core/src/external_module.rs | 9 + .../src/module_graph/connection.rs | 60 ++++++ crates/rspack_plugin_esm_library/Cargo.toml | 1 + .../src/dependency/commonjs_external.rs | 135 +++++++++++++- .../rspack_plugin_esm_library/src/plugin.rs | 16 +- .../src/esm_node_target_plugin.rs | 16 +- crates/rspack_plugin_externals/src/lib.rs | 1 + .../__snapshot__/f.js.txt | 8 +- .../__snapshot__/runtimeModeSnapshot/f.js.txt | 6 +- .../rspack.config.mjs | 2 +- .../__snapshots__/esm.snap.txt | 137 ++++++++++++++ .../runtimeModeSnapshot/esm.snap.txt | 134 ++++++++++++++ .../entry-safe.js | 5 + .../entry-unsafe.js | 14 ++ .../commonjs-require-conditional/index.js | 11 -- .../commonjs-require-conditional/local.cjs | 2 +- .../node_modules/external/index.js | 5 + .../node_modules/external/package.json | 5 + .../rspack.config.js | 7 +- .../safe.cjs} | 0 .../test.config.js | 79 ++++++-- .../commonjs-require-conditional/unsafe.cjs | 13 ++ .../__snapshots__/esm.snap.txt | 111 +++++++++++ .../runtimeModeSnapshot/esm.snap.txt | 108 +++++++++++ .../commonjs-require-direct/consumer-a.cjs | 14 ++ .../commonjs-require-direct/consumer-b.cjs | 1 + .../commonjs-require-direct/entry-a.js | 19 ++ .../commonjs-require-direct/entry-b.js | 5 + .../commonjs-require-direct/index.js | 4 - .../node_modules/external/index.js | 8 + .../node_modules/external/package.json | 5 + .../commonjs-require-direct/rspack.config.js | 4 + .../commonjs-require-direct/test.config.js | 78 ++++++-- .../__snapshots__/esm.snap.txt | 82 +++++++++ .../runtimeModeSnapshot/esm.snap.txt | 80 ++++++++ .../commonjs-require-optional/index.js | 21 +++ .../node_modules/optional-external/index.js | 3 + .../optional-external/package.json | 5 + .../rspack.config.js | 6 + .../commonjs-require-optional/test.config.js | 38 ++++ .../__snapshots__/esm.snap.txt | 60 ++++++ .../runtimeModeSnapshot/esm.snap.txt | 58 ++++++ .../commonjs-require-request-rest/index.js | 7 + .../node_modules/external/index.js | 3 + .../node_modules/external/package.json | 5 + .../rspack.config.js | 5 + .../test.config.js | 24 +++ .../__snapshots__/esm.snap.txt | 22 ++- .../runtimeModeSnapshot/esm.snap.txt | 24 ++- .../esm-node-target-alias/cjs-consumer.cjs | 3 + .../externals/esm-node-target-alias/index.js | 8 +- .../esm-node-target-alias/rspack.config.mjs | 3 +- .../runtimeModeSnapshot/esm.snap.txt | 41 ----- .../__snapshots__/esm.snap.txt | 172 ++++++++++++++++++ .../runtimeModeSnapshot/esm.snap.txt | 162 +++++++++++++++++ .../external.cjs | 3 + .../node-commonjs-relative-request/index.js | 6 + .../node-commonjs-relative-request/lazy.cjs | 2 + .../packages/chunk/index.cjs | 3 + .../packages/chunk/package.json | 5 + .../packages/root/index.cjs | 3 + .../packages/root/package.json | 5 + .../rspack.config.js | 9 + .../test.config.js | 78 ++++++++ 65 files changed, 1836 insertions(+), 134 deletions(-) create mode 100644 tests/rspack-test/esmOutputCases/externals/commonjs-require-conditional/entry-safe.js create mode 100644 tests/rspack-test/esmOutputCases/externals/commonjs-require-conditional/entry-unsafe.js delete mode 100644 tests/rspack-test/esmOutputCases/externals/commonjs-require-conditional/index.js create mode 100644 tests/rspack-test/esmOutputCases/externals/commonjs-require-conditional/node_modules/external/index.js create mode 100644 tests/rspack-test/esmOutputCases/externals/commonjs-require-conditional/node_modules/external/package.json rename tests/rspack-test/esmOutputCases/externals/{commonjs-require-direct/reexport.cjs => commonjs-require-conditional/safe.cjs} (100%) create mode 100644 tests/rspack-test/esmOutputCases/externals/commonjs-require-conditional/unsafe.cjs create mode 100644 tests/rspack-test/esmOutputCases/externals/commonjs-require-direct/consumer-a.cjs create mode 100644 tests/rspack-test/esmOutputCases/externals/commonjs-require-direct/consumer-b.cjs create mode 100644 tests/rspack-test/esmOutputCases/externals/commonjs-require-direct/entry-a.js create mode 100644 tests/rspack-test/esmOutputCases/externals/commonjs-require-direct/entry-b.js delete mode 100644 tests/rspack-test/esmOutputCases/externals/commonjs-require-direct/index.js create mode 100644 tests/rspack-test/esmOutputCases/externals/commonjs-require-direct/node_modules/external/index.js create mode 100644 tests/rspack-test/esmOutputCases/externals/commonjs-require-direct/node_modules/external/package.json create mode 100644 tests/rspack-test/esmOutputCases/externals/commonjs-require-optional/__snapshots__/esm.snap.txt create mode 100644 tests/rspack-test/esmOutputCases/externals/commonjs-require-optional/__snapshots__/runtimeModeSnapshot/esm.snap.txt create mode 100644 tests/rspack-test/esmOutputCases/externals/commonjs-require-optional/index.js create mode 100644 tests/rspack-test/esmOutputCases/externals/commonjs-require-optional/node_modules/optional-external/index.js create mode 100644 tests/rspack-test/esmOutputCases/externals/commonjs-require-optional/node_modules/optional-external/package.json create mode 100644 tests/rspack-test/esmOutputCases/externals/commonjs-require-optional/rspack.config.js create mode 100644 tests/rspack-test/esmOutputCases/externals/commonjs-require-optional/test.config.js create mode 100644 tests/rspack-test/esmOutputCases/externals/commonjs-require-request-rest/__snapshots__/esm.snap.txt create mode 100644 tests/rspack-test/esmOutputCases/externals/commonjs-require-request-rest/__snapshots__/runtimeModeSnapshot/esm.snap.txt create mode 100644 tests/rspack-test/esmOutputCases/externals/commonjs-require-request-rest/index.js create mode 100644 tests/rspack-test/esmOutputCases/externals/commonjs-require-request-rest/node_modules/external/index.js create mode 100644 tests/rspack-test/esmOutputCases/externals/commonjs-require-request-rest/node_modules/external/package.json create mode 100644 tests/rspack-test/esmOutputCases/externals/commonjs-require-request-rest/rspack.config.js create mode 100644 tests/rspack-test/esmOutputCases/externals/commonjs-require-request-rest/test.config.js delete mode 100644 tests/rspack-test/esmOutputCases/externals/node-commonjs-helper-name-collision/__snapshots__/runtimeModeSnapshot/esm.snap.txt create mode 100644 tests/rspack-test/esmOutputCases/externals/node-commonjs-relative-request/__snapshots__/esm.snap.txt create mode 100644 tests/rspack-test/esmOutputCases/externals/node-commonjs-relative-request/__snapshots__/runtimeModeSnapshot/esm.snap.txt create mode 100644 tests/rspack-test/esmOutputCases/externals/node-commonjs-relative-request/external.cjs create mode 100644 tests/rspack-test/esmOutputCases/externals/node-commonjs-relative-request/index.js create mode 100644 tests/rspack-test/esmOutputCases/externals/node-commonjs-relative-request/lazy.cjs create mode 100644 tests/rspack-test/esmOutputCases/externals/node-commonjs-relative-request/packages/chunk/index.cjs create mode 100644 tests/rspack-test/esmOutputCases/externals/node-commonjs-relative-request/packages/chunk/package.json create mode 100644 tests/rspack-test/esmOutputCases/externals/node-commonjs-relative-request/packages/root/index.cjs create mode 100644 tests/rspack-test/esmOutputCases/externals/node-commonjs-relative-request/packages/root/package.json create mode 100644 tests/rspack-test/esmOutputCases/externals/node-commonjs-relative-request/rspack.config.js create mode 100644 tests/rspack-test/esmOutputCases/externals/node-commonjs-relative-request/test.config.js diff --git a/Cargo.lock b/Cargo.lock index 6bf2eefed8bc..2d8315c9e8b1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4852,6 +4852,7 @@ dependencies = [ "rspack_hook", "rspack_intern", "rspack_parallel", + "rspack_plugin_externals", "rspack_plugin_javascript", "rspack_plugin_rslib", "rspack_plugin_runtime", diff --git a/crates/rspack_core/src/external_module.rs b/crates/rspack_core/src/external_module.rs index 9bbf87c9af67..303940e175cf 100644 --- a/crates/rspack_core/src/external_module.rs +++ b/crates/rspack_core/src/external_module.rs @@ -607,6 +607,15 @@ impl ExternalModule { } pub fn set_external_type(&mut self, new_type: ExternalType) { + if let ExternalRequest::Map(map) = &mut self.request + && !map.contains_key(&new_type) + && let Some(request) = map.get(&self.external_type).cloned() + { + // Preserve the request selected by the previous type when a plugin + // changes how the external is rendered. Object-form externals are keyed + // by type, so changing only the type would make `get_request` panic. + map.insert(new_type.clone(), request); + } self.external_type = new_type; } diff --git a/crates/rspack_core/src/module_graph/connection.rs b/crates/rspack_core/src/module_graph/connection.rs index 3c1c9b1d51ec..45ca6e1c6767 100644 --- a/crates/rspack_core/src/module_graph/connection.rs +++ b/crates/rspack_core/src/module_graph/connection.rs @@ -45,6 +45,12 @@ pub struct ModuleGraphConnection { conditional: bool, } +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct ConnectionActiveState { + active: bool, + conditional: bool, +} + impl std::hash::Hash for ModuleGraphConnection { fn hash(&self, state: &mut H) { self.id.hash(state); @@ -82,6 +88,20 @@ impl ModuleGraphConnection { self.conditional = false; } + pub fn force_inactive_with_state(&mut self) -> ConnectionActiveState { + let state = ConnectionActiveState { + active: self.active, + conditional: self.conditional, + }; + self.force_inactive(); + state + } + + pub fn restore_active_state(&mut self, state: ConnectionActiveState) { + self.active = state.active; + self.conditional = state.conditional; + } + pub fn is_active( &self, module_graph: &ModuleGraph, @@ -155,6 +175,46 @@ impl ModuleGraphConnection { } } +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn should_restore_state_after_forcing_connection_inactive() { + let mut connection = ModuleGraphConnection::new( + DependencyId::from(1), + Some(ModuleIdentifier::from("issuer")), + ModuleIdentifier::from("target"), + true, + ); + + let state = connection.force_inactive_with_state(); + assert!(!connection.active); + assert!(!connection.conditional); + + connection.restore_active_state(state); + assert!(connection.active); + assert!(connection.conditional); + } + + #[test] + fn should_not_reactivate_an_already_inactive_connection() { + let mut connection = ModuleGraphConnection::new( + DependencyId::from(1), + Some(ModuleIdentifier::from("issuer")), + ModuleIdentifier::from("target"), + true, + ); + connection.force_inactive(); + + let state = connection.force_inactive_with_state(); + connection.restore_active_state(state); + + assert!(!connection.active); + assert!(!connection.conditional); + } +} + #[cacheable] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum ConnectionState { diff --git a/crates/rspack_plugin_esm_library/Cargo.toml b/crates/rspack_plugin_esm_library/Cargo.toml index 376aa17b39aa..0f46145f11da 100644 --- a/crates/rspack_plugin_esm_library/Cargo.toml +++ b/crates/rspack_plugin_esm_library/Cargo.toml @@ -19,6 +19,7 @@ rspack_hash = { workspace = true } rspack_hook = { workspace = true } rspack_intern = { workspace = true, features = ["atom"] } rspack_parallel = { workspace = true } +rspack_plugin_externals = { workspace = true } rspack_plugin_javascript = { workspace = true } rspack_plugin_rslib = { workspace = true } rspack_plugin_runtime = { workspace = true } diff --git a/crates/rspack_plugin_esm_library/src/dependency/commonjs_external.rs b/crates/rspack_plugin_esm_library/src/dependency/commonjs_external.rs index fdca15c8318e..748f0ec20161 100644 --- a/crates/rspack_plugin_esm_library/src/dependency/commonjs_external.rs +++ b/crates/rspack_plugin_esm_library/src/dependency/commonjs_external.rs @@ -1,11 +1,13 @@ -use std::sync::Arc; +use std::{collections::hash_map::Entry, sync::Arc}; use atomic_refcell::AtomicRefCell; +use rspack_cacheable::{cacheable, cacheable_dyn}; use rspack_core::{ - BuildModuleGraphArtifact, Dependency, DependencyCodeGeneration, DependencyId, DependencyRange, - DependencyTemplate, TemplateContext, TemplateReplaceSource, UsedName, - create_node_commonjs_init_fragment, property_access, + BuildModuleGraphArtifact, CodeGenerationDataItem, ConnectionActiveState, Dependency, + DependencyCodeGeneration, DependencyId, DependencyRange, DependencyTemplate, TemplateContext, + TemplateReplaceSource, UsedName, create_node_commonjs_init_fragment, property_access, }; +use rspack_plugin_externals::is_node_builtin; use rspack_plugin_javascript::dependency::{ CommonJsExportRequireDependency, CommonJsFullRequireDependency, CommonJsRequireDependency, RequireHeaderDependency, @@ -16,16 +18,23 @@ use rspack_util::{ }; pub type DirectCommonJsExternalDependencies = Arc>>>; +pub type DirectCommonJsExternalConnectionStates = + AtomicRefCell>; +#[cacheable] #[derive(Debug, Clone, Copy)] enum DirectRequireKind { CommonJs, NodeCommonJs, } +#[cacheable] #[derive(Debug, Clone)] struct DirectExternalRequireHeaders(Vec<(DependencyRange, DirectRequireKind)>); +#[cacheable_dyn] +impl CodeGenerationDataItem for DirectExternalRequireHeaders {} + fn direct_require_kind(external_type: &str) -> Option { match external_type { "commonjs" | "commonjs2" | "commonjs-module" | "commonjs-static" => { @@ -36,8 +45,29 @@ fn direct_require_kind(external_type: &str) -> Option { } } +fn is_relative_external_request(request: &str) -> bool { + request == "." + || request == ".." + || request.starts_with("./") + || request.starts_with("../") + || request.starts_with(".\\") + || request.starts_with("..\\") +} + +fn can_render_direct_request(kind: DirectRequireKind, request: &str) -> bool { + match kind { + DirectRequireKind::CommonJs => !is_relative_external_request(request), + // `createRequire(import.meta.url)` resolves packages and package imports + // relative to the emitted asset. Moving that call into an issuer in a + // different directory can load another package, so only base-independent + // Node builtins are safe to render directly. + DirectRequireKind::NodeCommonJs => is_node_builtin(request), + } +} + pub fn cutout_commonjs_externals( build_module_graph_artifact: &mut BuildModuleGraphArtifact, + connection_states: &mut FxHashMap, ) -> FxHashSet { let module_graph = build_module_graph_artifact.get_module_graph(); let mut direct_dependencies = FxHashSet::default(); @@ -103,6 +133,15 @@ pub fn cutout_commonjs_externals( }) .chain(self_rendering_require_dependencies); for dependency_id in direct_require_candidates { + let dependency = module_graph.dependency_by_id(&dependency_id); + // Keep optional requests on the normal module path so their failure and + // module-cache behavior remains owned by the CommonJS runtime. + if dependency + .as_module_dependency() + .is_some_and(|dependency| dependency.get_optional()) + { + continue; + } let Some(external_module) = module_graph .module_identifier_by_dependency_id(&dependency_id) .and_then(|module_id| module_graph.module_by_identifier(module_id)) @@ -111,8 +150,10 @@ pub fn cutout_commonjs_externals( continue; }; - if direct_require_kind(external_module.resolve_external_type()).is_some() - && !external_module.get_request().has_rest() + let request = external_module.get_request(); + if let Some(kind) = direct_require_kind(external_module.resolve_external_type()) + && !request.has_rest() + && can_render_direct_request(kind, request.primary()) { direct_dependencies.insert(dependency_id); } @@ -120,16 +161,92 @@ pub fn cutout_commonjs_externals( } let module_graph = build_module_graph_artifact.get_module_graph_mut(); + // A reused module graph can make a previously direct dependency ineligible. + // Restore the connection state captured before this plugin cut it out. + connection_states.retain(|dependency_id, state| { + if direct_dependencies.contains(dependency_id) { + return module_graph + .connection_by_dependency_id(dependency_id) + .is_some(); + } + if let Some(connection) = module_graph.connection_by_dependency_id_mut(dependency_id) { + connection.restore_active_state(*state); + } + false + }); for dependency_id in &direct_dependencies { - module_graph + let connection = module_graph .connection_by_dependency_id_mut(dependency_id) - .expect("direct CommonJS external should have a module graph connection") - .force_inactive(); + .expect("direct CommonJS external should have a module graph connection"); + match connection_states.entry(*dependency_id) { + Entry::Vacant(entry) => { + entry.insert(connection.force_inactive_with_state()); + } + Entry::Occupied(_) => connection.force_inactive(), + } } direct_dependencies } +#[cfg(test)] +mod tests { + use super::{DirectRequireKind, can_render_direct_request, is_relative_external_request}; + + #[test] + fn should_detect_relative_external_requests() { + assert!(is_relative_external_request(".")); + assert!(is_relative_external_request("..")); + assert!(is_relative_external_request("./external.cjs")); + assert!(is_relative_external_request("../external.cjs")); + assert!(is_relative_external_request(".\\external.cjs")); + assert!(is_relative_external_request("..\\external.cjs")); + assert!(!is_relative_external_request("external")); + assert!(!is_relative_external_request("node:fs")); + assert!(!is_relative_external_request("/external.cjs")); + } + + #[test] + fn should_only_render_base_independent_node_commonjs_requests_directly() { + assert!(can_render_direct_request( + DirectRequireKind::NodeCommonJs, + "path" + )); + assert!(can_render_direct_request( + DirectRequireKind::NodeCommonJs, + "node:path" + )); + assert!(!can_render_direct_request( + DirectRequireKind::NodeCommonJs, + "external" + )); + assert!(!can_render_direct_request( + DirectRequireKind::NodeCommonJs, + "." + )); + assert!(!can_render_direct_request( + DirectRequireKind::NodeCommonJs, + "#external" + )); + assert!(!can_render_direct_request( + DirectRequireKind::NodeCommonJs, + "/external.cjs" + )); + } + + #[test] + fn should_keep_bare_commonjs_requests_direct() { + assert!(can_render_direct_request( + DirectRequireKind::CommonJs, + "external" + )); + assert!(!can_render_direct_request( + DirectRequireKind::CommonJs, + "./external.cjs" + )); + } +} + fn get_direct_external_require( dependency_id: &DependencyId, expression_range: DependencyRange, diff --git a/crates/rspack_plugin_esm_library/src/plugin.rs b/crates/rspack_plugin_esm_library/src/plugin.rs index c7ed1db91b59..31357783448c 100644 --- a/crates/rspack_plugin_esm_library/src/plugin.rs +++ b/crates/rspack_plugin_esm_library/src/plugin.rs @@ -47,9 +47,10 @@ use crate::{ chunk_link::ChunkLinkContext, dependency::{ commonjs_external::{ - DirectCommonJsExportRequireDependencyTemplate, DirectCommonJsExternalDependencies, - DirectCommonJsFullRequireDependencyTemplate, DirectCommonJsRequireDependencyTemplate, - DirectRequireHeaderDependencyTemplate, cutout_commonjs_externals, + DirectCommonJsExportRequireDependencyTemplate, DirectCommonJsExternalConnectionStates, + DirectCommonJsExternalDependencies, DirectCommonJsFullRequireDependencyTemplate, + DirectCommonJsRequireDependencyTemplate, DirectRequireHeaderDependencyTemplate, + cutout_commonjs_externals, }, dyn_import::DynamicImportDependencyTemplate, }, @@ -85,6 +86,7 @@ pub struct EsmLibraryPlugin { pub(crate) all_dyn_targets: AtomicRefCell, pub(crate) namespace_targets: AtomicRefCell, pub(crate) direct_commonjs_external_dependencies: DirectCommonJsExternalDependencies, + pub(crate) direct_commonjs_external_connection_states: DirectCommonJsExternalConnectionStates, /// module_id → namespace export name in the chunk, for modules whose exports /// were renamed in a multi-module chunk. Written during link, read during code generation. pub(crate) dyn_import_ns_map: Arc>>, @@ -104,6 +106,7 @@ impl EsmLibraryPlugin { Default::default(), Default::default(), Default::default(), + Default::default(), ) } @@ -846,8 +849,11 @@ async fn optimize_dependencies( exports_info_artifact: &mut ExportsInfoArtifact, _diagnostics: &mut Vec, ) -> Result> { - *self.direct_commonjs_external_dependencies.borrow_mut() = - Arc::new(cutout_commonjs_externals(build_module_graph_artifact)); + let direct_dependencies = cutout_commonjs_externals( + build_module_graph_artifact, + &mut self.direct_commonjs_external_connection_states.borrow_mut(), + ); + *self.direct_commonjs_external_dependencies.borrow_mut() = Arc::new(direct_dependencies); cutout_dyn_import_externals( false, compilation.options.output.module, diff --git a/crates/rspack_plugin_externals/src/esm_node_target_plugin.rs b/crates/rspack_plugin_externals/src/esm_node_target_plugin.rs index 952b41b6c23e..c7ae64ba636c 100644 --- a/crates/rspack_plugin_externals/src/esm_node_target_plugin.rs +++ b/crates/rspack_plugin_externals/src/esm_node_target_plugin.rs @@ -42,10 +42,18 @@ async fn after_factorize( let dep = data.dependencies[0] .as_module_dependency() .expect("should be module dependency"); - if matches!( - dep.dependency_type(), - DependencyType::CjsRequire | DependencyType::CjsFullRequire - ) { + let should_downgrade = + matches!( + dep.dependency_type(), + DependencyType::CjsRequire | DependencyType::CjsFullRequire + ) || (matches!(dep.dependency_type(), DependencyType::CjsExportRequire) + && data + .options + .output + .enabled_library_types + .as_ref() + .is_some_and(|types| types.iter().any(|ty| ty == "modern-module"))); + if should_downgrade { external_module.set_external_type("node-commonjs".to_string()); } } diff --git a/crates/rspack_plugin_externals/src/lib.rs b/crates/rspack_plugin_externals/src/lib.rs index 2d170ae268e0..0e24e53acd50 100644 --- a/crates/rspack_plugin_externals/src/lib.rs +++ b/crates/rspack_plugin_externals/src/lib.rs @@ -8,5 +8,6 @@ mod plugin; pub use electron_target_plugin::{ElectronTargetContext, electron_target_plugin}; pub use esm_node_target_plugin::EsmNodeTargetPlugin; pub use http_externals_plugin::{css_http_externals_rspack_plugin, http_externals_rspack_plugin}; +pub use node_builtins::is_node_builtin; pub use node_target_plugin::node_target_plugin; pub use plugin::ExternalsPlugin; diff --git a/tests/rspack-test/configCases/library/modern-module-force-concaten/__snapshot__/f.js.txt b/tests/rspack-test/configCases/library/modern-module-force-concaten/__snapshot__/f.js.txt index 7ff9df5dcf48..7404ab06ffad 100644 --- a/tests/rspack-test/configCases/library/modern-module-force-concaten/__snapshot__/f.js.txt +++ b/tests/rspack-test/configCases/library/modern-module-force-concaten/__snapshot__/f.js.txt @@ -3,12 +3,8 @@ import { __webpack_require__ } from "./runtime~0.js"; import { createRequire as __rspack_createRequire } from "node:module"; const __rspack_createRequire_require = __rspack_createRequire(import.meta.url); __webpack_require__.add({ -928(module) { -module.exports = __rspack_createRequire_require("path"); - -}, -227(module, __unused_rspack_exports, __webpack_require__) { -const path = __webpack_require__(928) +227(module) { +const path = __rspack_createRequire_require("path") module.exports = path.sep diff --git a/tests/rspack-test/configCases/library/modern-module-force-concaten/__snapshot__/runtimeModeSnapshot/f.js.txt b/tests/rspack-test/configCases/library/modern-module-force-concaten/__snapshot__/runtimeModeSnapshot/f.js.txt index d632a10d2ede..3737bc1c99c0 100644 --- a/tests/rspack-test/configCases/library/modern-module-force-concaten/__snapshot__/runtimeModeSnapshot/f.js.txt +++ b/tests/rspack-test/configCases/library/modern-module-force-concaten/__snapshot__/runtimeModeSnapshot/f.js.txt @@ -2,12 +2,8 @@ import { rspackRequire, moduleFactories, compatGetDefaultExport } from "./runtim import { createRequire as __rspack_createRequire } from "node:module"; const __rspack_createRequire_require = __rspack_createRequire(import.meta.url); moduleFactories.add({ -928(module) { -module.exports = __rspack_createRequire_require("path"); - -}, 227(module) { -const path = rspackRequire(928) +const path = __rspack_createRequire_require("path") module.exports = path.sep diff --git a/tests/rspack-test/configCases/library/modern-module-force-concaten/rspack.config.mjs b/tests/rspack-test/configCases/library/modern-module-force-concaten/rspack.config.mjs index 54aac27e4bc7..9754d0e008a9 100644 --- a/tests/rspack-test/configCases/library/modern-module-force-concaten/rspack.config.mjs +++ b/tests/rspack-test/configCases/library/modern-module-force-concaten/rspack.config.mjs @@ -63,7 +63,7 @@ export default { ); expect(assets['f.js']._value).toMatchFileSnapshotSync( path.join(import.meta.dirname, '__snapshot__', 'f.js.txt'), - 'external module should bail out when bundling', + 'CJS module with a direct external should bail out when bundling', ); expect(assets['g.js']._value).toMatchFileSnapshotSync( path.join(import.meta.dirname, '__snapshot__', 'g.js.txt'), diff --git a/tests/rspack-test/esmOutputCases/externals/commonjs-require-conditional/__snapshots__/esm.snap.txt b/tests/rspack-test/esmOutputCases/externals/commonjs-require-conditional/__snapshots__/esm.snap.txt index e69de29bb2d1..1f52d6c07002 100644 --- a/tests/rspack-test/esmOutputCases/externals/commonjs-require-conditional/__snapshots__/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/externals/commonjs-require-conditional/__snapshots__/esm.snap.txt @@ -0,0 +1,137 @@ +```mjs title=runtime.mjs + +var __webpack_modules__ = {}; +// The module cache +var __webpack_module_cache__ = {}; +// The require function +function __webpack_require__(moduleId) { +// Check if module is in cache +var cachedModule = __webpack_module_cache__[moduleId]; +if (cachedModule !== undefined) { +return cachedModule.exports; +} +// Create a new module (and put it into the cache) +var module = (__webpack_module_cache__[moduleId] = { +exports: {} +}); +// Execute the module function +__webpack_modules__[moduleId](module, module.exports, __webpack_require__); + +// Return the exports of the module +return module.exports; +} +// expose the modules object (__webpack_modules__) +__webpack_require__.m = __webpack_modules__; + +// webpack/runtime/esm_register_module +(() => { +__webpack_require__.add = function registerModules(modules) { Object.assign(__webpack_require__.m, modules) } + +})(); + +export { __webpack_require__ }; + +``` + +```mjs title=safe.mjs +import { __webpack_require__ } from "./runtime.mjs"; + +__webpack_require__.add({ +"./safe.cjs" +/*!******************!*\ + !*** ./safe.cjs ***! + \******************/ +(module) { +module.exports = require("external"); + + +}, +}); +// ./entry-safe.js +const external = __webpack_require__(/*! ./safe.cjs */ "./safe.cjs"); + +process.__mixedExternalValues.push(external); + +const value = external.value; + +export { value }; + +``` + +```mjs title=unsafe.mjs +import { __webpack_require__ } from "./runtime.mjs"; + +__webpack_require__.add({ +"./. sync recursive" +/*!****************!*\ + !*** ./.|sync ***! + \****************/ +(module) { +function __rspack_empty_context(req) { + var e = new Error("Cannot find module '" + req + "'"); + e.code = 'MODULE_NOT_FOUND'; + throw e; +} +__rspack_empty_context.keys = () => ([]); +__rspack_empty_context.resolve = __rspack_empty_context; +__rspack_empty_context.id = "./. sync recursive"; +module.exports = __rspack_empty_context; + + +}, +"external" +/*!***************************!*\ + !*** external "external" ***! + \***************************/ +(module) { +module.exports = require("external"); + +}, +"./local.cjs" +/*!*******************!*\ + !*** ./local.cjs ***! + \*******************/ +(__unused_rspack_module, exports) { +exports.value = 7; + + +}, +"./unsafe.cjs" +/*!********************!*\ + !*** ./unsafe.cjs ***! + \********************/ +(module, __unused_rspack_exports, __webpack_require__) { +const selected = __webpack_require__( + globalThis.__USE_EXTERNAL__ ? /*! external */ "external" : /*! ./local.cjs */ "./local.cjs" +); + +const contextual = globalThis.__RUN_DYNAMIC_CONTEXT__ + ? __webpack_require__(/*! . */ "./. sync recursive")(globalThis.__USE_CONTEXT_EXTERNAL__ + ? /*! external */ "external" + : "./" + globalThis.__LOCAL_MODULE__) + : __webpack_require__(/*! ./local.cjs */ "./local.cjs"); + +module.exports = { selected, contextual }; + + +}, +}); +// ./entry-unsafe.js +globalThis.__USE_EXTERNAL__ = true; +globalThis.__RUN_DYNAMIC_CONTEXT__ = false; +globalThis.__USE_CONTEXT_EXTERNAL__ = false; +globalThis.__LOCAL_MODULE__ = "local.cjs"; + +const { selected: selected, contextual: contextual } = __webpack_require__(/*! ./unsafe.cjs */ "./unsafe.cjs"); + +process.__mixedExternalValues.push(selected); + +if (contextual.value !== 7) { + throw new Error("dynamic CommonJS context fallback should keep working"); +} + +const value = selected.value; + +export { value }; + +``` \ No newline at end of file diff --git a/tests/rspack-test/esmOutputCases/externals/commonjs-require-conditional/__snapshots__/runtimeModeSnapshot/esm.snap.txt b/tests/rspack-test/esmOutputCases/externals/commonjs-require-conditional/__snapshots__/runtimeModeSnapshot/esm.snap.txt index e69de29bb2d1..b5bfb4b1adc1 100644 --- a/tests/rspack-test/esmOutputCases/externals/commonjs-require-conditional/__snapshots__/runtimeModeSnapshot/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/externals/commonjs-require-conditional/__snapshots__/runtimeModeSnapshot/esm.snap.txt @@ -0,0 +1,134 @@ +```mjs title=runtime.mjs + +var modules = {}; +// The module cache +var moduleCache = {}; +// The require function +function rspackRequire(moduleId) { +// Check if module is in cache +var cachedModule = moduleCache[moduleId]; +if (cachedModule !== undefined) { +return cachedModule.exports; +} +// Create a new module (and put it into the cache) +var module = (moduleCache[moduleId] = { +exports: {} +}); +// Execute the module function +modules[moduleId](module, module.exports, rspackRequire); + +// Return the exports of the module +return module.exports; +} +export { rspackRequire }; +// expose the modules object (modules) +var moduleFactories = modules; +export { moduleFactories }; + +// rspack/runtime/esm_register_module +moduleFactories.add = function registerModules(modules) { Object.assign(moduleFactories, modules) } +; + + +``` + +```mjs title=safe.mjs +import { rspackRequire, moduleFactories } from "./runtime.mjs"; +moduleFactories.add({ +"./safe.cjs" +/*!******************!*\ + !*** ./safe.cjs ***! + \******************/ +(module) { +module.exports = require("external"); + + +}, +}); +// ./entry-safe.js +const external = rspackRequire(/*! ./safe.cjs */ "./safe.cjs"); + +process.__mixedExternalValues.push(external); + +const value = external.value; + +export { value }; + +``` + +```mjs title=unsafe.mjs +import { rspackRequire, moduleFactories } from "./runtime.mjs"; +moduleFactories.add({ +"./. sync recursive" +/*!****************!*\ + !*** ./.|sync ***! + \****************/ +(module) { +function __rspack_empty_context(req) { + var e = new Error("Cannot find module '" + req + "'"); + e.code = 'MODULE_NOT_FOUND'; + throw e; +} +__rspack_empty_context.keys = () => ([]); +__rspack_empty_context.resolve = __rspack_empty_context; +__rspack_empty_context.id = "./. sync recursive"; +module.exports = __rspack_empty_context; + + +}, +"external" +/*!***************************!*\ + !*** external "external" ***! + \***************************/ +(module) { +module.exports = require("external"); + +}, +"./local.cjs" +/*!*******************!*\ + !*** ./local.cjs ***! + \*******************/ +(__unused_rspack_module, exports) { +exports.value = 7; + + +}, +"./unsafe.cjs" +/*!********************!*\ + !*** ./unsafe.cjs ***! + \********************/ +(module) { +const selected = rspackRequire( + globalThis.__USE_EXTERNAL__ ? /*! external */ "external" : /*! ./local.cjs */ "./local.cjs" +); + +const contextual = globalThis.__RUN_DYNAMIC_CONTEXT__ + ? rspackRequire(/*! . */ "./. sync recursive")(globalThis.__USE_CONTEXT_EXTERNAL__ + ? /*! external */ "external" + : "./" + globalThis.__LOCAL_MODULE__) + : rspackRequire(/*! ./local.cjs */ "./local.cjs"); + +module.exports = { selected, contextual }; + + +}, +}); +// ./entry-unsafe.js +globalThis.__USE_EXTERNAL__ = true; +globalThis.__RUN_DYNAMIC_CONTEXT__ = false; +globalThis.__USE_CONTEXT_EXTERNAL__ = false; +globalThis.__LOCAL_MODULE__ = "local.cjs"; + +const { selected: selected, contextual: contextual } = rspackRequire(/*! ./unsafe.cjs */ "./unsafe.cjs"); + +process.__mixedExternalValues.push(selected); + +if (contextual.value !== 7) { + throw new Error("dynamic CommonJS context fallback should keep working"); +} + +const value = selected.value; + +export { value }; + +``` \ No newline at end of file diff --git a/tests/rspack-test/esmOutputCases/externals/commonjs-require-conditional/entry-safe.js b/tests/rspack-test/esmOutputCases/externals/commonjs-require-conditional/entry-safe.js new file mode 100644 index 000000000000..102124d4aa09 --- /dev/null +++ b/tests/rspack-test/esmOutputCases/externals/commonjs-require-conditional/entry-safe.js @@ -0,0 +1,5 @@ +const external = require("./safe.cjs"); + +process.__mixedExternalValues.push(external); + +export const value = external.value; diff --git a/tests/rspack-test/esmOutputCases/externals/commonjs-require-conditional/entry-unsafe.js b/tests/rspack-test/esmOutputCases/externals/commonjs-require-conditional/entry-unsafe.js new file mode 100644 index 000000000000..b85d2f76f8f7 --- /dev/null +++ b/tests/rspack-test/esmOutputCases/externals/commonjs-require-conditional/entry-unsafe.js @@ -0,0 +1,14 @@ +globalThis.__USE_EXTERNAL__ = true; +globalThis.__RUN_DYNAMIC_CONTEXT__ = false; +globalThis.__USE_CONTEXT_EXTERNAL__ = false; +globalThis.__LOCAL_MODULE__ = "local.cjs"; + +const { selected, contextual } = require("./unsafe.cjs"); + +process.__mixedExternalValues.push(selected); + +if (contextual.value !== 7) { + throw new Error("dynamic CommonJS context fallback should keep working"); +} + +export const value = selected.value; diff --git a/tests/rspack-test/esmOutputCases/externals/commonjs-require-conditional/index.js b/tests/rspack-test/esmOutputCases/externals/commonjs-require-conditional/index.js deleted file mode 100644 index 542027def77f..000000000000 --- a/tests/rspack-test/esmOutputCases/externals/commonjs-require-conditional/index.js +++ /dev/null @@ -1,11 +0,0 @@ -const selected = require( - globalThis.__USE_EXTERNAL_OS__ ? "external-os" : "./local.cjs" -); -const mixed = require( - globalThis.__USE_EXTERNAL_OS__ - ? "external-os" - : "./" + globalThis.__LOCAL_MODULE__ -); - -export const platform = selected.platform(); -export const mixedPlatform = mixed.platform; diff --git a/tests/rspack-test/esmOutputCases/externals/commonjs-require-conditional/local.cjs b/tests/rspack-test/esmOutputCases/externals/commonjs-require-conditional/local.cjs index cdec022116d6..2558e07312c3 100644 --- a/tests/rspack-test/esmOutputCases/externals/commonjs-require-conditional/local.cjs +++ b/tests/rspack-test/esmOutputCases/externals/commonjs-require-conditional/local.cjs @@ -1 +1 @@ -exports.platform = () => "local"; +exports.value = 7; diff --git a/tests/rspack-test/esmOutputCases/externals/commonjs-require-conditional/node_modules/external/index.js b/tests/rspack-test/esmOutputCases/externals/commonjs-require-conditional/node_modules/external/index.js new file mode 100644 index 000000000000..f69bfa0174ae --- /dev/null +++ b/tests/rspack-test/esmOutputCases/externals/commonjs-require-conditional/node_modules/external/index.js @@ -0,0 +1,5 @@ +process.__mixedExternalLoadCount++; + +module.exports = { + value: 42 +}; diff --git a/tests/rspack-test/esmOutputCases/externals/commonjs-require-conditional/node_modules/external/package.json b/tests/rspack-test/esmOutputCases/externals/commonjs-require-conditional/node_modules/external/package.json new file mode 100644 index 000000000000..a9e27c9a5823 --- /dev/null +++ b/tests/rspack-test/esmOutputCases/externals/commonjs-require-conditional/node_modules/external/package.json @@ -0,0 +1,5 @@ +{ + "name": "external", + "version": "1.0.0", + "main": "index.js" +} diff --git a/tests/rspack-test/esmOutputCases/externals/commonjs-require-conditional/rspack.config.js b/tests/rspack-test/esmOutputCases/externals/commonjs-require-conditional/rspack.config.js index 003601ecdc23..38e1add730dc 100644 --- a/tests/rspack-test/esmOutputCases/externals/commonjs-require-conditional/rspack.config.js +++ b/tests/rspack-test/esmOutputCases/externals/commonjs-require-conditional/rspack.config.js @@ -1,6 +1,9 @@ module.exports = { - externalsType: 'modern-module', + entry: { + safe: './entry-safe.js', + unsafe: './entry-unsafe.js', + }, externals: { - 'external-os': 'os', + external: 'commonjs external', }, }; diff --git a/tests/rspack-test/esmOutputCases/externals/commonjs-require-direct/reexport.cjs b/tests/rspack-test/esmOutputCases/externals/commonjs-require-conditional/safe.cjs similarity index 100% rename from tests/rspack-test/esmOutputCases/externals/commonjs-require-direct/reexport.cjs rename to tests/rspack-test/esmOutputCases/externals/commonjs-require-conditional/safe.cjs diff --git a/tests/rspack-test/esmOutputCases/externals/commonjs-require-conditional/test.config.js b/tests/rspack-test/esmOutputCases/externals/commonjs-require-conditional/test.config.js index 2383cefeb8a5..d2acaeb854a9 100644 --- a/tests/rspack-test/esmOutputCases/externals/commonjs-require-conditional/test.config.js +++ b/tests/rspack-test/esmOutputCases/externals/commonjs-require-conditional/test.config.js @@ -1,27 +1,80 @@ const fs = require("fs"); const path = require("path"); +const { execFileSync } = require("child_process"); +const { createRequire } = require("module"); +const { pathToFileURL } = require("url"); -function readOutput(options) { - return fs - .readdirSync(options.output.path) - .filter(file => file.endsWith(".mjs")) - .map(file => fs.readFileSync(path.join(options.output.path, file), "utf-8")) - .join("\n"); +function runtimeRequire() { + return createRequire(path.join(__dirname, "__external_runtime__.cjs")); +} + +function readOutput(options, file) { + return fs.readFileSync(path.join(options.output.path, file), "utf-8"); } module.exports = { + beforeExecute() { + const require = runtimeRequire(); + delete require.cache[require.resolve("external")]; + process.__mixedExternalLoadCount = 0; + process.__mixedExternalValues = []; + }, findBundle() { - return []; + return ["safe.mjs", "unsafe.mjs"]; }, - snapshotFileFilter() { - return false; + moduleScope(scope) { + scope.require = runtimeRequire(); }, afterExecute(options) { - const source = readOutput(options); + const safe = readOutput(options, "safe.mjs"); + const unsafe = readOutput(options, "unsafe.mjs"); + const source = `${safe}\n${unsafe}`; - expect(source).toContain('external "os"'); - expect(source).toMatch( - /(?:__webpack_require__|__rspack_context\.r)\s*\(/ + expect(safe).toMatch( + /module\.exports\s*=\s*require\s*\(\s*["']external["']\s*\)/ ); + expect(safe).not.toContain('external "external"'); + expect(unsafe).toContain('external "external"'); + expect(unsafe).toMatch( + /(?:__webpack_require__|__rspack_context\.r|rspackRequire)\s*\(\s*[^)]*["']external["']/ + ); + expect(source.match(/external "external"/g)).toHaveLength(1); + + expect(process.__mixedExternalLoadCount).toBe(1); + expect(process.__mixedExternalValues).toHaveLength(2); + expect(process.__mixedExternalValues[0]).toBe( + process.__mixedExternalValues[1] + ); + + const requireBase = path.join(__dirname, "__external_runtime__.cjs"); + const safeUrl = pathToFileURL(path.join(options.output.path, "safe.mjs")).href; + const unsafeUrl = pathToFileURL( + path.join(options.output.path, "unsafe.mjs") + ).href; + const reverseOrderScript = ` + import { createRequire } from "node:module"; + globalThis.require = createRequire(${JSON.stringify(requireBase)}); + process.__mixedExternalLoadCount = 0; + process.__mixedExternalValues = []; + await import(${JSON.stringify(unsafeUrl)}); + await import(${JSON.stringify(safeUrl)}); + if ( + process.__mixedExternalLoadCount !== 1 || + process.__mixedExternalValues.length !== 2 || + process.__mixedExternalValues[0] !== process.__mixedExternalValues[1] + ) { + throw new Error("mixed direct and wrapped external should share identity"); + } + `; + execFileSync( + process.execPath, + ["--input-type=module", "--eval", reverseOrderScript], + { stdio: "pipe" } + ); + + const require = runtimeRequire(); + delete require.cache[require.resolve("external")]; + delete process.__mixedExternalLoadCount; + delete process.__mixedExternalValues; } }; diff --git a/tests/rspack-test/esmOutputCases/externals/commonjs-require-conditional/unsafe.cjs b/tests/rspack-test/esmOutputCases/externals/commonjs-require-conditional/unsafe.cjs new file mode 100644 index 000000000000..5f535474cdee --- /dev/null +++ b/tests/rspack-test/esmOutputCases/externals/commonjs-require-conditional/unsafe.cjs @@ -0,0 +1,13 @@ +const selected = require( + globalThis.__USE_EXTERNAL__ ? "external" : "./local.cjs" +); + +const contextual = globalThis.__RUN_DYNAMIC_CONTEXT__ + ? require( + globalThis.__USE_CONTEXT_EXTERNAL__ + ? "external" + : "./" + globalThis.__LOCAL_MODULE__ + ) + : require("./local.cjs"); + +module.exports = { selected, contextual }; diff --git a/tests/rspack-test/esmOutputCases/externals/commonjs-require-direct/__snapshots__/esm.snap.txt b/tests/rspack-test/esmOutputCases/externals/commonjs-require-direct/__snapshots__/esm.snap.txt index e69de29bb2d1..14cc8b0ef160 100644 --- a/tests/rspack-test/esmOutputCases/externals/commonjs-require-direct/__snapshots__/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/externals/commonjs-require-direct/__snapshots__/esm.snap.txt @@ -0,0 +1,111 @@ +```mjs title=entry-a.mjs +import { __webpack_require__ } from "./runtime.mjs"; + +__webpack_require__.add({ +"./consumer-a.cjs" +/*!************************!*\ + !*** ./consumer-a.cjs ***! + \************************/ +(__unused_rspack_module, exports) { +const first = require("external"); +const second = require("external"); +const viaModuleRequire = require("external"); +const constructed = new require("external"); +const { value } = require("external"); + +exports.first = first; +exports.second = second; +exports.viaModuleRequire = viaModuleRequire; +exports.constructed = constructed; +exports.destructured = value; +exports.method = (require("external").getValue)(); +exports.named = require("external"); +this.fromThis = require("external").value; + + +}, +}); +// ./entry-a.js +const consumer = __webpack_require__(/*! ./consumer-a.cjs */ "./consumer-a.cjs"); + +process.__commonjsExternalValues.push( + consumer.first, + consumer.second, + consumer.named, + consumer.viaModuleRequire, + consumer.constructed +); + +if ( + consumer.method !== 42 || + consumer.fromThis !== 42 || + consumer.destructured !== 42 +) { + throw new Error("direct CommonJS external member access should preserve semantics"); +} + +const value = consumer.first.value; + +export { value }; + +``` + +```mjs title=entry-b.mjs +import { __webpack_require__ } from "./runtime.mjs"; + +__webpack_require__.add({ +"./consumer-b.cjs" +/*!************************!*\ + !*** ./consumer-b.cjs ***! + \************************/ +(module) { +module.exports = require("external"); + + +}, +}); +// ./entry-b.js +const consumer = __webpack_require__(/*! ./consumer-b.cjs */ "./consumer-b.cjs"); + +process.__commonjsExternalValues.push(consumer); + +const value = consumer.value; + +export { value }; + +``` + +```mjs title=runtime.mjs + +var __webpack_modules__ = {}; +// The module cache +var __webpack_module_cache__ = {}; +// The require function +function __webpack_require__(moduleId) { +// Check if module is in cache +var cachedModule = __webpack_module_cache__[moduleId]; +if (cachedModule !== undefined) { +return cachedModule.exports; +} +// Create a new module (and put it into the cache) +var module = (__webpack_module_cache__[moduleId] = { +exports: {} +}); +// Execute the module function +__webpack_modules__[moduleId].call(module.exports, module, module.exports, __webpack_require__); + +// Return the exports of the module +return module.exports; +} +// expose the modules object (__webpack_modules__) +__webpack_require__.m = __webpack_modules__; + +// webpack/runtime/esm_register_module +(() => { +__webpack_require__.add = function registerModules(modules) { Object.assign(__webpack_require__.m, modules) } + +})(); + +export { __webpack_require__ }; + +``` \ No newline at end of file diff --git a/tests/rspack-test/esmOutputCases/externals/commonjs-require-direct/__snapshots__/runtimeModeSnapshot/esm.snap.txt b/tests/rspack-test/esmOutputCases/externals/commonjs-require-direct/__snapshots__/runtimeModeSnapshot/esm.snap.txt index e69de29bb2d1..abf41c56a9d0 100644 --- a/tests/rspack-test/esmOutputCases/externals/commonjs-require-direct/__snapshots__/runtimeModeSnapshot/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/externals/commonjs-require-direct/__snapshots__/runtimeModeSnapshot/esm.snap.txt @@ -0,0 +1,108 @@ +```mjs title=entry-a.mjs +import { rspackRequire, moduleFactories } from "./runtime.mjs"; +moduleFactories.add({ +"./consumer-a.cjs" +/*!************************!*\ + !*** ./consumer-a.cjs ***! + \************************/ +(__unused_rspack_module, exports) { +const first = require("external"); +const second = require("external"); +const viaModuleRequire = require("external"); +const constructed = new require("external"); +const { value } = require("external"); + +exports.first = first; +exports.second = second; +exports.viaModuleRequire = viaModuleRequire; +exports.constructed = constructed; +exports.destructured = value; +exports.method = (require("external").getValue)(); +exports.named = require("external"); +this.fromThis = require("external").value; + + +}, +}); +// ./entry-a.js +const consumer = rspackRequire(/*! ./consumer-a.cjs */ "./consumer-a.cjs"); + +process.__commonjsExternalValues.push( + consumer.first, + consumer.second, + consumer.named, + consumer.viaModuleRequire, + consumer.constructed +); + +if ( + consumer.method !== 42 || + consumer.fromThis !== 42 || + consumer.destructured !== 42 +) { + throw new Error("direct CommonJS external member access should preserve semantics"); +} + +const value = consumer.first.value; + +export { value }; + +``` + +```mjs title=entry-b.mjs +import { rspackRequire, moduleFactories } from "./runtime.mjs"; +moduleFactories.add({ +"./consumer-b.cjs" +/*!************************!*\ + !*** ./consumer-b.cjs ***! + \************************/ +(module) { +module.exports = require("external"); + + +}, +}); +// ./entry-b.js +const consumer = rspackRequire(/*! ./consumer-b.cjs */ "./consumer-b.cjs"); + +process.__commonjsExternalValues.push(consumer); + +const value = consumer.value; + +export { value }; + +``` + +```mjs title=runtime.mjs + +var modules = {}; +// The module cache +var moduleCache = {}; +// The require function +function rspackRequire(moduleId) { +// Check if module is in cache +var cachedModule = moduleCache[moduleId]; +if (cachedModule !== undefined) { +return cachedModule.exports; +} +// Create a new module (and put it into the cache) +var module = (moduleCache[moduleId] = { +exports: {} +}); +// Execute the module function +modules[moduleId].call(module.exports, module, module.exports, rspackRequire); + +// Return the exports of the module +return module.exports; +} +export { rspackRequire }; +// expose the modules object (modules) +var moduleFactories = modules; +export { moduleFactories }; + +// rspack/runtime/esm_register_module +moduleFactories.add = function registerModules(modules) { Object.assign(moduleFactories, modules) } +; + + +``` \ No newline at end of file diff --git a/tests/rspack-test/esmOutputCases/externals/commonjs-require-direct/consumer-a.cjs b/tests/rspack-test/esmOutputCases/externals/commonjs-require-direct/consumer-a.cjs new file mode 100644 index 000000000000..1aec7a56d131 --- /dev/null +++ b/tests/rspack-test/esmOutputCases/externals/commonjs-require-direct/consumer-a.cjs @@ -0,0 +1,14 @@ +const first = require("external"); +const second = require("external"); +const viaModuleRequire = module.require("external"); +const constructed = new require("external"); +const { value } = require("external"); + +exports.first = first; +exports.second = second; +exports.viaModuleRequire = viaModuleRequire; +exports.constructed = constructed; +exports.destructured = value; +exports.method = require("external").getValue(); +exports.named = require("external"); +this.fromThis = require("external").value; diff --git a/tests/rspack-test/esmOutputCases/externals/commonjs-require-direct/consumer-b.cjs b/tests/rspack-test/esmOutputCases/externals/commonjs-require-direct/consumer-b.cjs new file mode 100644 index 000000000000..0f9cd4f1c1df --- /dev/null +++ b/tests/rspack-test/esmOutputCases/externals/commonjs-require-direct/consumer-b.cjs @@ -0,0 +1 @@ +module.exports = require("external"); diff --git a/tests/rspack-test/esmOutputCases/externals/commonjs-require-direct/entry-a.js b/tests/rspack-test/esmOutputCases/externals/commonjs-require-direct/entry-a.js new file mode 100644 index 000000000000..9897a8da8b88 --- /dev/null +++ b/tests/rspack-test/esmOutputCases/externals/commonjs-require-direct/entry-a.js @@ -0,0 +1,19 @@ +const consumer = require("./consumer-a.cjs"); + +process.__commonjsExternalValues.push( + consumer.first, + consumer.second, + consumer.named, + consumer.viaModuleRequire, + consumer.constructed +); + +if ( + consumer.method !== 42 || + consumer.fromThis !== 42 || + consumer.destructured !== 42 +) { + throw new Error("direct CommonJS external member access should preserve semantics"); +} + +export const value = consumer.first.value; diff --git a/tests/rspack-test/esmOutputCases/externals/commonjs-require-direct/entry-b.js b/tests/rspack-test/esmOutputCases/externals/commonjs-require-direct/entry-b.js new file mode 100644 index 000000000000..c3b30354442d --- /dev/null +++ b/tests/rspack-test/esmOutputCases/externals/commonjs-require-direct/entry-b.js @@ -0,0 +1,5 @@ +const consumer = require("./consumer-b.cjs"); + +process.__commonjsExternalValues.push(consumer); + +export const value = consumer.value; diff --git a/tests/rspack-test/esmOutputCases/externals/commonjs-require-direct/index.js b/tests/rspack-test/esmOutputCases/externals/commonjs-require-direct/index.js deleted file mode 100644 index 93d724dbee6b..000000000000 --- a/tests/rspack-test/esmOutputCases/externals/commonjs-require-direct/index.js +++ /dev/null @@ -1,4 +0,0 @@ -const external = require("external"); -const reexported = require("./reexport.cjs"); - -export const value = external.value + reexported.value; diff --git a/tests/rspack-test/esmOutputCases/externals/commonjs-require-direct/node_modules/external/index.js b/tests/rspack-test/esmOutputCases/externals/commonjs-require-direct/node_modules/external/index.js new file mode 100644 index 000000000000..4f69bae222cb --- /dev/null +++ b/tests/rspack-test/esmOutputCases/externals/commonjs-require-direct/node_modules/external/index.js @@ -0,0 +1,8 @@ +process.__commonjsExternalLoadCount++; + +module.exports = { + value: 42, + getValue() { + return this.value; + } +}; diff --git a/tests/rspack-test/esmOutputCases/externals/commonjs-require-direct/node_modules/external/package.json b/tests/rspack-test/esmOutputCases/externals/commonjs-require-direct/node_modules/external/package.json new file mode 100644 index 000000000000..a9e27c9a5823 --- /dev/null +++ b/tests/rspack-test/esmOutputCases/externals/commonjs-require-direct/node_modules/external/package.json @@ -0,0 +1,5 @@ +{ + "name": "external", + "version": "1.0.0", + "main": "index.js" +} diff --git a/tests/rspack-test/esmOutputCases/externals/commonjs-require-direct/rspack.config.js b/tests/rspack-test/esmOutputCases/externals/commonjs-require-direct/rspack.config.js index 0bbeab3fab92..4195aa4e7fb3 100644 --- a/tests/rspack-test/esmOutputCases/externals/commonjs-require-direct/rspack.config.js +++ b/tests/rspack-test/esmOutputCases/externals/commonjs-require-direct/rspack.config.js @@ -1,4 +1,8 @@ module.exports = { + entry: { + 'entry-a': './entry-a.js', + 'entry-b': './entry-b.js', + }, externals: { external: 'commonjs external', }, diff --git a/tests/rspack-test/esmOutputCases/externals/commonjs-require-direct/test.config.js b/tests/rspack-test/esmOutputCases/externals/commonjs-require-direct/test.config.js index 08174bcd7c65..f40715c8978c 100644 --- a/tests/rspack-test/esmOutputCases/externals/commonjs-require-direct/test.config.js +++ b/tests/rspack-test/esmOutputCases/externals/commonjs-require-direct/test.config.js @@ -1,33 +1,83 @@ const fs = require("fs"); const path = require("path"); +const { execFileSync } = require("child_process"); +const { createRequire } = require("module"); +const { pathToFileURL } = require("url"); -function readOutput(options) { - return fs - .readdirSync(options.output.path) - .filter(file => file.endsWith(".mjs")) - .map(file => fs.readFileSync(path.join(options.output.path, file), "utf-8")) - .join("\n"); +function runtimeRequire() { + return createRequire(path.join(__dirname, "__external_runtime__.cjs")); +} + +function readOutput(options, file) { + return fs.readFileSync(path.join(options.output.path, file), "utf-8"); } module.exports = { + beforeExecute() { + const require = runtimeRequire(); + delete require.cache[require.resolve("external")]; + process.__commonjsExternalLoadCount = 0; + process.__commonjsExternalValues = []; + }, findBundle() { - return []; + return ["entry-a.mjs", "entry-b.mjs"]; }, - snapshotFileFilter() { - return false; + moduleScope(scope) { + scope.require = runtimeRequire(); }, afterExecute(options) { - const source = readOutput(options); + const entryA = readOutput(options, "entry-a.mjs"); + const entryB = readOutput(options, "entry-b.mjs"); + const source = `${entryA}\n${entryB}`; - expect(source).toMatch( - /const\s+external\s*=\s*require\s*\(\s*["']external["']\s*\)/ + expect(entryA).toMatch( + /const\s+first\s*=\s*require\s*\(\s*["']external["']\s*\)/ ); - expect(source).toMatch( + expect(entryB).toMatch( /module\.exports\s*=\s*require\s*\(\s*["']external["']\s*\)/ ); expect(source).not.toContain('external "external"'); expect(source).not.toMatch( - /(?:__webpack_require__|__rspack_context\.r)\s*\(\s*[^)]*["']external["']/ + /(?:__webpack_require__|__rspack_context\.r|rspackRequire)\s*\(\s*[^)]*["']external["']/ ); + + expect(process.__commonjsExternalLoadCount).toBe(1); + expect(process.__commonjsExternalValues).toHaveLength(6); + for (const value of process.__commonjsExternalValues) { + expect(value).toBe(process.__commonjsExternalValues[0]); + } + + const requireBase = path.join(__dirname, "__external_runtime__.cjs"); + const entryAUrl = pathToFileURL(path.join(options.output.path, "entry-a.mjs")).href; + const entryBUrl = pathToFileURL(path.join(options.output.path, "entry-b.mjs")).href; + const reverseOrderScript = ` + import { createRequire } from "node:module"; + globalThis.require = createRequire(${JSON.stringify(requireBase)}); + process.__commonjsExternalLoadCount = 0; + process.__commonjsExternalValues = []; + await import(${JSON.stringify(entryBUrl)}); + await import(${JSON.stringify(entryAUrl)}); + if (process.__commonjsExternalLoadCount !== 1) { + throw new Error("external should initialize once in reverse entry order"); + } + if ( + process.__commonjsExternalValues.length !== 6 || + !process.__commonjsExternalValues.every( + value => value === process.__commonjsExternalValues[0] + ) + ) { + throw new Error("external identity should be shared in reverse entry order"); + } + `; + execFileSync( + process.execPath, + ["--input-type=module", "--eval", reverseOrderScript], + { stdio: "pipe" } + ); + + const require = runtimeRequire(); + delete require.cache[require.resolve("external")]; + delete process.__commonjsExternalLoadCount; + delete process.__commonjsExternalValues; } }; diff --git a/tests/rspack-test/esmOutputCases/externals/commonjs-require-optional/__snapshots__/esm.snap.txt b/tests/rspack-test/esmOutputCases/externals/commonjs-require-optional/__snapshots__/esm.snap.txt new file mode 100644 index 000000000000..8f345a4219c1 --- /dev/null +++ b/tests/rspack-test/esmOutputCases/externals/commonjs-require-optional/__snapshots__/esm.snap.txt @@ -0,0 +1,82 @@ +```mjs title=main.mjs +import { __webpack_require__ } from "./runtime.mjs"; + +__webpack_require__.add({ +"missing-external" +/*!***********************************!*\ + !*** external "missing-external" ***! + \***********************************/ +(module) { +module.exports = require("missing-external"); + +}, +"optional-external" +/*!************************************!*\ + !*** external "optional-external" ***! + \************************************/ +(module) { +module.exports = require("optional-external"); + +}, +}); +// ./index.js +let value; +let missing; + +try { + value = (__webpack_require__(/*! optional-external */ "optional-external")/* .value */.value); +} catch { + value = -1; +} + +try { + __webpack_require__(/*! missing-external */ "missing-external"); + missing = false; +} catch { + missing = true; +} + +if (value !== 42 || !missing) { + throw new Error("optional external should keep working through the wrapper path"); +} + + + +export { missing, value }; + +``` + +```mjs title=runtime.mjs + +var __webpack_modules__ = {}; +// The module cache +var __webpack_module_cache__ = {}; +// The require function +function __webpack_require__(moduleId) { +// Check if module is in cache +var cachedModule = __webpack_module_cache__[moduleId]; +if (cachedModule !== undefined) { +return cachedModule.exports; +} +// Create a new module (and put it into the cache) +var module = (__webpack_module_cache__[moduleId] = { +exports: {} +}); +// Execute the module function +__webpack_modules__[moduleId](module, module.exports, __webpack_require__); + +// Return the exports of the module +return module.exports; +} +// expose the modules object (__webpack_modules__) +__webpack_require__.m = __webpack_modules__; + +// webpack/runtime/esm_register_module +(() => { +__webpack_require__.add = function registerModules(modules) { Object.assign(__webpack_require__.m, modules) } + +})(); + +export { __webpack_require__ }; + +``` \ No newline at end of file diff --git a/tests/rspack-test/esmOutputCases/externals/commonjs-require-optional/__snapshots__/runtimeModeSnapshot/esm.snap.txt b/tests/rspack-test/esmOutputCases/externals/commonjs-require-optional/__snapshots__/runtimeModeSnapshot/esm.snap.txt new file mode 100644 index 000000000000..9ac1eb7d6fec --- /dev/null +++ b/tests/rspack-test/esmOutputCases/externals/commonjs-require-optional/__snapshots__/runtimeModeSnapshot/esm.snap.txt @@ -0,0 +1,80 @@ +```mjs title=main.mjs +import { rspackRequire, moduleFactories } from "./runtime.mjs"; +moduleFactories.add({ +"missing-external" +/*!***********************************!*\ + !*** external "missing-external" ***! + \***********************************/ +(module) { +module.exports = require("missing-external"); + +}, +"optional-external" +/*!************************************!*\ + !*** external "optional-external" ***! + \************************************/ +(module) { +module.exports = require("optional-external"); + +}, +}); +// ./index.js +let value; +let missing; + +try { + value = (rspackRequire(/*! optional-external */ "optional-external")/* .value */.value); +} catch { + value = -1; +} + +try { + rspackRequire(/*! missing-external */ "missing-external"); + missing = false; +} catch { + missing = true; +} + +if (value !== 42 || !missing) { + throw new Error("optional external should keep working through the wrapper path"); +} + + + +export { missing, value }; + +``` + +```mjs title=runtime.mjs + +var modules = {}; +// The module cache +var moduleCache = {}; +// The require function +function rspackRequire(moduleId) { +// Check if module is in cache +var cachedModule = moduleCache[moduleId]; +if (cachedModule !== undefined) { +return cachedModule.exports; +} +// Create a new module (and put it into the cache) +var module = (moduleCache[moduleId] = { +exports: {} +}); +// Execute the module function +modules[moduleId](module, module.exports, rspackRequire); + +// Return the exports of the module +return module.exports; +} +export { rspackRequire }; +// expose the modules object (modules) +var moduleFactories = modules; +export { moduleFactories }; + +// rspack/runtime/esm_register_module +moduleFactories.add = function registerModules(modules) { Object.assign(moduleFactories, modules) } +; + + +``` \ No newline at end of file diff --git a/tests/rspack-test/esmOutputCases/externals/commonjs-require-optional/index.js b/tests/rspack-test/esmOutputCases/externals/commonjs-require-optional/index.js new file mode 100644 index 000000000000..59bf15e3794e --- /dev/null +++ b/tests/rspack-test/esmOutputCases/externals/commonjs-require-optional/index.js @@ -0,0 +1,21 @@ +let value; +let missing; + +try { + value = require("optional-external").value; +} catch { + value = -1; +} + +try { + require("missing-external"); + missing = false; +} catch { + missing = true; +} + +if (value !== 42 || !missing) { + throw new Error("optional external should keep working through the wrapper path"); +} + +export { value, missing }; diff --git a/tests/rspack-test/esmOutputCases/externals/commonjs-require-optional/node_modules/optional-external/index.js b/tests/rspack-test/esmOutputCases/externals/commonjs-require-optional/node_modules/optional-external/index.js new file mode 100644 index 000000000000..885c586e241b --- /dev/null +++ b/tests/rspack-test/esmOutputCases/externals/commonjs-require-optional/node_modules/optional-external/index.js @@ -0,0 +1,3 @@ +module.exports = { + value: 42 +}; diff --git a/tests/rspack-test/esmOutputCases/externals/commonjs-require-optional/node_modules/optional-external/package.json b/tests/rspack-test/esmOutputCases/externals/commonjs-require-optional/node_modules/optional-external/package.json new file mode 100644 index 000000000000..7a5aa5d008ab --- /dev/null +++ b/tests/rspack-test/esmOutputCases/externals/commonjs-require-optional/node_modules/optional-external/package.json @@ -0,0 +1,5 @@ +{ + "name": "optional-external", + "version": "1.0.0", + "main": "index.js" +} diff --git a/tests/rspack-test/esmOutputCases/externals/commonjs-require-optional/rspack.config.js b/tests/rspack-test/esmOutputCases/externals/commonjs-require-optional/rspack.config.js new file mode 100644 index 000000000000..ed631916d779 --- /dev/null +++ b/tests/rspack-test/esmOutputCases/externals/commonjs-require-optional/rspack.config.js @@ -0,0 +1,6 @@ +module.exports = { + externals: { + 'optional-external': 'commonjs optional-external', + 'missing-external': 'commonjs missing-external', + }, +}; diff --git a/tests/rspack-test/esmOutputCases/externals/commonjs-require-optional/test.config.js b/tests/rspack-test/esmOutputCases/externals/commonjs-require-optional/test.config.js new file mode 100644 index 000000000000..f6cd522e1fee --- /dev/null +++ b/tests/rspack-test/esmOutputCases/externals/commonjs-require-optional/test.config.js @@ -0,0 +1,38 @@ +const fs = require("fs"); +const path = require("path"); +const { createRequire } = require("module"); + +function runtimeRequire() { + return createRequire(path.join(__dirname, "__external_runtime__.cjs")); +} + +module.exports = { + beforeExecute() { + const require = runtimeRequire(); + delete require.cache[require.resolve("optional-external")]; + }, + moduleScope(scope) { + scope.require = runtimeRequire(); + }, + afterExecute(options) { + const source = fs.readFileSync( + path.join(options.output.path, "main.mjs"), + "utf-8" + ); + + expect(source).toContain('external "optional-external"'); + expect(source).toContain('external "missing-external"'); + expect(source).toMatch( + /(?:__webpack_require__|__rspack_context\.r|rspackRequire)\s*\(\s*[^)]*["']optional-external["']/ + ); + expect(source).toMatch( + /(?:__webpack_require__|__rspack_context\.r|rspackRequire)\s*\(\s*[^)]*["']missing-external["']/ + ); + expect(source).not.toMatch( + /value\s*=\s*require\s*\(\s*["']optional-external["']\s*\)/ + ); + + const require = runtimeRequire(); + delete require.cache[require.resolve("optional-external")]; + } +}; diff --git a/tests/rspack-test/esmOutputCases/externals/commonjs-require-request-rest/__snapshots__/esm.snap.txt b/tests/rspack-test/esmOutputCases/externals/commonjs-require-request-rest/__snapshots__/esm.snap.txt new file mode 100644 index 000000000000..e3cdf01d6bf4 --- /dev/null +++ b/tests/rspack-test/esmOutputCases/externals/commonjs-require-request-rest/__snapshots__/esm.snap.txt @@ -0,0 +1,60 @@ +```mjs title=main.mjs +import { __webpack_require__ } from "./runtime.mjs"; + +__webpack_require__.add({ +"external-value" +/*!*************************************!*\ + !*** external ["external","value"] ***! + \*************************************/ +(module) { +module.exports = require("external").value; + +}, +}); +// ./index.js +const value = __webpack_require__(/*! external-value */ "external-value"); + +if (value !== 42) { + throw new Error("external request rest segments should keep their wrapper semantics"); +} + + + +export { value }; + +``` + +```mjs title=runtime.mjs + +var __webpack_modules__ = {}; +// The module cache +var __webpack_module_cache__ = {}; +// The require function +function __webpack_require__(moduleId) { +// Check if module is in cache +var cachedModule = __webpack_module_cache__[moduleId]; +if (cachedModule !== undefined) { +return cachedModule.exports; +} +// Create a new module (and put it into the cache) +var module = (__webpack_module_cache__[moduleId] = { +exports: {} +}); +// Execute the module function +__webpack_modules__[moduleId](module, module.exports, __webpack_require__); + +// Return the exports of the module +return module.exports; +} +// expose the modules object (__webpack_modules__) +__webpack_require__.m = __webpack_modules__; + +// webpack/runtime/esm_register_module +(() => { +__webpack_require__.add = function registerModules(modules) { Object.assign(__webpack_require__.m, modules) } + +})(); + +export { __webpack_require__ }; + +``` \ No newline at end of file diff --git a/tests/rspack-test/esmOutputCases/externals/commonjs-require-request-rest/__snapshots__/runtimeModeSnapshot/esm.snap.txt b/tests/rspack-test/esmOutputCases/externals/commonjs-require-request-rest/__snapshots__/runtimeModeSnapshot/esm.snap.txt new file mode 100644 index 000000000000..ce7938402925 --- /dev/null +++ b/tests/rspack-test/esmOutputCases/externals/commonjs-require-request-rest/__snapshots__/runtimeModeSnapshot/esm.snap.txt @@ -0,0 +1,58 @@ +```mjs title=main.mjs +import { rspackRequire, moduleFactories } from "./runtime.mjs"; +moduleFactories.add({ +"external-value" +/*!*************************************!*\ + !*** external ["external","value"] ***! + \*************************************/ +(module) { +module.exports = require("external").value; + +}, +}); +// ./index.js +const value = rspackRequire(/*! external-value */ "external-value"); + +if (value !== 42) { + throw new Error("external request rest segments should keep their wrapper semantics"); +} + + + +export { value }; + +``` + +```mjs title=runtime.mjs + +var modules = {}; +// The module cache +var moduleCache = {}; +// The require function +function rspackRequire(moduleId) { +// Check if module is in cache +var cachedModule = moduleCache[moduleId]; +if (cachedModule !== undefined) { +return cachedModule.exports; +} +// Create a new module (and put it into the cache) +var module = (moduleCache[moduleId] = { +exports: {} +}); +// Execute the module function +modules[moduleId](module, module.exports, rspackRequire); + +// Return the exports of the module +return module.exports; +} +export { rspackRequire }; +// expose the modules object (modules) +var moduleFactories = modules; +export { moduleFactories }; + +// rspack/runtime/esm_register_module +moduleFactories.add = function registerModules(modules) { Object.assign(moduleFactories, modules) } +; + + +``` \ No newline at end of file diff --git a/tests/rspack-test/esmOutputCases/externals/commonjs-require-request-rest/index.js b/tests/rspack-test/esmOutputCases/externals/commonjs-require-request-rest/index.js new file mode 100644 index 000000000000..932a83ce7f3d --- /dev/null +++ b/tests/rspack-test/esmOutputCases/externals/commonjs-require-request-rest/index.js @@ -0,0 +1,7 @@ +const value = require("external-value"); + +if (value !== 42) { + throw new Error("external request rest segments should keep their wrapper semantics"); +} + +export { value }; diff --git a/tests/rspack-test/esmOutputCases/externals/commonjs-require-request-rest/node_modules/external/index.js b/tests/rspack-test/esmOutputCases/externals/commonjs-require-request-rest/node_modules/external/index.js new file mode 100644 index 000000000000..885c586e241b --- /dev/null +++ b/tests/rspack-test/esmOutputCases/externals/commonjs-require-request-rest/node_modules/external/index.js @@ -0,0 +1,3 @@ +module.exports = { + value: 42 +}; diff --git a/tests/rspack-test/esmOutputCases/externals/commonjs-require-request-rest/node_modules/external/package.json b/tests/rspack-test/esmOutputCases/externals/commonjs-require-request-rest/node_modules/external/package.json new file mode 100644 index 000000000000..a9e27c9a5823 --- /dev/null +++ b/tests/rspack-test/esmOutputCases/externals/commonjs-require-request-rest/node_modules/external/package.json @@ -0,0 +1,5 @@ +{ + "name": "external", + "version": "1.0.0", + "main": "index.js" +} diff --git a/tests/rspack-test/esmOutputCases/externals/commonjs-require-request-rest/rspack.config.js b/tests/rspack-test/esmOutputCases/externals/commonjs-require-request-rest/rspack.config.js new file mode 100644 index 000000000000..5f12c9514c8a --- /dev/null +++ b/tests/rspack-test/esmOutputCases/externals/commonjs-require-request-rest/rspack.config.js @@ -0,0 +1,5 @@ +module.exports = { + externals: { + 'external-value': ['commonjs external', 'value'], + }, +}; diff --git a/tests/rspack-test/esmOutputCases/externals/commonjs-require-request-rest/test.config.js b/tests/rspack-test/esmOutputCases/externals/commonjs-require-request-rest/test.config.js new file mode 100644 index 000000000000..7c12c430c784 --- /dev/null +++ b/tests/rspack-test/esmOutputCases/externals/commonjs-require-request-rest/test.config.js @@ -0,0 +1,24 @@ +const fs = require("fs"); +const path = require("path"); +const { createRequire } = require("module"); + +function runtimeRequire() { + return createRequire(path.join(__dirname, "__external_runtime__.cjs")); +} + +module.exports = { + moduleScope(scope) { + scope.require = runtimeRequire(); + }, + afterExecute(options) { + const source = fs.readFileSync( + path.join(options.output.path, "main.mjs"), + "utf-8" + ); + + expect(source).toContain('external ["external","value"]'); + expect(source).toMatch( + /(?:__webpack_require__|__rspack_context\.r|rspackRequire)\s*\(\s*[^)]*["']external-value["']/ + ); + } +}; diff --git a/tests/rspack-test/esmOutputCases/externals/esm-node-target-alias/__snapshots__/esm.snap.txt b/tests/rspack-test/esmOutputCases/externals/esm-node-target-alias/__snapshots__/esm.snap.txt index 7a13a9bbe52e..c629af6abbb7 100644 --- a/tests/rspack-test/esmOutputCases/externals/esm-node-target-alias/__snapshots__/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/externals/esm-node-target-alias/__snapshots__/esm.snap.txt @@ -13,11 +13,14 @@ __webpack_require__.add({ (__unused_rspack_module, exports) { // CJS require of "module" type external — should be downgraded to node-commonjs const nodePath = __rspack_createRequire_require("node:path"); -exports.n = nodePath.resolve; +exports.nq = nodePath.resolve; // CJS require of "module-import" type external — should also be downgraded const nodeUrl = __rspack_createRequire_require("node:url"); -exports.g = nodeUrl.parse; +exports.gd = nodeUrl.parse; + +// CJS export-require dependency should use the same node-commonjs downgrade +exports.M = __rspack_createRequire_require("node:path"); }, @@ -28,8 +31,9 @@ exports.g = nodeUrl.parse; // ./index.js const cjs_consumer = __webpack_require__("./cjs-consumer.cjs"); -var g = cjs_consumer.g; -var n = cjs_consumer.n; +var gd = cjs_consumer.gd; +var M = cjs_consumer.M; +var nq = cjs_consumer.nq; @@ -48,17 +52,21 @@ it("should use aliased external request with correct external type", async () => expect(main.parse).toBe(nodeUrl.parse); // CJS require of "module" external — downgraded to node-commonjs - expect(cjs_consumer.n).toBe(nodePath.resolve); + expect(cjs_consumer.nq).toBe(nodePath.resolve); expect(main.cjsResolve).toBe(nodePath.resolve); // CJS require of "module-import" external — downgraded to node-commonjs - expect(cjs_consumer.g).toBe(nodeUrl.parse); + expect(cjs_consumer.gd).toBe(nodeUrl.parse); expect(main.cjsParse).toBe(nodeUrl.parse); + + // CJS export-require dependency — also downgraded to node-commonjs + expect(cjs_consumer.M.resolve).toBe(nodePath.resolve); + expect(main.cjsReexport.resolve).toBe(nodePath.resolve); }); -export { g as cjsParse, n as cjsResolve, parse, resolve }; +export { M as cjsReexport, gd as cjsParse, nq as cjsResolve, parse, resolve }; ``` diff --git a/tests/rspack-test/esmOutputCases/externals/esm-node-target-alias/__snapshots__/runtimeModeSnapshot/esm.snap.txt b/tests/rspack-test/esmOutputCases/externals/esm-node-target-alias/__snapshots__/runtimeModeSnapshot/esm.snap.txt index 64c8527493d5..eefaf9e99393 100644 --- a/tests/rspack-test/esmOutputCases/externals/esm-node-target-alias/__snapshots__/runtimeModeSnapshot/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/externals/esm-node-target-alias/__snapshots__/runtimeModeSnapshot/esm.snap.txt @@ -13,11 +13,14 @@ moduleFactories.add({ (__unused_rspack_module, exports) { // CJS require of "module" type external — should be downgraded to node-commonjs const nodePath = __rspack_createRequire_require("node:path"); -exports.n = nodePath.resolve; +exports.nq = nodePath.resolve; // CJS require of "module-import" type external — should also be downgraded const nodeUrl = __rspack_createRequire_require("node:url"); -exports.g = nodeUrl.parse; +exports.gd = nodeUrl.parse; + +// CJS export-require dependency should use the same node-commonjs downgrade +exports.M = __rspack_createRequire_require("node:path"); }, @@ -28,8 +31,9 @@ exports.g = nodeUrl.parse; // ./index.js const cjs_consumer = rspackRequire("./cjs-consumer.cjs"); -var g = cjs_consumer.g; -var n = cjs_consumer.n; +var gd = cjs_consumer.gd; +var M = cjs_consumer.M; +var nq = cjs_consumer.nq; @@ -48,17 +52,21 @@ it("should use aliased external request with correct external type", async () => expect(main.parse).toBe(nodeUrl.parse); // CJS require of "module" external — downgraded to node-commonjs - expect(cjs_consumer.n).toBe(nodePath.resolve); + expect(cjs_consumer.nq).toBe(nodePath.resolve); expect(main.cjsResolve).toBe(nodePath.resolve); // CJS require of "module-import" external — downgraded to node-commonjs - expect(cjs_consumer.g).toBe(nodeUrl.parse); + expect(cjs_consumer.gd).toBe(nodeUrl.parse); expect(main.cjsParse).toBe(nodeUrl.parse); + + // CJS export-require dependency — also downgraded to node-commonjs + expect(cjs_consumer.M.resolve).toBe(nodePath.resolve); + expect(main.cjsReexport.resolve).toBe(nodePath.resolve); }); -export { g as cjsParse, n as cjsResolve, parse, resolve }; +export { M as cjsReexport, gd as cjsParse, nq as cjsResolve, parse, resolve }; ``` @@ -94,4 +102,4 @@ moduleFactories.add = function registerModules(modules) { Object.assign(moduleFa ; -``` +``` \ No newline at end of file diff --git a/tests/rspack-test/esmOutputCases/externals/esm-node-target-alias/cjs-consumer.cjs b/tests/rspack-test/esmOutputCases/externals/esm-node-target-alias/cjs-consumer.cjs index 5dedff5bc53c..f883d2049f6b 100644 --- a/tests/rspack-test/esmOutputCases/externals/esm-node-target-alias/cjs-consumer.cjs +++ b/tests/rspack-test/esmOutputCases/externals/esm-node-target-alias/cjs-consumer.cjs @@ -5,3 +5,6 @@ exports.cjsResolve = nodePath.resolve; // CJS require of "module-import" type external — should also be downgraded const nodeUrl = require("node:url"); exports.cjsParse = nodeUrl.parse; + +// CJS export-require dependency should use the same node-commonjs downgrade +exports.cjsReexport = require("node:fs"); diff --git a/tests/rspack-test/esmOutputCases/externals/esm-node-target-alias/index.js b/tests/rspack-test/esmOutputCases/externals/esm-node-target-alias/index.js index 5d7a5d768eee..40560c0e73a4 100644 --- a/tests/rspack-test/esmOutputCases/externals/esm-node-target-alias/index.js +++ b/tests/rspack-test/esmOutputCases/externals/esm-node-target-alias/index.js @@ -1,6 +1,6 @@ import { resolve } from "node:fs"; import { parse } from "node:url"; -import { cjsResolve, cjsParse } from "./cjs-consumer.cjs"; +import { cjsResolve, cjsParse, cjsReexport } from "./cjs-consumer.cjs"; it("should use aliased external request with correct external type", async () => { const main = await import(/* webpackIgnore: true */ "./main.mjs"); @@ -22,6 +22,10 @@ it("should use aliased external request with correct external type", async () => // CJS require of "module-import" external — downgraded to node-commonjs expect(cjsParse).toBe(nodeUrl.parse); expect(main.cjsParse).toBe(nodeUrl.parse); + + // CJS export-require dependency — also downgraded to node-commonjs + expect(cjsReexport.resolve).toBe(nodePath.resolve); + expect(main.cjsReexport.resolve).toBe(nodePath.resolve); }); -export { resolve, parse, cjsResolve, cjsParse }; +export { resolve, parse, cjsResolve, cjsParse, cjsReexport }; diff --git a/tests/rspack-test/esmOutputCases/externals/esm-node-target-alias/rspack.config.mjs b/tests/rspack-test/esmOutputCases/externals/esm-node-target-alias/rspack.config.mjs index 798934412bba..99788ac554f6 100644 --- a/tests/rspack-test/esmOutputCases/externals/esm-node-target-alias/rspack.config.mjs +++ b/tests/rspack-test/esmOutputCases/externals/esm-node-target-alias/rspack.config.mjs @@ -6,8 +6,9 @@ const { /** @type {import("@rspack/core").Configuration} */ export default { + externalsType: 'module', externals: { - 'node:fs': 'module node:path', + 'node:fs': { module: 'node:path' }, 'node:url': 'module-import node:url', }, plugins: [ diff --git a/tests/rspack-test/esmOutputCases/externals/node-commonjs-helper-name-collision/__snapshots__/runtimeModeSnapshot/esm.snap.txt b/tests/rspack-test/esmOutputCases/externals/node-commonjs-helper-name-collision/__snapshots__/runtimeModeSnapshot/esm.snap.txt deleted file mode 100644 index 3e352f74cb81..000000000000 --- a/tests/rspack-test/esmOutputCases/externals/node-commonjs-helper-name-collision/__snapshots__/runtimeModeSnapshot/esm.snap.txt +++ /dev/null @@ -1,41 +0,0 @@ -```mjs title=main.mjs -import {fileURLToPath as __rspack_fileURLToPath} from "node:url"; -import {dirname as __rspack_dirname} from "node:path"; -var __rspack_import_meta_dirname__ = __rspack_dirname(__rspack_fileURLToPath(import.meta.url)); -import { createRequire as __rspack_createRequire } from "node:module"; -const __rspack_createRequire_require = __rspack_createRequire(import.meta.url); -// node:module -const external_node_module_namespaceObject = __rspack_createRequire_require("node:module"); -// ./index.js - - -const index_rspack_createRequire_require = (0,external_node_module_namespaceObject.createRequire)('/tests/rspack-test/esmOutputCases/externals/node-commonjs-helper-name-collision/index.js'); -// fs -const external_fs_namespaceObject = index_rspack_createRequire_require("fs"); - -const sourceCreateRequireRequire = index_rspack_createRequire_require; -const sourceReadFile = external_fs_namespaceObject.readFile; -const sourceRequireReadFile = (index_rspack_createRequire_require("fs").readFile); - -it("should deconflict source bindings that already use the node-commonjs helper names", async () => { - const mod = await import(/* webpackIgnore: true */ "./main.mjs"); - const { createRequire } = await import(/* webpackIgnore: true */ "node:module"); - const require = createRequire('/tests/rspack-test/esmOutputCases/externals/node-commonjs-helper-name-collision/index.js'); - const fs = require("fs"); - const path = require("path"); - const code = fs.readFileSync(path.join(__rspack_import_meta_dirname__, "main.mjs"), "utf-8"); - - expect(mod.sourceReadFile).toBe(fs.readFile); - expect(mod.sourceRequireReadFile).toBe(fs.readFile); - expect(mod.sourceCreateRequireRequire("fs").readFile).toBe(fs.readFile); - expect(code).toContain( - 'const __rspack_createRequire_require = __rspack_createRequire(import.meta.url);' - ); - expect(code).toMatch( - /^const (?!__rspack_createRequire_require\b)[A-Za-z0-9_$]*rspack_createRequire_require = .*createRequire.*;$/m - ); -}); - -export { sourceCreateRequireRequire, sourceReadFile, sourceRequireReadFile }; - -``` diff --git a/tests/rspack-test/esmOutputCases/externals/node-commonjs-relative-request/__snapshots__/esm.snap.txt b/tests/rspack-test/esmOutputCases/externals/node-commonjs-relative-request/__snapshots__/esm.snap.txt new file mode 100644 index 000000000000..974c7e2c3cfd --- /dev/null +++ b/tests/rspack-test/esmOutputCases/externals/node-commonjs-relative-request/__snapshots__/esm.snap.txt @@ -0,0 +1,172 @@ +```mjs title=chunks/lazy.mjs +import { __webpack_require__ } from "../runtime.mjs"; +import "../index_js-relative-external-package-external.mjs"; + +__webpack_require__.add({ +"./lazy.cjs" +/*!******************!*\ + !*** ./lazy.cjs ***! + \******************/ +(__unused_rspack_module, exports, __webpack_require__) { +exports.relativeValue = __webpack_require__(/*! relative-external */ "relative-external")/* .value */.value; +exports.packageValue = __webpack_require__(/*! package-external */ "package-external")/* .value */.value; + + +}, +}); +const lazy = __webpack_require__("./lazy.cjs"); +var lazy_default = /*#__PURE__*/__webpack_require__.n(lazy); +var lazy_default_0 = lazy_default(); +var packageValue = lazy.packageValue; +var relativeValue = lazy.relativeValue; + +export { packageValue, relativeValue }; +export default lazy_default_0; + +``` + +```mjs title=index_js-relative-external-package-external.mjs +import { __webpack_require__ } from "./runtime.mjs"; + +import { createRequire as __rspack_createRequire } from "node:module"; +const __rspack_createRequire_require = __rspack_createRequire(import.meta.url); +__webpack_require__.add({ +"relative-external" +/*!*********************************!*\ + !*** external "./external.cjs" ***! + \*********************************/ +(module) { +module.exports = __rspack_createRequire_require("./external.cjs"); + +}, +"package-external" +/*!*****************************!*\ + !*** external "shadow-pkg" ***! + \*****************************/ +(module) { +module.exports = __rspack_createRequire_require("shadow-pkg"); + +}, +}); +// ./index.js +it("should preserve the resolution base for node-commonjs externals", async () => { + const { relativeValue, packageValue } = await import("./chunks/lazy.mjs").then(__webpack_require__.t.bind(__webpack_require__, /*! ./lazy.cjs */ "./lazy.cjs", 19)); + + expect(relativeValue).toBe(42); + expect(packageValue).toBe("root"); +}); + +export {}; + +``` + +```mjs title=main.mjs +import "./index_js-relative-external-package-external.mjs"; + +export {}; + +``` + +```mjs title=runtime.mjs + +var __webpack_modules__ = {}; +// The module cache +var __webpack_module_cache__ = {}; +// The require function +function __webpack_require__(moduleId) { +// Check if module is in cache +var cachedModule = __webpack_module_cache__[moduleId]; +if (cachedModule !== undefined) { +return cachedModule.exports; +} +// Create a new module (and put it into the cache) +var module = (__webpack_module_cache__[moduleId] = { +exports: {} +}); +// Execute the module function +__webpack_modules__[moduleId](module, module.exports, __webpack_require__); + +// Return the exports of the module +return module.exports; +} +// expose the modules object (__webpack_modules__) +__webpack_require__.m = __webpack_modules__; + +// webpack/runtime/compat_get_default_export +(() => { +// getDefaultExport function for compatibility with non-ESM modules +__webpack_require__.n = (module) => { + var getter = module && module.__esModule ? + () => (module['default']) : + () => (module); + __webpack_require__.d(getter, { a: getter }); + return getter; +}; + +})(); +// webpack/runtime/create_fake_namespace_object +(() => { +var getProto = Object.getPrototypeOf ? (obj) => (Object.getPrototypeOf(obj)) : (obj) => (obj.__proto__); +var leafPrototypes; +// create a fake namespace object +// mode & 1: value is a module id, require it +// mode & 2: merge all properties of value into the ns +// mode & 4: return value when already ns object +// mode & 16: return value when it's Promise-like +// mode & 8|1: behave like require +__webpack_require__.t = function(value, mode) { + if(mode & 1) value = this(value); + if(mode & 8) return value; + if(typeof value === 'object' && value) { + if((mode & 4) && value.__esModule) return value; + if((mode & 16) && typeof value.then === 'function') return value; + } + var ns = Object.create(null); + __webpack_require__.r(ns); + var def = {}; + leafPrototypes = leafPrototypes || [null, getProto({}), getProto([]), getProto(getProto)]; + for(var current = mode & 2 && value; (typeof current == 'object' || typeof current == 'function') && !~leafPrototypes.indexOf(current); current = getProto(current)) { + Object.getOwnPropertyNames(current).forEach((key) => { def[key] = () => (value[key]) }); + } + def['default'] = () => (value); + __webpack_require__.d(ns, def); + return ns; +}; +})(); +// webpack/runtime/define_property_getters +(() => { +__webpack_require__.d = (exports, getters, values) => { + var define = (defs, kind) => { + for(var key in defs) { + if(__webpack_require__.o(defs, key) && !__webpack_require__.o(exports, key)) { + Object.defineProperty(exports, key, { enumerable: true, [kind]: defs[key] }); + } + } + }; + define(getters, "get"); + define(values, "value"); +}; +})(); +// webpack/runtime/esm_register_module +(() => { +__webpack_require__.add = function registerModules(modules) { Object.assign(__webpack_require__.m, modules) } + +})(); +// webpack/runtime/has_own_property +(() => { +__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop)) +})(); +// webpack/runtime/make_namespace_object +(() => { +// define __esModule on exports +__webpack_require__.r = (exports) => { + if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { + Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); + } + Object.defineProperty(exports, '__esModule', { value: true }); +}; +})(); + +export { __webpack_require__ }; + +``` \ No newline at end of file diff --git a/tests/rspack-test/esmOutputCases/externals/node-commonjs-relative-request/__snapshots__/runtimeModeSnapshot/esm.snap.txt b/tests/rspack-test/esmOutputCases/externals/node-commonjs-relative-request/__snapshots__/runtimeModeSnapshot/esm.snap.txt new file mode 100644 index 000000000000..168c2af6237e --- /dev/null +++ b/tests/rspack-test/esmOutputCases/externals/node-commonjs-relative-request/__snapshots__/runtimeModeSnapshot/esm.snap.txt @@ -0,0 +1,162 @@ +```mjs title=chunks/lazy.mjs +import { rspackRequire, moduleFactories, compatGetDefaultExport } from "../runtime.mjs"; +import "../index_js-relative-external-package-external.mjs"; + +moduleFactories.add({ +"./lazy.cjs" +/*!******************!*\ + !*** ./lazy.cjs ***! + \******************/ +(__unused_rspack_module, exports) { +exports.relativeValue = rspackRequire(/*! relative-external */ "relative-external")/* .value */.value; +exports.packageValue = rspackRequire(/*! package-external */ "package-external")/* .value */.value; + + +}, +}); +const lazy = rspackRequire("./lazy.cjs"); +var lazy_default = /*#__PURE__*/compatGetDefaultExport(lazy); +var lazy_default_0 = lazy_default(); +var packageValue = lazy.packageValue; +var relativeValue = lazy.relativeValue; + +export { packageValue, relativeValue }; +export default lazy_default_0; + +``` + +```mjs title=index_js-relative-external-package-external.mjs +import { rspackRequire, moduleFactories, createFakeNamespaceObject } from "./runtime.mjs"; +import { createRequire as __rspack_createRequire } from "node:module"; +const __rspack_createRequire_require = __rspack_createRequire(import.meta.url); +moduleFactories.add({ +"relative-external" +/*!*********************************!*\ + !*** external "./external.cjs" ***! + \*********************************/ +(module) { +module.exports = __rspack_createRequire_require("./external.cjs"); + +}, +"package-external" +/*!*****************************!*\ + !*** external "shadow-pkg" ***! + \*****************************/ +(module) { +module.exports = __rspack_createRequire_require("shadow-pkg"); + +}, +}); +// ./index.js +it("should preserve the resolution base for node-commonjs externals", async () => { + const { relativeValue, packageValue } = await import("./chunks/lazy.mjs").then(createFakeNamespaceObject.bind(rspackRequire, /*! ./lazy.cjs */ "./lazy.cjs", 19)); + + expect(relativeValue).toBe(42); + expect(packageValue).toBe("root"); +}); + +export {}; + +``` + +```mjs title=main.mjs +import "./index_js-relative-external-package-external.mjs"; + +export {}; + +``` + +```mjs title=runtime.mjs + +var modules = {}; +// The module cache +var moduleCache = {}; +// The require function +function rspackRequire(moduleId) { +// Check if module is in cache +var cachedModule = moduleCache[moduleId]; +if (cachedModule !== undefined) { +return cachedModule.exports; +} +// Create a new module (and put it into the cache) +var module = (moduleCache[moduleId] = { +exports: {} +}); +// Execute the module function +modules[moduleId](module, module.exports, rspackRequire); + +// Return the exports of the module +return module.exports; +} +export { rspackRequire }; +// expose the modules object (modules) +var moduleFactories = modules; +export { moduleFactories }; + +// rspack/runtime/compat_get_default_export +// getDefaultExport function for compatibility with non-ESM modules +var compatGetDefaultExport = (module) => { + var getter = module && module.__esModule ? + () => (module['default']) : + () => (module); + definePropertyGetters(getter, { a: getter }); + return getter; +}; +; +export { compatGetDefaultExport }; +// rspack/runtime/create_fake_namespace_object +var getProto = Object.getPrototypeOf ? (obj) => (Object.getPrototypeOf(obj)) : (obj) => (obj.__proto__); +var leafPrototypes; +// create a fake namespace object +// mode & 1: value is a module id, require it +// mode & 2: merge all properties of value into the ns +// mode & 4: return value when already ns object +// mode & 16: return value when it's Promise-like +// mode & 8|1: behave like require +var createFakeNamespaceObject = function(value, mode) { + if(mode & 1) value = (typeof this === "function" ? this : this.r)(value); + if(mode & 8) return value; + if(typeof value === 'object' && value) { + if((mode & 4) && value.__esModule) return value; + if((mode & 16) && typeof value.then === 'function') return value; + } + var ns = Object.create(null); + makeNamespaceObject(ns); + var def = {}; + leafPrototypes = leafPrototypes || [null, getProto({}), getProto([]), getProto(getProto)]; + for(var current = mode & 2 && value; (typeof current == 'object' || typeof current == 'function') && !~leafPrototypes.indexOf(current); current = getProto(current)) { + Object.getOwnPropertyNames(current).forEach((key) => { def[key] = () => (value[key]) }); + } + def['default'] = () => (value); + definePropertyGetters(ns, def); + return ns; +};; +export { createFakeNamespaceObject }; +// rspack/runtime/define_property_getters +var definePropertyGetters = (exports, getters, values) => { + var define = (defs, kind) => { + for(var key in defs) { + if(hasOwnProperty(defs, key) && !hasOwnProperty(exports, key)) { + Object.defineProperty(exports, key, { enumerable: true, [kind]: defs[key] }); + } + } + }; + define(getters, "get"); + define(values, "value"); +};; +// rspack/runtime/esm_register_module +moduleFactories.add = function registerModules(modules) { Object.assign(moduleFactories, modules) } +; +// rspack/runtime/has_own_property +var hasOwnProperty = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop)); +// rspack/runtime/make_namespace_object +// define __esModule on exports +var makeNamespaceObject = (exports) => { + if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { + Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); + } + Object.defineProperty(exports, '__esModule', { value: true }); +};; + + +``` \ No newline at end of file diff --git a/tests/rspack-test/esmOutputCases/externals/node-commonjs-relative-request/external.cjs b/tests/rspack-test/esmOutputCases/externals/node-commonjs-relative-request/external.cjs new file mode 100644 index 000000000000..885c586e241b --- /dev/null +++ b/tests/rspack-test/esmOutputCases/externals/node-commonjs-relative-request/external.cjs @@ -0,0 +1,3 @@ +module.exports = { + value: 42 +}; diff --git a/tests/rspack-test/esmOutputCases/externals/node-commonjs-relative-request/index.js b/tests/rspack-test/esmOutputCases/externals/node-commonjs-relative-request/index.js new file mode 100644 index 000000000000..5c7ccf63ff5c --- /dev/null +++ b/tests/rspack-test/esmOutputCases/externals/node-commonjs-relative-request/index.js @@ -0,0 +1,6 @@ +it("should preserve the resolution base for node-commonjs externals", async () => { + const { relativeValue, packageValue } = await import("./lazy.cjs"); + + expect(relativeValue).toBe(42); + expect(packageValue).toBe("root"); +}); diff --git a/tests/rspack-test/esmOutputCases/externals/node-commonjs-relative-request/lazy.cjs b/tests/rspack-test/esmOutputCases/externals/node-commonjs-relative-request/lazy.cjs new file mode 100644 index 000000000000..3ed479f2a221 --- /dev/null +++ b/tests/rspack-test/esmOutputCases/externals/node-commonjs-relative-request/lazy.cjs @@ -0,0 +1,2 @@ +exports.relativeValue = require("relative-external").value; +exports.packageValue = require("package-external").value; diff --git a/tests/rspack-test/esmOutputCases/externals/node-commonjs-relative-request/packages/chunk/index.cjs b/tests/rspack-test/esmOutputCases/externals/node-commonjs-relative-request/packages/chunk/index.cjs new file mode 100644 index 000000000000..5f865cd82e96 --- /dev/null +++ b/tests/rspack-test/esmOutputCases/externals/node-commonjs-relative-request/packages/chunk/index.cjs @@ -0,0 +1,3 @@ +module.exports = { + value: "chunk" +}; diff --git a/tests/rspack-test/esmOutputCases/externals/node-commonjs-relative-request/packages/chunk/package.json b/tests/rspack-test/esmOutputCases/externals/node-commonjs-relative-request/packages/chunk/package.json new file mode 100644 index 000000000000..72d0b88aa931 --- /dev/null +++ b/tests/rspack-test/esmOutputCases/externals/node-commonjs-relative-request/packages/chunk/package.json @@ -0,0 +1,5 @@ +{ + "name": "shadow-pkg", + "version": "1.0.0", + "main": "index.cjs" +} diff --git a/tests/rspack-test/esmOutputCases/externals/node-commonjs-relative-request/packages/root/index.cjs b/tests/rspack-test/esmOutputCases/externals/node-commonjs-relative-request/packages/root/index.cjs new file mode 100644 index 000000000000..768124d9c7c3 --- /dev/null +++ b/tests/rspack-test/esmOutputCases/externals/node-commonjs-relative-request/packages/root/index.cjs @@ -0,0 +1,3 @@ +module.exports = { + value: "root" +}; diff --git a/tests/rspack-test/esmOutputCases/externals/node-commonjs-relative-request/packages/root/package.json b/tests/rspack-test/esmOutputCases/externals/node-commonjs-relative-request/packages/root/package.json new file mode 100644 index 000000000000..72d0b88aa931 --- /dev/null +++ b/tests/rspack-test/esmOutputCases/externals/node-commonjs-relative-request/packages/root/package.json @@ -0,0 +1,5 @@ +{ + "name": "shadow-pkg", + "version": "1.0.0", + "main": "index.cjs" +} diff --git a/tests/rspack-test/esmOutputCases/externals/node-commonjs-relative-request/rspack.config.js b/tests/rspack-test/esmOutputCases/externals/node-commonjs-relative-request/rspack.config.js new file mode 100644 index 000000000000..7f9576d71500 --- /dev/null +++ b/tests/rspack-test/esmOutputCases/externals/node-commonjs-relative-request/rspack.config.js @@ -0,0 +1,9 @@ +module.exports = { + output: { + chunkFilename: 'chunks/[name].mjs', + }, + externals: { + 'relative-external': 'node-commonjs ./external.cjs', + 'package-external': 'node-commonjs shadow-pkg', + }, +}; diff --git a/tests/rspack-test/esmOutputCases/externals/node-commonjs-relative-request/test.config.js b/tests/rspack-test/esmOutputCases/externals/node-commonjs-relative-request/test.config.js new file mode 100644 index 000000000000..1fcc6a466ac4 --- /dev/null +++ b/tests/rspack-test/esmOutputCases/externals/node-commonjs-relative-request/test.config.js @@ -0,0 +1,78 @@ +const fs = require("fs"); +const path = require("path"); + +function readOutputs(directory) { + const outputs = new Map(); + const queue = [directory]; + + while (queue.length > 0) { + const current = queue.pop(); + for (const entry of fs.readdirSync(current, { withFileTypes: true })) { + const file = path.join(current, entry.name); + if (entry.isDirectory()) { + queue.push(file); + } else if (file.endsWith(".mjs")) { + outputs.set( + path.relative(directory, file), + fs.readFileSync(file, "utf-8") + ); + } + } + } + + return outputs; +} + +module.exports = { + beforeExecute(options) { + if (Array.isArray(options)) { + options = options[0]; + } + fs.copyFileSync( + path.join(options.context, "external.cjs"), + path.join(options.output.path, "external.cjs") + ); + fs.cpSync( + path.join(options.context, "packages", "root"), + path.join(options.output.path, "node_modules", "shadow-pkg"), + { recursive: true } + ); + fs.cpSync( + path.join(options.context, "packages", "chunk"), + path.join(options.output.path, "chunks", "node_modules", "shadow-pkg"), + { recursive: true } + ); + }, + afterExecute(options) { + const outputs = readOutputs(options.output.path); + const source = [...outputs.values()].join("\n"); + const lazySource = outputs.get(path.join("chunks", "lazy.mjs")); + const relativeExternalSource = [...outputs.values()].find(output => + output.includes('external "./external.cjs"') + ); + const packageExternalSource = [...outputs.values()].find(output => + output.includes('external "shadow-pkg"') + ); + + expect(lazySource).toBeDefined(); + expect(relativeExternalSource).toBeDefined(); + expect(packageExternalSource).toBeDefined(); + expect(source).toContain('external "./external.cjs"'); + expect(source).toContain('external "shadow-pkg"'); + expect(relativeExternalSource).toMatch( + /__rspack_createRequire_require\s*\(\s*["']\.\/external\.cjs["']\s*\)/ + ); + expect(packageExternalSource).toMatch( + /__rspack_createRequire_require\s*\(\s*["']shadow-pkg["']\s*\)/ + ); + expect(lazySource).not.toMatch( + /__rspack_createRequire_require\s*\(\s*["'](?:\.\/external\.cjs|shadow-pkg)["']\s*\)/ + ); + expect(lazySource).toMatch( + /(?:__webpack_require__|__rspack_context\.r|rspackRequire)\s*\(\s*[^)]*["']relative-external["']/ + ); + expect(lazySource).toMatch( + /(?:__webpack_require__|__rspack_context\.r|rspackRequire)\s*\(\s*[^)]*["']package-external["']/ + ); + } +}; From 5e13ffae15454259ba02aba115ea0e6f48618ae6 Mon Sep 17 00:00:00 2001 From: Fy <1114550440@qq.com> Date: Tue, 25 Aug 2026 17:13:57 +0800 Subject: [PATCH 03/13] test: remove added CommonJS external cases --- .../src/module_graph/connection.rs | 40 ---- .../src/dependency/commonjs_external.rs | 58 ------ .../__snapshots__/esm.snap.txt | 137 -------------- .../runtimeModeSnapshot/esm.snap.txt | 134 -------------- .../entry-safe.js | 5 - .../entry-unsafe.js | 14 -- .../commonjs-require-conditional/local.cjs | 1 - .../node_modules/external/index.js | 5 - .../node_modules/external/package.json | 5 - .../rspack.config.js | 9 - .../commonjs-require-conditional/safe.cjs | 1 - .../test.config.js | 80 -------- .../commonjs-require-conditional/unsafe.cjs | 13 -- .../commonjs-require-conditional/warnings.js | 3 - .../__snapshots__/esm.snap.txt | 111 ----------- .../runtimeModeSnapshot/esm.snap.txt | 108 ----------- .../commonjs-require-direct/consumer-a.cjs | 14 -- .../commonjs-require-direct/consumer-b.cjs | 1 - .../commonjs-require-direct/entry-a.js | 19 -- .../commonjs-require-direct/entry-b.js | 5 - .../node_modules/external/index.js | 8 - .../node_modules/external/package.json | 5 - .../commonjs-require-direct/rspack.config.js | 9 - .../commonjs-require-direct/test.config.js | 83 --------- .../__snapshots__/esm.snap.txt | 82 --------- .../runtimeModeSnapshot/esm.snap.txt | 80 -------- .../commonjs-require-optional/index.js | 21 --- .../node_modules/optional-external/index.js | 3 - .../optional-external/package.json | 5 - .../rspack.config.js | 6 - .../commonjs-require-optional/test.config.js | 38 ---- .../__snapshots__/esm.snap.txt | 60 ------ .../runtimeModeSnapshot/esm.snap.txt | 58 ------ .../commonjs-require-request-rest/index.js | 7 - .../node_modules/external/index.js | 3 - .../node_modules/external/package.json | 5 - .../rspack.config.js | 5 - .../test.config.js | 24 --- .../__snapshots__/esm.snap.txt | 22 +-- .../runtimeModeSnapshot/esm.snap.txt | 22 +-- .../esm-node-target-alias/cjs-consumer.cjs | 3 - .../externals/esm-node-target-alias/index.js | 8 +- .../esm-node-target-alias/rspack.config.mjs | 3 +- .../modern-module-explicit-node/index.js | 1 - .../test.config.mjs | 7 +- .../__snapshots__/esm.snap.txt | 172 ------------------ .../runtimeModeSnapshot/esm.snap.txt | 162 ----------------- .../external.cjs | 3 - .../node-commonjs-relative-request/index.js | 6 - .../node-commonjs-relative-request/lazy.cjs | 2 - .../packages/chunk/index.cjs | 3 - .../packages/chunk/package.json | 5 - .../packages/root/index.cjs | 3 - .../packages/root/package.json | 5 - .../rspack.config.js | 9 - .../test.config.js | 78 -------- 56 files changed, 18 insertions(+), 1761 deletions(-) delete mode 100644 tests/rspack-test/esmOutputCases/externals/commonjs-require-conditional/__snapshots__/esm.snap.txt delete mode 100644 tests/rspack-test/esmOutputCases/externals/commonjs-require-conditional/__snapshots__/runtimeModeSnapshot/esm.snap.txt delete mode 100644 tests/rspack-test/esmOutputCases/externals/commonjs-require-conditional/entry-safe.js delete mode 100644 tests/rspack-test/esmOutputCases/externals/commonjs-require-conditional/entry-unsafe.js delete mode 100644 tests/rspack-test/esmOutputCases/externals/commonjs-require-conditional/local.cjs delete mode 100644 tests/rspack-test/esmOutputCases/externals/commonjs-require-conditional/node_modules/external/index.js delete mode 100644 tests/rspack-test/esmOutputCases/externals/commonjs-require-conditional/node_modules/external/package.json delete mode 100644 tests/rspack-test/esmOutputCases/externals/commonjs-require-conditional/rspack.config.js delete mode 100644 tests/rspack-test/esmOutputCases/externals/commonjs-require-conditional/safe.cjs delete mode 100644 tests/rspack-test/esmOutputCases/externals/commonjs-require-conditional/test.config.js delete mode 100644 tests/rspack-test/esmOutputCases/externals/commonjs-require-conditional/unsafe.cjs delete mode 100644 tests/rspack-test/esmOutputCases/externals/commonjs-require-conditional/warnings.js delete mode 100644 tests/rspack-test/esmOutputCases/externals/commonjs-require-direct/__snapshots__/esm.snap.txt delete mode 100644 tests/rspack-test/esmOutputCases/externals/commonjs-require-direct/__snapshots__/runtimeModeSnapshot/esm.snap.txt delete mode 100644 tests/rspack-test/esmOutputCases/externals/commonjs-require-direct/consumer-a.cjs delete mode 100644 tests/rspack-test/esmOutputCases/externals/commonjs-require-direct/consumer-b.cjs delete mode 100644 tests/rspack-test/esmOutputCases/externals/commonjs-require-direct/entry-a.js delete mode 100644 tests/rspack-test/esmOutputCases/externals/commonjs-require-direct/entry-b.js delete mode 100644 tests/rspack-test/esmOutputCases/externals/commonjs-require-direct/node_modules/external/index.js delete mode 100644 tests/rspack-test/esmOutputCases/externals/commonjs-require-direct/node_modules/external/package.json delete mode 100644 tests/rspack-test/esmOutputCases/externals/commonjs-require-direct/rspack.config.js delete mode 100644 tests/rspack-test/esmOutputCases/externals/commonjs-require-direct/test.config.js delete mode 100644 tests/rspack-test/esmOutputCases/externals/commonjs-require-optional/__snapshots__/esm.snap.txt delete mode 100644 tests/rspack-test/esmOutputCases/externals/commonjs-require-optional/__snapshots__/runtimeModeSnapshot/esm.snap.txt delete mode 100644 tests/rspack-test/esmOutputCases/externals/commonjs-require-optional/index.js delete mode 100644 tests/rspack-test/esmOutputCases/externals/commonjs-require-optional/node_modules/optional-external/index.js delete mode 100644 tests/rspack-test/esmOutputCases/externals/commonjs-require-optional/node_modules/optional-external/package.json delete mode 100644 tests/rspack-test/esmOutputCases/externals/commonjs-require-optional/rspack.config.js delete mode 100644 tests/rspack-test/esmOutputCases/externals/commonjs-require-optional/test.config.js delete mode 100644 tests/rspack-test/esmOutputCases/externals/commonjs-require-request-rest/__snapshots__/esm.snap.txt delete mode 100644 tests/rspack-test/esmOutputCases/externals/commonjs-require-request-rest/__snapshots__/runtimeModeSnapshot/esm.snap.txt delete mode 100644 tests/rspack-test/esmOutputCases/externals/commonjs-require-request-rest/index.js delete mode 100644 tests/rspack-test/esmOutputCases/externals/commonjs-require-request-rest/node_modules/external/index.js delete mode 100644 tests/rspack-test/esmOutputCases/externals/commonjs-require-request-rest/node_modules/external/package.json delete mode 100644 tests/rspack-test/esmOutputCases/externals/commonjs-require-request-rest/rspack.config.js delete mode 100644 tests/rspack-test/esmOutputCases/externals/commonjs-require-request-rest/test.config.js delete mode 100644 tests/rspack-test/esmOutputCases/externals/node-commonjs-relative-request/__snapshots__/esm.snap.txt delete mode 100644 tests/rspack-test/esmOutputCases/externals/node-commonjs-relative-request/__snapshots__/runtimeModeSnapshot/esm.snap.txt delete mode 100644 tests/rspack-test/esmOutputCases/externals/node-commonjs-relative-request/external.cjs delete mode 100644 tests/rspack-test/esmOutputCases/externals/node-commonjs-relative-request/index.js delete mode 100644 tests/rspack-test/esmOutputCases/externals/node-commonjs-relative-request/lazy.cjs delete mode 100644 tests/rspack-test/esmOutputCases/externals/node-commonjs-relative-request/packages/chunk/index.cjs delete mode 100644 tests/rspack-test/esmOutputCases/externals/node-commonjs-relative-request/packages/chunk/package.json delete mode 100644 tests/rspack-test/esmOutputCases/externals/node-commonjs-relative-request/packages/root/index.cjs delete mode 100644 tests/rspack-test/esmOutputCases/externals/node-commonjs-relative-request/packages/root/package.json delete mode 100644 tests/rspack-test/esmOutputCases/externals/node-commonjs-relative-request/rspack.config.js delete mode 100644 tests/rspack-test/esmOutputCases/externals/node-commonjs-relative-request/test.config.js diff --git a/crates/rspack_core/src/module_graph/connection.rs b/crates/rspack_core/src/module_graph/connection.rs index 45ca6e1c6767..fe40e80b0b90 100644 --- a/crates/rspack_core/src/module_graph/connection.rs +++ b/crates/rspack_core/src/module_graph/connection.rs @@ -175,46 +175,6 @@ impl ModuleGraphConnection { } } -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn should_restore_state_after_forcing_connection_inactive() { - let mut connection = ModuleGraphConnection::new( - DependencyId::from(1), - Some(ModuleIdentifier::from("issuer")), - ModuleIdentifier::from("target"), - true, - ); - - let state = connection.force_inactive_with_state(); - assert!(!connection.active); - assert!(!connection.conditional); - - connection.restore_active_state(state); - assert!(connection.active); - assert!(connection.conditional); - } - - #[test] - fn should_not_reactivate_an_already_inactive_connection() { - let mut connection = ModuleGraphConnection::new( - DependencyId::from(1), - Some(ModuleIdentifier::from("issuer")), - ModuleIdentifier::from("target"), - true, - ); - connection.force_inactive(); - - let state = connection.force_inactive_with_state(); - connection.restore_active_state(state); - - assert!(!connection.active); - assert!(!connection.conditional); - } -} - #[cacheable] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum ConnectionState { diff --git a/crates/rspack_plugin_esm_library/src/dependency/commonjs_external.rs b/crates/rspack_plugin_esm_library/src/dependency/commonjs_external.rs index 748f0ec20161..0543acf405cd 100644 --- a/crates/rspack_plugin_esm_library/src/dependency/commonjs_external.rs +++ b/crates/rspack_plugin_esm_library/src/dependency/commonjs_external.rs @@ -189,64 +189,6 @@ pub fn cutout_commonjs_externals( direct_dependencies } -#[cfg(test)] -mod tests { - use super::{DirectRequireKind, can_render_direct_request, is_relative_external_request}; - - #[test] - fn should_detect_relative_external_requests() { - assert!(is_relative_external_request(".")); - assert!(is_relative_external_request("..")); - assert!(is_relative_external_request("./external.cjs")); - assert!(is_relative_external_request("../external.cjs")); - assert!(is_relative_external_request(".\\external.cjs")); - assert!(is_relative_external_request("..\\external.cjs")); - assert!(!is_relative_external_request("external")); - assert!(!is_relative_external_request("node:fs")); - assert!(!is_relative_external_request("/external.cjs")); - } - - #[test] - fn should_only_render_base_independent_node_commonjs_requests_directly() { - assert!(can_render_direct_request( - DirectRequireKind::NodeCommonJs, - "path" - )); - assert!(can_render_direct_request( - DirectRequireKind::NodeCommonJs, - "node:path" - )); - assert!(!can_render_direct_request( - DirectRequireKind::NodeCommonJs, - "external" - )); - assert!(!can_render_direct_request( - DirectRequireKind::NodeCommonJs, - "." - )); - assert!(!can_render_direct_request( - DirectRequireKind::NodeCommonJs, - "#external" - )); - assert!(!can_render_direct_request( - DirectRequireKind::NodeCommonJs, - "/external.cjs" - )); - } - - #[test] - fn should_keep_bare_commonjs_requests_direct() { - assert!(can_render_direct_request( - DirectRequireKind::CommonJs, - "external" - )); - assert!(!can_render_direct_request( - DirectRequireKind::CommonJs, - "./external.cjs" - )); - } -} - fn get_direct_external_require( dependency_id: &DependencyId, expression_range: DependencyRange, diff --git a/tests/rspack-test/esmOutputCases/externals/commonjs-require-conditional/__snapshots__/esm.snap.txt b/tests/rspack-test/esmOutputCases/externals/commonjs-require-conditional/__snapshots__/esm.snap.txt deleted file mode 100644 index 1f52d6c07002..000000000000 --- a/tests/rspack-test/esmOutputCases/externals/commonjs-require-conditional/__snapshots__/esm.snap.txt +++ /dev/null @@ -1,137 +0,0 @@ -```mjs title=runtime.mjs - -var __webpack_modules__ = {}; -// The module cache -var __webpack_module_cache__ = {}; -// The require function -function __webpack_require__(moduleId) { -// Check if module is in cache -var cachedModule = __webpack_module_cache__[moduleId]; -if (cachedModule !== undefined) { -return cachedModule.exports; -} -// Create a new module (and put it into the cache) -var module = (__webpack_module_cache__[moduleId] = { -exports: {} -}); -// Execute the module function -__webpack_modules__[moduleId](module, module.exports, __webpack_require__); - -// Return the exports of the module -return module.exports; -} -// expose the modules object (__webpack_modules__) -__webpack_require__.m = __webpack_modules__; - -// webpack/runtime/esm_register_module -(() => { -__webpack_require__.add = function registerModules(modules) { Object.assign(__webpack_require__.m, modules) } - -})(); - -export { __webpack_require__ }; - -``` - -```mjs title=safe.mjs -import { __webpack_require__ } from "./runtime.mjs"; - -__webpack_require__.add({ -"./safe.cjs" -/*!******************!*\ - !*** ./safe.cjs ***! - \******************/ -(module) { -module.exports = require("external"); - - -}, -}); -// ./entry-safe.js -const external = __webpack_require__(/*! ./safe.cjs */ "./safe.cjs"); - -process.__mixedExternalValues.push(external); - -const value = external.value; - -export { value }; - -``` - -```mjs title=unsafe.mjs -import { __webpack_require__ } from "./runtime.mjs"; - -__webpack_require__.add({ -"./. sync recursive" -/*!****************!*\ - !*** ./.|sync ***! - \****************/ -(module) { -function __rspack_empty_context(req) { - var e = new Error("Cannot find module '" + req + "'"); - e.code = 'MODULE_NOT_FOUND'; - throw e; -} -__rspack_empty_context.keys = () => ([]); -__rspack_empty_context.resolve = __rspack_empty_context; -__rspack_empty_context.id = "./. sync recursive"; -module.exports = __rspack_empty_context; - - -}, -"external" -/*!***************************!*\ - !*** external "external" ***! - \***************************/ -(module) { -module.exports = require("external"); - -}, -"./local.cjs" -/*!*******************!*\ - !*** ./local.cjs ***! - \*******************/ -(__unused_rspack_module, exports) { -exports.value = 7; - - -}, -"./unsafe.cjs" -/*!********************!*\ - !*** ./unsafe.cjs ***! - \********************/ -(module, __unused_rspack_exports, __webpack_require__) { -const selected = __webpack_require__( - globalThis.__USE_EXTERNAL__ ? /*! external */ "external" : /*! ./local.cjs */ "./local.cjs" -); - -const contextual = globalThis.__RUN_DYNAMIC_CONTEXT__ - ? __webpack_require__(/*! . */ "./. sync recursive")(globalThis.__USE_CONTEXT_EXTERNAL__ - ? /*! external */ "external" - : "./" + globalThis.__LOCAL_MODULE__) - : __webpack_require__(/*! ./local.cjs */ "./local.cjs"); - -module.exports = { selected, contextual }; - - -}, -}); -// ./entry-unsafe.js -globalThis.__USE_EXTERNAL__ = true; -globalThis.__RUN_DYNAMIC_CONTEXT__ = false; -globalThis.__USE_CONTEXT_EXTERNAL__ = false; -globalThis.__LOCAL_MODULE__ = "local.cjs"; - -const { selected: selected, contextual: contextual } = __webpack_require__(/*! ./unsafe.cjs */ "./unsafe.cjs"); - -process.__mixedExternalValues.push(selected); - -if (contextual.value !== 7) { - throw new Error("dynamic CommonJS context fallback should keep working"); -} - -const value = selected.value; - -export { value }; - -``` \ No newline at end of file diff --git a/tests/rspack-test/esmOutputCases/externals/commonjs-require-conditional/__snapshots__/runtimeModeSnapshot/esm.snap.txt b/tests/rspack-test/esmOutputCases/externals/commonjs-require-conditional/__snapshots__/runtimeModeSnapshot/esm.snap.txt deleted file mode 100644 index b5bfb4b1adc1..000000000000 --- a/tests/rspack-test/esmOutputCases/externals/commonjs-require-conditional/__snapshots__/runtimeModeSnapshot/esm.snap.txt +++ /dev/null @@ -1,134 +0,0 @@ -```mjs title=runtime.mjs - -var modules = {}; -// The module cache -var moduleCache = {}; -// The require function -function rspackRequire(moduleId) { -// Check if module is in cache -var cachedModule = moduleCache[moduleId]; -if (cachedModule !== undefined) { -return cachedModule.exports; -} -// Create a new module (and put it into the cache) -var module = (moduleCache[moduleId] = { -exports: {} -}); -// Execute the module function -modules[moduleId](module, module.exports, rspackRequire); - -// Return the exports of the module -return module.exports; -} -export { rspackRequire }; -// expose the modules object (modules) -var moduleFactories = modules; -export { moduleFactories }; - -// rspack/runtime/esm_register_module -moduleFactories.add = function registerModules(modules) { Object.assign(moduleFactories, modules) } -; - - -``` - -```mjs title=safe.mjs -import { rspackRequire, moduleFactories } from "./runtime.mjs"; -moduleFactories.add({ -"./safe.cjs" -/*!******************!*\ - !*** ./safe.cjs ***! - \******************/ -(module) { -module.exports = require("external"); - - -}, -}); -// ./entry-safe.js -const external = rspackRequire(/*! ./safe.cjs */ "./safe.cjs"); - -process.__mixedExternalValues.push(external); - -const value = external.value; - -export { value }; - -``` - -```mjs title=unsafe.mjs -import { rspackRequire, moduleFactories } from "./runtime.mjs"; -moduleFactories.add({ -"./. sync recursive" -/*!****************!*\ - !*** ./.|sync ***! - \****************/ -(module) { -function __rspack_empty_context(req) { - var e = new Error("Cannot find module '" + req + "'"); - e.code = 'MODULE_NOT_FOUND'; - throw e; -} -__rspack_empty_context.keys = () => ([]); -__rspack_empty_context.resolve = __rspack_empty_context; -__rspack_empty_context.id = "./. sync recursive"; -module.exports = __rspack_empty_context; - - -}, -"external" -/*!***************************!*\ - !*** external "external" ***! - \***************************/ -(module) { -module.exports = require("external"); - -}, -"./local.cjs" -/*!*******************!*\ - !*** ./local.cjs ***! - \*******************/ -(__unused_rspack_module, exports) { -exports.value = 7; - - -}, -"./unsafe.cjs" -/*!********************!*\ - !*** ./unsafe.cjs ***! - \********************/ -(module) { -const selected = rspackRequire( - globalThis.__USE_EXTERNAL__ ? /*! external */ "external" : /*! ./local.cjs */ "./local.cjs" -); - -const contextual = globalThis.__RUN_DYNAMIC_CONTEXT__ - ? rspackRequire(/*! . */ "./. sync recursive")(globalThis.__USE_CONTEXT_EXTERNAL__ - ? /*! external */ "external" - : "./" + globalThis.__LOCAL_MODULE__) - : rspackRequire(/*! ./local.cjs */ "./local.cjs"); - -module.exports = { selected, contextual }; - - -}, -}); -// ./entry-unsafe.js -globalThis.__USE_EXTERNAL__ = true; -globalThis.__RUN_DYNAMIC_CONTEXT__ = false; -globalThis.__USE_CONTEXT_EXTERNAL__ = false; -globalThis.__LOCAL_MODULE__ = "local.cjs"; - -const { selected: selected, contextual: contextual } = rspackRequire(/*! ./unsafe.cjs */ "./unsafe.cjs"); - -process.__mixedExternalValues.push(selected); - -if (contextual.value !== 7) { - throw new Error("dynamic CommonJS context fallback should keep working"); -} - -const value = selected.value; - -export { value }; - -``` \ No newline at end of file diff --git a/tests/rspack-test/esmOutputCases/externals/commonjs-require-conditional/entry-safe.js b/tests/rspack-test/esmOutputCases/externals/commonjs-require-conditional/entry-safe.js deleted file mode 100644 index 102124d4aa09..000000000000 --- a/tests/rspack-test/esmOutputCases/externals/commonjs-require-conditional/entry-safe.js +++ /dev/null @@ -1,5 +0,0 @@ -const external = require("./safe.cjs"); - -process.__mixedExternalValues.push(external); - -export const value = external.value; diff --git a/tests/rspack-test/esmOutputCases/externals/commonjs-require-conditional/entry-unsafe.js b/tests/rspack-test/esmOutputCases/externals/commonjs-require-conditional/entry-unsafe.js deleted file mode 100644 index b85d2f76f8f7..000000000000 --- a/tests/rspack-test/esmOutputCases/externals/commonjs-require-conditional/entry-unsafe.js +++ /dev/null @@ -1,14 +0,0 @@ -globalThis.__USE_EXTERNAL__ = true; -globalThis.__RUN_DYNAMIC_CONTEXT__ = false; -globalThis.__USE_CONTEXT_EXTERNAL__ = false; -globalThis.__LOCAL_MODULE__ = "local.cjs"; - -const { selected, contextual } = require("./unsafe.cjs"); - -process.__mixedExternalValues.push(selected); - -if (contextual.value !== 7) { - throw new Error("dynamic CommonJS context fallback should keep working"); -} - -export const value = selected.value; diff --git a/tests/rspack-test/esmOutputCases/externals/commonjs-require-conditional/local.cjs b/tests/rspack-test/esmOutputCases/externals/commonjs-require-conditional/local.cjs deleted file mode 100644 index 2558e07312c3..000000000000 --- a/tests/rspack-test/esmOutputCases/externals/commonjs-require-conditional/local.cjs +++ /dev/null @@ -1 +0,0 @@ -exports.value = 7; diff --git a/tests/rspack-test/esmOutputCases/externals/commonjs-require-conditional/node_modules/external/index.js b/tests/rspack-test/esmOutputCases/externals/commonjs-require-conditional/node_modules/external/index.js deleted file mode 100644 index f69bfa0174ae..000000000000 --- a/tests/rspack-test/esmOutputCases/externals/commonjs-require-conditional/node_modules/external/index.js +++ /dev/null @@ -1,5 +0,0 @@ -process.__mixedExternalLoadCount++; - -module.exports = { - value: 42 -}; diff --git a/tests/rspack-test/esmOutputCases/externals/commonjs-require-conditional/node_modules/external/package.json b/tests/rspack-test/esmOutputCases/externals/commonjs-require-conditional/node_modules/external/package.json deleted file mode 100644 index a9e27c9a5823..000000000000 --- a/tests/rspack-test/esmOutputCases/externals/commonjs-require-conditional/node_modules/external/package.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "name": "external", - "version": "1.0.0", - "main": "index.js" -} diff --git a/tests/rspack-test/esmOutputCases/externals/commonjs-require-conditional/rspack.config.js b/tests/rspack-test/esmOutputCases/externals/commonjs-require-conditional/rspack.config.js deleted file mode 100644 index 38e1add730dc..000000000000 --- a/tests/rspack-test/esmOutputCases/externals/commonjs-require-conditional/rspack.config.js +++ /dev/null @@ -1,9 +0,0 @@ -module.exports = { - entry: { - safe: './entry-safe.js', - unsafe: './entry-unsafe.js', - }, - externals: { - external: 'commonjs external', - }, -}; diff --git a/tests/rspack-test/esmOutputCases/externals/commonjs-require-conditional/safe.cjs b/tests/rspack-test/esmOutputCases/externals/commonjs-require-conditional/safe.cjs deleted file mode 100644 index 0f9cd4f1c1df..000000000000 --- a/tests/rspack-test/esmOutputCases/externals/commonjs-require-conditional/safe.cjs +++ /dev/null @@ -1 +0,0 @@ -module.exports = require("external"); diff --git a/tests/rspack-test/esmOutputCases/externals/commonjs-require-conditional/test.config.js b/tests/rspack-test/esmOutputCases/externals/commonjs-require-conditional/test.config.js deleted file mode 100644 index d2acaeb854a9..000000000000 --- a/tests/rspack-test/esmOutputCases/externals/commonjs-require-conditional/test.config.js +++ /dev/null @@ -1,80 +0,0 @@ -const fs = require("fs"); -const path = require("path"); -const { execFileSync } = require("child_process"); -const { createRequire } = require("module"); -const { pathToFileURL } = require("url"); - -function runtimeRequire() { - return createRequire(path.join(__dirname, "__external_runtime__.cjs")); -} - -function readOutput(options, file) { - return fs.readFileSync(path.join(options.output.path, file), "utf-8"); -} - -module.exports = { - beforeExecute() { - const require = runtimeRequire(); - delete require.cache[require.resolve("external")]; - process.__mixedExternalLoadCount = 0; - process.__mixedExternalValues = []; - }, - findBundle() { - return ["safe.mjs", "unsafe.mjs"]; - }, - moduleScope(scope) { - scope.require = runtimeRequire(); - }, - afterExecute(options) { - const safe = readOutput(options, "safe.mjs"); - const unsafe = readOutput(options, "unsafe.mjs"); - const source = `${safe}\n${unsafe}`; - - expect(safe).toMatch( - /module\.exports\s*=\s*require\s*\(\s*["']external["']\s*\)/ - ); - expect(safe).not.toContain('external "external"'); - expect(unsafe).toContain('external "external"'); - expect(unsafe).toMatch( - /(?:__webpack_require__|__rspack_context\.r|rspackRequire)\s*\(\s*[^)]*["']external["']/ - ); - expect(source.match(/external "external"/g)).toHaveLength(1); - - expect(process.__mixedExternalLoadCount).toBe(1); - expect(process.__mixedExternalValues).toHaveLength(2); - expect(process.__mixedExternalValues[0]).toBe( - process.__mixedExternalValues[1] - ); - - const requireBase = path.join(__dirname, "__external_runtime__.cjs"); - const safeUrl = pathToFileURL(path.join(options.output.path, "safe.mjs")).href; - const unsafeUrl = pathToFileURL( - path.join(options.output.path, "unsafe.mjs") - ).href; - const reverseOrderScript = ` - import { createRequire } from "node:module"; - globalThis.require = createRequire(${JSON.stringify(requireBase)}); - process.__mixedExternalLoadCount = 0; - process.__mixedExternalValues = []; - await import(${JSON.stringify(unsafeUrl)}); - await import(${JSON.stringify(safeUrl)}); - if ( - process.__mixedExternalLoadCount !== 1 || - process.__mixedExternalValues.length !== 2 || - process.__mixedExternalValues[0] !== process.__mixedExternalValues[1] - ) { - throw new Error("mixed direct and wrapped external should share identity"); - } - `; - execFileSync( - process.execPath, - ["--input-type=module", "--eval", reverseOrderScript], - { stdio: "pipe" } - ); - - const require = runtimeRequire(); - delete require.cache[require.resolve("external")]; - delete process.__mixedExternalLoadCount; - delete process.__mixedExternalValues; - } -}; diff --git a/tests/rspack-test/esmOutputCases/externals/commonjs-require-conditional/unsafe.cjs b/tests/rspack-test/esmOutputCases/externals/commonjs-require-conditional/unsafe.cjs deleted file mode 100644 index 5f535474cdee..000000000000 --- a/tests/rspack-test/esmOutputCases/externals/commonjs-require-conditional/unsafe.cjs +++ /dev/null @@ -1,13 +0,0 @@ -const selected = require( - globalThis.__USE_EXTERNAL__ ? "external" : "./local.cjs" -); - -const contextual = globalThis.__RUN_DYNAMIC_CONTEXT__ - ? require( - globalThis.__USE_CONTEXT_EXTERNAL__ - ? "external" - : "./" + globalThis.__LOCAL_MODULE__ - ) - : require("./local.cjs"); - -module.exports = { selected, contextual }; diff --git a/tests/rspack-test/esmOutputCases/externals/commonjs-require-conditional/warnings.js b/tests/rspack-test/esmOutputCases/externals/commonjs-require-conditional/warnings.js deleted file mode 100644 index a96e46cf5ef9..000000000000 --- a/tests/rspack-test/esmOutputCases/externals/commonjs-require-conditional/warnings.js +++ /dev/null @@ -1,3 +0,0 @@ -module.exports = [ - /Critical dependency: the request of a dependency is an expression/ -]; diff --git a/tests/rspack-test/esmOutputCases/externals/commonjs-require-direct/__snapshots__/esm.snap.txt b/tests/rspack-test/esmOutputCases/externals/commonjs-require-direct/__snapshots__/esm.snap.txt deleted file mode 100644 index 14cc8b0ef160..000000000000 --- a/tests/rspack-test/esmOutputCases/externals/commonjs-require-direct/__snapshots__/esm.snap.txt +++ /dev/null @@ -1,111 +0,0 @@ -```mjs title=entry-a.mjs -import { __webpack_require__ } from "./runtime.mjs"; - -__webpack_require__.add({ -"./consumer-a.cjs" -/*!************************!*\ - !*** ./consumer-a.cjs ***! - \************************/ -(__unused_rspack_module, exports) { -const first = require("external"); -const second = require("external"); -const viaModuleRequire = require("external"); -const constructed = new require("external"); -const { value } = require("external"); - -exports.first = first; -exports.second = second; -exports.viaModuleRequire = viaModuleRequire; -exports.constructed = constructed; -exports.destructured = value; -exports.method = (require("external").getValue)(); -exports.named = require("external"); -this.fromThis = require("external").value; - - -}, -}); -// ./entry-a.js -const consumer = __webpack_require__(/*! ./consumer-a.cjs */ "./consumer-a.cjs"); - -process.__commonjsExternalValues.push( - consumer.first, - consumer.second, - consumer.named, - consumer.viaModuleRequire, - consumer.constructed -); - -if ( - consumer.method !== 42 || - consumer.fromThis !== 42 || - consumer.destructured !== 42 -) { - throw new Error("direct CommonJS external member access should preserve semantics"); -} - -const value = consumer.first.value; - -export { value }; - -``` - -```mjs title=entry-b.mjs -import { __webpack_require__ } from "./runtime.mjs"; - -__webpack_require__.add({ -"./consumer-b.cjs" -/*!************************!*\ - !*** ./consumer-b.cjs ***! - \************************/ -(module) { -module.exports = require("external"); - - -}, -}); -// ./entry-b.js -const consumer = __webpack_require__(/*! ./consumer-b.cjs */ "./consumer-b.cjs"); - -process.__commonjsExternalValues.push(consumer); - -const value = consumer.value; - -export { value }; - -``` - -```mjs title=runtime.mjs - -var __webpack_modules__ = {}; -// The module cache -var __webpack_module_cache__ = {}; -// The require function -function __webpack_require__(moduleId) { -// Check if module is in cache -var cachedModule = __webpack_module_cache__[moduleId]; -if (cachedModule !== undefined) { -return cachedModule.exports; -} -// Create a new module (and put it into the cache) -var module = (__webpack_module_cache__[moduleId] = { -exports: {} -}); -// Execute the module function -__webpack_modules__[moduleId].call(module.exports, module, module.exports, __webpack_require__); - -// Return the exports of the module -return module.exports; -} -// expose the modules object (__webpack_modules__) -__webpack_require__.m = __webpack_modules__; - -// webpack/runtime/esm_register_module -(() => { -__webpack_require__.add = function registerModules(modules) { Object.assign(__webpack_require__.m, modules) } - -})(); - -export { __webpack_require__ }; - -``` \ No newline at end of file diff --git a/tests/rspack-test/esmOutputCases/externals/commonjs-require-direct/__snapshots__/runtimeModeSnapshot/esm.snap.txt b/tests/rspack-test/esmOutputCases/externals/commonjs-require-direct/__snapshots__/runtimeModeSnapshot/esm.snap.txt deleted file mode 100644 index abf41c56a9d0..000000000000 --- a/tests/rspack-test/esmOutputCases/externals/commonjs-require-direct/__snapshots__/runtimeModeSnapshot/esm.snap.txt +++ /dev/null @@ -1,108 +0,0 @@ -```mjs title=entry-a.mjs -import { rspackRequire, moduleFactories } from "./runtime.mjs"; -moduleFactories.add({ -"./consumer-a.cjs" -/*!************************!*\ - !*** ./consumer-a.cjs ***! - \************************/ -(__unused_rspack_module, exports) { -const first = require("external"); -const second = require("external"); -const viaModuleRequire = require("external"); -const constructed = new require("external"); -const { value } = require("external"); - -exports.first = first; -exports.second = second; -exports.viaModuleRequire = viaModuleRequire; -exports.constructed = constructed; -exports.destructured = value; -exports.method = (require("external").getValue)(); -exports.named = require("external"); -this.fromThis = require("external").value; - - -}, -}); -// ./entry-a.js -const consumer = rspackRequire(/*! ./consumer-a.cjs */ "./consumer-a.cjs"); - -process.__commonjsExternalValues.push( - consumer.first, - consumer.second, - consumer.named, - consumer.viaModuleRequire, - consumer.constructed -); - -if ( - consumer.method !== 42 || - consumer.fromThis !== 42 || - consumer.destructured !== 42 -) { - throw new Error("direct CommonJS external member access should preserve semantics"); -} - -const value = consumer.first.value; - -export { value }; - -``` - -```mjs title=entry-b.mjs -import { rspackRequire, moduleFactories } from "./runtime.mjs"; -moduleFactories.add({ -"./consumer-b.cjs" -/*!************************!*\ - !*** ./consumer-b.cjs ***! - \************************/ -(module) { -module.exports = require("external"); - - -}, -}); -// ./entry-b.js -const consumer = rspackRequire(/*! ./consumer-b.cjs */ "./consumer-b.cjs"); - -process.__commonjsExternalValues.push(consumer); - -const value = consumer.value; - -export { value }; - -``` - -```mjs title=runtime.mjs - -var modules = {}; -// The module cache -var moduleCache = {}; -// The require function -function rspackRequire(moduleId) { -// Check if module is in cache -var cachedModule = moduleCache[moduleId]; -if (cachedModule !== undefined) { -return cachedModule.exports; -} -// Create a new module (and put it into the cache) -var module = (moduleCache[moduleId] = { -exports: {} -}); -// Execute the module function -modules[moduleId].call(module.exports, module, module.exports, rspackRequire); - -// Return the exports of the module -return module.exports; -} -export { rspackRequire }; -// expose the modules object (modules) -var moduleFactories = modules; -export { moduleFactories }; - -// rspack/runtime/esm_register_module -moduleFactories.add = function registerModules(modules) { Object.assign(moduleFactories, modules) } -; - - -``` \ No newline at end of file diff --git a/tests/rspack-test/esmOutputCases/externals/commonjs-require-direct/consumer-a.cjs b/tests/rspack-test/esmOutputCases/externals/commonjs-require-direct/consumer-a.cjs deleted file mode 100644 index 1aec7a56d131..000000000000 --- a/tests/rspack-test/esmOutputCases/externals/commonjs-require-direct/consumer-a.cjs +++ /dev/null @@ -1,14 +0,0 @@ -const first = require("external"); -const second = require("external"); -const viaModuleRequire = module.require("external"); -const constructed = new require("external"); -const { value } = require("external"); - -exports.first = first; -exports.second = second; -exports.viaModuleRequire = viaModuleRequire; -exports.constructed = constructed; -exports.destructured = value; -exports.method = require("external").getValue(); -exports.named = require("external"); -this.fromThis = require("external").value; diff --git a/tests/rspack-test/esmOutputCases/externals/commonjs-require-direct/consumer-b.cjs b/tests/rspack-test/esmOutputCases/externals/commonjs-require-direct/consumer-b.cjs deleted file mode 100644 index 0f9cd4f1c1df..000000000000 --- a/tests/rspack-test/esmOutputCases/externals/commonjs-require-direct/consumer-b.cjs +++ /dev/null @@ -1 +0,0 @@ -module.exports = require("external"); diff --git a/tests/rspack-test/esmOutputCases/externals/commonjs-require-direct/entry-a.js b/tests/rspack-test/esmOutputCases/externals/commonjs-require-direct/entry-a.js deleted file mode 100644 index 9897a8da8b88..000000000000 --- a/tests/rspack-test/esmOutputCases/externals/commonjs-require-direct/entry-a.js +++ /dev/null @@ -1,19 +0,0 @@ -const consumer = require("./consumer-a.cjs"); - -process.__commonjsExternalValues.push( - consumer.first, - consumer.second, - consumer.named, - consumer.viaModuleRequire, - consumer.constructed -); - -if ( - consumer.method !== 42 || - consumer.fromThis !== 42 || - consumer.destructured !== 42 -) { - throw new Error("direct CommonJS external member access should preserve semantics"); -} - -export const value = consumer.first.value; diff --git a/tests/rspack-test/esmOutputCases/externals/commonjs-require-direct/entry-b.js b/tests/rspack-test/esmOutputCases/externals/commonjs-require-direct/entry-b.js deleted file mode 100644 index c3b30354442d..000000000000 --- a/tests/rspack-test/esmOutputCases/externals/commonjs-require-direct/entry-b.js +++ /dev/null @@ -1,5 +0,0 @@ -const consumer = require("./consumer-b.cjs"); - -process.__commonjsExternalValues.push(consumer); - -export const value = consumer.value; diff --git a/tests/rspack-test/esmOutputCases/externals/commonjs-require-direct/node_modules/external/index.js b/tests/rspack-test/esmOutputCases/externals/commonjs-require-direct/node_modules/external/index.js deleted file mode 100644 index 4f69bae222cb..000000000000 --- a/tests/rspack-test/esmOutputCases/externals/commonjs-require-direct/node_modules/external/index.js +++ /dev/null @@ -1,8 +0,0 @@ -process.__commonjsExternalLoadCount++; - -module.exports = { - value: 42, - getValue() { - return this.value; - } -}; diff --git a/tests/rspack-test/esmOutputCases/externals/commonjs-require-direct/node_modules/external/package.json b/tests/rspack-test/esmOutputCases/externals/commonjs-require-direct/node_modules/external/package.json deleted file mode 100644 index a9e27c9a5823..000000000000 --- a/tests/rspack-test/esmOutputCases/externals/commonjs-require-direct/node_modules/external/package.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "name": "external", - "version": "1.0.0", - "main": "index.js" -} diff --git a/tests/rspack-test/esmOutputCases/externals/commonjs-require-direct/rspack.config.js b/tests/rspack-test/esmOutputCases/externals/commonjs-require-direct/rspack.config.js deleted file mode 100644 index 4195aa4e7fb3..000000000000 --- a/tests/rspack-test/esmOutputCases/externals/commonjs-require-direct/rspack.config.js +++ /dev/null @@ -1,9 +0,0 @@ -module.exports = { - entry: { - 'entry-a': './entry-a.js', - 'entry-b': './entry-b.js', - }, - externals: { - external: 'commonjs external', - }, -}; diff --git a/tests/rspack-test/esmOutputCases/externals/commonjs-require-direct/test.config.js b/tests/rspack-test/esmOutputCases/externals/commonjs-require-direct/test.config.js deleted file mode 100644 index f40715c8978c..000000000000 --- a/tests/rspack-test/esmOutputCases/externals/commonjs-require-direct/test.config.js +++ /dev/null @@ -1,83 +0,0 @@ -const fs = require("fs"); -const path = require("path"); -const { execFileSync } = require("child_process"); -const { createRequire } = require("module"); -const { pathToFileURL } = require("url"); - -function runtimeRequire() { - return createRequire(path.join(__dirname, "__external_runtime__.cjs")); -} - -function readOutput(options, file) { - return fs.readFileSync(path.join(options.output.path, file), "utf-8"); -} - -module.exports = { - beforeExecute() { - const require = runtimeRequire(); - delete require.cache[require.resolve("external")]; - process.__commonjsExternalLoadCount = 0; - process.__commonjsExternalValues = []; - }, - findBundle() { - return ["entry-a.mjs", "entry-b.mjs"]; - }, - moduleScope(scope) { - scope.require = runtimeRequire(); - }, - afterExecute(options) { - const entryA = readOutput(options, "entry-a.mjs"); - const entryB = readOutput(options, "entry-b.mjs"); - const source = `${entryA}\n${entryB}`; - - expect(entryA).toMatch( - /const\s+first\s*=\s*require\s*\(\s*["']external["']\s*\)/ - ); - expect(entryB).toMatch( - /module\.exports\s*=\s*require\s*\(\s*["']external["']\s*\)/ - ); - expect(source).not.toContain('external "external"'); - expect(source).not.toMatch( - /(?:__webpack_require__|__rspack_context\.r|rspackRequire)\s*\(\s*[^)]*["']external["']/ - ); - - expect(process.__commonjsExternalLoadCount).toBe(1); - expect(process.__commonjsExternalValues).toHaveLength(6); - for (const value of process.__commonjsExternalValues) { - expect(value).toBe(process.__commonjsExternalValues[0]); - } - - const requireBase = path.join(__dirname, "__external_runtime__.cjs"); - const entryAUrl = pathToFileURL(path.join(options.output.path, "entry-a.mjs")).href; - const entryBUrl = pathToFileURL(path.join(options.output.path, "entry-b.mjs")).href; - const reverseOrderScript = ` - import { createRequire } from "node:module"; - globalThis.require = createRequire(${JSON.stringify(requireBase)}); - process.__commonjsExternalLoadCount = 0; - process.__commonjsExternalValues = []; - await import(${JSON.stringify(entryBUrl)}); - await import(${JSON.stringify(entryAUrl)}); - if (process.__commonjsExternalLoadCount !== 1) { - throw new Error("external should initialize once in reverse entry order"); - } - if ( - process.__commonjsExternalValues.length !== 6 || - !process.__commonjsExternalValues.every( - value => value === process.__commonjsExternalValues[0] - ) - ) { - throw new Error("external identity should be shared in reverse entry order"); - } - `; - execFileSync( - process.execPath, - ["--input-type=module", "--eval", reverseOrderScript], - { stdio: "pipe" } - ); - - const require = runtimeRequire(); - delete require.cache[require.resolve("external")]; - delete process.__commonjsExternalLoadCount; - delete process.__commonjsExternalValues; - } -}; diff --git a/tests/rspack-test/esmOutputCases/externals/commonjs-require-optional/__snapshots__/esm.snap.txt b/tests/rspack-test/esmOutputCases/externals/commonjs-require-optional/__snapshots__/esm.snap.txt deleted file mode 100644 index 8f345a4219c1..000000000000 --- a/tests/rspack-test/esmOutputCases/externals/commonjs-require-optional/__snapshots__/esm.snap.txt +++ /dev/null @@ -1,82 +0,0 @@ -```mjs title=main.mjs -import { __webpack_require__ } from "./runtime.mjs"; - -__webpack_require__.add({ -"missing-external" -/*!***********************************!*\ - !*** external "missing-external" ***! - \***********************************/ -(module) { -module.exports = require("missing-external"); - -}, -"optional-external" -/*!************************************!*\ - !*** external "optional-external" ***! - \************************************/ -(module) { -module.exports = require("optional-external"); - -}, -}); -// ./index.js -let value; -let missing; - -try { - value = (__webpack_require__(/*! optional-external */ "optional-external")/* .value */.value); -} catch { - value = -1; -} - -try { - __webpack_require__(/*! missing-external */ "missing-external"); - missing = false; -} catch { - missing = true; -} - -if (value !== 42 || !missing) { - throw new Error("optional external should keep working through the wrapper path"); -} - - - -export { missing, value }; - -``` - -```mjs title=runtime.mjs - -var __webpack_modules__ = {}; -// The module cache -var __webpack_module_cache__ = {}; -// The require function -function __webpack_require__(moduleId) { -// Check if module is in cache -var cachedModule = __webpack_module_cache__[moduleId]; -if (cachedModule !== undefined) { -return cachedModule.exports; -} -// Create a new module (and put it into the cache) -var module = (__webpack_module_cache__[moduleId] = { -exports: {} -}); -// Execute the module function -__webpack_modules__[moduleId](module, module.exports, __webpack_require__); - -// Return the exports of the module -return module.exports; -} -// expose the modules object (__webpack_modules__) -__webpack_require__.m = __webpack_modules__; - -// webpack/runtime/esm_register_module -(() => { -__webpack_require__.add = function registerModules(modules) { Object.assign(__webpack_require__.m, modules) } - -})(); - -export { __webpack_require__ }; - -``` \ No newline at end of file diff --git a/tests/rspack-test/esmOutputCases/externals/commonjs-require-optional/__snapshots__/runtimeModeSnapshot/esm.snap.txt b/tests/rspack-test/esmOutputCases/externals/commonjs-require-optional/__snapshots__/runtimeModeSnapshot/esm.snap.txt deleted file mode 100644 index 9ac1eb7d6fec..000000000000 --- a/tests/rspack-test/esmOutputCases/externals/commonjs-require-optional/__snapshots__/runtimeModeSnapshot/esm.snap.txt +++ /dev/null @@ -1,80 +0,0 @@ -```mjs title=main.mjs -import { rspackRequire, moduleFactories } from "./runtime.mjs"; -moduleFactories.add({ -"missing-external" -/*!***********************************!*\ - !*** external "missing-external" ***! - \***********************************/ -(module) { -module.exports = require("missing-external"); - -}, -"optional-external" -/*!************************************!*\ - !*** external "optional-external" ***! - \************************************/ -(module) { -module.exports = require("optional-external"); - -}, -}); -// ./index.js -let value; -let missing; - -try { - value = (rspackRequire(/*! optional-external */ "optional-external")/* .value */.value); -} catch { - value = -1; -} - -try { - rspackRequire(/*! missing-external */ "missing-external"); - missing = false; -} catch { - missing = true; -} - -if (value !== 42 || !missing) { - throw new Error("optional external should keep working through the wrapper path"); -} - - - -export { missing, value }; - -``` - -```mjs title=runtime.mjs - -var modules = {}; -// The module cache -var moduleCache = {}; -// The require function -function rspackRequire(moduleId) { -// Check if module is in cache -var cachedModule = moduleCache[moduleId]; -if (cachedModule !== undefined) { -return cachedModule.exports; -} -// Create a new module (and put it into the cache) -var module = (moduleCache[moduleId] = { -exports: {} -}); -// Execute the module function -modules[moduleId](module, module.exports, rspackRequire); - -// Return the exports of the module -return module.exports; -} -export { rspackRequire }; -// expose the modules object (modules) -var moduleFactories = modules; -export { moduleFactories }; - -// rspack/runtime/esm_register_module -moduleFactories.add = function registerModules(modules) { Object.assign(moduleFactories, modules) } -; - - -``` \ No newline at end of file diff --git a/tests/rspack-test/esmOutputCases/externals/commonjs-require-optional/index.js b/tests/rspack-test/esmOutputCases/externals/commonjs-require-optional/index.js deleted file mode 100644 index 59bf15e3794e..000000000000 --- a/tests/rspack-test/esmOutputCases/externals/commonjs-require-optional/index.js +++ /dev/null @@ -1,21 +0,0 @@ -let value; -let missing; - -try { - value = require("optional-external").value; -} catch { - value = -1; -} - -try { - require("missing-external"); - missing = false; -} catch { - missing = true; -} - -if (value !== 42 || !missing) { - throw new Error("optional external should keep working through the wrapper path"); -} - -export { value, missing }; diff --git a/tests/rspack-test/esmOutputCases/externals/commonjs-require-optional/node_modules/optional-external/index.js b/tests/rspack-test/esmOutputCases/externals/commonjs-require-optional/node_modules/optional-external/index.js deleted file mode 100644 index 885c586e241b..000000000000 --- a/tests/rspack-test/esmOutputCases/externals/commonjs-require-optional/node_modules/optional-external/index.js +++ /dev/null @@ -1,3 +0,0 @@ -module.exports = { - value: 42 -}; diff --git a/tests/rspack-test/esmOutputCases/externals/commonjs-require-optional/node_modules/optional-external/package.json b/tests/rspack-test/esmOutputCases/externals/commonjs-require-optional/node_modules/optional-external/package.json deleted file mode 100644 index 7a5aa5d008ab..000000000000 --- a/tests/rspack-test/esmOutputCases/externals/commonjs-require-optional/node_modules/optional-external/package.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "name": "optional-external", - "version": "1.0.0", - "main": "index.js" -} diff --git a/tests/rspack-test/esmOutputCases/externals/commonjs-require-optional/rspack.config.js b/tests/rspack-test/esmOutputCases/externals/commonjs-require-optional/rspack.config.js deleted file mode 100644 index ed631916d779..000000000000 --- a/tests/rspack-test/esmOutputCases/externals/commonjs-require-optional/rspack.config.js +++ /dev/null @@ -1,6 +0,0 @@ -module.exports = { - externals: { - 'optional-external': 'commonjs optional-external', - 'missing-external': 'commonjs missing-external', - }, -}; diff --git a/tests/rspack-test/esmOutputCases/externals/commonjs-require-optional/test.config.js b/tests/rspack-test/esmOutputCases/externals/commonjs-require-optional/test.config.js deleted file mode 100644 index f6cd522e1fee..000000000000 --- a/tests/rspack-test/esmOutputCases/externals/commonjs-require-optional/test.config.js +++ /dev/null @@ -1,38 +0,0 @@ -const fs = require("fs"); -const path = require("path"); -const { createRequire } = require("module"); - -function runtimeRequire() { - return createRequire(path.join(__dirname, "__external_runtime__.cjs")); -} - -module.exports = { - beforeExecute() { - const require = runtimeRequire(); - delete require.cache[require.resolve("optional-external")]; - }, - moduleScope(scope) { - scope.require = runtimeRequire(); - }, - afterExecute(options) { - const source = fs.readFileSync( - path.join(options.output.path, "main.mjs"), - "utf-8" - ); - - expect(source).toContain('external "optional-external"'); - expect(source).toContain('external "missing-external"'); - expect(source).toMatch( - /(?:__webpack_require__|__rspack_context\.r|rspackRequire)\s*\(\s*[^)]*["']optional-external["']/ - ); - expect(source).toMatch( - /(?:__webpack_require__|__rspack_context\.r|rspackRequire)\s*\(\s*[^)]*["']missing-external["']/ - ); - expect(source).not.toMatch( - /value\s*=\s*require\s*\(\s*["']optional-external["']\s*\)/ - ); - - const require = runtimeRequire(); - delete require.cache[require.resolve("optional-external")]; - } -}; diff --git a/tests/rspack-test/esmOutputCases/externals/commonjs-require-request-rest/__snapshots__/esm.snap.txt b/tests/rspack-test/esmOutputCases/externals/commonjs-require-request-rest/__snapshots__/esm.snap.txt deleted file mode 100644 index e3cdf01d6bf4..000000000000 --- a/tests/rspack-test/esmOutputCases/externals/commonjs-require-request-rest/__snapshots__/esm.snap.txt +++ /dev/null @@ -1,60 +0,0 @@ -```mjs title=main.mjs -import { __webpack_require__ } from "./runtime.mjs"; - -__webpack_require__.add({ -"external-value" -/*!*************************************!*\ - !*** external ["external","value"] ***! - \*************************************/ -(module) { -module.exports = require("external").value; - -}, -}); -// ./index.js -const value = __webpack_require__(/*! external-value */ "external-value"); - -if (value !== 42) { - throw new Error("external request rest segments should keep their wrapper semantics"); -} - - - -export { value }; - -``` - -```mjs title=runtime.mjs - -var __webpack_modules__ = {}; -// The module cache -var __webpack_module_cache__ = {}; -// The require function -function __webpack_require__(moduleId) { -// Check if module is in cache -var cachedModule = __webpack_module_cache__[moduleId]; -if (cachedModule !== undefined) { -return cachedModule.exports; -} -// Create a new module (and put it into the cache) -var module = (__webpack_module_cache__[moduleId] = { -exports: {} -}); -// Execute the module function -__webpack_modules__[moduleId](module, module.exports, __webpack_require__); - -// Return the exports of the module -return module.exports; -} -// expose the modules object (__webpack_modules__) -__webpack_require__.m = __webpack_modules__; - -// webpack/runtime/esm_register_module -(() => { -__webpack_require__.add = function registerModules(modules) { Object.assign(__webpack_require__.m, modules) } - -})(); - -export { __webpack_require__ }; - -``` \ No newline at end of file diff --git a/tests/rspack-test/esmOutputCases/externals/commonjs-require-request-rest/__snapshots__/runtimeModeSnapshot/esm.snap.txt b/tests/rspack-test/esmOutputCases/externals/commonjs-require-request-rest/__snapshots__/runtimeModeSnapshot/esm.snap.txt deleted file mode 100644 index ce7938402925..000000000000 --- a/tests/rspack-test/esmOutputCases/externals/commonjs-require-request-rest/__snapshots__/runtimeModeSnapshot/esm.snap.txt +++ /dev/null @@ -1,58 +0,0 @@ -```mjs title=main.mjs -import { rspackRequire, moduleFactories } from "./runtime.mjs"; -moduleFactories.add({ -"external-value" -/*!*************************************!*\ - !*** external ["external","value"] ***! - \*************************************/ -(module) { -module.exports = require("external").value; - -}, -}); -// ./index.js -const value = rspackRequire(/*! external-value */ "external-value"); - -if (value !== 42) { - throw new Error("external request rest segments should keep their wrapper semantics"); -} - - - -export { value }; - -``` - -```mjs title=runtime.mjs - -var modules = {}; -// The module cache -var moduleCache = {}; -// The require function -function rspackRequire(moduleId) { -// Check if module is in cache -var cachedModule = moduleCache[moduleId]; -if (cachedModule !== undefined) { -return cachedModule.exports; -} -// Create a new module (and put it into the cache) -var module = (moduleCache[moduleId] = { -exports: {} -}); -// Execute the module function -modules[moduleId](module, module.exports, rspackRequire); - -// Return the exports of the module -return module.exports; -} -export { rspackRequire }; -// expose the modules object (modules) -var moduleFactories = modules; -export { moduleFactories }; - -// rspack/runtime/esm_register_module -moduleFactories.add = function registerModules(modules) { Object.assign(moduleFactories, modules) } -; - - -``` \ No newline at end of file diff --git a/tests/rspack-test/esmOutputCases/externals/commonjs-require-request-rest/index.js b/tests/rspack-test/esmOutputCases/externals/commonjs-require-request-rest/index.js deleted file mode 100644 index 932a83ce7f3d..000000000000 --- a/tests/rspack-test/esmOutputCases/externals/commonjs-require-request-rest/index.js +++ /dev/null @@ -1,7 +0,0 @@ -const value = require("external-value"); - -if (value !== 42) { - throw new Error("external request rest segments should keep their wrapper semantics"); -} - -export { value }; diff --git a/tests/rspack-test/esmOutputCases/externals/commonjs-require-request-rest/node_modules/external/index.js b/tests/rspack-test/esmOutputCases/externals/commonjs-require-request-rest/node_modules/external/index.js deleted file mode 100644 index 885c586e241b..000000000000 --- a/tests/rspack-test/esmOutputCases/externals/commonjs-require-request-rest/node_modules/external/index.js +++ /dev/null @@ -1,3 +0,0 @@ -module.exports = { - value: 42 -}; diff --git a/tests/rspack-test/esmOutputCases/externals/commonjs-require-request-rest/node_modules/external/package.json b/tests/rspack-test/esmOutputCases/externals/commonjs-require-request-rest/node_modules/external/package.json deleted file mode 100644 index a9e27c9a5823..000000000000 --- a/tests/rspack-test/esmOutputCases/externals/commonjs-require-request-rest/node_modules/external/package.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "name": "external", - "version": "1.0.0", - "main": "index.js" -} diff --git a/tests/rspack-test/esmOutputCases/externals/commonjs-require-request-rest/rspack.config.js b/tests/rspack-test/esmOutputCases/externals/commonjs-require-request-rest/rspack.config.js deleted file mode 100644 index 5f12c9514c8a..000000000000 --- a/tests/rspack-test/esmOutputCases/externals/commonjs-require-request-rest/rspack.config.js +++ /dev/null @@ -1,5 +0,0 @@ -module.exports = { - externals: { - 'external-value': ['commonjs external', 'value'], - }, -}; diff --git a/tests/rspack-test/esmOutputCases/externals/commonjs-require-request-rest/test.config.js b/tests/rspack-test/esmOutputCases/externals/commonjs-require-request-rest/test.config.js deleted file mode 100644 index 7c12c430c784..000000000000 --- a/tests/rspack-test/esmOutputCases/externals/commonjs-require-request-rest/test.config.js +++ /dev/null @@ -1,24 +0,0 @@ -const fs = require("fs"); -const path = require("path"); -const { createRequire } = require("module"); - -function runtimeRequire() { - return createRequire(path.join(__dirname, "__external_runtime__.cjs")); -} - -module.exports = { - moduleScope(scope) { - scope.require = runtimeRequire(); - }, - afterExecute(options) { - const source = fs.readFileSync( - path.join(options.output.path, "main.mjs"), - "utf-8" - ); - - expect(source).toContain('external ["external","value"]'); - expect(source).toMatch( - /(?:__webpack_require__|__rspack_context\.r|rspackRequire)\s*\(\s*[^)]*["']external-value["']/ - ); - } -}; diff --git a/tests/rspack-test/esmOutputCases/externals/esm-node-target-alias/__snapshots__/esm.snap.txt b/tests/rspack-test/esmOutputCases/externals/esm-node-target-alias/__snapshots__/esm.snap.txt index c629af6abbb7..7a13a9bbe52e 100644 --- a/tests/rspack-test/esmOutputCases/externals/esm-node-target-alias/__snapshots__/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/externals/esm-node-target-alias/__snapshots__/esm.snap.txt @@ -13,14 +13,11 @@ __webpack_require__.add({ (__unused_rspack_module, exports) { // CJS require of "module" type external — should be downgraded to node-commonjs const nodePath = __rspack_createRequire_require("node:path"); -exports.nq = nodePath.resolve; +exports.n = nodePath.resolve; // CJS require of "module-import" type external — should also be downgraded const nodeUrl = __rspack_createRequire_require("node:url"); -exports.gd = nodeUrl.parse; - -// CJS export-require dependency should use the same node-commonjs downgrade -exports.M = __rspack_createRequire_require("node:path"); +exports.g = nodeUrl.parse; }, @@ -31,9 +28,8 @@ exports.M = __rspack_createRequire_require("node:path"); // ./index.js const cjs_consumer = __webpack_require__("./cjs-consumer.cjs"); -var gd = cjs_consumer.gd; -var M = cjs_consumer.M; -var nq = cjs_consumer.nq; +var g = cjs_consumer.g; +var n = cjs_consumer.n; @@ -52,21 +48,17 @@ it("should use aliased external request with correct external type", async () => expect(main.parse).toBe(nodeUrl.parse); // CJS require of "module" external — downgraded to node-commonjs - expect(cjs_consumer.nq).toBe(nodePath.resolve); + expect(cjs_consumer.n).toBe(nodePath.resolve); expect(main.cjsResolve).toBe(nodePath.resolve); // CJS require of "module-import" external — downgraded to node-commonjs - expect(cjs_consumer.gd).toBe(nodeUrl.parse); + expect(cjs_consumer.g).toBe(nodeUrl.parse); expect(main.cjsParse).toBe(nodeUrl.parse); - - // CJS export-require dependency — also downgraded to node-commonjs - expect(cjs_consumer.M.resolve).toBe(nodePath.resolve); - expect(main.cjsReexport.resolve).toBe(nodePath.resolve); }); -export { M as cjsReexport, gd as cjsParse, nq as cjsResolve, parse, resolve }; +export { g as cjsParse, n as cjsResolve, parse, resolve }; ``` diff --git a/tests/rspack-test/esmOutputCases/externals/esm-node-target-alias/__snapshots__/runtimeModeSnapshot/esm.snap.txt b/tests/rspack-test/esmOutputCases/externals/esm-node-target-alias/__snapshots__/runtimeModeSnapshot/esm.snap.txt index eefaf9e99393..afdfacc201f0 100644 --- a/tests/rspack-test/esmOutputCases/externals/esm-node-target-alias/__snapshots__/runtimeModeSnapshot/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/externals/esm-node-target-alias/__snapshots__/runtimeModeSnapshot/esm.snap.txt @@ -13,14 +13,11 @@ moduleFactories.add({ (__unused_rspack_module, exports) { // CJS require of "module" type external — should be downgraded to node-commonjs const nodePath = __rspack_createRequire_require("node:path"); -exports.nq = nodePath.resolve; +exports.n = nodePath.resolve; // CJS require of "module-import" type external — should also be downgraded const nodeUrl = __rspack_createRequire_require("node:url"); -exports.gd = nodeUrl.parse; - -// CJS export-require dependency should use the same node-commonjs downgrade -exports.M = __rspack_createRequire_require("node:path"); +exports.g = nodeUrl.parse; }, @@ -31,9 +28,8 @@ exports.M = __rspack_createRequire_require("node:path"); // ./index.js const cjs_consumer = rspackRequire("./cjs-consumer.cjs"); -var gd = cjs_consumer.gd; -var M = cjs_consumer.M; -var nq = cjs_consumer.nq; +var g = cjs_consumer.g; +var n = cjs_consumer.n; @@ -52,21 +48,17 @@ it("should use aliased external request with correct external type", async () => expect(main.parse).toBe(nodeUrl.parse); // CJS require of "module" external — downgraded to node-commonjs - expect(cjs_consumer.nq).toBe(nodePath.resolve); + expect(cjs_consumer.n).toBe(nodePath.resolve); expect(main.cjsResolve).toBe(nodePath.resolve); // CJS require of "module-import" external — downgraded to node-commonjs - expect(cjs_consumer.gd).toBe(nodeUrl.parse); + expect(cjs_consumer.g).toBe(nodeUrl.parse); expect(main.cjsParse).toBe(nodeUrl.parse); - - // CJS export-require dependency — also downgraded to node-commonjs - expect(cjs_consumer.M.resolve).toBe(nodePath.resolve); - expect(main.cjsReexport.resolve).toBe(nodePath.resolve); }); -export { M as cjsReexport, gd as cjsParse, nq as cjsResolve, parse, resolve }; +export { g as cjsParse, n as cjsResolve, parse, resolve }; ``` diff --git a/tests/rspack-test/esmOutputCases/externals/esm-node-target-alias/cjs-consumer.cjs b/tests/rspack-test/esmOutputCases/externals/esm-node-target-alias/cjs-consumer.cjs index f883d2049f6b..5dedff5bc53c 100644 --- a/tests/rspack-test/esmOutputCases/externals/esm-node-target-alias/cjs-consumer.cjs +++ b/tests/rspack-test/esmOutputCases/externals/esm-node-target-alias/cjs-consumer.cjs @@ -5,6 +5,3 @@ exports.cjsResolve = nodePath.resolve; // CJS require of "module-import" type external — should also be downgraded const nodeUrl = require("node:url"); exports.cjsParse = nodeUrl.parse; - -// CJS export-require dependency should use the same node-commonjs downgrade -exports.cjsReexport = require("node:fs"); diff --git a/tests/rspack-test/esmOutputCases/externals/esm-node-target-alias/index.js b/tests/rspack-test/esmOutputCases/externals/esm-node-target-alias/index.js index 40560c0e73a4..5d7a5d768eee 100644 --- a/tests/rspack-test/esmOutputCases/externals/esm-node-target-alias/index.js +++ b/tests/rspack-test/esmOutputCases/externals/esm-node-target-alias/index.js @@ -1,6 +1,6 @@ import { resolve } from "node:fs"; import { parse } from "node:url"; -import { cjsResolve, cjsParse, cjsReexport } from "./cjs-consumer.cjs"; +import { cjsResolve, cjsParse } from "./cjs-consumer.cjs"; it("should use aliased external request with correct external type", async () => { const main = await import(/* webpackIgnore: true */ "./main.mjs"); @@ -22,10 +22,6 @@ it("should use aliased external request with correct external type", async () => // CJS require of "module-import" external — downgraded to node-commonjs expect(cjsParse).toBe(nodeUrl.parse); expect(main.cjsParse).toBe(nodeUrl.parse); - - // CJS export-require dependency — also downgraded to node-commonjs - expect(cjsReexport.resolve).toBe(nodePath.resolve); - expect(main.cjsReexport.resolve).toBe(nodePath.resolve); }); -export { resolve, parse, cjsResolve, cjsParse, cjsReexport }; +export { resolve, parse, cjsResolve, cjsParse }; diff --git a/tests/rspack-test/esmOutputCases/externals/esm-node-target-alias/rspack.config.mjs b/tests/rspack-test/esmOutputCases/externals/esm-node-target-alias/rspack.config.mjs index 99788ac554f6..798934412bba 100644 --- a/tests/rspack-test/esmOutputCases/externals/esm-node-target-alias/rspack.config.mjs +++ b/tests/rspack-test/esmOutputCases/externals/esm-node-target-alias/rspack.config.mjs @@ -6,9 +6,8 @@ const { /** @type {import("@rspack/core").Configuration} */ export default { - externalsType: 'module', externals: { - 'node:fs': { module: 'node:path' }, + 'node:fs': 'module node:path', 'node:url': 'module-import node:url', }, plugins: [ diff --git a/tests/rspack-test/esmOutputCases/externals/modern-module-explicit-node/index.js b/tests/rspack-test/esmOutputCases/externals/modern-module-explicit-node/index.js index 8c634237df44..a68a55be1df9 100644 --- a/tests/rspack-test/esmOutputCases/externals/modern-module-explicit-node/index.js +++ b/tests/rspack-test/esmOutputCases/externals/modern-module-explicit-node/index.js @@ -3,7 +3,6 @@ import { resolve } from "path"; const fs = require("fs"); export const readFile = fs.readFile; -export const stat = require("fs").stat; export const pathResolve = resolve; export async function loadPlatform() { diff --git a/tests/rspack-test/esmOutputCases/externals/modern-module-explicit-node/test.config.mjs b/tests/rspack-test/esmOutputCases/externals/modern-module-explicit-node/test.config.mjs index 5c33d8ee8047..2412beceb400 100644 --- a/tests/rspack-test/esmOutputCases/externals/modern-module-explicit-node/test.config.mjs +++ b/tests/rspack-test/esmOutputCases/externals/modern-module-explicit-node/test.config.mjs @@ -23,12 +23,7 @@ export default { expect(source).toMatch(/import\s*\(\s*["']os["']\s*\)/); expect(source).toMatch(/createRequire\s+as\s+__rspack_createRequire/); expect(source).toMatch( - /const\s+fs\s*=\s*__rspack_createRequire_require\s*\(\s*["']fs["']\s*\)/ - ); - expect(source).not.toContain('external "fs"'); - expect(source).not.toMatch(/__webpack_require__\s*\(\s*[^)]*["']fs["']/); - expect(source).toMatch( - /__rspack_createRequire_require\s*\(\s*["']fs["']\s*\)\.stat/ + /__rspack_createRequire_require\s*\(\s*["']fs["']\s*\)/ ); } }; diff --git a/tests/rspack-test/esmOutputCases/externals/node-commonjs-relative-request/__snapshots__/esm.snap.txt b/tests/rspack-test/esmOutputCases/externals/node-commonjs-relative-request/__snapshots__/esm.snap.txt deleted file mode 100644 index 974c7e2c3cfd..000000000000 --- a/tests/rspack-test/esmOutputCases/externals/node-commonjs-relative-request/__snapshots__/esm.snap.txt +++ /dev/null @@ -1,172 +0,0 @@ -```mjs title=chunks/lazy.mjs -import { __webpack_require__ } from "../runtime.mjs"; -import "../index_js-relative-external-package-external.mjs"; - -__webpack_require__.add({ -"./lazy.cjs" -/*!******************!*\ - !*** ./lazy.cjs ***! - \******************/ -(__unused_rspack_module, exports, __webpack_require__) { -exports.relativeValue = __webpack_require__(/*! relative-external */ "relative-external")/* .value */.value; -exports.packageValue = __webpack_require__(/*! package-external */ "package-external")/* .value */.value; - - -}, -}); -const lazy = __webpack_require__("./lazy.cjs"); -var lazy_default = /*#__PURE__*/__webpack_require__.n(lazy); -var lazy_default_0 = lazy_default(); -var packageValue = lazy.packageValue; -var relativeValue = lazy.relativeValue; - -export { packageValue, relativeValue }; -export default lazy_default_0; - -``` - -```mjs title=index_js-relative-external-package-external.mjs -import { __webpack_require__ } from "./runtime.mjs"; - -import { createRequire as __rspack_createRequire } from "node:module"; -const __rspack_createRequire_require = __rspack_createRequire(import.meta.url); -__webpack_require__.add({ -"relative-external" -/*!*********************************!*\ - !*** external "./external.cjs" ***! - \*********************************/ -(module) { -module.exports = __rspack_createRequire_require("./external.cjs"); - -}, -"package-external" -/*!*****************************!*\ - !*** external "shadow-pkg" ***! - \*****************************/ -(module) { -module.exports = __rspack_createRequire_require("shadow-pkg"); - -}, -}); -// ./index.js -it("should preserve the resolution base for node-commonjs externals", async () => { - const { relativeValue, packageValue } = await import("./chunks/lazy.mjs").then(__webpack_require__.t.bind(__webpack_require__, /*! ./lazy.cjs */ "./lazy.cjs", 19)); - - expect(relativeValue).toBe(42); - expect(packageValue).toBe("root"); -}); - -export {}; - -``` - -```mjs title=main.mjs -import "./index_js-relative-external-package-external.mjs"; - -export {}; - -``` - -```mjs title=runtime.mjs - -var __webpack_modules__ = {}; -// The module cache -var __webpack_module_cache__ = {}; -// The require function -function __webpack_require__(moduleId) { -// Check if module is in cache -var cachedModule = __webpack_module_cache__[moduleId]; -if (cachedModule !== undefined) { -return cachedModule.exports; -} -// Create a new module (and put it into the cache) -var module = (__webpack_module_cache__[moduleId] = { -exports: {} -}); -// Execute the module function -__webpack_modules__[moduleId](module, module.exports, __webpack_require__); - -// Return the exports of the module -return module.exports; -} -// expose the modules object (__webpack_modules__) -__webpack_require__.m = __webpack_modules__; - -// webpack/runtime/compat_get_default_export -(() => { -// getDefaultExport function for compatibility with non-ESM modules -__webpack_require__.n = (module) => { - var getter = module && module.__esModule ? - () => (module['default']) : - () => (module); - __webpack_require__.d(getter, { a: getter }); - return getter; -}; - -})(); -// webpack/runtime/create_fake_namespace_object -(() => { -var getProto = Object.getPrototypeOf ? (obj) => (Object.getPrototypeOf(obj)) : (obj) => (obj.__proto__); -var leafPrototypes; -// create a fake namespace object -// mode & 1: value is a module id, require it -// mode & 2: merge all properties of value into the ns -// mode & 4: return value when already ns object -// mode & 16: return value when it's Promise-like -// mode & 8|1: behave like require -__webpack_require__.t = function(value, mode) { - if(mode & 1) value = this(value); - if(mode & 8) return value; - if(typeof value === 'object' && value) { - if((mode & 4) && value.__esModule) return value; - if((mode & 16) && typeof value.then === 'function') return value; - } - var ns = Object.create(null); - __webpack_require__.r(ns); - var def = {}; - leafPrototypes = leafPrototypes || [null, getProto({}), getProto([]), getProto(getProto)]; - for(var current = mode & 2 && value; (typeof current == 'object' || typeof current == 'function') && !~leafPrototypes.indexOf(current); current = getProto(current)) { - Object.getOwnPropertyNames(current).forEach((key) => { def[key] = () => (value[key]) }); - } - def['default'] = () => (value); - __webpack_require__.d(ns, def); - return ns; -}; -})(); -// webpack/runtime/define_property_getters -(() => { -__webpack_require__.d = (exports, getters, values) => { - var define = (defs, kind) => { - for(var key in defs) { - if(__webpack_require__.o(defs, key) && !__webpack_require__.o(exports, key)) { - Object.defineProperty(exports, key, { enumerable: true, [kind]: defs[key] }); - } - } - }; - define(getters, "get"); - define(values, "value"); -}; -})(); -// webpack/runtime/esm_register_module -(() => { -__webpack_require__.add = function registerModules(modules) { Object.assign(__webpack_require__.m, modules) } - -})(); -// webpack/runtime/has_own_property -(() => { -__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop)) -})(); -// webpack/runtime/make_namespace_object -(() => { -// define __esModule on exports -__webpack_require__.r = (exports) => { - if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { - Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); - } - Object.defineProperty(exports, '__esModule', { value: true }); -}; -})(); - -export { __webpack_require__ }; - -``` \ No newline at end of file diff --git a/tests/rspack-test/esmOutputCases/externals/node-commonjs-relative-request/__snapshots__/runtimeModeSnapshot/esm.snap.txt b/tests/rspack-test/esmOutputCases/externals/node-commonjs-relative-request/__snapshots__/runtimeModeSnapshot/esm.snap.txt deleted file mode 100644 index 168c2af6237e..000000000000 --- a/tests/rspack-test/esmOutputCases/externals/node-commonjs-relative-request/__snapshots__/runtimeModeSnapshot/esm.snap.txt +++ /dev/null @@ -1,162 +0,0 @@ -```mjs title=chunks/lazy.mjs -import { rspackRequire, moduleFactories, compatGetDefaultExport } from "../runtime.mjs"; -import "../index_js-relative-external-package-external.mjs"; - -moduleFactories.add({ -"./lazy.cjs" -/*!******************!*\ - !*** ./lazy.cjs ***! - \******************/ -(__unused_rspack_module, exports) { -exports.relativeValue = rspackRequire(/*! relative-external */ "relative-external")/* .value */.value; -exports.packageValue = rspackRequire(/*! package-external */ "package-external")/* .value */.value; - - -}, -}); -const lazy = rspackRequire("./lazy.cjs"); -var lazy_default = /*#__PURE__*/compatGetDefaultExport(lazy); -var lazy_default_0 = lazy_default(); -var packageValue = lazy.packageValue; -var relativeValue = lazy.relativeValue; - -export { packageValue, relativeValue }; -export default lazy_default_0; - -``` - -```mjs title=index_js-relative-external-package-external.mjs -import { rspackRequire, moduleFactories, createFakeNamespaceObject } from "./runtime.mjs"; -import { createRequire as __rspack_createRequire } from "node:module"; -const __rspack_createRequire_require = __rspack_createRequire(import.meta.url); -moduleFactories.add({ -"relative-external" -/*!*********************************!*\ - !*** external "./external.cjs" ***! - \*********************************/ -(module) { -module.exports = __rspack_createRequire_require("./external.cjs"); - -}, -"package-external" -/*!*****************************!*\ - !*** external "shadow-pkg" ***! - \*****************************/ -(module) { -module.exports = __rspack_createRequire_require("shadow-pkg"); - -}, -}); -// ./index.js -it("should preserve the resolution base for node-commonjs externals", async () => { - const { relativeValue, packageValue } = await import("./chunks/lazy.mjs").then(createFakeNamespaceObject.bind(rspackRequire, /*! ./lazy.cjs */ "./lazy.cjs", 19)); - - expect(relativeValue).toBe(42); - expect(packageValue).toBe("root"); -}); - -export {}; - -``` - -```mjs title=main.mjs -import "./index_js-relative-external-package-external.mjs"; - -export {}; - -``` - -```mjs title=runtime.mjs - -var modules = {}; -// The module cache -var moduleCache = {}; -// The require function -function rspackRequire(moduleId) { -// Check if module is in cache -var cachedModule = moduleCache[moduleId]; -if (cachedModule !== undefined) { -return cachedModule.exports; -} -// Create a new module (and put it into the cache) -var module = (moduleCache[moduleId] = { -exports: {} -}); -// Execute the module function -modules[moduleId](module, module.exports, rspackRequire); - -// Return the exports of the module -return module.exports; -} -export { rspackRequire }; -// expose the modules object (modules) -var moduleFactories = modules; -export { moduleFactories }; - -// rspack/runtime/compat_get_default_export -// getDefaultExport function for compatibility with non-ESM modules -var compatGetDefaultExport = (module) => { - var getter = module && module.__esModule ? - () => (module['default']) : - () => (module); - definePropertyGetters(getter, { a: getter }); - return getter; -}; -; -export { compatGetDefaultExport }; -// rspack/runtime/create_fake_namespace_object -var getProto = Object.getPrototypeOf ? (obj) => (Object.getPrototypeOf(obj)) : (obj) => (obj.__proto__); -var leafPrototypes; -// create a fake namespace object -// mode & 1: value is a module id, require it -// mode & 2: merge all properties of value into the ns -// mode & 4: return value when already ns object -// mode & 16: return value when it's Promise-like -// mode & 8|1: behave like require -var createFakeNamespaceObject = function(value, mode) { - if(mode & 1) value = (typeof this === "function" ? this : this.r)(value); - if(mode & 8) return value; - if(typeof value === 'object' && value) { - if((mode & 4) && value.__esModule) return value; - if((mode & 16) && typeof value.then === 'function') return value; - } - var ns = Object.create(null); - makeNamespaceObject(ns); - var def = {}; - leafPrototypes = leafPrototypes || [null, getProto({}), getProto([]), getProto(getProto)]; - for(var current = mode & 2 && value; (typeof current == 'object' || typeof current == 'function') && !~leafPrototypes.indexOf(current); current = getProto(current)) { - Object.getOwnPropertyNames(current).forEach((key) => { def[key] = () => (value[key]) }); - } - def['default'] = () => (value); - definePropertyGetters(ns, def); - return ns; -};; -export { createFakeNamespaceObject }; -// rspack/runtime/define_property_getters -var definePropertyGetters = (exports, getters, values) => { - var define = (defs, kind) => { - for(var key in defs) { - if(hasOwnProperty(defs, key) && !hasOwnProperty(exports, key)) { - Object.defineProperty(exports, key, { enumerable: true, [kind]: defs[key] }); - } - } - }; - define(getters, "get"); - define(values, "value"); -};; -// rspack/runtime/esm_register_module -moduleFactories.add = function registerModules(modules) { Object.assign(moduleFactories, modules) } -; -// rspack/runtime/has_own_property -var hasOwnProperty = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop)); -// rspack/runtime/make_namespace_object -// define __esModule on exports -var makeNamespaceObject = (exports) => { - if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { - Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); - } - Object.defineProperty(exports, '__esModule', { value: true }); -};; - - -``` \ No newline at end of file diff --git a/tests/rspack-test/esmOutputCases/externals/node-commonjs-relative-request/external.cjs b/tests/rspack-test/esmOutputCases/externals/node-commonjs-relative-request/external.cjs deleted file mode 100644 index 885c586e241b..000000000000 --- a/tests/rspack-test/esmOutputCases/externals/node-commonjs-relative-request/external.cjs +++ /dev/null @@ -1,3 +0,0 @@ -module.exports = { - value: 42 -}; diff --git a/tests/rspack-test/esmOutputCases/externals/node-commonjs-relative-request/index.js b/tests/rspack-test/esmOutputCases/externals/node-commonjs-relative-request/index.js deleted file mode 100644 index 5c7ccf63ff5c..000000000000 --- a/tests/rspack-test/esmOutputCases/externals/node-commonjs-relative-request/index.js +++ /dev/null @@ -1,6 +0,0 @@ -it("should preserve the resolution base for node-commonjs externals", async () => { - const { relativeValue, packageValue } = await import("./lazy.cjs"); - - expect(relativeValue).toBe(42); - expect(packageValue).toBe("root"); -}); diff --git a/tests/rspack-test/esmOutputCases/externals/node-commonjs-relative-request/lazy.cjs b/tests/rspack-test/esmOutputCases/externals/node-commonjs-relative-request/lazy.cjs deleted file mode 100644 index 3ed479f2a221..000000000000 --- a/tests/rspack-test/esmOutputCases/externals/node-commonjs-relative-request/lazy.cjs +++ /dev/null @@ -1,2 +0,0 @@ -exports.relativeValue = require("relative-external").value; -exports.packageValue = require("package-external").value; diff --git a/tests/rspack-test/esmOutputCases/externals/node-commonjs-relative-request/packages/chunk/index.cjs b/tests/rspack-test/esmOutputCases/externals/node-commonjs-relative-request/packages/chunk/index.cjs deleted file mode 100644 index 5f865cd82e96..000000000000 --- a/tests/rspack-test/esmOutputCases/externals/node-commonjs-relative-request/packages/chunk/index.cjs +++ /dev/null @@ -1,3 +0,0 @@ -module.exports = { - value: "chunk" -}; diff --git a/tests/rspack-test/esmOutputCases/externals/node-commonjs-relative-request/packages/chunk/package.json b/tests/rspack-test/esmOutputCases/externals/node-commonjs-relative-request/packages/chunk/package.json deleted file mode 100644 index 72d0b88aa931..000000000000 --- a/tests/rspack-test/esmOutputCases/externals/node-commonjs-relative-request/packages/chunk/package.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "name": "shadow-pkg", - "version": "1.0.0", - "main": "index.cjs" -} diff --git a/tests/rspack-test/esmOutputCases/externals/node-commonjs-relative-request/packages/root/index.cjs b/tests/rspack-test/esmOutputCases/externals/node-commonjs-relative-request/packages/root/index.cjs deleted file mode 100644 index 768124d9c7c3..000000000000 --- a/tests/rspack-test/esmOutputCases/externals/node-commonjs-relative-request/packages/root/index.cjs +++ /dev/null @@ -1,3 +0,0 @@ -module.exports = { - value: "root" -}; diff --git a/tests/rspack-test/esmOutputCases/externals/node-commonjs-relative-request/packages/root/package.json b/tests/rspack-test/esmOutputCases/externals/node-commonjs-relative-request/packages/root/package.json deleted file mode 100644 index 72d0b88aa931..000000000000 --- a/tests/rspack-test/esmOutputCases/externals/node-commonjs-relative-request/packages/root/package.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "name": "shadow-pkg", - "version": "1.0.0", - "main": "index.cjs" -} diff --git a/tests/rspack-test/esmOutputCases/externals/node-commonjs-relative-request/rspack.config.js b/tests/rspack-test/esmOutputCases/externals/node-commonjs-relative-request/rspack.config.js deleted file mode 100644 index 7f9576d71500..000000000000 --- a/tests/rspack-test/esmOutputCases/externals/node-commonjs-relative-request/rspack.config.js +++ /dev/null @@ -1,9 +0,0 @@ -module.exports = { - output: { - chunkFilename: 'chunks/[name].mjs', - }, - externals: { - 'relative-external': 'node-commonjs ./external.cjs', - 'package-external': 'node-commonjs shadow-pkg', - }, -}; diff --git a/tests/rspack-test/esmOutputCases/externals/node-commonjs-relative-request/test.config.js b/tests/rspack-test/esmOutputCases/externals/node-commonjs-relative-request/test.config.js deleted file mode 100644 index 1fcc6a466ac4..000000000000 --- a/tests/rspack-test/esmOutputCases/externals/node-commonjs-relative-request/test.config.js +++ /dev/null @@ -1,78 +0,0 @@ -const fs = require("fs"); -const path = require("path"); - -function readOutputs(directory) { - const outputs = new Map(); - const queue = [directory]; - - while (queue.length > 0) { - const current = queue.pop(); - for (const entry of fs.readdirSync(current, { withFileTypes: true })) { - const file = path.join(current, entry.name); - if (entry.isDirectory()) { - queue.push(file); - } else if (file.endsWith(".mjs")) { - outputs.set( - path.relative(directory, file), - fs.readFileSync(file, "utf-8") - ); - } - } - } - - return outputs; -} - -module.exports = { - beforeExecute(options) { - if (Array.isArray(options)) { - options = options[0]; - } - fs.copyFileSync( - path.join(options.context, "external.cjs"), - path.join(options.output.path, "external.cjs") - ); - fs.cpSync( - path.join(options.context, "packages", "root"), - path.join(options.output.path, "node_modules", "shadow-pkg"), - { recursive: true } - ); - fs.cpSync( - path.join(options.context, "packages", "chunk"), - path.join(options.output.path, "chunks", "node_modules", "shadow-pkg"), - { recursive: true } - ); - }, - afterExecute(options) { - const outputs = readOutputs(options.output.path); - const source = [...outputs.values()].join("\n"); - const lazySource = outputs.get(path.join("chunks", "lazy.mjs")); - const relativeExternalSource = [...outputs.values()].find(output => - output.includes('external "./external.cjs"') - ); - const packageExternalSource = [...outputs.values()].find(output => - output.includes('external "shadow-pkg"') - ); - - expect(lazySource).toBeDefined(); - expect(relativeExternalSource).toBeDefined(); - expect(packageExternalSource).toBeDefined(); - expect(source).toContain('external "./external.cjs"'); - expect(source).toContain('external "shadow-pkg"'); - expect(relativeExternalSource).toMatch( - /__rspack_createRequire_require\s*\(\s*["']\.\/external\.cjs["']\s*\)/ - ); - expect(packageExternalSource).toMatch( - /__rspack_createRequire_require\s*\(\s*["']shadow-pkg["']\s*\)/ - ); - expect(lazySource).not.toMatch( - /__rspack_createRequire_require\s*\(\s*["'](?:\.\/external\.cjs|shadow-pkg)["']\s*\)/ - ); - expect(lazySource).toMatch( - /(?:__webpack_require__|__rspack_context\.r|rspackRequire)\s*\(\s*[^)]*["']relative-external["']/ - ); - expect(lazySource).toMatch( - /(?:__webpack_require__|__rspack_context\.r|rspackRequire)\s*\(\s*[^)]*["']package-external["']/ - ); - } -}; From 1b78945c68016b4c26ee1b556708a48bc556c92d Mon Sep 17 00:00:00 2001 From: Fy <1114550440@qq.com> Date: Tue, 25 Aug 2026 19:27:34 +0800 Subject: [PATCH 04/13] fix: align CommonJS external direct rendering --- Cargo.lock | 1 - crates/rspack_plugin_esm_library/Cargo.toml | 1 - .../src/dependency/commonjs_external.rs | 20 ++++++++----------- crates/rspack_plugin_externals/src/lib.rs | 1 - 4 files changed, 8 insertions(+), 15 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2d8315c9e8b1..6bf2eefed8bc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4852,7 +4852,6 @@ dependencies = [ "rspack_hook", "rspack_intern", "rspack_parallel", - "rspack_plugin_externals", "rspack_plugin_javascript", "rspack_plugin_rslib", "rspack_plugin_runtime", diff --git a/crates/rspack_plugin_esm_library/Cargo.toml b/crates/rspack_plugin_esm_library/Cargo.toml index 0f46145f11da..376aa17b39aa 100644 --- a/crates/rspack_plugin_esm_library/Cargo.toml +++ b/crates/rspack_plugin_esm_library/Cargo.toml @@ -19,7 +19,6 @@ rspack_hash = { workspace = true } rspack_hook = { workspace = true } rspack_intern = { workspace = true, features = ["atom"] } rspack_parallel = { workspace = true } -rspack_plugin_externals = { workspace = true } rspack_plugin_javascript = { workspace = true } rspack_plugin_rslib = { workspace = true } rspack_plugin_runtime = { workspace = true } diff --git a/crates/rspack_plugin_esm_library/src/dependency/commonjs_external.rs b/crates/rspack_plugin_esm_library/src/dependency/commonjs_external.rs index 0543acf405cd..2ebf07ce6b77 100644 --- a/crates/rspack_plugin_esm_library/src/dependency/commonjs_external.rs +++ b/crates/rspack_plugin_esm_library/src/dependency/commonjs_external.rs @@ -7,7 +7,6 @@ use rspack_core::{ DependencyCodeGeneration, DependencyId, DependencyRange, DependencyTemplate, TemplateContext, TemplateReplaceSource, UsedName, create_node_commonjs_init_fragment, property_access, }; -use rspack_plugin_externals::is_node_builtin; use rspack_plugin_javascript::dependency::{ CommonJsExportRequireDependency, CommonJsFullRequireDependency, CommonJsRequireDependency, RequireHeaderDependency, @@ -54,15 +53,12 @@ fn is_relative_external_request(request: &str) -> bool { || request.starts_with("..\\") } -fn can_render_direct_request(kind: DirectRequireKind, request: &str) -> bool { - match kind { - DirectRequireKind::CommonJs => !is_relative_external_request(request), - // `createRequire(import.meta.url)` resolves packages and package imports - // relative to the emitted asset. Moving that call into an issuer in a - // different directory can load another package, so only base-independent - // Node builtins are safe to render directly. - DirectRequireKind::NodeCommonJs => is_node_builtin(request), - } +fn can_render_direct_request(request: &str) -> bool { + // Both ambient `require` and `createRequire(import.meta.url)` resolve + // relative requests from the emitted asset containing the call. Keep those + // requests on the external-module path because direct rendering can move the + // call into an issuer emitted in another directory. + !is_relative_external_request(request) } pub fn cutout_commonjs_externals( @@ -151,9 +147,9 @@ pub fn cutout_commonjs_externals( }; let request = external_module.get_request(); - if let Some(kind) = direct_require_kind(external_module.resolve_external_type()) + if direct_require_kind(external_module.resolve_external_type()).is_some() && !request.has_rest() - && can_render_direct_request(kind, request.primary()) + && can_render_direct_request(request.primary()) { direct_dependencies.insert(dependency_id); } diff --git a/crates/rspack_plugin_externals/src/lib.rs b/crates/rspack_plugin_externals/src/lib.rs index 0e24e53acd50..2d170ae268e0 100644 --- a/crates/rspack_plugin_externals/src/lib.rs +++ b/crates/rspack_plugin_externals/src/lib.rs @@ -8,6 +8,5 @@ mod plugin; pub use electron_target_plugin::{ElectronTargetContext, electron_target_plugin}; pub use esm_node_target_plugin::EsmNodeTargetPlugin; pub use http_externals_plugin::{css_http_externals_rspack_plugin, http_externals_rspack_plugin}; -pub use node_builtins::is_node_builtin; pub use node_target_plugin::node_target_plugin; pub use plugin::ExternalsPlugin; From a9fd8f0a378fd458a41192f1e3c5f02ffc143afb Mon Sep 17 00:00:00 2001 From: Fy <1114550440@qq.com> Date: Wed, 26 Aug 2026 14:58:21 +0800 Subject: [PATCH 05/13] refactor: share CommonJS external require rendering --- crates/rspack_core/src/external_module.rs | 138 ++++++++++++------ .../src/dependency/commonjs_external.rs | 77 +++------- 2 files changed, 117 insertions(+), 98 deletions(-) diff --git a/crates/rspack_core/src/external_module.rs b/crates/rspack_core/src/external_module.rs index 303940e175cf..85d0611f7bb0 100644 --- a/crates/rspack_core/src/external_module.rs +++ b/crates/rspack_core/src/external_module.rs @@ -56,6 +56,92 @@ impl ExternalRequestValue { } } +/// The CommonJS require form used to render an external request. +#[cacheable] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum CommonJsExternalRequireKind { + CommonJs, + NodeCommonJs, +} + +impl CommonJsExternalRequireKind { + pub fn from_external_type(external_type: &str) -> Option { + match external_type { + "commonjs" | "commonjs2" | "commonjs-module" | "commonjs-static" => Some(Self::CommonJs), + "node-commonjs" => Some(Self::NodeCommonJs), + _ => None, + } + } + + /// Renders the complete require expression and installs any init fragment + /// required by its callee. + pub fn render_expression>( + self, + request: Option<&str>, + properties: impl IntoIterator, + compilation: &Compilation, + chunk_init_fragments: &mut ChunkInitFragments, + ) -> String { + let require = self.render_callee(compilation, chunk_init_fragments); + format!( + "{require}({}){}", + request + .map(json_stringify_str) + .unwrap_or_else(|| "undefined".to_string()), + property_access(properties, 0) + ) + } + + fn render_external_request( + self, + request: Option<&ExternalRequestValue>, + compilation: &Compilation, + chunk_init_fragments: &mut ChunkInitFragments, + ) -> String { + match request { + Some(request) => self.render_expression( + Some(request.primary()), + request.iter().skip(1), + compilation, + chunk_init_fragments, + ), + // Preserve the existing fallback for a missing object-form request: + // ESM node-commonjs used the undefined value while other CommonJS + // renderers requested the literal module name "undefined". + None if matches!(self, Self::NodeCommonJs) && compilation.options.output.module => self + .render_expression( + None, + iter::empty::<&str>(), + compilation, + chunk_init_fragments, + ), + None => self.render_expression( + Some("undefined"), + iter::empty::<&str>(), + compilation, + chunk_init_fragments, + ), + } + } + + /// Renders only the require callee and installs its required init fragment. + /// + /// This is the split-range counterpart of [`Self::render_expression`]. + pub fn render_callee( + self, + compilation: &Compilation, + chunk_init_fragments: &mut ChunkInitFragments, + ) -> &'static str { + match self { + Self::NodeCommonJs if compilation.options.output.module => { + chunk_init_fragments.push(create_node_commonjs_init_fragment(compilation)); + "__rspack_createRequire_require" + } + Self::CommonJs | Self::NodeCommonJs => "require", + } + } +} + impl Serialize for ExternalRequestValue { fn serialize(&self, serializer: S) -> std::result::Result where @@ -128,19 +214,7 @@ fn get_request_string(request: &ExternalRequestValue) -> String { format!("{variable_name}{object_lookup}") } -fn get_source_for_commonjs(module_and_specifiers: Option<&ExternalRequestValue>) -> String { - let (module_name, properties) = if let Some(module_and_specifiers) = module_and_specifiers { - ( - module_and_specifiers.primary(), - property_access(module_and_specifiers.iter(), 1), - ) - } else { - ("undefined", String::new()) - }; - format!("require({}){}", json_stringify_str(module_name), properties) -} - -pub fn create_node_commonjs_init_fragment(compilation: &Compilation) -> BoxChunkInitFragment { +fn create_node_commonjs_init_fragment(compilation: &Compilation) -> BoxChunkInitFragment { let need_prefix = compilation .options .output @@ -645,6 +719,8 @@ impl ExternalModule { let mut chunk_init_fragments: ChunkInitFragments = Default::default(); let supports_const = compilation.options.output.environment.supports_const(); let resolved_external_type = self.resolve_external_type(); + let commonjs_require_kind = + CommonJsExternalRequireKind::from_external_type(resolved_external_type); let module_graph = compilation.get_module_graph(); let module_graph_cache = &compilation.module_graph_cache_artifact; @@ -664,38 +740,16 @@ impl ExternalModule { get_namespace_object_export(concatenation_scope, supports_const, runtime_template), get_source_for_global_variable_external(request, &compilation.options.output.global_object) ), - "commonjs" | "commonjs2" | "commonjs-module" | "commonjs-static" => { + _ if commonjs_require_kind.is_some() => { + let require_kind = + commonjs_require_kind.expect("matched CommonJS external type should have a require kind"); + let require_expression = + require_kind.render_external_request(request, compilation, &mut chunk_init_fragments); format!( - "{} = {};", - get_namespace_object_export(concatenation_scope, supports_const, runtime_template), - get_source_for_commonjs(request) + "{} = {require_expression};", + get_namespace_object_export(concatenation_scope, supports_const, runtime_template) ) } - "node-commonjs" => { - if compilation.options.output.module { - chunk_init_fragments.push(create_node_commonjs_init_fragment(compilation)); - let (request, specifiers) = if let Some(request) = request { - ( - json_stringify_str(request.primary()), - property_access(request.iter(), 1), - ) - } else { - ("undefined".to_string(), String::new()) - }; - format!( - "{} = __rspack_createRequire_require({}){};", - get_namespace_object_export(concatenation_scope, supports_const, runtime_template), - request, - specifiers - ) - } else { - format!( - "{} = {};", - get_namespace_object_export(concatenation_scope, supports_const, runtime_template), - get_source_for_commonjs(request) - ) - } - } "amd" | "amd-require" | "umd" | "umd2" | "system" | "jsonp" => { let id = ChunkGraph::get_module_id(&compilation.module_ids_artifact, self.identifier()) .map(|s| s.as_str()) diff --git a/crates/rspack_plugin_esm_library/src/dependency/commonjs_external.rs b/crates/rspack_plugin_esm_library/src/dependency/commonjs_external.rs index 2ebf07ce6b77..a53b4bd230b9 100644 --- a/crates/rspack_plugin_esm_library/src/dependency/commonjs_external.rs +++ b/crates/rspack_plugin_esm_library/src/dependency/commonjs_external.rs @@ -3,9 +3,9 @@ use std::{collections::hash_map::Entry, sync::Arc}; use atomic_refcell::AtomicRefCell; use rspack_cacheable::{cacheable, cacheable_dyn}; use rspack_core::{ - BuildModuleGraphArtifact, CodeGenerationDataItem, ConnectionActiveState, Dependency, - DependencyCodeGeneration, DependencyId, DependencyRange, DependencyTemplate, TemplateContext, - TemplateReplaceSource, UsedName, create_node_commonjs_init_fragment, property_access, + BuildModuleGraphArtifact, CodeGenerationDataItem, CommonJsExternalRequireKind, + ConnectionActiveState, Dependency, DependencyCodeGeneration, DependencyId, DependencyRange, + DependencyTemplate, TemplateContext, TemplateReplaceSource, UsedName, property_access, }; use rspack_plugin_javascript::dependency::{ CommonJsExportRequireDependency, CommonJsFullRequireDependency, CommonJsRequireDependency, @@ -20,30 +20,13 @@ pub type DirectCommonJsExternalDependencies = Arc>; -#[cacheable] -#[derive(Debug, Clone, Copy)] -enum DirectRequireKind { - CommonJs, - NodeCommonJs, -} - #[cacheable] #[derive(Debug, Clone)] -struct DirectExternalRequireHeaders(Vec<(DependencyRange, DirectRequireKind)>); +struct DirectExternalRequireHeaders(Vec<(DependencyRange, CommonJsExternalRequireKind)>); #[cacheable_dyn] impl CodeGenerationDataItem for DirectExternalRequireHeaders {} -fn direct_require_kind(external_type: &str) -> Option { - match external_type { - "commonjs" | "commonjs2" | "commonjs-module" | "commonjs-static" => { - Some(DirectRequireKind::CommonJs) - } - "node-commonjs" => Some(DirectRequireKind::NodeCommonJs), - _ => None, - } -} - fn is_relative_external_request(request: &str) -> bool { request == "." || request == ".." @@ -147,7 +130,8 @@ pub fn cutout_commonjs_externals( }; let request = external_module.get_request(); - if direct_require_kind(external_module.resolve_external_type()).is_some() + if CommonJsExternalRequireKind::from_external_type(external_module.resolve_external_type()) + .is_some() && !request.has_rest() && can_render_direct_request(request.primary()) { @@ -190,7 +174,7 @@ fn get_direct_external_require( expression_range: DependencyRange, direct_dependencies: &DirectCommonJsExternalDependencies, context: &TemplateContext, -) -> Option<(String, DependencyRange, DirectRequireKind)> { +) -> Option<(String, DependencyRange, CommonJsExternalRequireKind)> { if !direct_dependencies.borrow().contains(dependency_id) { return None; } @@ -204,30 +188,22 @@ fn get_direct_external_require( Some(( external_module.get_request().primary().to_string(), expression_range, - direct_require_kind(external_module.resolve_external_type())?, + CommonJsExternalRequireKind::from_external_type(external_module.resolve_external_type())?, )) } fn render_direct_require( request: &str, properties: &[rspack_util::atom::Atom], - kind: DirectRequireKind, + kind: CommonJsExternalRequireKind, context: &mut TemplateContext, ) -> String { - let require = match kind { - DirectRequireKind::CommonJs => "require", - DirectRequireKind::NodeCommonJs => "__rspack_createRequire_require", - }; - - if matches!(kind, DirectRequireKind::NodeCommonJs) { - let init_fragment = create_node_commonjs_init_fragment(context.compilation); - context.chunk_init_fragments().push(init_fragment); - } - - format!( - "{require}({}){}", - json_stringify_str(request), - property_access(properties, 0) + let compilation = context.compilation; + kind.render_expression( + Some(request), + properties, + compilation, + context.chunk_init_fragments(), ) } @@ -438,23 +414,12 @@ impl DependencyTemplate for DirectRequireHeaderDependencyTemplate { }); match direct_require_kind { - Some(DirectRequireKind::CommonJs) => { - source.replace( - header_range.start, - header_range.end, - "require".to_string(), - None, - ); - } - Some(DirectRequireKind::NodeCommonJs) => { - source.replace( - header_range.start, - header_range.end, - "__rspack_createRequire_require".to_string(), - None, - ); - let init_fragment = create_node_commonjs_init_fragment(context.compilation); - context.chunk_init_fragments().push(init_fragment); + Some(kind) => { + let compilation = context.compilation; + let require = kind + .render_callee(compilation, context.chunk_init_fragments()) + .to_string(); + source.replace(header_range.start, header_range.end, require, None); } None => { if let Some(template) = &self.template { From 42dc520af3904e906b4355c3f9da3b398c9db404 Mon Sep 17 00:00:00 2001 From: Fy <1114550440@qq.com> Date: Wed, 26 Aug 2026 17:11:17 +0800 Subject: [PATCH 06/13] refactor: simplify CommonJS external connection cutout --- .../src/module_graph/connection.rs | 20 ----------- .../src/dependency/commonjs_external.rs | 35 ++++--------------- .../rspack_plugin_esm_library/src/plugin.rs | 14 +++----- 3 files changed, 11 insertions(+), 58 deletions(-) diff --git a/crates/rspack_core/src/module_graph/connection.rs b/crates/rspack_core/src/module_graph/connection.rs index fe40e80b0b90..3c1c9b1d51ec 100644 --- a/crates/rspack_core/src/module_graph/connection.rs +++ b/crates/rspack_core/src/module_graph/connection.rs @@ -45,12 +45,6 @@ pub struct ModuleGraphConnection { conditional: bool, } -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub struct ConnectionActiveState { - active: bool, - conditional: bool, -} - impl std::hash::Hash for ModuleGraphConnection { fn hash(&self, state: &mut H) { self.id.hash(state); @@ -88,20 +82,6 @@ impl ModuleGraphConnection { self.conditional = false; } - pub fn force_inactive_with_state(&mut self) -> ConnectionActiveState { - let state = ConnectionActiveState { - active: self.active, - conditional: self.conditional, - }; - self.force_inactive(); - state - } - - pub fn restore_active_state(&mut self, state: ConnectionActiveState) { - self.active = state.active; - self.conditional = state.conditional; - } - pub fn is_active( &self, module_graph: &ModuleGraph, diff --git a/crates/rspack_plugin_esm_library/src/dependency/commonjs_external.rs b/crates/rspack_plugin_esm_library/src/dependency/commonjs_external.rs index a53b4bd230b9..214000096a01 100644 --- a/crates/rspack_plugin_esm_library/src/dependency/commonjs_external.rs +++ b/crates/rspack_plugin_esm_library/src/dependency/commonjs_external.rs @@ -1,11 +1,11 @@ -use std::{collections::hash_map::Entry, sync::Arc}; +use std::sync::Arc; use atomic_refcell::AtomicRefCell; use rspack_cacheable::{cacheable, cacheable_dyn}; use rspack_core::{ - BuildModuleGraphArtifact, CodeGenerationDataItem, CommonJsExternalRequireKind, - ConnectionActiveState, Dependency, DependencyCodeGeneration, DependencyId, DependencyRange, - DependencyTemplate, TemplateContext, TemplateReplaceSource, UsedName, property_access, + BuildModuleGraphArtifact, CodeGenerationDataItem, CommonJsExternalRequireKind, Dependency, + DependencyCodeGeneration, DependencyId, DependencyRange, DependencyTemplate, TemplateContext, + TemplateReplaceSource, UsedName, property_access, }; use rspack_plugin_javascript::dependency::{ CommonJsExportRequireDependency, CommonJsFullRequireDependency, CommonJsRequireDependency, @@ -17,8 +17,6 @@ use rspack_util::{ }; pub type DirectCommonJsExternalDependencies = Arc>>>; -pub type DirectCommonJsExternalConnectionStates = - AtomicRefCell>; #[cacheable] #[derive(Debug, Clone)] @@ -46,7 +44,6 @@ fn can_render_direct_request(request: &str) -> bool { pub fn cutout_commonjs_externals( build_module_graph_artifact: &mut BuildModuleGraphArtifact, - connection_states: &mut FxHashMap, ) -> FxHashSet { let module_graph = build_module_graph_artifact.get_module_graph(); let mut direct_dependencies = FxHashSet::default(); @@ -141,29 +138,11 @@ pub fn cutout_commonjs_externals( } let module_graph = build_module_graph_artifact.get_module_graph_mut(); - // A reused module graph can make a previously direct dependency ineligible. - // Restore the connection state captured before this plugin cut it out. - connection_states.retain(|dependency_id, state| { - if direct_dependencies.contains(dependency_id) { - return module_graph - .connection_by_dependency_id(dependency_id) - .is_some(); - } - if let Some(connection) = module_graph.connection_by_dependency_id_mut(dependency_id) { - connection.restore_active_state(*state); - } - false - }); for dependency_id in &direct_dependencies { - let connection = module_graph + module_graph .connection_by_dependency_id_mut(dependency_id) - .expect("direct CommonJS external should have a module graph connection"); - match connection_states.entry(*dependency_id) { - Entry::Vacant(entry) => { - entry.insert(connection.force_inactive_with_state()); - } - Entry::Occupied(_) => connection.force_inactive(), - } + .expect("direct CommonJS external should have a module graph connection") + .force_inactive(); } direct_dependencies diff --git a/crates/rspack_plugin_esm_library/src/plugin.rs b/crates/rspack_plugin_esm_library/src/plugin.rs index 31357783448c..7aa143dcb6ea 100644 --- a/crates/rspack_plugin_esm_library/src/plugin.rs +++ b/crates/rspack_plugin_esm_library/src/plugin.rs @@ -47,10 +47,9 @@ use crate::{ chunk_link::ChunkLinkContext, dependency::{ commonjs_external::{ - DirectCommonJsExportRequireDependencyTemplate, DirectCommonJsExternalConnectionStates, - DirectCommonJsExternalDependencies, DirectCommonJsFullRequireDependencyTemplate, - DirectCommonJsRequireDependencyTemplate, DirectRequireHeaderDependencyTemplate, - cutout_commonjs_externals, + DirectCommonJsExportRequireDependencyTemplate, DirectCommonJsExternalDependencies, + DirectCommonJsFullRequireDependencyTemplate, DirectCommonJsRequireDependencyTemplate, + DirectRequireHeaderDependencyTemplate, cutout_commonjs_externals, }, dyn_import::DynamicImportDependencyTemplate, }, @@ -86,7 +85,6 @@ pub struct EsmLibraryPlugin { pub(crate) all_dyn_targets: AtomicRefCell, pub(crate) namespace_targets: AtomicRefCell, pub(crate) direct_commonjs_external_dependencies: DirectCommonJsExternalDependencies, - pub(crate) direct_commonjs_external_connection_states: DirectCommonJsExternalConnectionStates, /// module_id → namespace export name in the chunk, for modules whose exports /// were renamed in a multi-module chunk. Written during link, read during code generation. pub(crate) dyn_import_ns_map: Arc>>, @@ -106,7 +104,6 @@ impl EsmLibraryPlugin { Default::default(), Default::default(), Default::default(), - Default::default(), ) } @@ -849,10 +846,7 @@ async fn optimize_dependencies( exports_info_artifact: &mut ExportsInfoArtifact, _diagnostics: &mut Vec, ) -> Result> { - let direct_dependencies = cutout_commonjs_externals( - build_module_graph_artifact, - &mut self.direct_commonjs_external_connection_states.borrow_mut(), - ); + let direct_dependencies = cutout_commonjs_externals(build_module_graph_artifact); *self.direct_commonjs_external_dependencies.borrow_mut() = Arc::new(direct_dependencies); cutout_dyn_import_externals( false, From 154931df2525dab2d7279987c55ac736cb80e70a Mon Sep 17 00:00:00 2001 From: Fy <1114550440@qq.com> Date: Wed, 26 Aug 2026 17:25:36 +0800 Subject: [PATCH 07/13] refactor: bind CommonJS external require kind in guard --- crates/rspack_core/src/external_module.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/crates/rspack_core/src/external_module.rs b/crates/rspack_core/src/external_module.rs index 85d0611f7bb0..d646e0c5e785 100644 --- a/crates/rspack_core/src/external_module.rs +++ b/crates/rspack_core/src/external_module.rs @@ -740,9 +740,7 @@ impl ExternalModule { get_namespace_object_export(concatenation_scope, supports_const, runtime_template), get_source_for_global_variable_external(request, &compilation.options.output.global_object) ), - _ if commonjs_require_kind.is_some() => { - let require_kind = - commonjs_require_kind.expect("matched CommonJS external type should have a require kind"); + _ if let Some(require_kind) = commonjs_require_kind => { let require_expression = require_kind.render_external_request(request, compilation, &mut chunk_init_fragments); format!( From 51daf70362152cd9779322707cfd34aad00789ed Mon Sep 17 00:00:00 2001 From: Fy <1114550440@qq.com> Date: Mon, 14 Sep 2026 18:18:04 +0800 Subject: [PATCH 08/13] fix(esm-library): streamline direct external rendering Render native ESM externals through dependency templates and share CommonJS request rendering. Preserve fallback identities, guard generated bindings, reserve named class expression bindings, and update existing output snapshots. --- .../src/artifacts/code_generation_results.rs | 6 +- .../src/chunk_graph/chunk_graph_module.rs | 11 +- crates/rspack_core/src/concatenated_module.rs | 41 ++- .../rspack_core/src/concatenation_backend.rs | 49 ++- crates/rspack_core/src/external_module.rs | 237 +++++++++------ .../src/utils/concatenated_module_visitor.rs | 7 +- .../src/utils/concatenation_scope.rs | 70 ++++- .../src/dependency/commonjs_external.rs | 282 +++++------------- .../src/dependency/esm_external.rs | 178 +++++++++++ .../src/dependency/mod.rs | 43 +++ .../src/esm_lib_parser_plugin.rs | 17 +- crates/rspack_plugin_esm_library/src/link.rs | 169 ++++++----- .../rspack_plugin_esm_library/src/plugin.rs | 219 ++++---------- .../src/esm_node_target_plugin.rs | 3 +- .../common_js_export_require_dependency.rs | 28 +- ...sm_export_imported_specifier_dependency.rs | 89 +++++- .../dependency/esm/esm_import_dependency.rs | 46 ++- .../esm/esm_import_specifier_dependency.rs | 84 +++++- .../src/dependency/esm/mod.rs | 2 +- .../reexport-star/__snapshot__/case1.txt | 16 +- .../reexport-star/__snapshot__/case2.txt | 4 +- .../reexport-star/__snapshot__/case3.txt | 1 - .../reexport-star/__snapshot__/case4.txt | 6 - .../reexport-star/__snapshot__/case5.txt | 5 +- .../reexport-star/__snapshot__/case6.txt | 7 - .../runtimeModeSnapshot/case1.txt | 16 +- .../runtimeModeSnapshot/case2.txt | 4 +- .../runtimeModeSnapshot/case3.txt | 1 - .../runtimeModeSnapshot/case4.txt | 6 - .../runtimeModeSnapshot/case5.txt | 5 +- .../runtimeModeSnapshot/case6.txt | 7 - .../rspack.config.mjs | 46 ++- .../runtimeModeSnapshot/esm.snap.txt | 12 + .../__snapshots__/esm.snap.txt | 9 +- .../__snapshots__/esm.snap.txt | 2 - .../__snapshots__/esm.snap.txt | 4 - .../__snapshots__/esm.snap.txt | 4 +- .../runtimeModeSnapshot/esm.snap.txt | 4 +- .../__snapshots__/esm.snap.txt | 4 - .../runtimeModeSnapshot/esm.snap.txt | 4 - .../__snapshots__/esm.snap.txt | 4 - .../__snapshots__/esm.snap.txt | 4 - .../__snapshots__/esm.snap.txt | 2 - .../aliased/__snapshots__/esm.snap.txt | 4 - .../__snapshots__/esm.snap.txt | 2 - .../runtimeModeSnapshot/esm.snap.txt | 2 - .../__snapshots__/esm.snap.txt | 6 +- .../runtimeModeSnapshot/esm.snap.txt | 6 +- .../__snapshots__/esm.snap.txt | 4 - .../__snapshots__/esm.snap.txt | 12 +- .../empty-import/__snapshots__/esm.snap.txt | 2 - .../__snapshots__/esm.snap.txt | 4 - .../runtimeModeSnapshot/esm.snap.txt | 4 - .../__snapshots__/esm.snap.txt | 4 - .../runtimeModeSnapshot/esm.snap.txt | 4 - .../__snapshots__/esm.snap.txt | 5 +- .../__snapshots__/esm.snap.txt | 2 - .../__snapshots__/esm.snap.txt | 4 - .../__snapshots__/esm.snap.txt | 4 - .../__snapshots__/esm.snap.txt | 5 +- .../__snapshots__/esm.snap.txt | 4 - .../__snapshots__/esm.snap.txt | 2 - .../__snapshots__/esm.snap.txt | 2 - .../__snapshots__/esm.snap.txt | 14 +- .../__snapshots__/esm.snap.txt | 2 - .../__snapshots__/esm.snap.txt | 8 +- .../__snapshots__/esm.snap.txt | 5 +- .../__snapshots__/esm.snap.txt | 2 - .../runtimeModeSnapshot/esm.snap.txt | 35 +++ .../__snapshots__/esm.snap.txt | 49 ++- .../runtimeModeSnapshot/esm.snap.txt | 86 ++++++ .../__snapshots__/esm.snap.txt | 4 - .../__snapshots__/esm.snap.txt | 10 +- .../__snapshots__/esm.snap.txt | 2 - .../__snapshots__/esm.snap.txt | 2 - .../__snapshots__/esm.snap.txt | 6 +- .../runtimeModeSnapshot/esm.snap.txt | 6 +- .../__snapshots__/esm.snap.txt | 6 +- .../runtimeModeSnapshot/esm.snap.txt | 6 +- .../__snapshots__/esm.snap.txt | 7 +- .../runtime-decide/__snapshots__/esm.snap.txt | 1 + .../runtimeModeSnapshot/esm.snap.txt | 1 + .../__snapshots__/esm.snap.txt | 4 - .../__snapshots__/esm.snap.txt | 18 +- .../__snapshots__/esm.snap.txt | 5 +- .../__snapshots__/esm.snap.txt | 37 +-- .../runtimeModeSnapshot/esm.snap.txt | 37 +-- .../__snapshots__/esm.snap.txt | 32 +- .../runtimeModeSnapshot/esm.snap.txt | 32 +- .../__snapshots__/esm.snap.txt | 17 +- .../runtimeModeSnapshot/esm.snap.txt | 17 +- .../__snapshots__/esm.snap.txt | 26 +- .../runtimeModeSnapshot/esm.snap.txt | 26 +- .../__snapshots__/esm.snap.txt | 6 - .../__snapshots__/esm.snap.txt | 6 - .../__snapshots__/esm.snap.txt | 5 - .../__snapshots__/esm.snap.txt | 4 - .../runtimeModeSnapshot/esm.snap.txt | 4 - .../__snapshots__/esm.snap.txt | 4 - .../runtimeModeSnapshot/esm.snap.txt | 4 - .../move-entry/__snapshots__/esm.snap.txt | 4 +- .../__snapshots__/esm.snap.txt | 10 +- .../__snapshots__/esm.snap.txt | 13 +- .../__snapshots__/esm.snap.txt | 12 +- .../runtimeModeSnapshot/esm.snap.txt | 12 +- .../__snapshots__/esm.snap.txt | 4 - 106 files changed, 1286 insertions(+), 1145 deletions(-) create mode 100644 crates/rspack_plugin_esm_library/src/dependency/esm_external.rs create mode 100644 tests/rspack-test/esmOutputCases/deconflict/asset-preserve-import-external-symbols/__snapshots__/runtimeModeSnapshot/esm.snap.txt create mode 100644 tests/rspack-test/esmOutputCases/externals/namespace-name-collision-across-modules/__snapshots__/runtimeModeSnapshot/esm.snap.txt create mode 100644 tests/rspack-test/esmOutputCases/externals/node-commonjs-helper-name-collision/__snapshots__/runtimeModeSnapshot/esm.snap.txt diff --git a/crates/rspack_core/src/artifacts/code_generation_results.rs b/crates/rspack_core/src/artifacts/code_generation_results.rs index cbf21f88dc35..db73d10108d0 100644 --- a/crates/rspack_core/src/artifacts/code_generation_results.rs +++ b/crates/rspack_core/src/artifacts/code_generation_results.rs @@ -196,7 +196,11 @@ impl CodeGenerationDataItem for CodeGenerationDataChunkInitFragments { } #[cacheable_dyn] -impl CodeGenerationDataItem for CodeGenerationDataConcatenationScopeOutput {} +impl CodeGenerationDataItem for CodeGenerationDataConcatenationScopeOutput { + fn update_hash(&self, hasher: &mut RspackHasher) { + std::hash::Hash::hash(self, hasher); + } +} #[cacheable] #[derive(Debug, Default)] diff --git a/crates/rspack_core/src/chunk_graph/chunk_graph_module.rs b/crates/rspack_core/src/chunk_graph/chunk_graph_module.rs index 24a205f46ad8..8057f676d998 100644 --- a/crates/rspack_core/src/chunk_graph/chunk_graph_module.rs +++ b/crates/rspack_core/src/chunk_graph/chunk_graph_module.rs @@ -357,9 +357,18 @@ impl ChunkGraph { side_effects_state_artifact, &compilation.exports_info_artifact, ); - if active_state.is_false() { + let is_external = mg + .module_by_identifier(module_identifier) + .is_some_and(|module| module.as_external_module().is_some()); + if active_state.is_false() && !is_external { return None; } + // Direct external templates still read the request/type and export + // names after the placement connection is cut out. Such modules may + // have no chunk module id, so also hash their semantic identity. + if is_external { + module_identifier.hash(&mut hasher); + } visited_modules.insert(*module_identifier); for_each_runtime( runtime, diff --git a/crates/rspack_core/src/concatenated_module.rs b/crates/rspack_core/src/concatenated_module.rs index 741fc783244b..d550a846c93b 100644 --- a/crates/rspack_core/src/concatenated_module.rs +++ b/crates/rspack_core/src/concatenated_module.rs @@ -10,7 +10,7 @@ use rayon::prelude::*; use regex::Regex; use rspack_cacheable::{ cacheable, cacheable_dyn, - with::{As, AsOption, AsPreset, AsVec}, + with::{As, AsMap, AsPreset, AsVec}, }; use rspack_collections::{ Identifiable, Identifier, IdentifierIndexMap, IdentifierIndexSet, IdentifierMap, IdentifierSet, @@ -184,10 +184,11 @@ impl ConcatenationEntryExternal { #[cacheable] #[derive(Clone, Debug, Default)] pub struct ConcatenatedImportMapItem { + /// Local binding to the original external export name. + #[cacheable(with=AsMap)] + pub specifiers: HashMap, #[cacheable(with=AsVec)] - pub specifiers: HashSet, - #[cacheable(with=AsOption)] - pub namespace: Option, + pub namespaces: HashSet, } pub type ConcatenatedImportMap = @@ -707,7 +708,7 @@ pub fn render_imports(source: &str, attr: Option<&str>, import_spec: &ImportSpec if atom == internal { atom.to_string() } else { - format!("{atom} as {internal}") + format!("{} as {internal}", crate::to_module_export_name(atom)) } }) .collect::>() @@ -1050,7 +1051,7 @@ impl Module for ConcatenatedModule { for ((source, attr), imported) in import_map { let total_imported_atoms = import_stmts.entry((source.clone(), attr)).or_default(); - if let Some(ns_import) = imported.namespace { + for ns_import in imported.namespaces { if let Some(internal_ns_import) = total_imported_atoms.ns_import.as_ref() { info .internal_names @@ -1075,10 +1076,21 @@ impl Module for ConcatenatedModule { } } - for atom in imported.specifiers { - let existing_name = total_imported_atoms.atoms.get(&atom).cloned(); + for (local_name, imported_name) in imported.specifiers { + let existing_name = total_imported_atoms + .atoms + .get(&imported_name) + .or_else(|| { + if imported_name == "default" { + total_imported_atoms.default_import.as_ref() + } else { + None + } + }) + .cloned(); let new_name = name_allocator.assign_import_binding_name( - &atom, + &local_name, + &imported_name, existing_name.as_ref(), &source, info, @@ -1086,10 +1098,10 @@ impl Module for ConcatenatedModule { ); if existing_name.is_none() { - if atom == "default" { + if imported_name == "default" { total_imported_atoms.default_import = Some(new_name); } else { - total_imported_atoms.atoms.insert(atom, new_name); + total_imported_atoms.atoms.insert(imported_name, new_name); } } } @@ -3028,11 +3040,10 @@ pub fn collect_ident<'a>( } } - /// https://github.com/webpack/webpack/blob/1f99ad6367f2b8a6ef17cce0e058f7a67fb7db18/lib/optimize/ConcatenatedModule.js#L1173-L1197 + /// Reserve every class expression's inner name, even without a superclass, + /// so renaming an outer binding cannot make it captured by the class scope. fn visit_class_expr(&mut self, node: &ClassExpr<'a>) { - if let Some(ident) = &node.ident - && node.class.super_class.is_some() - { + if let Some(ident) = &node.ident { self.ids.push(NewConcatenatedModuleIdent { id: ident.as_ref().clone_in(self.allocator), shorthand: false, diff --git a/crates/rspack_core/src/concatenation_backend.rs b/crates/rspack_core/src/concatenation_backend.rs index aceb78cb76eb..8431e5bb3425 100644 --- a/crates/rspack_core/src/concatenation_backend.rs +++ b/crates/rspack_core/src/concatenation_backend.rs @@ -20,7 +20,7 @@ use crate::{ ExportInfo, ExportProvided, ExportsInfoArtifact, ExportsType, FindTargetResult, ModuleGraph, ModuleGraphCacheArtifact, ModuleIdentifier, ModuleInfo, ModuleStaticCache, RuntimeSpec, UsedName, collect_ident, escape_name_atom_ref, find_target, get_cached_readable_identifier, - split_readable_identifier, to_identifier_with_escaped, + split_readable_identifier, to_identifier, to_identifier_with_escaped, }; /// Reusable read-only context shared by concatenation implementations. @@ -447,7 +447,7 @@ impl ConcatenationNameAllocator { ) { let escaped_identifier = context.module_identifier(&module_info.module); for (name, ctxt) in module_info.binding_to_ref.keys() { - if ctxt != &module_info.module_ctxt { + if ctxt != &module_info.module_ctxt || module_info.internal_names.contains_key(name) { continue; } @@ -472,15 +472,19 @@ impl ConcatenationNameAllocator { pub fn assign_import_binding_name( &mut self, + local_name: &Atom, imported_name: &Atom, existing_name: Option<&Atom>, source: &str, module_info: &mut ConcatenatedModuleInfo, context: &ConcatenationContext, ) -> Atom { - let should_update_raw_export = existing_name.is_some() || self.contains(imported_name); + let needs_rename = self.contains(imported_name) + || imported_name.is_empty() + || to_identifier(imported_name) != imported_name.as_str(); + let should_update_raw_export = existing_name.is_some() || needs_rename; let internal_name = existing_name.cloned().unwrap_or_else(|| { - if !self.contains(imported_name) { + if !needs_rename { self.insert(imported_name.clone()); return imported_name.clone(); } @@ -501,13 +505,13 @@ impl ConcatenationNameAllocator { if should_update_raw_export && let Some(raw_export_map) = module_info.raw_export_map.as_mut() - && raw_export_map.contains_key(imported_name) + && raw_export_map.contains_key(local_name) { - raw_export_map.insert(imported_name.clone(), internal_name.to_string()); + raw_export_map.insert(local_name.clone(), internal_name.to_string()); } module_info .internal_names - .insert(imported_name.clone(), internal_name.clone()); + .insert(local_name.clone(), internal_name.clone()); internal_name } @@ -590,9 +594,19 @@ pub fn analyze_module_scope( module_info.global_scope_ident.reserve(identifiers.len()); module_info.binding_to_ref.reserve(identifiers.len()); + let imported_bindings = module_info + .import_map + .iter() + .flat_map(|map| map.values()) + .flat_map(|item| item.specifiers.keys().chain(item.namespaces.iter())) + .map(|atom| atom.as_str()) + .collect::>(); for identifier in identifiers { let scope = semantic.node_scope(&identifier.id); - let is_global = SyntaxContext::from_u32(scope.raw()) == module_info.global_ctxt; + let is_import = scope != top_level_scope_id + && imported_bindings.contains(identifier.id.sym.as_str()) + && SyntaxContext::from_u32(scope.raw()) == module_info.global_ctxt; + let is_global = !is_import && SyntaxContext::from_u32(scope.raw()) == module_info.global_ctxt; let legacy = if is_global { let legacy = identifier.to_legacy(&semantic); module_info.global_scope_ident.push(legacy.clone()); @@ -611,13 +625,16 @@ pub fn analyze_module_scope( continue; } - if scope != top_level_scope_id { + if scope != top_level_scope_id && !is_import { module_info .all_used_names .insert(Atom::from(identifier.id.sym.as_str())); } - let legacy = legacy.unwrap_or_else(|| identifier.to_legacy(&semantic)); + let mut legacy = legacy.unwrap_or_else(|| identifier.to_legacy(&semantic)); + if is_import { + legacy.id.ctxt = module_info.module_ctxt; + } module_info.idents.push(legacy.clone()); module_info .binding_to_ref @@ -651,9 +668,7 @@ impl<'a> ConcatenationContext<'a> { let imported_names = import_map.map_or(0, |map| { map .values() - .map(|imported| { - imported.specifiers.len() + usize::from(imported.namespace.is_some()) - }) + .map(|imported| imported.specifiers.len() + imported.namespaces.len()) .sum::() }); ( @@ -689,12 +704,16 @@ impl<'a> ConcatenationContext<'a> { source.clone(), split_readable_identifier(source.as_str()), )); - for atom in &imported.specifiers { + for atom in imported + .specifiers + .keys() + .chain(imported.specifiers.values()) + { escaped_names .entry(atom.clone()) .or_insert_with(|| escape_name_atom_ref(atom)); } - if let Some(namespace) = &imported.namespace { + for namespace in &imported.namespaces { escaped_names .entry(namespace.clone()) .or_insert_with(|| escape_name_atom_ref(namespace)); diff --git a/crates/rspack_core/src/external_module.rs b/crates/rspack_core/src/external_module.rs index d646e0c5e785..9aa4d1ee85dd 100644 --- a/crates/rspack_core/src/external_module.rs +++ b/crates/rspack_core/src/external_module.rs @@ -5,16 +5,17 @@ use rspack_collections::{Identifiable, Identifier}; use rspack_error::{Result, impl_empty_diagnosable_trait}; use rspack_hash::{RspackHashDigest, RspackHasher}; use rspack_hook::define_hook; +use rspack_intern::Atom; use rspack_macros::impl_source_map_config; use rspack_util::{json_stringify_str, source_map::SourceMapKind}; use rustc_hash::FxHashMap as HashMap; use serde::Serialize; use crate::{ - BoxChunkInitFragment, BoxModule, BuildContext, BuildInfo, BuildMeta, BuildMetaExportsType, ChunkGraph, - ChunkInitFragments, ChunkUkey, CodeGenerationDataChunkInitFragments, CodeGenerationDataUrl, - CodeGenerationResultBuilder, Compilation, ConcatenationScope, Context, CssLayer, - CssModuleRenderCondition, DependenciesBlock, DependenciesBlockData, DependencyRef, + BoxChunkInitFragment, BoxModule, BuildContext, BuildInfo, BuildMeta, BuildMetaExportsType, + ChunkGraph, ChunkInitFragments, ChunkUkey, CodeGenerationDataChunkInitFragments, + CodeGenerationDataUrl, CodeGenerationResultBuilder, Compilation, ConcatenationScope, Context, + CssLayer, CssModuleRenderCondition, DependenciesBlock, DependenciesBlockData, DependencyRef, ExportProvided, ExternalType, FactoryMetaStore, FreezeLock, ImportAttributes, ImportPhase, InitFragmentExt, InitFragmentKey, InitFragmentStage, LibIdentOptions, Module, ModuleArgument, ModuleCodeGenerationContext, ModuleCodeTemplate, ModuleGraph, ModuleType, @@ -85,45 +86,11 @@ impl CommonJsExternalRequireKind { let require = self.render_callee(compilation, chunk_init_fragments); format!( "{require}({}){}", - request - .map(json_stringify_str) - .unwrap_or_else(|| "undefined".to_string()), + request.map_or_else(|| "undefined".to_string(), json_stringify_str), property_access(properties, 0) ) } - fn render_external_request( - self, - request: Option<&ExternalRequestValue>, - compilation: &Compilation, - chunk_init_fragments: &mut ChunkInitFragments, - ) -> String { - match request { - Some(request) => self.render_expression( - Some(request.primary()), - request.iter().skip(1), - compilation, - chunk_init_fragments, - ), - // Preserve the existing fallback for a missing object-form request: - // ESM node-commonjs used the undefined value while other CommonJS - // renderers requested the literal module name "undefined". - None if matches!(self, Self::NodeCommonJs) && compilation.options.output.module => self - .render_expression( - None, - iter::empty::<&str>(), - compilation, - chunk_init_fragments, - ), - None => self.render_expression( - Some("undefined"), - iter::empty::<&str>(), - compilation, - chunk_init_fragments, - ), - } - } - /// Renders only the require callee and installs its required init fragment. /// /// This is the split-range counterpart of [`Self::render_expression`]. @@ -588,6 +555,37 @@ pub struct DependencyMeta { } impl ExternalModule { + fn create_identifier( + request: &ExternalRequest, + external_type: &str, + dependency_meta: &DependencyMeta, + ) -> Identifier { + let resolved_type = resolve_external_type(external_type, dependency_meta); + let request_str = simd_json::to_string(request).expect("invalid json to_string"); + let attrs_str = dependency_meta + .attributes + .as_ref() + .map_or(String::new(), |attrs| { + format!( + " {}", + simd_json::to_string(attrs).expect("invalid json to_string") + ) + }); + let phase_str = if dependency_meta.phase == ImportPhase::Evaluation { + String::new() + } else { + format!(" phase={}", dependency_meta.phase.as_str()) + }; + let css_import_str = + css_module_render_conditions_identifier(dependency_meta.css_import_conditions.iter()) + .map_or(String::new(), |conditions| { + format!(" css-import-conditions={}", json_stringify_str(&conditions)) + }); + Identifier::from(format!( + "external {resolved_type} {request_str}{attrs_str}{phase_str}{css_import_str}" + )) + } + pub fn new( request: ExternalRequest, external_type: ExternalType, @@ -597,30 +595,7 @@ impl ExternalModule { ) -> Self { Self { dependencies_block: Default::default(), - id: Identifier::from({ - let resolved_type = resolve_external_type(external_type.as_str(), &dependency_meta); - let request_str = simd_json::to_string(&request).expect("invalid json to_string"); - let attrs_str = dependency_meta - .attributes - .as_ref() - .map_or(String::new(), |attrs| { - format!( - " {}", - simd_json::to_string(attrs).expect("invalid json to_string") - ) - }); - let phase_str = if dependency_meta.phase == ImportPhase::Evaluation { - String::new() - } else { - format!(" phase={}", dependency_meta.phase.as_str()) - }; - let css_import_str = - css_module_render_conditions_identifier(dependency_meta.css_import_conditions.iter()) - .map_or(String::new(), |conditions| { - format!(" css-import-conditions={}", json_stringify_str(&conditions)) - }); - format!("external {resolved_type} {request_str}{attrs_str}{phase_str}{css_import_str}") - }), + id: Self::create_identifier(&request, &external_type, &dependency_meta), request, external_type, user_request, @@ -654,6 +629,98 @@ impl ExternalModule { self.dependency_meta.phase } + fn module_import_identifier(&self, compilation: &Compilation) -> String { + let request = self.get_request(); + if to_identifier(&request.primary) == request.primary + && self.dependency_meta.attributes.is_none() + { + return request.primary.clone(); + } + let mut hasher = RspackHasher::from(&compilation.options.output); + use rspack_hash::RspackHash as _; + request.primary.hash(&mut hasher); + if let Some(attributes) = &self.dependency_meta.attributes { + simd_json::to_string(attributes) + .expect("json stringify failed") + .hash(&mut hasher); + } + let hash_suffix = hasher.digest(&compilation.options.output.hash_digest); + format!( + "{}_{}", + to_identifier(&request.primary), + hash_suffix.rendered(8) + ) + } + + /// Register a native import owned by the referencing module's scope. + pub fn register_module_import( + &self, + compilation: &Compilation, + scope: &mut ConcatenationScope, + imported: Option<&Atom>, + local: Option<&Atom>, + ) -> String { + let request = self.get_request(); + let attributes = self.module_import_attributes(); + let namespace = format!( + "__rspack_external_{}", + self.module_import_identifier(compilation) + ); + if let Some(imported) = imported { + let local = local.map_or_else( + || format!("{namespace}_{}", hex::encode(imported.as_bytes())), + ToString::to_string, + ); + scope.register_import_as( + request.primary.clone(), + attributes, + imported.clone(), + local.clone().into(), + ); + local + } else { + let local = local.cloned().unwrap_or_else(|| namespace.into()); + scope.register_namespace_import(request.primary.clone(), attributes, local.clone()); + local.to_string() + } + } + + pub fn module_import_attributes(&self) -> Option { + self.dependency_meta.attributes.as_ref().map(|attributes| { + format!( + " with {}", + simd_json::to_string(attributes).expect("json stringify failed") + ) + }) + } + + pub fn register_module_side_effect(&self, scope: &mut ConcatenationScope) { + scope.register_import( + self.get_request().primary.clone(), + self.module_import_attributes(), + None, + ); + } + + pub fn render_module_namespace( + &self, + compilation: &Compilation, + runtime: Option<&RuntimeSpec>, + runtime_template: &mut ModuleCodeTemplate, + ) -> (Option, String, ChunkInitFragments) { + get_source_for_module_external( + self.get_request(), + &self.module_import_identifier(compilation), + &self.dependency_meta, + &compilation.exports_info_artifact, + compilation + .exports_info_artifact + .get_exports_info_data(&self.identifier()), + runtime, + runtime_template, + ) + } + pub fn resolve_external_type(&self) -> &str { resolve_external_type(self.external_type.as_str(), &self.dependency_meta) } @@ -691,6 +758,7 @@ impl ExternalModule { map.insert(new_type.clone(), request); } self.external_type = new_type; + self.id = Self::create_identifier(&self.request, &self.external_type, &self.dependency_meta); } pub fn get_request(&self) -> &ExternalRequestValue { @@ -741,8 +809,19 @@ impl ExternalModule { get_source_for_global_variable_external(request, &compilation.options.output.global_object) ), _ if let Some(require_kind) = commonjs_require_kind => { - let require_expression = - require_kind.render_external_request(request, compilation, &mut chunk_init_fragments); + // For a missing object-form request, only ESM node-commonjs uses the + // undefined value; other CommonJS types request the name "undefined". + let fallback = (require_kind != CommonJsExternalRequireKind::NodeCommonJs + || !compilation.options.output.module) + .then_some("undefined"); + let require_expression = require_kind.render_expression( + request.map(ExternalRequestValue::primary).or(fallback), + request + .into_iter() + .flat_map(|request| request.iter().skip(1)), + compilation, + &mut chunk_init_fragments, + ); format!( "{} = {require_expression};", get_namespace_object_export(concatenation_scope, supports_const, runtime_template) @@ -822,26 +901,7 @@ impl ExternalModule { if compilation.options.output.module && let Some(request) = request { - let id: Cow<'_, str> = if to_identifier(&request.primary) != request.primary - || self.dependency_meta.attributes.is_some() - { - let mut hasher = RspackHasher::from(&compilation.options.output); - use rspack_hash::RspackHash as _; - request.primary.hash(&mut hasher); - if let Some(attributes) = &self.dependency_meta.attributes { - simd_json::to_string(attributes) - .expect("json stringify failed") - .hash(&mut hasher); - } - let hash_suffix = hasher.digest(&compilation.options.output.hash_digest); - Cow::Owned(format!( - "{}_{}", - to_identifier(&request.primary), - hash_suffix.rendered(8) - )) - } else { - to_identifier(&request.primary) - }; + let id = self.module_import_identifier(compilation); if let Some(concatenation_scope) = concatenation_scope { let exports_info = compilation .exports_info_artifact @@ -858,12 +918,7 @@ impl ExternalModule { .ns_access() }) ); - let attributes = self.dependency_meta.attributes.as_ref().map(|meta| { - format!( - " with {}", - simd_json::to_string(meta).expect("json stringify failed"), - ) - }); + let attributes = self.module_import_attributes(); #[derive(Clone, Copy)] struct ExternalImportOptimize(pub bool); diff --git a/crates/rspack_core/src/utils/concatenated_module_visitor.rs b/crates/rspack_core/src/utils/concatenated_module_visitor.rs index f1e6e6cd2da5..425b55b8fb6f 100644 --- a/crates/rspack_core/src/utils/concatenated_module_visitor.rs +++ b/crates/rspack_core/src/utils/concatenated_module_visitor.rs @@ -59,11 +59,10 @@ impl Visit for IdentCollector { } } - /// https://github.com/webpack/webpack/blob/1f99ad6367f2b8a6ef17cce0e058f7a67fb7db18/lib/optimize/ConcatenatedModule.js#L1173-L1197 + /// Reserve every class expression's inner name, even without a superclass, + /// so renaming an outer binding cannot make it captured by the class scope. fn visit_class_expr(&mut self, node: &ClassExpr) { - if let Some(ref ident) = node.ident - && node.class.super_class.is_some() - { + if let Some(ref ident) = node.ident { self.ids.push(ConcatenatedModuleIdent { id: ident.clone(), shorthand: false, diff --git a/crates/rspack_core/src/utils/concatenation_scope.rs b/crates/rspack_core/src/utils/concatenation_scope.rs index 0691b4074953..e0feb246a577 100644 --- a/crates/rspack_core/src/utils/concatenation_scope.rs +++ b/crates/rspack_core/src/utils/concatenation_scope.rs @@ -1,4 +1,7 @@ -use std::sync::{Arc, LazyLock}; +use std::{ + hash::Hash, + sync::{Arc, LazyLock}, +}; use anymap::CloneAny; use rspack_cacheable::{ @@ -22,7 +25,7 @@ const MODULE_REFERENCE_PREFIX: &str = "__rspack_module_ref"; const MODULE_REFERENCE_PROPERTY_ACCESS_SUFFIX: &str = "._"; #[cacheable] -#[derive(Default, Debug, Clone)] +#[derive(Default, Debug, Clone, Hash)] pub struct ModuleReferenceOptions { #[cacheable(with=AsVec)] pub ids: Vec, @@ -51,6 +54,37 @@ pub struct CodeGenerationDataConcatenationScopeOutput { refs: IdentifierIndexMap>, } +impl Hash for CodeGenerationDataConcatenationScopeOutput { + fn hash(&self, hasher: &mut H) { + // Native imports/reexports are emitted by the linker, not the module + // source. They must participate in the chunk-render cache key as well. + self.namespace_export_symbol.hash(hasher); + for map in [&self.export_map, &self.raw_export_map] { + let mut entries = map.iter().flat_map(|map| map.iter()).collect::>(); + entries.sort_unstable(); + entries.hash(hasher); + } + if let Some(import_map) = &self.import_map { + for (source, imports) in import_map { + source.hash(hasher); + let mut specifiers = imports.specifiers.iter().collect::>(); + specifiers.sort_unstable(); + specifiers.hash(hasher); + let mut namespaces = imports.namespaces.iter().collect::>(); + namespaces.sort_unstable(); + namespaces.hash(hasher); + } + } + for (module, refs) in &self.refs { + module.hash(hasher); + for (symbol, options) in refs { + symbol.hash(hasher); + options.hash(hasher); + } + } + } +} + impl CodeGenerationDataConcatenationScopeOutput { pub fn apply_to(&self, current_module: &mut ConcatenatedModuleInfo) { current_module @@ -139,20 +173,13 @@ impl ConcatenationScope { import_source: String, attributes: Option, import_symbol: Atom, - ) -> &Atom { + ) { let raw_import_map = self.current_module.import_map.get_or_insert_default(); let entry = raw_import_map .entry((import_source, attributes)) .or_default(); - if entry.namespace.is_none() { - entry.namespace = Some(import_symbol) - } - - entry - .namespace - .as_ref() - .expect("should have namespace symbol") + entry.namespaces.insert(import_symbol); } pub fn register_import( @@ -170,7 +197,26 @@ impl ConcatenationScope { return; }; - entry.specifiers.insert(import_symbol); + entry + .specifiers + .insert(import_symbol.clone(), import_symbol); + } + + pub fn register_import_as( + &mut self, + import_source: String, + attributes: Option, + imported: Atom, + local: Atom, + ) { + self + .current_module + .import_map + .get_or_insert_default() + .entry((import_source, attributes)) + .or_default() + .specifiers + .insert(local, imported); } pub fn register_namespace_export(&mut self, symbol: &str) { diff --git a/crates/rspack_plugin_esm_library/src/dependency/commonjs_external.rs b/crates/rspack_plugin_esm_library/src/dependency/commonjs_external.rs index 214000096a01..f2101336e2bd 100644 --- a/crates/rspack_plugin_esm_library/src/dependency/commonjs_external.rs +++ b/crates/rspack_plugin_esm_library/src/dependency/commonjs_external.rs @@ -5,18 +5,20 @@ use rspack_cacheable::{cacheable, cacheable_dyn}; use rspack_core::{ BuildModuleGraphArtifact, CodeGenerationDataItem, CommonJsExternalRequireKind, Dependency, DependencyCodeGeneration, DependencyId, DependencyRange, DependencyTemplate, TemplateContext, - TemplateReplaceSource, UsedName, property_access, + TemplateReplaceSource, }; use rspack_plugin_javascript::dependency::{ - CommonJsExportRequireDependency, CommonJsFullRequireDependency, CommonJsRequireDependency, - RequireHeaderDependency, + CommonJsExportRequireDependency, CommonJsExportRequireDependencyTemplate, + CommonJsFullRequireDependency, CommonJsRequireDependency, RequireHeaderDependency, }; use rspack_util::{ fx_hash::{FxHashMap, FxHashSet}, json_stringify_str, }; -pub type DirectCommonJsExternalDependencies = Arc>>>; +use super::ExternalBindingBailout; + +pub type DirectCommonJsExternalDependencies = Arc>>; #[cacheable] #[derive(Debug, Clone)] @@ -25,7 +27,7 @@ struct DirectExternalRequireHeaders(Vec<(DependencyRange, CommonJsExternalRequir #[cacheable_dyn] impl CodeGenerationDataItem for DirectExternalRequireHeaders {} -fn is_relative_external_request(request: &str) -> bool { +pub(super) fn is_relative_external_request(request: &str) -> bool { request == "." || request == ".." || request.starts_with("./") @@ -34,14 +36,6 @@ fn is_relative_external_request(request: &str) -> bool { || request.starts_with("..\\") } -fn can_render_direct_request(request: &str) -> bool { - // Both ambient `require` and `createRequire(import.meta.url)` resolve - // relative requests from the emitted asset containing the call. Keep those - // requests on the external-module path because direct rendering can move the - // call into an issuer emitted in another directory. - !is_relative_external_request(request) -} - pub fn cutout_commonjs_externals( build_module_graph_artifact: &mut BuildModuleGraphArtifact, ) -> FxHashSet { @@ -49,6 +43,9 @@ pub fn cutout_commonjs_externals( let mut direct_dependencies = FxHashSet::default(); for (_, module) in module_graph.modules() { + if ExternalBindingBailout::is_present(module.as_ref()) { + continue; + } let require_header_ranges = module .get_presentational_dependencies() .into_iter() @@ -63,8 +60,9 @@ pub fn cutout_commonjs_externals( let mut dependencies_by_range = FxHashMap::::default(); let mut self_rendering_require_dependencies = Vec::new(); - for dependency_id in module.get_dependencies() { - let dependency = module_graph.dependency_by_id(dependency_id); + for dependency in module.get_dependencies() { + let dependency = dependency.as_ref(); + let dependency_id = dependency.id(); if dependency.as_any().is::() || dependency.as_any().is::() { @@ -91,21 +89,13 @@ pub fn cutout_commonjs_externals( } let direct_require_candidates = dependencies_by_range - .into_values() - .filter_map(|(dependency_id, count)| { - if count != 1 { - return None; - } - let expression_range = module_graph - .dependency_by_id(&dependency_id) - .range() - .expect("grouped CommonJS require should have an expression range"); - require_header_ranges - .iter() - .any(|header_range| { + .into_iter() + .filter_map(|(expression_range, (dependency_id, count))| { + (count == 1 + && require_header_ranges.iter().any(|header_range| { expression_range.start <= header_range.start && header_range.end <= expression_range.end - }) - .then_some(dependency_id) + })) + .then_some(dependency_id) }) .chain(self_rendering_require_dependencies); for dependency_id in direct_require_candidates { @@ -130,7 +120,8 @@ pub fn cutout_commonjs_externals( if CommonJsExternalRequireKind::from_external_type(external_module.resolve_external_type()) .is_some() && !request.has_rest() - && can_render_direct_request(request.primary()) + // Relative calls must stay in the external module's emitted directory. + && !is_relative_external_request(request.primary()) { direct_dependencies.insert(dependency_id); } @@ -150,10 +141,9 @@ pub fn cutout_commonjs_externals( fn get_direct_external_require( dependency_id: &DependencyId, - expression_range: DependencyRange, direct_dependencies: &DirectCommonJsExternalDependencies, context: &TemplateContext, -) -> Option<(String, DependencyRange, CommonJsExternalRequireKind)> { +) -> Option<(String, CommonJsExternalRequireKind)> { if !direct_dependencies.borrow().contains(dependency_id) { return None; } @@ -166,108 +156,38 @@ fn get_direct_external_require( Some(( external_module.get_request().primary().to_string(), - expression_range, CommonJsExternalRequireKind::from_external_type(external_module.resolve_external_type())?, )) } -fn render_direct_require( - request: &str, - properties: &[rspack_util::atom::Atom], - kind: CommonJsExternalRequireKind, - context: &mut TemplateContext, -) -> String { - let compilation = context.compilation; - kind.render_expression( - Some(request), - properties, - compilation, - context.chunk_init_fragments(), - ) -} - #[derive(Debug)] -pub struct DirectCommonJsRequireDependencyTemplate { +pub struct DirectCommonJsDependencyTemplate { pub direct_dependencies: DirectCommonJsExternalDependencies, pub template: Option>, } -impl DependencyTemplate for DirectCommonJsRequireDependencyTemplate { +impl DependencyTemplate for DirectCommonJsDependencyTemplate { fn render( &self, dependency: &dyn DependencyCodeGeneration, source: &mut TemplateReplaceSource, context: &mut TemplateContext, ) { - let dependency = dependency + let require = dependency .as_any() - .downcast_ref::() - .expect( - "DirectCommonJsRequireDependencyTemplate should only be used for CommonJsRequireDependency", - ); - - let Some(expression_range) = dependency.range() else { - if let Some(template) = &self.template { - template.render(dependency, source, context); - } - return; - }; - let Some((request, expression_range, kind)) = get_direct_external_require( - dependency.id(), - expression_range, - &self.direct_dependencies, - context, - ) else { - if let Some(template) = &self.template { - template.render(dependency, source, context); - } - return; - }; - - let request_range = dependency.request_range(); - source.replace( - request_range.start, - request_range.end, - json_stringify_str(&request), - None, - ); - - if context.data.get::().is_none() { - context - .data - .insert(DirectExternalRequireHeaders(Vec::new())); - } - context - .data - .get_mut::() - .expect("direct external require headers should be initialized") - .0 - .push((expression_range, kind)); - } -} - -#[derive(Debug)] -pub struct DirectCommonJsExportRequireDependencyTemplate { - pub direct_dependencies: DirectCommonJsExternalDependencies, - pub template: Option>, -} - -impl DependencyTemplate for DirectCommonJsExportRequireDependencyTemplate { - fn render( - &self, - dependency: &dyn DependencyCodeGeneration, - source: &mut TemplateReplaceSource, - context: &mut TemplateContext, - ) { - let dependency = dependency + .downcast_ref::(); + let full_require = dependency .as_any() - .downcast_ref::() - .expect( - "DirectCommonJsExportRequireDependencyTemplate should only be used for CommonJsExportRequireDependency", - ); - let range = dependency.range(); - let Some((request, _, kind)) = - get_direct_external_require(dependency.id(), range, &self.direct_dependencies, context) + .downcast_ref::(); + let export_require = dependency + .as_any() + .downcast_ref::(); + let id = require + .map(Dependency::id) + .or_else(|| full_require.map(Dependency::id)) + .or_else(|| export_require.map(Dependency::id)) + .expect("only CommonJS dependency templates are wrapped"); + let Some((request, kind)) = get_direct_external_require(id, &self.direct_dependencies, context) else { if let Some(template) = &self.template { template.render(dependency, source, context); @@ -275,86 +195,46 @@ impl DependencyTemplate for DirectCommonJsExportRequireDependencyTemplate { return; }; - let module_graph = context.compilation.get_module_graph(); - let module = module_graph - .module_by_identifier(&context.module.identifier()) - .expect("CommonJS export require should have a module graph module"); - let base = dependency.base(); - let base = if base.is_exports() { - context - .runtime_template - .render_exports_argument(module.get_exports_argument()) - } else if base.is_module_exports() { - format!( - "{}.exports", - context - .runtime_template - .render_module_argument(module.get_module_argument()) - ) - } else if base.is_this() { - context.runtime_template.render_this_exports() - } else { - unreachable!("CommonJS export require should use an expression base") - }; - let used = context - .compilation - .exports_info_artifact - .get_exports_info_data(&module.identifier()) - .get_used_name( - &context.compilation.exports_info_artifact, - context.runtime, - dependency.names(), + if let Some(dep) = require { + let range = dep.request_range(); + source.replace(range.start, range.end, json_stringify_str(&request), None); + let header = ( + dep.range().expect("direct require has an expression range"), + kind, ); - let require_expression = - render_direct_require(&request, dependency.get_ids(module_graph), kind, context); - - let expression = match used { - Some(UsedName::Normal(used)) => { - format!("{base}{} = {require_expression}", property_access(used, 0)) - } - Some(UsedName::Inlined(_)) => { - format!("/* inlined reexport */ {require_expression}") + if let Some(headers) = context.data.get_mut::() { + headers.0.push(header); + } else { + context + .data + .insert(DirectExternalRequireHeaders(vec![header])); } - None => format!("/* unused reexport */ {require_expression}"), - }; - source.replace(range.start, range.end, expression, None); - } -} - -#[derive(Debug)] -pub struct DirectCommonJsFullRequireDependencyTemplate { - pub direct_dependencies: DirectCommonJsExternalDependencies, - pub template: Option>, -} - -impl DependencyTemplate for DirectCommonJsFullRequireDependencyTemplate { - fn render( - &self, - dependency: &dyn DependencyCodeGeneration, - source: &mut TemplateReplaceSource, - context: &mut TemplateContext, - ) { - let dependency = dependency - .as_any() - .downcast_ref::() - .expect( - "DirectCommonJsFullRequireDependencyTemplate should only be used for CommonJsFullRequireDependency", + } else if let Some(dep) = full_require { + let mut expression = kind.render_expression( + Some(&request), + dep.names(), + context.compilation, + context.chunk_init_fragments(), ); - let range = dependency.range(); - let Some((request, _, kind)) = - get_direct_external_require(dependency.id(), range, &self.direct_dependencies, context) - else { - if let Some(template) = &self.template { - template.render(dependency, source, context); + if dep.asi_safe() { + expression = format!("({expression})"); } - return; - }; - - let mut expression = render_direct_require(&request, dependency.names(), kind, context); - if dependency.asi_safe() { - expression = format!("({expression})"); + let range = dep.range(); + source.replace(range.start, range.end, expression, None); + } else if let Some(dep) = export_require { + let expression = kind.render_expression( + Some(&request), + dep.get_ids(context.compilation.get_module_graph()), + context.compilation, + context.chunk_init_fragments(), + ); + CommonJsExportRequireDependencyTemplate.render_with_require( + dep, + source, + context, + Some(expression), + ); } - source.replace(range.start, range.end, expression, None); } } @@ -392,19 +272,11 @@ impl DependencyTemplate for DirectRequireHeaderDependencyTemplate { .map(|(_, kind)| *kind) }); - match direct_require_kind { - Some(kind) => { - let compilation = context.compilation; - let require = kind - .render_callee(compilation, context.chunk_init_fragments()) - .to_string(); - source.replace(header_range.start, header_range.end, require, None); - } - None => { - if let Some(template) = &self.template { - template.render(dependency, source, context); - } - } + if let Some(kind) = direct_require_kind { + let require = kind.render_callee(context.compilation, context.chunk_init_fragments()); + source.replace_static(header_range.start, header_range.end, require, None); + } else if let Some(template) = &self.template { + template.render(dependency, source, context); } } } diff --git a/crates/rspack_plugin_esm_library/src/dependency/esm_external.rs b/crates/rspack_plugin_esm_library/src/dependency/esm_external.rs new file mode 100644 index 000000000000..9a91ab6d49d0 --- /dev/null +++ b/crates/rspack_plugin_esm_library/src/dependency/esm_external.rs @@ -0,0 +1,178 @@ +use std::sync::Arc; + +use atomic_refcell::AtomicRefCell; +use rspack_core::{ + BuildModuleGraphArtifact, Compilation, Dependency, DependencyCodeGeneration, DependencyId, + DependencyTemplate, ExportsInfoArtifact, ExternalModule, ImportPhase, ModuleGraphConnection, + TemplateContext, TemplateReplaceSource, +}; +use rspack_plugin_javascript::dependency::{ + ESMExportImportedSpecifierDependency, ESMExportImportedSpecifierDependencyTemplate, + ESMImportSideEffectDependency, ESMImportSpecifierDependency, + ESMImportSpecifierDependencyTemplate, esm_import_external, +}; +use rspack_util::fx_hash::FxHashMap; + +use super::{ExternalBindingBailout, commonjs_external::is_relative_external_request}; + +pub type DirectEsmExternalDependencies = + Arc>>; + +pub fn requires_issuer_identity(external: &ExternalModule) -> bool { + let request = external.get_request(); + // Relative imports must remain in the issuer's emitted directory. Projected + // namespaces are expressions, not bindings that can be exported by a shared chunk. + request.has_rest() || is_relative_external_request(request.primary()) +} + +pub fn can_render_esm_external(dependency: &dyn Dependency, external: &ExternalModule) -> bool { + external.resolve_external_type() == "module" + && !dependency + .as_module_dependency() + .is_some_and(|dependency| dependency.weak()) + && external.get_import_phase() == ImportPhase::Evaluation + && !requires_issuer_identity(external) + && (dependency.as_any().is::() + || dependency.as_any().is::() + || dependency + .as_any() + .is::()) +} + +pub fn cutout_esm_externals( + compilation: &Compilation, + artifact: &mut BuildModuleGraphArtifact, + exports_info: &ExportsInfoArtifact, + direct: &DirectEsmExternalDependencies, +) { + let mg = artifact.get_module_graph(); + let mut previous = std::mem::take(&mut *direct.borrow_mut()); + let mut connections = FxHashMap::default(); + for (_, module) in mg.modules() { + if ExternalBindingBailout::is_present(module.as_ref()) { + continue; + } + for dependency in module.get_dependencies() { + let dependency = dependency.as_ref(); + let id = dependency.id(); + let Some(connection) = mg.connection_by_dependency_id(id) else { + continue; + }; + let Some(external) = mg + .module_by_identifier(connection.module_identifier()) + .and_then(|module| module.as_external_module()) + else { + continue; + }; + // Checked/partial reexports still need their original template semantics. + // Keep their edge, instead of changing the issuer's scope-hoisting decision. + if let Some(dependency) = dependency + .as_any() + .downcast_ref::() + && !ESMExportImportedSpecifierDependencyTemplate::supports_direct_scope_export( + &dependency.get_mode( + mg, + None, + &compilation.module_graph_cache_artifact, + exports_info, + ), + ) + { + continue; + } + if can_render_esm_external(dependency, external) + && (previous.contains_key(id) + || connection.is_active( + mg, + None, + &compilation.module_graph_cache_artifact, + &artifact.side_effects_state_artifact, + exports_info, + )) + { + // OptimizeDependencies may run more than once. Preserve the semantic + // condition, while only disabling placement in the chunk graph. + connections.insert( + *id, + previous.remove(id).unwrap_or_else(|| connection.clone()), + ); + } + } + } + let mg = artifact.get_module_graph_mut(); + for id in connections.keys() { + mg.connection_by_dependency_id_mut(id) + .expect("external connection should exist") + .force_inactive(); + } + *direct.borrow_mut() = connections; +} + +#[derive(Debug)] +pub struct DirectEsmExternalDependencyTemplate { + pub direct: DirectEsmExternalDependencies, + pub template: Arc, +} + +impl DependencyTemplate for DirectEsmExternalDependencyTemplate { + fn render( + &self, + dependency: &dyn DependencyCodeGeneration, + source: &mut TemplateReplaceSource, + context: &mut TemplateContext, + ) { + let side_effect = dependency + .as_any() + .downcast_ref::(); + let specifier = dependency + .as_any() + .downcast_ref::(); + let reexport = dependency + .as_any() + .downcast_ref::(); + let id = side_effect + .map(Dependency::id) + .or_else(|| specifier.map(Dependency::id)) + .or_else(|| reexport.map(Dependency::id)) + .expect("only ESM dependency templates are wrapped"); + let direct = self.direct.borrow(); + let Some(connection) = direct.get(id) else { + self.template.render(dependency, source, context); + return; + }; + let compilation = context.compilation; + let mg = compilation.get_module_graph(); + if !connection.is_target_active( + mg, + context.runtime, + &compilation.module_graph_cache_artifact, + &compilation + .build_module_graph_artifact + .side_effects_state_artifact, + &compilation.exports_info_artifact, + ) { + return; + } + let external = mg + .module_by_identifier(connection.module_identifier()) + .and_then(|module| module.as_external_module()) + .expect("direct dependency should target an external"); + if let Some(dep) = side_effect { + if let Some(scope) = context.concatenation_scope.as_mut() { + external.register_module_side_effect(scope); + } else { + esm_import_external(external, dep, context); + } + } else if let Some(dep) = specifier { + ESMImportSpecifierDependencyTemplate.render_with_external( + dep, + source, + context, + Some((external, connection)), + ); + } else if let Some(dep) = reexport { + ESMExportImportedSpecifierDependencyTemplate + .render_external(dep, external, connection, context); + } + } +} diff --git a/crates/rspack_plugin_esm_library/src/dependency/mod.rs b/crates/rspack_plugin_esm_library/src/dependency/mod.rs index 4079c6574cb8..9460e14eeeaf 100644 --- a/crates/rspack_plugin_esm_library/src/dependency/mod.rs +++ b/crates/rspack_plugin_esm_library/src/dependency/mod.rs @@ -1,2 +1,45 @@ pub mod commonjs_external; pub mod dyn_import; +pub mod esm_external; + +use rspack_cacheable::{cacheable, cacheable_dyn}; +use rspack_core::{ + DependencyCodeGeneration, DependencyTemplate, DependencyTemplateType, Module, TemplateContext, + TemplateReplaceSource, +}; + +/// Keep generated external bindings outside issuers that use Rspack's identifier +/// namespace. Persist this parser result with the module, including nested scopes. +#[cacheable] +#[derive(Debug)] +pub(crate) struct ExternalBindingBailout; + +impl ExternalBindingBailout { + pub fn template_type() -> DependencyTemplateType { + DependencyTemplateType::Custom("EsmExternalBindingBailout") + } + + pub fn is_present(module: &dyn Module) -> bool { + module + .get_presentational_dependencies() + .is_some_and(|deps| deps.iter().any(|dep| dep.as_any().is::())) + } +} + +#[cacheable_dyn] +impl DependencyCodeGeneration for ExternalBindingBailout { + fn dependency_template(&self) -> Option { + Some(Self::template_type()) + } +} + +impl DependencyTemplate for ExternalBindingBailout { + fn render( + &self, + _dependency: &dyn DependencyCodeGeneration, + _source: &mut TemplateReplaceSource, + _context: &mut TemplateContext, + ) { + // Parser metadata only; the original dependency templates render the issuer. + } +} diff --git a/crates/rspack_plugin_esm_library/src/esm_lib_parser_plugin.rs b/crates/rspack_plugin_esm_library/src/esm_lib_parser_plugin.rs index 04436603ffe9..a741e47cbe68 100644 --- a/crates/rspack_plugin_esm_library/src/esm_lib_parser_plugin.rs +++ b/crates/rspack_plugin_esm_library/src/esm_lib_parser_plugin.rs @@ -1,14 +1,29 @@ use std::sync::Arc; -use rspack_core::DependencyType; +use rspack_core::{DependencyType, collect_ident}; use rspack_plugin_javascript::{ JavascriptParserPlugin, dependency::ESMCompatibilityDependency, visitors::JavascriptParser, }; + +use crate::dependency::ExternalBindingBailout; + pub struct EsmLibParserPlugin; #[rspack_plugin_javascript::implemented_javascript_parser_hooks] impl<'p, 'a> JavascriptParserPlugin<'p, 'a> for EsmLibParserPlugin { fn finish(&self, parser: &mut JavascriptParser<'p>) -> Option { + // These bindings are introduced after parsing. A source-level collision + // cannot be repaired by the linker's top-level deconfliction, especially + // inside wrapped modules or function parameters. Inspect decoded AST names + // so escaped identifiers are covered as well. + if !parser.get_dependencies().is_empty() + && collect_ident(parser.ast.allocator, parser.ast.program) + .iter() + .any(|ident| ident.id.sym.as_str().starts_with("__rspack_")) + { + parser.add_presentational_dependency(Arc::new(ExternalBindingBailout)); + } + if parser.module_type.is_js_auto() && matches!( parser.build_meta.exports_type(), diff --git a/crates/rspack_plugin_esm_library/src/link.rs b/crates/rspack_plugin_esm_library/src/link.rs index fed00512cc04..a2d4a508588b 100644 --- a/crates/rspack_plugin_esm_library/src/link.rs +++ b/crates/rspack_plugin_esm_library/src/link.rs @@ -32,6 +32,7 @@ use rspack_util::fx_hash::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet}; use crate::{ EsmLibraryPlugin, chunk_link::{ChunkLinkContext, ExternalInterop, RawImportSource, ReExportFrom, Ref, SymbolRef}, + dependency::esm_external::DirectEsmExternalDependencies, }; pub(crate) trait GetMut { @@ -473,18 +474,17 @@ impl EsmLibraryPlugin { let raw_import_source = RawImportSource::Source((source.clone(), attr.clone())); if imported_atoms - .namespace - .as_ref() - .is_some_and(|namespace| namespace == local_name) - || info.namespace_object_name.as_ref() == Some(local_name) + .namespaces + .iter() + .any(|namespace| info.get_internal_name(namespace).unwrap_or(namespace) == local_name) + || (info.namespace_export_symbol.is_some() + && info.namespace_object_name.as_ref() == Some(local_name)) { return Some((raw_import_source, ExternalImportBinding::Namespace)); } - for imported_name in &imported_atoms.specifiers { - let internal_name = info - .get_internal_name(imported_name) - .unwrap_or(imported_name); + for (local, imported_name) in &imported_atoms.specifiers { + let internal_name = info.get_internal_name(local).unwrap_or(local); if internal_name != local_name { continue; } @@ -501,7 +501,9 @@ impl EsmLibraryPlugin { } } - if info.namespace_object_name.as_ref() == Some(local_name) { + if info.namespace_export_symbol.is_some() + && info.namespace_object_name.as_ref() == Some(local_name) + { return Self::collect_module_external_namespace_imports(&info.chunk_init_fragments) .into_iter() .next() @@ -818,28 +820,57 @@ impl EsmLibraryPlugin { .build_module_graph_artifact .side_effects_state_artifact, binding_resolver.context.exports_info_artifact, + &self.direct_esm_external_dependencies, &mut namespace_re_export_star_cache, ) .and_then(|target_module| { + if let Some(external) = module_graph + .module_by_identifier(&target_module) + .and_then(|module| module.as_external_module()) + && compilation + .build_chunk_graph_artifact + .chunk_graph + .try_get_module_chunks(&target_module) + .is_none_or(|chunks| chunks.is_empty()) + { + let import_source = RawImportSource::Source(( + external.get_request().primary().into(), + external.module_import_attributes(), + )); + let existing = chunk_link + .module_external_namespace_imports + .get(&import_source) + .cloned(); + let imports = chunk_link + .raw_import_stmts + .entry(import_source) + .or_default(); + let local = imports.ns_import.get_or_insert_with(|| { + existing.unwrap_or_else(|| chunk_link.name_allocator.find_new_name("external", &[])) + }); + return Some(local.to_string()); + } let target_strict_esm_module = module_graph .module_by_identifier(&target_module) .expect("should have target module") .build_meta() .strict_esm_module(); - self.get_binding( - None, - &mut binding_resolver, - &target_module, - vec![], - &mut needed_namespace_objects, - false, - false, - target_strict_esm_module, - None, - &mut chunk_link.required, - &mut chunk_link.name_allocator, - ) + self + .get_binding( + None, + &mut binding_resolver, + &target_module, + vec![], + &mut needed_namespace_objects, + false, + false, + target_strict_esm_module, + None, + &mut chunk_link.required, + &mut chunk_link.name_allocator, + ) + .map(|binding| binding.render().into_owned()) }); let star_re_export_getters = if let Some(binding) = star_re_export_binding { let star_exports_base = format!("{name}_starExports"); @@ -856,7 +887,7 @@ Object.keys({}).forEach(function(key) {{ }}); "#, star_exports_name, - binding.render(), + binding, star_exports_name, runtime_template.render_runtime_globals(&RuntimeGlobals::DEFINE_PROPERTY_GETTERS), name, @@ -1107,57 +1138,40 @@ var {} = {{}}; if let Some(import_map) = concate_info.import_map.take() { for ((source, attr), imported_atoms) in &import_map { let raw_import_source = RawImportSource::Source((source.clone(), attr.clone())); - let existing_namespace_import = chunk_link + let mut existing_namespace_import = chunk_link .module_external_namespace_imports .get(&raw_import_source) + .or_else(|| { + chunk_link + .raw_import_stmts + .get(&raw_import_source) + .and_then(|spec| spec.ns_import.as_ref()) + }) .cloned(); - let mut total_imported_atoms = None; - - if imported_atoms.namespace.is_none() - && imported_atoms.specifiers.is_empty() - && existing_namespace_import.is_none() - { - total_imported_atoms = Some( + for ns_import in &imported_atoms.namespaces { + let local = existing_namespace_import.get_or_insert_with(|| { + let local = name_allocator.find_new_name(ns_import, &[]); chunk_link .raw_import_stmts .entry(raw_import_source.clone()) - .or_default(), - ); + .or_default() + .ns_import = Some(local.clone()); + local + }); + concate_info + .internal_names + .insert(ns_import.clone(), local.clone()); } - if let Some(ns_import) = &imported_atoms.namespace { - if let Some(existing_local) = existing_namespace_import.as_ref() { - if existing_local != ns_import { - concate_info - .internal_names - .insert(ns_import.clone(), existing_local.clone()); - } - } else { - total_imported_atoms = Some( - chunk_link - .raw_import_stmts - .entry(raw_import_source.clone()) - .or_default(), - ); - total_imported_atoms - .as_mut() - .expect("should have import spec") - .ns_import = Some(ns_import.clone()); - } + if imported_atoms.specifiers.is_empty() && existing_namespace_import.is_some() { + continue; } - - for atom in &imported_atoms.specifiers { - if total_imported_atoms.is_none() { - total_imported_atoms = Some( - chunk_link - .raw_import_stmts - .entry(raw_import_source.clone()) - .or_default(), - ); - } - let total_imported_atoms = total_imported_atoms - .as_mut() - .expect("should have import spec"); + // Also register side-effect-only imports when no namespace already covers them. + let total_imported_atoms = chunk_link + .raw_import_stmts + .entry(raw_import_source) + .or_default(); + for (local_name, atom) in &imported_atoms.specifiers { let existing_name = total_imported_atoms.atoms.get(atom).or_else(|| { if atom == "default" && let Some(default_symbol) = &total_imported_atoms.default_import @@ -1168,6 +1182,7 @@ var {} = {{}}; } }); let new_name = name_allocator.assign_import_binding_name( + local_name, atom, existing_name, source, @@ -1534,12 +1549,14 @@ var {} = {{}}; require_info } + #[allow(clippy::too_many_arguments)] fn resolve_re_export_star_from_unknown( module_id: ModuleIdentifier, module_graph: &ModuleGraph, module_graph_cache: &ModuleGraphCacheArtifact, side_effects_state_artifact: &SideEffectsStateArtifact, exports_info_artifact: &ExportsInfoArtifact, + direct: &DirectEsmExternalDependencies, collect_own_exports: bool, cache: &mut IdentifierMap>>, ) -> FxIndexSet> { @@ -1573,8 +1590,12 @@ var {} = {{}}; FxIndexSet::default() }; + let connections = direct.borrow(); for dep in module.get_dependencies() { - let Some(conn) = module_graph.connection_by_dependency_id(dep.id()) else { + let Some(conn) = connections + .get(dep.id()) + .or_else(|| module_graph.connection_by_dependency_id(dep.id())) + else { continue; }; @@ -1606,6 +1627,7 @@ var {} = {{}}; module_graph_cache, side_effects_state_artifact, exports_info_artifact, + direct, true, cache, )); @@ -1626,6 +1648,7 @@ var {} = {{}}; module_graph_cache: &ModuleGraphCacheArtifact, side_effects_state_artifact: &SideEffectsStateArtifact, exports_info_artifact: &ExportsInfoArtifact, + direct: &DirectEsmExternalDependencies, cache: &mut IdentifierMap>>, ) -> Option { let mut star_target = None; @@ -1635,6 +1658,7 @@ var {} = {{}}; module_graph_cache, side_effects_state_artifact, exports_info_artifact, + direct, false, cache, ) { @@ -1830,6 +1854,7 @@ var {} = {{}}; .build_module_graph_artifact .side_effects_state_artifact, binding_resolver.context.exports_info_artifact, + &self.direct_esm_external_dependencies, // When filter_unused is true, own exports are already collected and filtered // by usage above — only collect `export *` targets here. // When filter_unused is false (entry modules), also collect own exports. @@ -2797,6 +2822,14 @@ var {} = {{}}; None } }) + .chain(chunk_link.hoisted_modules.iter().flat_map(|module| { + let info = binding_resolver.module_to_info_map[module].as_concatenated(); + info.idents.iter().filter_map(move |ident| { + (ident.id.ctxt == info.module_ctxt) + .then(|| info.get_internal_name(&ident.id.sym)) + .flatten() + }) + })) .collect::>(); let all_chunk_exported_symbols = &exports[&chunk_link.chunk].exports; @@ -2822,7 +2855,9 @@ var {} = {{}}; continue; }; - if specifiers.atoms.is_empty() && specifiers.default_import.is_none() { + if (specifiers.atoms.is_empty() && specifiers.default_import.is_none()) + || specifiers.ns_import.is_some() + { // import 'externals' continue; } diff --git a/crates/rspack_plugin_esm_library/src/plugin.rs b/crates/rspack_plugin_esm_library/src/plugin.rs index 7aa143dcb6ea..3edc3de45b89 100644 --- a/crates/rspack_plugin_esm_library/src/plugin.rs +++ b/crates/rspack_plugin_esm_library/src/plugin.rs @@ -5,22 +5,20 @@ use std::{ use atomic_refcell::AtomicRefCell; use regex::Regex; -use rspack_collections::{ - Identifiable, Identifier, IdentifierIndexMap, IdentifierMap, IdentifierSet, -}; +use rspack_collections::{Identifiable, IdentifierIndexMap, IdentifierMap, IdentifierSet}; use rspack_core::{ ApplyContext, AssetInfo, AsyncModulesArtifact, BoxModule, BuildModuleGraphArtifact, ChunkUkey, Compilation, CompilationAdditionalChunkRuntimeRequirements, CompilationAdditionalModuleRuntimeRequirements, CompilationAdditionalTreeRuntimeRequirements, CompilationAfterCodeGeneration, CompilationConcatenationScope, CompilationFinishModules, - CompilationOptimizeChunkModules, CompilationOptimizeChunks, CompilationOptimizeDependencies, - CompilationParams, CompilationProcessAssets, CompilationRuntimeRequirementInTree, - CompilerCompilation, ConcatenatedModuleInfo, ConcatenationScope, DependencyType, - ExportsInfoArtifact, ExternalModuleInfo, GetTargetResult, JavascriptParserUrl, Logger, - ModuleFactoryCreateData, ModuleGraph, ModuleIdentifier, ModuleInfo, ModuleType, - NormalModuleFactoryAfterFactorize, NormalModuleFactoryParser, ParserAndGenerator, ParserOptions, - Plugin, REQUIRE_SCOPE_GLOBALS, RuntimeCodeTemplate, RuntimeGlobals, RuntimeModule, - SideEffectsOptimizeArtifact, SideEffectsStateArtifact, get_target, is_esm_dep_like, + CompilationOptimizeChunks, CompilationOptimizeDependencies, CompilationParams, + CompilationProcessAssets, CompilationRuntimeRequirementInTree, CompilerCompilation, + ConcatenatedModuleInfo, ConcatenationScope, DependencyType, ExportsInfoArtifact, + ExternalModuleInfo, GetTargetResult, JavascriptParserUrl, Logger, ModuleFactoryCreateData, + ModuleGraph, ModuleIdentifier, ModuleInfo, ModuleType, NormalModuleFactoryAfterFactorize, + NormalModuleFactoryParser, ParserAndGenerator, ParserOptions, Plugin, REQUIRE_SCOPE_GLOBALS, + RuntimeCodeTemplate, RuntimeGlobals, RuntimeModule, SideEffectsOptimizeArtifact, + SideEffectsStateArtifact, get_target, is_esm_dep_like, rspack_sources::{ReplaceSource, Source}, }; use rspack_error::{Diagnostic, Result}; @@ -30,7 +28,9 @@ use rspack_plugin_javascript::{ JavascriptModulesRenderChunkContent, JsPlugin, RenderSource, dependency::{ CommonJsExportRequireDependencyTemplate, CommonJsFullRequireDependencyTemplate, - CommonJsRequireDependencyTemplate, ImportDependencyTemplate, RequireHeaderDependencyTemplate, + CommonJsRequireDependencyTemplate, ESMExportImportedSpecifierDependencyTemplate, + ESMImportSideEffectDependencyTemplate, ESMImportSpecifierDependencyTemplate, + ImportDependencyTemplate, RequireHeaderDependencyTemplate, }, parser_and_generator::JavaScriptParserAndGenerator, }; @@ -46,12 +46,16 @@ use tokio::sync::RwLock; use crate::{ chunk_link::ChunkLinkContext, dependency::{ + ExternalBindingBailout, commonjs_external::{ - DirectCommonJsExportRequireDependencyTemplate, DirectCommonJsExternalDependencies, - DirectCommonJsFullRequireDependencyTemplate, DirectCommonJsRequireDependencyTemplate, + DirectCommonJsDependencyTemplate, DirectCommonJsExternalDependencies, DirectRequireHeaderDependencyTemplate, cutout_commonjs_externals, }, dyn_import::DynamicImportDependencyTemplate, + esm_external::{ + DirectEsmExternalDependencies, DirectEsmExternalDependencyTemplate, cutout_esm_externals, + requires_issuer_identity, + }, }, esm_lib_parser_plugin::EsmLibParserPlugin, optimize_chunks::{ @@ -85,6 +89,7 @@ pub struct EsmLibraryPlugin { pub(crate) all_dyn_targets: AtomicRefCell, pub(crate) namespace_targets: AtomicRefCell, pub(crate) direct_commonjs_external_dependencies: DirectCommonJsExternalDependencies, + pub(crate) direct_esm_external_dependencies: DirectEsmExternalDependencies, /// module_id → namespace export name in the chunk, for modules whose exports /// were renamed in a multi-module chunk. Written during link, read during code generation. pub(crate) dyn_import_ns_map: Arc>>, @@ -104,6 +109,7 @@ impl EsmLibraryPlugin { Default::default(), Default::default(), Default::default(), + Default::default(), ) } @@ -282,6 +288,26 @@ async fn compilation( compilation: &mut Compilation, _params: &mut CompilationParams, ) -> Result<()> { + self.direct_esm_external_dependencies.borrow_mut().clear(); + compilation.set_dependency_template( + ExternalBindingBailout::template_type(), + Arc::new(ExternalBindingBailout), + ); + for template_type in [ + ESMImportSideEffectDependencyTemplate::template_type(), + ESMImportSpecifierDependencyTemplate::template_type(), + ESMExportImportedSpecifierDependencyTemplate::template_type(), + ] { + if let Some(template) = compilation.get_dependency_template(template_type.clone()) { + compilation.set_dependency_template( + template_type, + Arc::new(DirectEsmExternalDependencyTemplate { + direct: self.direct_esm_external_dependencies.clone(), + template, + }), + ); + } + } let hooks = JsPlugin::get_compilation_hooks_mut(compilation.id()); let mut hooks = hooks.write().await; hooks @@ -295,33 +321,20 @@ async fn compilation( dyn_import_ns_map: self.dyn_import_ns_map.clone(), }), ); - let commonjs_require_template = - compilation.get_dependency_template(CommonJsRequireDependencyTemplate::template_type()); - compilation.set_dependency_template( + for template_type in [ CommonJsRequireDependencyTemplate::template_type(), - Arc::new(DirectCommonJsRequireDependencyTemplate { - direct_dependencies: self.direct_commonjs_external_dependencies.clone(), - template: commonjs_require_template, - }), - ); - let commonjs_export_require_template = - compilation.get_dependency_template(CommonJsExportRequireDependencyTemplate::template_type()); - compilation.set_dependency_template( CommonJsExportRequireDependencyTemplate::template_type(), - Arc::new(DirectCommonJsExportRequireDependencyTemplate { - direct_dependencies: self.direct_commonjs_external_dependencies.clone(), - template: commonjs_export_require_template, - }), - ); - let commonjs_full_require_template = - compilation.get_dependency_template(CommonJsFullRequireDependencyTemplate::template_type()); - compilation.set_dependency_template( CommonJsFullRequireDependencyTemplate::template_type(), - Arc::new(DirectCommonJsFullRequireDependencyTemplate { - direct_dependencies: self.direct_commonjs_external_dependencies.clone(), - template: commonjs_full_require_template, - }), - ); + ] { + let template = compilation.get_dependency_template(template_type.clone()); + compilation.set_dependency_template( + template_type, + Arc::new(DirectCommonJsDependencyTemplate { + direct_dependencies: self.direct_commonjs_external_dependencies.clone(), + template, + }), + ); + } let require_header_template = compilation.get_dependency_template(RequireHeaderDependencyTemplate::template_type()); compilation.set_dependency_template( @@ -723,121 +736,18 @@ async fn after_factorize( data: &mut ModuleFactoryCreateData, module: &mut BoxModule, ) -> Result<()> { - // Check if this is an external module using the existing downcast helper - if let Some(external_module) = module.as_external_module_mut() - && external_module.resolve_external_type() == "module" - && (external_module.get_external_type() != "modern-module" - || data - .dependencies - .first() - .is_some_and(|dependency| is_esm_dep_like(dependency.as_ref()))) + if let Some(external) = module.as_external_module_mut() + && external.resolve_external_type() == "module" + && requires_issuer_identity(external) + && let Some(issuer) = &data.issuer_identifier { - // If there's an issuer, append it to the module id - if let Some(issuer_identifier) = &data.issuer_identifier { - let current_id = external_module.identifier(); - let new_id = Identifier::from(format!("{current_id}|{issuer_identifier}")); - external_module.set_id(new_id); - } + external.set_id(format!("{}|{issuer}", external.identifier()).into()); } Ok(()) } -#[plugin_hook(CompilationOptimizeChunkModules for EsmLibraryPlugin, stage = 100)] -async fn optimize_chunk_modules(&self, compilation: &mut Compilation) -> Result> { - // Group duplicate external modules by (base_id, chunk) so we only merge - // duplicates within the same chunk. Merging across chunks would cause a - // module to appear in multiple chunks, which violates get_module_chunk's - // single-chunk assumption. - let mut groups: FxHashMap<(String, ChunkUkey), Vec> = FxHashMap::default(); - let mg = compilation.get_module_graph(); - let cg = &compilation.build_chunk_graph_artifact.chunk_graph; - - let modules_map = self.concatenated_modules_map.read().await; - - for (id, module) in mg.modules() { - if module.as_external_module().is_some() { - let id_str = id.as_str(); - if modules_map[id].is_external() - && let Some(pipe_pos) = id_str.rfind('|') - && let Some(chunks) = cg.try_get_module_chunks(id) - && !chunks.is_empty() - { - let base = id_str[..pipe_pos].to_string(); - for &chunk in chunks { - groups.entry((base.clone(), chunk)).or_default().push(*id); - } - } - } - } - - // Phase 2: Merge duplicates within the same chunk - for mut module_ids in groups.into_values() { - module_ids.sort_unstable(); - module_ids.dedup(); - if module_ids.len() <= 1 { - continue; - } - - let canonical_id = module_ids[0]; - - let mut used_exports = FxHashSet::default(); - let mut used_in_unknown = false; - - for dup_id in &module_ids[1..] { - let dup_id_used = compilation - .exports_info_artifact - .get_exports_info_data(dup_id); - if !matches!( - dup_id_used.other_exports_info().get_used(None), - rspack_core::UsageState::Unused - ) { - used_in_unknown = true; - break; - } else { - let used = dup_id_used.exports().iter().filter_map(|(name, export)| { - if matches!(export.get_used(None), rspack_core::UsageState::Used) { - Some(name.clone()) - } else { - None - } - }); - - used_exports.extend(used); - } - } - - if used_in_unknown { - // used in unknown way, we should make canonical_id the same used in unknown way - let exports_info = compilation - .exports_info_artifact - .get_exports_info_data_mut(&canonical_id); - exports_info.set_used_in_unknown_way(None); - } else { - for name in used_exports { - let exports_info = compilation - .exports_info_artifact - .get_exports_info_data_mut(&canonical_id); - - let info = exports_info.ensure_export_info(&name); - let info = info.as_data_mut(&mut compilation.exports_info_artifact); - info.set_used(rspack_core::UsageState::Used, None); - } - } - - for &dup_id in &module_ids[1..] { - let cg = &mut compilation.build_chunk_graph_artifact.chunk_graph; - cg.replace_module(&dup_id, &canonical_id); - - // 1. Move incoming connections from duplicate to canonical - let mg = compilation.get_module_graph_mut(); - mg.move_module_connections(&dup_id, &canonical_id, |_, _| true); - } - } - - Ok(None) -} - -#[plugin_hook(CompilationOptimizeDependencies for EsmLibraryPlugin)] +// Cut out placement edges only after dependency optimizers have settled. +#[plugin_hook(CompilationOptimizeDependencies for EsmLibraryPlugin, stage = i32::MAX)] async fn optimize_dependencies( &self, compilation: &Compilation, @@ -847,7 +757,13 @@ async fn optimize_dependencies( _diagnostics: &mut Vec, ) -> Result> { let direct_dependencies = cutout_commonjs_externals(build_module_graph_artifact); - *self.direct_commonjs_external_dependencies.borrow_mut() = Arc::new(direct_dependencies); + *self.direct_commonjs_external_dependencies.borrow_mut() = direct_dependencies; + cutout_esm_externals( + compilation, + build_module_graph_artifact, + exports_info_artifact, + &self.direct_esm_external_dependencies, + ); cutout_dyn_import_externals( false, compilation.options.output.module, @@ -929,11 +845,6 @@ impl Plugin for EsmLibraryPlugin { .optimize_chunks .tap(optimize_runtime_chunk_hook::new(self)); - ctx - .compilation_hooks - .optimize_chunk_modules - .tap(optimize_chunk_modules::new(self)); - ctx.normal_module_factory_hooks.parser.tap(parse::new(self)); ctx .normal_module_factory_hooks diff --git a/crates/rspack_plugin_externals/src/esm_node_target_plugin.rs b/crates/rspack_plugin_externals/src/esm_node_target_plugin.rs index c7ae64ba636c..4b05ff0baa28 100644 --- a/crates/rspack_plugin_externals/src/esm_node_target_plugin.rs +++ b/crates/rspack_plugin_externals/src/esm_node_target_plugin.rs @@ -48,7 +48,8 @@ async fn after_factorize( DependencyType::CjsRequire | DependencyType::CjsFullRequire ) || (matches!(dep.dependency_type(), DependencyType::CjsExportRequire) && data - .options + .build_context + .compiler_options .output .enabled_library_types .as_ref() diff --git a/crates/rspack_plugin_javascript/src/dependency/commonjs/common_js_export_require_dependency.rs b/crates/rspack_plugin_javascript/src/dependency/commonjs/common_js_export_require_dependency.rs index a01795e917c7..ae3e9b343cf2 100644 --- a/crates/rspack_plugin_javascript/src/dependency/commonjs/common_js_export_require_dependency.rs +++ b/crates/rspack_plugin_javascript/src/dependency/commonjs/common_js_export_require_dependency.rs @@ -54,18 +54,6 @@ impl CommonJsExportRequireDependency { result_used, } } - - pub fn range(&self) -> DependencyRange { - self.range - } - - pub fn base(&self) -> ExportsBase { - self.base - } - - pub fn names(&self) -> &[Atom] { - &self.names - } } impl CommonJsExportRequireDependency { @@ -433,6 +421,18 @@ impl DependencyTemplate for CommonJsExportRequireDependencyTemplate { dep: &dyn DependencyCodeGeneration, source: &mut TemplateReplaceSource, code_generatable_context: &mut TemplateContext, + ) { + self.render_with_require(dep, source, code_generatable_context, None); + } +} + +impl CommonJsExportRequireDependencyTemplate { + pub fn render_with_require( + &self, + dep: &dyn DependencyCodeGeneration, + source: &mut TemplateReplaceSource, + code_generatable_context: &mut TemplateContext, + direct_require: Option, ) { let dep = dep .as_any() @@ -474,7 +474,9 @@ impl DependencyTemplate for CommonJsExportRequireDependencyTemplate { unreachable!() }; - let require_expr = if let Some(imported_module) = mg.get_module_by_dependency_id(&dep.id) + let require_expr = if let Some(direct_require) = direct_require { + direct_require + } else if let Some(imported_module) = mg.get_module_by_dependency_id(&dep.id) && let ids = dep.get_ids(mg) && let Some(used_imported) = compilation .exports_info_artifact 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 e56913b3dc99..3024a4b3eb99 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 @@ -20,14 +20,15 @@ use rspack_core::{ ExportModeReexportDynamicDefault, ExportModeReexportNamedDefault, ExportModeReexportNamespaceObject, ExportModeReexportUndefined, ExportModeUnused, ExportNameOrSpec, ExportPresenceMode, ExportProvided, ExportSpec, ExportsInfoArtifact, - ExportsInfoData, ExportsOfExportsSpec, ExportsSpec, ExportsType, ForwardId, ImportAttributes, - ImportPhase, InitFragmentExt, InitFragmentKey, InitFragmentStage, JavascriptParserOptions, - LazyUntil, ModuleDependency, ModuleGraph, ModuleGraphCacheArtifact, ModuleIdentifier, - NormalInitFragment, NormalReexportItem, ReferencedExport, ResourceIdentifier, RuntimeCondition, - RuntimeGlobals, RuntimeSpec, SideEffectsStateArtifact, StarReexportsInfo, TemplateContext, - TemplateReplaceSource, UsageState, UsedName, collect_referenced_export_items, - create_exports_object_referenced, create_no_exports_referenced, filter_runtime, get_exports_type, - get_runtime_key, get_terminal_binding, property_access, property_name, + ExportsInfoData, ExportsOfExportsSpec, ExportsSpec, ExportsType, ExternalModule, ForwardId, + ImportAttributes, ImportPhase, InitFragmentExt, InitFragmentKey, InitFragmentStage, + JavascriptParserOptions, LazyUntil, ModuleDependency, ModuleGraph, ModuleGraphCacheArtifact, + ModuleGraphConnection, ModuleIdentifier, NormalInitFragment, NormalReexportItem, + ReferencedExport, ResourceIdentifier, RuntimeCondition, RuntimeGlobals, RuntimeSpec, + SideEffectsStateArtifact, StarReexportsInfo, TemplateContext, TemplateReplaceSource, UsageState, + UsedName, collect_referenced_export_items, create_exports_object_referenced, + create_no_exports_referenced, filter_runtime, get_exports_type, get_runtime_key, + get_terminal_binding, property_access, property_name, render_make_deferred_namespace_mode_from_exports_type, to_normal_comment, }; use rspack_error::{Diagnostic, Error, Severity}; @@ -39,6 +40,7 @@ use rustc_hash::{FxHashSet as HashSet, FxHasher}; use super::{ create_resource_identifier_for_esm_dependency, esm_import_dependency::esm_import_dependency_get_linking_error, esm_import_dependency_apply, + esm_import_external, }; use crate::{Atom, connection_active_inline_value_for_esm_export_imported_specifier}; @@ -517,6 +519,15 @@ impl ESMExportImportedSpecifierDependency { } pub fn add_export_fragments(&self, ctxt: &mut TemplateContext, mode: ExportMode) { + self.add_export_fragments_with_connection(ctxt, mode, None); + } + + fn add_export_fragments_with_connection( + &self, + ctxt: &mut TemplateContext, + mode: ExportMode, + connection: Option<&ModuleGraphConnection>, + ) { let module = ctxt.module; let runtime = ctxt.runtime; let compilation = ctxt.compilation; @@ -720,7 +731,9 @@ impl ESMExportImportedSpecifierDependency { let key = InitFragmentKey::ESMImport(format!("reexport (checked) {import_var} {name}")); let runtime_condition = if self.weak() { RuntimeCondition::Boolean(false) - } else if let Some(connection) = mg.connection_by_dependency_id(self.id()) { + } else if let Some(connection) = + connection.or_else(|| mg.connection_by_dependency_id(self.id())) + { filter_runtime(ctxt.runtime, |r| { connection.is_target_active( mg, @@ -1708,6 +1721,64 @@ impl ESMExportImportedSpecifierDependencyTemplate { pub fn template_type() -> DependencyTemplateType { DependencyTemplateType::Dependency(DependencyType::EsmExportImportedSpecifier) } + + pub fn supports_direct_scope_export(mode: &ExportMode) -> bool { + match mode { + ExportMode::Unused(_) + | ExportMode::EmptyStar(_) + | ExportMode::ReexportNamespaceObject(_) + | ExportMode::DynamicReexport(_) => true, + ExportMode::NormalReexport(mode) => mode + .items + .iter() + .all(|item| item.hidden || (!item.checked && item.ids.len() == 1)), + _ => false, + } + } + + pub fn render_external( + &self, + dep: &ESMExportImportedSpecifierDependency, + external: &ExternalModule, + connection: &ModuleGraphConnection, + context: &mut TemplateContext, + ) { + let compilation = context.compilation; + let mode = dep.get_mode( + compilation.get_module_graph(), + context.runtime, + &compilation.module_graph_cache_artifact, + &compilation.exports_info_artifact, + ); + if matches!( + mode, + ExportMode::Unused(_) | ExportMode::EmptyStar(_) | ExportMode::LazyMake + ) { + return; + } + if let Some(scope) = context.concatenation_scope.as_mut() { + match mode { + // The ESM linker follows the original export-star connection and emits + // native reexports, including local-export precedence and live bindings. + ExportMode::DynamicReexport(_) => {} + ExportMode::ReexportNamespaceObject(mode) => { + let binding = external.register_module_import(compilation, scope, None, None); + scope.register_raw_export(mode.name, binding); + } + ExportMode::NormalReexport(mode) => { + for item in mode.items.into_iter().filter(|item| !item.hidden) { + let binding = + external.register_module_import(compilation, scope, item.ids.first(), None); + scope.register_raw_export(item.name, binding); + } + } + _ => unreachable!("unsupported external reexport must retain its module wrapper"), + } + } else { + esm_import_external(external, dep, context); + dep.add_export_fragments_with_connection(context, mode, Some(connection)); + } + } } impl DependencyTemplate for ESMExportImportedSpecifierDependencyTemplate { 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 0646b1e4ba73..f1def2a18f28 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 @@ -12,11 +12,11 @@ use rspack_core::{ DependencyCodeGeneration, DependencyCondition, DependencyConditionFn, DependencyDiagnosticsContext, DependencyId, DependencyLocation, DependencyRange, DependencyTemplate, DependencyTemplateType, DependencyType, ExportProvided, ExportsInfoArtifact, - ExportsType, ForwardId, ImportAttributes, ImportPhase, InitFragmentExt, InitFragmentKey, - InitFragmentStage, LazyUntil, ModuleDependency, ModuleGraph, ModuleGraphCacheArtifact, - ModuleIdentifier, ProvidedExports, ReferencedExport, ResourceIdentifier, RuntimeCondition, - RuntimeSpec, SideEffectsStateArtifact, SourceType, TemplateContext, TemplateReplaceSource, - TypeReexportPresenceMode, filter_runtime, + ExportsType, ExternalModule, ForwardId, ImportAttributes, ImportPhase, InitFragmentExt, + InitFragmentKey, InitFragmentStage, LazyUntil, ModuleDependency, ModuleGraph, + ModuleGraphCacheArtifact, ModuleIdentifier, NormalInitFragment, ProvidedExports, + ReferencedExport, ResourceIdentifier, RuntimeCondition, RuntimeSpec, SideEffectsStateArtifact, + SourceType, TemplateContext, TemplateReplaceSource, TypeReexportPresenceMode, filter_runtime, }; use rspack_error::{Diagnostic, Error, Severity}; @@ -114,6 +114,42 @@ impl ESMImportSideEffectDependency { } } +/// The wrapped-module path uses the same namespace remapping as ExternalModule codegen. +pub fn esm_import_external( + external: &ExternalModule, + dependency: &dyn Dependency, + context: &mut TemplateContext, +) -> String { + let compilation = context.compilation; + let target = compilation + .get_module_graph() + .get_module_by_dependency_id(dependency.id()); + let import_var = compilation.get_import_var( + context.module.identifier(), + target, + external.user_request(), + dependency.get_phase(), + context.runtime, + ); + let (init, expression, fragments) = + external.render_module_namespace(compilation, context.runtime, context.runtime_template); + context.chunk_init_fragments().extend(fragments); + context.init_fragments.push( + NormalInitFragment::new( + format!( + "{}var {import_var} = {expression};\n", + init.unwrap_or_default() + ), + InitFragmentStage::StageESMImports, + dependency.source_order().unwrap_or_default(), + InitFragmentKey::Const(format!("direct external {import_var}")), + None, + ) + .boxed(), + ); + import_var +} + pub fn esm_import_dependency_apply( module_dependency: &T, source_order: i32, diff --git a/crates/rspack_plugin_javascript/src/dependency/esm/esm_import_specifier_dependency.rs b/crates/rspack_plugin_javascript/src/dependency/esm/esm_import_specifier_dependency.rs index 94ac3adcfd3b..f8d74aa58792 100644 --- a/crates/rspack_plugin_javascript/src/dependency/esm/esm_import_specifier_dependency.rs +++ b/crates/rspack_plugin_javascript/src/dependency/esm/esm_import_specifier_dependency.rs @@ -7,7 +7,7 @@ use rspack_core::{ AsContextDependency, ConnectionState, Dependency, DependencyCategory, DependencyCodeGeneration, DependencyCondition, DependencyConditionFn, DependencyDiagnosticsContext, DependencyId, DependencyLocation, DependencyRange, DependencyTemplate, DependencyTemplateType, DependencyType, - ExportPresenceMode, ExportProvided, ExportsInfoArtifact, ExportsType, ForwardId, + ExportPresenceMode, ExportProvided, ExportsInfoArtifact, ExportsType, ExternalModule, ForwardId, ImportAttributes, ImportPhase, JavascriptParserOptions, ModuleDependency, ModuleGraph, ModuleGraphCacheArtifact, ModuleGraphConnection, ModuleReferenceOptions, ReferencedExport, ResourceIdentifier, RuntimeSpec, SideEffectsStateArtifact, TemplateContext, @@ -21,6 +21,7 @@ use rspack_util::json_stringify_str; use super::{ create_resource_identifier_for_esm_dependency, esm_import_dependency::esm_import_dependency_get_linking_error, esm_import_dependency_apply, + esm_import_external, }; use crate::{ Atom, connection_active_inline_value_for_esm_import_specifier, connection_active_used_by_exports, @@ -430,7 +431,32 @@ impl ESMImportSpecifierDependencyTemplate { dep: &ESMImportSpecifierDependency, connection: Option<&ModuleGraphConnection>, code_generatable_context: &mut TemplateContext, + external: Option<&ExternalModule>, ) -> String { + if let Some(external) = external + && let Some(scope) = code_generatable_context.concatenation_scope.as_mut() + { + let namespace = ids.is_empty() || dep.ns_access; + let binding = external.register_module_import( + code_generatable_context.compilation, + scope, + if namespace { None } else { ids.first() }, + Some(&dep.name), + ); + let access = format!("{binding}{}", property_access(ids, usize::from(!namespace))); + return if dep.call && dep.direct_import && ids.len() > usize::from(!namespace) { + format!( + "{}(0, {access})", + if dep.shorthand || dep.asi_safe { + "" + } else { + ";" + } + ) + } else { + access + }; + } let TemplateContext { compilation, concatenation_scope, @@ -493,14 +519,20 @@ impl ESMImportSpecifierDependencyTemplate { } else { let mg = code_generatable_context.compilation.get_module_graph(); let target_module = mg.get_module_by_dependency_id(&dep.id); - let import_var = code_generatable_context.compilation.get_import_var( - code_generatable_context.module.identifier(), - target_module, - dep.user_request(), - dep.phase, - code_generatable_context.runtime, - ); - esm_import_dependency_apply(dep, dep.source_order, dep.phase, code_generatable_context); + let import_var = if let Some(external) = external { + esm_import_external(external, dep, code_generatable_context) + } else { + code_generatable_context.compilation.get_import_var( + code_generatable_context.module.identifier(), + target_module, + dep.user_request(), + dep.phase, + code_generatable_context.runtime, + ) + }; + if external.is_none() { + esm_import_dependency_apply(dep, dep.source_order, dep.phase, code_generatable_context); + } let TemplateContext { compilation, module, @@ -534,6 +566,7 @@ impl ESMImportSpecifierDependencyTemplate { connection: Option<&ModuleGraphConnection>, source: &mut TemplateReplaceSource, code_generatable_context: &mut TemplateContext, + external: Option<&ExternalModule>, ) { let Some(con) = connection else { return; @@ -608,7 +641,7 @@ impl ESMImportSpecifierDependencyTemplate { } else { ids }; - let Some(used_name) = exports_info + let Some(mut used_name) = exports_info .get_used_name(&compilation.exports_info_artifact, *runtime, used_name_ids) .and_then(|used_name| match used_name { UsedName::Normal(names) => names.last().cloned(), @@ -617,11 +650,18 @@ impl ESMImportSpecifierDependencyTemplate { else { return; }; + if external.is_some() && code_generatable_context.concatenation_scope.is_some() { + used_name = used_name_ids + .last() + .expect("in operator has a property") + .clone(); + } let code = self.get_code_for_ids( &ids[..(ids.len() - 1)], dep, connection, code_generatable_context, + external, ); source.replace( dep.range.start, @@ -640,6 +680,18 @@ impl DependencyTemplate for ESMImportSpecifierDependencyTemplate { dep: &dyn DependencyCodeGeneration, source: &mut TemplateReplaceSource, code_generatable_context: &mut TemplateContext, + ) { + self.render_with_external(dep, source, code_generatable_context, None); + } +} + +impl ESMImportSpecifierDependencyTemplate { + pub fn render_with_external( + &self, + dep: &dyn DependencyCodeGeneration, + source: &mut TemplateReplaceSource, + code_generatable_context: &mut TemplateContext, + external: Option<(&ExternalModule, &ModuleGraphConnection)>, ) { let dep = dep .as_any() @@ -651,7 +703,10 @@ impl DependencyTemplate for ESMImportSpecifierDependencyTemplate { let runtime = code_generatable_context.runtime; let module_graph = compilation.get_module_graph(); let ids = dep.get_ids(module_graph); - let connection = module_graph.connection_by_dependency_id(&dep.id); + let connection = external + .map(|(_, connection)| connection) + .or_else(|| module_graph.connection_by_dependency_id(&dep.id)); + let external = external.map(|(external, _)| external); // Early return if target is not active and export is not inlined if let Some(con) = connection && !con.is_target_active( @@ -680,10 +735,12 @@ impl DependencyTemplate for ESMImportSpecifierDependencyTemplate { connection, source, code_generatable_context, + external, ); } - let export_expr = self.get_code_for_ids(ids, dep, connection, code_generatable_context); + let export_expr = + self.get_code_for_ids(ids, dep, connection, code_generatable_context, external); if dep.shorthand { source.insert(dep.range.end, format!(": {export_expr}"), None); @@ -691,6 +748,9 @@ impl DependencyTemplate for ESMImportSpecifierDependencyTemplate { source.replace(dep.range.start, dep.range.end, export_expr, None); } + if external.is_some() && code_generatable_context.concatenation_scope.is_some() { + return; + } let module_graph = code_generatable_context.compilation.get_module_graph(); if let Some(referenced_properties) = &dep.referenced_properties_in_destructuring { let mut prefixed_ids = ids.to_vec(); diff --git a/crates/rspack_plugin_javascript/src/dependency/esm/mod.rs b/crates/rspack_plugin_javascript/src/dependency/esm/mod.rs index e23572730588..770f3a253640 100644 --- a/crates/rspack_plugin_javascript/src/dependency/esm/mod.rs +++ b/crates/rspack_plugin_javascript/src/dependency/esm/mod.rs @@ -33,7 +33,7 @@ pub use self::{ }, esm_import_dependency::{ ESMImportSideEffectDependency, ESMImportSideEffectDependencyTemplate, - esm_import_dependency_apply, import_emitted_runtime, + esm_import_dependency_apply, esm_import_external, import_emitted_runtime, }, esm_import_specifier_dependency::{ ESMImportSpecifierDependency, ESMImportSpecifierDependencyTemplate, diff --git a/tests/rspack-test/configCases/externals/reexport-star/__snapshot__/case1.txt b/tests/rspack-test/configCases/externals/reexport-star/__snapshot__/case1.txt index 097ba02a2b30..f06952f3a4ca 100644 --- a/tests/rspack-test/configCases/externals/reexport-star/__snapshot__/case1.txt +++ b/tests/rspack-test/configCases/externals/reexport-star/__snapshot__/case1.txt @@ -5,12 +5,12 @@ import * as __rspack_external_external2_alias_d6100a5a from "external2-alias"; __webpack_require__.add({ 42(__unused_rspack_module, __webpack_exports__, __webpack_require__) { __webpack_require__.r(__webpack_exports__); -/* import */ var external1__rspack_import_0 = __webpack_require__(322); +var external1__rspack_import_0 = __rspack_external_external1_alias_dd38afe7; /* reexport */ var __rspack_reexport = {}; /* reexport */ for( const __rspack_import_key in external1__rspack_import_0) if(__rspack_import_key !== "default") __rspack_reexport[__rspack_import_key] =() => external1__rspack_import_0[__rspack_import_key] /* reexport */ __webpack_require__.d(__webpack_exports__, __rspack_reexport); -/* import */ var external2__rspack_import_1 = __webpack_require__(101); +var external2__rspack_import_1 = __rspack_external_external2_alias_d6100a5a; /* reexport */ var __rspack_reexport = {}; /* reexport */ for( const __rspack_import_key in external2__rspack_import_1) if(__rspack_import_key !== "default") __rspack_reexport[__rspack_import_key] =() => external2__rspack_import_1[__rspack_import_key] @@ -19,18 +19,6 @@ __webpack_require__.r(__webpack_exports__); -}, -322(module) { - -module.exports = __rspack_external_external1_alias_dd38afe7; - - -}, -101(module) { - -module.exports = __rspack_external_external2_alias_d6100a5a; - - }, }); __webpack_require__("42"); diff --git a/tests/rspack-test/configCases/externals/reexport-star/__snapshot__/case2.txt b/tests/rspack-test/configCases/externals/reexport-star/__snapshot__/case2.txt index 4380a93c2e2f..5b9510177466 100644 --- a/tests/rspack-test/configCases/externals/reexport-star/__snapshot__/case2.txt +++ b/tests/rspack-test/configCases/externals/reexport-star/__snapshot__/case2.txt @@ -1,4 +1,5 @@ import * as __rspack_external_external1_alias_dd38afe7 from "external1-alias"; +import { a, b } from "external1-alias"; @@ -6,8 +7,5 @@ import * as __rspack_external_external1_alias_dd38afe7 from "external1-alias"; - -var a = __rspack_external_external1_alias_dd38afe7.a; -var b = __rspack_external_external1_alias_dd38afe7.b; export { __rspack_external_external1_alias_dd38afe7 as n1, a, b }; export * from "external1-alias"; \ No newline at end of file diff --git a/tests/rspack-test/configCases/externals/reexport-star/__snapshot__/case3.txt b/tests/rspack-test/configCases/externals/reexport-star/__snapshot__/case3.txt index 3af23e5ab247..0d5b73c911f3 100644 --- a/tests/rspack-test/configCases/externals/reexport-star/__snapshot__/case3.txt +++ b/tests/rspack-test/configCases/externals/reexport-star/__snapshot__/case3.txt @@ -1,7 +1,6 @@ import "external1-alias"; - const foo = 2 diff --git a/tests/rspack-test/configCases/externals/reexport-star/__snapshot__/case4.txt b/tests/rspack-test/configCases/externals/reexport-star/__snapshot__/case4.txt index 9e6108c4a9b5..1984044fca54 100644 --- a/tests/rspack-test/configCases/externals/reexport-star/__snapshot__/case4.txt +++ b/tests/rspack-test/configCases/externals/reexport-star/__snapshot__/case4.txt @@ -1,7 +1 @@ -import * as __rspack_external_external1_alias_dd38afe7 from "external1-alias"; - - - - - export * from "external1-alias"; \ No newline at end of file diff --git a/tests/rspack-test/configCases/externals/reexport-star/__snapshot__/case5.txt b/tests/rspack-test/configCases/externals/reexport-star/__snapshot__/case5.txt index 49dabb03122d..8563c30e2ed0 100644 --- a/tests/rspack-test/configCases/externals/reexport-star/__snapshot__/case5.txt +++ b/tests/rspack-test/configCases/externals/reexport-star/__snapshot__/case5.txt @@ -1,9 +1,8 @@ -import * as __rspack_external_external1_alias_dd38afe7 from "external1-alias"; +import { foo } from "external1-alias"; - -const bar = __rspack_external_external1_alias_dd38afe7.foo + 1 +const bar = foo + 1 diff --git a/tests/rspack-test/configCases/externals/reexport-star/__snapshot__/case6.txt b/tests/rspack-test/configCases/externals/reexport-star/__snapshot__/case6.txt index d6431e01af8b..1984044fca54 100644 --- a/tests/rspack-test/configCases/externals/reexport-star/__snapshot__/case6.txt +++ b/tests/rspack-test/configCases/externals/reexport-star/__snapshot__/case6.txt @@ -1,8 +1 @@ -import * as __rspack_external_external1_alias_dd38afe7 from "external1-alias"; - - - - - - export * from "external1-alias"; \ No newline at end of file diff --git a/tests/rspack-test/configCases/externals/reexport-star/__snapshot__/runtimeModeSnapshot/case1.txt b/tests/rspack-test/configCases/externals/reexport-star/__snapshot__/runtimeModeSnapshot/case1.txt index 73a01befb2e6..68f0986a42b0 100644 --- a/tests/rspack-test/configCases/externals/reexport-star/__snapshot__/runtimeModeSnapshot/case1.txt +++ b/tests/rspack-test/configCases/externals/reexport-star/__snapshot__/runtimeModeSnapshot/case1.txt @@ -4,12 +4,12 @@ import * as __rspack_external_external2_alias_d6100a5a from "external2-alias"; moduleFactories.add({ 42(__unused_rspack_module, exports) { makeNamespaceObject(exports); -/* import */ var external1__rspack_import_0 = rspackRequire(322); +var external1__rspack_import_0 = __rspack_external_external1_alias_dd38afe7; /* reexport */ var __rspack_reexport = {}; /* reexport */ for( const __rspack_import_key in external1__rspack_import_0) if(__rspack_import_key !== "default") __rspack_reexport[__rspack_import_key] =() => external1__rspack_import_0[__rspack_import_key] /* reexport */ definePropertyGetters(exports, __rspack_reexport); -/* import */ var external2__rspack_import_1 = rspackRequire(101); +var external2__rspack_import_1 = __rspack_external_external2_alias_d6100a5a; /* reexport */ var __rspack_reexport = {}; /* reexport */ for( const __rspack_import_key in external2__rspack_import_1) if(__rspack_import_key !== "default") __rspack_reexport[__rspack_import_key] =() => external2__rspack_import_1[__rspack_import_key] @@ -18,18 +18,6 @@ makeNamespaceObject(exports); -}, -322(module) { - -module.exports = __rspack_external_external1_alias_dd38afe7; - - -}, -101(module) { - -module.exports = __rspack_external_external2_alias_d6100a5a; - - }, }); rspackRequire("42"); diff --git a/tests/rspack-test/configCases/externals/reexport-star/__snapshot__/runtimeModeSnapshot/case2.txt b/tests/rspack-test/configCases/externals/reexport-star/__snapshot__/runtimeModeSnapshot/case2.txt index 4380a93c2e2f..5b9510177466 100644 --- a/tests/rspack-test/configCases/externals/reexport-star/__snapshot__/runtimeModeSnapshot/case2.txt +++ b/tests/rspack-test/configCases/externals/reexport-star/__snapshot__/runtimeModeSnapshot/case2.txt @@ -1,4 +1,5 @@ import * as __rspack_external_external1_alias_dd38afe7 from "external1-alias"; +import { a, b } from "external1-alias"; @@ -6,8 +7,5 @@ import * as __rspack_external_external1_alias_dd38afe7 from "external1-alias"; - -var a = __rspack_external_external1_alias_dd38afe7.a; -var b = __rspack_external_external1_alias_dd38afe7.b; export { __rspack_external_external1_alias_dd38afe7 as n1, a, b }; export * from "external1-alias"; \ No newline at end of file diff --git a/tests/rspack-test/configCases/externals/reexport-star/__snapshot__/runtimeModeSnapshot/case3.txt b/tests/rspack-test/configCases/externals/reexport-star/__snapshot__/runtimeModeSnapshot/case3.txt index 3af23e5ab247..0d5b73c911f3 100644 --- a/tests/rspack-test/configCases/externals/reexport-star/__snapshot__/runtimeModeSnapshot/case3.txt +++ b/tests/rspack-test/configCases/externals/reexport-star/__snapshot__/runtimeModeSnapshot/case3.txt @@ -1,7 +1,6 @@ import "external1-alias"; - const foo = 2 diff --git a/tests/rspack-test/configCases/externals/reexport-star/__snapshot__/runtimeModeSnapshot/case4.txt b/tests/rspack-test/configCases/externals/reexport-star/__snapshot__/runtimeModeSnapshot/case4.txt index 9e6108c4a9b5..1984044fca54 100644 --- a/tests/rspack-test/configCases/externals/reexport-star/__snapshot__/runtimeModeSnapshot/case4.txt +++ b/tests/rspack-test/configCases/externals/reexport-star/__snapshot__/runtimeModeSnapshot/case4.txt @@ -1,7 +1 @@ -import * as __rspack_external_external1_alias_dd38afe7 from "external1-alias"; - - - - - export * from "external1-alias"; \ No newline at end of file diff --git a/tests/rspack-test/configCases/externals/reexport-star/__snapshot__/runtimeModeSnapshot/case5.txt b/tests/rspack-test/configCases/externals/reexport-star/__snapshot__/runtimeModeSnapshot/case5.txt index 49dabb03122d..8563c30e2ed0 100644 --- a/tests/rspack-test/configCases/externals/reexport-star/__snapshot__/runtimeModeSnapshot/case5.txt +++ b/tests/rspack-test/configCases/externals/reexport-star/__snapshot__/runtimeModeSnapshot/case5.txt @@ -1,9 +1,8 @@ -import * as __rspack_external_external1_alias_dd38afe7 from "external1-alias"; +import { foo } from "external1-alias"; - -const bar = __rspack_external_external1_alias_dd38afe7.foo + 1 +const bar = foo + 1 diff --git a/tests/rspack-test/configCases/externals/reexport-star/__snapshot__/runtimeModeSnapshot/case6.txt b/tests/rspack-test/configCases/externals/reexport-star/__snapshot__/runtimeModeSnapshot/case6.txt index d6431e01af8b..1984044fca54 100644 --- a/tests/rspack-test/configCases/externals/reexport-star/__snapshot__/runtimeModeSnapshot/case6.txt +++ b/tests/rspack-test/configCases/externals/reexport-star/__snapshot__/runtimeModeSnapshot/case6.txt @@ -1,8 +1 @@ -import * as __rspack_external_external1_alias_dd38afe7 from "external1-alias"; - - - - - - export * from "external1-alias"; \ No newline at end of file diff --git a/tests/rspack-test/configCases/library/modern-module-named-import-externals/rspack.config.mjs b/tests/rspack-test/configCases/library/modern-module-named-import-externals/rspack.config.mjs index 339605a2902e..c45c5fcce5c7 100644 --- a/tests/rspack-test/configCases/library/modern-module-named-import-externals/rspack.config.mjs +++ b/tests/rspack-test/configCases/library/modern-module-named-import-externals/rspack.config.mjs @@ -30,48 +30,42 @@ export default { compilation.hooks.processAssets.tap('testcase', (assets) => { const source = assets['test.js'].source(); expect(source).toMatchInlineSnapshot(` - import { HomeLayout as external_externals0_HomeLayout, a } from "externals0"; - import { a as external_externals1_a } from "externals1"; - import externals2 from "externals2"; - import * as __rspack_external_externals3 from "externals3"; - import "externals4"; + import { HomeLayout as lib_HomeLayout, a } from "externals0"; + import { a as test_a } from "externals1"; + import externals2 from "externals2"; + import * as namespace from "externals3"; + import "externals4"; + (function Layout(props) { + const { HomeLayout = lib_HomeLayout } = props; + call({ HomeLayout }); + })() + // re export + // named import + ; + // default import - (function Layout(props) { - const { HomeLayout = external_externals0_HomeLayout } = props; - call({ HomeLayout }); - })() + // namespace import - // re export + // side effect only import - // named import - ; - // default import - // namespace import + test_a; + externals2; + namespace; - - // side effect only import - - - - - external_externals1_a; - externals2; - __rspack_external_externals3; - - export { a }; - `); + export { a }; + `); }); }; this.hooks.compilation.tap('testcase', handler); diff --git a/tests/rspack-test/esmOutputCases/deconflict/asset-preserve-import-external-symbols/__snapshots__/runtimeModeSnapshot/esm.snap.txt b/tests/rspack-test/esmOutputCases/deconflict/asset-preserve-import-external-symbols/__snapshots__/runtimeModeSnapshot/esm.snap.txt new file mode 100644 index 000000000000..1d404996a3af --- /dev/null +++ b/tests/rspack-test/esmOutputCases/deconflict/asset-preserve-import-external-symbols/__snapshots__/runtimeModeSnapshot/esm.snap.txt @@ -0,0 +1,12 @@ +```mjs title=main.mjs +import fileURLToPath from "./assets/fileURLToPath.mjs"; +import readFile from "./assets/readFile.mjs"; +import { readFile as external_fs_readFile } from "fs"; +import { fileURLToPath as external_node_url_fileURLToPath } from "node:url"; +import {fileURLToPath as __rspack_fileURLToPath} from "node:url"; +var __rspack_import_meta_dirname__ = __rspack_dirname(__rspack_fileURLToPath(import.meta.url)); +module.exports = fileURLToPath; +module.exports = readFile; +const generatedDirname = __rspack_import_meta_dirname__ +export { external_fs_readFile as readFile, external_node_url_fileURLToPath as fileURLToPath, fileURLToPath_0 as fileURLToPathAsset, generatedDirname, index_rspack_fileURLToPath as applicationHelperValue, readFile_0 as readFileAsset }; +``` \ No newline at end of file diff --git a/tests/rspack-test/esmOutputCases/dynamic-import/dyn-import-default-interop-external/__snapshots__/esm.snap.txt b/tests/rspack-test/esmOutputCases/dynamic-import/dyn-import-default-interop-external/__snapshots__/esm.snap.txt index 0b6637d07dae..6293831dee6d 100644 --- a/tests/rspack-test/esmOutputCases/dynamic-import/dyn-import-default-interop-external/__snapshots__/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/dynamic-import/dyn-import-default-interop-external/__snapshots__/esm.snap.txt @@ -12,9 +12,8 @@ export {}; ``` ```mjs title=wrapper.mjs -import * as __rspack_external_fs from "fs"; - -// fs +import fs, * as __rspack_external_fs from "fs"; +import { readFile } from "fs"; // ./wrapper.js @@ -22,9 +21,7 @@ import * as __rspack_external_fs from "fs"; ; -var default_0 = __rspack_external_fs["default"]; -var readFile = __rspack_external_fs.readFile; export { __rspack_external_fs as ns, readFile }; -export default default_0; +export default fs; ``` \ No newline at end of file diff --git a/tests/rspack-test/esmOutputCases/dynamic-import/dyn-import-mixed-external-local/__snapshots__/esm.snap.txt b/tests/rspack-test/esmOutputCases/dynamic-import/dyn-import-mixed-external-local/__snapshots__/esm.snap.txt index 24b20f8f5a06..480ce5a54802 100644 --- a/tests/rspack-test/esmOutputCases/dynamic-import/dyn-import-mixed-external-local/__snapshots__/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/dynamic-import/dyn-import-mixed-external-local/__snapshots__/esm.snap.txt @@ -12,8 +12,6 @@ export {}; ``` ```mjs title=wrapper.mjs -// fs - // ./wrapper.js const localValue = 42 diff --git a/tests/rspack-test/esmOutputCases/dynamic-import/dyn-import-module-external-default-named-collision/__snapshots__/esm.snap.txt b/tests/rspack-test/esmOutputCases/dynamic-import/dyn-import-module-external-default-named-collision/__snapshots__/esm.snap.txt index 53a514edfe31..d94ec1966fe0 100644 --- a/tests/rspack-test/esmOutputCases/dynamic-import/dyn-import-module-external-default-named-collision/__snapshots__/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/dynamic-import/dyn-import-module-external-default-named-collision/__snapshots__/esm.snap.txt @@ -18,15 +18,11 @@ export {}; ```mjs title=shared.mjs import fs, { readFile } from "fs"; -// fs?2aa6 - // ./a.js const defaultImport = fs -// fs?f4d4 - // ./b.js diff --git a/tests/rspack-test/esmOutputCases/dynamic-import/dyn-import-multi-module-duplicate-external/__snapshots__/esm.snap.txt b/tests/rspack-test/esmOutputCases/dynamic-import/dyn-import-multi-module-duplicate-external/__snapshots__/esm.snap.txt index e5a7102f279a..c5bffd791cf0 100644 --- a/tests/rspack-test/esmOutputCases/dynamic-import/dyn-import-multi-module-duplicate-external/__snapshots__/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/dynamic-import/dyn-import-multi-module-duplicate-external/__snapshots__/esm.snap.txt @@ -72,14 +72,12 @@ __webpack_require__.d(b_namespaceObject, { readFile: () => (readFile) }); -// fs?2aa6 +// fs // ./a.js -// fs?f4d4 - // ./b.js diff --git a/tests/rspack-test/esmOutputCases/dynamic-import/dyn-import-multi-module-duplicate-external/__snapshots__/runtimeModeSnapshot/esm.snap.txt b/tests/rspack-test/esmOutputCases/dynamic-import/dyn-import-multi-module-duplicate-external/__snapshots__/runtimeModeSnapshot/esm.snap.txt index ad3015e3ed49..bbdc0375c5f1 100644 --- a/tests/rspack-test/esmOutputCases/dynamic-import/dyn-import-multi-module-duplicate-external/__snapshots__/runtimeModeSnapshot/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/dynamic-import/dyn-import-multi-module-duplicate-external/__snapshots__/runtimeModeSnapshot/esm.snap.txt @@ -68,14 +68,12 @@ definePropertyGetters(b_namespaceObject, { readFile: () => (readFile) }); -// fs?2aa6 +// fs // ./a.js -// fs?f4d4 - // ./b.js diff --git a/tests/rspack-test/esmOutputCases/dynamic-import/dyn-import-multi-module-namespace-named-external/__snapshots__/esm.snap.txt b/tests/rspack-test/esmOutputCases/dynamic-import/dyn-import-multi-module-namespace-named-external/__snapshots__/esm.snap.txt index 454b48ae094d..ffbf59be5e71 100644 --- a/tests/rspack-test/esmOutputCases/dynamic-import/dyn-import-multi-module-namespace-named-external/__snapshots__/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/dynamic-import/dyn-import-multi-module-namespace-named-external/__snapshots__/esm.snap.txt @@ -71,15 +71,11 @@ __webpack_require__.d(b_namespaceObject, { resolve: () => (resolve) }); -// path?2d49 - // ./a.js -// path?2b46 - // ./b.js diff --git a/tests/rspack-test/esmOutputCases/dynamic-import/dyn-import-multi-module-namespace-named-external/__snapshots__/runtimeModeSnapshot/esm.snap.txt b/tests/rspack-test/esmOutputCases/dynamic-import/dyn-import-multi-module-namespace-named-external/__snapshots__/runtimeModeSnapshot/esm.snap.txt index 5b761b156aaf..d8c000c7af22 100644 --- a/tests/rspack-test/esmOutputCases/dynamic-import/dyn-import-multi-module-namespace-named-external/__snapshots__/runtimeModeSnapshot/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/dynamic-import/dyn-import-multi-module-namespace-named-external/__snapshots__/runtimeModeSnapshot/esm.snap.txt @@ -67,15 +67,11 @@ definePropertyGetters(b_namespaceObject, { resolve: () => (resolve) }); -// path?2d49 - // ./a.js -// path?2b46 - // ./b.js diff --git a/tests/rspack-test/esmOutputCases/dynamic-import/dyn-import-multi-module-namespace-source-conflict/__snapshots__/esm.snap.txt b/tests/rspack-test/esmOutputCases/dynamic-import/dyn-import-multi-module-namespace-source-conflict/__snapshots__/esm.snap.txt index 24ab0a4677f5..d257410aba27 100644 --- a/tests/rspack-test/esmOutputCases/dynamic-import/dyn-import-multi-module-namespace-source-conflict/__snapshots__/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/dynamic-import/dyn-import-multi-module-namespace-source-conflict/__snapshots__/esm.snap.txt @@ -18,15 +18,11 @@ export {}; import * as __rspack_external_fs from "fs"; import * as __rspack_external_path from "path"; -// fs - // ./a.js -// path - // ./b.js diff --git a/tests/rspack-test/esmOutputCases/dynamic-import/dyn-import-multi-module-re-export/__snapshots__/esm.snap.txt b/tests/rspack-test/esmOutputCases/dynamic-import/dyn-import-multi-module-re-export/__snapshots__/esm.snap.txt index 3a44d82f028e..9f7619f81418 100644 --- a/tests/rspack-test/esmOutputCases/dynamic-import/dyn-import-multi-module-re-export/__snapshots__/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/dynamic-import/dyn-import-multi-module-re-export/__snapshots__/esm.snap.txt @@ -1,6 +1,4 @@ ```mjs title=ab-chunk.mjs -// fs - // ./a.js @@ -9,8 +7,6 @@ const value = 42 const helper = () => 1 -// path - // ./b.js diff --git a/tests/rspack-test/esmOutputCases/dynamic-import/dyn-import-re-export-external/__snapshots__/esm.snap.txt b/tests/rspack-test/esmOutputCases/dynamic-import/dyn-import-re-export-external/__snapshots__/esm.snap.txt index 209df5ca399d..9006cc889a28 100644 --- a/tests/rspack-test/esmOutputCases/dynamic-import/dyn-import-re-export-external/__snapshots__/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/dynamic-import/dyn-import-re-export-external/__snapshots__/esm.snap.txt @@ -11,8 +11,6 @@ export {}; ``` ```mjs title=wrapper.mjs -// fs - // ./wrapper.js diff --git a/tests/rspack-test/esmOutputCases/externals/aliased/__snapshots__/esm.snap.txt b/tests/rspack-test/esmOutputCases/externals/aliased/__snapshots__/esm.snap.txt index 8713819f2c29..e831b7513ddf 100644 --- a/tests/rspack-test/esmOutputCases/externals/aliased/__snapshots__/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/externals/aliased/__snapshots__/esm.snap.txt @@ -1,8 +1,4 @@ ```mjs title=main.mjs -import * as __rspack_external_path from "path"; - -// external - // ./index.js diff --git a/tests/rspack-test/esmOutputCases/externals/create-require-name/__snapshots__/esm.snap.txt b/tests/rspack-test/esmOutputCases/externals/create-require-name/__snapshots__/esm.snap.txt index f933df9ec1ed..5ff6939738a3 100644 --- a/tests/rspack-test/esmOutputCases/externals/create-require-name/__snapshots__/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/externals/create-require-name/__snapshots__/esm.snap.txt @@ -1,8 +1,6 @@ ```mjs title=main.mjs import { createRequire } from "node:module"; -// node:module - // ./index.js diff --git a/tests/rspack-test/esmOutputCases/externals/create-require-name/__snapshots__/runtimeModeSnapshot/esm.snap.txt b/tests/rspack-test/esmOutputCases/externals/create-require-name/__snapshots__/runtimeModeSnapshot/esm.snap.txt index f933df9ec1ed..5ff6939738a3 100644 --- a/tests/rspack-test/esmOutputCases/externals/create-require-name/__snapshots__/runtimeModeSnapshot/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/externals/create-require-name/__snapshots__/runtimeModeSnapshot/esm.snap.txt @@ -1,8 +1,6 @@ ```mjs title=main.mjs import { createRequire } from "node:module"; -// node:module - // ./index.js diff --git a/tests/rspack-test/esmOutputCases/externals/dedup-external-imports-mixed/__snapshots__/esm.snap.txt b/tests/rspack-test/esmOutputCases/externals/dedup-external-imports-mixed/__snapshots__/esm.snap.txt index 62c5e38c3ddf..68e1cc5c0fa6 100644 --- a/tests/rspack-test/esmOutputCases/externals/dedup-external-imports-mixed/__snapshots__/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/externals/dedup-external-imports-mixed/__snapshots__/esm.snap.txt @@ -3,7 +3,7 @@ import { __webpack_require__ } from "./runtime.mjs"; import * as __rspack_external_fs from "fs"; __webpack_require__.add({ -"fs?94de" +"fs" /*!*********************!*\ !*** external "fs" ***! \*********************/ @@ -20,14 +20,12 @@ module.exports = __rspack_external_fs; (__unused_rspack_module, exports, __webpack_require__) { // CJS module - will NOT be scope-hoisted, causing its fs dep // to go through init fragment path instead of raw_import_stmts -const fs = __webpack_require__(/*! fs */ "fs?94de") +const fs = __webpack_require__(/*! fs */ "fs") exports.g = fs.readFileSync }, }); -// fs?fa25 - // ./esm-consumer.js // ESM module importing fs namespace - will be scope-hoisted (Concatenated) diff --git a/tests/rspack-test/esmOutputCases/externals/dedup-external-imports-mixed/__snapshots__/runtimeModeSnapshot/esm.snap.txt b/tests/rspack-test/esmOutputCases/externals/dedup-external-imports-mixed/__snapshots__/runtimeModeSnapshot/esm.snap.txt index 89c975c8fbf2..848a50de0398 100644 --- a/tests/rspack-test/esmOutputCases/externals/dedup-external-imports-mixed/__snapshots__/runtimeModeSnapshot/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/externals/dedup-external-imports-mixed/__snapshots__/runtimeModeSnapshot/esm.snap.txt @@ -2,7 +2,7 @@ import { rspackRequire, moduleFactories } from "./runtime.mjs"; import * as __rspack_external_fs from "fs"; moduleFactories.add({ -"fs?94de" +"fs" /*!*********************!*\ !*** external "fs" ***! \*********************/ @@ -19,14 +19,12 @@ module.exports = __rspack_external_fs; (__unused_rspack_module, exports) { // CJS module - will NOT be scope-hoisted, causing its fs dep // to go through init fragment path instead of raw_import_stmts -const fs = rspackRequire(/*! fs */ "fs?94de") +const fs = rspackRequire(/*! fs */ "fs") exports.g = fs.readFileSync }, }); -// fs?fa25 - // ./esm-consumer.js // ESM module importing fs namespace - will be scope-hoisted (Concatenated) diff --git a/tests/rspack-test/esmOutputCases/externals/dedup-external-imports/__snapshots__/esm.snap.txt b/tests/rspack-test/esmOutputCases/externals/dedup-external-imports/__snapshots__/esm.snap.txt index 723b9fedd354..e8b35f69d101 100644 --- a/tests/rspack-test/esmOutputCases/externals/dedup-external-imports/__snapshots__/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/externals/dedup-external-imports/__snapshots__/esm.snap.txt @@ -2,13 +2,9 @@ import * as __rspack_external_fs from "fs"; import { readFile } from "fs"; -// fs?f137 - // ./lib.js -// fs?303b - // ./lib2.js diff --git a/tests/rspack-test/esmOutputCases/externals/default-and-namespace/__snapshots__/esm.snap.txt b/tests/rspack-test/esmOutputCases/externals/default-and-namespace/__snapshots__/esm.snap.txt index 1ecec45fe60f..e1f32dfdf6d4 100644 --- a/tests/rspack-test/esmOutputCases/externals/default-and-namespace/__snapshots__/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/externals/default-and-namespace/__snapshots__/esm.snap.txt @@ -1,24 +1,22 @@ ```mjs title=main.mjs -import * as __rspack_external_fs from "fs"; - -// fs +import fs, * as fsNs from "fs"; // ./index.js -/* export default */ const index = (__rspack_external_fs["default"]); +/* export default */ const index = (fs); it("should distinguish external default and namespace imports", async () => { const mod = await import(/* webpackIgnore: true */ "./main.mjs"); - expect(mod.default).toBe(__rspack_external_fs["default"]); - expect(mod.default).toBe(__rspack_external_fs["default"]); + expect(mod.default).toBe(fs); + expect(mod.default).toBe(fsNs["default"]); expect(typeof mod.fsNs.readFile).toBe("function"); }); -export { __rspack_external_fs as fsNs }; +export { fsNs }; export default index; ``` \ No newline at end of file diff --git a/tests/rspack-test/esmOutputCases/externals/empty-import/__snapshots__/esm.snap.txt b/tests/rspack-test/esmOutputCases/externals/empty-import/__snapshots__/esm.snap.txt index fa9f9806550a..68c7dbf92cf5 100644 --- a/tests/rspack-test/esmOutputCases/externals/empty-import/__snapshots__/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/externals/empty-import/__snapshots__/esm.snap.txt @@ -1,8 +1,6 @@ ```mjs title=main.mjs import "fs"; -// fs - // ./index.js export {}; diff --git a/tests/rspack-test/esmOutputCases/externals/esm-node-target-alias/__snapshots__/esm.snap.txt b/tests/rspack-test/esmOutputCases/externals/esm-node-target-alias/__snapshots__/esm.snap.txt index 7a13a9bbe52e..5d9521b6412c 100644 --- a/tests/rspack-test/esmOutputCases/externals/esm-node-target-alias/__snapshots__/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/externals/esm-node-target-alias/__snapshots__/esm.snap.txt @@ -22,10 +22,6 @@ exports.g = nodeUrl.parse; }, }); -// node:fs - -// node:url - // ./index.js const cjs_consumer = __webpack_require__("./cjs-consumer.cjs"); var g = cjs_consumer.g; diff --git a/tests/rspack-test/esmOutputCases/externals/esm-node-target-alias/__snapshots__/runtimeModeSnapshot/esm.snap.txt b/tests/rspack-test/esmOutputCases/externals/esm-node-target-alias/__snapshots__/runtimeModeSnapshot/esm.snap.txt index afdfacc201f0..e12b2a11397e 100644 --- a/tests/rspack-test/esmOutputCases/externals/esm-node-target-alias/__snapshots__/runtimeModeSnapshot/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/externals/esm-node-target-alias/__snapshots__/runtimeModeSnapshot/esm.snap.txt @@ -22,10 +22,6 @@ exports.g = nodeUrl.parse; }, }); -// node:fs - -// node:url - // ./index.js const cjs_consumer = rspackRequire("./cjs-consumer.cjs"); var g = cjs_consumer.g; diff --git a/tests/rspack-test/esmOutputCases/externals/esm-node-target/__snapshots__/esm.snap.txt b/tests/rspack-test/esmOutputCases/externals/esm-node-target/__snapshots__/esm.snap.txt index 24b25b3e89d8..009785410d06 100644 --- a/tests/rspack-test/esmOutputCases/externals/esm-node-target/__snapshots__/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/externals/esm-node-target/__snapshots__/esm.snap.txt @@ -2,10 +2,6 @@ import { resolve } from "path"; import { __webpack_require__ } from "./runtime.mjs"; -// path - -// fs - // ./index.js diff --git a/tests/rspack-test/esmOutputCases/externals/esm-node-target/__snapshots__/runtimeModeSnapshot/esm.snap.txt b/tests/rspack-test/esmOutputCases/externals/esm-node-target/__snapshots__/runtimeModeSnapshot/esm.snap.txt index 25d5c48134ff..7de9a3de432e 100644 --- a/tests/rspack-test/esmOutputCases/externals/esm-node-target/__snapshots__/runtimeModeSnapshot/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/externals/esm-node-target/__snapshots__/runtimeModeSnapshot/esm.snap.txt @@ -2,10 +2,6 @@ import { rspackRequire, createFakeNamespaceObject } from "./runtime.mjs"; import { resolve } from "path"; -// path - -// fs - // ./index.js diff --git a/tests/rspack-test/esmOutputCases/externals/export-namespace-as-with-named-same-source/__snapshots__/esm.snap.txt b/tests/rspack-test/esmOutputCases/externals/export-namespace-as-with-named-same-source/__snapshots__/esm.snap.txt index 250c22775274..b4d9fd46bfbe 100644 --- a/tests/rspack-test/esmOutputCases/externals/export-namespace-as-with-named-same-source/__snapshots__/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/externals/export-namespace-as-with-named-same-source/__snapshots__/esm.snap.txt @@ -1,7 +1,6 @@ ```mjs title=main.mjs import * as __rspack_external_fs from "fs"; - -// fs +import { readFile, readFileSync } from "fs"; // ./index.js @@ -14,8 +13,6 @@ it("should combine export-star-as and named exports for the same external source expect(mod.fsNs.readFileSync).toBe(mod.readFileSync); }); -var readFile = __rspack_external_fs.readFile; -var readFileSync = __rspack_external_fs.readFileSync; export { __rspack_external_fs as fsNs, readFile, readFileSync }; ``` \ No newline at end of file diff --git a/tests/rspack-test/esmOutputCases/externals/export-namespace-as/__snapshots__/esm.snap.txt b/tests/rspack-test/esmOutputCases/externals/export-namespace-as/__snapshots__/esm.snap.txt index 2537c131c023..cddabdbee82f 100644 --- a/tests/rspack-test/esmOutputCases/externals/export-namespace-as/__snapshots__/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/externals/export-namespace-as/__snapshots__/esm.snap.txt @@ -1,8 +1,6 @@ ```mjs title=main.mjs import * as __rspack_external_fs from "fs"; -// fs - // ./index.js diff --git a/tests/rspack-test/esmOutputCases/externals/externals-aliased/__snapshots__/esm.snap.txt b/tests/rspack-test/esmOutputCases/externals/externals-aliased/__snapshots__/esm.snap.txt index a45fc8089479..ca556f788a06 100644 --- a/tests/rspack-test/esmOutputCases/externals/externals-aliased/__snapshots__/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/externals/externals-aliased/__snapshots__/esm.snap.txt @@ -1,13 +1,9 @@ ```mjs title=main.mjs -// fs?f23b - // ./module.js console.log.bind(console) -// fs?771d - // ./index.js diff --git a/tests/rspack-test/esmOutputCases/externals/externals-import-render/__snapshots__/esm.snap.txt b/tests/rspack-test/esmOutputCases/externals/externals-import-render/__snapshots__/esm.snap.txt index 4f9c43227502..f76dd7745d40 100644 --- a/tests/rspack-test/esmOutputCases/externals/externals-import-render/__snapshots__/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/externals/externals-import-render/__snapshots__/esm.snap.txt @@ -2,10 +2,6 @@ import fs from "fs"; import { join, resolve } from "path"; -// fs - -// path - // ./index.js diff --git a/tests/rspack-test/esmOutputCases/externals/import-namespace-reexport-with-named-same-source/__snapshots__/esm.snap.txt b/tests/rspack-test/esmOutputCases/externals/import-namespace-reexport-with-named-same-source/__snapshots__/esm.snap.txt index 2c168dba93f4..14c4f1058bf0 100644 --- a/tests/rspack-test/esmOutputCases/externals/import-namespace-reexport-with-named-same-source/__snapshots__/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/externals/import-namespace-reexport-with-named-same-source/__snapshots__/esm.snap.txt @@ -1,7 +1,6 @@ ```mjs title=main.mjs import * as __rspack_external_fs from "fs"; - -// fs +import { readFile, readFileSync } from "fs"; // ./index.js @@ -16,8 +15,6 @@ it("should re-export an imported external namespace alongside named exports from expect(mod.fsNs.readFileSync).toBe(mod.readFileSync); }); -var readFile = __rspack_external_fs.readFile; -var readFileSync = __rspack_external_fs.readFileSync; export { __rspack_external_fs as fsNs, readFile, readFileSync }; ``` \ No newline at end of file diff --git a/tests/rspack-test/esmOutputCases/externals/import-namespace-reexport-with-named/__snapshots__/esm.snap.txt b/tests/rspack-test/esmOutputCases/externals/import-namespace-reexport-with-named/__snapshots__/esm.snap.txt index 518a9b605557..d4b80e3980f1 100644 --- a/tests/rspack-test/esmOutputCases/externals/import-namespace-reexport-with-named/__snapshots__/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/externals/import-namespace-reexport-with-named/__snapshots__/esm.snap.txt @@ -2,10 +2,6 @@ import { sep } from "path"; import * as __rspack_external_fs from "fs"; -// path - -// fs - // ./index.js diff --git a/tests/rspack-test/esmOutputCases/externals/import-namespace-reexport/__snapshots__/esm.snap.txt b/tests/rspack-test/esmOutputCases/externals/import-namespace-reexport/__snapshots__/esm.snap.txt index 3a76e92218e5..dd812be7339a 100644 --- a/tests/rspack-test/esmOutputCases/externals/import-namespace-reexport/__snapshots__/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/externals/import-namespace-reexport/__snapshots__/esm.snap.txt @@ -1,8 +1,6 @@ ```mjs title=main.mjs import * as __rspack_external_fs from "fs"; -// fs - // ./index.js diff --git a/tests/rspack-test/esmOutputCases/externals/mixed-module-import-and-node-commonjs-same-target/__snapshots__/esm.snap.txt b/tests/rspack-test/esmOutputCases/externals/mixed-module-import-and-node-commonjs-same-target/__snapshots__/esm.snap.txt index a0d31e24e9a5..a32b7d8ed7b3 100644 --- a/tests/rspack-test/esmOutputCases/externals/mixed-module-import-and-node-commonjs-same-target/__snapshots__/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/externals/mixed-module-import-and-node-commonjs-same-target/__snapshots__/esm.snap.txt @@ -3,8 +3,6 @@ import * as __rspack_external_webpack_sources_lib_index_js_9a113ddb from "webpac import { createRequire as __rspack_createRequire } from "node:module"; const __rspack_createRequire_require = __rspack_createRequire(import.meta.url); -// ws-ns - // ./namespace.js diff --git a/tests/rspack-test/esmOutputCases/externals/multiple-externals/__snapshots__/esm.snap.txt b/tests/rspack-test/esmOutputCases/externals/multiple-externals/__snapshots__/esm.snap.txt index 9a5a52a68e8b..af1bbb09722e 100644 --- a/tests/rspack-test/esmOutputCases/externals/multiple-externals/__snapshots__/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/externals/multiple-externals/__snapshots__/esm.snap.txt @@ -1,33 +1,25 @@ ```mjs title=async.mjs -import * as __rspack_external_fs from "fs"; - -// fs?3cf4 +import * as ns from "fs"; // ./async.js // access namespace -console.log.bind(__rspack_external_fs) +console.log.bind(ns) -export { __rspack_external_fs as ns }; +export { ns }; ``` ```mjs title=main.mjs import fs, { readFile } from "fs"; -// fs?771d - -// fs?5ccf - // ./other.js /* export default */ const other = (fs); -// fs?22cf - // ./other2.js diff --git a/tests/rspack-test/esmOutputCases/externals/named-import-scope-hoisted/__snapshots__/esm.snap.txt b/tests/rspack-test/esmOutputCases/externals/named-import-scope-hoisted/__snapshots__/esm.snap.txt index 2788b489eb9b..880be4484ea7 100644 --- a/tests/rspack-test/esmOutputCases/externals/named-import-scope-hoisted/__snapshots__/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/externals/named-import-scope-hoisted/__snapshots__/esm.snap.txt @@ -1,8 +1,6 @@ ```mjs title=main.mjs import { readFile } from "fs"; -// virtual-fs - // ./index.js diff --git a/tests/rspack-test/esmOutputCases/externals/namespace-and-named/__snapshots__/esm.snap.txt b/tests/rspack-test/esmOutputCases/externals/namespace-and-named/__snapshots__/esm.snap.txt index e440dcaab1aa..249b7f66e5bb 100644 --- a/tests/rspack-test/esmOutputCases/externals/namespace-and-named/__snapshots__/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/externals/namespace-and-named/__snapshots__/esm.snap.txt @@ -1,14 +1,14 @@ ```mjs title=main.mjs -import * as __rspack_external_fs from "fs"; -// fs +import * as fsNs from "fs"; +import { readFile, readFileSync } from "fs"; // ./index.js it("should keep namespace and named external imports aligned", () => { - expect(__rspack_external_fs.readFile).toBe(__rspack_external_fs.readFile); - expect(__rspack_external_fs.readFileSync).toBe(__rspack_external_fs.readFileSync); + expect(fsNs.readFile).toBe(readFile); + expect(fsNs.readFileSync).toBe(readFileSync); }); export {}; diff --git a/tests/rspack-test/esmOutputCases/externals/namespace-member-access/__snapshots__/esm.snap.txt b/tests/rspack-test/esmOutputCases/externals/namespace-member-access/__snapshots__/esm.snap.txt index cb58462d6b13..fda0d0b8d4a1 100644 --- a/tests/rspack-test/esmOutputCases/externals/namespace-member-access/__snapshots__/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/externals/namespace-member-access/__snapshots__/esm.snap.txt @@ -1,12 +1,11 @@ ```mjs title=main.mjs -import * as __rspack_external_fs from "fs"; -// fs +import * as fsNs from "fs"; // ./index.js it('should keep namespace import for external namespace member access', () => { - expect(__rspack_external_fs.readFile).toBeDefined() + expect(fsNs.readFile).toBeDefined() }) export {}; diff --git a/tests/rspack-test/esmOutputCases/externals/namespace-name-collision-across-modules/__snapshots__/esm.snap.txt b/tests/rspack-test/esmOutputCases/externals/namespace-name-collision-across-modules/__snapshots__/esm.snap.txt index f56116763bd8..d3d323cf1915 100644 --- a/tests/rspack-test/esmOutputCases/externals/namespace-name-collision-across-modules/__snapshots__/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/externals/namespace-name-collision-across-modules/__snapshots__/esm.snap.txt @@ -1,8 +1,6 @@ ```mjs title=main.mjs import * as __rspack_external_path from "path"; -// fs - // ./named.js diff --git a/tests/rspack-test/esmOutputCases/externals/namespace-name-collision-across-modules/__snapshots__/runtimeModeSnapshot/esm.snap.txt b/tests/rspack-test/esmOutputCases/externals/namespace-name-collision-across-modules/__snapshots__/runtimeModeSnapshot/esm.snap.txt new file mode 100644 index 000000000000..d3d323cf1915 --- /dev/null +++ b/tests/rspack-test/esmOutputCases/externals/namespace-name-collision-across-modules/__snapshots__/runtimeModeSnapshot/esm.snap.txt @@ -0,0 +1,35 @@ +```mjs title=main.mjs +import * as __rspack_external_path from "path"; + +// ./named.js + + +// path + +// ./path-ns.js + + +const joinFn = Reflect.get(__rspack_external_path, "join"); + + + +// ./index.js + + + +it("should deconflict concatenated namespace imports that match generated module-import names", async () => { + const mod = await import(/* webpackIgnore: true */ "./main.mjs"); + const fs = await import("fs"); + const path = await import("path"); + + expect(mod.readFile).toBe(fs.readFile); + expect(mod.readFileSync).toBe(fs.readFileSync); + expect(mod.pathNs.sep).toBe(path.sep); + expect(mod.pathNs.join).toBe(path.join); + expect(mod.joinFn).toBe(path.join); +}); + +export { __rspack_external_path as pathNs, joinFn }; +export { readFile, readFileSync } from "fs"; + +``` \ No newline at end of file diff --git a/tests/rspack-test/esmOutputCases/externals/node-commonjs-helper-name-collision/__snapshots__/esm.snap.txt b/tests/rspack-test/esmOutputCases/externals/node-commonjs-helper-name-collision/__snapshots__/esm.snap.txt index 08e3e6bfa052..08cd3f9bb7dd 100644 --- a/tests/rspack-test/esmOutputCases/externals/node-commonjs-helper-name-collision/__snapshots__/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/externals/node-commonjs-helper-name-collision/__snapshots__/esm.snap.txt @@ -1,9 +1,21 @@ ```mjs title=main.mjs +import { __webpack_require__ } from "./runtime.mjs"; + import {fileURLToPath as __rspack_fileURLToPath} from "node:url"; import {dirname as __rspack_dirname} from "node:path"; var __rspack_import_meta_dirname__ = __rspack_dirname(__rspack_fileURLToPath(import.meta.url)); import { createRequire as __rspack_createRequire } from "node:module"; const __rspack_createRequire_require = __rspack_createRequire(import.meta.url); +__webpack_require__.add({ +"fs" +/*!*********************!*\ + !*** external "fs" ***! + \*********************/ +(module) { +module.exports = __rspack_createRequire_require("fs"); + +}, +}); // node:module const external_node_module_namespaceObject = __rspack_createRequire_require("node:module"); // ./index.js @@ -15,7 +27,7 @@ const external_fs_namespaceObject = index_rspack_createRequire_require("fs"); const sourceCreateRequireRequire = index_rspack_createRequire_require; const sourceReadFile = external_fs_namespaceObject.readFile; -const sourceRequireReadFile = (index_rspack_createRequire_require("fs").readFile); +const sourceRequireReadFile = (__webpack_require__(/*! fs */ "fs")/* .readFile */.readFile); it("should deconflict source bindings that already use the node-commonjs helper names", async () => { const mod = await import(/* webpackIgnore: true */ "./main.mjs"); @@ -38,4 +50,39 @@ it("should deconflict source bindings that already use the node-commonjs helper export { sourceCreateRequireRequire, sourceReadFile, sourceRequireReadFile }; +``` + +```mjs title=runtime.mjs + +var __webpack_modules__ = {}; +// The module cache +var __webpack_module_cache__ = {}; +// The require function +function __webpack_require__(moduleId) { +// Check if module is in cache +var cachedModule = __webpack_module_cache__[moduleId]; +if (cachedModule !== undefined) { +return cachedModule.exports; +} +// Create a new module (and put it into the cache) +var module = (__webpack_module_cache__[moduleId] = { +exports: {} +}); +// Execute the module function +__webpack_modules__[moduleId](module, module.exports, __webpack_require__); + +// Return the exports of the module +return module.exports; +} +// expose the modules object (__webpack_modules__) +__webpack_require__.m = __webpack_modules__; + +// webpack/runtime/esm_register_module +(() => { +__webpack_require__.add = function registerModules(modules) { Object.assign(__webpack_require__.m, modules) } + +})(); + +export { __webpack_require__ }; + ``` \ No newline at end of file diff --git a/tests/rspack-test/esmOutputCases/externals/node-commonjs-helper-name-collision/__snapshots__/runtimeModeSnapshot/esm.snap.txt b/tests/rspack-test/esmOutputCases/externals/node-commonjs-helper-name-collision/__snapshots__/runtimeModeSnapshot/esm.snap.txt new file mode 100644 index 000000000000..fcaedecb87ef --- /dev/null +++ b/tests/rspack-test/esmOutputCases/externals/node-commonjs-helper-name-collision/__snapshots__/runtimeModeSnapshot/esm.snap.txt @@ -0,0 +1,86 @@ +```mjs title=main.mjs +import { rspackRequire, moduleFactories } from "./runtime.mjs"; +import {fileURLToPath as __rspack_fileURLToPath} from "node:url"; +import {dirname as __rspack_dirname} from "node:path"; +var __rspack_import_meta_dirname__ = __rspack_dirname(__rspack_fileURLToPath(import.meta.url)); +import { createRequire as __rspack_createRequire } from "node:module"; +const __rspack_createRequire_require = __rspack_createRequire(import.meta.url); +moduleFactories.add({ +"fs" +/*!*********************!*\ + !*** external "fs" ***! + \*********************/ +(module) { +module.exports = __rspack_createRequire_require("fs"); + +}, +}); +// node:module +const external_node_module_namespaceObject = __rspack_createRequire_require("node:module"); +// ./index.js + + +const index_rspack_createRequire_require = (0,external_node_module_namespaceObject.createRequire)('/tests/rspack-test/esmOutputCases/externals/node-commonjs-helper-name-collision/index.js'); +// fs +const external_fs_namespaceObject = index_rspack_createRequire_require("fs"); + +const sourceCreateRequireRequire = index_rspack_createRequire_require; +const sourceReadFile = external_fs_namespaceObject.readFile; +const sourceRequireReadFile = (rspackRequire(/*! fs */ "fs")/* .readFile */.readFile); + +it("should deconflict source bindings that already use the node-commonjs helper names", async () => { + const mod = await import(/* webpackIgnore: true */ "./main.mjs"); + const { createRequire } = await import(/* webpackIgnore: true */ "node:module"); + const require = createRequire('/tests/rspack-test/esmOutputCases/externals/node-commonjs-helper-name-collision/index.js'); + const fs = require("fs"); + const path = require("path"); + const code = fs.readFileSync(path.join(__rspack_import_meta_dirname__, "main.mjs"), "utf-8"); + + expect(mod.sourceReadFile).toBe(fs.readFile); + expect(mod.sourceRequireReadFile).toBe(fs.readFile); + expect(mod.sourceCreateRequireRequire("fs").readFile).toBe(fs.readFile); + expect(code).toContain( + 'const __rspack_createRequire_require = __rspack_createRequire(import.meta.url);' + ); + expect(code).toMatch( + /^const (?!__rspack_createRequire_require\b)[A-Za-z0-9_$]*rspack_createRequire_require = .*createRequire.*;$/m + ); +}); + +export { sourceCreateRequireRequire, sourceReadFile, sourceRequireReadFile }; + +``` + +```mjs title=runtime.mjs + +var modules = {}; +// The module cache +var moduleCache = {}; +// The require function +function rspackRequire(moduleId) { +// Check if module is in cache +var cachedModule = moduleCache[moduleId]; +if (cachedModule !== undefined) { +return cachedModule.exports; +} +// Create a new module (and put it into the cache) +var module = (moduleCache[moduleId] = { +exports: {} +}); +// Execute the module function +modules[moduleId](module, module.exports, rspackRequire); + +// Return the exports of the module +return module.exports; +} +export { rspackRequire }; +// expose the modules object (modules) +var moduleFactories = modules; +export { moduleFactories }; + +// rspack/runtime/esm_register_module +moduleFactories.add = function registerModules(modules) { Object.assign(moduleFactories, modules) } +; + + +``` \ No newline at end of file diff --git a/tests/rspack-test/esmOutputCases/externals/override-star-reexport/__snapshots__/esm.snap.txt b/tests/rspack-test/esmOutputCases/externals/override-star-reexport/__snapshots__/esm.snap.txt index b9a97b47d049..5d7438757a30 100644 --- a/tests/rspack-test/esmOutputCases/externals/override-star-reexport/__snapshots__/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/externals/override-star-reexport/__snapshots__/esm.snap.txt @@ -1,8 +1,4 @@ ```mjs title=main.mjs -import * as __rspack_external_fs from "fs"; - -// fs - // ./index.js diff --git a/tests/rspack-test/esmOutputCases/externals/probe-namespace-properties/__snapshots__/esm.snap.txt b/tests/rspack-test/esmOutputCases/externals/probe-namespace-properties/__snapshots__/esm.snap.txt index 8415bc9ac55c..b57053c5f561 100644 --- a/tests/rspack-test/esmOutputCases/externals/probe-namespace-properties/__snapshots__/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/externals/probe-namespace-properties/__snapshots__/esm.snap.txt @@ -1,7 +1,5 @@ ```mjs title=main.mjs -import * as __rspack_external_fs from "fs"; - -// fs +import * as fsNs from "fs"; // ./index.js @@ -10,9 +8,9 @@ it("should allow probing external namespace properties", () => { const presentKey = ["read", "File"].join(""); const missingKey = ["not", "There"].join(""); - expect(__rspack_external_fs["default"]).toBeDefined(); - expect(Reflect.get(__rspack_external_fs, presentKey)).toBeDefined(); - expect(Reflect.get(__rspack_external_fs, missingKey)).toBeUndefined(); + expect(fsNs["default"]).toBeDefined(); + expect(Reflect.get(fsNs, presentKey)).toBeDefined(); + expect(Reflect.get(fsNs, missingKey)).toBeUndefined(); }); export {}; diff --git a/tests/rspack-test/esmOutputCases/externals/reexport-external-namespace-as/__snapshots__/esm.snap.txt b/tests/rspack-test/esmOutputCases/externals/reexport-external-namespace-as/__snapshots__/esm.snap.txt index 1709d0a284d4..fecf60a91244 100644 --- a/tests/rspack-test/esmOutputCases/externals/reexport-external-namespace-as/__snapshots__/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/externals/reexport-external-namespace-as/__snapshots__/esm.snap.txt @@ -1,8 +1,6 @@ ```mjs title=main.mjs import * as __rspack_external_fs from "fs"; -// fs - // ./index.js diff --git a/tests/rspack-test/esmOutputCases/externals/reexport-imported-namespace-via-module/__snapshots__/esm.snap.txt b/tests/rspack-test/esmOutputCases/externals/reexport-imported-namespace-via-module/__snapshots__/esm.snap.txt index 9d5269cefb61..2e8b635603e2 100644 --- a/tests/rspack-test/esmOutputCases/externals/reexport-imported-namespace-via-module/__snapshots__/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/externals/reexport-imported-namespace-via-module/__snapshots__/esm.snap.txt @@ -1,8 +1,6 @@ ```mjs title=main.mjs import * as __rspack_external_fs from "fs"; -// fs - // ./dep.js diff --git a/tests/rspack-test/esmOutputCases/externals/reexport-star-as-namespace-via-module-with-own-export/__snapshots__/esm.snap.txt b/tests/rspack-test/esmOutputCases/externals/reexport-star-as-namespace-via-module-with-own-export/__snapshots__/esm.snap.txt index 9f62ec88a555..e63e239bf625 100644 --- a/tests/rspack-test/esmOutputCases/externals/reexport-star-as-namespace-via-module-with-own-export/__snapshots__/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/externals/reexport-star-as-namespace-via-module-with-own-export/__snapshots__/esm.snap.txt @@ -1,6 +1,6 @@ ```mjs title=main.mjs import { __webpack_require__ } from "./runtime.mjs"; -import * as __rspack_external_fs from "fs"; +import * as external from "fs"; // NAMESPACE OBJECT: ./reexport-external.js var reexport_external_namespaceObject = {}; @@ -8,7 +8,7 @@ __webpack_require__.r(reexport_external_namespaceObject); __webpack_require__.d(reexport_external_namespaceObject, { marker: () => (marker), readFile: () => (readFile) }); -var reexport_external_namespaceObject_starExports = __rspack_external_fs; +var reexport_external_namespaceObject_starExports = external; Object.keys(reexport_external_namespaceObject_starExports).forEach(function(key) { if (key !== "default" && key !== "__esModule") { __webpack_require__.d(reexport_external_namespaceObject, { [key]: function() { return reexport_external_namespaceObject_starExports[key]; } }); @@ -16,8 +16,6 @@ Object.keys(reexport_external_namespaceObject_starExports).forEach(function(key) }); -// fs - // ./reexport-external.js diff --git a/tests/rspack-test/esmOutputCases/externals/reexport-star-as-namespace-via-module-with-own-export/__snapshots__/runtimeModeSnapshot/esm.snap.txt b/tests/rspack-test/esmOutputCases/externals/reexport-star-as-namespace-via-module-with-own-export/__snapshots__/runtimeModeSnapshot/esm.snap.txt index 983523a8c455..d1d61766fcc5 100644 --- a/tests/rspack-test/esmOutputCases/externals/reexport-star-as-namespace-via-module-with-own-export/__snapshots__/runtimeModeSnapshot/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/externals/reexport-star-as-namespace-via-module-with-own-export/__snapshots__/runtimeModeSnapshot/esm.snap.txt @@ -1,6 +1,6 @@ ```mjs title=main.mjs import { rspackRequire, definePropertyGetters, makeNamespaceObject } from "./runtime.mjs"; -import * as __rspack_external_fs from "fs"; +import * as external from "fs"; // NAMESPACE OBJECT: ./reexport-external.js var reexport_external_namespaceObject = {}; @@ -8,7 +8,7 @@ makeNamespaceObject(reexport_external_namespaceObject); definePropertyGetters(reexport_external_namespaceObject, { marker: () => (marker), readFile: () => (readFile) }); -var reexport_external_namespaceObject_starExports = __rspack_external_fs; +var reexport_external_namespaceObject_starExports = external; Object.keys(reexport_external_namespaceObject_starExports).forEach(function(key) { if (key !== "default" && key !== "__esModule") { definePropertyGetters(reexport_external_namespaceObject, { [key]: function() { return reexport_external_namespaceObject_starExports[key]; } }); @@ -16,8 +16,6 @@ Object.keys(reexport_external_namespaceObject_starExports).forEach(function(key) }); -// fs - // ./reexport-external.js diff --git a/tests/rspack-test/esmOutputCases/externals/reexport-star-as-namespace-via-module/__snapshots__/esm.snap.txt b/tests/rspack-test/esmOutputCases/externals/reexport-star-as-namespace-via-module/__snapshots__/esm.snap.txt index b35f0fbdc542..705cc897d97c 100644 --- a/tests/rspack-test/esmOutputCases/externals/reexport-star-as-namespace-via-module/__snapshots__/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/externals/reexport-star-as-namespace-via-module/__snapshots__/esm.snap.txt @@ -1,11 +1,11 @@ ```mjs title=main.mjs import { __webpack_require__ } from "./runtime.mjs"; -import * as __rspack_external_fs from "fs"; +import * as external from "fs"; // NAMESPACE OBJECT: ./reexport-external.js var reexport_external_namespaceObject = {}; __webpack_require__.r(reexport_external_namespaceObject); -var reexport_external_namespaceObject_starExports = __rspack_external_fs; +var reexport_external_namespaceObject_starExports = external; Object.keys(reexport_external_namespaceObject_starExports).forEach(function(key) { if (key !== "default" && key !== "__esModule") { __webpack_require__.d(reexport_external_namespaceObject, { [key]: function() { return reexport_external_namespaceObject_starExports[key]; } }); @@ -13,8 +13,6 @@ Object.keys(reexport_external_namespaceObject_starExports).forEach(function(key) }); -// fs - // ./reexport-external.js diff --git a/tests/rspack-test/esmOutputCases/externals/reexport-star-as-namespace-via-module/__snapshots__/runtimeModeSnapshot/esm.snap.txt b/tests/rspack-test/esmOutputCases/externals/reexport-star-as-namespace-via-module/__snapshots__/runtimeModeSnapshot/esm.snap.txt index a427d8e70b4b..154ba280d364 100644 --- a/tests/rspack-test/esmOutputCases/externals/reexport-star-as-namespace-via-module/__snapshots__/runtimeModeSnapshot/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/externals/reexport-star-as-namespace-via-module/__snapshots__/runtimeModeSnapshot/esm.snap.txt @@ -1,11 +1,11 @@ ```mjs title=main.mjs import { rspackRequire, definePropertyGetters, makeNamespaceObject } from "./runtime.mjs"; -import * as __rspack_external_fs from "fs"; +import * as external from "fs"; // NAMESPACE OBJECT: ./reexport-external.js var reexport_external_namespaceObject = {}; makeNamespaceObject(reexport_external_namespaceObject); -var reexport_external_namespaceObject_starExports = __rspack_external_fs; +var reexport_external_namespaceObject_starExports = external; Object.keys(reexport_external_namespaceObject_starExports).forEach(function(key) { if (key !== "default" && key !== "__esModule") { definePropertyGetters(reexport_external_namespaceObject, { [key]: function() { return reexport_external_namespaceObject_starExports[key]; } }); @@ -13,8 +13,6 @@ Object.keys(reexport_external_namespaceObject_starExports).forEach(function(key) }); -// fs - // ./reexport-external.js diff --git a/tests/rspack-test/esmOutputCases/externals/reexport-used-external-namespace-as/__snapshots__/esm.snap.txt b/tests/rspack-test/esmOutputCases/externals/reexport-used-external-namespace-as/__snapshots__/esm.snap.txt index 018fc94fe676..ca00242f4f6a 100644 --- a/tests/rspack-test/esmOutputCases/externals/reexport-used-external-namespace-as/__snapshots__/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/externals/reexport-used-external-namespace-as/__snapshots__/esm.snap.txt @@ -1,10 +1,7 @@ ```mjs title=main.mjs import * as __rspack_external_fs from "fs"; import * as __rspack_external_path from "path"; - -// fs - -// path +import { resolve } from "path"; // ./index.js @@ -19,7 +16,7 @@ it("should re-export used external namespaces without duplicating semantics", as const mod = await import(/* webpackIgnore: true */ "./main.mjs"); expect(mod.external1.readFile).toBe(__rspack_external_fs.readFile); - expect(mod.external2.resolve).toBe(__rspack_external_path.resolve); + expect(mod.external2.resolve).toBe(resolve); }); export { __rspack_external_fs as external1, __rspack_external_path as external2 }; diff --git a/tests/rspack-test/esmOutputCases/externals/runtime-decide/__snapshots__/esm.snap.txt b/tests/rspack-test/esmOutputCases/externals/runtime-decide/__snapshots__/esm.snap.txt index 03914e9880bb..c5e5b164ded7 100644 --- a/tests/rspack-test/esmOutputCases/externals/runtime-decide/__snapshots__/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/externals/runtime-decide/__snapshots__/esm.snap.txt @@ -26,6 +26,7 @@ def(exports) /* import */ var _dynamic_exports__rspack_import_0 = __webpack_require__(/*! ./dynamic-exports */ "./dynamic-exports.js"); /* import */ var _dynamic_exports__rspack_import_0_default = /*#__PURE__*/__webpack_require__.n(_dynamic_exports__rspack_import_0); if(__webpack_require__.o(_dynamic_exports__rspack_import_0, "readFile")) __webpack_require__.d(__webpack_exports__, { readFile: function() { return _dynamic_exports__rspack_import_0.readFile; } }); +var fs__rspack_import_1 = __rspack_external_fs; /* import */ var fs__rspack_import_1 = __webpack_require__(/*! fs */ "fs"); if(__webpack_require__.o(fs__rspack_import_1, "readFile")) __webpack_require__.d(__webpack_exports__, { readFile: function() { return fs__rspack_import_1.readFile; } }); diff --git a/tests/rspack-test/esmOutputCases/externals/runtime-decide/__snapshots__/runtimeModeSnapshot/esm.snap.txt b/tests/rspack-test/esmOutputCases/externals/runtime-decide/__snapshots__/runtimeModeSnapshot/esm.snap.txt index 12a68d29d854..41964ef21b34 100644 --- a/tests/rspack-test/esmOutputCases/externals/runtime-decide/__snapshots__/runtimeModeSnapshot/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/externals/runtime-decide/__snapshots__/runtimeModeSnapshot/esm.snap.txt @@ -25,6 +25,7 @@ def(exports) /* import */ var _dynamic_exports__rspack_import_0 = rspackRequire(/*! ./dynamic-exports */ "./dynamic-exports.js"); /* import */ var _dynamic_exports__rspack_import_0_default = /*#__PURE__*/compatGetDefaultExport(_dynamic_exports__rspack_import_0); if(hasOwnProperty(_dynamic_exports__rspack_import_0, "readFile")) definePropertyGetters(exports, { readFile: function() { return _dynamic_exports__rspack_import_0.readFile; } }); +var fs__rspack_import_1 = __rspack_external_fs; /* import */ var fs__rspack_import_1 = rspackRequire(/*! fs */ "fs"); if(hasOwnProperty(fs__rspack_import_1, "readFile")) definePropertyGetters(exports, { readFile: function() { return fs__rspack_import_1.readFile; } }); diff --git a/tests/rspack-test/esmOutputCases/externals/shared-external-entry-and-dyn/__snapshots__/esm.snap.txt b/tests/rspack-test/esmOutputCases/externals/shared-external-entry-and-dyn/__snapshots__/esm.snap.txt index a2a952a16f64..0265fdff6518 100644 --- a/tests/rspack-test/esmOutputCases/externals/shared-external-entry-and-dyn/__snapshots__/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/externals/shared-external-entry-and-dyn/__snapshots__/esm.snap.txt @@ -1,6 +1,4 @@ ```mjs title=async.mjs -// fs?3cf4 - // ./async.js const asyncValue = 'async' @@ -12,8 +10,6 @@ export { readFile } from "fs"; ```mjs title=main.mjs import { readFile } from "fs"; -// fs?771d - // ./index.js diff --git a/tests/rspack-test/esmOutputCases/externals/tostring-external-namespaces/__snapshots__/esm.snap.txt b/tests/rspack-test/esmOutputCases/externals/tostring-external-namespaces/__snapshots__/esm.snap.txt index 49e6ba9d9472..03dab4e2a39e 100644 --- a/tests/rspack-test/esmOutputCases/externals/tostring-external-namespaces/__snapshots__/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/externals/tostring-external-namespaces/__snapshots__/esm.snap.txt @@ -1,21 +1,17 @@ ```mjs title=main.mjs -import * as __rspack_external_fs from "fs"; -import * as __rspack_external_path from "path"; - -// fs - -// path +import * as fsNs from "fs"; +import * as pathNs from "path"; // ./index.js /* export default */ const index = ({ - fsTag: __rspack_external_fs[Symbol.toStringTag], - fsText: Object.prototype.toString.call(__rspack_external_fs), - pathTag: __rspack_external_path[Symbol.toStringTag], - pathText: Object.prototype.toString.call(__rspack_external_path), - basename: __rspack_external_path.basename("a/b.txt"), + fsTag: fsNs[Symbol.toStringTag], + fsText: Object.prototype.toString.call(fsNs), + pathTag: pathNs[Symbol.toStringTag], + pathText: Object.prototype.toString.call(pathNs), + basename: pathNs.basename("a/b.txt"), }); it("should preserve module toStringTag on external namespace imports", async () => { diff --git a/tests/rspack-test/esmOutputCases/externals/treeshake-namespace-access/__snapshots__/esm.snap.txt b/tests/rspack-test/esmOutputCases/externals/treeshake-namespace-access/__snapshots__/esm.snap.txt index 6d4a4f40c952..c311aad90aa3 100644 --- a/tests/rspack-test/esmOutputCases/externals/treeshake-namespace-access/__snapshots__/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/externals/treeshake-namespace-access/__snapshots__/esm.snap.txt @@ -1,11 +1,10 @@ ```mjs title=main.mjs -import * as __rspack_external_fs from "fs"; -// fs +import * as fsNs from "fs"; // ./index.js -const unused = __rspack_external_fs.readFile; +const unused = fsNs.readFile; /* export default */ const index = ("main"); diff --git a/tests/rspack-test/esmOutputCases/preserve-modules/module-external-remapping/__snapshots__/esm.snap.txt b/tests/rspack-test/esmOutputCases/preserve-modules/module-external-remapping/__snapshots__/esm.snap.txt index 38dd70911540..4339c2fc4557 100644 --- a/tests/rspack-test/esmOutputCases/preserve-modules/module-external-remapping/__snapshots__/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/preserve-modules/module-external-remapping/__snapshots__/esm.snap.txt @@ -1,5 +1,5 @@ ```mjs title=hoisted.mjs -import { once, EventEmitter } from "./node_events-node_events.mjs"; +import { EventEmitter, once } from "node:events"; // ./src/hoisted.js @@ -44,32 +44,6 @@ export {}; ``` -```mjs title=node_events-node_events.mjs -import { __webpack_require__ } from "./runtime.mjs"; - -import * as __rspack_external_node_events_3969b2b3 from "node:events"; -__webpack_require__.add({ -"node:events?df85" -/*!******************************!*\ - !*** external "node:events" ***! - \******************************/ -(module, __unused_rspack_exports, __webpack_require__) { -var __rspack_create_module_external_namespace_node_events_3969b2b3 = (y) => { -var x = {}; -__webpack_require__.d(x, y); -return x; -}; -var __rspack_wrap_module_external_namespace_node_events_3969b2b3 = (x) => (() => (x)); -module.exports = __rspack_create_module_external_namespace_node_events_3969b2b3({["a"]: () => (__rspack_external_node_events_3969b2b3.EventEmitter), ["b"]: () => (__rspack_external_node_events_3969b2b3.once)}); - -}, -}); -// node:events?41dc - -export { EventEmitter, once } from "node:events"; - -``` - ```mjs title=runtime.mjs var __webpack_modules__ = {}; @@ -140,15 +114,20 @@ export { __webpack_require__ }; ```mjs title=wrapped.mjs import { __webpack_require__ } from "./runtime.mjs"; -import "./node_events-node_events.mjs"; +import * as __rspack_external_node_events_3969b2b3 from "node:events"; __webpack_require__.add({ "./src/wrapped.js" /*!************************!*\ !*** ./src/wrapped.js ***! \************************/ (module, __webpack_exports__, __webpack_require__) { -/* import */ var node_events__rspack_import_0 = __webpack_require__(/*! node:events */ "node:events?df85"); +var __rspack_create_module_external_namespace_node_events_3969b2b3 = (y) => { +var x = {}; +__webpack_require__.d(x, y); +return x; +}; +var __rspack_wrap_module_external_namespace_node_events_3969b2b3 = (x) => (() => (x));var node_events__rspack_import_0 = __rspack_create_module_external_namespace_node_events_3969b2b3({["a"]: () => (__rspack_external_node_events_3969b2b3.EventEmitter), ["b"]: () => (__rspack_external_node_events_3969b2b3.once)}); /* module decorator */ module = __webpack_require__.hmd(module); diff --git a/tests/rspack-test/esmOutputCases/preserve-modules/module-external-remapping/__snapshots__/runtimeModeSnapshot/esm.snap.txt b/tests/rspack-test/esmOutputCases/preserve-modules/module-external-remapping/__snapshots__/runtimeModeSnapshot/esm.snap.txt index 4d3b55e4d020..60faa757f501 100644 --- a/tests/rspack-test/esmOutputCases/preserve-modules/module-external-remapping/__snapshots__/runtimeModeSnapshot/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/preserve-modules/module-external-remapping/__snapshots__/runtimeModeSnapshot/esm.snap.txt @@ -1,5 +1,5 @@ ```mjs title=hoisted.mjs -import { once, EventEmitter } from "./node_events-node_events.mjs"; +import { EventEmitter, once } from "node:events"; // ./src/hoisted.js @@ -44,31 +44,6 @@ export {}; ``` -```mjs title=node_events-node_events.mjs -import { rspackRequire, moduleFactories, definePropertyGetters } from "./runtime.mjs"; -import * as __rspack_external_node_events_3969b2b3 from "node:events"; -moduleFactories.add({ -"node:events?df85" -/*!******************************!*\ - !*** external "node:events" ***! - \******************************/ -(module) { -var __rspack_create_module_external_namespace_node_events_3969b2b3 = (y) => { -var x = {}; -definePropertyGetters(x, y); -return x; -}; -var __rspack_wrap_module_external_namespace_node_events_3969b2b3 = (x) => (() => (x)); -module.exports = __rspack_create_module_external_namespace_node_events_3969b2b3({["a"]: () => (__rspack_external_node_events_3969b2b3.EventEmitter), ["b"]: () => (__rspack_external_node_events_3969b2b3.once)}); - -}, -}); -// node:events?41dc - -export { EventEmitter, once } from "node:events"; - -``` - ```mjs title=runtime.mjs var modules = {}; @@ -134,15 +109,19 @@ var hasOwnProperty = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, p ```mjs title=wrapped.mjs import { rspackRequire, moduleFactories, definePropertyGetters, esmModuleDecorator } from "./runtime.mjs"; -import "./node_events-node_events.mjs"; - +import * as __rspack_external_node_events_3969b2b3 from "node:events"; moduleFactories.add({ "./src/wrapped.js" /*!************************!*\ !*** ./src/wrapped.js ***! \************************/ (module, exports) { -/* import */ var node_events__rspack_import_0 = rspackRequire(/*! node:events */ "node:events?df85"); +var __rspack_create_module_external_namespace_node_events_3969b2b3 = (y) => { +var x = {}; +definePropertyGetters(x, y); +return x; +}; +var __rspack_wrap_module_external_namespace_node_events_3969b2b3 = (x) => (() => (x));var node_events__rspack_import_0 = __rspack_create_module_external_namespace_node_events_3969b2b3({["a"]: () => (__rspack_external_node_events_3969b2b3.EventEmitter), ["b"]: () => (__rspack_external_node_events_3969b2b3.once)}); /* module decorator */ module = esmModuleDecorator(module); diff --git a/tests/rspack-test/esmOutputCases/preserve-modules/re-export-module-external-hoist-mix/__snapshots__/esm.snap.txt b/tests/rspack-test/esmOutputCases/preserve-modules/re-export-module-external-hoist-mix/__snapshots__/esm.snap.txt index 617b87f34906..fbd85af85e3c 100644 --- a/tests/rspack-test/esmOutputCases/preserve-modules/re-export-module-external-hoist-mix/__snapshots__/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/preserve-modules/re-export-module-external-hoist-mix/__snapshots__/esm.snap.txt @@ -1,39 +1,15 @@ -```mjs title=fs-fs.mjs -import { __webpack_require__ } from "./runtime.mjs"; - -import * as __rspack_external_fs from "fs"; -__webpack_require__.add({ -"fs?2159" -/*!*********************!*\ - !*** external "fs" ***! - \*********************/ -(module) { - -module.exports = __rspack_external_fs; - - -}, -}); -// fs?82ef - -export { readFile as readFileHoisted, readFileSync as readFileSyncHoisted } from "fs"; - -``` - ```mjs title=hoisted.mjs - // ./src/hoisted.js -export { readFileHoisted, readFileSyncHoisted } from "./fs-fs.mjs"; +export { readFile as readFileHoisted, readFileSync as readFileSyncHoisted } from "fs"; ``` ```mjs title=index.mjs import { __webpack_require__ } from "./runtime.mjs"; import "./wrapped.mjs"; -import "./hoisted.mjs"; -import { readFileSyncHoisted as readFileSync, readFileHoisted as readFile } from "./fs-fs.mjs"; +import { readFileSyncHoisted as readFileSync, readFileHoisted as readFile } from "./hoisted.mjs"; // ./src/index.js const wrapped_0 = __webpack_require__("./src/wrapped.js"); @@ -131,15 +107,15 @@ export { __webpack_require__ }; ```mjs title=wrapped.mjs import { __webpack_require__ } from "./runtime.mjs"; -import "./fs-fs.mjs"; +import * as __rspack_external_fs from "fs"; __webpack_require__.add({ "./src/wrapped.js" /*!************************!*\ !*** ./src/wrapped.js ***! \************************/ (module, __webpack_exports__, __webpack_require__) { -/* import */ var fs__rspack_import_0 = __webpack_require__(/*! fs */ "fs?2159"); +var fs__rspack_import_0 = __rspack_external_fs; /* module decorator */ module = __webpack_require__.hmd(module); diff --git a/tests/rspack-test/esmOutputCases/preserve-modules/re-export-module-external-hoist-mix/__snapshots__/runtimeModeSnapshot/esm.snap.txt b/tests/rspack-test/esmOutputCases/preserve-modules/re-export-module-external-hoist-mix/__snapshots__/runtimeModeSnapshot/esm.snap.txt index 57822b7aef9f..ec518ef19cf0 100644 --- a/tests/rspack-test/esmOutputCases/preserve-modules/re-export-module-external-hoist-mix/__snapshots__/runtimeModeSnapshot/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/preserve-modules/re-export-module-external-hoist-mix/__snapshots__/runtimeModeSnapshot/esm.snap.txt @@ -1,38 +1,15 @@ -```mjs title=fs-fs.mjs -import { rspackRequire, moduleFactories } from "./runtime.mjs"; -import * as __rspack_external_fs from "fs"; -moduleFactories.add({ -"fs?2159" -/*!*********************!*\ - !*** external "fs" ***! - \*********************/ -(module) { - -module.exports = __rspack_external_fs; - - -}, -}); -// fs?82ef - -export { readFile as readFileHoisted, readFileSync as readFileSyncHoisted } from "fs"; - -``` - ```mjs title=hoisted.mjs - // ./src/hoisted.js -export { readFileHoisted, readFileSyncHoisted } from "./fs-fs.mjs"; +export { readFile as readFileHoisted, readFileSync as readFileSyncHoisted } from "fs"; ``` ```mjs title=index.mjs import { rspackRequire } from "./runtime.mjs"; import "./wrapped.mjs"; -import "./hoisted.mjs"; -import { readFileSyncHoisted as readFileSync, readFileHoisted as readFile } from "./fs-fs.mjs"; +import { readFileSyncHoisted as readFileSync, readFileHoisted as readFile } from "./hoisted.mjs"; // ./src/index.js const wrapped_0 = rspackRequire("./src/wrapped.js"); @@ -125,15 +102,14 @@ var hasOwnProperty = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, p ```mjs title=wrapped.mjs import { rspackRequire, moduleFactories, definePropertyGetters, esmModuleDecorator } from "./runtime.mjs"; -import "./fs-fs.mjs"; - +import * as __rspack_external_fs from "fs"; moduleFactories.add({ "./src/wrapped.js" /*!************************!*\ !*** ./src/wrapped.js ***! \************************/ (module, exports) { -/* import */ var fs__rspack_import_0 = rspackRequire(/*! fs */ "fs?2159"); +var fs__rspack_import_0 = __rspack_external_fs; /* module decorator */ module = esmModuleDecorator(module); diff --git a/tests/rspack-test/esmOutputCases/re-exports/deep-re-export-external/__snapshots__/esm.snap.txt b/tests/rspack-test/esmOutputCases/re-exports/deep-re-export-external/__snapshots__/esm.snap.txt index a4b9c30ecbfc..013716766459 100644 --- a/tests/rspack-test/esmOutputCases/re-exports/deep-re-export-external/__snapshots__/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/re-exports/deep-re-export-external/__snapshots__/esm.snap.txt @@ -1,14 +1,14 @@ ```mjs title=main.mjs import { __webpack_require__ } from "./runtime.mjs"; -import * as __rspack_external_fs from "fs"; +import * as external from "fs"; // NAMESPACE OBJECT: ./externals.js var externals_namespaceObject = {}; __webpack_require__.r(externals_namespaceObject); __webpack_require__.d(externals_namespaceObject, { - "default": () => (__rspack_external_fs["default"]), - readFile: () => (__rspack_external_fs.readFile) }); -var externals_namespaceObject_starExports = __rspack_external_fs; + "default": () => (fs), + readFile: () => (externals_readFile) }); +var externals_namespaceObject_starExports = external; Object.keys(externals_namespaceObject_starExports).forEach(function(key) { if (key !== "default" && key !== "__esModule") { __webpack_require__.d(externals_namespaceObject, { [key]: function() { return externals_namespaceObject_starExports[key]; } }); @@ -16,8 +16,6 @@ Object.keys(externals_namespaceObject_starExports).forEach(function(key) { }); -// fs - // ./externals.js @@ -37,12 +35,9 @@ it('should have exports', async () => { expect(externalsNs).toBeDefined(); }); -var default_0 = __rspack_external_fs["default"]; -var externals_0 = __rspack_external_fs["default"]; -var readFile_0 = __rspack_external_fs.readFile; -export { externals_0 as externals, externals_namespaceObject as externalsNs, readFile_0 as readFile }; +export { externals_namespaceObject as externalsNs }; export * from "fs"; -export default default_0; +export { default, default as externals, readFile } from "fs"; ``` diff --git a/tests/rspack-test/esmOutputCases/re-exports/deep-re-export-external/__snapshots__/runtimeModeSnapshot/esm.snap.txt b/tests/rspack-test/esmOutputCases/re-exports/deep-re-export-external/__snapshots__/runtimeModeSnapshot/esm.snap.txt index e40fe46099ca..0d002e3fd49c 100644 --- a/tests/rspack-test/esmOutputCases/re-exports/deep-re-export-external/__snapshots__/runtimeModeSnapshot/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/re-exports/deep-re-export-external/__snapshots__/runtimeModeSnapshot/esm.snap.txt @@ -1,14 +1,14 @@ ```mjs title=main.mjs import { rspackRequire, definePropertyGetters, makeNamespaceObject } from "./runtime.mjs"; -import * as __rspack_external_fs from "fs"; +import * as external from "fs"; // NAMESPACE OBJECT: ./externals.js var externals_namespaceObject = {}; makeNamespaceObject(externals_namespaceObject); definePropertyGetters(externals_namespaceObject, { - "default": () => (__rspack_external_fs["default"]), - readFile: () => (__rspack_external_fs.readFile) }); -var externals_namespaceObject_starExports = __rspack_external_fs; + "default": () => (fs), + readFile: () => (externals_readFile) }); +var externals_namespaceObject_starExports = external; Object.keys(externals_namespaceObject_starExports).forEach(function(key) { if (key !== "default" && key !== "__esModule") { definePropertyGetters(externals_namespaceObject, { [key]: function() { return externals_namespaceObject_starExports[key]; } }); @@ -16,8 +16,6 @@ Object.keys(externals_namespaceObject_starExports).forEach(function(key) { }); -// fs - // ./externals.js @@ -37,12 +35,9 @@ it('should have exports', async () => { expect(externalsNs).toBeDefined(); }); -var default_0 = __rspack_external_fs["default"]; -var externals_0 = __rspack_external_fs["default"]; -var readFile_0 = __rspack_external_fs.readFile; -export { externals_0 as externals, externals_namespaceObject as externalsNs, readFile_0 as readFile }; +export { externals_namespaceObject as externalsNs }; export * from "fs"; -export default default_0; +export { default, default as externals, readFile } from "fs"; ``` diff --git a/tests/rspack-test/esmOutputCases/re-exports/deep-re-exports-esm-2/__snapshots__/esm.snap.txt b/tests/rspack-test/esmOutputCases/re-exports/deep-re-exports-esm-2/__snapshots__/esm.snap.txt index 50e9015f824b..ec9fe02a92c6 100644 --- a/tests/rspack-test/esmOutputCases/re-exports/deep-re-exports-esm-2/__snapshots__/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/re-exports/deep-re-exports-esm-2/__snapshots__/esm.snap.txt @@ -10,7 +10,7 @@ __webpack_require__.add({ \****************/ (__unused_rspack_module, __webpack_exports__, __webpack_require__) { __webpack_require__.r(__webpack_exports__); -/* import */ var fs__rspack_import_0 = __webpack_require__(/*! fs */ "fs"); +var fs__rspack_import_0 = __rspack_external_fs; /* reexport */ var __rspack_reexport = {}; /* reexport */ for( const __rspack_import_key in fs__rspack_import_0) if(["default","lib"].indexOf(__rspack_import_key) < 0) __rspack_reexport[__rspack_import_key] =() => fs__rspack_import_0[__rspack_import_key] @@ -39,7 +39,7 @@ __webpack_require__.d(__webpack_exports__, { \*****************/ (__unused_rspack_module, __webpack_exports__, __webpack_require__) { __webpack_require__.r(__webpack_exports__); -/* import */ var path__rspack_import_0 = __webpack_require__(/*! path */ "path"); +var path__rspack_import_0 = __rspack_external_path; /* reexport */ var __rspack_reexport = {}; /* reexport */ for( const __rspack_import_key in path__rspack_import_0) if(["default","lib2"].indexOf(__rspack_import_key) < 0) __rspack_reexport[__rspack_import_key] =() => path__rspack_import_0[__rspack_import_key] @@ -66,7 +66,7 @@ __webpack_require__.d(__webpack_exports__, { !*** ./lib3.js ***! \*****************/ (__unused_rspack_module, __webpack_exports__, __webpack_require__) { -/* import */ var fs__rspack_import_0 = __webpack_require__(/*! fs */ "fs"); +var fs__rspack_import_0 = __rspack_external_fs; const lib3 = 42 const lib_local = 24 @@ -79,26 +79,6 @@ __webpack_require__.d(__webpack_exports__, { }); -}, -"fs" -/*!*********************!*\ - !*** external "fs" ***! - \*********************/ -(module) { - -module.exports = __rspack_external_fs; - - -}, -"path" -/*!***********************!*\ - !*** external "path" ***! - \***********************/ -(module) { - -module.exports = __rspack_external_path; - - }, }); // ./index.js diff --git a/tests/rspack-test/esmOutputCases/re-exports/deep-re-exports-esm-2/__snapshots__/runtimeModeSnapshot/esm.snap.txt b/tests/rspack-test/esmOutputCases/re-exports/deep-re-exports-esm-2/__snapshots__/runtimeModeSnapshot/esm.snap.txt index a72cdeec36a2..12f960b83ad9 100644 --- a/tests/rspack-test/esmOutputCases/re-exports/deep-re-exports-esm-2/__snapshots__/runtimeModeSnapshot/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/re-exports/deep-re-exports-esm-2/__snapshots__/runtimeModeSnapshot/esm.snap.txt @@ -9,7 +9,7 @@ moduleFactories.add({ \****************/ (__unused_rspack_module, exports) { makeNamespaceObject(exports); -/* import */ var fs__rspack_import_0 = rspackRequire(/*! fs */ "fs"); +var fs__rspack_import_0 = __rspack_external_fs; /* reexport */ var __rspack_reexport = {}; /* reexport */ for( const __rspack_import_key in fs__rspack_import_0) if(["default","lib"].indexOf(__rspack_import_key) < 0) __rspack_reexport[__rspack_import_key] =() => fs__rspack_import_0[__rspack_import_key] @@ -38,7 +38,7 @@ definePropertyGetters(exports, { \*****************/ (__unused_rspack_module, exports) { makeNamespaceObject(exports); -/* import */ var path__rspack_import_0 = rspackRequire(/*! path */ "path"); +var path__rspack_import_0 = __rspack_external_path; /* reexport */ var __rspack_reexport = {}; /* reexport */ for( const __rspack_import_key in path__rspack_import_0) if(["default","lib2"].indexOf(__rspack_import_key) < 0) __rspack_reexport[__rspack_import_key] =() => path__rspack_import_0[__rspack_import_key] @@ -65,7 +65,7 @@ definePropertyGetters(exports, { !*** ./lib3.js ***! \*****************/ (__unused_rspack_module, exports) { -/* import */ var fs__rspack_import_0 = rspackRequire(/*! fs */ "fs"); +var fs__rspack_import_0 = __rspack_external_fs; const lib3 = 42 const lib_local = 24 @@ -78,26 +78,6 @@ definePropertyGetters(exports, { }); -}, -"fs" -/*!*********************!*\ - !*** external "fs" ***! - \*********************/ -(module) { - -module.exports = __rspack_external_fs; - - -}, -"path" -/*!***********************!*\ - !*** external "path" ***! - \***********************/ -(module) { - -module.exports = __rspack_external_path; - - }, }); // ./index.js diff --git a/tests/rspack-test/esmOutputCases/re-exports/deep-re-exports-esm-3/__snapshots__/esm.snap.txt b/tests/rspack-test/esmOutputCases/re-exports/deep-re-exports-esm-3/__snapshots__/esm.snap.txt index b36828ce84e5..7013f7a06bec 100644 --- a/tests/rspack-test/esmOutputCases/re-exports/deep-re-exports-esm-3/__snapshots__/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/re-exports/deep-re-exports-esm-3/__snapshots__/esm.snap.txt @@ -2,12 +2,6 @@ import * as __rspack_external_fs from "fs"; import * as __rspack_external_path from "path"; -// fs?f137 - -// path - -// fs?c303 - // ./lib3.js const lib3_lib3 = 42 diff --git a/tests/rspack-test/esmOutputCases/re-exports/deep-re-exports-esm-4/__snapshots__/esm.snap.txt b/tests/rspack-test/esmOutputCases/re-exports/deep-re-exports-esm-4/__snapshots__/esm.snap.txt index b36828ce84e5..7013f7a06bec 100644 --- a/tests/rspack-test/esmOutputCases/re-exports/deep-re-exports-esm-4/__snapshots__/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/re-exports/deep-re-exports-esm-4/__snapshots__/esm.snap.txt @@ -2,12 +2,6 @@ import * as __rspack_external_fs from "fs"; import * as __rspack_external_path from "path"; -// fs?f137 - -// path - -// fs?c303 - // ./lib3.js const lib3_lib3 = 42 diff --git a/tests/rspack-test/esmOutputCases/re-exports/deep-re-exports-wrapped/__snapshots__/esm.snap.txt b/tests/rspack-test/esmOutputCases/re-exports/deep-re-exports-wrapped/__snapshots__/esm.snap.txt index 6e912396244e..eb5a46d2219b 100644 --- a/tests/rspack-test/esmOutputCases/re-exports/deep-re-exports-wrapped/__snapshots__/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/re-exports/deep-re-exports-wrapped/__snapshots__/esm.snap.txt @@ -1,15 +1,10 @@ ```mjs title=main.mjs -import * as __rspack_external_fs from "fs"; import * as __rspack_external_path from "path"; -// fs - // ./lib3.js const v = 42 -// path - // ./lib2.js diff --git a/tests/rspack-test/esmOutputCases/re-exports/default-namespace-external/__snapshots__/esm.snap.txt b/tests/rspack-test/esmOutputCases/re-exports/default-namespace-external/__snapshots__/esm.snap.txt index 0344b866e7c9..d9bdb32eaf89 100644 --- a/tests/rspack-test/esmOutputCases/re-exports/default-namespace-external/__snapshots__/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/re-exports/default-namespace-external/__snapshots__/esm.snap.txt @@ -10,15 +10,11 @@ __webpack_require__.d(file_namespaceObject, { value: () => (value) }); -// fs?42cb - // ./sharding.js const value = fs; -// fs?5257 - // ./file.js diff --git a/tests/rspack-test/esmOutputCases/re-exports/default-namespace-external/__snapshots__/runtimeModeSnapshot/esm.snap.txt b/tests/rspack-test/esmOutputCases/re-exports/default-namespace-external/__snapshots__/runtimeModeSnapshot/esm.snap.txt index be53a770410b..9579881a2d53 100644 --- a/tests/rspack-test/esmOutputCases/re-exports/default-namespace-external/__snapshots__/runtimeModeSnapshot/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/re-exports/default-namespace-external/__snapshots__/runtimeModeSnapshot/esm.snap.txt @@ -10,15 +10,11 @@ definePropertyGetters(file_namespaceObject, { value: () => (value) }); -// fs?42cb - // ./sharding.js const value = fs; -// fs?5257 - // ./file.js diff --git a/tests/rspack-test/esmOutputCases/re-exports/default-re-export-external/__snapshots__/esm.snap.txt b/tests/rspack-test/esmOutputCases/re-exports/default-re-export-external/__snapshots__/esm.snap.txt index df6c42329ead..d2d6566349a1 100644 --- a/tests/rspack-test/esmOutputCases/re-exports/default-re-export-external/__snapshots__/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/re-exports/default-re-export-external/__snapshots__/esm.snap.txt @@ -10,15 +10,11 @@ __webpack_require__.d(file_namespaceObject, { value: () => (value) }); -// fs?42cb - // ./sharding.js const value = fs; -// fs?5257 - // ./file.js diff --git a/tests/rspack-test/esmOutputCases/re-exports/default-re-export-external/__snapshots__/runtimeModeSnapshot/esm.snap.txt b/tests/rspack-test/esmOutputCases/re-exports/default-re-export-external/__snapshots__/runtimeModeSnapshot/esm.snap.txt index ac5c48d017c5..703c91895a36 100644 --- a/tests/rspack-test/esmOutputCases/re-exports/default-re-export-external/__snapshots__/runtimeModeSnapshot/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/re-exports/default-re-export-external/__snapshots__/runtimeModeSnapshot/esm.snap.txt @@ -10,15 +10,11 @@ definePropertyGetters(file_namespaceObject, { value: () => (value) }); -// fs?42cb - // ./sharding.js const value = fs; -// fs?5257 - // ./file.js diff --git a/tests/rspack-test/esmOutputCases/re-exports/move-entry/__snapshots__/esm.snap.txt b/tests/rspack-test/esmOutputCases/re-exports/move-entry/__snapshots__/esm.snap.txt index bf460aa2d71d..fd067339ad9b 100644 --- a/tests/rspack-test/esmOutputCases/re-exports/move-entry/__snapshots__/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/re-exports/move-entry/__snapshots__/esm.snap.txt @@ -13,9 +13,7 @@ export { a, b } from "./proxy-main.mjs"; ``` ```mjs title=proxy-main.mjs -import * as __rspack_external_fs from "fs"; - -// fs +import "fs"; // ./lib.js // side effect diff --git a/tests/rspack-test/esmOutputCases/re-exports/re-export-external/__snapshots__/esm.snap.txt b/tests/rspack-test/esmOutputCases/re-exports/re-export-external/__snapshots__/esm.snap.txt index 8c7fe47a1e53..9f69bafacd58 100644 --- a/tests/rspack-test/esmOutputCases/re-exports/re-export-external/__snapshots__/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/re-exports/re-export-external/__snapshots__/esm.snap.txt @@ -1,8 +1,4 @@ ```mjs title=main.mjs -import * as __rspack_external_fs from "fs"; - -// fs - // ./index.js @@ -25,12 +21,10 @@ it('should compile and import success', async () => { expect(readFile).toBeDefined() }) -var fs_0 = __rspack_external_fs["default"]; var index_named = (/* inlined export .named */42); -var r_0 = __rspack_external_fs.readFile; -var readFile_0 = __rspack_external_fs.readFile; var index_starExports = (/* inlined export .starExports */42); -export { fs_0 as fs, index_named as named, index_starExports as starExports, r_0 as r, readFile_0 as readFile }; +export { index_named as named, index_starExports as starExports }; export * from "fs"; +export { default as fs, readFile as r, readFile } from "fs"; ``` \ No newline at end of file diff --git a/tests/rspack-test/esmOutputCases/re-exports/re-export-namespaced-external/__snapshots__/esm.snap.txt b/tests/rspack-test/esmOutputCases/re-exports/re-export-namespaced-external/__snapshots__/esm.snap.txt index 87c91f94b712..37658fbd6b50 100644 --- a/tests/rspack-test/esmOutputCases/re-exports/re-export-namespaced-external/__snapshots__/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/re-exports/re-export-namespaced-external/__snapshots__/esm.snap.txt @@ -1,7 +1,6 @@ ```mjs title=main.mjs -import * as __rspack_external_fs from "fs"; - -// fs +import fs_0, * as __rspack_external_fs from "fs"; +import { readFile as index_readFile } from "fs"; // ./index.js @@ -37,14 +36,10 @@ it('should compile and import success', async () => { expect(readFile).toBeDefined() }) -var default_0 = __rspack_external_fs["default"]; -var fs_0 = __rspack_external_fs["default"]; var index_named = (/* inlined export .named */42); -var r_0 = __rspack_external_fs.readFile; -var readFile_0 = __rspack_external_fs.readFile; var index_starExports = (/* inlined export .starExports */42); -export { __rspack_external_fs as fsNs, fs_0 as fs, index_named as named, index_starExports as starExports, r_0 as r, readFile_0 as readFile }; +export { __rspack_external_fs as fsNs, fs_0 as fs, index_named as named, index_readFile as r, index_readFile as readFile, index_starExports as starExports }; export * from "fs"; -export default default_0; +export default fs_0; ``` \ No newline at end of file diff --git a/tests/rspack-test/esmOutputCases/re-exports/wrapped-esm-entry/__snapshots__/esm.snap.txt b/tests/rspack-test/esmOutputCases/re-exports/wrapped-esm-entry/__snapshots__/esm.snap.txt index bd259b995d67..00a544b4fe1b 100644 --- a/tests/rspack-test/esmOutputCases/re-exports/wrapped-esm-entry/__snapshots__/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/re-exports/wrapped-esm-entry/__snapshots__/esm.snap.txt @@ -9,7 +9,7 @@ __webpack_require__.add({ \******************/ (module, __webpack_exports__, __webpack_require__) { __webpack_require__.r(__webpack_exports__); -/* import */ var fs__rspack_import_0 = __webpack_require__(/*! fs */ "fs"); +var fs__rspack_import_0 = __rspack_external_fs; /* reexport */ var __rspack_reexport = {}; /* reexport */ for( const __rspack_import_key in fs__rspack_import_0) if(["r","named","default","fs","starExports","readFile"].indexOf(__rspack_import_key) < 0) __rspack_reexport[__rspack_import_key] =() => fs__rspack_import_0[__rspack_import_key] @@ -47,16 +47,6 @@ __webpack_require__.d(__webpack_exports__, { }); -}, -"fs" -/*!*********************!*\ - !*** external "fs" ***! - \*********************/ -(module) { - -module.exports = __rspack_external_fs; - - }, }); const index = __webpack_require__("./index.js"); diff --git a/tests/rspack-test/esmOutputCases/re-exports/wrapped-esm-entry/__snapshots__/runtimeModeSnapshot/esm.snap.txt b/tests/rspack-test/esmOutputCases/re-exports/wrapped-esm-entry/__snapshots__/runtimeModeSnapshot/esm.snap.txt index 00500775a4d0..f0549ecb0405 100644 --- a/tests/rspack-test/esmOutputCases/re-exports/wrapped-esm-entry/__snapshots__/runtimeModeSnapshot/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/re-exports/wrapped-esm-entry/__snapshots__/runtimeModeSnapshot/esm.snap.txt @@ -8,7 +8,7 @@ moduleFactories.add({ \******************/ (module, exports) { makeNamespaceObject(exports); -/* import */ var fs__rspack_import_0 = rspackRequire(/*! fs */ "fs"); +var fs__rspack_import_0 = __rspack_external_fs; /* reexport */ var __rspack_reexport = {}; /* reexport */ for( const __rspack_import_key in fs__rspack_import_0) if(["r","named","default","fs","starExports","readFile"].indexOf(__rspack_import_key) < 0) __rspack_reexport[__rspack_import_key] =() => fs__rspack_import_0[__rspack_import_key] @@ -46,16 +46,6 @@ definePropertyGetters(exports, { }); -}, -"fs" -/*!*********************!*\ - !*** external "fs" ***! - \*********************/ -(module) { - -module.exports = __rspack_external_fs; - - }, }); const index = rspackRequire("./index.js"); diff --git a/tests/rspack-test/esmOutputCases/split-chunks/re-export-external-cross-chunk/__snapshots__/esm.snap.txt b/tests/rspack-test/esmOutputCases/split-chunks/re-export-external-cross-chunk/__snapshots__/esm.snap.txt index 06038dc837c8..14ca8e868611 100644 --- a/tests/rspack-test/esmOutputCases/split-chunks/re-export-external-cross-chunk/__snapshots__/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/split-chunks/re-export-external-cross-chunk/__snapshots__/esm.snap.txt @@ -16,10 +16,6 @@ export { join, readFile } from "./wrapper-chunk.mjs"; ``` ```mjs title=wrapper-chunk.mjs -// fs - -// path - // ./wrapper.js From f46b21b10b6b400dcad87c748509d0c4498a1846 Mon Sep 17 00:00:00 2001 From: Fy <1114550440@qq.com> Date: Tue, 15 Sep 2026 14:39:55 +0800 Subject: [PATCH 09/13] fix(esm-library): restore issuer-scoped module externals --- .../rspack_plugin_esm_library/src/plugin.rs | 138 ++++++++++++++++-- 1 file changed, 123 insertions(+), 15 deletions(-) diff --git a/crates/rspack_plugin_esm_library/src/plugin.rs b/crates/rspack_plugin_esm_library/src/plugin.rs index 3edc3de45b89..46f00f84bab3 100644 --- a/crates/rspack_plugin_esm_library/src/plugin.rs +++ b/crates/rspack_plugin_esm_library/src/plugin.rs @@ -5,20 +5,20 @@ use std::{ use atomic_refcell::AtomicRefCell; use regex::Regex; -use rspack_collections::{Identifiable, IdentifierIndexMap, IdentifierMap, IdentifierSet}; +use rspack_collections::{Identifiable, Identifier, IdentifierIndexMap, IdentifierMap, IdentifierSet}; use rspack_core::{ ApplyContext, AssetInfo, AsyncModulesArtifact, BoxModule, BuildModuleGraphArtifact, ChunkUkey, Compilation, CompilationAdditionalChunkRuntimeRequirements, CompilationAdditionalModuleRuntimeRequirements, CompilationAdditionalTreeRuntimeRequirements, CompilationAfterCodeGeneration, CompilationConcatenationScope, CompilationFinishModules, - CompilationOptimizeChunks, CompilationOptimizeDependencies, CompilationParams, - CompilationProcessAssets, CompilationRuntimeRequirementInTree, CompilerCompilation, - ConcatenatedModuleInfo, ConcatenationScope, DependencyType, ExportsInfoArtifact, - ExternalModuleInfo, GetTargetResult, JavascriptParserUrl, Logger, ModuleFactoryCreateData, - ModuleGraph, ModuleIdentifier, ModuleInfo, ModuleType, NormalModuleFactoryAfterFactorize, - NormalModuleFactoryParser, ParserAndGenerator, ParserOptions, Plugin, REQUIRE_SCOPE_GLOBALS, - RuntimeCodeTemplate, RuntimeGlobals, RuntimeModule, SideEffectsOptimizeArtifact, - SideEffectsStateArtifact, get_target, is_esm_dep_like, + CompilationOptimizeChunkModules, CompilationOptimizeChunks, CompilationOptimizeDependencies, + CompilationParams, CompilationProcessAssets, CompilationRuntimeRequirementInTree, + CompilerCompilation, ConcatenatedModuleInfo, ConcatenationScope, DependencyType, + ExportsInfoArtifact, ExternalModuleInfo, GetTargetResult, JavascriptParserUrl, Logger, + ModuleFactoryCreateData, ModuleGraph, ModuleIdentifier, ModuleInfo, ModuleType, + NormalModuleFactoryAfterFactorize, NormalModuleFactoryParser, ParserAndGenerator, ParserOptions, + Plugin, REQUIRE_SCOPE_GLOBALS, RuntimeCodeTemplate, RuntimeGlobals, RuntimeModule, + SideEffectsOptimizeArtifact, SideEffectsStateArtifact, get_target, is_esm_dep_like, rspack_sources::{ReplaceSource, Source}, }; use rspack_error::{Diagnostic, Result}; @@ -54,7 +54,6 @@ use crate::{ dyn_import::DynamicImportDependencyTemplate, esm_external::{ DirectEsmExternalDependencies, DirectEsmExternalDependencyTemplate, cutout_esm_externals, - requires_issuer_identity, }, }, esm_lib_parser_plugin::EsmLibParserPlugin, @@ -736,16 +735,120 @@ async fn after_factorize( data: &mut ModuleFactoryCreateData, module: &mut BoxModule, ) -> Result<()> { - if let Some(external) = module.as_external_module_mut() - && external.resolve_external_type() == "module" - && requires_issuer_identity(external) - && let Some(issuer) = &data.issuer_identifier + // Check if this is an external module using the existing downcast helper + if let Some(external_module) = module.as_external_module_mut() + && external_module.resolve_external_type() == "module" + && (external_module.get_external_type() != "modern-module" + || data + .dependencies + .first() + .is_some_and(|dependency| is_esm_dep_like(dependency.as_ref()))) { - external.set_id(format!("{}|{issuer}", external.identifier()).into()); + // If there's an issuer, append it to the module id + if let Some(issuer_identifier) = &data.issuer_identifier { + let current_id = external_module.identifier(); + let new_id = Identifier::from(format!("{current_id}|{issuer_identifier}")); + external_module.set_id(new_id); + } } Ok(()) } +#[plugin_hook(CompilationOptimizeChunkModules for EsmLibraryPlugin, stage = 100)] +async fn optimize_chunk_modules(&self, compilation: &mut Compilation) -> Result> { + // Group duplicate external modules by (base_id, chunk) so we only merge + // duplicates within the same chunk. Merging across chunks would cause a + // module to appear in multiple chunks, which violates get_module_chunk's + // single-chunk assumption. + let mut groups: FxHashMap<(String, ChunkUkey), Vec> = FxHashMap::default(); + let mg = compilation.get_module_graph(); + let cg = &compilation.build_chunk_graph_artifact.chunk_graph; + + let modules_map = self.concatenated_modules_map.read().await; + + for (id, module) in mg.modules() { + if module.as_external_module().is_some() { + let id_str = id.as_str(); + if modules_map[id].is_external() + && let Some(pipe_pos) = id_str.rfind('|') + && let Some(chunks) = cg.try_get_module_chunks(id) + && !chunks.is_empty() + { + let base = id_str[..pipe_pos].to_string(); + for &chunk in chunks { + groups.entry((base.clone(), chunk)).or_default().push(*id); + } + } + } + } + + // Phase 2: Merge duplicates within the same chunk + for mut module_ids in groups.into_values() { + module_ids.sort_unstable(); + module_ids.dedup(); + if module_ids.len() <= 1 { + continue; + } + + let canonical_id = module_ids[0]; + + let mut used_exports = FxHashSet::default(); + let mut used_in_unknown = false; + + for dup_id in &module_ids[1..] { + let dup_id_used = compilation + .exports_info_artifact + .get_exports_info_data(dup_id); + if !matches!( + dup_id_used.other_exports_info().get_used(None), + rspack_core::UsageState::Unused + ) { + used_in_unknown = true; + break; + } else { + let used = dup_id_used.exports().iter().filter_map(|(name, export)| { + if matches!(export.get_used(None), rspack_core::UsageState::Used) { + Some(name.clone()) + } else { + None + } + }); + + used_exports.extend(used); + } + } + + if used_in_unknown { + // used in unknown way, we should make canonical_id the same used in unknown way + let exports_info = compilation + .exports_info_artifact + .get_exports_info_data_mut(&canonical_id); + exports_info.set_used_in_unknown_way(None); + } else { + for name in used_exports { + let exports_info = compilation + .exports_info_artifact + .get_exports_info_data_mut(&canonical_id); + + let info = exports_info.ensure_export_info(&name); + let info = info.as_data_mut(&mut compilation.exports_info_artifact); + info.set_used(rspack_core::UsageState::Used, None); + } + } + + for &dup_id in &module_ids[1..] { + let cg = &mut compilation.build_chunk_graph_artifact.chunk_graph; + cg.replace_module(&dup_id, &canonical_id); + + // 1. Move incoming connections from duplicate to canonical + let mg = compilation.get_module_graph_mut(); + mg.move_module_connections(&dup_id, &canonical_id, |_, _| true); + } + } + + Ok(None) +} + // Cut out placement edges only after dependency optimizers have settled. #[plugin_hook(CompilationOptimizeDependencies for EsmLibraryPlugin, stage = i32::MAX)] async fn optimize_dependencies( @@ -845,6 +948,11 @@ impl Plugin for EsmLibraryPlugin { .optimize_chunks .tap(optimize_runtime_chunk_hook::new(self)); + ctx + .compilation_hooks + .optimize_chunk_modules + .tap(optimize_chunk_modules::new(self)); + ctx.normal_module_factory_hooks.parser.tap(parse::new(self)); ctx .normal_module_factory_hooks From efd672ed3937bfc345a49b163e04382a54a8bf2f Mon Sep 17 00:00:00 2001 From: Fy <1114550440@qq.com> Date: Tue, 15 Sep 2026 17:21:33 +0800 Subject: [PATCH 10/13] fix(esm-library): address CI compatibility and code size --- crates/rspack_core/src/external_module.rs | 43 ++++++++++--------- .../src/utils/concatenation_scope.rs | 18 ++++++-- .../rspack_plugin_esm_library/src/plugin.rs | 4 +- 3 files changed, 40 insertions(+), 25 deletions(-) diff --git a/crates/rspack_core/src/external_module.rs b/crates/rspack_core/src/external_module.rs index 9aa4d1ee85dd..09b1672bb15c 100644 --- a/crates/rspack_core/src/external_module.rs +++ b/crates/rspack_core/src/external_module.rs @@ -787,8 +787,28 @@ impl ExternalModule { let mut chunk_init_fragments: ChunkInitFragments = Default::default(); let supports_const = compilation.options.output.environment.supports_const(); let resolved_external_type = self.resolve_external_type(); - let commonjs_require_kind = - CommonJsExternalRequireKind::from_external_type(resolved_external_type); + if let Some(require_kind) = + CommonJsExternalRequireKind::from_external_type(resolved_external_type) + { + // For a missing object-form request, only ESM node-commonjs uses the + // undefined value; other CommonJS types request the name "undefined". + let fallback = (require_kind != CommonJsExternalRequireKind::NodeCommonJs + || !compilation.options.output.module) + .then_some("undefined"); + let require_expression = require_kind.render_expression( + request.map(ExternalRequestValue::primary).or(fallback), + request + .into_iter() + .flat_map(|request| request.iter().skip(1)), + compilation, + &mut chunk_init_fragments, + ); + let source = format!( + "{} = {require_expression};", + get_namespace_object_export(concatenation_scope, supports_const, runtime_template) + ); + return Ok((RawStringSource::from(source).boxed(), chunk_init_fragments)); + } let module_graph = compilation.get_module_graph(); let module_graph_cache = &compilation.module_graph_cache_artifact; @@ -808,25 +828,6 @@ impl ExternalModule { get_namespace_object_export(concatenation_scope, supports_const, runtime_template), get_source_for_global_variable_external(request, &compilation.options.output.global_object) ), - _ if let Some(require_kind) = commonjs_require_kind => { - // For a missing object-form request, only ESM node-commonjs uses the - // undefined value; other CommonJS types request the name "undefined". - let fallback = (require_kind != CommonJsExternalRequireKind::NodeCommonJs - || !compilation.options.output.module) - .then_some("undefined"); - let require_expression = require_kind.render_expression( - request.map(ExternalRequestValue::primary).or(fallback), - request - .into_iter() - .flat_map(|request| request.iter().skip(1)), - compilation, - &mut chunk_init_fragments, - ); - format!( - "{} = {require_expression};", - get_namespace_object_export(concatenation_scope, supports_const, runtime_template) - ) - } "amd" | "amd-require" | "umd" | "umd2" | "system" | "jsonp" => { let id = ChunkGraph::get_module_id(&compilation.module_ids_artifact, self.identifier()) .map(|s| s.as_str()) diff --git a/crates/rspack_core/src/utils/concatenation_scope.rs b/crates/rspack_core/src/utils/concatenation_scope.rs index e0feb246a577..03fd7f6e1243 100644 --- a/crates/rspack_core/src/utils/concatenation_scope.rs +++ b/crates/rspack_core/src/utils/concatenation_scope.rs @@ -60,17 +60,29 @@ impl Hash for CodeGenerationDataConcatenationScopeOutput { // source. They must participate in the chunk-render cache key as well. self.namespace_export_symbol.hash(hasher); for map in [&self.export_map, &self.raw_export_map] { - let mut entries = map.iter().flat_map(|map| map.iter()).collect::>(); + let mut entries = map + .iter() + .flat_map(|map| map.iter()) + .map(|(name, value)| (name.as_str(), value.as_str())) + .collect::>(); entries.sort_unstable(); entries.hash(hasher); } if let Some(import_map) = &self.import_map { for (source, imports) in import_map { source.hash(hasher); - let mut specifiers = imports.specifiers.iter().collect::>(); + let mut specifiers = imports + .specifiers + .iter() + .map(|(local, imported)| (local.as_str(), imported.as_str())) + .collect::>(); specifiers.sort_unstable(); specifiers.hash(hasher); - let mut namespaces = imports.namespaces.iter().collect::>(); + let mut namespaces = imports + .namespaces + .iter() + .map(Atom::as_str) + .collect::>(); namespaces.sort_unstable(); namespaces.hash(hasher); } diff --git a/crates/rspack_plugin_esm_library/src/plugin.rs b/crates/rspack_plugin_esm_library/src/plugin.rs index 46f00f84bab3..33032e9ba40d 100644 --- a/crates/rspack_plugin_esm_library/src/plugin.rs +++ b/crates/rspack_plugin_esm_library/src/plugin.rs @@ -5,7 +5,9 @@ use std::{ use atomic_refcell::AtomicRefCell; use regex::Regex; -use rspack_collections::{Identifiable, Identifier, IdentifierIndexMap, IdentifierMap, IdentifierSet}; +use rspack_collections::{ + Identifiable, Identifier, IdentifierIndexMap, IdentifierMap, IdentifierSet, +}; use rspack_core::{ ApplyContext, AssetInfo, AsyncModulesArtifact, BoxModule, BuildModuleGraphArtifact, ChunkUkey, Compilation, CompilationAdditionalChunkRuntimeRequirements, From 83a28c01adf2a564d02e579dcf46259ee6503e66 Mon Sep 17 00:00:00 2001 From: Fy <1114550440@qq.com> Date: Wed, 16 Sep 2026 00:19:20 +0800 Subject: [PATCH 11/13] perf(esm-library): reduce external codegen overhead --- crates/rspack_core/src/external_module.rs | 18 +++----- .../src/utils/concatenation_scope.rs | 46 +++++++++++-------- .../src/dependency/commonjs_external.rs | 8 +++- 3 files changed, 39 insertions(+), 33 deletions(-) diff --git a/crates/rspack_core/src/external_module.rs b/crates/rspack_core/src/external_module.rs index 09b1672bb15c..174d2030206d 100644 --- a/crates/rspack_core/src/external_module.rs +++ b/crates/rspack_core/src/external_module.rs @@ -58,7 +58,6 @@ impl ExternalRequestValue { } /// The CommonJS require form used to render an external request. -#[cacheable] #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum CommonJsExternalRequireKind { CommonJs, @@ -631,9 +630,8 @@ impl ExternalModule { fn module_import_identifier(&self, compilation: &Compilation) -> String { let request = self.get_request(); - if to_identifier(&request.primary) == request.primary - && self.dependency_meta.attributes.is_none() - { + let identifier = to_identifier(&request.primary); + if identifier == request.primary && self.dependency_meta.attributes.is_none() { return request.primary.clone(); } let mut hasher = RspackHasher::from(&compilation.options.output); @@ -645,11 +643,7 @@ impl ExternalModule { .hash(&mut hasher); } let hash_suffix = hasher.digest(&compilation.options.output.hash_digest); - format!( - "{}_{}", - to_identifier(&request.primary), - hash_suffix.rendered(8) - ) + format!("{identifier}_{}", hash_suffix.rendered(8)) } /// Register a native import owned by the referencing module's scope. @@ -675,7 +669,7 @@ impl ExternalModule { request.primary.clone(), attributes, imported.clone(), - local.clone().into(), + local.as_str().into(), ); local } else { @@ -798,8 +792,8 @@ impl ExternalModule { let require_expression = require_kind.render_expression( request.map(ExternalRequestValue::primary).or(fallback), request - .into_iter() - .flat_map(|request| request.iter().skip(1)), + .and_then(ExternalRequestValue::rest) + .unwrap_or_default(), compilation, &mut chunk_init_fragments, ); diff --git a/crates/rspack_core/src/utils/concatenation_scope.rs b/crates/rspack_core/src/utils/concatenation_scope.rs index 03fd7f6e1243..c79124d09cfa 100644 --- a/crates/rspack_core/src/utils/concatenation_scope.rs +++ b/crates/rspack_core/src/utils/concatenation_scope.rs @@ -56,33 +56,41 @@ pub struct CodeGenerationDataConcatenationScopeOutput { impl Hash for CodeGenerationDataConcatenationScopeOutput { fn hash(&self, hasher: &mut H) { + fn hash_entries(entries: &mut [(&str, &str)], hasher: &mut H) { + // Map keys are unique, so comparing values cannot change their order. + entries.sort_unstable_by_key(|(name, _)| *name); + entries.hash(hasher); + } + // Native imports/reexports are emitted by the linker, not the module // source. They must participate in the chunk-render cache key as well. self.namespace_export_symbol.hash(hasher); + let mut entries = Vec::new(); for map in [&self.export_map, &self.raw_export_map] { - let mut entries = map - .iter() - .flat_map(|map| map.iter()) - .map(|(name, value)| (name.as_str(), value.as_str())) - .collect::>(); - entries.sort_unstable(); - entries.hash(hasher); + entries.clear(); + if let Some(map) = map { + entries.reserve(map.len()); + for (name, value) in map { + entries.push((name.as_str(), value.as_str())); + } + } + hash_entries(&mut entries, hasher); } if let Some(import_map) = &self.import_map { + let mut namespaces = Vec::new(); for (source, imports) in import_map { source.hash(hasher); - let mut specifiers = imports - .specifiers - .iter() - .map(|(local, imported)| (local.as_str(), imported.as_str())) - .collect::>(); - specifiers.sort_unstable(); - specifiers.hash(hasher); - let mut namespaces = imports - .namespaces - .iter() - .map(Atom::as_str) - .collect::>(); + entries.clear(); + entries.reserve(imports.specifiers.len()); + for (local, imported) in &imports.specifiers { + entries.push((local.as_str(), imported.as_str())); + } + hash_entries(&mut entries, hasher); + namespaces.clear(); + namespaces.reserve(imports.namespaces.len()); + for namespace in &imports.namespaces { + namespaces.push(namespace.as_str()); + } namespaces.sort_unstable(); namespaces.hash(hasher); } diff --git a/crates/rspack_plugin_esm_library/src/dependency/commonjs_external.rs b/crates/rspack_plugin_esm_library/src/dependency/commonjs_external.rs index f2101336e2bd..d3fe56d96419 100644 --- a/crates/rspack_plugin_esm_library/src/dependency/commonjs_external.rs +++ b/crates/rspack_plugin_esm_library/src/dependency/commonjs_external.rs @@ -1,7 +1,7 @@ use std::sync::Arc; use atomic_refcell::AtomicRefCell; -use rspack_cacheable::{cacheable, cacheable_dyn}; +use rspack_cacheable::{cacheable, cacheable_dyn, with::Skip}; use rspack_core::{ BuildModuleGraphArtifact, CodeGenerationDataItem, CommonJsExternalRequireKind, Dependency, DependencyCodeGeneration, DependencyId, DependencyRange, DependencyTemplate, TemplateContext, @@ -22,7 +22,11 @@ pub type DirectCommonJsExternalDependencies = Arc); +struct DirectExternalRequireHeaders( + // Only shared between dependency templates during codegen. Cached sources + // already contain the rendered callee and never consume these ranges again. + #[cacheable(with=Skip)] Vec<(DependencyRange, CommonJsExternalRequireKind)>, +); #[cacheable_dyn] impl CodeGenerationDataItem for DirectExternalRequireHeaders {} From b58bcf20db54f99e820959ab59b4e123dc34a791 Mon Sep 17 00:00:00 2001 From: Fy <1114550440@qq.com> Date: Thu, 17 Sep 2026 18:48:01 +0800 Subject: [PATCH 12/13] refactor(esm-library): limit direct external rendering to CommonJS --- .../src/artifacts/code_generation_results.rs | 6 +- .../src/chunk_graph/chunk_graph_module.rs | 16 +- crates/rspack_core/src/concatenated_module.rs | 34 ++-- .../rspack_core/src/concatenation_backend.rs | 49 ++--- crates/rspack_core/src/external_module.rs | 116 +++--------- .../src/utils/concatenation_scope.rs | 90 ++------- .../src/dependency/commonjs_external.rs | 2 +- .../src/dependency/esm_external.rs | 178 ------------------ .../src/dependency/mod.rs | 5 +- .../src/esm_lib_parser_plugin.rs | 16 +- crates/rspack_plugin_esm_library/src/link.rs | 169 +++++++---------- .../rspack_plugin_esm_library/src/plugin.rs | 31 +-- ...sm_export_imported_specifier_dependency.rs | 89 +-------- .../dependency/esm/esm_import_dependency.rs | 46 +---- .../esm/esm_import_specifier_dependency.rs | 84 ++------- .../src/dependency/esm/mod.rs | 2 +- .../reexport-star/__snapshot__/case1.txt | 16 +- .../reexport-star/__snapshot__/case2.txt | 4 +- .../reexport-star/__snapshot__/case3.txt | 1 + .../reexport-star/__snapshot__/case4.txt | 6 + .../reexport-star/__snapshot__/case5.txt | 5 +- .../reexport-star/__snapshot__/case6.txt | 7 + .../runtimeModeSnapshot/case1.txt | 16 +- .../runtimeModeSnapshot/case2.txt | 4 +- .../runtimeModeSnapshot/case3.txt | 1 + .../runtimeModeSnapshot/case4.txt | 6 + .../runtimeModeSnapshot/case5.txt | 5 +- .../runtimeModeSnapshot/case6.txt | 7 + .../rspack.config.mjs | 46 +++-- .../runtimeModeSnapshot/esm.snap.txt | 12 -- .../__snapshots__/esm.snap.txt | 9 +- .../__snapshots__/esm.snap.txt | 2 + .../__snapshots__/esm.snap.txt | 4 + .../__snapshots__/esm.snap.txt | 4 +- .../runtimeModeSnapshot/esm.snap.txt | 4 +- .../__snapshots__/esm.snap.txt | 4 + .../runtimeModeSnapshot/esm.snap.txt | 4 + .../__snapshots__/esm.snap.txt | 4 + .../__snapshots__/esm.snap.txt | 4 + .../__snapshots__/esm.snap.txt | 2 + .../aliased/__snapshots__/esm.snap.txt | 4 + .../__snapshots__/esm.snap.txt | 2 + .../runtimeModeSnapshot/esm.snap.txt | 2 + .../__snapshots__/esm.snap.txt | 6 +- .../runtimeModeSnapshot/esm.snap.txt | 6 +- .../__snapshots__/esm.snap.txt | 4 + .../__snapshots__/esm.snap.txt | 12 +- .../empty-import/__snapshots__/esm.snap.txt | 2 + .../__snapshots__/esm.snap.txt | 4 + .../runtimeModeSnapshot/esm.snap.txt | 4 + .../__snapshots__/esm.snap.txt | 4 + .../runtimeModeSnapshot/esm.snap.txt | 4 + .../__snapshots__/esm.snap.txt | 5 +- .../__snapshots__/esm.snap.txt | 2 + .../__snapshots__/esm.snap.txt | 4 + .../__snapshots__/esm.snap.txt | 4 + .../__snapshots__/esm.snap.txt | 5 +- .../__snapshots__/esm.snap.txt | 4 + .../__snapshots__/esm.snap.txt | 2 + .../__snapshots__/esm.snap.txt | 2 + .../__snapshots__/esm.snap.txt | 14 +- .../__snapshots__/esm.snap.txt | 2 + .../__snapshots__/esm.snap.txt | 8 +- .../__snapshots__/esm.snap.txt | 5 +- .../__snapshots__/esm.snap.txt | 2 + .../runtimeModeSnapshot/esm.snap.txt | 35 ---- .../__snapshots__/esm.snap.txt | 4 + .../__snapshots__/esm.snap.txt | 10 +- .../__snapshots__/esm.snap.txt | 2 + .../__snapshots__/esm.snap.txt | 2 + .../__snapshots__/esm.snap.txt | 6 +- .../runtimeModeSnapshot/esm.snap.txt | 6 +- .../__snapshots__/esm.snap.txt | 6 +- .../runtimeModeSnapshot/esm.snap.txt | 6 +- .../__snapshots__/esm.snap.txt | 7 +- .../runtime-decide/__snapshots__/esm.snap.txt | 1 - .../runtimeModeSnapshot/esm.snap.txt | 1 - .../__snapshots__/esm.snap.txt | 4 + .../__snapshots__/esm.snap.txt | 18 +- .../__snapshots__/esm.snap.txt | 5 +- .../__snapshots__/esm.snap.txt | 37 +++- .../runtimeModeSnapshot/esm.snap.txt | 37 +++- .../__snapshots__/esm.snap.txt | 32 +++- .../runtimeModeSnapshot/esm.snap.txt | 32 +++- .../__snapshots__/esm.snap.txt | 17 +- .../runtimeModeSnapshot/esm.snap.txt | 17 +- .../__snapshots__/esm.snap.txt | 26 ++- .../runtimeModeSnapshot/esm.snap.txt | 26 ++- .../__snapshots__/esm.snap.txt | 6 + .../__snapshots__/esm.snap.txt | 6 + .../__snapshots__/esm.snap.txt | 5 + .../__snapshots__/esm.snap.txt | 4 + .../runtimeModeSnapshot/esm.snap.txt | 4 + .../__snapshots__/esm.snap.txt | 4 + .../runtimeModeSnapshot/esm.snap.txt | 4 + .../move-entry/__snapshots__/esm.snap.txt | 4 +- .../__snapshots__/esm.snap.txt | 10 +- .../__snapshots__/esm.snap.txt | 13 +- .../__snapshots__/esm.snap.txt | 12 +- .../runtimeModeSnapshot/esm.snap.txt | 12 +- .../__snapshots__/esm.snap.txt | 4 + 101 files changed, 721 insertions(+), 927 deletions(-) delete mode 100644 crates/rspack_plugin_esm_library/src/dependency/esm_external.rs delete mode 100644 tests/rspack-test/esmOutputCases/deconflict/asset-preserve-import-external-symbols/__snapshots__/runtimeModeSnapshot/esm.snap.txt delete mode 100644 tests/rspack-test/esmOutputCases/externals/namespace-name-collision-across-modules/__snapshots__/runtimeModeSnapshot/esm.snap.txt diff --git a/crates/rspack_core/src/artifacts/code_generation_results.rs b/crates/rspack_core/src/artifacts/code_generation_results.rs index db73d10108d0..cbf21f88dc35 100644 --- a/crates/rspack_core/src/artifacts/code_generation_results.rs +++ b/crates/rspack_core/src/artifacts/code_generation_results.rs @@ -196,11 +196,7 @@ impl CodeGenerationDataItem for CodeGenerationDataChunkInitFragments { } #[cacheable_dyn] -impl CodeGenerationDataItem for CodeGenerationDataConcatenationScopeOutput { - fn update_hash(&self, hasher: &mut RspackHasher) { - std::hash::Hash::hash(self, hasher); - } -} +impl CodeGenerationDataItem for CodeGenerationDataConcatenationScopeOutput {} #[cacheable] #[derive(Debug, Default)] diff --git a/crates/rspack_core/src/chunk_graph/chunk_graph_module.rs b/crates/rspack_core/src/chunk_graph/chunk_graph_module.rs index 8057f676d998..6a18d91559d2 100644 --- a/crates/rspack_core/src/chunk_graph/chunk_graph_module.rs +++ b/crates/rspack_core/src/chunk_graph/chunk_graph_module.rs @@ -357,16 +357,20 @@ impl ChunkGraph { side_effects_state_artifact, &compilation.exports_info_artifact, ); - let is_external = mg + let is_commonjs_external = mg .module_by_identifier(module_identifier) - .is_some_and(|module| module.as_external_module().is_some()); - if active_state.is_false() && !is_external { + .and_then(|module| module.as_external_module()) + .is_some_and(|external| { + crate::CommonJsExternalRequireKind::from_external_type(external.resolve_external_type()) + .is_some() + }); + if active_state.is_false() && !is_commonjs_external { return None; } - // Direct external templates still read the request/type and export - // names after the placement connection is cut out. Such modules may + // Direct CommonJS external templates still read the request/type + // after the placement connection is cut out. Such modules may // have no chunk module id, so also hash their semantic identity. - if is_external { + if is_commonjs_external { module_identifier.hash(&mut hasher); } visited_modules.insert(*module_identifier); diff --git a/crates/rspack_core/src/concatenated_module.rs b/crates/rspack_core/src/concatenated_module.rs index d550a846c93b..08c8f38ee1ec 100644 --- a/crates/rspack_core/src/concatenated_module.rs +++ b/crates/rspack_core/src/concatenated_module.rs @@ -10,7 +10,7 @@ use rayon::prelude::*; use regex::Regex; use rspack_cacheable::{ cacheable, cacheable_dyn, - with::{As, AsMap, AsPreset, AsVec}, + with::{As, AsOption, AsPreset, AsVec}, }; use rspack_collections::{ Identifiable, Identifier, IdentifierIndexMap, IdentifierIndexSet, IdentifierMap, IdentifierSet, @@ -184,11 +184,10 @@ impl ConcatenationEntryExternal { #[cacheable] #[derive(Clone, Debug, Default)] pub struct ConcatenatedImportMapItem { - /// Local binding to the original external export name. - #[cacheable(with=AsMap)] - pub specifiers: HashMap, #[cacheable(with=AsVec)] - pub namespaces: HashSet, + pub specifiers: HashSet, + #[cacheable(with=AsOption)] + pub namespace: Option, } pub type ConcatenatedImportMap = @@ -708,7 +707,7 @@ pub fn render_imports(source: &str, attr: Option<&str>, import_spec: &ImportSpec if atom == internal { atom.to_string() } else { - format!("{} as {internal}", crate::to_module_export_name(atom)) + format!("{atom} as {internal}") } }) .collect::>() @@ -1051,7 +1050,7 @@ impl Module for ConcatenatedModule { for ((source, attr), imported) in import_map { let total_imported_atoms = import_stmts.entry((source.clone(), attr)).or_default(); - for ns_import in imported.namespaces { + if let Some(ns_import) = imported.namespace { if let Some(internal_ns_import) = total_imported_atoms.ns_import.as_ref() { info .internal_names @@ -1076,21 +1075,10 @@ impl Module for ConcatenatedModule { } } - for (local_name, imported_name) in imported.specifiers { - let existing_name = total_imported_atoms - .atoms - .get(&imported_name) - .or_else(|| { - if imported_name == "default" { - total_imported_atoms.default_import.as_ref() - } else { - None - } - }) - .cloned(); + for atom in imported.specifiers { + let existing_name = total_imported_atoms.atoms.get(&atom).cloned(); let new_name = name_allocator.assign_import_binding_name( - &local_name, - &imported_name, + &atom, existing_name.as_ref(), &source, info, @@ -1098,10 +1086,10 @@ impl Module for ConcatenatedModule { ); if existing_name.is_none() { - if imported_name == "default" { + if atom == "default" { total_imported_atoms.default_import = Some(new_name); } else { - total_imported_atoms.atoms.insert(imported_name, new_name); + total_imported_atoms.atoms.insert(atom, new_name); } } } diff --git a/crates/rspack_core/src/concatenation_backend.rs b/crates/rspack_core/src/concatenation_backend.rs index 8431e5bb3425..aceb78cb76eb 100644 --- a/crates/rspack_core/src/concatenation_backend.rs +++ b/crates/rspack_core/src/concatenation_backend.rs @@ -20,7 +20,7 @@ use crate::{ ExportInfo, ExportProvided, ExportsInfoArtifact, ExportsType, FindTargetResult, ModuleGraph, ModuleGraphCacheArtifact, ModuleIdentifier, ModuleInfo, ModuleStaticCache, RuntimeSpec, UsedName, collect_ident, escape_name_atom_ref, find_target, get_cached_readable_identifier, - split_readable_identifier, to_identifier, to_identifier_with_escaped, + split_readable_identifier, to_identifier_with_escaped, }; /// Reusable read-only context shared by concatenation implementations. @@ -447,7 +447,7 @@ impl ConcatenationNameAllocator { ) { let escaped_identifier = context.module_identifier(&module_info.module); for (name, ctxt) in module_info.binding_to_ref.keys() { - if ctxt != &module_info.module_ctxt || module_info.internal_names.contains_key(name) { + if ctxt != &module_info.module_ctxt { continue; } @@ -472,19 +472,15 @@ impl ConcatenationNameAllocator { pub fn assign_import_binding_name( &mut self, - local_name: &Atom, imported_name: &Atom, existing_name: Option<&Atom>, source: &str, module_info: &mut ConcatenatedModuleInfo, context: &ConcatenationContext, ) -> Atom { - let needs_rename = self.contains(imported_name) - || imported_name.is_empty() - || to_identifier(imported_name) != imported_name.as_str(); - let should_update_raw_export = existing_name.is_some() || needs_rename; + let should_update_raw_export = existing_name.is_some() || self.contains(imported_name); let internal_name = existing_name.cloned().unwrap_or_else(|| { - if !needs_rename { + if !self.contains(imported_name) { self.insert(imported_name.clone()); return imported_name.clone(); } @@ -505,13 +501,13 @@ impl ConcatenationNameAllocator { if should_update_raw_export && let Some(raw_export_map) = module_info.raw_export_map.as_mut() - && raw_export_map.contains_key(local_name) + && raw_export_map.contains_key(imported_name) { - raw_export_map.insert(local_name.clone(), internal_name.to_string()); + raw_export_map.insert(imported_name.clone(), internal_name.to_string()); } module_info .internal_names - .insert(local_name.clone(), internal_name.clone()); + .insert(imported_name.clone(), internal_name.clone()); internal_name } @@ -594,19 +590,9 @@ pub fn analyze_module_scope( module_info.global_scope_ident.reserve(identifiers.len()); module_info.binding_to_ref.reserve(identifiers.len()); - let imported_bindings = module_info - .import_map - .iter() - .flat_map(|map| map.values()) - .flat_map(|item| item.specifiers.keys().chain(item.namespaces.iter())) - .map(|atom| atom.as_str()) - .collect::>(); for identifier in identifiers { let scope = semantic.node_scope(&identifier.id); - let is_import = scope != top_level_scope_id - && imported_bindings.contains(identifier.id.sym.as_str()) - && SyntaxContext::from_u32(scope.raw()) == module_info.global_ctxt; - let is_global = !is_import && SyntaxContext::from_u32(scope.raw()) == module_info.global_ctxt; + let is_global = SyntaxContext::from_u32(scope.raw()) == module_info.global_ctxt; let legacy = if is_global { let legacy = identifier.to_legacy(&semantic); module_info.global_scope_ident.push(legacy.clone()); @@ -625,16 +611,13 @@ pub fn analyze_module_scope( continue; } - if scope != top_level_scope_id && !is_import { + if scope != top_level_scope_id { module_info .all_used_names .insert(Atom::from(identifier.id.sym.as_str())); } - let mut legacy = legacy.unwrap_or_else(|| identifier.to_legacy(&semantic)); - if is_import { - legacy.id.ctxt = module_info.module_ctxt; - } + let legacy = legacy.unwrap_or_else(|| identifier.to_legacy(&semantic)); module_info.idents.push(legacy.clone()); module_info .binding_to_ref @@ -668,7 +651,9 @@ impl<'a> ConcatenationContext<'a> { let imported_names = import_map.map_or(0, |map| { map .values() - .map(|imported| imported.specifiers.len() + imported.namespaces.len()) + .map(|imported| { + imported.specifiers.len() + usize::from(imported.namespace.is_some()) + }) .sum::() }); ( @@ -704,16 +689,12 @@ impl<'a> ConcatenationContext<'a> { source.clone(), split_readable_identifier(source.as_str()), )); - for atom in imported - .specifiers - .keys() - .chain(imported.specifiers.values()) - { + for atom in &imported.specifiers { escaped_names .entry(atom.clone()) .or_insert_with(|| escape_name_atom_ref(atom)); } - for namespace in &imported.namespaces { + if let Some(namespace) = &imported.namespace { escaped_names .entry(namespace.clone()) .or_insert_with(|| escape_name_atom_ref(namespace)); diff --git a/crates/rspack_core/src/external_module.rs b/crates/rspack_core/src/external_module.rs index 174d2030206d..77c19dadbd09 100644 --- a/crates/rspack_core/src/external_module.rs +++ b/crates/rspack_core/src/external_module.rs @@ -5,7 +5,6 @@ use rspack_collections::{Identifiable, Identifier}; use rspack_error::{Result, impl_empty_diagnosable_trait}; use rspack_hash::{RspackHashDigest, RspackHasher}; use rspack_hook::define_hook; -use rspack_intern::Atom; use rspack_macros::impl_source_map_config; use rspack_util::{json_stringify_str, source_map::SourceMapKind}; use rustc_hash::FxHashMap as HashMap; @@ -628,93 +627,6 @@ impl ExternalModule { self.dependency_meta.phase } - fn module_import_identifier(&self, compilation: &Compilation) -> String { - let request = self.get_request(); - let identifier = to_identifier(&request.primary); - if identifier == request.primary && self.dependency_meta.attributes.is_none() { - return request.primary.clone(); - } - let mut hasher = RspackHasher::from(&compilation.options.output); - use rspack_hash::RspackHash as _; - request.primary.hash(&mut hasher); - if let Some(attributes) = &self.dependency_meta.attributes { - simd_json::to_string(attributes) - .expect("json stringify failed") - .hash(&mut hasher); - } - let hash_suffix = hasher.digest(&compilation.options.output.hash_digest); - format!("{identifier}_{}", hash_suffix.rendered(8)) - } - - /// Register a native import owned by the referencing module's scope. - pub fn register_module_import( - &self, - compilation: &Compilation, - scope: &mut ConcatenationScope, - imported: Option<&Atom>, - local: Option<&Atom>, - ) -> String { - let request = self.get_request(); - let attributes = self.module_import_attributes(); - let namespace = format!( - "__rspack_external_{}", - self.module_import_identifier(compilation) - ); - if let Some(imported) = imported { - let local = local.map_or_else( - || format!("{namespace}_{}", hex::encode(imported.as_bytes())), - ToString::to_string, - ); - scope.register_import_as( - request.primary.clone(), - attributes, - imported.clone(), - local.as_str().into(), - ); - local - } else { - let local = local.cloned().unwrap_or_else(|| namespace.into()); - scope.register_namespace_import(request.primary.clone(), attributes, local.clone()); - local.to_string() - } - } - - pub fn module_import_attributes(&self) -> Option { - self.dependency_meta.attributes.as_ref().map(|attributes| { - format!( - " with {}", - simd_json::to_string(attributes).expect("json stringify failed") - ) - }) - } - - pub fn register_module_side_effect(&self, scope: &mut ConcatenationScope) { - scope.register_import( - self.get_request().primary.clone(), - self.module_import_attributes(), - None, - ); - } - - pub fn render_module_namespace( - &self, - compilation: &Compilation, - runtime: Option<&RuntimeSpec>, - runtime_template: &mut ModuleCodeTemplate, - ) -> (Option, String, ChunkInitFragments) { - get_source_for_module_external( - self.get_request(), - &self.module_import_identifier(compilation), - &self.dependency_meta, - &compilation.exports_info_artifact, - compilation - .exports_info_artifact - .get_exports_info_data(&self.identifier()), - runtime, - runtime_template, - ) - } - pub fn resolve_external_type(&self) -> &str { resolve_external_type(self.external_type.as_str(), &self.dependency_meta) } @@ -896,7 +808,26 @@ impl ExternalModule { if compilation.options.output.module && let Some(request) = request { - let id = self.module_import_identifier(compilation); + let id: Cow<'_, str> = if to_identifier(&request.primary) != request.primary + || self.dependency_meta.attributes.is_some() + { + let mut hasher = RspackHasher::from(&compilation.options.output); + use rspack_hash::RspackHash as _; + request.primary.hash(&mut hasher); + if let Some(attributes) = &self.dependency_meta.attributes { + simd_json::to_string(attributes) + .expect("json stringify failed") + .hash(&mut hasher); + } + let hash_suffix = hasher.digest(&compilation.options.output.hash_digest); + Cow::Owned(format!( + "{}_{}", + to_identifier(&request.primary), + hash_suffix.rendered(8) + )) + } else { + to_identifier(&request.primary) + }; if let Some(concatenation_scope) = concatenation_scope { let exports_info = compilation .exports_info_artifact @@ -913,7 +844,12 @@ impl ExternalModule { .ns_access() }) ); - let attributes = self.module_import_attributes(); + let attributes = self.dependency_meta.attributes.as_ref().map(|meta| { + format!( + " with {}", + simd_json::to_string(meta).expect("json stringify failed"), + ) + }); #[derive(Clone, Copy)] struct ExternalImportOptimize(pub bool); diff --git a/crates/rspack_core/src/utils/concatenation_scope.rs b/crates/rspack_core/src/utils/concatenation_scope.rs index c79124d09cfa..0691b4074953 100644 --- a/crates/rspack_core/src/utils/concatenation_scope.rs +++ b/crates/rspack_core/src/utils/concatenation_scope.rs @@ -1,7 +1,4 @@ -use std::{ - hash::Hash, - sync::{Arc, LazyLock}, -}; +use std::sync::{Arc, LazyLock}; use anymap::CloneAny; use rspack_cacheable::{ @@ -25,7 +22,7 @@ const MODULE_REFERENCE_PREFIX: &str = "__rspack_module_ref"; const MODULE_REFERENCE_PROPERTY_ACCESS_SUFFIX: &str = "._"; #[cacheable] -#[derive(Default, Debug, Clone, Hash)] +#[derive(Default, Debug, Clone)] pub struct ModuleReferenceOptions { #[cacheable(with=AsVec)] pub ids: Vec, @@ -54,57 +51,6 @@ pub struct CodeGenerationDataConcatenationScopeOutput { refs: IdentifierIndexMap>, } -impl Hash for CodeGenerationDataConcatenationScopeOutput { - fn hash(&self, hasher: &mut H) { - fn hash_entries(entries: &mut [(&str, &str)], hasher: &mut H) { - // Map keys are unique, so comparing values cannot change their order. - entries.sort_unstable_by_key(|(name, _)| *name); - entries.hash(hasher); - } - - // Native imports/reexports are emitted by the linker, not the module - // source. They must participate in the chunk-render cache key as well. - self.namespace_export_symbol.hash(hasher); - let mut entries = Vec::new(); - for map in [&self.export_map, &self.raw_export_map] { - entries.clear(); - if let Some(map) = map { - entries.reserve(map.len()); - for (name, value) in map { - entries.push((name.as_str(), value.as_str())); - } - } - hash_entries(&mut entries, hasher); - } - if let Some(import_map) = &self.import_map { - let mut namespaces = Vec::new(); - for (source, imports) in import_map { - source.hash(hasher); - entries.clear(); - entries.reserve(imports.specifiers.len()); - for (local, imported) in &imports.specifiers { - entries.push((local.as_str(), imported.as_str())); - } - hash_entries(&mut entries, hasher); - namespaces.clear(); - namespaces.reserve(imports.namespaces.len()); - for namespace in &imports.namespaces { - namespaces.push(namespace.as_str()); - } - namespaces.sort_unstable(); - namespaces.hash(hasher); - } - } - for (module, refs) in &self.refs { - module.hash(hasher); - for (symbol, options) in refs { - symbol.hash(hasher); - options.hash(hasher); - } - } - } -} - impl CodeGenerationDataConcatenationScopeOutput { pub fn apply_to(&self, current_module: &mut ConcatenatedModuleInfo) { current_module @@ -193,13 +139,20 @@ impl ConcatenationScope { import_source: String, attributes: Option, import_symbol: Atom, - ) { + ) -> &Atom { let raw_import_map = self.current_module.import_map.get_or_insert_default(); let entry = raw_import_map .entry((import_source, attributes)) .or_default(); - entry.namespaces.insert(import_symbol); + if entry.namespace.is_none() { + entry.namespace = Some(import_symbol) + } + + entry + .namespace + .as_ref() + .expect("should have namespace symbol") } pub fn register_import( @@ -217,26 +170,7 @@ impl ConcatenationScope { return; }; - entry - .specifiers - .insert(import_symbol.clone(), import_symbol); - } - - pub fn register_import_as( - &mut self, - import_source: String, - attributes: Option, - imported: Atom, - local: Atom, - ) { - self - .current_module - .import_map - .get_or_insert_default() - .entry((import_source, attributes)) - .or_default() - .specifiers - .insert(local, imported); + entry.specifiers.insert(import_symbol); } pub fn register_namespace_export(&mut self, symbol: &str) { diff --git a/crates/rspack_plugin_esm_library/src/dependency/commonjs_external.rs b/crates/rspack_plugin_esm_library/src/dependency/commonjs_external.rs index d3fe56d96419..30a84ab28f55 100644 --- a/crates/rspack_plugin_esm_library/src/dependency/commonjs_external.rs +++ b/crates/rspack_plugin_esm_library/src/dependency/commonjs_external.rs @@ -31,7 +31,7 @@ struct DirectExternalRequireHeaders( #[cacheable_dyn] impl CodeGenerationDataItem for DirectExternalRequireHeaders {} -pub(super) fn is_relative_external_request(request: &str) -> bool { +fn is_relative_external_request(request: &str) -> bool { request == "." || request == ".." || request.starts_with("./") diff --git a/crates/rspack_plugin_esm_library/src/dependency/esm_external.rs b/crates/rspack_plugin_esm_library/src/dependency/esm_external.rs deleted file mode 100644 index 9a91ab6d49d0..000000000000 --- a/crates/rspack_plugin_esm_library/src/dependency/esm_external.rs +++ /dev/null @@ -1,178 +0,0 @@ -use std::sync::Arc; - -use atomic_refcell::AtomicRefCell; -use rspack_core::{ - BuildModuleGraphArtifact, Compilation, Dependency, DependencyCodeGeneration, DependencyId, - DependencyTemplate, ExportsInfoArtifact, ExternalModule, ImportPhase, ModuleGraphConnection, - TemplateContext, TemplateReplaceSource, -}; -use rspack_plugin_javascript::dependency::{ - ESMExportImportedSpecifierDependency, ESMExportImportedSpecifierDependencyTemplate, - ESMImportSideEffectDependency, ESMImportSpecifierDependency, - ESMImportSpecifierDependencyTemplate, esm_import_external, -}; -use rspack_util::fx_hash::FxHashMap; - -use super::{ExternalBindingBailout, commonjs_external::is_relative_external_request}; - -pub type DirectEsmExternalDependencies = - Arc>>; - -pub fn requires_issuer_identity(external: &ExternalModule) -> bool { - let request = external.get_request(); - // Relative imports must remain in the issuer's emitted directory. Projected - // namespaces are expressions, not bindings that can be exported by a shared chunk. - request.has_rest() || is_relative_external_request(request.primary()) -} - -pub fn can_render_esm_external(dependency: &dyn Dependency, external: &ExternalModule) -> bool { - external.resolve_external_type() == "module" - && !dependency - .as_module_dependency() - .is_some_and(|dependency| dependency.weak()) - && external.get_import_phase() == ImportPhase::Evaluation - && !requires_issuer_identity(external) - && (dependency.as_any().is::() - || dependency.as_any().is::() - || dependency - .as_any() - .is::()) -} - -pub fn cutout_esm_externals( - compilation: &Compilation, - artifact: &mut BuildModuleGraphArtifact, - exports_info: &ExportsInfoArtifact, - direct: &DirectEsmExternalDependencies, -) { - let mg = artifact.get_module_graph(); - let mut previous = std::mem::take(&mut *direct.borrow_mut()); - let mut connections = FxHashMap::default(); - for (_, module) in mg.modules() { - if ExternalBindingBailout::is_present(module.as_ref()) { - continue; - } - for dependency in module.get_dependencies() { - let dependency = dependency.as_ref(); - let id = dependency.id(); - let Some(connection) = mg.connection_by_dependency_id(id) else { - continue; - }; - let Some(external) = mg - .module_by_identifier(connection.module_identifier()) - .and_then(|module| module.as_external_module()) - else { - continue; - }; - // Checked/partial reexports still need their original template semantics. - // Keep their edge, instead of changing the issuer's scope-hoisting decision. - if let Some(dependency) = dependency - .as_any() - .downcast_ref::() - && !ESMExportImportedSpecifierDependencyTemplate::supports_direct_scope_export( - &dependency.get_mode( - mg, - None, - &compilation.module_graph_cache_artifact, - exports_info, - ), - ) - { - continue; - } - if can_render_esm_external(dependency, external) - && (previous.contains_key(id) - || connection.is_active( - mg, - None, - &compilation.module_graph_cache_artifact, - &artifact.side_effects_state_artifact, - exports_info, - )) - { - // OptimizeDependencies may run more than once. Preserve the semantic - // condition, while only disabling placement in the chunk graph. - connections.insert( - *id, - previous.remove(id).unwrap_or_else(|| connection.clone()), - ); - } - } - } - let mg = artifact.get_module_graph_mut(); - for id in connections.keys() { - mg.connection_by_dependency_id_mut(id) - .expect("external connection should exist") - .force_inactive(); - } - *direct.borrow_mut() = connections; -} - -#[derive(Debug)] -pub struct DirectEsmExternalDependencyTemplate { - pub direct: DirectEsmExternalDependencies, - pub template: Arc, -} - -impl DependencyTemplate for DirectEsmExternalDependencyTemplate { - fn render( - &self, - dependency: &dyn DependencyCodeGeneration, - source: &mut TemplateReplaceSource, - context: &mut TemplateContext, - ) { - let side_effect = dependency - .as_any() - .downcast_ref::(); - let specifier = dependency - .as_any() - .downcast_ref::(); - let reexport = dependency - .as_any() - .downcast_ref::(); - let id = side_effect - .map(Dependency::id) - .or_else(|| specifier.map(Dependency::id)) - .or_else(|| reexport.map(Dependency::id)) - .expect("only ESM dependency templates are wrapped"); - let direct = self.direct.borrow(); - let Some(connection) = direct.get(id) else { - self.template.render(dependency, source, context); - return; - }; - let compilation = context.compilation; - let mg = compilation.get_module_graph(); - if !connection.is_target_active( - mg, - context.runtime, - &compilation.module_graph_cache_artifact, - &compilation - .build_module_graph_artifact - .side_effects_state_artifact, - &compilation.exports_info_artifact, - ) { - return; - } - let external = mg - .module_by_identifier(connection.module_identifier()) - .and_then(|module| module.as_external_module()) - .expect("direct dependency should target an external"); - if let Some(dep) = side_effect { - if let Some(scope) = context.concatenation_scope.as_mut() { - external.register_module_side_effect(scope); - } else { - esm_import_external(external, dep, context); - } - } else if let Some(dep) = specifier { - ESMImportSpecifierDependencyTemplate.render_with_external( - dep, - source, - context, - Some((external, connection)), - ); - } else if let Some(dep) = reexport { - ESMExportImportedSpecifierDependencyTemplate - .render_external(dep, external, connection, context); - } - } -} diff --git a/crates/rspack_plugin_esm_library/src/dependency/mod.rs b/crates/rspack_plugin_esm_library/src/dependency/mod.rs index 9460e14eeeaf..f0e0f22cc9c5 100644 --- a/crates/rspack_plugin_esm_library/src/dependency/mod.rs +++ b/crates/rspack_plugin_esm_library/src/dependency/mod.rs @@ -1,6 +1,5 @@ pub mod commonjs_external; pub mod dyn_import; -pub mod esm_external; use rspack_cacheable::{cacheable, cacheable_dyn}; use rspack_core::{ @@ -8,7 +7,7 @@ use rspack_core::{ TemplateReplaceSource, }; -/// Keep generated external bindings outside issuers that use Rspack's identifier +/// Keep generated CommonJS external bindings outside issuers using Rspack's identifier /// namespace. Persist this parser result with the module, including nested scopes. #[cacheable] #[derive(Debug)] @@ -16,7 +15,7 @@ pub(crate) struct ExternalBindingBailout; impl ExternalBindingBailout { pub fn template_type() -> DependencyTemplateType { - DependencyTemplateType::Custom("EsmExternalBindingBailout") + DependencyTemplateType::Custom("CommonJsExternalBindingBailout") } pub fn is_present(module: &dyn Module) -> bool { diff --git a/crates/rspack_plugin_esm_library/src/esm_lib_parser_plugin.rs b/crates/rspack_plugin_esm_library/src/esm_lib_parser_plugin.rs index a741e47cbe68..9987955b9cd7 100644 --- a/crates/rspack_plugin_esm_library/src/esm_lib_parser_plugin.rs +++ b/crates/rspack_plugin_esm_library/src/esm_lib_parser_plugin.rs @@ -12,14 +12,20 @@ pub struct EsmLibParserPlugin; #[rspack_plugin_javascript::implemented_javascript_parser_hooks] impl<'p, 'a> JavascriptParserPlugin<'p, 'a> for EsmLibParserPlugin { fn finish(&self, parser: &mut JavascriptParser<'p>) -> Option { - // These bindings are introduced after parsing. A source-level collision + // Direct CommonJS external bindings are introduced after parsing. A collision // cannot be repaired by the linker's top-level deconfliction, especially // inside wrapped modules or function parameters. Inspect decoded AST names // so escaped identifiers are covered as well. - if !parser.get_dependencies().is_empty() - && collect_ident(parser.ast.allocator, parser.ast.program) - .iter() - .any(|ident| ident.id.sym.as_str().starts_with("__rspack_")) + if parser.get_dependencies().iter().any(|dep| { + matches!( + dep.dependency_type(), + DependencyType::CjsRequire + | DependencyType::CjsFullRequire + | DependencyType::CjsExportRequire + ) + }) && collect_ident(parser.ast.allocator, parser.ast.program) + .iter() + .any(|ident| ident.id.sym.as_str().starts_with("__rspack_")) { parser.add_presentational_dependency(Arc::new(ExternalBindingBailout)); } diff --git a/crates/rspack_plugin_esm_library/src/link.rs b/crates/rspack_plugin_esm_library/src/link.rs index a2d4a508588b..fed00512cc04 100644 --- a/crates/rspack_plugin_esm_library/src/link.rs +++ b/crates/rspack_plugin_esm_library/src/link.rs @@ -32,7 +32,6 @@ use rspack_util::fx_hash::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet}; use crate::{ EsmLibraryPlugin, chunk_link::{ChunkLinkContext, ExternalInterop, RawImportSource, ReExportFrom, Ref, SymbolRef}, - dependency::esm_external::DirectEsmExternalDependencies, }; pub(crate) trait GetMut { @@ -474,17 +473,18 @@ impl EsmLibraryPlugin { let raw_import_source = RawImportSource::Source((source.clone(), attr.clone())); if imported_atoms - .namespaces - .iter() - .any(|namespace| info.get_internal_name(namespace).unwrap_or(namespace) == local_name) - || (info.namespace_export_symbol.is_some() - && info.namespace_object_name.as_ref() == Some(local_name)) + .namespace + .as_ref() + .is_some_and(|namespace| namespace == local_name) + || info.namespace_object_name.as_ref() == Some(local_name) { return Some((raw_import_source, ExternalImportBinding::Namespace)); } - for (local, imported_name) in &imported_atoms.specifiers { - let internal_name = info.get_internal_name(local).unwrap_or(local); + for imported_name in &imported_atoms.specifiers { + let internal_name = info + .get_internal_name(imported_name) + .unwrap_or(imported_name); if internal_name != local_name { continue; } @@ -501,9 +501,7 @@ impl EsmLibraryPlugin { } } - if info.namespace_export_symbol.is_some() - && info.namespace_object_name.as_ref() == Some(local_name) - { + if info.namespace_object_name.as_ref() == Some(local_name) { return Self::collect_module_external_namespace_imports(&info.chunk_init_fragments) .into_iter() .next() @@ -820,57 +818,28 @@ impl EsmLibraryPlugin { .build_module_graph_artifact .side_effects_state_artifact, binding_resolver.context.exports_info_artifact, - &self.direct_esm_external_dependencies, &mut namespace_re_export_star_cache, ) .and_then(|target_module| { - if let Some(external) = module_graph - .module_by_identifier(&target_module) - .and_then(|module| module.as_external_module()) - && compilation - .build_chunk_graph_artifact - .chunk_graph - .try_get_module_chunks(&target_module) - .is_none_or(|chunks| chunks.is_empty()) - { - let import_source = RawImportSource::Source(( - external.get_request().primary().into(), - external.module_import_attributes(), - )); - let existing = chunk_link - .module_external_namespace_imports - .get(&import_source) - .cloned(); - let imports = chunk_link - .raw_import_stmts - .entry(import_source) - .or_default(); - let local = imports.ns_import.get_or_insert_with(|| { - existing.unwrap_or_else(|| chunk_link.name_allocator.find_new_name("external", &[])) - }); - return Some(local.to_string()); - } let target_strict_esm_module = module_graph .module_by_identifier(&target_module) .expect("should have target module") .build_meta() .strict_esm_module(); - self - .get_binding( - None, - &mut binding_resolver, - &target_module, - vec![], - &mut needed_namespace_objects, - false, - false, - target_strict_esm_module, - None, - &mut chunk_link.required, - &mut chunk_link.name_allocator, - ) - .map(|binding| binding.render().into_owned()) + self.get_binding( + None, + &mut binding_resolver, + &target_module, + vec![], + &mut needed_namespace_objects, + false, + false, + target_strict_esm_module, + None, + &mut chunk_link.required, + &mut chunk_link.name_allocator, + ) }); let star_re_export_getters = if let Some(binding) = star_re_export_binding { let star_exports_base = format!("{name}_starExports"); @@ -887,7 +856,7 @@ Object.keys({}).forEach(function(key) {{ }}); "#, star_exports_name, - binding, + binding.render(), star_exports_name, runtime_template.render_runtime_globals(&RuntimeGlobals::DEFINE_PROPERTY_GETTERS), name, @@ -1138,40 +1107,57 @@ var {} = {{}}; if let Some(import_map) = concate_info.import_map.take() { for ((source, attr), imported_atoms) in &import_map { let raw_import_source = RawImportSource::Source((source.clone(), attr.clone())); - let mut existing_namespace_import = chunk_link + let existing_namespace_import = chunk_link .module_external_namespace_imports .get(&raw_import_source) - .or_else(|| { - chunk_link - .raw_import_stmts - .get(&raw_import_source) - .and_then(|spec| spec.ns_import.as_ref()) - }) .cloned(); - for ns_import in &imported_atoms.namespaces { - let local = existing_namespace_import.get_or_insert_with(|| { - let local = name_allocator.find_new_name(ns_import, &[]); + let mut total_imported_atoms = None; + + if imported_atoms.namespace.is_none() + && imported_atoms.specifiers.is_empty() + && existing_namespace_import.is_none() + { + total_imported_atoms = Some( chunk_link .raw_import_stmts .entry(raw_import_source.clone()) - .or_default() - .ns_import = Some(local.clone()); - local - }); - concate_info - .internal_names - .insert(ns_import.clone(), local.clone()); + .or_default(), + ); } - if imported_atoms.specifiers.is_empty() && existing_namespace_import.is_some() { - continue; + if let Some(ns_import) = &imported_atoms.namespace { + if let Some(existing_local) = existing_namespace_import.as_ref() { + if existing_local != ns_import { + concate_info + .internal_names + .insert(ns_import.clone(), existing_local.clone()); + } + } else { + total_imported_atoms = Some( + chunk_link + .raw_import_stmts + .entry(raw_import_source.clone()) + .or_default(), + ); + total_imported_atoms + .as_mut() + .expect("should have import spec") + .ns_import = Some(ns_import.clone()); + } } - // Also register side-effect-only imports when no namespace already covers them. - let total_imported_atoms = chunk_link - .raw_import_stmts - .entry(raw_import_source) - .or_default(); - for (local_name, atom) in &imported_atoms.specifiers { + + for atom in &imported_atoms.specifiers { + if total_imported_atoms.is_none() { + total_imported_atoms = Some( + chunk_link + .raw_import_stmts + .entry(raw_import_source.clone()) + .or_default(), + ); + } + let total_imported_atoms = total_imported_atoms + .as_mut() + .expect("should have import spec"); let existing_name = total_imported_atoms.atoms.get(atom).or_else(|| { if atom == "default" && let Some(default_symbol) = &total_imported_atoms.default_import @@ -1182,7 +1168,6 @@ var {} = {{}}; } }); let new_name = name_allocator.assign_import_binding_name( - local_name, atom, existing_name, source, @@ -1549,14 +1534,12 @@ var {} = {{}}; require_info } - #[allow(clippy::too_many_arguments)] fn resolve_re_export_star_from_unknown( module_id: ModuleIdentifier, module_graph: &ModuleGraph, module_graph_cache: &ModuleGraphCacheArtifact, side_effects_state_artifact: &SideEffectsStateArtifact, exports_info_artifact: &ExportsInfoArtifact, - direct: &DirectEsmExternalDependencies, collect_own_exports: bool, cache: &mut IdentifierMap>>, ) -> FxIndexSet> { @@ -1590,12 +1573,8 @@ var {} = {{}}; FxIndexSet::default() }; - let connections = direct.borrow(); for dep in module.get_dependencies() { - let Some(conn) = connections - .get(dep.id()) - .or_else(|| module_graph.connection_by_dependency_id(dep.id())) - else { + let Some(conn) = module_graph.connection_by_dependency_id(dep.id()) else { continue; }; @@ -1627,7 +1606,6 @@ var {} = {{}}; module_graph_cache, side_effects_state_artifact, exports_info_artifact, - direct, true, cache, )); @@ -1648,7 +1626,6 @@ var {} = {{}}; module_graph_cache: &ModuleGraphCacheArtifact, side_effects_state_artifact: &SideEffectsStateArtifact, exports_info_artifact: &ExportsInfoArtifact, - direct: &DirectEsmExternalDependencies, cache: &mut IdentifierMap>>, ) -> Option { let mut star_target = None; @@ -1658,7 +1635,6 @@ var {} = {{}}; module_graph_cache, side_effects_state_artifact, exports_info_artifact, - direct, false, cache, ) { @@ -1854,7 +1830,6 @@ var {} = {{}}; .build_module_graph_artifact .side_effects_state_artifact, binding_resolver.context.exports_info_artifact, - &self.direct_esm_external_dependencies, // When filter_unused is true, own exports are already collected and filtered // by usage above — only collect `export *` targets here. // When filter_unused is false (entry modules), also collect own exports. @@ -2822,14 +2797,6 @@ var {} = {{}}; None } }) - .chain(chunk_link.hoisted_modules.iter().flat_map(|module| { - let info = binding_resolver.module_to_info_map[module].as_concatenated(); - info.idents.iter().filter_map(move |ident| { - (ident.id.ctxt == info.module_ctxt) - .then(|| info.get_internal_name(&ident.id.sym)) - .flatten() - }) - })) .collect::>(); let all_chunk_exported_symbols = &exports[&chunk_link.chunk].exports; @@ -2855,9 +2822,7 @@ var {} = {{}}; continue; }; - if (specifiers.atoms.is_empty() && specifiers.default_import.is_none()) - || specifiers.ns_import.is_some() - { + if specifiers.atoms.is_empty() && specifiers.default_import.is_none() { // import 'externals' continue; } diff --git a/crates/rspack_plugin_esm_library/src/plugin.rs b/crates/rspack_plugin_esm_library/src/plugin.rs index 33032e9ba40d..06968a750b6d 100644 --- a/crates/rspack_plugin_esm_library/src/plugin.rs +++ b/crates/rspack_plugin_esm_library/src/plugin.rs @@ -30,9 +30,7 @@ use rspack_plugin_javascript::{ JavascriptModulesRenderChunkContent, JsPlugin, RenderSource, dependency::{ CommonJsExportRequireDependencyTemplate, CommonJsFullRequireDependencyTemplate, - CommonJsRequireDependencyTemplate, ESMExportImportedSpecifierDependencyTemplate, - ESMImportSideEffectDependencyTemplate, ESMImportSpecifierDependencyTemplate, - ImportDependencyTemplate, RequireHeaderDependencyTemplate, + CommonJsRequireDependencyTemplate, ImportDependencyTemplate, RequireHeaderDependencyTemplate, }, parser_and_generator::JavaScriptParserAndGenerator, }; @@ -54,9 +52,6 @@ use crate::{ DirectRequireHeaderDependencyTemplate, cutout_commonjs_externals, }, dyn_import::DynamicImportDependencyTemplate, - esm_external::{ - DirectEsmExternalDependencies, DirectEsmExternalDependencyTemplate, cutout_esm_externals, - }, }, esm_lib_parser_plugin::EsmLibParserPlugin, optimize_chunks::{ @@ -90,7 +85,6 @@ pub struct EsmLibraryPlugin { pub(crate) all_dyn_targets: AtomicRefCell, pub(crate) namespace_targets: AtomicRefCell, pub(crate) direct_commonjs_external_dependencies: DirectCommonJsExternalDependencies, - pub(crate) direct_esm_external_dependencies: DirectEsmExternalDependencies, /// module_id → namespace export name in the chunk, for modules whose exports /// were renamed in a multi-module chunk. Written during link, read during code generation. pub(crate) dyn_import_ns_map: Arc>>, @@ -110,7 +104,6 @@ impl EsmLibraryPlugin { Default::default(), Default::default(), Default::default(), - Default::default(), ) } @@ -289,26 +282,10 @@ async fn compilation( compilation: &mut Compilation, _params: &mut CompilationParams, ) -> Result<()> { - self.direct_esm_external_dependencies.borrow_mut().clear(); compilation.set_dependency_template( ExternalBindingBailout::template_type(), Arc::new(ExternalBindingBailout), ); - for template_type in [ - ESMImportSideEffectDependencyTemplate::template_type(), - ESMImportSpecifierDependencyTemplate::template_type(), - ESMExportImportedSpecifierDependencyTemplate::template_type(), - ] { - if let Some(template) = compilation.get_dependency_template(template_type.clone()) { - compilation.set_dependency_template( - template_type, - Arc::new(DirectEsmExternalDependencyTemplate { - direct: self.direct_esm_external_dependencies.clone(), - template, - }), - ); - } - } let hooks = JsPlugin::get_compilation_hooks_mut(compilation.id()); let mut hooks = hooks.write().await; hooks @@ -863,12 +840,6 @@ async fn optimize_dependencies( ) -> Result> { let direct_dependencies = cutout_commonjs_externals(build_module_graph_artifact); *self.direct_commonjs_external_dependencies.borrow_mut() = direct_dependencies; - cutout_esm_externals( - compilation, - build_module_graph_artifact, - exports_info_artifact, - &self.direct_esm_external_dependencies, - ); cutout_dyn_import_externals( false, compilation.options.output.module, 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 3024a4b3eb99..e56913b3dc99 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 @@ -20,15 +20,14 @@ use rspack_core::{ ExportModeReexportDynamicDefault, ExportModeReexportNamedDefault, ExportModeReexportNamespaceObject, ExportModeReexportUndefined, ExportModeUnused, ExportNameOrSpec, ExportPresenceMode, ExportProvided, ExportSpec, ExportsInfoArtifact, - ExportsInfoData, ExportsOfExportsSpec, ExportsSpec, ExportsType, ExternalModule, ForwardId, - ImportAttributes, ImportPhase, InitFragmentExt, InitFragmentKey, InitFragmentStage, - JavascriptParserOptions, LazyUntil, ModuleDependency, ModuleGraph, ModuleGraphCacheArtifact, - ModuleGraphConnection, ModuleIdentifier, NormalInitFragment, NormalReexportItem, - ReferencedExport, ResourceIdentifier, RuntimeCondition, RuntimeGlobals, RuntimeSpec, - SideEffectsStateArtifact, StarReexportsInfo, TemplateContext, TemplateReplaceSource, UsageState, - UsedName, collect_referenced_export_items, create_exports_object_referenced, - create_no_exports_referenced, filter_runtime, get_exports_type, get_runtime_key, - get_terminal_binding, property_access, property_name, + ExportsInfoData, ExportsOfExportsSpec, ExportsSpec, ExportsType, ForwardId, ImportAttributes, + ImportPhase, InitFragmentExt, InitFragmentKey, InitFragmentStage, JavascriptParserOptions, + LazyUntil, ModuleDependency, ModuleGraph, ModuleGraphCacheArtifact, ModuleIdentifier, + NormalInitFragment, NormalReexportItem, ReferencedExport, ResourceIdentifier, RuntimeCondition, + RuntimeGlobals, RuntimeSpec, SideEffectsStateArtifact, StarReexportsInfo, TemplateContext, + TemplateReplaceSource, UsageState, UsedName, collect_referenced_export_items, + create_exports_object_referenced, create_no_exports_referenced, filter_runtime, get_exports_type, + get_runtime_key, get_terminal_binding, property_access, property_name, render_make_deferred_namespace_mode_from_exports_type, to_normal_comment, }; use rspack_error::{Diagnostic, Error, Severity}; @@ -40,7 +39,6 @@ use rustc_hash::{FxHashSet as HashSet, FxHasher}; use super::{ create_resource_identifier_for_esm_dependency, esm_import_dependency::esm_import_dependency_get_linking_error, esm_import_dependency_apply, - esm_import_external, }; use crate::{Atom, connection_active_inline_value_for_esm_export_imported_specifier}; @@ -519,15 +517,6 @@ impl ESMExportImportedSpecifierDependency { } pub fn add_export_fragments(&self, ctxt: &mut TemplateContext, mode: ExportMode) { - self.add_export_fragments_with_connection(ctxt, mode, None); - } - - fn add_export_fragments_with_connection( - &self, - ctxt: &mut TemplateContext, - mode: ExportMode, - connection: Option<&ModuleGraphConnection>, - ) { let module = ctxt.module; let runtime = ctxt.runtime; let compilation = ctxt.compilation; @@ -731,9 +720,7 @@ impl ESMExportImportedSpecifierDependency { let key = InitFragmentKey::ESMImport(format!("reexport (checked) {import_var} {name}")); let runtime_condition = if self.weak() { RuntimeCondition::Boolean(false) - } else if let Some(connection) = - connection.or_else(|| mg.connection_by_dependency_id(self.id())) - { + } else if let Some(connection) = mg.connection_by_dependency_id(self.id()) { filter_runtime(ctxt.runtime, |r| { connection.is_target_active( mg, @@ -1721,64 +1708,6 @@ impl ESMExportImportedSpecifierDependencyTemplate { pub fn template_type() -> DependencyTemplateType { DependencyTemplateType::Dependency(DependencyType::EsmExportImportedSpecifier) } - - pub fn supports_direct_scope_export(mode: &ExportMode) -> bool { - match mode { - ExportMode::Unused(_) - | ExportMode::EmptyStar(_) - | ExportMode::ReexportNamespaceObject(_) - | ExportMode::DynamicReexport(_) => true, - ExportMode::NormalReexport(mode) => mode - .items - .iter() - .all(|item| item.hidden || (!item.checked && item.ids.len() == 1)), - _ => false, - } - } - - pub fn render_external( - &self, - dep: &ESMExportImportedSpecifierDependency, - external: &ExternalModule, - connection: &ModuleGraphConnection, - context: &mut TemplateContext, - ) { - let compilation = context.compilation; - let mode = dep.get_mode( - compilation.get_module_graph(), - context.runtime, - &compilation.module_graph_cache_artifact, - &compilation.exports_info_artifact, - ); - if matches!( - mode, - ExportMode::Unused(_) | ExportMode::EmptyStar(_) | ExportMode::LazyMake - ) { - return; - } - if let Some(scope) = context.concatenation_scope.as_mut() { - match mode { - // The ESM linker follows the original export-star connection and emits - // native reexports, including local-export precedence and live bindings. - ExportMode::DynamicReexport(_) => {} - ExportMode::ReexportNamespaceObject(mode) => { - let binding = external.register_module_import(compilation, scope, None, None); - scope.register_raw_export(mode.name, binding); - } - ExportMode::NormalReexport(mode) => { - for item in mode.items.into_iter().filter(|item| !item.hidden) { - let binding = - external.register_module_import(compilation, scope, item.ids.first(), None); - scope.register_raw_export(item.name, binding); - } - } - _ => unreachable!("unsupported external reexport must retain its module wrapper"), - } - } else { - esm_import_external(external, dep, context); - dep.add_export_fragments_with_connection(context, mode, Some(connection)); - } - } } impl DependencyTemplate for ESMExportImportedSpecifierDependencyTemplate { 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 f1def2a18f28..0646b1e4ba73 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 @@ -12,11 +12,11 @@ use rspack_core::{ DependencyCodeGeneration, DependencyCondition, DependencyConditionFn, DependencyDiagnosticsContext, DependencyId, DependencyLocation, DependencyRange, DependencyTemplate, DependencyTemplateType, DependencyType, ExportProvided, ExportsInfoArtifact, - ExportsType, ExternalModule, ForwardId, ImportAttributes, ImportPhase, InitFragmentExt, - InitFragmentKey, InitFragmentStage, LazyUntil, ModuleDependency, ModuleGraph, - ModuleGraphCacheArtifact, ModuleIdentifier, NormalInitFragment, ProvidedExports, - ReferencedExport, ResourceIdentifier, RuntimeCondition, RuntimeSpec, SideEffectsStateArtifact, - SourceType, TemplateContext, TemplateReplaceSource, TypeReexportPresenceMode, filter_runtime, + ExportsType, ForwardId, ImportAttributes, ImportPhase, InitFragmentExt, InitFragmentKey, + InitFragmentStage, LazyUntil, ModuleDependency, ModuleGraph, ModuleGraphCacheArtifact, + ModuleIdentifier, ProvidedExports, ReferencedExport, ResourceIdentifier, RuntimeCondition, + RuntimeSpec, SideEffectsStateArtifact, SourceType, TemplateContext, TemplateReplaceSource, + TypeReexportPresenceMode, filter_runtime, }; use rspack_error::{Diagnostic, Error, Severity}; @@ -114,42 +114,6 @@ impl ESMImportSideEffectDependency { } } -/// The wrapped-module path uses the same namespace remapping as ExternalModule codegen. -pub fn esm_import_external( - external: &ExternalModule, - dependency: &dyn Dependency, - context: &mut TemplateContext, -) -> String { - let compilation = context.compilation; - let target = compilation - .get_module_graph() - .get_module_by_dependency_id(dependency.id()); - let import_var = compilation.get_import_var( - context.module.identifier(), - target, - external.user_request(), - dependency.get_phase(), - context.runtime, - ); - let (init, expression, fragments) = - external.render_module_namespace(compilation, context.runtime, context.runtime_template); - context.chunk_init_fragments().extend(fragments); - context.init_fragments.push( - NormalInitFragment::new( - format!( - "{}var {import_var} = {expression};\n", - init.unwrap_or_default() - ), - InitFragmentStage::StageESMImports, - dependency.source_order().unwrap_or_default(), - InitFragmentKey::Const(format!("direct external {import_var}")), - None, - ) - .boxed(), - ); - import_var -} - pub fn esm_import_dependency_apply( module_dependency: &T, source_order: i32, diff --git a/crates/rspack_plugin_javascript/src/dependency/esm/esm_import_specifier_dependency.rs b/crates/rspack_plugin_javascript/src/dependency/esm/esm_import_specifier_dependency.rs index f8d74aa58792..94ac3adcfd3b 100644 --- a/crates/rspack_plugin_javascript/src/dependency/esm/esm_import_specifier_dependency.rs +++ b/crates/rspack_plugin_javascript/src/dependency/esm/esm_import_specifier_dependency.rs @@ -7,7 +7,7 @@ use rspack_core::{ AsContextDependency, ConnectionState, Dependency, DependencyCategory, DependencyCodeGeneration, DependencyCondition, DependencyConditionFn, DependencyDiagnosticsContext, DependencyId, DependencyLocation, DependencyRange, DependencyTemplate, DependencyTemplateType, DependencyType, - ExportPresenceMode, ExportProvided, ExportsInfoArtifact, ExportsType, ExternalModule, ForwardId, + ExportPresenceMode, ExportProvided, ExportsInfoArtifact, ExportsType, ForwardId, ImportAttributes, ImportPhase, JavascriptParserOptions, ModuleDependency, ModuleGraph, ModuleGraphCacheArtifact, ModuleGraphConnection, ModuleReferenceOptions, ReferencedExport, ResourceIdentifier, RuntimeSpec, SideEffectsStateArtifact, TemplateContext, @@ -21,7 +21,6 @@ use rspack_util::json_stringify_str; use super::{ create_resource_identifier_for_esm_dependency, esm_import_dependency::esm_import_dependency_get_linking_error, esm_import_dependency_apply, - esm_import_external, }; use crate::{ Atom, connection_active_inline_value_for_esm_import_specifier, connection_active_used_by_exports, @@ -431,32 +430,7 @@ impl ESMImportSpecifierDependencyTemplate { dep: &ESMImportSpecifierDependency, connection: Option<&ModuleGraphConnection>, code_generatable_context: &mut TemplateContext, - external: Option<&ExternalModule>, ) -> String { - if let Some(external) = external - && let Some(scope) = code_generatable_context.concatenation_scope.as_mut() - { - let namespace = ids.is_empty() || dep.ns_access; - let binding = external.register_module_import( - code_generatable_context.compilation, - scope, - if namespace { None } else { ids.first() }, - Some(&dep.name), - ); - let access = format!("{binding}{}", property_access(ids, usize::from(!namespace))); - return if dep.call && dep.direct_import && ids.len() > usize::from(!namespace) { - format!( - "{}(0, {access})", - if dep.shorthand || dep.asi_safe { - "" - } else { - ";" - } - ) - } else { - access - }; - } let TemplateContext { compilation, concatenation_scope, @@ -519,20 +493,14 @@ impl ESMImportSpecifierDependencyTemplate { } else { let mg = code_generatable_context.compilation.get_module_graph(); let target_module = mg.get_module_by_dependency_id(&dep.id); - let import_var = if let Some(external) = external { - esm_import_external(external, dep, code_generatable_context) - } else { - code_generatable_context.compilation.get_import_var( - code_generatable_context.module.identifier(), - target_module, - dep.user_request(), - dep.phase, - code_generatable_context.runtime, - ) - }; - if external.is_none() { - esm_import_dependency_apply(dep, dep.source_order, dep.phase, code_generatable_context); - } + let import_var = code_generatable_context.compilation.get_import_var( + code_generatable_context.module.identifier(), + target_module, + dep.user_request(), + dep.phase, + code_generatable_context.runtime, + ); + esm_import_dependency_apply(dep, dep.source_order, dep.phase, code_generatable_context); let TemplateContext { compilation, module, @@ -566,7 +534,6 @@ impl ESMImportSpecifierDependencyTemplate { connection: Option<&ModuleGraphConnection>, source: &mut TemplateReplaceSource, code_generatable_context: &mut TemplateContext, - external: Option<&ExternalModule>, ) { let Some(con) = connection else { return; @@ -641,7 +608,7 @@ impl ESMImportSpecifierDependencyTemplate { } else { ids }; - let Some(mut used_name) = exports_info + let Some(used_name) = exports_info .get_used_name(&compilation.exports_info_artifact, *runtime, used_name_ids) .and_then(|used_name| match used_name { UsedName::Normal(names) => names.last().cloned(), @@ -650,18 +617,11 @@ impl ESMImportSpecifierDependencyTemplate { else { return; }; - if external.is_some() && code_generatable_context.concatenation_scope.is_some() { - used_name = used_name_ids - .last() - .expect("in operator has a property") - .clone(); - } let code = self.get_code_for_ids( &ids[..(ids.len() - 1)], dep, connection, code_generatable_context, - external, ); source.replace( dep.range.start, @@ -680,18 +640,6 @@ impl DependencyTemplate for ESMImportSpecifierDependencyTemplate { dep: &dyn DependencyCodeGeneration, source: &mut TemplateReplaceSource, code_generatable_context: &mut TemplateContext, - ) { - self.render_with_external(dep, source, code_generatable_context, None); - } -} - -impl ESMImportSpecifierDependencyTemplate { - pub fn render_with_external( - &self, - dep: &dyn DependencyCodeGeneration, - source: &mut TemplateReplaceSource, - code_generatable_context: &mut TemplateContext, - external: Option<(&ExternalModule, &ModuleGraphConnection)>, ) { let dep = dep .as_any() @@ -703,10 +651,7 @@ impl ESMImportSpecifierDependencyTemplate { let runtime = code_generatable_context.runtime; let module_graph = compilation.get_module_graph(); let ids = dep.get_ids(module_graph); - let connection = external - .map(|(_, connection)| connection) - .or_else(|| module_graph.connection_by_dependency_id(&dep.id)); - let external = external.map(|(external, _)| external); + let connection = module_graph.connection_by_dependency_id(&dep.id); // Early return if target is not active and export is not inlined if let Some(con) = connection && !con.is_target_active( @@ -735,12 +680,10 @@ impl ESMImportSpecifierDependencyTemplate { connection, source, code_generatable_context, - external, ); } - let export_expr = - self.get_code_for_ids(ids, dep, connection, code_generatable_context, external); + let export_expr = self.get_code_for_ids(ids, dep, connection, code_generatable_context); if dep.shorthand { source.insert(dep.range.end, format!(": {export_expr}"), None); @@ -748,9 +691,6 @@ impl ESMImportSpecifierDependencyTemplate { source.replace(dep.range.start, dep.range.end, export_expr, None); } - if external.is_some() && code_generatable_context.concatenation_scope.is_some() { - return; - } let module_graph = code_generatable_context.compilation.get_module_graph(); if let Some(referenced_properties) = &dep.referenced_properties_in_destructuring { let mut prefixed_ids = ids.to_vec(); diff --git a/crates/rspack_plugin_javascript/src/dependency/esm/mod.rs b/crates/rspack_plugin_javascript/src/dependency/esm/mod.rs index 770f3a253640..e23572730588 100644 --- a/crates/rspack_plugin_javascript/src/dependency/esm/mod.rs +++ b/crates/rspack_plugin_javascript/src/dependency/esm/mod.rs @@ -33,7 +33,7 @@ pub use self::{ }, esm_import_dependency::{ ESMImportSideEffectDependency, ESMImportSideEffectDependencyTemplate, - esm_import_dependency_apply, esm_import_external, import_emitted_runtime, + esm_import_dependency_apply, import_emitted_runtime, }, esm_import_specifier_dependency::{ ESMImportSpecifierDependency, ESMImportSpecifierDependencyTemplate, diff --git a/tests/rspack-test/configCases/externals/reexport-star/__snapshot__/case1.txt b/tests/rspack-test/configCases/externals/reexport-star/__snapshot__/case1.txt index f06952f3a4ca..097ba02a2b30 100644 --- a/tests/rspack-test/configCases/externals/reexport-star/__snapshot__/case1.txt +++ b/tests/rspack-test/configCases/externals/reexport-star/__snapshot__/case1.txt @@ -5,12 +5,12 @@ import * as __rspack_external_external2_alias_d6100a5a from "external2-alias"; __webpack_require__.add({ 42(__unused_rspack_module, __webpack_exports__, __webpack_require__) { __webpack_require__.r(__webpack_exports__); -var external1__rspack_import_0 = __rspack_external_external1_alias_dd38afe7; +/* import */ var external1__rspack_import_0 = __webpack_require__(322); /* reexport */ var __rspack_reexport = {}; /* reexport */ for( const __rspack_import_key in external1__rspack_import_0) if(__rspack_import_key !== "default") __rspack_reexport[__rspack_import_key] =() => external1__rspack_import_0[__rspack_import_key] /* reexport */ __webpack_require__.d(__webpack_exports__, __rspack_reexport); -var external2__rspack_import_1 = __rspack_external_external2_alias_d6100a5a; +/* import */ var external2__rspack_import_1 = __webpack_require__(101); /* reexport */ var __rspack_reexport = {}; /* reexport */ for( const __rspack_import_key in external2__rspack_import_1) if(__rspack_import_key !== "default") __rspack_reexport[__rspack_import_key] =() => external2__rspack_import_1[__rspack_import_key] @@ -19,6 +19,18 @@ var external2__rspack_import_1 = __rspack_external_external2_alias_d6100a5a; +}, +322(module) { + +module.exports = __rspack_external_external1_alias_dd38afe7; + + +}, +101(module) { + +module.exports = __rspack_external_external2_alias_d6100a5a; + + }, }); __webpack_require__("42"); diff --git a/tests/rspack-test/configCases/externals/reexport-star/__snapshot__/case2.txt b/tests/rspack-test/configCases/externals/reexport-star/__snapshot__/case2.txt index 5b9510177466..4380a93c2e2f 100644 --- a/tests/rspack-test/configCases/externals/reexport-star/__snapshot__/case2.txt +++ b/tests/rspack-test/configCases/externals/reexport-star/__snapshot__/case2.txt @@ -1,5 +1,4 @@ import * as __rspack_external_external1_alias_dd38afe7 from "external1-alias"; -import { a, b } from "external1-alias"; @@ -7,5 +6,8 @@ import { a, b } from "external1-alias"; + +var a = __rspack_external_external1_alias_dd38afe7.a; +var b = __rspack_external_external1_alias_dd38afe7.b; export { __rspack_external_external1_alias_dd38afe7 as n1, a, b }; export * from "external1-alias"; \ No newline at end of file diff --git a/tests/rspack-test/configCases/externals/reexport-star/__snapshot__/case3.txt b/tests/rspack-test/configCases/externals/reexport-star/__snapshot__/case3.txt index 0d5b73c911f3..3af23e5ab247 100644 --- a/tests/rspack-test/configCases/externals/reexport-star/__snapshot__/case3.txt +++ b/tests/rspack-test/configCases/externals/reexport-star/__snapshot__/case3.txt @@ -1,6 +1,7 @@ import "external1-alias"; + const foo = 2 diff --git a/tests/rspack-test/configCases/externals/reexport-star/__snapshot__/case4.txt b/tests/rspack-test/configCases/externals/reexport-star/__snapshot__/case4.txt index 1984044fca54..9e6108c4a9b5 100644 --- a/tests/rspack-test/configCases/externals/reexport-star/__snapshot__/case4.txt +++ b/tests/rspack-test/configCases/externals/reexport-star/__snapshot__/case4.txt @@ -1 +1,7 @@ +import * as __rspack_external_external1_alias_dd38afe7 from "external1-alias"; + + + + + export * from "external1-alias"; \ No newline at end of file diff --git a/tests/rspack-test/configCases/externals/reexport-star/__snapshot__/case5.txt b/tests/rspack-test/configCases/externals/reexport-star/__snapshot__/case5.txt index 8563c30e2ed0..49dabb03122d 100644 --- a/tests/rspack-test/configCases/externals/reexport-star/__snapshot__/case5.txt +++ b/tests/rspack-test/configCases/externals/reexport-star/__snapshot__/case5.txt @@ -1,8 +1,9 @@ -import { foo } from "external1-alias"; +import * as __rspack_external_external1_alias_dd38afe7 from "external1-alias"; -const bar = foo + 1 + +const bar = __rspack_external_external1_alias_dd38afe7.foo + 1 diff --git a/tests/rspack-test/configCases/externals/reexport-star/__snapshot__/case6.txt b/tests/rspack-test/configCases/externals/reexport-star/__snapshot__/case6.txt index 1984044fca54..d6431e01af8b 100644 --- a/tests/rspack-test/configCases/externals/reexport-star/__snapshot__/case6.txt +++ b/tests/rspack-test/configCases/externals/reexport-star/__snapshot__/case6.txt @@ -1 +1,8 @@ +import * as __rspack_external_external1_alias_dd38afe7 from "external1-alias"; + + + + + + export * from "external1-alias"; \ No newline at end of file diff --git a/tests/rspack-test/configCases/externals/reexport-star/__snapshot__/runtimeModeSnapshot/case1.txt b/tests/rspack-test/configCases/externals/reexport-star/__snapshot__/runtimeModeSnapshot/case1.txt index 68f0986a42b0..73a01befb2e6 100644 --- a/tests/rspack-test/configCases/externals/reexport-star/__snapshot__/runtimeModeSnapshot/case1.txt +++ b/tests/rspack-test/configCases/externals/reexport-star/__snapshot__/runtimeModeSnapshot/case1.txt @@ -4,12 +4,12 @@ import * as __rspack_external_external2_alias_d6100a5a from "external2-alias"; moduleFactories.add({ 42(__unused_rspack_module, exports) { makeNamespaceObject(exports); -var external1__rspack_import_0 = __rspack_external_external1_alias_dd38afe7; +/* import */ var external1__rspack_import_0 = rspackRequire(322); /* reexport */ var __rspack_reexport = {}; /* reexport */ for( const __rspack_import_key in external1__rspack_import_0) if(__rspack_import_key !== "default") __rspack_reexport[__rspack_import_key] =() => external1__rspack_import_0[__rspack_import_key] /* reexport */ definePropertyGetters(exports, __rspack_reexport); -var external2__rspack_import_1 = __rspack_external_external2_alias_d6100a5a; +/* import */ var external2__rspack_import_1 = rspackRequire(101); /* reexport */ var __rspack_reexport = {}; /* reexport */ for( const __rspack_import_key in external2__rspack_import_1) if(__rspack_import_key !== "default") __rspack_reexport[__rspack_import_key] =() => external2__rspack_import_1[__rspack_import_key] @@ -18,6 +18,18 @@ var external2__rspack_import_1 = __rspack_external_external2_alias_d6100a5a; +}, +322(module) { + +module.exports = __rspack_external_external1_alias_dd38afe7; + + +}, +101(module) { + +module.exports = __rspack_external_external2_alias_d6100a5a; + + }, }); rspackRequire("42"); diff --git a/tests/rspack-test/configCases/externals/reexport-star/__snapshot__/runtimeModeSnapshot/case2.txt b/tests/rspack-test/configCases/externals/reexport-star/__snapshot__/runtimeModeSnapshot/case2.txt index 5b9510177466..4380a93c2e2f 100644 --- a/tests/rspack-test/configCases/externals/reexport-star/__snapshot__/runtimeModeSnapshot/case2.txt +++ b/tests/rspack-test/configCases/externals/reexport-star/__snapshot__/runtimeModeSnapshot/case2.txt @@ -1,5 +1,4 @@ import * as __rspack_external_external1_alias_dd38afe7 from "external1-alias"; -import { a, b } from "external1-alias"; @@ -7,5 +6,8 @@ import { a, b } from "external1-alias"; + +var a = __rspack_external_external1_alias_dd38afe7.a; +var b = __rspack_external_external1_alias_dd38afe7.b; export { __rspack_external_external1_alias_dd38afe7 as n1, a, b }; export * from "external1-alias"; \ No newline at end of file diff --git a/tests/rspack-test/configCases/externals/reexport-star/__snapshot__/runtimeModeSnapshot/case3.txt b/tests/rspack-test/configCases/externals/reexport-star/__snapshot__/runtimeModeSnapshot/case3.txt index 0d5b73c911f3..3af23e5ab247 100644 --- a/tests/rspack-test/configCases/externals/reexport-star/__snapshot__/runtimeModeSnapshot/case3.txt +++ b/tests/rspack-test/configCases/externals/reexport-star/__snapshot__/runtimeModeSnapshot/case3.txt @@ -1,6 +1,7 @@ import "external1-alias"; + const foo = 2 diff --git a/tests/rspack-test/configCases/externals/reexport-star/__snapshot__/runtimeModeSnapshot/case4.txt b/tests/rspack-test/configCases/externals/reexport-star/__snapshot__/runtimeModeSnapshot/case4.txt index 1984044fca54..9e6108c4a9b5 100644 --- a/tests/rspack-test/configCases/externals/reexport-star/__snapshot__/runtimeModeSnapshot/case4.txt +++ b/tests/rspack-test/configCases/externals/reexport-star/__snapshot__/runtimeModeSnapshot/case4.txt @@ -1 +1,7 @@ +import * as __rspack_external_external1_alias_dd38afe7 from "external1-alias"; + + + + + export * from "external1-alias"; \ No newline at end of file diff --git a/tests/rspack-test/configCases/externals/reexport-star/__snapshot__/runtimeModeSnapshot/case5.txt b/tests/rspack-test/configCases/externals/reexport-star/__snapshot__/runtimeModeSnapshot/case5.txt index 8563c30e2ed0..49dabb03122d 100644 --- a/tests/rspack-test/configCases/externals/reexport-star/__snapshot__/runtimeModeSnapshot/case5.txt +++ b/tests/rspack-test/configCases/externals/reexport-star/__snapshot__/runtimeModeSnapshot/case5.txt @@ -1,8 +1,9 @@ -import { foo } from "external1-alias"; +import * as __rspack_external_external1_alias_dd38afe7 from "external1-alias"; -const bar = foo + 1 + +const bar = __rspack_external_external1_alias_dd38afe7.foo + 1 diff --git a/tests/rspack-test/configCases/externals/reexport-star/__snapshot__/runtimeModeSnapshot/case6.txt b/tests/rspack-test/configCases/externals/reexport-star/__snapshot__/runtimeModeSnapshot/case6.txt index 1984044fca54..d6431e01af8b 100644 --- a/tests/rspack-test/configCases/externals/reexport-star/__snapshot__/runtimeModeSnapshot/case6.txt +++ b/tests/rspack-test/configCases/externals/reexport-star/__snapshot__/runtimeModeSnapshot/case6.txt @@ -1 +1,8 @@ +import * as __rspack_external_external1_alias_dd38afe7 from "external1-alias"; + + + + + + export * from "external1-alias"; \ No newline at end of file diff --git a/tests/rspack-test/configCases/library/modern-module-named-import-externals/rspack.config.mjs b/tests/rspack-test/configCases/library/modern-module-named-import-externals/rspack.config.mjs index c45c5fcce5c7..339605a2902e 100644 --- a/tests/rspack-test/configCases/library/modern-module-named-import-externals/rspack.config.mjs +++ b/tests/rspack-test/configCases/library/modern-module-named-import-externals/rspack.config.mjs @@ -30,42 +30,48 @@ export default { compilation.hooks.processAssets.tap('testcase', (assets) => { const source = assets['test.js'].source(); expect(source).toMatchInlineSnapshot(` - import { HomeLayout as lib_HomeLayout, a } from "externals0"; - import { a as test_a } from "externals1"; - import externals2 from "externals2"; - import * as namespace from "externals3"; - import "externals4"; + import { HomeLayout as external_externals0_HomeLayout, a } from "externals0"; + import { a as external_externals1_a } from "externals1"; + import externals2 from "externals2"; + import * as __rspack_external_externals3 from "externals3"; + import "externals4"; - (function Layout(props) { - const { HomeLayout = lib_HomeLayout } = props; - call({ HomeLayout }); - })() - // re export - // named import - ; - // default import - // namespace import + (function Layout(props) { + const { HomeLayout = external_externals0_HomeLayout } = props; + call({ HomeLayout }); + })() + // re export - // side effect only import + // named import + ; + // default import - test_a; - externals2; - namespace; + // namespace import - export { a }; - `); + + // side effect only import + + + + + external_externals1_a; + externals2; + __rspack_external_externals3; + + export { a }; + `); }); }; this.hooks.compilation.tap('testcase', handler); diff --git a/tests/rspack-test/esmOutputCases/deconflict/asset-preserve-import-external-symbols/__snapshots__/runtimeModeSnapshot/esm.snap.txt b/tests/rspack-test/esmOutputCases/deconflict/asset-preserve-import-external-symbols/__snapshots__/runtimeModeSnapshot/esm.snap.txt deleted file mode 100644 index 1d404996a3af..000000000000 --- a/tests/rspack-test/esmOutputCases/deconflict/asset-preserve-import-external-symbols/__snapshots__/runtimeModeSnapshot/esm.snap.txt +++ /dev/null @@ -1,12 +0,0 @@ -```mjs title=main.mjs -import fileURLToPath from "./assets/fileURLToPath.mjs"; -import readFile from "./assets/readFile.mjs"; -import { readFile as external_fs_readFile } from "fs"; -import { fileURLToPath as external_node_url_fileURLToPath } from "node:url"; -import {fileURLToPath as __rspack_fileURLToPath} from "node:url"; -var __rspack_import_meta_dirname__ = __rspack_dirname(__rspack_fileURLToPath(import.meta.url)); -module.exports = fileURLToPath; -module.exports = readFile; -const generatedDirname = __rspack_import_meta_dirname__ -export { external_fs_readFile as readFile, external_node_url_fileURLToPath as fileURLToPath, fileURLToPath_0 as fileURLToPathAsset, generatedDirname, index_rspack_fileURLToPath as applicationHelperValue, readFile_0 as readFileAsset }; -``` \ No newline at end of file diff --git a/tests/rspack-test/esmOutputCases/dynamic-import/dyn-import-default-interop-external/__snapshots__/esm.snap.txt b/tests/rspack-test/esmOutputCases/dynamic-import/dyn-import-default-interop-external/__snapshots__/esm.snap.txt index 6293831dee6d..0b6637d07dae 100644 --- a/tests/rspack-test/esmOutputCases/dynamic-import/dyn-import-default-interop-external/__snapshots__/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/dynamic-import/dyn-import-default-interop-external/__snapshots__/esm.snap.txt @@ -12,8 +12,9 @@ export {}; ``` ```mjs title=wrapper.mjs -import fs, * as __rspack_external_fs from "fs"; -import { readFile } from "fs"; +import * as __rspack_external_fs from "fs"; + +// fs // ./wrapper.js @@ -21,7 +22,9 @@ import { readFile } from "fs"; ; +var default_0 = __rspack_external_fs["default"]; +var readFile = __rspack_external_fs.readFile; export { __rspack_external_fs as ns, readFile }; -export default fs; +export default default_0; ``` \ No newline at end of file diff --git a/tests/rspack-test/esmOutputCases/dynamic-import/dyn-import-mixed-external-local/__snapshots__/esm.snap.txt b/tests/rspack-test/esmOutputCases/dynamic-import/dyn-import-mixed-external-local/__snapshots__/esm.snap.txt index 480ce5a54802..24b20f8f5a06 100644 --- a/tests/rspack-test/esmOutputCases/dynamic-import/dyn-import-mixed-external-local/__snapshots__/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/dynamic-import/dyn-import-mixed-external-local/__snapshots__/esm.snap.txt @@ -12,6 +12,8 @@ export {}; ``` ```mjs title=wrapper.mjs +// fs + // ./wrapper.js const localValue = 42 diff --git a/tests/rspack-test/esmOutputCases/dynamic-import/dyn-import-module-external-default-named-collision/__snapshots__/esm.snap.txt b/tests/rspack-test/esmOutputCases/dynamic-import/dyn-import-module-external-default-named-collision/__snapshots__/esm.snap.txt index d94ec1966fe0..53a514edfe31 100644 --- a/tests/rspack-test/esmOutputCases/dynamic-import/dyn-import-module-external-default-named-collision/__snapshots__/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/dynamic-import/dyn-import-module-external-default-named-collision/__snapshots__/esm.snap.txt @@ -18,11 +18,15 @@ export {}; ```mjs title=shared.mjs import fs, { readFile } from "fs"; +// fs?2aa6 + // ./a.js const defaultImport = fs +// fs?f4d4 + // ./b.js diff --git a/tests/rspack-test/esmOutputCases/dynamic-import/dyn-import-multi-module-duplicate-external/__snapshots__/esm.snap.txt b/tests/rspack-test/esmOutputCases/dynamic-import/dyn-import-multi-module-duplicate-external/__snapshots__/esm.snap.txt index c5bffd791cf0..e5a7102f279a 100644 --- a/tests/rspack-test/esmOutputCases/dynamic-import/dyn-import-multi-module-duplicate-external/__snapshots__/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/dynamic-import/dyn-import-multi-module-duplicate-external/__snapshots__/esm.snap.txt @@ -72,12 +72,14 @@ __webpack_require__.d(b_namespaceObject, { readFile: () => (readFile) }); -// fs +// fs?2aa6 // ./a.js +// fs?f4d4 + // ./b.js diff --git a/tests/rspack-test/esmOutputCases/dynamic-import/dyn-import-multi-module-duplicate-external/__snapshots__/runtimeModeSnapshot/esm.snap.txt b/tests/rspack-test/esmOutputCases/dynamic-import/dyn-import-multi-module-duplicate-external/__snapshots__/runtimeModeSnapshot/esm.snap.txt index bbdc0375c5f1..ad3015e3ed49 100644 --- a/tests/rspack-test/esmOutputCases/dynamic-import/dyn-import-multi-module-duplicate-external/__snapshots__/runtimeModeSnapshot/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/dynamic-import/dyn-import-multi-module-duplicate-external/__snapshots__/runtimeModeSnapshot/esm.snap.txt @@ -68,12 +68,14 @@ definePropertyGetters(b_namespaceObject, { readFile: () => (readFile) }); -// fs +// fs?2aa6 // ./a.js +// fs?f4d4 + // ./b.js diff --git a/tests/rspack-test/esmOutputCases/dynamic-import/dyn-import-multi-module-namespace-named-external/__snapshots__/esm.snap.txt b/tests/rspack-test/esmOutputCases/dynamic-import/dyn-import-multi-module-namespace-named-external/__snapshots__/esm.snap.txt index ffbf59be5e71..454b48ae094d 100644 --- a/tests/rspack-test/esmOutputCases/dynamic-import/dyn-import-multi-module-namespace-named-external/__snapshots__/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/dynamic-import/dyn-import-multi-module-namespace-named-external/__snapshots__/esm.snap.txt @@ -71,11 +71,15 @@ __webpack_require__.d(b_namespaceObject, { resolve: () => (resolve) }); +// path?2d49 + // ./a.js +// path?2b46 + // ./b.js diff --git a/tests/rspack-test/esmOutputCases/dynamic-import/dyn-import-multi-module-namespace-named-external/__snapshots__/runtimeModeSnapshot/esm.snap.txt b/tests/rspack-test/esmOutputCases/dynamic-import/dyn-import-multi-module-namespace-named-external/__snapshots__/runtimeModeSnapshot/esm.snap.txt index d8c000c7af22..5b761b156aaf 100644 --- a/tests/rspack-test/esmOutputCases/dynamic-import/dyn-import-multi-module-namespace-named-external/__snapshots__/runtimeModeSnapshot/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/dynamic-import/dyn-import-multi-module-namespace-named-external/__snapshots__/runtimeModeSnapshot/esm.snap.txt @@ -67,11 +67,15 @@ definePropertyGetters(b_namespaceObject, { resolve: () => (resolve) }); +// path?2d49 + // ./a.js +// path?2b46 + // ./b.js diff --git a/tests/rspack-test/esmOutputCases/dynamic-import/dyn-import-multi-module-namespace-source-conflict/__snapshots__/esm.snap.txt b/tests/rspack-test/esmOutputCases/dynamic-import/dyn-import-multi-module-namespace-source-conflict/__snapshots__/esm.snap.txt index d257410aba27..24ab0a4677f5 100644 --- a/tests/rspack-test/esmOutputCases/dynamic-import/dyn-import-multi-module-namespace-source-conflict/__snapshots__/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/dynamic-import/dyn-import-multi-module-namespace-source-conflict/__snapshots__/esm.snap.txt @@ -18,11 +18,15 @@ export {}; import * as __rspack_external_fs from "fs"; import * as __rspack_external_path from "path"; +// fs + // ./a.js +// path + // ./b.js diff --git a/tests/rspack-test/esmOutputCases/dynamic-import/dyn-import-multi-module-re-export/__snapshots__/esm.snap.txt b/tests/rspack-test/esmOutputCases/dynamic-import/dyn-import-multi-module-re-export/__snapshots__/esm.snap.txt index 9f7619f81418..3a44d82f028e 100644 --- a/tests/rspack-test/esmOutputCases/dynamic-import/dyn-import-multi-module-re-export/__snapshots__/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/dynamic-import/dyn-import-multi-module-re-export/__snapshots__/esm.snap.txt @@ -1,4 +1,6 @@ ```mjs title=ab-chunk.mjs +// fs + // ./a.js @@ -7,6 +9,8 @@ const value = 42 const helper = () => 1 +// path + // ./b.js diff --git a/tests/rspack-test/esmOutputCases/dynamic-import/dyn-import-re-export-external/__snapshots__/esm.snap.txt b/tests/rspack-test/esmOutputCases/dynamic-import/dyn-import-re-export-external/__snapshots__/esm.snap.txt index 9006cc889a28..209df5ca399d 100644 --- a/tests/rspack-test/esmOutputCases/dynamic-import/dyn-import-re-export-external/__snapshots__/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/dynamic-import/dyn-import-re-export-external/__snapshots__/esm.snap.txt @@ -11,6 +11,8 @@ export {}; ``` ```mjs title=wrapper.mjs +// fs + // ./wrapper.js diff --git a/tests/rspack-test/esmOutputCases/externals/aliased/__snapshots__/esm.snap.txt b/tests/rspack-test/esmOutputCases/externals/aliased/__snapshots__/esm.snap.txt index e831b7513ddf..8713819f2c29 100644 --- a/tests/rspack-test/esmOutputCases/externals/aliased/__snapshots__/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/externals/aliased/__snapshots__/esm.snap.txt @@ -1,4 +1,8 @@ ```mjs title=main.mjs +import * as __rspack_external_path from "path"; + +// external + // ./index.js diff --git a/tests/rspack-test/esmOutputCases/externals/create-require-name/__snapshots__/esm.snap.txt b/tests/rspack-test/esmOutputCases/externals/create-require-name/__snapshots__/esm.snap.txt index 5ff6939738a3..f933df9ec1ed 100644 --- a/tests/rspack-test/esmOutputCases/externals/create-require-name/__snapshots__/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/externals/create-require-name/__snapshots__/esm.snap.txt @@ -1,6 +1,8 @@ ```mjs title=main.mjs import { createRequire } from "node:module"; +// node:module + // ./index.js diff --git a/tests/rspack-test/esmOutputCases/externals/create-require-name/__snapshots__/runtimeModeSnapshot/esm.snap.txt b/tests/rspack-test/esmOutputCases/externals/create-require-name/__snapshots__/runtimeModeSnapshot/esm.snap.txt index 5ff6939738a3..f933df9ec1ed 100644 --- a/tests/rspack-test/esmOutputCases/externals/create-require-name/__snapshots__/runtimeModeSnapshot/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/externals/create-require-name/__snapshots__/runtimeModeSnapshot/esm.snap.txt @@ -1,6 +1,8 @@ ```mjs title=main.mjs import { createRequire } from "node:module"; +// node:module + // ./index.js diff --git a/tests/rspack-test/esmOutputCases/externals/dedup-external-imports-mixed/__snapshots__/esm.snap.txt b/tests/rspack-test/esmOutputCases/externals/dedup-external-imports-mixed/__snapshots__/esm.snap.txt index 68e1cc5c0fa6..62c5e38c3ddf 100644 --- a/tests/rspack-test/esmOutputCases/externals/dedup-external-imports-mixed/__snapshots__/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/externals/dedup-external-imports-mixed/__snapshots__/esm.snap.txt @@ -3,7 +3,7 @@ import { __webpack_require__ } from "./runtime.mjs"; import * as __rspack_external_fs from "fs"; __webpack_require__.add({ -"fs" +"fs?94de" /*!*********************!*\ !*** external "fs" ***! \*********************/ @@ -20,12 +20,14 @@ module.exports = __rspack_external_fs; (__unused_rspack_module, exports, __webpack_require__) { // CJS module - will NOT be scope-hoisted, causing its fs dep // to go through init fragment path instead of raw_import_stmts -const fs = __webpack_require__(/*! fs */ "fs") +const fs = __webpack_require__(/*! fs */ "fs?94de") exports.g = fs.readFileSync }, }); +// fs?fa25 + // ./esm-consumer.js // ESM module importing fs namespace - will be scope-hoisted (Concatenated) diff --git a/tests/rspack-test/esmOutputCases/externals/dedup-external-imports-mixed/__snapshots__/runtimeModeSnapshot/esm.snap.txt b/tests/rspack-test/esmOutputCases/externals/dedup-external-imports-mixed/__snapshots__/runtimeModeSnapshot/esm.snap.txt index 848a50de0398..89c975c8fbf2 100644 --- a/tests/rspack-test/esmOutputCases/externals/dedup-external-imports-mixed/__snapshots__/runtimeModeSnapshot/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/externals/dedup-external-imports-mixed/__snapshots__/runtimeModeSnapshot/esm.snap.txt @@ -2,7 +2,7 @@ import { rspackRequire, moduleFactories } from "./runtime.mjs"; import * as __rspack_external_fs from "fs"; moduleFactories.add({ -"fs" +"fs?94de" /*!*********************!*\ !*** external "fs" ***! \*********************/ @@ -19,12 +19,14 @@ module.exports = __rspack_external_fs; (__unused_rspack_module, exports) { // CJS module - will NOT be scope-hoisted, causing its fs dep // to go through init fragment path instead of raw_import_stmts -const fs = rspackRequire(/*! fs */ "fs") +const fs = rspackRequire(/*! fs */ "fs?94de") exports.g = fs.readFileSync }, }); +// fs?fa25 + // ./esm-consumer.js // ESM module importing fs namespace - will be scope-hoisted (Concatenated) diff --git a/tests/rspack-test/esmOutputCases/externals/dedup-external-imports/__snapshots__/esm.snap.txt b/tests/rspack-test/esmOutputCases/externals/dedup-external-imports/__snapshots__/esm.snap.txt index e8b35f69d101..723b9fedd354 100644 --- a/tests/rspack-test/esmOutputCases/externals/dedup-external-imports/__snapshots__/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/externals/dedup-external-imports/__snapshots__/esm.snap.txt @@ -2,9 +2,13 @@ import * as __rspack_external_fs from "fs"; import { readFile } from "fs"; +// fs?f137 + // ./lib.js +// fs?303b + // ./lib2.js diff --git a/tests/rspack-test/esmOutputCases/externals/default-and-namespace/__snapshots__/esm.snap.txt b/tests/rspack-test/esmOutputCases/externals/default-and-namespace/__snapshots__/esm.snap.txt index e1f32dfdf6d4..1ecec45fe60f 100644 --- a/tests/rspack-test/esmOutputCases/externals/default-and-namespace/__snapshots__/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/externals/default-and-namespace/__snapshots__/esm.snap.txt @@ -1,22 +1,24 @@ ```mjs title=main.mjs -import fs, * as fsNs from "fs"; +import * as __rspack_external_fs from "fs"; + +// fs // ./index.js -/* export default */ const index = (fs); +/* export default */ const index = (__rspack_external_fs["default"]); it("should distinguish external default and namespace imports", async () => { const mod = await import(/* webpackIgnore: true */ "./main.mjs"); - expect(mod.default).toBe(fs); - expect(mod.default).toBe(fsNs["default"]); + expect(mod.default).toBe(__rspack_external_fs["default"]); + expect(mod.default).toBe(__rspack_external_fs["default"]); expect(typeof mod.fsNs.readFile).toBe("function"); }); -export { fsNs }; +export { __rspack_external_fs as fsNs }; export default index; ``` \ No newline at end of file diff --git a/tests/rspack-test/esmOutputCases/externals/empty-import/__snapshots__/esm.snap.txt b/tests/rspack-test/esmOutputCases/externals/empty-import/__snapshots__/esm.snap.txt index 68c7dbf92cf5..fa9f9806550a 100644 --- a/tests/rspack-test/esmOutputCases/externals/empty-import/__snapshots__/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/externals/empty-import/__snapshots__/esm.snap.txt @@ -1,6 +1,8 @@ ```mjs title=main.mjs import "fs"; +// fs + // ./index.js export {}; diff --git a/tests/rspack-test/esmOutputCases/externals/esm-node-target-alias/__snapshots__/esm.snap.txt b/tests/rspack-test/esmOutputCases/externals/esm-node-target-alias/__snapshots__/esm.snap.txt index 5d9521b6412c..7a13a9bbe52e 100644 --- a/tests/rspack-test/esmOutputCases/externals/esm-node-target-alias/__snapshots__/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/externals/esm-node-target-alias/__snapshots__/esm.snap.txt @@ -22,6 +22,10 @@ exports.g = nodeUrl.parse; }, }); +// node:fs + +// node:url + // ./index.js const cjs_consumer = __webpack_require__("./cjs-consumer.cjs"); var g = cjs_consumer.g; diff --git a/tests/rspack-test/esmOutputCases/externals/esm-node-target-alias/__snapshots__/runtimeModeSnapshot/esm.snap.txt b/tests/rspack-test/esmOutputCases/externals/esm-node-target-alias/__snapshots__/runtimeModeSnapshot/esm.snap.txt index e12b2a11397e..afdfacc201f0 100644 --- a/tests/rspack-test/esmOutputCases/externals/esm-node-target-alias/__snapshots__/runtimeModeSnapshot/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/externals/esm-node-target-alias/__snapshots__/runtimeModeSnapshot/esm.snap.txt @@ -22,6 +22,10 @@ exports.g = nodeUrl.parse; }, }); +// node:fs + +// node:url + // ./index.js const cjs_consumer = rspackRequire("./cjs-consumer.cjs"); var g = cjs_consumer.g; diff --git a/tests/rspack-test/esmOutputCases/externals/esm-node-target/__snapshots__/esm.snap.txt b/tests/rspack-test/esmOutputCases/externals/esm-node-target/__snapshots__/esm.snap.txt index 009785410d06..24b25b3e89d8 100644 --- a/tests/rspack-test/esmOutputCases/externals/esm-node-target/__snapshots__/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/externals/esm-node-target/__snapshots__/esm.snap.txt @@ -2,6 +2,10 @@ import { resolve } from "path"; import { __webpack_require__ } from "./runtime.mjs"; +// path + +// fs + // ./index.js diff --git a/tests/rspack-test/esmOutputCases/externals/esm-node-target/__snapshots__/runtimeModeSnapshot/esm.snap.txt b/tests/rspack-test/esmOutputCases/externals/esm-node-target/__snapshots__/runtimeModeSnapshot/esm.snap.txt index 7de9a3de432e..25d5c48134ff 100644 --- a/tests/rspack-test/esmOutputCases/externals/esm-node-target/__snapshots__/runtimeModeSnapshot/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/externals/esm-node-target/__snapshots__/runtimeModeSnapshot/esm.snap.txt @@ -2,6 +2,10 @@ import { rspackRequire, createFakeNamespaceObject } from "./runtime.mjs"; import { resolve } from "path"; +// path + +// fs + // ./index.js diff --git a/tests/rspack-test/esmOutputCases/externals/export-namespace-as-with-named-same-source/__snapshots__/esm.snap.txt b/tests/rspack-test/esmOutputCases/externals/export-namespace-as-with-named-same-source/__snapshots__/esm.snap.txt index b4d9fd46bfbe..250c22775274 100644 --- a/tests/rspack-test/esmOutputCases/externals/export-namespace-as-with-named-same-source/__snapshots__/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/externals/export-namespace-as-with-named-same-source/__snapshots__/esm.snap.txt @@ -1,6 +1,7 @@ ```mjs title=main.mjs import * as __rspack_external_fs from "fs"; -import { readFile, readFileSync } from "fs"; + +// fs // ./index.js @@ -13,6 +14,8 @@ it("should combine export-star-as and named exports for the same external source expect(mod.fsNs.readFileSync).toBe(mod.readFileSync); }); +var readFile = __rspack_external_fs.readFile; +var readFileSync = __rspack_external_fs.readFileSync; export { __rspack_external_fs as fsNs, readFile, readFileSync }; ``` \ No newline at end of file diff --git a/tests/rspack-test/esmOutputCases/externals/export-namespace-as/__snapshots__/esm.snap.txt b/tests/rspack-test/esmOutputCases/externals/export-namespace-as/__snapshots__/esm.snap.txt index cddabdbee82f..2537c131c023 100644 --- a/tests/rspack-test/esmOutputCases/externals/export-namespace-as/__snapshots__/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/externals/export-namespace-as/__snapshots__/esm.snap.txt @@ -1,6 +1,8 @@ ```mjs title=main.mjs import * as __rspack_external_fs from "fs"; +// fs + // ./index.js diff --git a/tests/rspack-test/esmOutputCases/externals/externals-aliased/__snapshots__/esm.snap.txt b/tests/rspack-test/esmOutputCases/externals/externals-aliased/__snapshots__/esm.snap.txt index ca556f788a06..a45fc8089479 100644 --- a/tests/rspack-test/esmOutputCases/externals/externals-aliased/__snapshots__/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/externals/externals-aliased/__snapshots__/esm.snap.txt @@ -1,9 +1,13 @@ ```mjs title=main.mjs +// fs?f23b + // ./module.js console.log.bind(console) +// fs?771d + // ./index.js diff --git a/tests/rspack-test/esmOutputCases/externals/externals-import-render/__snapshots__/esm.snap.txt b/tests/rspack-test/esmOutputCases/externals/externals-import-render/__snapshots__/esm.snap.txt index f76dd7745d40..4f9c43227502 100644 --- a/tests/rspack-test/esmOutputCases/externals/externals-import-render/__snapshots__/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/externals/externals-import-render/__snapshots__/esm.snap.txt @@ -2,6 +2,10 @@ import fs from "fs"; import { join, resolve } from "path"; +// fs + +// path + // ./index.js diff --git a/tests/rspack-test/esmOutputCases/externals/import-namespace-reexport-with-named-same-source/__snapshots__/esm.snap.txt b/tests/rspack-test/esmOutputCases/externals/import-namespace-reexport-with-named-same-source/__snapshots__/esm.snap.txt index 14c4f1058bf0..2c168dba93f4 100644 --- a/tests/rspack-test/esmOutputCases/externals/import-namespace-reexport-with-named-same-source/__snapshots__/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/externals/import-namespace-reexport-with-named-same-source/__snapshots__/esm.snap.txt @@ -1,6 +1,7 @@ ```mjs title=main.mjs import * as __rspack_external_fs from "fs"; -import { readFile, readFileSync } from "fs"; + +// fs // ./index.js @@ -15,6 +16,8 @@ it("should re-export an imported external namespace alongside named exports from expect(mod.fsNs.readFileSync).toBe(mod.readFileSync); }); +var readFile = __rspack_external_fs.readFile; +var readFileSync = __rspack_external_fs.readFileSync; export { __rspack_external_fs as fsNs, readFile, readFileSync }; ``` \ No newline at end of file diff --git a/tests/rspack-test/esmOutputCases/externals/import-namespace-reexport-with-named/__snapshots__/esm.snap.txt b/tests/rspack-test/esmOutputCases/externals/import-namespace-reexport-with-named/__snapshots__/esm.snap.txt index d4b80e3980f1..518a9b605557 100644 --- a/tests/rspack-test/esmOutputCases/externals/import-namespace-reexport-with-named/__snapshots__/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/externals/import-namespace-reexport-with-named/__snapshots__/esm.snap.txt @@ -2,6 +2,10 @@ import { sep } from "path"; import * as __rspack_external_fs from "fs"; +// path + +// fs + // ./index.js diff --git a/tests/rspack-test/esmOutputCases/externals/import-namespace-reexport/__snapshots__/esm.snap.txt b/tests/rspack-test/esmOutputCases/externals/import-namespace-reexport/__snapshots__/esm.snap.txt index dd812be7339a..3a76e92218e5 100644 --- a/tests/rspack-test/esmOutputCases/externals/import-namespace-reexport/__snapshots__/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/externals/import-namespace-reexport/__snapshots__/esm.snap.txt @@ -1,6 +1,8 @@ ```mjs title=main.mjs import * as __rspack_external_fs from "fs"; +// fs + // ./index.js diff --git a/tests/rspack-test/esmOutputCases/externals/mixed-module-import-and-node-commonjs-same-target/__snapshots__/esm.snap.txt b/tests/rspack-test/esmOutputCases/externals/mixed-module-import-and-node-commonjs-same-target/__snapshots__/esm.snap.txt index a32b7d8ed7b3..a0d31e24e9a5 100644 --- a/tests/rspack-test/esmOutputCases/externals/mixed-module-import-and-node-commonjs-same-target/__snapshots__/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/externals/mixed-module-import-and-node-commonjs-same-target/__snapshots__/esm.snap.txt @@ -3,6 +3,8 @@ import * as __rspack_external_webpack_sources_lib_index_js_9a113ddb from "webpac import { createRequire as __rspack_createRequire } from "node:module"; const __rspack_createRequire_require = __rspack_createRequire(import.meta.url); +// ws-ns + // ./namespace.js diff --git a/tests/rspack-test/esmOutputCases/externals/multiple-externals/__snapshots__/esm.snap.txt b/tests/rspack-test/esmOutputCases/externals/multiple-externals/__snapshots__/esm.snap.txt index af1bbb09722e..9a5a52a68e8b 100644 --- a/tests/rspack-test/esmOutputCases/externals/multiple-externals/__snapshots__/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/externals/multiple-externals/__snapshots__/esm.snap.txt @@ -1,25 +1,33 @@ ```mjs title=async.mjs -import * as ns from "fs"; +import * as __rspack_external_fs from "fs"; + +// fs?3cf4 // ./async.js // access namespace -console.log.bind(ns) +console.log.bind(__rspack_external_fs) -export { ns }; +export { __rspack_external_fs as ns }; ``` ```mjs title=main.mjs import fs, { readFile } from "fs"; +// fs?771d + +// fs?5ccf + // ./other.js /* export default */ const other = (fs); +// fs?22cf + // ./other2.js diff --git a/tests/rspack-test/esmOutputCases/externals/named-import-scope-hoisted/__snapshots__/esm.snap.txt b/tests/rspack-test/esmOutputCases/externals/named-import-scope-hoisted/__snapshots__/esm.snap.txt index 880be4484ea7..2788b489eb9b 100644 --- a/tests/rspack-test/esmOutputCases/externals/named-import-scope-hoisted/__snapshots__/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/externals/named-import-scope-hoisted/__snapshots__/esm.snap.txt @@ -1,6 +1,8 @@ ```mjs title=main.mjs import { readFile } from "fs"; +// virtual-fs + // ./index.js diff --git a/tests/rspack-test/esmOutputCases/externals/namespace-and-named/__snapshots__/esm.snap.txt b/tests/rspack-test/esmOutputCases/externals/namespace-and-named/__snapshots__/esm.snap.txt index 249b7f66e5bb..e440dcaab1aa 100644 --- a/tests/rspack-test/esmOutputCases/externals/namespace-and-named/__snapshots__/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/externals/namespace-and-named/__snapshots__/esm.snap.txt @@ -1,14 +1,14 @@ ```mjs title=main.mjs -import * as fsNs from "fs"; -import { readFile, readFileSync } from "fs"; +import * as __rspack_external_fs from "fs"; +// fs // ./index.js it("should keep namespace and named external imports aligned", () => { - expect(fsNs.readFile).toBe(readFile); - expect(fsNs.readFileSync).toBe(readFileSync); + expect(__rspack_external_fs.readFile).toBe(__rspack_external_fs.readFile); + expect(__rspack_external_fs.readFileSync).toBe(__rspack_external_fs.readFileSync); }); export {}; diff --git a/tests/rspack-test/esmOutputCases/externals/namespace-member-access/__snapshots__/esm.snap.txt b/tests/rspack-test/esmOutputCases/externals/namespace-member-access/__snapshots__/esm.snap.txt index fda0d0b8d4a1..cb58462d6b13 100644 --- a/tests/rspack-test/esmOutputCases/externals/namespace-member-access/__snapshots__/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/externals/namespace-member-access/__snapshots__/esm.snap.txt @@ -1,11 +1,12 @@ ```mjs title=main.mjs -import * as fsNs from "fs"; +import * as __rspack_external_fs from "fs"; +// fs // ./index.js it('should keep namespace import for external namespace member access', () => { - expect(fsNs.readFile).toBeDefined() + expect(__rspack_external_fs.readFile).toBeDefined() }) export {}; diff --git a/tests/rspack-test/esmOutputCases/externals/namespace-name-collision-across-modules/__snapshots__/esm.snap.txt b/tests/rspack-test/esmOutputCases/externals/namespace-name-collision-across-modules/__snapshots__/esm.snap.txt index d3d323cf1915..f56116763bd8 100644 --- a/tests/rspack-test/esmOutputCases/externals/namespace-name-collision-across-modules/__snapshots__/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/externals/namespace-name-collision-across-modules/__snapshots__/esm.snap.txt @@ -1,6 +1,8 @@ ```mjs title=main.mjs import * as __rspack_external_path from "path"; +// fs + // ./named.js diff --git a/tests/rspack-test/esmOutputCases/externals/namespace-name-collision-across-modules/__snapshots__/runtimeModeSnapshot/esm.snap.txt b/tests/rspack-test/esmOutputCases/externals/namespace-name-collision-across-modules/__snapshots__/runtimeModeSnapshot/esm.snap.txt deleted file mode 100644 index d3d323cf1915..000000000000 --- a/tests/rspack-test/esmOutputCases/externals/namespace-name-collision-across-modules/__snapshots__/runtimeModeSnapshot/esm.snap.txt +++ /dev/null @@ -1,35 +0,0 @@ -```mjs title=main.mjs -import * as __rspack_external_path from "path"; - -// ./named.js - - -// path - -// ./path-ns.js - - -const joinFn = Reflect.get(__rspack_external_path, "join"); - - - -// ./index.js - - - -it("should deconflict concatenated namespace imports that match generated module-import names", async () => { - const mod = await import(/* webpackIgnore: true */ "./main.mjs"); - const fs = await import("fs"); - const path = await import("path"); - - expect(mod.readFile).toBe(fs.readFile); - expect(mod.readFileSync).toBe(fs.readFileSync); - expect(mod.pathNs.sep).toBe(path.sep); - expect(mod.pathNs.join).toBe(path.join); - expect(mod.joinFn).toBe(path.join); -}); - -export { __rspack_external_path as pathNs, joinFn }; -export { readFile, readFileSync } from "fs"; - -``` \ No newline at end of file diff --git a/tests/rspack-test/esmOutputCases/externals/override-star-reexport/__snapshots__/esm.snap.txt b/tests/rspack-test/esmOutputCases/externals/override-star-reexport/__snapshots__/esm.snap.txt index 5d7438757a30..b9a97b47d049 100644 --- a/tests/rspack-test/esmOutputCases/externals/override-star-reexport/__snapshots__/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/externals/override-star-reexport/__snapshots__/esm.snap.txt @@ -1,4 +1,8 @@ ```mjs title=main.mjs +import * as __rspack_external_fs from "fs"; + +// fs + // ./index.js diff --git a/tests/rspack-test/esmOutputCases/externals/probe-namespace-properties/__snapshots__/esm.snap.txt b/tests/rspack-test/esmOutputCases/externals/probe-namespace-properties/__snapshots__/esm.snap.txt index b57053c5f561..8415bc9ac55c 100644 --- a/tests/rspack-test/esmOutputCases/externals/probe-namespace-properties/__snapshots__/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/externals/probe-namespace-properties/__snapshots__/esm.snap.txt @@ -1,5 +1,7 @@ ```mjs title=main.mjs -import * as fsNs from "fs"; +import * as __rspack_external_fs from "fs"; + +// fs // ./index.js @@ -8,9 +10,9 @@ it("should allow probing external namespace properties", () => { const presentKey = ["read", "File"].join(""); const missingKey = ["not", "There"].join(""); - expect(fsNs["default"]).toBeDefined(); - expect(Reflect.get(fsNs, presentKey)).toBeDefined(); - expect(Reflect.get(fsNs, missingKey)).toBeUndefined(); + expect(__rspack_external_fs["default"]).toBeDefined(); + expect(Reflect.get(__rspack_external_fs, presentKey)).toBeDefined(); + expect(Reflect.get(__rspack_external_fs, missingKey)).toBeUndefined(); }); export {}; diff --git a/tests/rspack-test/esmOutputCases/externals/reexport-external-namespace-as/__snapshots__/esm.snap.txt b/tests/rspack-test/esmOutputCases/externals/reexport-external-namespace-as/__snapshots__/esm.snap.txt index fecf60a91244..1709d0a284d4 100644 --- a/tests/rspack-test/esmOutputCases/externals/reexport-external-namespace-as/__snapshots__/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/externals/reexport-external-namespace-as/__snapshots__/esm.snap.txt @@ -1,6 +1,8 @@ ```mjs title=main.mjs import * as __rspack_external_fs from "fs"; +// fs + // ./index.js diff --git a/tests/rspack-test/esmOutputCases/externals/reexport-imported-namespace-via-module/__snapshots__/esm.snap.txt b/tests/rspack-test/esmOutputCases/externals/reexport-imported-namespace-via-module/__snapshots__/esm.snap.txt index 2e8b635603e2..9d5269cefb61 100644 --- a/tests/rspack-test/esmOutputCases/externals/reexport-imported-namespace-via-module/__snapshots__/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/externals/reexport-imported-namespace-via-module/__snapshots__/esm.snap.txt @@ -1,6 +1,8 @@ ```mjs title=main.mjs import * as __rspack_external_fs from "fs"; +// fs + // ./dep.js diff --git a/tests/rspack-test/esmOutputCases/externals/reexport-star-as-namespace-via-module-with-own-export/__snapshots__/esm.snap.txt b/tests/rspack-test/esmOutputCases/externals/reexport-star-as-namespace-via-module-with-own-export/__snapshots__/esm.snap.txt index e63e239bf625..9f62ec88a555 100644 --- a/tests/rspack-test/esmOutputCases/externals/reexport-star-as-namespace-via-module-with-own-export/__snapshots__/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/externals/reexport-star-as-namespace-via-module-with-own-export/__snapshots__/esm.snap.txt @@ -1,6 +1,6 @@ ```mjs title=main.mjs import { __webpack_require__ } from "./runtime.mjs"; -import * as external from "fs"; +import * as __rspack_external_fs from "fs"; // NAMESPACE OBJECT: ./reexport-external.js var reexport_external_namespaceObject = {}; @@ -8,7 +8,7 @@ __webpack_require__.r(reexport_external_namespaceObject); __webpack_require__.d(reexport_external_namespaceObject, { marker: () => (marker), readFile: () => (readFile) }); -var reexport_external_namespaceObject_starExports = external; +var reexport_external_namespaceObject_starExports = __rspack_external_fs; Object.keys(reexport_external_namespaceObject_starExports).forEach(function(key) { if (key !== "default" && key !== "__esModule") { __webpack_require__.d(reexport_external_namespaceObject, { [key]: function() { return reexport_external_namespaceObject_starExports[key]; } }); @@ -16,6 +16,8 @@ Object.keys(reexport_external_namespaceObject_starExports).forEach(function(key) }); +// fs + // ./reexport-external.js diff --git a/tests/rspack-test/esmOutputCases/externals/reexport-star-as-namespace-via-module-with-own-export/__snapshots__/runtimeModeSnapshot/esm.snap.txt b/tests/rspack-test/esmOutputCases/externals/reexport-star-as-namespace-via-module-with-own-export/__snapshots__/runtimeModeSnapshot/esm.snap.txt index d1d61766fcc5..983523a8c455 100644 --- a/tests/rspack-test/esmOutputCases/externals/reexport-star-as-namespace-via-module-with-own-export/__snapshots__/runtimeModeSnapshot/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/externals/reexport-star-as-namespace-via-module-with-own-export/__snapshots__/runtimeModeSnapshot/esm.snap.txt @@ -1,6 +1,6 @@ ```mjs title=main.mjs import { rspackRequire, definePropertyGetters, makeNamespaceObject } from "./runtime.mjs"; -import * as external from "fs"; +import * as __rspack_external_fs from "fs"; // NAMESPACE OBJECT: ./reexport-external.js var reexport_external_namespaceObject = {}; @@ -8,7 +8,7 @@ makeNamespaceObject(reexport_external_namespaceObject); definePropertyGetters(reexport_external_namespaceObject, { marker: () => (marker), readFile: () => (readFile) }); -var reexport_external_namespaceObject_starExports = external; +var reexport_external_namespaceObject_starExports = __rspack_external_fs; Object.keys(reexport_external_namespaceObject_starExports).forEach(function(key) { if (key !== "default" && key !== "__esModule") { definePropertyGetters(reexport_external_namespaceObject, { [key]: function() { return reexport_external_namespaceObject_starExports[key]; } }); @@ -16,6 +16,8 @@ Object.keys(reexport_external_namespaceObject_starExports).forEach(function(key) }); +// fs + // ./reexport-external.js diff --git a/tests/rspack-test/esmOutputCases/externals/reexport-star-as-namespace-via-module/__snapshots__/esm.snap.txt b/tests/rspack-test/esmOutputCases/externals/reexport-star-as-namespace-via-module/__snapshots__/esm.snap.txt index 705cc897d97c..b35f0fbdc542 100644 --- a/tests/rspack-test/esmOutputCases/externals/reexport-star-as-namespace-via-module/__snapshots__/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/externals/reexport-star-as-namespace-via-module/__snapshots__/esm.snap.txt @@ -1,11 +1,11 @@ ```mjs title=main.mjs import { __webpack_require__ } from "./runtime.mjs"; -import * as external from "fs"; +import * as __rspack_external_fs from "fs"; // NAMESPACE OBJECT: ./reexport-external.js var reexport_external_namespaceObject = {}; __webpack_require__.r(reexport_external_namespaceObject); -var reexport_external_namespaceObject_starExports = external; +var reexport_external_namespaceObject_starExports = __rspack_external_fs; Object.keys(reexport_external_namespaceObject_starExports).forEach(function(key) { if (key !== "default" && key !== "__esModule") { __webpack_require__.d(reexport_external_namespaceObject, { [key]: function() { return reexport_external_namespaceObject_starExports[key]; } }); @@ -13,6 +13,8 @@ Object.keys(reexport_external_namespaceObject_starExports).forEach(function(key) }); +// fs + // ./reexport-external.js diff --git a/tests/rspack-test/esmOutputCases/externals/reexport-star-as-namespace-via-module/__snapshots__/runtimeModeSnapshot/esm.snap.txt b/tests/rspack-test/esmOutputCases/externals/reexport-star-as-namespace-via-module/__snapshots__/runtimeModeSnapshot/esm.snap.txt index 154ba280d364..a427d8e70b4b 100644 --- a/tests/rspack-test/esmOutputCases/externals/reexport-star-as-namespace-via-module/__snapshots__/runtimeModeSnapshot/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/externals/reexport-star-as-namespace-via-module/__snapshots__/runtimeModeSnapshot/esm.snap.txt @@ -1,11 +1,11 @@ ```mjs title=main.mjs import { rspackRequire, definePropertyGetters, makeNamespaceObject } from "./runtime.mjs"; -import * as external from "fs"; +import * as __rspack_external_fs from "fs"; // NAMESPACE OBJECT: ./reexport-external.js var reexport_external_namespaceObject = {}; makeNamespaceObject(reexport_external_namespaceObject); -var reexport_external_namespaceObject_starExports = external; +var reexport_external_namespaceObject_starExports = __rspack_external_fs; Object.keys(reexport_external_namespaceObject_starExports).forEach(function(key) { if (key !== "default" && key !== "__esModule") { definePropertyGetters(reexport_external_namespaceObject, { [key]: function() { return reexport_external_namespaceObject_starExports[key]; } }); @@ -13,6 +13,8 @@ Object.keys(reexport_external_namespaceObject_starExports).forEach(function(key) }); +// fs + // ./reexport-external.js diff --git a/tests/rspack-test/esmOutputCases/externals/reexport-used-external-namespace-as/__snapshots__/esm.snap.txt b/tests/rspack-test/esmOutputCases/externals/reexport-used-external-namespace-as/__snapshots__/esm.snap.txt index ca00242f4f6a..018fc94fe676 100644 --- a/tests/rspack-test/esmOutputCases/externals/reexport-used-external-namespace-as/__snapshots__/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/externals/reexport-used-external-namespace-as/__snapshots__/esm.snap.txt @@ -1,7 +1,10 @@ ```mjs title=main.mjs import * as __rspack_external_fs from "fs"; import * as __rspack_external_path from "path"; -import { resolve } from "path"; + +// fs + +// path // ./index.js @@ -16,7 +19,7 @@ it("should re-export used external namespaces without duplicating semantics", as const mod = await import(/* webpackIgnore: true */ "./main.mjs"); expect(mod.external1.readFile).toBe(__rspack_external_fs.readFile); - expect(mod.external2.resolve).toBe(resolve); + expect(mod.external2.resolve).toBe(__rspack_external_path.resolve); }); export { __rspack_external_fs as external1, __rspack_external_path as external2 }; diff --git a/tests/rspack-test/esmOutputCases/externals/runtime-decide/__snapshots__/esm.snap.txt b/tests/rspack-test/esmOutputCases/externals/runtime-decide/__snapshots__/esm.snap.txt index c5e5b164ded7..03914e9880bb 100644 --- a/tests/rspack-test/esmOutputCases/externals/runtime-decide/__snapshots__/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/externals/runtime-decide/__snapshots__/esm.snap.txt @@ -26,7 +26,6 @@ def(exports) /* import */ var _dynamic_exports__rspack_import_0 = __webpack_require__(/*! ./dynamic-exports */ "./dynamic-exports.js"); /* import */ var _dynamic_exports__rspack_import_0_default = /*#__PURE__*/__webpack_require__.n(_dynamic_exports__rspack_import_0); if(__webpack_require__.o(_dynamic_exports__rspack_import_0, "readFile")) __webpack_require__.d(__webpack_exports__, { readFile: function() { return _dynamic_exports__rspack_import_0.readFile; } }); -var fs__rspack_import_1 = __rspack_external_fs; /* import */ var fs__rspack_import_1 = __webpack_require__(/*! fs */ "fs"); if(__webpack_require__.o(fs__rspack_import_1, "readFile")) __webpack_require__.d(__webpack_exports__, { readFile: function() { return fs__rspack_import_1.readFile; } }); diff --git a/tests/rspack-test/esmOutputCases/externals/runtime-decide/__snapshots__/runtimeModeSnapshot/esm.snap.txt b/tests/rspack-test/esmOutputCases/externals/runtime-decide/__snapshots__/runtimeModeSnapshot/esm.snap.txt index 41964ef21b34..12a68d29d854 100644 --- a/tests/rspack-test/esmOutputCases/externals/runtime-decide/__snapshots__/runtimeModeSnapshot/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/externals/runtime-decide/__snapshots__/runtimeModeSnapshot/esm.snap.txt @@ -25,7 +25,6 @@ def(exports) /* import */ var _dynamic_exports__rspack_import_0 = rspackRequire(/*! ./dynamic-exports */ "./dynamic-exports.js"); /* import */ var _dynamic_exports__rspack_import_0_default = /*#__PURE__*/compatGetDefaultExport(_dynamic_exports__rspack_import_0); if(hasOwnProperty(_dynamic_exports__rspack_import_0, "readFile")) definePropertyGetters(exports, { readFile: function() { return _dynamic_exports__rspack_import_0.readFile; } }); -var fs__rspack_import_1 = __rspack_external_fs; /* import */ var fs__rspack_import_1 = rspackRequire(/*! fs */ "fs"); if(hasOwnProperty(fs__rspack_import_1, "readFile")) definePropertyGetters(exports, { readFile: function() { return fs__rspack_import_1.readFile; } }); diff --git a/tests/rspack-test/esmOutputCases/externals/shared-external-entry-and-dyn/__snapshots__/esm.snap.txt b/tests/rspack-test/esmOutputCases/externals/shared-external-entry-and-dyn/__snapshots__/esm.snap.txt index 0265fdff6518..a2a952a16f64 100644 --- a/tests/rspack-test/esmOutputCases/externals/shared-external-entry-and-dyn/__snapshots__/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/externals/shared-external-entry-and-dyn/__snapshots__/esm.snap.txt @@ -1,4 +1,6 @@ ```mjs title=async.mjs +// fs?3cf4 + // ./async.js const asyncValue = 'async' @@ -10,6 +12,8 @@ export { readFile } from "fs"; ```mjs title=main.mjs import { readFile } from "fs"; +// fs?771d + // ./index.js diff --git a/tests/rspack-test/esmOutputCases/externals/tostring-external-namespaces/__snapshots__/esm.snap.txt b/tests/rspack-test/esmOutputCases/externals/tostring-external-namespaces/__snapshots__/esm.snap.txt index 03dab4e2a39e..49e6ba9d9472 100644 --- a/tests/rspack-test/esmOutputCases/externals/tostring-external-namespaces/__snapshots__/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/externals/tostring-external-namespaces/__snapshots__/esm.snap.txt @@ -1,17 +1,21 @@ ```mjs title=main.mjs -import * as fsNs from "fs"; -import * as pathNs from "path"; +import * as __rspack_external_fs from "fs"; +import * as __rspack_external_path from "path"; + +// fs + +// path // ./index.js /* export default */ const index = ({ - fsTag: fsNs[Symbol.toStringTag], - fsText: Object.prototype.toString.call(fsNs), - pathTag: pathNs[Symbol.toStringTag], - pathText: Object.prototype.toString.call(pathNs), - basename: pathNs.basename("a/b.txt"), + fsTag: __rspack_external_fs[Symbol.toStringTag], + fsText: Object.prototype.toString.call(__rspack_external_fs), + pathTag: __rspack_external_path[Symbol.toStringTag], + pathText: Object.prototype.toString.call(__rspack_external_path), + basename: __rspack_external_path.basename("a/b.txt"), }); it("should preserve module toStringTag on external namespace imports", async () => { diff --git a/tests/rspack-test/esmOutputCases/externals/treeshake-namespace-access/__snapshots__/esm.snap.txt b/tests/rspack-test/esmOutputCases/externals/treeshake-namespace-access/__snapshots__/esm.snap.txt index c311aad90aa3..6d4a4f40c952 100644 --- a/tests/rspack-test/esmOutputCases/externals/treeshake-namespace-access/__snapshots__/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/externals/treeshake-namespace-access/__snapshots__/esm.snap.txt @@ -1,10 +1,11 @@ ```mjs title=main.mjs -import * as fsNs from "fs"; +import * as __rspack_external_fs from "fs"; +// fs // ./index.js -const unused = fsNs.readFile; +const unused = __rspack_external_fs.readFile; /* export default */ const index = ("main"); diff --git a/tests/rspack-test/esmOutputCases/preserve-modules/module-external-remapping/__snapshots__/esm.snap.txt b/tests/rspack-test/esmOutputCases/preserve-modules/module-external-remapping/__snapshots__/esm.snap.txt index 4339c2fc4557..38dd70911540 100644 --- a/tests/rspack-test/esmOutputCases/preserve-modules/module-external-remapping/__snapshots__/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/preserve-modules/module-external-remapping/__snapshots__/esm.snap.txt @@ -1,5 +1,5 @@ ```mjs title=hoisted.mjs -import { EventEmitter, once } from "node:events"; +import { once, EventEmitter } from "./node_events-node_events.mjs"; // ./src/hoisted.js @@ -44,6 +44,32 @@ export {}; ``` +```mjs title=node_events-node_events.mjs +import { __webpack_require__ } from "./runtime.mjs"; + +import * as __rspack_external_node_events_3969b2b3 from "node:events"; +__webpack_require__.add({ +"node:events?df85" +/*!******************************!*\ + !*** external "node:events" ***! + \******************************/ +(module, __unused_rspack_exports, __webpack_require__) { +var __rspack_create_module_external_namespace_node_events_3969b2b3 = (y) => { +var x = {}; +__webpack_require__.d(x, y); +return x; +}; +var __rspack_wrap_module_external_namespace_node_events_3969b2b3 = (x) => (() => (x)); +module.exports = __rspack_create_module_external_namespace_node_events_3969b2b3({["a"]: () => (__rspack_external_node_events_3969b2b3.EventEmitter), ["b"]: () => (__rspack_external_node_events_3969b2b3.once)}); + +}, +}); +// node:events?41dc + +export { EventEmitter, once } from "node:events"; + +``` + ```mjs title=runtime.mjs var __webpack_modules__ = {}; @@ -114,20 +140,15 @@ export { __webpack_require__ }; ```mjs title=wrapped.mjs import { __webpack_require__ } from "./runtime.mjs"; +import "./node_events-node_events.mjs"; -import * as __rspack_external_node_events_3969b2b3 from "node:events"; __webpack_require__.add({ "./src/wrapped.js" /*!************************!*\ !*** ./src/wrapped.js ***! \************************/ (module, __webpack_exports__, __webpack_require__) { -var __rspack_create_module_external_namespace_node_events_3969b2b3 = (y) => { -var x = {}; -__webpack_require__.d(x, y); -return x; -}; -var __rspack_wrap_module_external_namespace_node_events_3969b2b3 = (x) => (() => (x));var node_events__rspack_import_0 = __rspack_create_module_external_namespace_node_events_3969b2b3({["a"]: () => (__rspack_external_node_events_3969b2b3.EventEmitter), ["b"]: () => (__rspack_external_node_events_3969b2b3.once)}); +/* import */ var node_events__rspack_import_0 = __webpack_require__(/*! node:events */ "node:events?df85"); /* module decorator */ module = __webpack_require__.hmd(module); diff --git a/tests/rspack-test/esmOutputCases/preserve-modules/module-external-remapping/__snapshots__/runtimeModeSnapshot/esm.snap.txt b/tests/rspack-test/esmOutputCases/preserve-modules/module-external-remapping/__snapshots__/runtimeModeSnapshot/esm.snap.txt index 60faa757f501..4d3b55e4d020 100644 --- a/tests/rspack-test/esmOutputCases/preserve-modules/module-external-remapping/__snapshots__/runtimeModeSnapshot/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/preserve-modules/module-external-remapping/__snapshots__/runtimeModeSnapshot/esm.snap.txt @@ -1,5 +1,5 @@ ```mjs title=hoisted.mjs -import { EventEmitter, once } from "node:events"; +import { once, EventEmitter } from "./node_events-node_events.mjs"; // ./src/hoisted.js @@ -44,6 +44,31 @@ export {}; ``` +```mjs title=node_events-node_events.mjs +import { rspackRequire, moduleFactories, definePropertyGetters } from "./runtime.mjs"; +import * as __rspack_external_node_events_3969b2b3 from "node:events"; +moduleFactories.add({ +"node:events?df85" +/*!******************************!*\ + !*** external "node:events" ***! + \******************************/ +(module) { +var __rspack_create_module_external_namespace_node_events_3969b2b3 = (y) => { +var x = {}; +definePropertyGetters(x, y); +return x; +}; +var __rspack_wrap_module_external_namespace_node_events_3969b2b3 = (x) => (() => (x)); +module.exports = __rspack_create_module_external_namespace_node_events_3969b2b3({["a"]: () => (__rspack_external_node_events_3969b2b3.EventEmitter), ["b"]: () => (__rspack_external_node_events_3969b2b3.once)}); + +}, +}); +// node:events?41dc + +export { EventEmitter, once } from "node:events"; + +``` + ```mjs title=runtime.mjs var modules = {}; @@ -109,19 +134,15 @@ var hasOwnProperty = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, p ```mjs title=wrapped.mjs import { rspackRequire, moduleFactories, definePropertyGetters, esmModuleDecorator } from "./runtime.mjs"; -import * as __rspack_external_node_events_3969b2b3 from "node:events"; +import "./node_events-node_events.mjs"; + moduleFactories.add({ "./src/wrapped.js" /*!************************!*\ !*** ./src/wrapped.js ***! \************************/ (module, exports) { -var __rspack_create_module_external_namespace_node_events_3969b2b3 = (y) => { -var x = {}; -definePropertyGetters(x, y); -return x; -}; -var __rspack_wrap_module_external_namespace_node_events_3969b2b3 = (x) => (() => (x));var node_events__rspack_import_0 = __rspack_create_module_external_namespace_node_events_3969b2b3({["a"]: () => (__rspack_external_node_events_3969b2b3.EventEmitter), ["b"]: () => (__rspack_external_node_events_3969b2b3.once)}); +/* import */ var node_events__rspack_import_0 = rspackRequire(/*! node:events */ "node:events?df85"); /* module decorator */ module = esmModuleDecorator(module); diff --git a/tests/rspack-test/esmOutputCases/preserve-modules/re-export-module-external-hoist-mix/__snapshots__/esm.snap.txt b/tests/rspack-test/esmOutputCases/preserve-modules/re-export-module-external-hoist-mix/__snapshots__/esm.snap.txt index fbd85af85e3c..617b87f34906 100644 --- a/tests/rspack-test/esmOutputCases/preserve-modules/re-export-module-external-hoist-mix/__snapshots__/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/preserve-modules/re-export-module-external-hoist-mix/__snapshots__/esm.snap.txt @@ -1,15 +1,39 @@ +```mjs title=fs-fs.mjs +import { __webpack_require__ } from "./runtime.mjs"; + +import * as __rspack_external_fs from "fs"; +__webpack_require__.add({ +"fs?2159" +/*!*********************!*\ + !*** external "fs" ***! + \*********************/ +(module) { + +module.exports = __rspack_external_fs; + + +}, +}); +// fs?82ef + +export { readFile as readFileHoisted, readFileSync as readFileSyncHoisted } from "fs"; + +``` + ```mjs title=hoisted.mjs + // ./src/hoisted.js -export { readFile as readFileHoisted, readFileSync as readFileSyncHoisted } from "fs"; +export { readFileHoisted, readFileSyncHoisted } from "./fs-fs.mjs"; ``` ```mjs title=index.mjs import { __webpack_require__ } from "./runtime.mjs"; import "./wrapped.mjs"; -import { readFileSyncHoisted as readFileSync, readFileHoisted as readFile } from "./hoisted.mjs"; +import "./hoisted.mjs"; +import { readFileSyncHoisted as readFileSync, readFileHoisted as readFile } from "./fs-fs.mjs"; // ./src/index.js const wrapped_0 = __webpack_require__("./src/wrapped.js"); @@ -107,15 +131,15 @@ export { __webpack_require__ }; ```mjs title=wrapped.mjs import { __webpack_require__ } from "./runtime.mjs"; +import "./fs-fs.mjs"; -import * as __rspack_external_fs from "fs"; __webpack_require__.add({ "./src/wrapped.js" /*!************************!*\ !*** ./src/wrapped.js ***! \************************/ (module, __webpack_exports__, __webpack_require__) { -var fs__rspack_import_0 = __rspack_external_fs; +/* import */ var fs__rspack_import_0 = __webpack_require__(/*! fs */ "fs?2159"); /* module decorator */ module = __webpack_require__.hmd(module); diff --git a/tests/rspack-test/esmOutputCases/preserve-modules/re-export-module-external-hoist-mix/__snapshots__/runtimeModeSnapshot/esm.snap.txt b/tests/rspack-test/esmOutputCases/preserve-modules/re-export-module-external-hoist-mix/__snapshots__/runtimeModeSnapshot/esm.snap.txt index ec518ef19cf0..57822b7aef9f 100644 --- a/tests/rspack-test/esmOutputCases/preserve-modules/re-export-module-external-hoist-mix/__snapshots__/runtimeModeSnapshot/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/preserve-modules/re-export-module-external-hoist-mix/__snapshots__/runtimeModeSnapshot/esm.snap.txt @@ -1,15 +1,38 @@ +```mjs title=fs-fs.mjs +import { rspackRequire, moduleFactories } from "./runtime.mjs"; +import * as __rspack_external_fs from "fs"; +moduleFactories.add({ +"fs?2159" +/*!*********************!*\ + !*** external "fs" ***! + \*********************/ +(module) { + +module.exports = __rspack_external_fs; + + +}, +}); +// fs?82ef + +export { readFile as readFileHoisted, readFileSync as readFileSyncHoisted } from "fs"; + +``` + ```mjs title=hoisted.mjs + // ./src/hoisted.js -export { readFile as readFileHoisted, readFileSync as readFileSyncHoisted } from "fs"; +export { readFileHoisted, readFileSyncHoisted } from "./fs-fs.mjs"; ``` ```mjs title=index.mjs import { rspackRequire } from "./runtime.mjs"; import "./wrapped.mjs"; -import { readFileSyncHoisted as readFileSync, readFileHoisted as readFile } from "./hoisted.mjs"; +import "./hoisted.mjs"; +import { readFileSyncHoisted as readFileSync, readFileHoisted as readFile } from "./fs-fs.mjs"; // ./src/index.js const wrapped_0 = rspackRequire("./src/wrapped.js"); @@ -102,14 +125,15 @@ var hasOwnProperty = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, p ```mjs title=wrapped.mjs import { rspackRequire, moduleFactories, definePropertyGetters, esmModuleDecorator } from "./runtime.mjs"; -import * as __rspack_external_fs from "fs"; +import "./fs-fs.mjs"; + moduleFactories.add({ "./src/wrapped.js" /*!************************!*\ !*** ./src/wrapped.js ***! \************************/ (module, exports) { -var fs__rspack_import_0 = __rspack_external_fs; +/* import */ var fs__rspack_import_0 = rspackRequire(/*! fs */ "fs?2159"); /* module decorator */ module = esmModuleDecorator(module); diff --git a/tests/rspack-test/esmOutputCases/re-exports/deep-re-export-external/__snapshots__/esm.snap.txt b/tests/rspack-test/esmOutputCases/re-exports/deep-re-export-external/__snapshots__/esm.snap.txt index 013716766459..a4b9c30ecbfc 100644 --- a/tests/rspack-test/esmOutputCases/re-exports/deep-re-export-external/__snapshots__/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/re-exports/deep-re-export-external/__snapshots__/esm.snap.txt @@ -1,14 +1,14 @@ ```mjs title=main.mjs import { __webpack_require__ } from "./runtime.mjs"; -import * as external from "fs"; +import * as __rspack_external_fs from "fs"; // NAMESPACE OBJECT: ./externals.js var externals_namespaceObject = {}; __webpack_require__.r(externals_namespaceObject); __webpack_require__.d(externals_namespaceObject, { - "default": () => (fs), - readFile: () => (externals_readFile) }); -var externals_namespaceObject_starExports = external; + "default": () => (__rspack_external_fs["default"]), + readFile: () => (__rspack_external_fs.readFile) }); +var externals_namespaceObject_starExports = __rspack_external_fs; Object.keys(externals_namespaceObject_starExports).forEach(function(key) { if (key !== "default" && key !== "__esModule") { __webpack_require__.d(externals_namespaceObject, { [key]: function() { return externals_namespaceObject_starExports[key]; } }); @@ -16,6 +16,8 @@ Object.keys(externals_namespaceObject_starExports).forEach(function(key) { }); +// fs + // ./externals.js @@ -35,9 +37,12 @@ it('should have exports', async () => { expect(externalsNs).toBeDefined(); }); -export { externals_namespaceObject as externalsNs }; +var default_0 = __rspack_external_fs["default"]; +var externals_0 = __rspack_external_fs["default"]; +var readFile_0 = __rspack_external_fs.readFile; +export { externals_0 as externals, externals_namespaceObject as externalsNs, readFile_0 as readFile }; export * from "fs"; -export { default, default as externals, readFile } from "fs"; +export default default_0; ``` diff --git a/tests/rspack-test/esmOutputCases/re-exports/deep-re-export-external/__snapshots__/runtimeModeSnapshot/esm.snap.txt b/tests/rspack-test/esmOutputCases/re-exports/deep-re-export-external/__snapshots__/runtimeModeSnapshot/esm.snap.txt index 0d002e3fd49c..e40fe46099ca 100644 --- a/tests/rspack-test/esmOutputCases/re-exports/deep-re-export-external/__snapshots__/runtimeModeSnapshot/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/re-exports/deep-re-export-external/__snapshots__/runtimeModeSnapshot/esm.snap.txt @@ -1,14 +1,14 @@ ```mjs title=main.mjs import { rspackRequire, definePropertyGetters, makeNamespaceObject } from "./runtime.mjs"; -import * as external from "fs"; +import * as __rspack_external_fs from "fs"; // NAMESPACE OBJECT: ./externals.js var externals_namespaceObject = {}; makeNamespaceObject(externals_namespaceObject); definePropertyGetters(externals_namespaceObject, { - "default": () => (fs), - readFile: () => (externals_readFile) }); -var externals_namespaceObject_starExports = external; + "default": () => (__rspack_external_fs["default"]), + readFile: () => (__rspack_external_fs.readFile) }); +var externals_namespaceObject_starExports = __rspack_external_fs; Object.keys(externals_namespaceObject_starExports).forEach(function(key) { if (key !== "default" && key !== "__esModule") { definePropertyGetters(externals_namespaceObject, { [key]: function() { return externals_namespaceObject_starExports[key]; } }); @@ -16,6 +16,8 @@ Object.keys(externals_namespaceObject_starExports).forEach(function(key) { }); +// fs + // ./externals.js @@ -35,9 +37,12 @@ it('should have exports', async () => { expect(externalsNs).toBeDefined(); }); -export { externals_namespaceObject as externalsNs }; +var default_0 = __rspack_external_fs["default"]; +var externals_0 = __rspack_external_fs["default"]; +var readFile_0 = __rspack_external_fs.readFile; +export { externals_0 as externals, externals_namespaceObject as externalsNs, readFile_0 as readFile }; export * from "fs"; -export { default, default as externals, readFile } from "fs"; +export default default_0; ``` diff --git a/tests/rspack-test/esmOutputCases/re-exports/deep-re-exports-esm-2/__snapshots__/esm.snap.txt b/tests/rspack-test/esmOutputCases/re-exports/deep-re-exports-esm-2/__snapshots__/esm.snap.txt index ec9fe02a92c6..50e9015f824b 100644 --- a/tests/rspack-test/esmOutputCases/re-exports/deep-re-exports-esm-2/__snapshots__/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/re-exports/deep-re-exports-esm-2/__snapshots__/esm.snap.txt @@ -10,7 +10,7 @@ __webpack_require__.add({ \****************/ (__unused_rspack_module, __webpack_exports__, __webpack_require__) { __webpack_require__.r(__webpack_exports__); -var fs__rspack_import_0 = __rspack_external_fs; +/* import */ var fs__rspack_import_0 = __webpack_require__(/*! fs */ "fs"); /* reexport */ var __rspack_reexport = {}; /* reexport */ for( const __rspack_import_key in fs__rspack_import_0) if(["default","lib"].indexOf(__rspack_import_key) < 0) __rspack_reexport[__rspack_import_key] =() => fs__rspack_import_0[__rspack_import_key] @@ -39,7 +39,7 @@ __webpack_require__.d(__webpack_exports__, { \*****************/ (__unused_rspack_module, __webpack_exports__, __webpack_require__) { __webpack_require__.r(__webpack_exports__); -var path__rspack_import_0 = __rspack_external_path; +/* import */ var path__rspack_import_0 = __webpack_require__(/*! path */ "path"); /* reexport */ var __rspack_reexport = {}; /* reexport */ for( const __rspack_import_key in path__rspack_import_0) if(["default","lib2"].indexOf(__rspack_import_key) < 0) __rspack_reexport[__rspack_import_key] =() => path__rspack_import_0[__rspack_import_key] @@ -66,7 +66,7 @@ __webpack_require__.d(__webpack_exports__, { !*** ./lib3.js ***! \*****************/ (__unused_rspack_module, __webpack_exports__, __webpack_require__) { -var fs__rspack_import_0 = __rspack_external_fs; +/* import */ var fs__rspack_import_0 = __webpack_require__(/*! fs */ "fs"); const lib3 = 42 const lib_local = 24 @@ -79,6 +79,26 @@ __webpack_require__.d(__webpack_exports__, { }); +}, +"fs" +/*!*********************!*\ + !*** external "fs" ***! + \*********************/ +(module) { + +module.exports = __rspack_external_fs; + + +}, +"path" +/*!***********************!*\ + !*** external "path" ***! + \***********************/ +(module) { + +module.exports = __rspack_external_path; + + }, }); // ./index.js diff --git a/tests/rspack-test/esmOutputCases/re-exports/deep-re-exports-esm-2/__snapshots__/runtimeModeSnapshot/esm.snap.txt b/tests/rspack-test/esmOutputCases/re-exports/deep-re-exports-esm-2/__snapshots__/runtimeModeSnapshot/esm.snap.txt index 12f960b83ad9..a72cdeec36a2 100644 --- a/tests/rspack-test/esmOutputCases/re-exports/deep-re-exports-esm-2/__snapshots__/runtimeModeSnapshot/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/re-exports/deep-re-exports-esm-2/__snapshots__/runtimeModeSnapshot/esm.snap.txt @@ -9,7 +9,7 @@ moduleFactories.add({ \****************/ (__unused_rspack_module, exports) { makeNamespaceObject(exports); -var fs__rspack_import_0 = __rspack_external_fs; +/* import */ var fs__rspack_import_0 = rspackRequire(/*! fs */ "fs"); /* reexport */ var __rspack_reexport = {}; /* reexport */ for( const __rspack_import_key in fs__rspack_import_0) if(["default","lib"].indexOf(__rspack_import_key) < 0) __rspack_reexport[__rspack_import_key] =() => fs__rspack_import_0[__rspack_import_key] @@ -38,7 +38,7 @@ definePropertyGetters(exports, { \*****************/ (__unused_rspack_module, exports) { makeNamespaceObject(exports); -var path__rspack_import_0 = __rspack_external_path; +/* import */ var path__rspack_import_0 = rspackRequire(/*! path */ "path"); /* reexport */ var __rspack_reexport = {}; /* reexport */ for( const __rspack_import_key in path__rspack_import_0) if(["default","lib2"].indexOf(__rspack_import_key) < 0) __rspack_reexport[__rspack_import_key] =() => path__rspack_import_0[__rspack_import_key] @@ -65,7 +65,7 @@ definePropertyGetters(exports, { !*** ./lib3.js ***! \*****************/ (__unused_rspack_module, exports) { -var fs__rspack_import_0 = __rspack_external_fs; +/* import */ var fs__rspack_import_0 = rspackRequire(/*! fs */ "fs"); const lib3 = 42 const lib_local = 24 @@ -78,6 +78,26 @@ definePropertyGetters(exports, { }); +}, +"fs" +/*!*********************!*\ + !*** external "fs" ***! + \*********************/ +(module) { + +module.exports = __rspack_external_fs; + + +}, +"path" +/*!***********************!*\ + !*** external "path" ***! + \***********************/ +(module) { + +module.exports = __rspack_external_path; + + }, }); // ./index.js diff --git a/tests/rspack-test/esmOutputCases/re-exports/deep-re-exports-esm-3/__snapshots__/esm.snap.txt b/tests/rspack-test/esmOutputCases/re-exports/deep-re-exports-esm-3/__snapshots__/esm.snap.txt index 7013f7a06bec..b36828ce84e5 100644 --- a/tests/rspack-test/esmOutputCases/re-exports/deep-re-exports-esm-3/__snapshots__/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/re-exports/deep-re-exports-esm-3/__snapshots__/esm.snap.txt @@ -2,6 +2,12 @@ import * as __rspack_external_fs from "fs"; import * as __rspack_external_path from "path"; +// fs?f137 + +// path + +// fs?c303 + // ./lib3.js const lib3_lib3 = 42 diff --git a/tests/rspack-test/esmOutputCases/re-exports/deep-re-exports-esm-4/__snapshots__/esm.snap.txt b/tests/rspack-test/esmOutputCases/re-exports/deep-re-exports-esm-4/__snapshots__/esm.snap.txt index 7013f7a06bec..b36828ce84e5 100644 --- a/tests/rspack-test/esmOutputCases/re-exports/deep-re-exports-esm-4/__snapshots__/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/re-exports/deep-re-exports-esm-4/__snapshots__/esm.snap.txt @@ -2,6 +2,12 @@ import * as __rspack_external_fs from "fs"; import * as __rspack_external_path from "path"; +// fs?f137 + +// path + +// fs?c303 + // ./lib3.js const lib3_lib3 = 42 diff --git a/tests/rspack-test/esmOutputCases/re-exports/deep-re-exports-wrapped/__snapshots__/esm.snap.txt b/tests/rspack-test/esmOutputCases/re-exports/deep-re-exports-wrapped/__snapshots__/esm.snap.txt index eb5a46d2219b..6e912396244e 100644 --- a/tests/rspack-test/esmOutputCases/re-exports/deep-re-exports-wrapped/__snapshots__/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/re-exports/deep-re-exports-wrapped/__snapshots__/esm.snap.txt @@ -1,10 +1,15 @@ ```mjs title=main.mjs +import * as __rspack_external_fs from "fs"; import * as __rspack_external_path from "path"; +// fs + // ./lib3.js const v = 42 +// path + // ./lib2.js diff --git a/tests/rspack-test/esmOutputCases/re-exports/default-namespace-external/__snapshots__/esm.snap.txt b/tests/rspack-test/esmOutputCases/re-exports/default-namespace-external/__snapshots__/esm.snap.txt index d9bdb32eaf89..0344b866e7c9 100644 --- a/tests/rspack-test/esmOutputCases/re-exports/default-namespace-external/__snapshots__/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/re-exports/default-namespace-external/__snapshots__/esm.snap.txt @@ -10,11 +10,15 @@ __webpack_require__.d(file_namespaceObject, { value: () => (value) }); +// fs?42cb + // ./sharding.js const value = fs; +// fs?5257 + // ./file.js diff --git a/tests/rspack-test/esmOutputCases/re-exports/default-namespace-external/__snapshots__/runtimeModeSnapshot/esm.snap.txt b/tests/rspack-test/esmOutputCases/re-exports/default-namespace-external/__snapshots__/runtimeModeSnapshot/esm.snap.txt index 9579881a2d53..be53a770410b 100644 --- a/tests/rspack-test/esmOutputCases/re-exports/default-namespace-external/__snapshots__/runtimeModeSnapshot/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/re-exports/default-namespace-external/__snapshots__/runtimeModeSnapshot/esm.snap.txt @@ -10,11 +10,15 @@ definePropertyGetters(file_namespaceObject, { value: () => (value) }); +// fs?42cb + // ./sharding.js const value = fs; +// fs?5257 + // ./file.js diff --git a/tests/rspack-test/esmOutputCases/re-exports/default-re-export-external/__snapshots__/esm.snap.txt b/tests/rspack-test/esmOutputCases/re-exports/default-re-export-external/__snapshots__/esm.snap.txt index d2d6566349a1..df6c42329ead 100644 --- a/tests/rspack-test/esmOutputCases/re-exports/default-re-export-external/__snapshots__/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/re-exports/default-re-export-external/__snapshots__/esm.snap.txt @@ -10,11 +10,15 @@ __webpack_require__.d(file_namespaceObject, { value: () => (value) }); +// fs?42cb + // ./sharding.js const value = fs; +// fs?5257 + // ./file.js diff --git a/tests/rspack-test/esmOutputCases/re-exports/default-re-export-external/__snapshots__/runtimeModeSnapshot/esm.snap.txt b/tests/rspack-test/esmOutputCases/re-exports/default-re-export-external/__snapshots__/runtimeModeSnapshot/esm.snap.txt index 703c91895a36..ac5c48d017c5 100644 --- a/tests/rspack-test/esmOutputCases/re-exports/default-re-export-external/__snapshots__/runtimeModeSnapshot/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/re-exports/default-re-export-external/__snapshots__/runtimeModeSnapshot/esm.snap.txt @@ -10,11 +10,15 @@ definePropertyGetters(file_namespaceObject, { value: () => (value) }); +// fs?42cb + // ./sharding.js const value = fs; +// fs?5257 + // ./file.js diff --git a/tests/rspack-test/esmOutputCases/re-exports/move-entry/__snapshots__/esm.snap.txt b/tests/rspack-test/esmOutputCases/re-exports/move-entry/__snapshots__/esm.snap.txt index fd067339ad9b..bf460aa2d71d 100644 --- a/tests/rspack-test/esmOutputCases/re-exports/move-entry/__snapshots__/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/re-exports/move-entry/__snapshots__/esm.snap.txt @@ -13,7 +13,9 @@ export { a, b } from "./proxy-main.mjs"; ``` ```mjs title=proxy-main.mjs -import "fs"; +import * as __rspack_external_fs from "fs"; + +// fs // ./lib.js // side effect diff --git a/tests/rspack-test/esmOutputCases/re-exports/re-export-external/__snapshots__/esm.snap.txt b/tests/rspack-test/esmOutputCases/re-exports/re-export-external/__snapshots__/esm.snap.txt index 9f69bafacd58..8c7fe47a1e53 100644 --- a/tests/rspack-test/esmOutputCases/re-exports/re-export-external/__snapshots__/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/re-exports/re-export-external/__snapshots__/esm.snap.txt @@ -1,4 +1,8 @@ ```mjs title=main.mjs +import * as __rspack_external_fs from "fs"; + +// fs + // ./index.js @@ -21,10 +25,12 @@ it('should compile and import success', async () => { expect(readFile).toBeDefined() }) +var fs_0 = __rspack_external_fs["default"]; var index_named = (/* inlined export .named */42); +var r_0 = __rspack_external_fs.readFile; +var readFile_0 = __rspack_external_fs.readFile; var index_starExports = (/* inlined export .starExports */42); -export { index_named as named, index_starExports as starExports }; +export { fs_0 as fs, index_named as named, index_starExports as starExports, r_0 as r, readFile_0 as readFile }; export * from "fs"; -export { default as fs, readFile as r, readFile } from "fs"; ``` \ No newline at end of file diff --git a/tests/rspack-test/esmOutputCases/re-exports/re-export-namespaced-external/__snapshots__/esm.snap.txt b/tests/rspack-test/esmOutputCases/re-exports/re-export-namespaced-external/__snapshots__/esm.snap.txt index 37658fbd6b50..87c91f94b712 100644 --- a/tests/rspack-test/esmOutputCases/re-exports/re-export-namespaced-external/__snapshots__/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/re-exports/re-export-namespaced-external/__snapshots__/esm.snap.txt @@ -1,6 +1,7 @@ ```mjs title=main.mjs -import fs_0, * as __rspack_external_fs from "fs"; -import { readFile as index_readFile } from "fs"; +import * as __rspack_external_fs from "fs"; + +// fs // ./index.js @@ -36,10 +37,14 @@ it('should compile and import success', async () => { expect(readFile).toBeDefined() }) +var default_0 = __rspack_external_fs["default"]; +var fs_0 = __rspack_external_fs["default"]; var index_named = (/* inlined export .named */42); +var r_0 = __rspack_external_fs.readFile; +var readFile_0 = __rspack_external_fs.readFile; var index_starExports = (/* inlined export .starExports */42); -export { __rspack_external_fs as fsNs, fs_0 as fs, index_named as named, index_readFile as r, index_readFile as readFile, index_starExports as starExports }; +export { __rspack_external_fs as fsNs, fs_0 as fs, index_named as named, index_starExports as starExports, r_0 as r, readFile_0 as readFile }; export * from "fs"; -export default fs_0; +export default default_0; ``` \ No newline at end of file diff --git a/tests/rspack-test/esmOutputCases/re-exports/wrapped-esm-entry/__snapshots__/esm.snap.txt b/tests/rspack-test/esmOutputCases/re-exports/wrapped-esm-entry/__snapshots__/esm.snap.txt index 00a544b4fe1b..bd259b995d67 100644 --- a/tests/rspack-test/esmOutputCases/re-exports/wrapped-esm-entry/__snapshots__/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/re-exports/wrapped-esm-entry/__snapshots__/esm.snap.txt @@ -9,7 +9,7 @@ __webpack_require__.add({ \******************/ (module, __webpack_exports__, __webpack_require__) { __webpack_require__.r(__webpack_exports__); -var fs__rspack_import_0 = __rspack_external_fs; +/* import */ var fs__rspack_import_0 = __webpack_require__(/*! fs */ "fs"); /* reexport */ var __rspack_reexport = {}; /* reexport */ for( const __rspack_import_key in fs__rspack_import_0) if(["r","named","default","fs","starExports","readFile"].indexOf(__rspack_import_key) < 0) __rspack_reexport[__rspack_import_key] =() => fs__rspack_import_0[__rspack_import_key] @@ -47,6 +47,16 @@ __webpack_require__.d(__webpack_exports__, { }); +}, +"fs" +/*!*********************!*\ + !*** external "fs" ***! + \*********************/ +(module) { + +module.exports = __rspack_external_fs; + + }, }); const index = __webpack_require__("./index.js"); diff --git a/tests/rspack-test/esmOutputCases/re-exports/wrapped-esm-entry/__snapshots__/runtimeModeSnapshot/esm.snap.txt b/tests/rspack-test/esmOutputCases/re-exports/wrapped-esm-entry/__snapshots__/runtimeModeSnapshot/esm.snap.txt index f0549ecb0405..00500775a4d0 100644 --- a/tests/rspack-test/esmOutputCases/re-exports/wrapped-esm-entry/__snapshots__/runtimeModeSnapshot/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/re-exports/wrapped-esm-entry/__snapshots__/runtimeModeSnapshot/esm.snap.txt @@ -8,7 +8,7 @@ moduleFactories.add({ \******************/ (module, exports) { makeNamespaceObject(exports); -var fs__rspack_import_0 = __rspack_external_fs; +/* import */ var fs__rspack_import_0 = rspackRequire(/*! fs */ "fs"); /* reexport */ var __rspack_reexport = {}; /* reexport */ for( const __rspack_import_key in fs__rspack_import_0) if(["r","named","default","fs","starExports","readFile"].indexOf(__rspack_import_key) < 0) __rspack_reexport[__rspack_import_key] =() => fs__rspack_import_0[__rspack_import_key] @@ -46,6 +46,16 @@ definePropertyGetters(exports, { }); +}, +"fs" +/*!*********************!*\ + !*** external "fs" ***! + \*********************/ +(module) { + +module.exports = __rspack_external_fs; + + }, }); const index = rspackRequire("./index.js"); diff --git a/tests/rspack-test/esmOutputCases/split-chunks/re-export-external-cross-chunk/__snapshots__/esm.snap.txt b/tests/rspack-test/esmOutputCases/split-chunks/re-export-external-cross-chunk/__snapshots__/esm.snap.txt index 14ca8e868611..06038dc837c8 100644 --- a/tests/rspack-test/esmOutputCases/split-chunks/re-export-external-cross-chunk/__snapshots__/esm.snap.txt +++ b/tests/rspack-test/esmOutputCases/split-chunks/re-export-external-cross-chunk/__snapshots__/esm.snap.txt @@ -16,6 +16,10 @@ export { join, readFile } from "./wrapper-chunk.mjs"; ``` ```mjs title=wrapper-chunk.mjs +// fs + +// path + // ./wrapper.js From accb09002ebf7546d1ee0b194d1251d63cac84db Mon Sep 17 00:00:00 2001 From: Fy <1114550440@qq.com> Date: Thu, 17 Sep 2026 19:26:37 +0800 Subject: [PATCH 13/13] fix(esm-library): bail out on missing external requests --- crates/rspack_core/src/external_module.rs | 4 ++++ .../src/dependency/commonjs_external.rs | 7 +++++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/crates/rspack_core/src/external_module.rs b/crates/rspack_core/src/external_module.rs index 77c19dadbd09..f748d7e8294b 100644 --- a/crates/rspack_core/src/external_module.rs +++ b/crates/rspack_core/src/external_module.rs @@ -674,6 +674,10 @@ impl ExternalModule { } } + pub fn try_get_request(&self) -> Option<&ExternalRequestValue> { + self.get_request_and_external_type().0 + } + fn get_request_and_external_type(&self) -> (Option<&ExternalRequestValue>, &ExternalType) { match &self.request { ExternalRequest::Single(request) => (Some(request), &self.external_type), diff --git a/crates/rspack_plugin_esm_library/src/dependency/commonjs_external.rs b/crates/rspack_plugin_esm_library/src/dependency/commonjs_external.rs index 30a84ab28f55..83c889687bf0 100644 --- a/crates/rspack_plugin_esm_library/src/dependency/commonjs_external.rs +++ b/crates/rspack_plugin_esm_library/src/dependency/commonjs_external.rs @@ -120,7 +120,10 @@ pub fn cutout_commonjs_externals( continue; }; - let request = external_module.get_request(); + // Missing object-form requests must keep the normal external rendering path. + let Some(request) = external_module.try_get_request() else { + continue; + }; if CommonJsExternalRequireKind::from_external_type(external_module.resolve_external_type()) .is_some() && !request.has_rest() @@ -159,7 +162,7 @@ fn get_direct_external_require( .and_then(|module| module.as_external_module())?; Some(( - external_module.get_request().primary().to_string(), + external_module.try_get_request()?.primary().to_string(), CommonJsExternalRequireKind::from_external_type(external_module.resolve_external_type())?, )) }