diff --git a/crates/node_binding/binding.d.ts b/crates/node_binding/binding.d.ts index 6d39a5d9393..a7665830c29 100644 --- a/crates/node_binding/binding.d.ts +++ b/crates/node_binding/binding.d.ts @@ -205,6 +205,11 @@ export declare class JsStats { getLogging(acceptedTypes: number): Array } +export declare class RawExternalItemFnCtx { + data(): RawExternalItemFnCtxData + getResolver(): JsResolver +} + export declare class Rspack { constructor(options: RawOptions, builtinPlugins: Array, registerJsTaps: RegisterJsTaps, outputFilesystem: ThreadsafeNodeFS, resolverFactoryReference: JsResolverFactory) setNonSkippableRegisters(kinds: Array): void @@ -1397,7 +1402,7 @@ export interface RawExposeOptions { import: Array } -export interface RawExternalItemFnCtx { +export interface RawExternalItemFnCtxData { request: string context: string dependencyType: string diff --git a/crates/rspack_binding_options/src/options/raw_external.rs b/crates/rspack_binding_options/src/options/raw_external.rs index 870ee263824..87a204229d5 100644 --- a/crates/rspack_binding_options/src/options/raw_external.rs +++ b/crates/rspack_binding_options/src/options/raw_external.rs @@ -1,10 +1,12 @@ use std::collections::HashMap; use std::fmt::Debug; +use std::sync::Arc; use napi::bindgen_prelude::Either4; use napi_derive::napi; -use rspack_core::ExternalItemFnCtx; +use rspack_binding_values::JsResolver; use rspack_core::{ExternalItem, ExternalItemFnResult, ExternalItemValue}; +use rspack_core::{ExternalItemFnCtx, ResolveOptionsWithDependencyType, ResolverFactory}; use rspack_napi::threadsafe_function::ThreadsafeFunction; use rspack_regex::RspackRegex; @@ -68,15 +70,47 @@ pub struct ContextInfo { pub issuer: String, } -#[derive(Debug, Clone)] -#[napi(object)] +#[derive(Debug)] +#[napi] pub struct RawExternalItemFnCtx { + request: String, + context: String, + dependency_type: String, + context_info: ContextInfo, + resolve_options_with_dependency_type: ResolveOptionsWithDependencyType, + resolver_factory: Arc, +} + +#[derive(Debug)] +#[napi(object)] +pub struct RawExternalItemFnCtxData { pub request: String, pub context: String, pub dependency_type: String, pub context_info: ContextInfo, } +#[napi] +impl RawExternalItemFnCtx { + #[napi] + pub fn data(&self) -> RawExternalItemFnCtxData { + RawExternalItemFnCtxData { + request: self.request.clone(), + context: self.context.clone(), + dependency_type: self.dependency_type.clone(), + context_info: self.context_info.clone(), + } + } + + #[napi] + pub fn get_resolver(&self) -> JsResolver { + JsResolver::new( + self.resolver_factory.clone(), + self.resolve_options_with_dependency_type.clone(), + ) + } +} + impl From for RawExternalItemFnCtx { fn from(value: ExternalItemFnCtx) -> Self { Self { @@ -86,6 +120,8 @@ impl From for RawExternalItemFnCtx { context_info: ContextInfo { issuer: value.context_info.issuer, }, + resolve_options_with_dependency_type: value.resolve_options_with_dependency_type, + resolver_factory: value.resolver_factory, } } } diff --git a/crates/rspack_binding_values/src/resolver.rs b/crates/rspack_binding_values/src/resolver.rs index f744f35d67e..14c344fef6b 100644 --- a/crates/rspack_binding_values/src/resolver.rs +++ b/crates/rspack_binding_values/src/resolver.rs @@ -10,6 +10,7 @@ use crate::raw_resolve::{ }; #[napi] +#[derive(Debug)] pub struct JsResolver { resolver_factory: Arc, resolver: Arc, diff --git a/crates/rspack_core/src/compiler/make/repair/factorize.rs b/crates/rspack_core/src/compiler/make/repair/factorize.rs index 69582af1da6..872d5e1ab0f 100644 --- a/crates/rspack_core/src/compiler/make/repair/factorize.rs +++ b/crates/rspack_core/src/compiler/make/repair/factorize.rs @@ -11,7 +11,7 @@ use crate::{ utils::task_loop::{Task, TaskResult, TaskType}, BoxDependency, CompilationId, CompilerOptions, Context, ExportInfoData, ExportsInfoData, ModuleFactory, ModuleFactoryCreateData, ModuleFactoryResult, ModuleIdentifier, ModuleLayer, - ModuleProfile, Resolve, + ModuleProfile, Resolve, ResolverFactory, }; #[derive(Debug)] @@ -24,9 +24,10 @@ pub struct FactorizeTask { pub issuer: Option>, pub issuer_layer: Option, pub dependencies: Vec, - pub resolve_options: Option>, + pub resolve_options: Option>, pub options: Arc, pub current_profile: Option>, + pub resolver_factory: Arc, } #[async_trait::async_trait] @@ -89,6 +90,7 @@ impl Task for FactorizeTask { issuer: self.issuer, issuer_identifier: self.original_module_identifier, issuer_layer, + resolver_factory: self.resolver_factory, file_dependencies: Default::default(), missing_dependencies: Default::default(), diff --git a/crates/rspack_core/src/compiler/make/repair/mod.rs b/crates/rspack_core/src/compiler/make/repair/mod.rs index 46598357b8e..a26e8151765 100644 --- a/crates/rspack_core/src/compiler/make/repair/mod.rs +++ b/crates/rspack_core/src/compiler/make/repair/mod.rs @@ -142,6 +142,7 @@ pub async fn repair( resolve_options: parent_module.and_then(|module| module.get_resolve_options()), options: compilation.options.clone(), current_profile, + resolver_factory: compilation.resolver_factory.clone(), })) }) .collect::>(); diff --git a/crates/rspack_core/src/compiler/make/repair/process_dependencies.rs b/crates/rspack_core/src/compiler/make/repair/process_dependencies.rs index 4040797ce72..57236fcbe12 100644 --- a/crates/rspack_core/src/compiler/make/repair/process_dependencies.rs +++ b/crates/rspack_core/src/compiler/make/repair/process_dependencies.rs @@ -109,6 +109,7 @@ impl Task for ProcessDependenciesTask { resolve_options: module.get_resolve_options(), options: context.compiler_options.clone(), current_profile, + resolver_factory: context.resolver_factory.clone(), })); } Ok(res) diff --git a/crates/rspack_core/src/compiler/module_executor/entry.rs b/crates/rspack_core/src/compiler/module_executor/entry.rs index 3b96db25d13..80e3c3c7958 100644 --- a/crates/rspack_core/src/compiler/module_executor/entry.rs +++ b/crates/rspack_core/src/compiler/module_executor/entry.rs @@ -45,6 +45,7 @@ impl Task for EntryTask { .compiler_options .profile .then(Box::::default), + resolver_factory: context.resolver_factory.clone(), })]) } } diff --git a/crates/rspack_core/src/concatenated_module.rs b/crates/rspack_core/src/concatenated_module.rs index 6efdde70cf9..bde515f202e 100644 --- a/crates/rspack_core/src/concatenated_module.rs +++ b/crates/rspack_core/src/concatenated_module.rs @@ -64,7 +64,7 @@ pub struct RootModuleContext { pub readable_identifier: String, pub name_for_condition: Option>, pub lib_indent: Option, - pub resolve_options: Option>, + pub resolve_options: Option>, pub code_generation_dependencies: Option>>, pub presentational_dependencies: Option>>, pub context: Option, @@ -1361,7 +1361,7 @@ impl Module for ConcatenatedModule { self.root_module_ctxt.lib_indent.clone().map(Cow::Owned) } - fn get_resolve_options(&self) -> Option> { + fn get_resolve_options(&self) -> Option> { self.root_module_ctxt.resolve_options.clone() } diff --git a/crates/rspack_core/src/context_module.rs b/crates/rspack_core/src/context_module.rs index 53b1764c89b..08c69bd772d 100644 --- a/crates/rspack_core/src/context_module.rs +++ b/crates/rspack_core/src/context_module.rs @@ -136,7 +136,7 @@ pub struct ContextModuleOptions { pub resource_fragment: String, pub context_options: ContextOptions, pub layer: Option, - pub resolve_options: Option>, + pub resolve_options: Option>, pub type_prefix: ContextTypePrefix, } diff --git a/crates/rspack_core/src/context_module_factory.rs b/crates/rspack_core/src/context_module_factory.rs index f2e2ae777cf..ca1ae462e77 100644 --- a/crates/rspack_core/src/context_module_factory.rs +++ b/crates/rspack_core/src/context_module_factory.rs @@ -125,7 +125,10 @@ impl ContextModuleFactory { tracing::trace!("resolving context module path {}", options.resource); let resolver = &resolver_factory.get(ResolveOptionsWithDependencyType { - resolve_options: options.resolve_options.clone(), + resolve_options: options + .resolve_options + .clone() + .map(|r| Box::new(Arc::unwrap_or_clone(r))), resolve_to_context: false, dependency_category: options.context_options.category, }); diff --git a/crates/rspack_core/src/module.rs b/crates/rspack_core/src/module.rs index a211cd4170a..4833bec9f20 100644 --- a/crates/rspack_core/src/module.rs +++ b/crates/rspack_core/src/module.rs @@ -329,7 +329,7 @@ pub trait Module: /// Resolve options matched by module rules. /// e.g `javascript/esm` may have special resolving options like `fullySpecified`. /// `css` and `css/module` may have special resolving options like `preferRelative`. - fn get_resolve_options(&self) -> Option> { + fn get_resolve_options(&self) -> Option> { None } diff --git a/crates/rspack_core/src/module_factory.rs b/crates/rspack_core/src/module_factory.rs index e011910eb25..376df7f71a3 100644 --- a/crates/rspack_core/src/module_factory.rs +++ b/crates/rspack_core/src/module_factory.rs @@ -6,19 +6,20 @@ use rustc_hash::FxHashSet as HashSet; use crate::{ BoxDependency, BoxModule, CompilationId, CompilerOptions, Context, ModuleIdentifier, ModuleLayer, - Resolve, + Resolve, ResolverFactory, }; #[derive(Debug, Clone)] pub struct ModuleFactoryCreateData { pub compilation_id: CompilationId, - pub resolve_options: Option>, + pub resolve_options: Option>, pub options: Arc, pub context: Context, pub dependencies: Vec, pub issuer: Option>, pub issuer_identifier: Option, pub issuer_layer: Option, + pub resolver_factory: Arc, pub file_dependencies: HashSet, pub context_dependencies: HashSet, diff --git a/crates/rspack_core/src/normal_module.rs b/crates/rspack_core/src/normal_module.rs index 8509f119f3d..b5c5731c913 100644 --- a/crates/rspack_core/src/normal_module.rs +++ b/crates/rspack_core/src/normal_module.rs @@ -127,7 +127,7 @@ pub struct NormalModule { source: NormalModuleSource, /// Resolve options derived from [Rule.resolve] - resolve_options: Option>, + resolve_options: Option>, /// Parser options derived from [Rule.parser] parser_options: Option, /// Generator options derived from [Rule.generator] @@ -197,7 +197,7 @@ impl NormalModule { generator_options: Option, match_resource: Option, resource_data: Arc, - resolve_options: Option>, + resolve_options: Option>, loaders: Vec, ) -> Self { let module_type = module_type.into(); @@ -720,7 +720,7 @@ impl Module for NormalModule { Some(Cow::Owned(ident)) } - fn get_resolve_options(&self) -> Option> { + fn get_resolve_options(&self) -> Option> { self.resolve_options.clone() } diff --git a/crates/rspack_core/src/normal_module_factory.rs b/crates/rspack_core/src/normal_module_factory.rs index 2859d227df5..015449eeeff 100644 --- a/crates/rspack_core/src/normal_module_factory.rs +++ b/crates/rspack_core/src/normal_module_factory.rs @@ -329,7 +329,7 @@ impl NormalModuleFactory { span: dependency_source_span, // take the options is safe here, because it // is not used in after_resolve hooks - resolve_options: data.resolve_options.take(), + resolve_options: data.resolve_options.clone(), resolve_to_context: false, optional: dependency_optional, file_dependencies: &mut file_dependencies, @@ -641,7 +641,7 @@ impl NormalModuleFactory { Ok(rules) } - fn calculate_resolve_options(&self, module_rules: &[&ModuleRuleEffect]) -> Option> { + fn calculate_resolve_options(&self, module_rules: &[&ModuleRuleEffect]) -> Option> { let mut resolved: Option = None; for rule in module_rules { if let Some(rule_resolve) = &rule.resolve { @@ -652,7 +652,7 @@ impl NormalModuleFactory { } } } - resolved.map(Box::new) + resolved.map(Arc::new) } fn calculate_side_effects(&self, module_rules: &[&ModuleRuleEffect]) -> Option { diff --git a/crates/rspack_core/src/options/externals.rs b/crates/rspack_core/src/options/externals.rs index cc8de9bb6a7..480234eece8 100644 --- a/crates/rspack_core/src/options/externals.rs +++ b/crates/rspack_core/src/options/externals.rs @@ -1,10 +1,12 @@ -use std::fmt::Debug; +use std::{fmt::Debug, sync::Arc}; use futures::future::BoxFuture; use rspack_error::Result; use rspack_regex::RspackRegex; use rustc_hash::FxHashMap as HashMap; +use crate::{ResolveOptionsWithDependencyType, ResolverFactory}; + pub type Externals = Vec; #[derive(Debug)] @@ -26,6 +28,8 @@ pub struct ExternalItemFnCtx { pub context: String, pub dependency_type: String, pub context_info: ContextInfo, + pub resolve_options_with_dependency_type: ResolveOptionsWithDependencyType, + pub resolver_factory: Arc, } pub struct ExternalItemFnResult { diff --git a/crates/rspack_core/src/resolver/mod.rs b/crates/rspack_core/src/resolver/mod.rs index 0c0ac472732..20afe2c546b 100644 --- a/crates/rspack_core/src/resolver/mod.rs +++ b/crates/rspack_core/src/resolver/mod.rs @@ -5,6 +5,7 @@ use std::borrow::Borrow; use std::fmt; use std::fs; use std::path::PathBuf; +use std::sync::Arc; use std::sync::LazyLock; use regex::Regex; @@ -41,7 +42,7 @@ pub struct ResolveArgs<'a> { pub dependency_type: &'a DependencyType, pub dependency_category: &'a DependencyCategory, pub span: Option, - pub resolve_options: Option>, + pub resolve_options: Option>, pub resolve_to_context: bool, pub optional: bool, pub file_dependencies: &'a mut FxHashSet, @@ -94,7 +95,9 @@ pub fn resolve_for_error_hints( plugin_driver: &SharedPluginDriver, ) -> Option { let dep = ResolveOptionsWithDependencyType { - resolve_options: args.resolve_options.clone(), + resolve_options: args + .resolve_options + .map(|r| Box::new(Arc::unwrap_or_clone(r))), resolve_to_context: args.resolve_to_context, dependency_category: *args.dependency_category, }; @@ -284,7 +287,10 @@ pub async fn resolve( plugin_driver: &SharedPluginDriver, ) -> Result { let dep = ResolveOptionsWithDependencyType { - resolve_options: args.resolve_options.clone(), + resolve_options: args + .resolve_options + .clone() + .map(|r| Box::new(Arc::unwrap_or_clone(r))), resolve_to_context: args.resolve_to_context, dependency_category: *args.dependency_category, }; diff --git a/crates/rspack_plugin_externals/src/plugin.rs b/crates/rspack_plugin_externals/src/plugin.rs index c10dddffa92..6efa2f352c0 100644 --- a/crates/rspack_plugin_externals/src/plugin.rs +++ b/crates/rspack_plugin_externals/src/plugin.rs @@ -1,12 +1,12 @@ -use std::fmt::Debug; use std::sync::LazyLock; +use std::{fmt::Debug, sync::Arc}; use regex::Regex; use rspack_core::{ ApplyContext, BoxModule, CompilerOptions, ContextInfo, DependencyMeta, ExternalItem, ExternalItemFnCtx, ExternalItemValue, ExternalModule, ExternalRequest, ExternalRequestValue, ExternalType, ExternalTypeEnum, ModuleDependency, ModuleExt, ModuleFactoryCreateData, - NormalModuleFactoryFactorize, Plugin, PluginContext, + NormalModuleFactoryFactorize, Plugin, PluginContext, ResolveOptionsWithDependencyType, }; use rspack_error::Result; use rspack_hook::{plugin, plugin_hook}; @@ -182,6 +182,19 @@ async fn factorize(&self, data: &mut ModuleFactoryCreateData) -> Result ((context: string, request: string, callback: (err?: Error, result?: string) => void) => void) | ((context: string, request: string) => Promise); }; // @public @@ -2015,15 +2017,13 @@ export type ExternalItemValue = string | boolean | string[] | ExternalItemUmdVal export type Externals = ExternalItem | ExternalItem[]; // @public (undocumented) -export const ExternalsPlugin: { - new (type: string, externals: Externals): { - name: BuiltinPluginName; - _args: [type: string, externals: Externals]; - affectedHooks: "done" | "make" | "compile" | "emit" | "afterEmit" | "invalid" | "thisCompilation" | "afterDone" | "compilation" | "normalModuleFactory" | "contextModuleFactory" | "initialize" | "shouldEmit" | "infrastructureLog" | "beforeRun" | "run" | "assetEmitted" | "failed" | "shutdown" | "watchRun" | "watchClose" | "environment" | "afterEnvironment" | "afterPlugins" | "afterResolvers" | "beforeCompile" | "afterCompile" | "finishMake" | "entryOption" | undefined; - raw(compiler: Compiler_2): BuiltinPlugin; - apply(compiler: Compiler_2): void; - }; -}; +export class ExternalsPlugin extends RspackBuiltinPlugin { + constructor(type: string, externals: Externals); + // (undocumented) + name: BuiltinPluginName; + // (undocumented) + raw(compiler: Compiler): BuiltinPlugin | undefined; +} // @public export type ExternalsPresets = { @@ -6490,107 +6490,7 @@ export const rspackOptions: z.ZodObject<{ } | undefined; } | undefined; }>>; - externals: z.ZodOptional]>, z.ZodRecord, z.ZodArray]>, ZodRspackCrossChecker]>>]>, z.ZodFunction; - dependencyType: z.ZodOptional; - request: z.ZodOptional; - contextInfo: z.ZodOptional>; - }, "strict", z.ZodTypeAny, { - request?: string | undefined; - context?: string | undefined; - dependencyType?: string | undefined; - contextInfo?: { - issuer: string; - } | undefined; - }, { - request?: string | undefined; - context?: string | undefined; - dependencyType?: string | undefined; - contextInfo?: { - issuer: string; - } | undefined; - }>, z.ZodFunction>, z.ZodOptional, z.ZodArray]>, ZodRspackCrossChecker]>>, z.ZodOptional>], z.ZodUnknown>, z.ZodVoid>], z.ZodUnknown>, z.ZodUnknown>]>, z.ZodFunction; - dependencyType: z.ZodOptional; - request: z.ZodOptional; - contextInfo: z.ZodOptional>; - }, "strict", z.ZodTypeAny, { - request?: string | undefined; - context?: string | undefined; - dependencyType?: string | undefined; - contextInfo?: { - issuer: string; - } | undefined; - }, { - request?: string | undefined; - context?: string | undefined; - dependencyType?: string | undefined; - contextInfo?: { - issuer: string; - } | undefined; - }>], z.ZodUnknown>, z.ZodPromise, z.ZodArray]>, ZodRspackCrossChecker]>>>]>, "many">, z.ZodUnion<[z.ZodUnion<[z.ZodUnion<[z.ZodUnion<[z.ZodString, z.ZodType]>, z.ZodRecord, z.ZodArray]>, ZodRspackCrossChecker]>>]>, z.ZodFunction; - dependencyType: z.ZodOptional; - request: z.ZodOptional; - contextInfo: z.ZodOptional>; - }, "strict", z.ZodTypeAny, { - request?: string | undefined; - context?: string | undefined; - dependencyType?: string | undefined; - contextInfo?: { - issuer: string; - } | undefined; - }, { - request?: string | undefined; - context?: string | undefined; - dependencyType?: string | undefined; - contextInfo?: { - issuer: string; - } | undefined; - }>, z.ZodFunction>, z.ZodOptional, z.ZodArray]>, ZodRspackCrossChecker]>>, z.ZodOptional>], z.ZodUnknown>, z.ZodVoid>], z.ZodUnknown>, z.ZodUnknown>]>, z.ZodFunction; - dependencyType: z.ZodOptional; - request: z.ZodOptional; - contextInfo: z.ZodOptional>; - }, "strict", z.ZodTypeAny, { - request?: string | undefined; - context?: string | undefined; - dependencyType?: string | undefined; - contextInfo?: { - issuer: string; - } | undefined; - }, { - request?: string | undefined; - context?: string | undefined; - dependencyType?: string | undefined; - contextInfo?: { - issuer: string; - } | undefined; - }>], z.ZodUnknown>, z.ZodPromise, z.ZodArray]>, ZodRspackCrossChecker]>>>]>]>>; + externals: z.ZodOptional]>, z.ZodRecord, z.ZodArray]>, ZodRspackCrossChecker]>>]>, z.ZodFunction, z.ZodFunction>, z.ZodOptional, z.ZodArray]>, ZodRspackCrossChecker]>>, z.ZodOptional>], z.ZodUnknown>, z.ZodVoid>], z.ZodUnknown>, z.ZodUnknown>]>, z.ZodFunction], z.ZodUnknown>, z.ZodPromise, z.ZodArray]>, ZodRspackCrossChecker]>>>]>, "many">, z.ZodUnion<[z.ZodUnion<[z.ZodUnion<[z.ZodUnion<[z.ZodString, z.ZodType]>, z.ZodRecord, z.ZodArray]>, ZodRspackCrossChecker]>>]>, z.ZodFunction, z.ZodFunction>, z.ZodOptional, z.ZodArray]>, ZodRspackCrossChecker]>>, z.ZodOptional>], z.ZodUnknown>, z.ZodVoid>], z.ZodUnknown>, z.ZodUnknown>]>, z.ZodFunction], z.ZodUnknown>, z.ZodPromise, z.ZodArray]>, ZodRspackCrossChecker]>>>]>]>>; externalsType: z.ZodOptional>; externalsPresets: z.ZodOptional; @@ -8865,35 +8765,7 @@ export const rspackOptions: z.ZodObject<{ } | undefined; loader?: Record | undefined; resolveLoader?: t.ResolveOptions | undefined; - externals?: string | RegExp | Record | ((args_0: { - request?: string | undefined; - context?: string | undefined; - dependencyType?: string | undefined; - contextInfo?: { - issuer: string; - } | undefined; - }, args_1: (args_0: Error | undefined, args_1: string | boolean | string[] | t.ExternalItemUmdValue | t.ExternalItemObjectValue | undefined, args_2: "module" | "global" | "system" | "script" | "commonjs" | "umd" | "amd" | "var" | "jsonp" | "import" | "assign" | "this" | "window" | "self" | "commonjs2" | "commonjs-module" | "commonjs-static" | "amd-require" | "umd2" | "promise" | "module-import" | "node-commonjs" | "commonjs-import" | undefined, ...args: unknown[]) => void, ...args: unknown[]) => unknown) | ((args_0: { - request?: string | undefined; - context?: string | undefined; - dependencyType?: string | undefined; - contextInfo?: { - issuer: string; - } | undefined; - }, ...args: unknown[]) => Promise) | (string | RegExp | Record | ((args_0: { - request?: string | undefined; - context?: string | undefined; - dependencyType?: string | undefined; - contextInfo?: { - issuer: string; - } | undefined; - }, args_1: (args_0: Error | undefined, args_1: string | boolean | string[] | t.ExternalItemUmdValue | t.ExternalItemObjectValue | undefined, args_2: "module" | "global" | "system" | "script" | "commonjs" | "umd" | "amd" | "var" | "jsonp" | "import" | "assign" | "this" | "window" | "self" | "commonjs2" | "commonjs-module" | "commonjs-static" | "amd-require" | "umd2" | "promise" | "module-import" | "node-commonjs" | "commonjs-import" | undefined, ...args: unknown[]) => void, ...args: unknown[]) => unknown) | ((args_0: { - request?: string | undefined; - context?: string | undefined; - dependencyType?: string | undefined; - contextInfo?: { - issuer: string; - } | undefined; - }, ...args: unknown[]) => Promise))[] | undefined; + externals?: string | RegExp | Record | ((args_0: t.ExternalItemFunctionData, args_1: (args_0: Error | undefined, args_1: string | boolean | string[] | t.ExternalItemUmdValue | t.ExternalItemObjectValue | undefined, args_2: "module" | "global" | "system" | "script" | "commonjs" | "umd" | "amd" | "var" | "jsonp" | "import" | "assign" | "this" | "window" | "self" | "commonjs2" | "commonjs-module" | "commonjs-static" | "amd-require" | "umd2" | "promise" | "module-import" | "node-commonjs" | "commonjs-import" | undefined, ...args: unknown[]) => void, ...args: unknown[]) => unknown) | ((args_0: t.ExternalItemFunctionData, ...args: unknown[]) => Promise) | (string | RegExp | Record | ((args_0: t.ExternalItemFunctionData, args_1: (args_0: Error | undefined, args_1: string | boolean | string[] | t.ExternalItemUmdValue | t.ExternalItemObjectValue | undefined, args_2: "module" | "global" | "system" | "script" | "commonjs" | "umd" | "amd" | "var" | "jsonp" | "import" | "assign" | "this" | "window" | "self" | "commonjs2" | "commonjs-module" | "commonjs-static" | "amd-require" | "umd2" | "promise" | "module-import" | "node-commonjs" | "commonjs-import" | undefined, ...args: unknown[]) => void, ...args: unknown[]) => unknown) | ((args_0: t.ExternalItemFunctionData, ...args: unknown[]) => Promise))[] | undefined; externalsType?: "module" | "global" | "system" | "script" | "commonjs" | "umd" | "amd" | "var" | "jsonp" | "import" | "assign" | "this" | "window" | "self" | "commonjs2" | "commonjs-module" | "commonjs-static" | "amd-require" | "umd2" | "promise" | "module-import" | "node-commonjs" | "commonjs-import" | undefined; externalsPresets?: { node?: boolean | undefined; @@ -9493,35 +9365,7 @@ export const rspackOptions: z.ZodObject<{ } | undefined; loader?: Record | undefined; resolveLoader?: t.ResolveOptions | undefined; - externals?: string | RegExp | Record | ((args_0: { - request?: string | undefined; - context?: string | undefined; - dependencyType?: string | undefined; - contextInfo?: { - issuer: string; - } | undefined; - }, args_1: (args_0: Error | undefined, args_1: string | boolean | string[] | t.ExternalItemUmdValue | t.ExternalItemObjectValue | undefined, args_2: "module" | "global" | "system" | "script" | "commonjs" | "umd" | "amd" | "var" | "jsonp" | "import" | "assign" | "this" | "window" | "self" | "commonjs2" | "commonjs-module" | "commonjs-static" | "amd-require" | "umd2" | "promise" | "module-import" | "node-commonjs" | "commonjs-import" | undefined, ...args: unknown[]) => void, ...args: unknown[]) => unknown) | ((args_0: { - request?: string | undefined; - context?: string | undefined; - dependencyType?: string | undefined; - contextInfo?: { - issuer: string; - } | undefined; - }, ...args: unknown[]) => Promise) | (string | RegExp | Record | ((args_0: { - request?: string | undefined; - context?: string | undefined; - dependencyType?: string | undefined; - contextInfo?: { - issuer: string; - } | undefined; - }, args_1: (args_0: Error | undefined, args_1: string | boolean | string[] | t.ExternalItemUmdValue | t.ExternalItemObjectValue | undefined, args_2: "module" | "global" | "system" | "script" | "commonjs" | "umd" | "amd" | "var" | "jsonp" | "import" | "assign" | "this" | "window" | "self" | "commonjs2" | "commonjs-module" | "commonjs-static" | "amd-require" | "umd2" | "promise" | "module-import" | "node-commonjs" | "commonjs-import" | undefined, ...args: unknown[]) => void, ...args: unknown[]) => unknown) | ((args_0: { - request?: string | undefined; - context?: string | undefined; - dependencyType?: string | undefined; - contextInfo?: { - issuer: string; - } | undefined; - }, ...args: unknown[]) => Promise))[] | undefined; + externals?: string | RegExp | Record | ((args_0: t.ExternalItemFunctionData, args_1: (args_0: Error | undefined, args_1: string | boolean | string[] | t.ExternalItemUmdValue | t.ExternalItemObjectValue | undefined, args_2: "module" | "global" | "system" | "script" | "commonjs" | "umd" | "amd" | "var" | "jsonp" | "import" | "assign" | "this" | "window" | "self" | "commonjs2" | "commonjs-module" | "commonjs-static" | "amd-require" | "umd2" | "promise" | "module-import" | "node-commonjs" | "commonjs-import" | undefined, ...args: unknown[]) => void, ...args: unknown[]) => unknown) | ((args_0: t.ExternalItemFunctionData, ...args: unknown[]) => Promise) | (string | RegExp | Record | ((args_0: t.ExternalItemFunctionData, args_1: (args_0: Error | undefined, args_1: string | boolean | string[] | t.ExternalItemUmdValue | t.ExternalItemObjectValue | undefined, args_2: "module" | "global" | "system" | "script" | "commonjs" | "umd" | "amd" | "var" | "jsonp" | "import" | "assign" | "this" | "window" | "self" | "commonjs2" | "commonjs-module" | "commonjs-static" | "amd-require" | "umd2" | "promise" | "module-import" | "node-commonjs" | "commonjs-import" | undefined, ...args: unknown[]) => void, ...args: unknown[]) => unknown) | ((args_0: t.ExternalItemFunctionData, ...args: unknown[]) => Promise))[] | undefined; externalsType?: "module" | "global" | "system" | "script" | "commonjs" | "umd" | "amd" | "var" | "jsonp" | "import" | "assign" | "this" | "window" | "self" | "commonjs2" | "commonjs-module" | "commonjs-static" | "amd-require" | "umd2" | "promise" | "module-import" | "node-commonjs" | "commonjs-import" | undefined; externalsPresets?: { node?: boolean | undefined; diff --git a/packages/rspack/src/builtin-plugin/ExternalsPlugin.ts b/packages/rspack/src/builtin-plugin/ExternalsPlugin.ts index 07551a5cb8c..de50c04a286 100644 --- a/packages/rspack/src/builtin-plugin/ExternalsPlugin.ts +++ b/packages/rspack/src/builtin-plugin/ExternalsPlugin.ts @@ -1,29 +1,44 @@ import { + type BuiltinPlugin, BuiltinPluginName, type RawExternalsPluginOptions } from "@rspack/binding"; -import type { ExternalItem, ExternalItemValue, Externals } from ".."; -import { create } from "./base"; +import type { Compiler, ExternalItem, ExternalItemValue, Externals } from ".."; +import { Resolver } from "../Resolver"; +import { RspackBuiltinPlugin, createBuiltinPlugin } from "./base"; -export const ExternalsPlugin = create( - BuiltinPluginName.ExternalsPlugin, - (type: string, externals: Externals): RawExternalsPluginOptions => { - return { +export class ExternalsPlugin extends RspackBuiltinPlugin { + name = BuiltinPluginName.ExternalsPlugin; + + constructor( + private type: string, + private externals: Externals + ) { + super(); + } + + raw(compiler: Compiler): BuiltinPlugin | undefined { + const { type, externals } = this; + const raw: RawExternalsPluginOptions = { type, externals: (Array.isArray(externals) ? externals : [externals]) .filter(Boolean) - .map(getRawExternalItem) + .map(item => getRawExternalItem(compiler, item)) }; + return createBuiltinPlugin(this.name, raw); } -); +} type ArrayType = T extends (infer R)[] ? R : never; type RecordValue = T extends Record ? R : never; type RawExternalItem = ArrayType; type RawExternalItemValue = RecordValue; -function getRawExternalItem(item: ExternalItem | undefined): RawExternalItem { +function getRawExternalItem( + compiler: Compiler, + item: ExternalItem | undefined +): RawExternalItem { if (typeof item === "string" || item instanceof RegExp) { return item; } @@ -31,13 +46,68 @@ function getRawExternalItem(item: ExternalItem | undefined): RawExternalItem { if (typeof item === "function") { return async ctx => { return await new Promise((resolve, reject) => { - const promise = item(ctx, (err, result, type) => { - if (err) reject(err); - resolve({ - result: getRawExternalItemValueFormFnResult(result), - externalType: type - }); - }) as Promise; + const data = ctx.data(); + const promise = item( + { + request: data.request, + dependencyType: data.dependencyType, + context: data.context, + contextInfo: { + issuer: data.contextInfo.issuer, + issuerLayer: data.contextInfo.issuerLayer ?? null + }, + getResolve: function getResolve(options) { + const resolver = new Resolver(ctx.getResolver()); + const getResolveContext = () => ({ + fileDependencies: compiler._lastCompilation!.fileDependencies, + missingDependencies: + compiler._lastCompilation!.missingDependencies, + contextDependencies: + compiler._lastCompilation!.contextDependencies + }); + const child = options ? resolver.withOptions(options) : resolver; + return (context, request, callback) => { + if (callback) { + child.resolve( + {}, + context, + request, + getResolveContext(), + (err, result) => { + if (err) return callback(err); + // Sync with how webpack fixes the type: + // https://github.com/webpack/webpack/blob/a2ad76cd50ae780dead395c68ea67d46de9828f3/lib/ExternalModuleFactoryPlugin.js#L276 + callback( + undefined, + typeof result === "string" ? result : undefined + ); + } + ); + } else { + return new Promise((resolve, reject) => { + child.resolve( + {}, + context, + request, + getResolveContext(), + (err, result) => { + if (err) reject(err); + else resolve(result); + } + ); + }); + } + }; + } + }, + (err, result, type) => { + if (err) reject(err); + resolve({ + result: getRawExternalItemValueFormFnResult(result), + externalType: type + }); + } + ) as Promise; if (promise?.then) { promise.then( result => diff --git a/packages/rspack/src/config/types.ts b/packages/rspack/src/config/types.ts index 1d141ec49cd..41f5db7cafd 100644 --- a/packages/rspack/src/config/types.ts +++ b/packages/rspack/src/config/types.ts @@ -1373,7 +1373,20 @@ export type ExternalItemFunctionData = { request?: string; contextInfo?: { issuer: string; + issuerLayer?: string | null; }; + /** + * Get a resolve function with the current resolver options. + */ + getResolve?: ( + options?: ResolveOptions + ) => + | (( + context: string, + request: string, + callback: (err?: Error, result?: string) => void + ) => void) + | ((context: string, request: string) => Promise); }; /** diff --git a/packages/rspack/src/config/zod.ts b/packages/rspack/src/config/zod.ts index b1b7b980ca0..8e4ed818f43 100644 --- a/packages/rspack/src/config/zod.ts +++ b/packages/rspack/src/config/zod.ts @@ -863,8 +863,31 @@ const externalItemFunctionData = z.strictObject({ request: z.string().optional(), contextInfo: z .strictObject({ - issuer: z.string() + issuer: z.string(), + issuerLayer: z.string().or(z.null()).optional() }) + .optional(), + getResolve: z + .function() + .returns( + z + .function() + .args(z.string(), z.string()) + .returns(z.promise(z.string())) + .or( + z + .function() + .args( + z.string(), + z.string(), + z + .function() + .args(z.instanceof(Error).optional(), z.string().optional()) + .returns(z.void()) + ) + .returns(z.void()) + ) + ) .optional() }) satisfies z.ZodType; @@ -876,7 +899,7 @@ const externalItem = z z .function() .args( - externalItemFunctionData, + externalItemFunctionData as z.ZodType, z .function() .args( @@ -890,14 +913,13 @@ const externalItem = z .or( z .function() - .args(externalItemFunctionData) + .args(externalItemFunctionData as z.ZodType) .returns(z.promise(externalItemValue)) ) satisfies z.ZodType; const externals = externalItem .array() .or(externalItem) satisfies z.ZodType; -//#endregion //#region ExternalsPresets const externalsPresets = z.strictObject({ diff --git a/packages/rspack/src/loader-runner/index.ts b/packages/rspack/src/loader-runner/index.ts index 99794a3a84c..b2bd8c174f5 100644 --- a/packages/rspack/src/loader-runner/index.ts +++ b/packages/rspack/src/loader-runner/index.ts @@ -599,7 +599,7 @@ export async function runLoaders( }; loaderContext.getResolve = function getResolve(options) { - const child = options ? resolver.withOptions(options as any) : resolver; + const child = options ? resolver.withOptions(options) : resolver; return (context, request, callback) => { if (callback) { child.resolve({}, context, request, getResolveContext(), callback); diff --git a/tests/webpack-test/configCases/externals/resolve/node_modules/external.js b/tests/webpack-test/configCases/externals/resolve/node_modules/external.js new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/webpack-test/configCases/externals/resolve/test.filter.js b/tests/webpack-test/configCases/externals/resolve/test.filter.js deleted file mode 100644 index 042493e42a5..00000000000 --- a/tests/webpack-test/configCases/externals/resolve/test.filter.js +++ /dev/null @@ -1,2 +0,0 @@ -// TODO: Should create a issue for this test -module.exports = () => { return false }