Turbopack: align automatic externals code with webpack (#58851)
### What? * remove the additional check which verifies identity of resolved and external module. * `serverComponentsExternals` will force it being an external ### Why? ### How? Closes PACK-2032 --------- Co-authored-by: Tim Neutkens <tim@timneutkens.nl>
This commit is contained in:
parent
6bfd1458b2
commit
2e28fa113e
1 changed files with 40 additions and 115 deletions
|
@ -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<FileSystemPath>,
|
||||
request: Vc<Request>,
|
||||
expected: Vc<FileSystemPath>,
|
||||
is_esm: bool,
|
||||
) -> Result<Vc<bool>> {
|
||||
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<FileSystemPath>) -> Vc<ResolvePluginCondition> {
|
||||
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 (expected, is_esm) = match (file_type, is_esm) {
|
||||
(FileType::Unsupported, _) => {
|
||||
// unsupported file type, bundle it
|
||||
return Ok(ResolveResultOption::none());
|
||||
}
|
||||
(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)
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let is_resolveable =
|
||||
*is_node_resolveable(self.project_path, request, expected, is_esm).await?;
|
||||
|
||||
if !is_resolveable {
|
||||
let node_resolved = resolve(
|
||||
context,
|
||||
reference_type.clone(),
|
||||
request,
|
||||
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(),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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?;
|
||||
|
||||
// mark as external
|
||||
Ok(ResolveResultOption::some(
|
||||
ResolveResult::primary(ResolveResultItem::OriginalReferenceExternal).cell(),
|
||||
))
|
||||
match (file_type, is_esm) {
|
||||
(FileType::Unsupported, _) => {
|
||||
// unsupported file type, bundle it
|
||||
Ok(ResolveResultOption::none())
|
||||
}
|
||||
(FileType::CommonJs, _) => {
|
||||
// mark as external
|
||||
Ok(ResolveResultOption::some(
|
||||
ResolveResult::primary(ResolveResultItem::OriginalReferenceExternal).cell(),
|
||||
))
|
||||
}
|
||||
(FileType::EcmaScriptModule, true) => {
|
||||
// mark as external
|
||||
Ok(ResolveResultOption::some(
|
||||
ResolveResult::primary(ResolveResultItem::OriginalReferenceExternal).cell(),
|
||||
))
|
||||
}
|
||||
(FileType::EcmaScriptModule, false) => {
|
||||
// even with require() this resolves to a ESM,
|
||||
// which would break node.js, bundle it
|
||||
Ok(ResolveResultOption::none())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue