Commit Graph

6 Commits

Author SHA1 Message Date
Public Theta cb96548418 Fix Turbopack worker_threads URL resolution (#93432)
Fixes #93427

## What?

This fixes Turbopack's handling of Node.js `worker_threads` entries
created with a `URL` object:

```ts
new Worker(new URL('./worker.ts', import.meta.url))
```

Turbopack was resolving this form with the same project-root context
used for string/path worker entries. That makes relative URL worker
entries fail when the relative URL should be resolved from the module
that constructs it.

This PR keeps the existing behavior for string/path Node.js workers, but
resolves relative URL worker entries from the module that creates the
URL.

## Why?

The issue reports a regression where this pattern worked in
`next@16.1.7`, but fails in `next@16.2.4` and `next@16.3.0-canary.8`:

```ts
new Worker(new URL('../../worker-entry.mjs', import.meta.url))
new Worker(new URL('../../worker-entry.mts', import.meta.url))
```

The failure happens before the app can build because Turbopack tries to
resolve the relative worker entry from the wrong context:

```text
Module not found: Can't resolve '../../worker-entry.mjs'
Module not found: Can't resolve '../../worker-entry.mts'
```

Node.js documents `Worker`'s `filename` argument as accepting either a
string path or a WHATWG `URL` object. Relative string paths are resolved
relative to the current working directory. By contrast, `new
URL(relative, import.meta.url)` constructs a URL by resolving the
relative specifier against the importing module's URL.

webpack also documents `new Worker(new URL("./worker.js",
import.meta.url))` as the supported Node.js `worker_threads` syntax.
Matching that documented pattern avoids treating URL-object workers as
if they were string-path workers.

## How?

In `turbopack-ecmascript` worker reference analysis:

- Detect relative `JsValue::Url` entries passed to the Node.js `Worker`
constructor.
- Use the importing module's parent directory as the resolution context
for those URL entries.
- Keep the existing traced project directory context for string/path
worker entries and other Node.js worker forms.

This keeps the fix scoped to the URL-object case from the issue while
preserving the existing behavior for string-path workers.

## Tests

Added an e2e regression test to the existing Turbopack-specific
`node-worker-threads` suite:

```text
test/e2e/app-dir/node-worker-threads
```

The new test covers a Route Handler that creates a worker with:

```ts
new Worker(new URL('../../worker-dir/url-worker.ts', import.meta.url))
```

Verified locally:

```text
cargo fmt --check --package turbopack-ecmascript
cargo check --package turbopack-ecmascript
pnpm build-all
pnpm test-dev-turbo test/e2e/app-dir/node-worker-threads/node-worker-threads.test.ts
pnpm test-start-turbo test/e2e/app-dir/node-worker-threads/node-worker-threads.test.ts
```

<!-- NEXT_JS_LLM_PR -->

Co-authored-by: Luke Sandberg <lukesandberg@users.noreply.github.com>
2026-05-12 21:43:06 +00:00
Luke Sandberg 3003e17b10 [turbopack] Respect {eval:true} in worker_threads constructors (#91666)
### What?

Fixed Turbopack incorrectly trying to resolve inline JavaScript code as module references when `new Worker()` is called with `{ eval: true }` option.

Now we skip creating a reference when `eval:true`, and report warnings if we cannot tell what the value is

### Why?

Libraries like jsPDF create Worker threads by passing inline JavaScript code as the first argument along with `{ eval: true }` as the second argument. Turbopack was incorrectly treating this inline code as a file path and attempting to resolve it as a module reference, causing build failures.

### How?

Added logic to detect when the `eval: true` option is passed to the Worker constructor. When this option is present, Turbopack now skips creating a worker reference since the first argument contains executable code rather than a file path. Added comprehensive test coverage using jsPDF to verify the fix works correctly.

Fixes #91642
2026-03-19 13:58:13 -07:00
Matt Mastracci a1c12562f0 Turbopack: Pass globals to node.js workers as well (#89261)
## What

Changes how Turbopack creates Web Workers and Worker Threads to use a unified factory function pattern. Workers now receive the same runtime globals (like `NEXT_DEPLOYMENT_ID` and `NEXT_CLIENT_ASSET_SUFFIX`) as the parent context, and asset loading works correctly inside workers.

## Why

Previously, worker creation was split between compile-time URL generation and runtime initialization, which made it difficult to:
- Forward runtime globals to worker contexts
- Ensure workers could load chunked assets with the correct suffix
- Maintain consistent initialization logic across browser and Node.js workers

This caused issues when workers needed to dynamically import assets or access deployment-specific configuration.

## How

Worker loader modules now export a factory function that receives the Worker constructor and options, rather than just a URL. The runtime handles all worker initialization, including forwarding necessary globals. This keeps all worker creation logic in a single place (the runtime) rather than being split between Rust code generation and JavaScript execution.

Tests added for PNG asset loading in workers to verify the asset suffix forwarding works correctly in both browser and Node.js contexts.
2026-02-06 10:02:54 -07:00
Luke Sandberg b690af0946 Reapply "[turbopack] Add bundling support for worker_threads" (#88725) (#88967)
## What?

This PR reapplies #87746 which adds bundling support for Node.js `worker_threads` in Turbopack.

## Why?

The original PR (#87746) was reverted in #88725 because it broke builds that use packages like `pino` with transports. These packages use dynamic patterns like `join(__dirname, 'lib', 'worker.js')` to resolve worker entry points, which can match non-evaluatable files like `package.json` or `tsconfig.json`.

## How?

This PR reapplies the original changes with the following fixes:

1. **Downgrade errors to warnings in tracing contexts**: When `loose_errors` is enabled (tracing mode) or `in_try` is true, worker entry point validation errors are now emitted as warnings instead of errors. This follows the established Turbopack pattern used in `handle_resolve_error` and other resolve error handling.

2. **Improved error messages**: Error messages for non-chunkable and non-evaluatable worker entry point modules now include:
   - The module identifier (so you can see which file caused the issue)
   - The issue source location (pointing to the `new Worker()` call in source code)

3. **Added regression test**: A new pino-based test case exercises the `thread-stream` worker pattern that caused the original failure. This test runs in `CodeGenerationAndTracing` mode via `test-start-turbo`.

## Changes from original PR

- Added `source` field to `CodeGenerationIssue` to support showing issue source locations
- Added `get_issue_severity()` helper that checks `loose_errors` and `in_try` to determine severity
- Fixed typo: `"SharedbWorker"` → `"SharedWorker"` in `to_string` implementation
- Added pino regression test in `test/e2e/app-dir/node-worker-threads/`

## Testing

- ✅ `pnpm test-dev-turbo test/e2e/app-dir/node-worker-threads/` - all tests pass
- ✅ `pnpm test-start-turbo test/e2e/app-dir/node-worker-threads/` - all tests pass (exercises bundling mode)
- ✅ Verified test fails without the `loose_errors` fix
- ✅ Verified vercel-docs build succeeds with warnings instead of errors
2026-01-26 12:42:15 -08:00
Tobias Koppers 1bbba2a079 Revert "[turbopack] Add bundling support for worker_threads" (#88725)
Reverts vercel/next.js#87746

because of this build error:
```
> Build error occurred
Error: Turbopack build failed with 1 errors:
./node_modules/.pnpm/thread-stream@3.1.0/node_modules/thread-stream/index.js
non-evaluatable module
Worker thread module must be evaluatable
```
2026-01-19 10:48:34 +01:00
Luke Sandberg 0929612595 [turbopack] Add bundling support for worker_threads (#87746)
Add support for bundling worker_threads workers

Previously we only supported tracing dependencies of worker threads.  However, this could trigger issues if the callsite was getting bundled since we would believe that the file was both bundled and unbundled.

The solution is to support bundling modules using worker threads and implementing the threads.  This requires a new reference and loader module type which follows the patter of async-loaders and webworkers. 

An interesting consideration is about file extensions.  `new Worker(...)` takes a relative or absolute filepath, in node 23+ that means you can load typescript files directly, so we support the same.  If you want to load a `.ts` file you need to write `foo.ts` we don't do any pattern rewriting.

This fixes a bug reported by an X user: https://x.com/strugglercss/status/2002504736860484008?s=20.  The problem with the previous approach is that we would record the reference as 'traced', but if you did `new Worker(__filename,...)` then we would end up with 'traced references' to a file that was bundled.  This caused issues during tracing when we tried to add CachedExternalModule references to the nft json files

```
Error [TurbopackInternalError]: NftJsonAsset: cannot handle filepath url

Debug info:
- Execution of get_all_written_entrypoints_with_issues_operation failed
- Execution of EntrypointsOperation::new failed
- Execution of all_entrypoints_write_to_disk_operation failed
- Execution of Project::emit_all_output_assets failed
- Execution of emit_assets failed
- Execution of emit failed
- Execution of <NftJsonAsset as Asset>::content failed
- NftJsonAsset: cannot handle filepath url
    at <unknown> (TurbopackInternalError: NftJsonAsset: cannot handle filepath url) {
```

there `url` was due to a `require('url')` statement in a bundled file this caused us to produce an external shim, but a `new Worker(__filename)` caused us to also create a traced reference to the same file.  The problem there was simply that the `ident()` for a `CachedExternalModule` contains a dummy filepath that broke the nft.json asset production.   The root issue here is that the `FilePathModuleReference` was using the wrong `AssetContext` to construct the referenced module which lead to the wrong files being traced.   After investigation @mischnic and I determined that that was an insufficient fix since we really do need to rewrite the reference.   Proper bundling support fixes this directly and the pattern here paves the way for more worker support in the future.

This doesn't seem like the only way a synthetic module (like an extern module) might end up as a dependency of traced module, so a more robust solution is probably in order.
2026-01-16 15:24:11 -08:00