diff --git a/packages/next-swc/crates/next-core/src/next_server/resolve.rs b/packages/next-swc/crates/next-core/src/next_server/resolve.rs index 43c1138f72668..2cee86cf225ab 100644 --- a/packages/next-swc/crates/next-core/src/next_server/resolve.rs +++ b/packages/next-swc/crates/next-core/src/next_server/resolve.rs @@ -3,15 +3,12 @@ use turbo_tasks::{Value, Vc}; use turbopack_binding::{ turbo::tasks_fs::{glob::Glob, FileJsonContent, FileSystemPath}, turbopack::core::{ - reference_type::{ - CommonJsReferenceSubType, EcmaScriptModulesReferenceSubType, ReferenceType, - }, + reference_type::{EcmaScriptModulesReferenceSubType, ReferenceType}, resolve::{ find_context_file, node::{node_cjs_resolve_options, node_esm_resolve_options}, package_json, parse::Request, - pattern::Pattern, plugin::{ResolvePlugin, ResolvePluginCondition}, resolve, FindContextFileResult, ResolveResult, ResolveResultItem, ResolveResultOption, }, @@ -60,44 +57,6 @@ impl ExternalCjsModulesResolvePlugin { } } -#[turbo_tasks::function] -async fn is_node_resolveable( - context: Vc, - request: Vc, - expected: Vc, - is_esm: bool, -) -> Result> { - let node_resolve_result = if is_esm { - resolve( - context, - Value::new(ReferenceType::EcmaScriptModules( - EcmaScriptModulesReferenceSubType::Undefined, - )), - request, - node_esm_resolve_options(context.root()), - ) - } else { - resolve( - context, - Value::new(ReferenceType::CommonJs(CommonJsReferenceSubType::Undefined)), - request, - node_cjs_resolve_options(context.root()), - ) - }; - let primary_node_assets = node_resolve_result.primary_sources().await?; - let Some(&node_asset) = primary_node_assets.first() else { - // can't resolve request with node.js options - return Ok(Vc::cell(false)); - }; - - if node_asset.ident().path().resolve().await? != expected.resolve().await? { - // node.js resolves to a different file - return Ok(Vc::cell(false)); - } - - Ok(Vc::cell(true)) -} - #[turbo_tasks::function] fn condition(root: Vc) -> Vc { ResolvePluginCondition::new(root, Glob::new("**/node_modules/**".to_string())) @@ -151,8 +110,9 @@ impl ResolvePlugin for ExternalCjsModulesResolvePlugin { } } - let is_esm = ReferenceType::EcmaScriptModules(EcmaScriptModulesReferenceSubType::Undefined) - .includes(&reference_type); + let is_esm = self.import_externals + && ReferenceType::EcmaScriptModules(EcmaScriptModulesReferenceSubType::Undefined) + .includes(&reference_type); enum FileType { CommonJs, @@ -197,81 +157,46 @@ impl ResolvePlugin for ExternalCjsModulesResolvePlugin { Ok(FileType::Unsupported) } - let file_type = get_file_type(fs_path, raw_fs_path).await?; + let node_resolved = resolve( + context, + reference_type.clone(), + request, + if is_esm { + node_esm_resolve_options(context.root()) + } else { + node_cjs_resolve_options(context.root()) + }, + ); + let Some(result) = *node_resolved.first_source().await? else { + // this can't resolve with node.js, so bundle it + return Ok(ResolveResultOption::none()); + }; + let path = result.ident().path(); + let file_type = get_file_type(path, &*path.await?).await?; - let (expected, is_esm) = match (file_type, is_esm) { + match (file_type, is_esm) { (FileType::Unsupported, _) => { // unsupported file type, bundle it - return Ok(ResolveResultOption::none()); + Ok(ResolveResultOption::none()) + } + (FileType::CommonJs, _) => { + // mark as external + Ok(ResolveResultOption::some( + ResolveResult::primary(ResolveResultItem::OriginalReferenceExternal).cell(), + )) } - (FileType::CommonJs, false) => (fs_path, false), - (FileType::CommonJs, true) => (fs_path, self.import_externals), - (FileType::EcmaScriptModule, false) => (fs_path, false), (FileType::EcmaScriptModule, true) => { - if self.import_externals { - (fs_path, true) - } else { - // We verify with the CommonJS alternative - let cjs_resolved = resolve( - context, - reference_type.clone(), - request, - node_cjs_resolve_options(context.root()), - ); - let Some(result) = *cjs_resolved.first_source().await? else { - // this can't resolve with commonjs, so bundle it - return Ok(ResolveResultOption::none()); - }; - let path = result.ident().path(); - let file_type = get_file_type(path, &*path.await?).await?; - if !matches!(file_type, FileType::CommonJs) { - // even with require() this resolves to a ESM, which would break node.js - // bundle it - // This happens for invalid packages like `textlinestream` - return Ok(ResolveResultOption::none()); - } - - (path, false) - } + // mark as external + Ok(ResolveResultOption::some( + ResolveResult::primary(ResolveResultItem::OriginalReferenceExternal).cell(), + )) } - }; - - let is_resolveable = - *is_node_resolveable(self.project_path, request, expected, is_esm).await?; - - if !is_resolveable { - if is_esm { - // When it's not resolveable as ESM, there is maybe an extension missing, - // try to add .js - if let Some(mut request_str) = request.await?.request() { - if !request_str.ends_with(".js") { - request_str += ".js"; - let new_request = - Request::parse(Value::new(Pattern::Constant(request_str.clone()))); - let is_resolveable = - *is_node_resolveable(self.project_path, new_request, expected, is_esm) - .await?; - if is_resolveable { - // mark as external, but with .js extension - return Ok(ResolveResultOption::some( - ResolveResult::primary( - ResolveResultItem::OriginalReferenceTypeExternal(request_str), - ) - .cell(), - )); - } - } - } + (FileType::EcmaScriptModule, false) => { + // even with require() this resolves to a ESM, + // which would break node.js, bundle it + Ok(ResolveResultOption::none()) } - - // this can't resolve with node.js, so bundle it - return Ok(ResolveResultOption::none()); } - - // mark as external - Ok(ResolveResultOption::some( - ResolveResult::primary(ResolveResultItem::OriginalReferenceExternal).cell(), - )) } }