Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions turbopack/crates/turbopack-core/src/reference_type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,7 @@ pub enum WorkerReferenceSubType {
WebWorker,
SharedWorker,
ServiceWorker,
NodeWorker,
Custom(u8),
Undefined,
}
Expand Down
29 changes: 21 additions & 8 deletions turbopack/crates/turbopack-ecmascript/src/analyzer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1788,15 +1788,19 @@ impl JsValue {
"module",
"The Node.js `module` module: https://nodejs.org/api/module.html",
),
WellKnownObjectKind::ChildProcess | WellKnownObjectKind::ChildProcessDefault => (
WellKnownObjectKind::WorkerThreadsModule | WellKnownObjectKind::WorkerThreadsModuleDefault => (
"worker_threads",
"The Node.js `worker_threads` module: https://nodejs.org/api/worker_threads.html",
),
WellKnownObjectKind::ChildProcessModule | WellKnownObjectKind::ChildProcessModuleDefault => (
"child_process",
"The Node.js child_process module: https://nodejs.org/api/child_process.html",
),
WellKnownObjectKind::OsModule | WellKnownObjectKind::OsModuleDefault => (
"os",
"The Node.js os module: https://nodejs.org/api/os.html",
),
WellKnownObjectKind::NodeProcess => (
WellKnownObjectKind::NodeProcessModule => (
"process",
"The Node.js process module: https://nodejs.org/api/process.html",
),
Expand Down Expand Up @@ -1954,6 +1958,10 @@ impl JsValue {
"load/loadSync".to_string(),
"require('@grpc/proto-loader').load(filepath, { includeDirs: [root] }) https://github.com/grpc/grpc-node"
),
WellKnownFunctionKind::NodeWorkerConstructor => (
"Worker".to_string(),
"The Node.js worker_threads Worker constructor: https://nodejs.org/api/worker_threads.html#worker_threads_class_worker"
),
WellKnownFunctionKind::WorkerConstructor => (
"Worker".to_string(),
"The standard Worker constructor: https://developer.mozilla.org/en-US/docs/Web/API/Worker/Worker"
Expand Down Expand Up @@ -3468,11 +3476,13 @@ pub enum WellKnownObjectKind {
ModuleModuleDefault,
UrlModule,
UrlModuleDefault,
ChildProcess,
ChildProcessDefault,
WorkerThreadsModule,
WorkerThreadsModuleDefault,
ChildProcessModule,
ChildProcessModuleDefault,
OsModule,
OsModuleDefault,
NodeProcess,
NodeProcessModule,
NodeProcessArgv,
NodeProcessEnv,
NodePreGyp,
Expand All @@ -3492,9 +3502,10 @@ impl WellKnownObjectKind {
Self::PathModule => Some(&["path"]),
Self::FsModule => Some(&["fs"]),
Self::UrlModule => Some(&["url"]),
Self::ChildProcess => Some(&["child_process"]),
Self::ChildProcessModule => Some(&["child_process"]),
Self::OsModule => Some(&["os"]),
Self::NodeProcess => Some(&["process"]),
Self::WorkerThreadsModule => Some(&["worker_threads"]),
Self::NodeProcessModule => Some(&["process"]),
Self::NodeProcessArgv => Some(&["process", "argv"]),
Self::NodeProcessEnv => Some(&["process", "env"]),
Self::NodeBuffer => Some(&["Buffer"]),
Expand Down Expand Up @@ -3623,6 +3634,8 @@ pub enum WellKnownFunctionKind {
NodeResolveFrom,
NodeProtobufLoad,
WorkerConstructor,
// The worker_threads Worker class
NodeWorkerConstructor,
URLConstructor,
}

Expand Down Expand Up @@ -3797,7 +3810,7 @@ pub mod test_utils {
),
"define" => JsValue::WellKnownFunction(WellKnownFunctionKind::Define),
"URL" => JsValue::WellKnownFunction(WellKnownFunctionKind::URLConstructor),
"process" => JsValue::WellKnownObject(WellKnownObjectKind::NodeProcess),
"process" => JsValue::WellKnownObject(WellKnownObjectKind::NodeProcessModule),
"Object" => JsValue::WellKnownObject(WellKnownObjectKind::GlobalObject),
"Buffer" => JsValue::WellKnownObject(WellKnownObjectKind::NodeBuffer),
_ => v.into_unknown(true, "unknown global"),
Expand Down
46 changes: 38 additions & 8 deletions turbopack/crates/turbopack-ecmascript/src/analyzer/well_known.rs
Original file line number Diff line number Diff line change
Expand Up @@ -609,13 +609,18 @@ async fn well_known_object_member(
WellKnownObjectKind::UrlModule | WellKnownObjectKind::UrlModuleDefault => {
url_module_member(kind, prop)
}
WellKnownObjectKind::ChildProcess | WellKnownObjectKind::ChildProcessDefault => {
child_process_module_member(kind, prop)
WellKnownObjectKind::WorkerThreadsModule
| WellKnownObjectKind::WorkerThreadsModuleDefault => {
worker_threads_module_member(kind, prop)
}
WellKnownObjectKind::ChildProcessModule
| WellKnownObjectKind::ChildProcessModuleDefault => child_process_module_member(kind, prop),
WellKnownObjectKind::OsModule | WellKnownObjectKind::OsModuleDefault => {
os_module_member(kind, prop)
}
WellKnownObjectKind::NodeProcess => node_process_member(prop, compile_time_info).await?,
WellKnownObjectKind::NodeProcessModule => {
node_process_member(prop, compile_time_info).await?
}
WellKnownObjectKind::NodePreGyp => node_pre_gyp(prop),
WellKnownObjectKind::NodeExpressApp => express(prop),
WellKnownObjectKind::NodeProtobufLoader => protobuf_loader(prop),
Expand Down Expand Up @@ -762,7 +767,7 @@ fn url_module_member(kind: WellKnownObjectKind, prop: JsValue) -> JsValue {
(.., Some("pathToFileURL")) => {
JsValue::WellKnownFunction(WellKnownFunctionKind::PathToFileUrl)
}
(WellKnownObjectKind::UrlModuleDefault, Some("default")) => {
(WellKnownObjectKind::UrlModule, Some("default")) => {
JsValue::WellKnownObject(WellKnownObjectKind::UrlModuleDefault)
}
_ => JsValue::unknown(
Expand All @@ -776,6 +781,27 @@ fn url_module_member(kind: WellKnownObjectKind, prop: JsValue) -> JsValue {
}
}

fn worker_threads_module_member(kind: WellKnownObjectKind, prop: JsValue) -> JsValue {
match (kind, prop.as_str()) {
(.., Some("Worker")) => {
JsValue::WellKnownFunction(WellKnownFunctionKind::NodeWorkerConstructor)
}
(WellKnownObjectKind::WorkerThreadsModule, Some("default")) => {
JsValue::WellKnownObject(WellKnownObjectKind::WorkerThreadsModuleDefault)
}
_ => JsValue::unknown(
JsValue::member(
Box::new(JsValue::WellKnownObject(
WellKnownObjectKind::WorkerThreadsModule,
)),
Box::new(prop),
),
true,
"unsupported property on Node.js worker_threads module",
),
}
}

fn child_process_module_member(kind: WellKnownObjectKind, prop: JsValue) -> JsValue {
let prop_str = prop.as_str();
match (kind, prop_str) {
Expand All @@ -785,13 +811,15 @@ fn child_process_module_member(kind: WellKnownObjectKind, prop: JsValue) -> JsVa
))
}
(.., Some("fork")) => JsValue::WellKnownFunction(WellKnownFunctionKind::ChildProcessFork),
(WellKnownObjectKind::ChildProcess, Some("default")) => {
JsValue::WellKnownObject(WellKnownObjectKind::ChildProcessDefault)
(WellKnownObjectKind::ChildProcessModule, Some("default")) => {
JsValue::WellKnownObject(WellKnownObjectKind::ChildProcessModuleDefault)
}

_ => JsValue::unknown(
JsValue::member(
Box::new(JsValue::WellKnownObject(WellKnownObjectKind::ChildProcess)),
Box::new(JsValue::WellKnownObject(
WellKnownObjectKind::ChildProcessModule,
)),
Box::new(prop),
),
true,
Expand Down Expand Up @@ -843,7 +871,9 @@ async fn node_process_member(
Some("env") => JsValue::WellKnownObject(WellKnownObjectKind::NodeProcessEnv),
_ => JsValue::unknown(
JsValue::member(
Box::new(JsValue::WellKnownObject(WellKnownObjectKind::NodeProcess)),
Box::new(JsValue::WellKnownObject(
WellKnownObjectKind::NodeProcessModule,
)),
Box::new(prop),
),
true,
Expand Down
12 changes: 3 additions & 9 deletions turbopack/crates/turbopack-ecmascript/src/parse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -176,15 +176,9 @@ pub async fn parse(
ty = display(&ty)
);

match parse_internal(
source,
ty,
transforms,
is_external_tracing && matches!(ty, EcmascriptModuleAssetType::EcmascriptExtensionless),
inline_helpers,
)
.instrument(span)
.await
match parse_internal(source, ty, transforms, is_external_tracing, inline_helpers)
.instrument(span)
.await
{
Ok(result) => Ok(result),
Err(error) => Err(error.context(format!(
Expand Down
100 changes: 73 additions & 27 deletions turbopack/crates/turbopack-ecmascript/src/references/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ use crate::{
},
ident::IdentReplacement,
member::MemberReplacement,
node::PackageJsonReference,
node::{FilePathModuleReference, PackageJsonReference},
require_context::{RequireContextAssetReference, RequireContextMap},
type_issue::SpecifiedModuleTypeIssue,
},
Expand Down Expand Up @@ -1646,8 +1646,27 @@ async fn handle_call<G: Fn(Vec<Effect>) + Send + Sync>(
.await
};

let make_issue_source =
let get_traced_project_dir = async || -> Result<FileSystemPath> {
// readFileSync("./foo") should always be relative to the project root, but this is
// dangerous inside of node_modules as it can cause a lot of false positives in the tracing,
// if some package does `path.join(dynamic)`, it would include everything from the project
// root as well.
//
// Also, when there's no cwd set (i.e. in a tracing-specific module context, as we shouldn't
// assume a `process.cwd()` for all of node_modules), fallback to the source file directory.
// This still allows relative file accesses, just not from the project root.
if allow_project_root_tracing
&& let Some(cwd) = compile_time_info.environment().cwd().owned().await?
{
Ok(cwd)
} else {
Ok(source.ident().path().await?.parent())
}
};

let get_issue_source =
|| IssueSource::from_swc_offsets(source, span.lo.to_u32(), span.hi.to_u32());

if new {
match func {
JsValue::WellKnownFunction(WellKnownFunctionKind::URLConstructor) => {
Expand Down Expand Up @@ -1726,9 +1745,54 @@ async fn handle_call<G: Fn(Vec<Effect>) + Send + Sync>(
// Ignore (e.g. dynamic parameter or string literal), just as Webpack does
return Ok(());
}
JsValue::WellKnownFunction(WellKnownFunctionKind::NodeWorkerConstructor)
if analysis.analyze_mode.is_tracing() =>
{
// Only for tracing, not for bundling (yet?)
let args = linked_args(args).await?;
if !args.is_empty() {
let pat = js_value_to_pattern(&args[0]);
if !pat.has_constant_parts() {
let (args, hints) = explain_args(&args);
handler.span_warn_with_code(
span,
&format!("new Worker({args}) is very dynamic{hints}",),
DiagnosticId::Lint(
errors::failed_to_analyze::ecmascript::NEW_WORKER.to_string(),
),
);
if ignore_dynamic_requests {
return Ok(());
}
}
analysis.add_reference(
FilePathModuleReference::new(
origin.asset_context(),
get_traced_project_dir().await?,
Pattern::new(pat),
collect_affecting_sources,
get_issue_source(),
)
.to_resolved()
.await?,
);
return Ok(());
}
let (args, hints) = explain_args(&args);
handler.span_warn_with_code(
span,
&format!("new Worker({args}) is not statically analyze-able{hints}",),
DiagnosticId::Error(
errors::failed_to_analyze::ecmascript::FS_METHOD.to_string(),
),
);
// Ignore (e.g. dynamic parameter or string literal)
return Ok(());
}
_ => {}
}

// linked_args wasn't called, so manually add the closure effects
for arg in args {
if let EffectArg::Closure(_, block) = arg {
add_effects(block.effects);
Expand All @@ -1737,24 +1801,6 @@ async fn handle_call<G: Fn(Vec<Effect>) + Send + Sync>(
return Ok(());
}

let get_traced_project_dir = async || -> Result<FileSystemPath> {
// readFileSync("./foo") should always be relative to the project root, but this is
// dangerous inside of node_modules as it can cause a lot of false positives in the tracing,
// if some package does `path.join(dynamic)`, it would include everything from the project
// root as well.
//
// Also, when there's no cwd set (i.e. in a tracing-specific module context, as we shouldn't
// assume a `process.cwd()` for all of node_modules), fallback to the source file directory.
// This still allows relative file accesses, just not from the project root.
if allow_project_root_tracing
&& let Some(cwd) = compile_time_info.environment().cwd().owned().await?
{
Ok(cwd)
} else {
Ok(source.ident().path().await?.parent())
}
};

match func {
JsValue::Alternatives {
total_nodes: _,
Expand Down Expand Up @@ -1988,7 +2034,7 @@ async fn handle_call<G: Fn(Vec<Effect>) + Send + Sync>(
get_traced_project_dir().await?,
Pattern::new(pat),
collect_affecting_sources,
make_issue_source(),
get_issue_source(),
)
.to_resolved()
.await?,
Expand Down Expand Up @@ -2041,7 +2087,7 @@ async fn handle_call<G: Fn(Vec<Effect>) + Send + Sync>(
DirAssetReference::new(
get_traced_project_dir().await?,
Pattern::new(pat),
make_issue_source(),
get_issue_source(),
)
.to_resolved()
.await?,
Expand Down Expand Up @@ -2085,7 +2131,7 @@ async fn handle_call<G: Fn(Vec<Effect>) + Send + Sync>(
DirAssetReference::new(
get_traced_project_dir().await?,
Pattern::new(pat),
make_issue_source(),
get_issue_source(),
)
.to_resolved()
.await?,
Expand Down Expand Up @@ -2376,7 +2422,7 @@ async fn handle_call<G: Fn(Vec<Effect>) + Send + Sync>(
DirAssetReference::new(
get_traced_project_dir().await?,
Pattern::new(abs_pattern),
make_issue_source(),
get_issue_source(),
)
.to_resolved()
.await?,
Expand Down Expand Up @@ -2443,7 +2489,7 @@ async fn handle_call<G: Fn(Vec<Effect>) + Send + Sync>(
DirAssetReference::new(
get_traced_project_dir().await?,
Pattern::new(abs_pattern),
make_issue_source(),
get_issue_source(),
)
.to_resolved()
.await?,
Expand Down Expand Up @@ -2512,7 +2558,7 @@ async fn handle_call<G: Fn(Vec<Effect>) + Send + Sync>(
DirAssetReference::new(
context_dir.clone(),
Pattern::new(Pattern::Constant(dir.into())),
make_issue_source(),
get_issue_source(),
)
.to_resolved()
})
Expand Down Expand Up @@ -3147,7 +3193,7 @@ async fn value_visitor_inner(
),
"define" => JsValue::WellKnownFunction(WellKnownFunctionKind::Define),
"URL" => JsValue::WellKnownFunction(WellKnownFunctionKind::URLConstructor),
"process" => JsValue::WellKnownObject(WellKnownObjectKind::NodeProcess),
"process" => JsValue::WellKnownObject(WellKnownObjectKind::NodeProcessModule),
"Object" => JsValue::WellKnownObject(WellKnownObjectKind::GlobalObject),
"Buffer" => JsValue::WellKnownObject(WellKnownObjectKind::NodeBuffer),
_ => return Ok((v, false)),
Expand Down
Loading
Loading