Commit Graph

1409 Commits

Author SHA1 Message Date
Niklas Mischkulnig 75df0bb469 Turbopack: rename ServerPaths to AssetPaths (#90234)
We are soon going to use these for client-side static assets as well
2026-02-20 20:31:58 +01:00
Sebastian "Sebbie" Silbermann 8f231d6380 [instant] Include declaration location of instant config in validation errors (#90169) 2026-02-20 11:31:53 -08:00
Niklas Mischkulnig a6d950a445 Turbopack: fix static asset skew protection for edge and prerenders (#90238)
- Edge Runtime was missing `globalThis.NEXT_CLIENT_ASSET_SUFFIX` at runtime
- Prerenders were always running `globalThis.NEXT_CLIENT_ASSET_SUFFIX` set

Fixups after #88828
2026-02-20 18:31:02 +01:00
Benjamin Woodruff f10b63d17e Turbopack: Derive Default on PartialProjectOptions, remove silly partial_project_options_with_debug_build_paths helper (#90170)
TSIA
2026-02-18 17:04:11 -08:00
Tobias Koppers c979cefa4a Turbopack: Enable tree-shaking for dynamic imports with destructuring (#89683)
## What?

This PR enables tree-shaking for dynamic imports when the imported module's exports are destructured or accessed via member expressions. Previously, dynamic imports were treated as importing all exports, preventing unused exports from being removed.

## Why?

Dynamic imports with destructuring patterns like `const { cat } = await import('./lib')` or member access like `(await import('./lib')).cat` now properly communicate which specific exports are actually used. This allows bundlers (particularly Turbopack) to tree-shake unused exports from dynamically imported modules, reducing bundle size.

## How?

### Core Changes:

1. **AST Analysis Enhancement** (`turbopack-ecmascript/src/analyzer/graph.rs`):
   - Added new `Effect::DynamicImport` variant that captures destructuring patterns and member access
   - Implemented `extract_dynamic_import_export_names()` to statically analyze destructuring patterns and extract used export names
   - Supports: const/let/var destructuring, renamed imports, nested destructuring, default exports, member access, and empty destructuring

2. **Export Usage Tracking** (`turbopack-core/src/resolve/mod.rs`):
   - Added `ExportUsage::NamedSet` variant to track multiple named exports being used
   - Updated `ModuleExportUsageInfo` to handle merging of multiple named exports

3. **Dynamic Import Reference** (`turbopack-ecmascript/src/references/esm/dynamic.rs`):
   - Extended `EsmAsyncAssetReference` with `export_names` field
   - Implemented `binding_usage()` to communicate which exports are used to the module graph

4. **Effect Processing** (`turbopack-ecmascript/src/references/mod.rs`):
   - Refactored dynamic import handling into dedicated `handle_dynamic_import()` function
   - Passes export usage information through the reference system

### Test Coverage:

- **E2E Tests** (`test/e2e/app-dir/dynamic-import-tree-shaking/`): Comprehensive tests for Next.js App Router covering various destructuring patterns
- **Snapshot Tests** (`turbopack-tests/tests/snapshot/basic-tree-shake/`): Turbopack-specific tests validating tree-shaking behavior

### Supported Patterns:

- ✅ Named destructuring: `const { cat } = await import('./lib')`
- ✅ Variable declarations: `var`, `let`, `const`
- ✅ Renamed imports: `const { cat: myCat } = await import('./lib')`
- ✅ Nested destructuring: `const { dogRef: { get } } = await import('./lib')`
- ✅ Default exports: `const { default: val } = await import('./lib')`
- ✅ Empty destructuring: `const {} = await import('./lib')` (side effects only)
- ✅ Member access: `(await import('./lib')).cat`

### Limitations:

- Rest patterns (`const { cat, ...rest }`) conservatively import all exports
- Computed property keys are not statically analyzed
- Member access tree-shaking is Turbopack-only (webpack limitation)

https://claude.ai/code/session_01QWi3udq2LX4GFqJEDaqFFU
2026-02-18 18:55:19 +01:00
Niklas Mischkulnig 91bdad8f39 Turbopack: use file_content.hash() consistently (#90078)
So that we don't hash asset contents multiple times.

`hash_xxh3_hash64(file.content())`  isn't a turbotask, but `file.hash()` is cached
2026-02-18 15:07:53 +01:00
Niklas Mischkulnig 2a9e7560a5 Turbopack: handle invalid RSC imports via importmap (#88146)
We have two lines of defense:
1. crates/next-custom-transforms/src/transforms/react_server_components.rs validates ESM imports of server-only and client-only and throws an issue if something is wrong. Notably, `require('server-only')` isn't caught by this
2. additionally, we had an `BeforeResolvePlugin` for server-only, client-only and styled-jsx. 

We should probably get rid of the first one completely for consistency (it's brittle)
https://github.com/vercel/next.js/blob/79040a318d29641eb3d96a5a47c92a5f8506e826/crates/next-custom-transforms/src/transforms/react_server_components.rs#L663-L674

This PR is about improving the second one:

The error message isn't ideal yet, but better than before (note: no import trace):

```
./bench/basic-app/app
Invalid import
'server-only' cannot be imported from a Client Component module. It should only be used from a Server Component.
The error was caused by importing 'bench/basic-app/app'
```

now

<img width="708" height="386" alt="Bildschirmfoto 2026-01-07 um 17 21 59" src="https://github.com/user-attachments/assets/4d49eff3-4959-4b70-aa47-6f3c10c75588" />
2026-02-18 14:06:18 +01:00
Luke Sandberg 91f2f354b2 refactor: fix non-determinism in resolve package (#90058)
Defer cell creation so it doesn't happen inside of async loops

There are a number of async functions in the resolve package that either directly construct ResolveResult or defer to a turbo task function, this leads to non-determinism when callers invoke these in async loops.  The fix is just to defer cell creation out of these async helper functions.  This was discovered by enabling the `verify_determinism` feature in #90013
2026-02-17 17:33:25 -08:00
JJ Kasper 6144980ce3 Expand deferred entries test suite and fix turbopack build (#90057)
## Summary
Reworks Turbopack deferred entries in production build so deferred
routes are processed last in the same project lifecycle, with
`onBeforeDeferredEntries` executed between the non-deferred and deferred
phases.

## What changed
- Moved deferred build phasing into Rust in
`project_write_all_entrypoints_to_disk`:
  - non-deferred phase
  - `onBeforeDeferredEntries`
  - deferred phase
- Kept callback invocation on the Rust side via the existing node-worker
callback plumbing.
- Narrowed invalidation after `onBeforeDeferredEntries` to deferred app
source subtrees instead of invalidating the whole project filesystem
cache.
- Added `DiskFileSystem::invalidate_path_and_children_with_reason(...)`
in `turbo-tasks-fs`.
- Derived deferred invalidation dirs from deferred routes’
`original_name` values.
- Retained a full-invalidation fallback only when app-dir path
resolution is unavailable.
- Deferred route selection still includes both app pages and app route
handlers.

## Validation
- `cargo check -p next-napi-bindings -p turbo-tasks-fs`
- `pnpm test-start-turbo
test/e2e/deferred-entries/deferred-entries.test.ts` (21/21 passing)
- Validated against [workflows
repo](https://github.com/vercel/workflow/pull/1058) and v0
2026-02-16 15:54:14 -08:00
Jiwon Choi 80e849e152 fix(turbopack): --debug-build-paths fails with route groups (#89336)
Confirmed the fix locally on the original app I faced the issue with.

### Why?

When using `--debug-build-paths`, a pattern with a route group on
Turbopack, it fails with an error:

```
Error [PageNotFoundError]: Cannot find module for page: /nested
    at ignore-listed frames {
  code: 'ENOENT'
}
```

Current Behavior:
https://github.com/vercel/next.js/actions/runs/21544427008/job/62083680496?pr=89336#step:35:459

The bug lives in `crates/next-api/src/project.rs`, specifically in
`from_debug_build_paths()`. This function is responsible for deriving
route paths from debug build inputs, but it currently preserves route
groups when it shouldn’t.

With the current behavior, an input like `app/(group)/nested/page.tsx`
produces the output `/(group)/nested`. In other words, the route group
segment is kept in the generated path.

However, Turbopack route keys explicitly strip route groups. In
`next-core/src/next_app/mod.rs`, the conversion from `AppPage` to
`AppPath` removes route group segments. For the same input, Turbopack
expects the route key to be `/nested`, not `/(group)/nested`.

This mismatch causes a downstream failure. `from_debug_build_paths()`
produces `/(group)/nested`, while the Turbopack route key is `/nested`.
Since `should_include_app_route()` relies on an exact string match, the
comparison fails. As a result, the route is excluded, the module is
never compiled, and the error ultimately surfaces as a
`PageNotFoundError`.

### How?

Strip route group `(xxx)` and parallel route `@xxx` segments in
`from_debug_build_paths()` to match how Turbopack normalizes route keys.

---------

Co-authored-by: Niklas Mischkulnig <4586894+mischnic@users.noreply.github.com>
2026-02-16 10:23:00 +01:00
Tobias Koppers 740d55cdce Turbopack: Add inline loader configuration via import attributes (#89644)
## What?

Adds support for inline loader configuration in Turbopack via import attributes. Developers can apply webpack-compatible loaders to individual imports using the `with` clause, without needing global `turbopack.rules` configuration.

```tsx
import rawText from '../data.txt' with { turbopackLoader: 'raw-loader', turbopackAs: '*.js' }
import value from '../data.js' with {
  turbopackLoader: 'string-replace-loader',
  turbopackLoaderOptions: '{"search":"PLACEHOLDER","replace":"replaced value"}'
}
```

## Why?

Global `turbopack.rules` applies loaders to all files matching a pattern. This PR provides per-import granularity — useful when only a specific import needs special treatment, avoiding side effects on other imports of the same file type.

## How?

### Import attributes parsing (`turbopack-ecmascript/src/analyzer/imports.rs`)
- Extended `ImportAnnotations` to parse four new attributes: `turbopackLoader`, `turbopackLoaderOptions`, `turbopackAs`, `turbopackModuleType`
- All values are strings per TC39 import attributes spec (`turbopackLoaderOptions` is a JSON-encoded string)
- Added unit tests for the parser

### New structured loader type (`turbopack-core/src/loader.rs`)
- Added `WebpackLoaderItem` struct shared between inline and global loader paths

### Reference type plumbing (`turbopack-core/src/reference_type.rs`, `turbopack-ecmascript/src/references/esm/base.rs`)
- Added `ImportWithTurbopackUse` variant to `EcmaScriptModulesReferenceSubType` carrying the parsed loader, rename_as, and module_type
- ESM reference resolution maps the parsed annotations to this new subtype

### Loader execution (`turbopack/src/lib.rs`)
- In `process_default_internal`, detects `ImportWithTurbopackUse` references and applies the loader as a source transform via the existing webpack loader infrastructure
- Requires `enable_webpack_loaders` to be configured (same as global rules)
- Supports `turbopackAs` (re-processes with new extension) and `turbopackModuleType` (directly sets module type)
- Avoids infinite recursion by switching to plain `Import` reference type on re-processing

### Documentation (`docs/.../turbopack.mdx`)
- Added section documenting the four import attributes with examples
- Added version history entry for v16.2.0

### Testing (`test/development/app-dir/turbopack-import-assertions-use/`)
- E2e test covering raw loader, replace loader with options, `turbopackModuleType: 'ecmascript'`, and `turbopackModuleType: 'json'`
- Turbopack-only (skipped for webpack)
2026-02-13 19:45:10 +01:00
Tobias Koppers b05a35a79f Turbopack: Move turbopackIgnoreIssue from experimental to turbopack.ignoreIssue (#89817)
## What?

Moves the `turbopackIgnoreIssue` config from `experimental` to the stable `turbopack` config as `turbopack.ignoreIssue`.

## Why?

Reviewers on #89682 agreed the API is stable enough to graduate from experimental. Also addresses a docs wording suggestion.

## How?

- **TypeScript types**: Moved `ignoreIssue` field from `ExperimentalConfig` to `TurbopackOptions` in `config-shared.ts`
- **Zod schema**: Moved validation from `experimentalSchema` to `zTurbopackConfig` in `config-schema.ts`
- **Serialization**: Moved RegExp serialization logic into the turbopack block in `build/swc/index.ts`
- **Rust**: Moved `ignore_issue` field from `ExperimentalConfig` to `TurbopackConfig` in `next_config.rs`, updated the `turbopack_ignore_issue_rules()` method to read from `self.turbopack`
- **Tests**: Updated config in test to use `turbopack.ignoreIssue` instead of `experimental.turbopackIgnoreIssue`
- **Docs**: Removed `version: experimental`, updated all code examples, moved entry from experimental table to stable config list in turbopack.mdx, fixed "Good to know" wording to say "prefer using more specific `path` patterns" (since `path` is already required)
2026-02-13 14:56:59 +01:00
Luke Sandberg fe39a3c440 fix: support multiple icon formats with same base name (icon.png + icon.svg) (#89504)
## What?

Fixes a crash in Turbopack and incorrect behavior in Webpack when users have multiple icon files with the same base name but different extensions (e.g., `icon.png` and `icon.svg`) in their app directory.

## Why?

This is a valid use case for browser fallback support - modern browsers can use SVG icons while older browsers (Safari <26) need to fall back to PNG. Previously:

- **Turbopack**: Crashed during `next build` with "Dependency tracking is disabled so invalidation is not allowed"
- **Webpack**: Silently ignored all but one format

## How?

**Turbopack**: Changed virtual source filename from `{stem}--route-entry.js` to `{filename}--route-entry.js` (e.g., `icon.png--route-entry.js` and `icon.svg--route-entry.js`) to avoid file conflicts that triggered invalidation.

**Webpack**: Changed `MetadataResolver` to return all matching files instead of just the first one.

Both icon formats are now properly rendered:
```html
<link rel="icon" type="image/png" sizes="114x114" href="/icon.png">
<link rel="icon" type="image/svg+xml" sizes="any" href="/icon.svg">
```

Fixes #85496
Fixes NEXT-4816
2026-02-13 04:55:27 -08:00
Niklas Mischkulnig 1fac9a1b7e Upgrade to swc 56 (#89111) 2026-02-13 11:47:27 +01:00
熊谷 凌 55046e234f Next-api: Check client_source_maps before generate source map (#89915) 2026-02-13 10:12:34 +01:00
Matt Mastracci 5070ad0df4 [turbopack] Add #[derive(ValueToString)] and convert ~45 manual impls (#89788)
## What

Add a `#[derive(ValueToString)]` proc macro and convert ~45 manual `ValueToString` implementations across turbopack crates to use it (-660 lines of boilerplate, 49 files touched).

## Why

Nearly every `ValueToString` impl follows the same pattern: format some fields into a string, possibly awaiting `Vc` values first. These hand-written impls are noisy boilerplate that obscure the actual format string.

## How

The derive macro generates the `#[turbo_tasks::value_impl] impl ValueToString` block automatically. A helper trait `ValueToStringify` with a blanket impl for `Display` and specializations for `Vc<T>`/`ResolvedVc<T>` handles async resolution of fields.

### Supported forms

- **No attribute** — delegates to `Display::to_string(&self)`
- `#[value_to_string("constant")]` — emits `rcstr!` directly
- `#[value_to_string("{field} text {other_field}")]` — auto-resolves named/positional fields via `ValueToStringify`
- `#[value_to_string("fmt {}", expr1, expr2)]` — explicit expressions as format args
- `#[value_to_string(expr)]` — single expression delegation

Enums support per-variant attributes (defaulting to variant name) or a single top-level attribute.
2026-02-12 19:12:44 -07:00
Luke Sandberg 1486592094 Change UrlBehavior.static_suffix to ResolvedVc<Option<RcStr>> (#89921)
## Summary

Changes `UrlBehavior.static_suffix` from `Option<RcStr>` to `ResolvedVc<Option<RcStr>>` so that `css_url_suffix` stays as a Vc longer instead of being eagerly resolved at the call site. This improves caching behavior by keeping the value cell-based through the chunking context construction.

- Updated `UrlBehavior` struct definition in `turbopack-core`
- Updated default fallbacks in browser/nodejs chunking contexts
- Updated CSS url reference consumer to `.await?` the `ResolvedVc`
- Replaced `.owned().await?` with `.to_resolved().await?` in next-core callers
2026-02-12 09:52:36 -08:00
Matt Mastracci ff636469af [turbopack] Simplify JS ChunkItem with a single impl in most cases (#89548)
# What

Removes the vast majority of `ChunkItem` implementations in favour of
one `EcmascriptModuleChunkItem`.

# Why

Almost all of the `ChunkItem` implementations are trivial and were, for
the most part, just places where additional traits could be implemented.

By removing all of the various, trivial implementations, this might open
up opportunities to better implement other features across the entire
codebase.

# How

Most chunk items are migrated over to EcmascriptModuleChunkItem. The
EcmascriptChunkPlaceable trait gains three new methods that modules can
optionally override:

  -  `chunk_item_content()` - generates the chunk item's JavaScript code
- `chunk_item_content_ident()` - returns the content identity for cache
invalidation
- `chunk_item_output_assets()` - returns output assets the chunk item
depends on

The generic EcmascriptModuleChunkItem delegates to these trait methods,
eliminating the need for per-module wrapper structs.
2026-02-12 09:56:26 -07:00
Tobias Koppers 9b0277f02c Turbopack: Pass asset_suffix_path as Vc (#89899)
## Summary
- Pass `asset_suffix_path` as `Vc<Option<RcStr>>` instead of eagerly resolving it to `Option<RcStr>` in the chunking context option structs
- Add filesystem cache size growth assertions to e2e tests to detect unbounded cache growth regressions

## Why

Previously, `css_url_suffix` was eagerly awaited in `project.rs` before being passed into `ClientChunkingContextOptions`, `ServerChunkingContextOptions`, and `EdgeChunkingContextOptions`. This caused a new chunking context `Vc` to be created for every build, duplicating the entire build in cache and recompiling it.

By keeping it as a `Vc`, the chunking context identity is stable across builds, preventing unnecessary cache duplication.

## How

- Changed `css_url_suffix` field from `Option<RcStr>` to `Vc<Option<RcStr>>` in all three chunking context option structs
- Removed `.owned().await?.clone()` in `project.rs` (3 call sites), passing the `Vc` directly
- Added `.owned().await?` at the point of use in the 5 context builder functions
- Added cache size measurements to `filesystem-cache.test.ts`: normal changes limited to 10% growth, renames allow up to 50% due to dead cache entries
2026-02-12 17:45:50 +01:00
Sebastian "Sebbie" Silbermann 3dafc76fc1 [fragment-scroll] Add experimental.appNewScrollHandler (#83107)
Just plumbing and enabling that flag in the experimental shards. The flag will enable our Layout router to use Fragment refs for scroll restoration. Implementation will be done in a follow-up.
2026-02-12 14:54:38 +01:00
Tobias Koppers d41c50b828 Turbopack: Store task error as pointer to the source error (#89293)
Store task error as pointer to the source error

<!-- Thanks for opening a PR! Your contribution is much appreciated.
To make sure your PR is handled as smoothly as possible we request that you follow the checklist sections below.
Choose the right checklist for the change(s) that you're making:

## For Contributors

### Improving Documentation

- Run `pnpm prettier-fix` to fix formatting issues before opening the PR.
- Read the Docs Contribution Guide to ensure your contribution follows the docs guidelines: https://nextjs.org/docs/community/contribution-guide

### Fixing a bug

- Related issues linked using `fixes #number`
- Tests added. See: https://github.com/vercel/next.js/blob/canary/contributing/core/testing.md#writing-tests-for-nextjs
- Errors have a helpful link attached, see https://github.com/vercel/next.js/blob/canary/contributing.md

### Adding a feature

- Implements an existing feature request or RFC. Make sure the feature request has been accepted for implementation before opening a PR. (A discussion must be opened, see https://github.com/vercel/next.js/discussions/new?category=ideas)
- Related issues/discussions are linked using `fixes #number`
- e2e tests added (https://github.com/vercel/next.js/blob/canary/contributing/core/testing.md#writing-tests-for-nextjs)
- Documentation added
- Telemetry added. In case of a feature if it's used or not.
- Errors have a helpful link attached, see https://github.com/vercel/next.js/blob/canary/contributing.md


## For Maintainers

- Minimal description (aim for explaining to someone not on the team to understand the PR)
- When linking to a Slack thread, you might want to share details of the conclusion
- Link both the Linear (Fixes NEXT-xxx) and the GitHub issues
- Add review comments if necessary to explain to the reviewer the logic behind a change

### What?

### Why?

### How?

Closes NEXT-
Fixes #

-->
2026-02-12 06:37:38 +01:00
Andrew Imm b6cf46a851 Allow sitemap.ts and sitemap/page.tsx to coexist in Turbopack (#89789)
Solves #78609

Today, Turbopack maps `app/sitemap.ts` to an AppPage of `/sitemap/route`, and `app/sitemap/page.tsx` maps to `/sitemap/page`, which leads to a conflict.

This treats sitemap.xml the same way as robots.txt and site.webmanifest, and puts the xml extension in the AppPage, and not later in the path resolution. This creates an AppPage of `/sitemap.xml/route` which no longer conflicts. This is pretty much what webpack was doing.

Because the page segment is now sitemap.xml, I had to update downstream logic for routes that export sitemap / generateSitemap.

The turbopack-utils is needed for dynamic sitemap routes like the example here: https://nextjs.org/docs/app/api-reference/file-conventions/metadata/sitemap#generating-multiple-sitemaps

In that setup, when a request for /product/sitemap/1.xml comes in, the "multiple" matcher matches and definition.page is "/product/sitemap/[__metadata_id__]/route". This becomes the page in the hot reloader. After that, normalizedPageToTurbopackStructureRoute strips [__metadata_id__] and it becomes /products/sitemap, but our updated Rust key is now /products/sitemap.xml/route... so add back the .xml!

My demo app tests four things in parallel:
1) app/sitemap.ts renders at /sitemap.xml
2) app/sitemap/page.tsx renders at /sitemap and the two do not conflict 3) app/product/sitemap.ts works when generating a static sitemap (/product/sitemap.xml) 4) app/product/sitemap.ts works when generating a dynamic sitemapo (/product/sitemap/1.xml) as in the linked docs above

Also I asked Claude if I've fixed all the relevant codepaths, and here's its output:

```
  Case 1: Single dynamic sitemap — app/products/sitemap.ts (no generateSitemaps)
  - Input page: /products/sitemap.xml/route, ext: .ts
  - Strip /route → /products/sitemap.xml
  - No [__metadata_id__] → skip
  - Doesn't end with /sitemap (ends with /sitemap.xml) → skip
  - Add /route → /products/sitemap.xml/route
  - Entry key: /products/sitemap.xml/route ✓

  Case 2: Multi-dynamic sitemap — app/products/sitemap.ts with generateSitemaps
  - Input page: /products/sitemap/[__metadata_id__]/route, ext: .ts
  - Strip /route → /products/sitemap/[__metadata_id__]
  - Strip [__metadata_id__] → /products/sitemap
  - Ends with /sitemap and ext .ts ≠ .xml → add .xml → /products/sitemap.xml
  - Add /route → /products/sitemap.xml/route
  - Entry key: /products/sitemap.xml/route ✓

  Case 3: Static sitemap — app/sitemap.xml
  - Input page: /sitemap.xml/route, ext: .xml
  - Strip /route → /sitemap.xml
  - No [__metadata_id__] → skip
  - ext IS .xml → skip .xml addition
  - Add /route → /sitemap.xml/route
  - Entry key: /sitemap.xml/route ✓

  Case 4: Non-sitemap metadata — app/opengraph-image.tsx
  - Input page: /opengraph-image/route, ext: .tsx
  - Strip /route → /opengraph-image
  - No [__metadata_id__] → skip
  - Doesn't end with /sitemap → skip
  - Add /route → /opengraph-image/route ✓

  Case 5: Non-sitemap multi-dynamic — app/opengraph-image.tsx with generateImageMetadata
  - Input page: /opengraph-image/[__metadata_id__]/route, ext: .tsx
  - Strip /route → /opengraph-image/[__metadata_id__]
  - Strip [__metadata_id__] → /opengraph-image
  - Doesn't end with /sitemap → skip
  - Add /route → /opengraph-image/route ✓

  All cases produce the correct entry key.
```

Seems legit. Would still appreciate someone with more Next.js knowledge validating my assumptions
2026-02-11 16:30:29 -08:00
Tobias Koppers 24c6e3e4de Add CSS URL deployment ID suffix support (#89771)
## Summary

Adds deployment ID suffix (`?dpl=<deployment_id>`) to asset URLs referenced in CSS `url()` declarations (images, fonts) for both Turbopack and Webpack builds. This enables proper cache busting for CSS-referenced assets when using `deploymentId` in `next.config.js`.

### Turbopack
- Added `static_suffix` field to the existing `UrlBehavior` struct, providing a build-time constant suffix for contexts that cannot use dynamic JS expressions (e.g., CSS `url()` references)
- CSS URL resolution now calls `url_behavior(None)` and uses `static_suffix` instead of a separate method
- Wired the suffix from `next.config.js` `deploymentId` through `asset_suffix_path()` into all three chunking contexts (client, server, edge) via `default_url_behavior` and `url_behavior_override`

### Webpack
- Passed `deploymentId` through the CSS loader config pipeline (`webpack-config.ts` → `config/index.ts` → `css/loaders/` → `postcss-url-parser.ts`)
- Appended `?dpl=<id>` to resolved asset URLs in the PostCSS URL parser plugin, placed before any hash fragment so it remains a server-visible query parameter

### Test
- Added production test (`test/production/css-url-deployment-id/`) covering global CSS, CSS modules, and SCSS modules with image and font `url()` references
- Verifies all asset URLs contain the `dpl` query parameter in both Turbopack and Webpack modes
2026-02-11 15:35:12 +01:00
Tobias Koppers ae64f6cff0 Turbopack: make routes hashes mainfest more incremental (#87107)
<!-- Thanks for opening a PR! Your contribution is much appreciated.
To make sure your PR is handled as smoothly as possible we request that you follow the checklist sections below.
Choose the right checklist for the change(s) that you're making:

## For Contributors

### Improving Documentation

- Run `pnpm prettier-fix` to fix formatting issues before opening the PR.
- Read the Docs Contribution Guide to ensure your contribution follows the docs guidelines: https://nextjs.org/docs/community/contribution-guide

### Fixing a bug

- Related issues linked using `fixes #number`
- Tests added. See: https://github.com/vercel/next.js/blob/canary/contributing/core/testing.md#writing-tests-for-nextjs
- Errors have a helpful link attached, see https://github.com/vercel/next.js/blob/canary/contributing.md

### Adding a feature

- Implements an existing feature request or RFC. Make sure the feature request has been accepted for implementation before opening a PR. (A discussion must be opened, see https://github.com/vercel/next.js/discussions/new?category=ideas)
- Related issues/discussions are linked using `fixes #number`
- e2e tests added (https://github.com/vercel/next.js/blob/canary/contributing/core/testing.md#writing-tests-for-nextjs)
- Documentation added
- Telemetry added. In case of a feature if it's used or not.
- Errors have a helpful link attached, see https://github.com/vercel/next.js/blob/canary/contributing.md


## For Maintainers

- Minimal description (aim for explaining to someone not on the team to understand the PR)
- When linking to a Slack thread, you might want to share details of the conclusion
- Link both the Linear (Fixes NEXT-xxx) and the GitHub issues
- Add review comments if necessary to explain to the reviewer the logic behind a change

### What?

### Why?

### How?

Closes NEXT-
Fixes #

-->
2026-02-11 11:58:11 +01:00
Niklas Mischkulnig c28948e0b3 Turbopack: remove ChunkableModuleReference trait (#89745) 2026-02-11 09:46:23 +01:00
Luke Sandberg b067991e59 Add support for with type: "text" under a new experimental flag, following what webpack did (#89560)
## Summary

Adds support for the TC39 `import ... with { type: "text" }` proposal to Turbopack, allowing files to be imported as strings.

This is gated behind a new experimental flag `turbopackImportTypeText`.

```js
// next.config.js
export default {
  experimental: {
    turbopackImportTypeText: true,
  },
}
```

```js
import text from './file.txt' with { type: 'text' }
// text is a string containing the file contents
```

### Related TC39 Proposals

- **[`type: "text"`](https://github.com/tc39/proposal-import-text)** - Stage 2 - Import file contents as a string
- **[`type: "bytes"`](https://github.com/nicolo-ribaudo/proposal-import-bytes)** - Stage 2.7 - Import file contents as a Uint8Array (already supported via `turbopackImportTypeBytes`)

### Implementation Details

- Created `TextSourceTransform` which transforms any file into an ES module exporting the file contents as a string
- Added `ResourceHasModifier` rule condition to match on ident modifiers, enabling proper module type resolution after source transforms
- Refactored `BytesSourceTransform` to use the same pattern for consistency
- Both transforms add a modifier to the ident (`text_module` / `bytes_module`) for uniqueness, allowing the same file to be imported both normally and with a type attribute

Using a source transform is simpler and allows the modules to participate in other bundler optimizations more easily (scope hoisting in particular)

This also fixes a few bugs where `with` imports would conflict with other module type rules:
  * if you attempted to import a `.js` file with `type:'bytes'` didn't work since the file extension matching would trigger first.
  * if you set a module type rule in your next config it would override the `with` attribute


## Test Plan

- Expanded e2e tests at `test/e2e/turbopack-import-with-type/`
2026-02-10 23:33:54 -08:00
Tobias Koppers adcac5dff1 Add turbopackIgnoreIssue config to suppress Turbopack warnings (#89682)
## What?

Adds the `experimental.turbopackIgnoreIssue` configuration option, which allows developers to suppress specific Turbopack warnings and errors based on file path, issue title, and/or description patterns. Filtered issues are hidden from both CLI output and the error overlay.

## Why?

Developers need a way to suppress noisy or expected warnings from Turbopack without disabling all warnings. This is useful for:
- Suppressing warnings from third-party code, generated files, or optional dependencies
- Reducing noise in development server output
- Hiding expected issues from the error overlay

## How?

### Configuration → Filtering Pipeline

1. **Config types** (`packages/next/src/server/config-shared.ts`, `config-schema.ts`):
   Each rule has a required `path` (glob string or RegExp) and optional `title`/`description` (exact string or RegExp). All specified fields must match (AND logic).

2. **RegExp serialization** (`packages/next/src/build/swc/index.ts`):
   Converts RegExp objects to `{ source, flags }` and glob strings to `{ type: 'glob', value }` for transfer to Rust.

3. **Rust deserialization** (`crates/next-core/src/next_config.rs`):
   `TurbopackIgnoreIssueRule`, `TurbopackIgnoreIssuePathPattern`, and `TurbopackIgnoreIssueTextPattern` types deserialize the config. A `turbopack_ignore_issue_rules()` turbo-tasks function converts them to `IgnoreIssue` rules with proper cache invalidation.

4. **Issue filtering** (`turbopack/crates/turbopack-core/src/issue/mod.rs`):
   `IssueFilter` is a turbo-tasks value that holds both severity filters and ignore rules. `IgnoreIssuePattern` supports exact string, glob, and regex matching (using `turbo-esregex` for ES-style regex). Matching issues are excluded before severity filtering.

5. **Integration** (`crates/next-api/src/project.rs`, `route.rs`, `empty.rs`):
   `Endpoint::project()` trait method provides access to the project config. `issue_filter()` builds the `IssueFilter` from project config. All issue collection points use the project's dynamic filter instead of the previous hardcoded `NEXT_ISSUE_FILTER`.

### Documentation

- New docs page: `docs/01-app/03-api-reference/05-config/01-next-config-js/turbopackIgnoreIssue.mdx`
- Updated Turbopack reference page with experimental options table: `docs/01-app/03-api-reference/08-turbopack.mdx`

### Testing

E2E test suite (`test/development/app-dir/turbopack-ignore-issue/`):
- **With config**: verifies matching warnings are suppressed from CLI output, matching errors are suppressed from the error overlay, and unrelated pages still compile normally
- **Without config**: verifies warnings and errors appear when no rules are defined

### Dependencies

- Added `turbo-esregex` for ES-style regex support in Rust

## Example

```js
// next.config.js
module.exports = {
  experimental: {
    turbopackIgnoreIssue: [
      { path: '**/vendor/**' },
      { path: 'app/**', title: 'Module not found' },
      { path: /generated\/.*\.ts/, description: /expected error/i },
    ],
  },
}
```
2026-02-11 08:26:58 +01:00
Benjamin Woodruff 50d61f93d8 Turbopack: Fix slow filesystem benchmark warning for next dev (#89798)
Apparently we broke this about 6 months ago and didn't notice:

- We briefly had both a `println` (legacy) and a compilation event, leading to duplicate logging.
- First: https://github.com/vercel/next.js/pull/80631 - I added a filter to `backgroundLogCompilationEvents` that inadvertently filtered out `SlowFilesystemEvent` on dev.
- Around the same time: https://github.com/vercel/next.js/pull/81972 - This removed the old `println` in favor of the compilation event

Changes in this PR:

- Add `SlowFilesystemEvent` to the filter used in dev.
- Increase the threshold from 100ms to 200ms. I'm concerned that with Turbopack's File System cache, that the FS might be more heavily loaded during this benchmark than it was before, and I'd rather err on the "less aggressive" side.
- Add a link to https://nextjs.org/docs/app/guides/local-development, which now has documentation on the antivirus thing.

Tested with a threshold of 0ms:

![Screenshot 2026-02-10 at 5.09.41 PM.png](https://app.graphite.com/user-attachments/assets/e871ad6d-c718-4308-9a14-ba70bda23efb.png)

There's not any easy way to test this, but it's also clearly not a big deal if it does break, as it's just a debugging hint for performance issues.
2026-02-10 21:02:44 -08:00
Will Binns-Smith aac4ebb7ac Turbopack: Server HMR infrastructure (#88870)
This adds some basic JavaScript/TypeScript infrastructure for Next to receive and handle server-side HMR updates from Turbopack.

This:
- Renames some existing hmr code as explicitly client hmr
- Adds counterpart apis for server hmr (e.g. subscribe to server HMR events via `project.serverHmrEvents()`)
- Add `__turbopack_server_hmr_apply__` runtime function (this is a stub for now, just logs on updates)

**Alternatives considered**
A single firehose for hmr events, pushing the filtering to the JS side. I figured separate dedicated apis would be cleaner since they’d have to be filtered and switched on anyway.

**In future PRs**
- Rust: Make Turbopack send 'partial' updates for server file changes
- Node dev runtime: Implement module factory replacement in `__turbopack_server_hmr_apply__`
- add client notification to trigger re-fetch of rsc
- e2e tests
2026-02-10 12:20:52 -08:00
Benjamin Woodruff 3f80419318 Turbopack: Remove old Vc::try_resolve_* methods in favor of the ResolvedVc alternatives (#89696)
These `try_resolve_*` methods predate the introduction of the `ResolvedVc` type.

`ResolvedVc` has efficient synchronous `try_downcast`/`try_sidecast` functions, and there are only a few callsites that need to do this, so it makes more sense to split the resolution and the casting into to separate calls.
2026-02-09 00:04:13 -08: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
Hendrik Liebau 869b45ef0d Resolve local variable references in error code SWC plugin (#89596)
The error code plugin now resolves local variable references in error
constructors to their string literal initializers. Previously, `const
msg = 'Error text'; throw new Error(msg)` would produce `"%s"` as the
error message, preventing it from being tracked in `errors.json`. A
pre-pass `BindingCollector` now collects variable declarations before
the transformation pass, enabling error code assignment for these
patterns. This adds 50 new error codes to `errors.json`.

Variable references that still can't be resolved include imported
constants (cross-module), function return values, object property
access, and function parameters. These continue to produce `"%s"` as
before.

Also fixes `rcstr!()` to `.into()`. The `rcstr!` macro was introduced by
a bulk Turbopack refactor (#80552), but was never available as a
dependency of this standalone crate. `turbo-rcstr` can't be added as a
dependency because it uses workspace-level dependency references that
aren't resolvable from this standalone crate's `Cargo.lock`.
2026-02-06 16:38:24 +00:00
Niklas Mischkulnig a2ee2d5830 Turbpopack: fix is_persistent_caching_enabled (#89533)
The next config setting was renamed, so this was always false.

So far, this was only used for telemetry.
2026-02-05 21:37:05 +01:00
Niklas Mischkulnig 37516d9579 Turbopack: improve suggestions for experimental.reportSystemEnvInlining (#89486)
Some better suggestions
2026-02-04 14:53:56 +01:00
Niklas Mischkulnig 43136958b4 Add experimental.reportSystemEnvInlining for Turbopack (#89304)
Part of PACK-6641

We don't have a way to silence (ignore-comment) warnings
And additionally, warnings in node_modules are always hidden...
2026-02-04 09:38:20 +01:00
Tobias Koppers b0facee66d Turbopack: Move PrettyPrintError to turbo_tasks and add tests (#89280)
### What?

Move the error printing logic to turbo_tasks and add test cases for it
2026-02-02 08:56:53 +01:00
Benjamin Woodruff a4c1a0cd72 Turbopack: Rename crates/napi to crates/next-napi-bindings and update crate name (#89314)
Disclaimer: This PR is entirely claude+opencode generated.

- Crate name said `next-swc-napi`, which was confusing, because this has a lot more than swc bindings nowdays.
- The crate name didn't match the directory name, which often confused agents.

This does not change the npm package name, as that would likely have a much larger blast radius, and could break more things, to a point where it may not be worth it.
2026-01-30 15:36:57 -08:00
Hendrik Liebau bb41cbd6ee Apply server actions transform to node_modules in route handlers (#89316)
The server actions transform, which handles the `'use cache'` directive,
was not being applied to `node_modules` when imported from route
handlers. This caused `'use cache'` functions from dependencies to fail
with errors like `"cacheLife() can only be called inside a 'use cache'
function"``.

The issue was that the `AppRoute` context used `internal_custom_rules`
for its foreign code module options, which did not include the server
actions transform. This is inconsistent with `AppRSC` (App Router
pages), which correctly uses `foreign_next_server_rules` that includes
the transform.

The fix extends `foreign_next_server_rules` with `internal_custom_rules`
and uses it for the foreign code context in `AppRoute`, matching the
pattern used by `AppRSC`.
2026-01-31 00:03:29 +01:00
Tobias Koppers 99eae38f38 Turbopack: add rules.*.type config to allow changing the type of a module (#88788)
### What?

This PR adds support for the `type` option in Turbopack rules, enabling users to set the module type directly without requiring a custom loader. This mirrors webpack's [`type`](https://webpack.js.org/configuration/module/#ruletype) option (e.g., `type: 'asset/resource'`).

Users can now configure how files are processed by setting the module type directly:

```js
// next.config.js
module.exports = {
  turbopack: {
    rules: {
      '*.svg': {
        type: 'asset',
      },
    },
  },
}
```

When using type: 'asset', importing the file returns its URL:

```
import svgUrl from './icon.svg'

export default function Page() {
  return <img src={svgUrl} alt="Icon" />
}
```

More types are available. See docs
2026-01-30 19:02:13 +01:00
Jiachi Liu af18c32bc8 Improve lock dir error message (#89119) 2026-01-30 16:38:25 +01:00
Tobias Koppers 0ed1edd852 Turbopack: refactor extend transforms (#89116)
### What?

Stop rules when module type is set.
Apply ecmascript transforms before module type is set. (no more errors when trying to apply a transform on non-ecmascript type)
Fix ordering of transform apply.
Reorder module rules to match previous order. They are applied in order now.
2026-01-30 15:32:35 +01:00
Tobias Koppers c6de62407a Turbopack: add support for contentType condition for webpack loaders (#89156)
### What?

Add `contentType` condition

This allows to apply webpack loaders to data urls

### Usage Example

```
module.exports = {
  turbopack: {
    rules: {
      '*': [
        {
          condition: { contentType: 'text/*' },  // glob match
          loaders: ['text-loader'],
          as: '*.js'
        },
        {
          condition: { contentType: /^image\// },  // regex match
          loaders: ['image-loader'],
          as: '*.js'
        },
      ],
    },
  },
}
```
2026-01-30 10:57:00 +01:00
Matt Mastracci 6bbec3cb3d Turbopack: Make the globals we pass to workers configurable (#88773)
# What 

Make the globals we pass to the workers configurable by the browser chunking context.

# Why

We don't want to hardcode knowledge of next.js, but we need to pass the deployment ID (in `NEXT_DEPLOYMENT_ID`) up to all workers.

# How

The chunking context provides `worker_forwarded_globals` that are passed into `getWorkerURL` which then passes them to the worker entrypoint via the `params=` mechanism. We switch to using an array of `params` rather than an object as the deserialization code is now mechanically generated.
2026-01-29 09:57:16 -07:00
Jiachi Liu f1a047fd80 IsolatedDevBuild flag removal (#89167)
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: jiachi <jiachi@vercel.com>
2026-01-29 15:00:12 +01:00
Tobias Koppers 980975f793 Turbopack: add support for turbopackOptional: true (#89227)
### What?

* add support for turbopackOptional: true
* fix runtime code for unresolvable dynamic imports
* add documentation about magic comments
2026-01-29 10:13:21 +01:00
Tobias Koppers e86876d379 Turbopack: selective reads of defined env vars in module analysis (#88759)
### What?

Use selective reads to read defined env vars in module analysis.

This allows to add/remove env vars without invalidating all modules.
2026-01-29 09:48:41 +01:00
Tobias Koppers 04898d8d0d Turbopack: change AsyncModulesInfo to use keyed reads (#89216)
### What?

Use keyed reads for the `AsyncModulesInfo` to reduce the number of tasks
2026-01-29 09:40:15 +01:00
Niklas Mischkulnig 42b0ce87f2 Turbopack: warn when tracing the whole project (#89157)
This should really be an error, but let's start with making it a warning

the only missing piece will be somehow showing the line/col information of the offending reference, this is currently very hard to figure out


<img width="1265" height="428" alt="Bildschirmfoto 2026-01-28 um 12 32 17" src="https://github.com/user-attachments/assets/80e48fa8-a021-4ca2-a966-26164c42b1dd" />
2026-01-28 22:05:01 +01:00
Tim Neutkens 1ce62f28d3 Turbopack: Remove unused argument (#80235)
## What?

Found this argument was unused and only being passed around.
2026-01-28 16:10:09 +01:00
Tobias Koppers ecc2ac976b Turbopack: import with type should be handled via condition (#89035)
### What?

The rule system should handle the import as json
2026-01-27 13:15:19 +01:00