Commit Graph

1409 Commits

Author SHA1 Message Date
Niklas Mischkulnig c1f13e48b0 Turbopack: rename CSS module structs for clarity (#91304) 2026-03-13 17:00:37 +01:00
Luke Sandberg 04a08435e2 Remove LMDB backend and ReadTransaction abstractions from turbo-tasks-backend (#91284)
## Summary

Remove the unused LMDB database backend and the `ReadTransaction` abstraction layer from `turbo-tasks-backend`. This is a pure cleanup that deletes ~1,500 lines of code and eliminates all `unsafe` blocks related to transaction lifetime management.

**Motivation:**
- This was much more useful in the early days of the persistence layer where comparing against a 'known good' db was useful, but this has rotted and turbo-persistence has gained lots of tests and usage so that this is not needed.
- Carrying the code added a lot of complexity to APIs e.g.
    - The `ReadTransaction` abstraction existed solely to support LMDB's transaction-based read model
    - The only remaining backend (`TurboKeyValueDatabase` via `turbo-persistence`) already used `()` as its `ReadTransaction` type, making the entire abstraction dead weight
    - The transaction plumbing required `unsafe` transmute-based lifetime extension in `ExecuteContextImpl`, adding complexity and risk for no benefit
    - The WriteBatch::Serial branches complicated already subtle code paths
2026-03-12 16:19:42 -07:00
Will Binns-Smith 5809756f55 bundle-analyzer: merge _app route modules into current route visualization (#90841)
This:

- Fetches `data/_app/analyze.data` alongside the current route's data
- Merges `_app` modules into the current route's `AnalyzeData` before
visualization using a `mergeAnalyzeData()`, which merges the two
datasets, reindexing the additional ones and recreating the binary data
format expected by the treemap.

## Test plan

- [x] Add a large dependency (e.g. `moment`) in `pages/_app.tsx`
- [x] Run `next experimental-analyze`
- [x] Open the bundle analyzer and select a pages page
- [x] Verify moment appears in the treemap
- [x] Verify App Router projects (no `_app`) work without errors
2026-03-12 14:52:36 -07:00
Janka Uryga 7bbea9d4b1 [Instant] Build-time validation (#90964)
Initial version of build-time instant validation.

During prerendering, if we have `unstable_instant` configs, we perform a
complete staged render of the page (including dynamic data). This render
mocks request data (`params`/`searchParams`/`cookies`/`headers`) using
the `samples` provided in `unstable_instant`. Then, we use the staged
chunks to run instant validation in mostly the same way that we would in
dev. Most changes in the validation flow are related to samples, which
also need to be passed into the client render to mock APIs like
`useParams`.

### Providing Mock data

We run everything in a fresh workStore+workUnitStore to (hopefully)
avoid any data from the prerender from sneaking in. This is quite
involved.

A big part of the trickiness is that if you do e.g. `(await
cookies()).get('myCookie')` but the `samples` don't contain `myCookie`,
we want the validation to error and require explicitly saying what state
`myCookie` is in.
If it's available, use
```ts
export const unstable_instant = {
  // ...
  samples: { cookies: [{ name: "myCookie", value: "someValue" }] }
}
```
If it's not available, use
```ts
export const unstable_instant = {
  // ...
  samples: { cookies: [{ name: "myCookie", value: null }] }
}
```
This explicitness makes it harder to e.g. unintentionally validate a
logged-out state.

Note that even validating a `prefetch: 'static'` page might require
samples, because we need the shared parent for the navigation to be
(mostly) complete. We might be able to relax this in the future, but
it's not straightforward.

Another issue is that a segment might access a missing sample in a
"benign" way, i.e. where it wouldn't block validation (or be inside a
suspense boundary). Ideally we wouldn't require providing a sample for
usages like that, but currently we do.

### Instrumenting APIs to detect missing samples

All request APIs are instrumented in this way.
- `params` throw when accessing a property that was not declared in
`samples`. same for the object from `useParams()`. `in` is allowed
because we know the shape of the params object statically, based on the
routing structure.
- `searchParams` throw when accessing a property that was not declared
in `samples` and `in` checks.
- objects returned from `cookies()`, `headers()`, `useSearchPrams()`
throw on `get()` and `has()`.

There's a lot of tests for this behavior in `instant-validation-build`.

One gap is that iteration/enumeration is currently not instrumented.
We're punting on it for now and will revisit in a follow-up.

### Relation to prerender

We kick off the validation after the prerender, in
`renderToHTMLOrFlightImpl`. Ideally, we should kick this off somewhere
higher up, separately from the prerender itself, but we're leaving that
for future work.

Note that if we do multiple prerenders for the same page (e.g. due to
`generateStaticParams`, we'll only run validation for the first
prerender for that route. `generateStaticParams` is not currently
integrated into the validation at all, i.e. we don't use those params to
validate, so this is safe. All params need to be provided via `samples`.
This will likely change in the future, but we're not sure how yet.

### Disabling build validation

Build-time instant validation is experimental, and has more potential
problems to deal with than dev validation. To allow incremental rollout
and testing, we allow disabling it per instant config:
```ts
export const unstable_instant = {
  unstable_disableBuildValidation: true
  // ...
}
```

for parity, there's also `unstable_disableBuildValidation`, but we don't
expect that to see much use.
2026-03-12 14:57:38 +01:00
zoomdong 41ed440b50 TURBOPACK: typescript transform support verbatimModuleSyntax (#90907)
In utoo case, we need to support react classic jsx transform(To
compitable with react 16 or above project).

We have a case like:

```ts
// index.ts
import React from 'react';

export const App = () => <div></div>;
```

Under the classic jsx transform, the jsx will be transformed as follows:

```ts
export const App = () => React.createElement("div", /***/);
```

But turbopack's jsx transform was behind typescript transform, so in the
stage of typescript transform, the import of react will be deleted by
the default config of swc typescript transform(which set
`verbatimmodulesyntax` as false by default):
https://swc.rs/docs/migrating-from-tsc#verbatimmodulesyntax-true

Then the output of classic jsx transform will get a runtime error like
`React was not found`.

For solve the problem, this pr just support a config
`verbatimModuleSyntax` for turbopack's typescript transform, it will not
remove user's React import under classic jsx transform.

We test the case under utoopack in the following pr:

- https://github.com/utooland/utoo/pull/2653
- https://github.com/utooland/utoo/pull/2655

And Rspack also enable `verbatimModuleSyntax` to true by default under
2.0:
https://github.com/web-infra-dev/rspack/discussions/9270#discussioncomment-13429924
2026-03-12 04:30:11 +00:00
Niklas Mischkulnig 196ed2b839 Fix syntax contexts in server action transform (#91210)
```
let x: Ident = IdentName::new(name, span).into();
```
should never be done. It uses `SyntaxContext::default()` for the Ident. So from swc's perspective, you are referring to a different variable than you think. When constructing an `Ident`, you should usually always provide a SyntaxContext.

I think this would pose a problem in Webpack because it serializes it into a code string again, but for Turbopack these SyntaxContext are important.
2026-03-11 22:16:01 +01:00
xusd320 b1db02697c fix(turbopack): unref ThreadsafeFunctions to allow Node.js exit after build (#91107)
## What?

Calls `unref()` on the `ThreadsafeFunction`s created in
`NapiNextTurbopackCallbacks::from_js` (`throw_turbopack_internal_error`
and `on_before_deferred_entries`).

## Why?

These `ThreadsafeFunction`s are not unref'd, which means they keep the
Node.js event loop alive even after `project_shutdown` completes.

Currently this doesn't cause a visible hang in Next.js because turbopack
runs inside a worker thread (via `packages/next/src/lib/worker.ts`), and
the worker thread is terminated externally. However, if turbopack were
ever run in a child process or directly in the main process, the build
would hang indefinitely after completion — the Rust side of
`stop_and_wait()` finishes, but the Node.js process never exits because
the ref'd `ThreadsafeFunction`s prevent the event loop from draining.
This happened in `utoo`, caused some CI hang forever, the same fix
commit:
https://github.com/utooland/utoo/pull/2670/changes/9e8fd08e84470dce6ac59e976db1b556ce7fece8.

This fix makes the shutdown behavior more robust by following the same
pattern already used in `register_worker_scheduler` in
`turbopack-node/src/worker_pool/worker_thread.rs`, where both creator
and terminator `ThreadsafeFunction`s are explicitly unref'd.

## How?

- Added `Env` parameter to `NapiNextTurbopackCallbacks::from_js()`
- Called `unref(&env)` on both `throw_turbopack_internal_error` and
`on_before_deferred_entries` after creation
- Updated the call site in `project_new` to pass `&env`
2026-03-11 19:05:52 +00:00
Niklas Mischkulnig 19ff1babf0 Lint against .context(format!(...)) (#91122)
There are unfortunately a few false-positives, because this isn't aware of type information of course.
2026-03-11 10:31:51 +01:00
Tobias Koppers 187f35f287 Add experimental.lightningCssFeatures config option (#90901)
### What?

Adds a new `experimental.lightningCssFeatures` config option that lets
users control which CSS features lightningcss should always transpile
(`include`) or never transpile (`exclude`), regardless of browserslist
targets.

```js
// next.config.js
module.exports = {
  experimental: {
    useLightningcss: true,
    lightningCssFeatures: {
      include: ['light-dark', 'oklab-colors'],
      exclude: ['nesting'],
    },
  },
}
```

### Why?

Currently, lightningcss feature transpilation is determined solely by
browserslist targets. There's no way to force transpilation of a
specific feature (e.g., `light-dark()`) when targeting modern browsers
that already support it, or to skip transpilation of a feature that the
user wants to preserve as-is.

This is useful for:
- Forcing polyfill-style transpilation for features with incomplete
browser support
- Testing transpiled output for specific features
- Opting out of specific transforms that may interfere with CSS tooling
downstream

### How?

**TypeScript config & validation:**
- `config-shared.ts`: `LIGHTNINGCSS_FEATURE_NAMES` const array (single
source of truth) with `LightningCssFeature` type derived from it, and
`LightningCssFeatures` interface
- `config-schema.ts`: Zod validation using
`z.enum(LIGHTNINGCSS_FEATURE_NAMES)` for both include/exclude arrays

**Feature name → bitmask mapping (Rust, shared via NAPI):**
- `crates/next-core/src/next_config.rs`:
`lightningcss_feature_names_to_mask()` maps feature name strings to
`lightningcss::targets::Features` bitflag constants and returns a
`Result<u32>` bitmask. Unknown feature names produce an error via
`bail!`.
- Exposed to JS via NAPI as `lightningcssFeatureNamesToMaskNapi`,
callable through `bindings.css.lightning.featureNamesToMask(names)`
- Single source of truth for feature name resolution — both webpack and
Turbopack paths use this Rust function

**Webpack path:**
- `global.ts` / `modules.ts` pass config through to loader options
- `loader.ts` calls `featureNamesToMask()` via the native bindings to
compute include/exclude masks, then passes them to the SWC `transform()`
call
- The `lightningCssFeatures` without `useLightningcss` warning only
shows when using webpack (Turbopack always uses lightningcss)

**Turbopack path (Rust):**
- `next_config.rs`: `LightningCssFeatures` struct for deserialization,
accessor methods converting names → u32 bitmask via
`lightningcss_feature_names_to_mask()`
- Config flows through `CssOptionsContext` → `ModuleType::Css` →
`CssModuleAsset` (using `LightningCssFeatureFlags { include, exclude }`
struct) → `process.rs` where bitmasks are merged into
`lightningcss::targets::Targets { include, exclude }`
- Uses `u32` bitmask representation throughout to avoid adding
lightningcss dependency to non-CSS crates

**Defaults preserved:** `Nesting | MediaRangeSyntax` for Turbopack,
`Nesting` for Webpack. User `include` is OR-ed on top, user `exclude`
masks bits off.

**Feature names:** 21 individual features (bit 0–20) + 3 composite
groups (`selectors`, `media-queries`, `colors`), all in dash-case.

### Test

- **Include test**
(`test/e2e/app-dir/experimental-lightningcss-features/`) — targets
Chrome 123 (which natively supports `light-dark()`) with `include:
['light-dark']`, then asserts the CSS output contains lightningcss
transpilation markers (`--lightningcss-light`, `--lightningcss-dark`)
instead of raw `light-dark()`.
- **Exclude test**
(`test/e2e/app-dir/experimental-lightningcss-features-exclude/`) —
targets Chrome 100 (which does NOT support `light-dark()` natively) with
`exclude: ['light-dark']`, then asserts the CSS output preserves raw
`light-dark()` calls and does not contain transpilation markers.
2026-03-11 08:06:52 +01:00
Luke Sandberg ff36c17c14 [turbopack] Render code frames on the turbopack side (#90534)
Not that error rendering performance is critical, but it is silly to pass frame information from turbopack to js just to have js pass the same information back to native code to draw a frame.
2026-03-10 18:52:40 -07:00
Niklas Mischkulnig c44578498f Turbopack: introduce ReferenceTypeCondition (#91101)
Previously, we used `RuleCondition::ReferenceType(ReferenceType)`. But there are some problem with using the type itself as a matcher:

1. the sub types' Undefined variant (like `CssReferenceSubType::Undefined`) always matched all possible variants. So it was actually impossible to match exactly `CssReferenceSubType::Undefined`
2. variants with more complex types were also impossible to match against, like `ReferenceType::Inner(ResolvedVc<...>)`
2026-03-10 09:47:58 +01:00
Tobias Koppers 014b9987fa Turbopack: implement module.hot.accept(deps, cb) and module.hot.decline(deps) (#90443)
### What?

Implements dependency-level HMR accept and decline for Turbopack,
covering both ESM (`import.meta.turbopackHot`) and CJS (`module.hot`)
modules.

Previously Turbopack only supported self-accept (`module.hot.accept()`
with no arguments) and self-decline. This PR adds the full
dependency-targeted API:

- `module.hot.accept(dep, cb)` / `import.meta.turbopackHot.accept(dep,
cb)` — single dep
- `module.hot.accept([depA, depB], cb)` /
`import.meta.turbopackHot.accept([depA, depB], cb)` — array of deps
- `module.hot.decline(dep)` / `import.meta.turbopackHot.decline(dep)` —
single dep
- `module.hot.decline([depA, depB])` /
`import.meta.turbopackHot.decline([depA, depB])` — array of deps

### Why?

Libraries like `react-refresh` and user code often need to accept
updates for specific dependencies rather than self-accepting the entire
module. Without this, those HMR patterns fall back to full page reloads
in Turbopack.

### How?

**Runtime** (`turbopack-ecmascript-runtime`):
- Extended `HotState` with `acceptedDependencies`,
`acceptedErrorHandlers`, and `declinedDependencies` maps (keyed by
`ModuleId`)
- Updated `hot.accept()` and `hot.decline()` to handle string and array
signatures
- Updated `getAffectedModuleEffects` to check accepted/declined
dependencies when propagating updates through the module graph
- Added `'declined'` effect type that throws an `UpdateApplyError`
- Track `outdatedDependencies` (map of parent → set of updated deps)
alongside `outdatedModules`
- In the apply phase, invoke per-dependency accept callbacks with the
correct outdated deps
- Use `Set` for `outdatedDependencies` dedup (O(1) vs O(n) lookups)

**Compiler** (`turbopack-ecmascript`):
- Added `ModuleHotReferenceAssetReference` — a single asset reference
type for both accept and decline deps, with shared resolve logic for ESM
(`esm_resolve`) and CJS (`cjs_resolve`)
- Added `ModuleHotReferenceCodeGen` — generates code that replaces dep
string literals with resolved module IDs at compile time
- ESM binding auto-update: when an ESM module accepts a dependency that
it also `import`s, the compiler wraps the accept callback to re-import
the namespace variable (`__TURBOPACK__imported__module__<id> =
__turbopack_import__(<id>)`) before the user callback runs, so ESM
bindings reflect updated values without needing `require()`
- Added `import.meta.turbopackHot` as the ESM equivalent of
`module.hot`, with TypeScript type declarations in
`packages/next/types/global.d.ts`
- Static analysis extracts dep strings from
`module.hot.accept`/`decline` calls; non-analyzable deps emit a warning
with distinct error codes (`TP1204` for accept, `TP1205` for decline)

**HMR gating** (`CompileTimeInfo`):
- Added `hot_module_replacement_enabled` flag to `CompileTimeInfo` to
gate recognition of `module.hot` and `import.meta.turbopackHot` as
well-known objects
- Without this flag, production builds would recognize
`module.hot.accept(...)` and generate HMR-specific code, leading to
runtime errors
- Flag set to `true` for dev servers and `false` for production builds
across Next.js and turbopack-cli entry points
- `import.meta.turbopackHot` getter is only emitted when HMR is enabled

**Server HMR** (`next-api`, `next-core`):
- Server-side `compile_time_info` now also sets
`hot_module_replacement_enabled` so that `module.hot` /
`import.meta.turbopackHot` are recognized during analysis of server
modules
- Server HMR requires the `--experimental-server-fast-refresh` CLI flag;
the flag is passed through `ProjectOptions` to the Rust side so
`server_compile_time_info` only enables HMR when appropriate

**Tests** (`test/development/app-dir/hmr-dep-accept/`):
- ESM single dep accept — verifies parent module is not re-evaluated,
accept callback fires, ESM bindings auto-update
- ESM array dep accept — same as above with `accept(['./dep-a',
'./dep-b'], cb)`
- CJS `module.hot.accept` — pure CJS dep observer pattern with `.cjs`
files
- Single dep decline — verifies full page reload occurs
- Array dep decline — verifies full page reload with
`decline(['./dep-a', './dep-b'])`
2026-03-09 10:51:17 -07:00
Niklas Mischkulnig fda324e206 Turbopack: correctly use ChunkGroup::Shared (#90978)
I don't think we have any tests that the server utility chunking actually works.
But I can't actually properly remember why we added it in the first place: https://github.com/vercel/next.js/pull/70461
2026-03-09 10:12:37 +01:00
Niklas Mischkulnig 99303d31fa Turbopack: accept ChunkGroup in entry_chunk_group (#90821)
Now all of the chunking context functions accept `ChunkGroup`

The names are bad, but `entry_chunk_group` and `ChunkGroup::Entry` have nothing to do with each other:
- `entry_chunk_group` means: it's a standalone file where `node path/to/chunk.js` will execute it
- `ChunkGroup::Entry` = it's the top-level chunk group

For example a `evaluated_chunk_group(ChunkGroup::Entry)` is also fine
2026-03-07 16:39:09 +01:00
Benjamin Woodruff 6e894cfc85 Turbopack: Make ReadVcFuture::strongly_consistent private (#90843)
This method is needed with `turbo-tasks` to implement `OperationVc`, but exposing it to other crates turns it into a footgun, because it allows you to attempt to read a `Vc` or `ResolvedVc` with strong consistency, which doesn't have a well-defined meaning.
2026-03-06 11:36:38 -08:00
Niklas Mischkulnig 07df7fa028 Turbopack: pass reference type to CustomModuleType (#90814)
No reason to restrict it to `ReferenceType::EcmaScriptModules(EcmaScriptModulesReferenceSubType::ImportPart(part))`
2026-03-06 12:19:15 +01:00
Niklas Mischkulnig 73b44a185b Turbopack: CompileTimeDefineValue numbers and regex (#90934)
- Number(f64) instead of Number(RcStr)
- Add BigInt
- Add Regex
2026-03-06 09:48:23 +01:00
Tobias Koppers ad030d782e Turbopack: Tree shaking fixes and code organization (#89295)
## Summary

A series of bug fixes, refactors, and code organization improvements to Turbopack's tree shaking and side effect optimization:

- **Fix `ModulePart` handling for `FreeVarReference::EcmaScriptModule`** — pass `ModulePart` correctly so free variable references resolve to the right module part
- **Extract `EcmascriptModuleRenameModule`** — split the rename/reexport logic (`RenamedExport`, `RenamedNamespace`) out of `EcmascriptModuleFacadeModule` into a dedicated `rename` module, shared between side effects optimization and tree shaking
- **Simplify `EcmascriptModuleFacadeModule`** — now only handles the `Facade` case (locals + reexports), no longer overloaded with rename variants
- **Reorganize tree shaking code** — moved `asset.rs` → `part/module.rs`, `chunk_item.rs` → `part/chunk_item.rs` + `side_effects/chunk_item.rs`, `side_effect_module.rs` → `side_effects/module.rs` for clearer separation between part modules and side effect modules
- **Use `EsmExport` in `FindExportFromReexportsResult`** — reduces code duplication by reusing the existing `EsmExport` enum
- **Minor simplifications** — code deduplication, reordered checks, and general cleanup
2026-03-05 07:49:19 +01:00
Luke Sandberg 286a73f84a Add trace spans for turbopack persistence in .next/trace (#90397)
## Summary

- Add a generic `TraceEvent` compilation event type that carries a name, wall-clock timing, and arbitrary attributes
- Emit `TraceEvent` from Turbopack's Rust backend for cache persistence and compaction operations
- Expose `eventJson` on compilation events through the NAPI bridge
- Record `turbopack-persistence` and `turbopack-compaction` trace spans in `.next/trace` with memory usage snapshots, in both dev and build workflows

## Details

Turbopack persistence and compaction operations were invisible in `.next/trace`. The only signal was a console log for operations exceeding 10s.

A new generic `TraceEvent` type replaces the need for per-operation event structs. It carries a name, start/end wall-clock timestamps, and a `Vec` of key-value attributes. On the JS side, `backgroundLogCompilationEvents` handles all `TraceEvent`s with a single code path — creating trace spans via `manualTraceChild` and recording memory usage snapshots. Adding new traced operations requires only a few lines of Rust and zero JS changes.

At @bgw's suggestion, I considered integrating as a `tracing_subscriber::Layer` to automatically forward spans to the compilation event system, but this ended up requiring quite a bit of code (a new subscriber, 'target' impl, span lifecycle management, new crate dependencies) for what is currently just 2 events, and we don't really anticipate adding more.

## Test plan

- [x] Integration test in `test/e2e/filesystem-cache` verifying `turbopack-persistence` spans exist with correct attributes
- [x] `pnpm test-dev-turbo test/e2e/filesystem-cache`
- [x] `pnpm test-start-turbo test/e2e/filesystem-cache`
2026-03-04 16:33:25 -08:00
Niklas Mischkulnig a41e4d5702 Unify Node and Edge externals list (#90819)
Unify the list of Node/Edge iexternals.
Turns out `readline/promises` and `stream/consumers` was missing in some places.

Closes https://github.com/vercel/next.js/issues/90765
2026-03-04 18:36:03 +01:00
Niklas Mischkulnig 5b17dfeb80 Turbopack: allow resolving TS files in tailwind config (#90046)
A regression from https://github.com/vercel/next.js/issues/86576

Closes https://github.com/vercel/next.js/issues/87898
Closes PACK-6421
2026-03-04 18:33:17 +01:00
Sebastian "Sebbie" Silbermann cb44b43cdf Use page extensions in next-swc transforms applying to pages (#90650)
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Niklas Mischkulnig <4586894+mischnic@users.noreply.github.com>
Co-authored-by: vercel[bot] <35613825+vercel[bot]@users.noreply.github.com>
2026-03-04 16:13:36 +00:00
Matt Mastracci 1bc8f55993 Add Err(anyhow(... ast-grep rule (#90869)
# What

Add an ast-grep rule to use `bail!` rather than `Err(anyhow!(` in a
return position.

# Why

This is slightly more compact, and allows us to port more code over to
turbofmt/turbobail.

Note: _this PR was previously merged into another branch due to a GH
bug_
2026-03-04 09:08:55 -07:00
Matt Mastracci e4cae37084 Turbopack: turbofmt/turbobail macros (#90092)
# What
Add turbofmt! and turbobail! proc macros for async string formatting
with Vc<T> and ResolvedVc<T> values.

A new, agent-friendly `FORMATTING.md` file is added to help agents
figure out how these macros work.

# Why

Formatting strings that include turbo-tasks values currently requires
manually .await?ing each Vc, then calling format!, then converting to
RcStr via .into(). By using macros, we can reduce a lot of boilerplate
and potentially offer some opportunities for optimizations by reducing
intermediate, throwaway tasks.

# How

We make use of the "auto-deref" pattern in Rust to choose the "best"
formatting option: ValueToString or Display.

- Zero-alloc FormatIter: A shared iterator parser over format strings
(RawString, EscapedBrace, VarRef, VarRefFormat) that both macros and the
derive use, replacing duplicated manual parsing.
- Borrow-based capture: turbofmt! uses async { .. } (not async move), so
non-Copy types like FileSystemPath can be used in multiple turbofmt!
calls without cloning.
  - Debug on StringifyType: Enables {:?} format specs in turbofmt!.
- Converted ~30 call sites across next-core, turbo-tasks-fs,
turbopack-core, turbopack-ecmascript, and others.

# What's Left

- Constants cannot be formatted with turbofmt! yet because of arcane
Rust hygiene rules (similar issue to
https://github.com/rust-lang/rust/issues/131446)
- rust-analyzer doesn't show these format strings as "real" format
strings yet because of limitations of the analyzer, but this should be
possible to make work.
- Automatic derive for ValueToStringRef to avoid intermediate tasks in a
few places where formatting is trivial
 -  turbowrite!/turbowriteln! could clean up a bit more code
2026-03-04 15:11:04 +00:00
Luke Sandberg ce14ca88a4 Reimplement code frame rendering in native code (#85592)
## What

Replaces the `@babel/code-frame` dependency with a new Rust-based implementation (`next-code-[frame](https://github.com/arthurprs/qfilter/pull/20#issuecomment-3986882055)` crate) for rendering code frames in error messages.

### Why

- **Crash fix**: `@babel/code-frame` uses the `js-tokens` library for syntax highlighting, which has [known issues](https://github.com/lydell/js-tokens?tab=readme-ov-file#known-failures) with large string literals and long lines. This can cause Next.js to throw RangeErrors when rendering errors, hiding the original issue!
- **Long line support**: The old implementation had no concept of terminal width, dumping entire lines into the output. The new implementation uses "horizontal scrolling" — truncating lines and centering the error location in the visible window.
- **Performance**: The Rust implementation only processes the visible line range (typically ~6 lines), not the entire file. Syntax highlighting uses a skip-scan heuristic to start tokenizing near the visible window rather than from byte 0.
- **Dependency reduction**: Drops the semi-unmaintained `@babel/code-frame` bundled dependency in favor of code we control.

### Benchmarks

In-process benchmarks comparing `render_code_frame()` (Rust, via criterion) against `codeFrameColumns()` (Babel, via hrtime with DCE prevention). Both have syntax highlighting and color output enabled. No process startup or file I/O is included in the measurement.

| Scenario | `next-code-frame` (Rust) | `@babel/code-frame` | Speedup |
|---|---|---|---|
| Small file (~490 lines TSX) | **5.4 µs** | 507 µs | **~94x** |
| Large file (~39k lines JS) | **143 µs** | 82.9 ms | **~580x** |
| Large file minified | **51 µs** | - | **-** |

The gap widens with file size because Babel's `highlight()` runs a regex tokenizer over the **entire source** before slicing to the visible window, while the Rust implementation uses a windowed line index and skip-scan heuristic — only processing the visible window regardless of file size.  However, for minified files we do end up tokenizing the whole thing so we end up being only 8x faster

### How

- New `crates/next-code-frame/` Rust crate with:
  - Frame rendering with terminal-width-aware horizontal scrolling
  - Regex-based syntax highlighting (matching Babel's color scheme)
  - Skip-scan heuristic for O(1)-ish highlighting regardless of file size
  - Windowed line index that only scans/stores offsets for the visible region
  - Comprehensive test suite (800+ lines)
- Exposed via both NAPI (native) and WASM bindings
- JS wrappers in `packages/next/src/shared/lib/errors/`:
  - `code-frame.ts` — primary wrapper using native bindings
  - `optional-code-frame.ts` — graceful fallback returning `undefined` if bindings are unavailable
- All existing callsites (`diagnosticFormatter`, `parseScss`, dev overlay, turbopack utils) updated
- for `patch-error-inspect.ts` i adopted an `injection` style approach to avoid coupling to the native dependency

### Concerns / review focus areas

- **Reliability**: The regex-based tokenizer is best-effort and language-agnostic — it should never crash on invalid syntax, but highlighting accuracy may differ from Babel's `js-tokens` in edge cases.
- **Native dependency**: This moves code frame rendering into the native binary. Performance should be better, but worth verifying there are no regressions in environments where native bindings behave differently (e.g. WASM fallback path).
- **Regressions**: The output format and color scheme closely match Babel's, but there may be subtle differences. The horizontal scrolling behavior is new.

Fixes #85357
Closes PACK-5754
2026-03-03 04:59:11 -08:00
Tobias Koppers de1add2539 Remove unused turbo-tasks items and add lint check (#90801)
### What?

Adds a lint script (`scripts/check-unused-turbo-tasks.mjs`) that detects
unused `#[turbo_tasks::function]`, `#[turbo_tasks::value]`, and
`#[turbo_tasks::value_trait]` definitions across the Rust codebase, and
removes all currently unused items.

### Why?

Dead turbo-tasks definitions add compilation overhead (each generates
trait impls, registrations, etc.) and make the codebase harder to
navigate. A lint check prevents regressions.

### How?

**New script** (`scripts/check-unused-turbo-tasks.mjs`):
1. Discovers all `.rs` files in `turbopack/crates/` and `crates/`
(excluding `turbo-tasks-macros-tests`)
2. Parses three kinds of turbo-tasks annotations:
- `#[turbo_tasks::function]` → extracts `fn` name + context (free,
inherent impl, trait impl, trait default)
   - `#[turbo_tasks::value]` → extracts `struct`/`enum` name
   - `#[turbo_tasks::value_trait]` → extracts `trait` name
3. Scans all files for identifier references, excluding definition sites
4. Reports any name that has no external references

The script is added to the `pnpm lint` command (runs in parallel with
other checks).

**Removed 23 unused items** across 18 files:

| Kind | Count | Examples |
|------|-------|---------|
| `value` (struct/enum) | 9 | `OutputAssetsWithAvailability`,
`ModuleNameMap`, `OptionModuleIds`, `LockedVersions`,
`AssetContentSnapshot` |
| `function` | 14 | `client_env`, `next_js_file`, `convert_path`,
`is_hot_module_replacement_enabled`,
`any_content_changed_of_output_asset` |

Also cleaned up imports that became unused after the removals.
2026-03-03 12:01:45 +01:00
Jan Nicklas 5fa40c806c exempt data URL CSS from Pages Router global CSS restriction (#89901)
### What?

Skip the Pages Router global CSS restriction for `data:` URL imports
(similar to app router and mixed app/pages router)

### Why?

`data:text/css` should work the same no matter if pages router, app
router or mixed router usage

### How?

the validation in `crates/next-api/src/module_graph.rs` already had a
carve-out for `node_modules`. This adds the same for data URL modules.

fixes #89900

- [x] Related issues linked using `fixes #89900`
- [x] Tests added

---------

Co-authored-by: Tim Neutkens <tim@timneutkens.nl>
2026-03-03 11:17:30 +01:00
Tobias Koppers 420b72b697 Update Rust dependencies for turbo-persistence and turbo-tasks-backend (#90774)
### What?

Updates outdated Rust dependencies used by `turbo-persistence` and
`turbo-tasks-backend` crates.

### Why?

Keep dependencies current to benefit from bug fixes, performance
improvements, and security patches.

### How?

Each dependency was updated in a separate commit. All crates were
verified to compile and tests pass.

**Direct dependency updates:**
- `lzzzz` 1.1.0 → 2.0.0 (moved to workspace dependency, used by both
crates)
- `arc-swap` 1.7.1 → 1.8.2 (turbo-tasks-backend)

**Workspace dependency updates:**
- `bitfield` 0.18 → 0.19
- `either` 1.9 → 1.15
- `indexmap` 2.7 → 2.13
- `once_cell` 1.17 → 1.21
- `rand` 0.9 → 0.10 (required API migration: `Rng`/`RngCore` → `RngExt`)
- `ringmap` 0.1 → 0.2

**Skipped:**
- `hashbrown` 0.14 → 0.16: The `raw` module was removed in 0.15 and
replaced with `HashTable` API. The codebase uses `RawTable`, `Bucket`,
`InsertSlot` extensively, requiring a non-trivial migration.
2026-03-03 09:49:20 +01:00
Luke Sandberg 8b70c61007 [turbopack] Don't schedule idle snapshots when we are in a short session (#90804)
In a few `next build` commands i saw multiple snapshots due to this.  Idle callbacks were firing near the end of the build.

```
  Creating an optimized production build ...
WARNING: The git repository is dirty, but File System Cache is still enabled. Manual removal of the filesystem cache database might be required.
✓ Finished writing to filesystem cache because: idle timeout in 6.1s
✓ Compiled successfully in 69s
✓ Collecting page data using 13 workers in 85ms
  Build ran with "compile" mode, to finalize the build run either "generate" or "generate-env" mode as well
✓ Finalizing page optimization in 32ms
Route (app)
...ommitted route table...
✓ Finished writing to filesystem cache because: stop in 3.5s
```

This is a bit wasteful since it is more efficient to write everything in a single batch at the end.

The solution is just to not schedule snapshotting operations in 'short sessions' (aka `next build`)
2026-03-02 23:58:52 -08:00
Josh Story 410c65808a Add static error when unstable_instant is used without cacheComponents (#90793)
`unstable_instant` requires `cacheComponents` to function — without it,
validation is entirely skipped and the config silently does nothing.
This adds a compile-time error in the SWC transform that catches the
misconfiguration early, matching the existing pattern used for segment
configs like `revalidate` that are incompatible with `cacheComponents`
(but inverted — `unstable_instant` requires it rather than being
incompatible with it). The error points directly to the export in the
user's source file.
2026-03-03 00:35:56 +00:00
Benjamin Woodruff c2a27526f8 Turbopack: Revert default loader runtime backend to child processes (#90675)
We're getting crashes in node: https://github.com/vercel/workflow/actions/runs/22500511618/job/65186125774#step:10:224

It looks like this should be fixed in newer versions of node:

- https://github.com/napi-rs/napi-rs/issues/2555#issuecomment-3645173223
- https://github.com/nodejs/node/pull/55877
- https://github.com/nodejs/node/pull/61400
- https://github.com/nodejs/node/pull/61661

So we may enable the worker threads feature by default if we detect a new enough version of node or bun.
2026-02-28 08:39:20 +01:00
Benjamin Woodruff c5b2cf1e32 Turbopack: Allow turbopack-node backend to be swapped at runtime using an experimental config option (#90671)
<!-- 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 #

-->

Follow-up to https://github.com/vercel/next.js/pull/86266  
This was mostly LLM-generated, but it's just moving things around and threading through a config option.  
  
We'd like to be able to turn this on/off with an experimental config option:  
\- Fixes issues where RA thinks a bunch of code is dead.  
\- Lets us isolate potential issues to the worker thread implementation.  
\- Provides an escape hatch for users in case there are issues.  
\- Better fits the cargo "additive feature" model.
2026-02-27 22:48:05 -08:00
Sebastian "Sebbie" Silbermann ef993b251c Use VisitMut instead of Fold for debug_instant_stack transform (#90274) 2026-02-27 12:47:07 +00:00
Niklas Mischkulnig 4d5840e3b7 Turbopack: experimental.immutableAssetToken (#88607)
This allows specifying a different deployment id for static immutable assets

- [x] rename `getImmutableAssetToken` to `getAssetToken` (because it can be non-immutable as well)
- [x] disable for webpack

Closes PACK-6534

For https://github.com/nextjs/adapter-vercel/pull/25

Part of PACK-6802
2026-02-27 11:55:47 +01:00
Niklas Mischkulnig 0b3da78825 Adapter: STATIC_FILE.immutableHash (#90045)
Disabled for now

Expose a hash for each file that should be treated as immutable

For https://github.com/nextjs/adapter-vercel/pull/25

Part of PACK-6802
2026-02-27 10:51:43 +01:00
Sebastian "Sebbie" Silbermann 4c6c31ad1e [instant] Don't add debug stack to random unstable_instant exports (#90273)
Instead of just limiting the transform to any file within the app dir, we now restrict it to any page, default, or layout file in the app dir. This avoids having the transform applied to random modules. The inserted value would not have been used by anything.
2026-02-27 10:17:52 +01:00
xusd320 2ba4d6ee9d refactor(turbopack-node): support execution by napi and worker_threads (#86266)
1. refactor `turbopack-node` to run webpack loaders via nodejs
`worker_threads`
2. the `child_proccess` loader runner is keep in the crate feature to
run unit tests in `turbopack-tests` or run `turbopack-cli`
3. if wanting to switch back to `child_proccess` loader runner, change
features of `turbopack_node/worker_pool` to
`turbopack_node/process_pool` in crate `next-swc-napi`
4. after switched to `worker_threads` loader runner, debugging with
`CDP` (spawn child_process via `--inspect-brk`) doesn't work anymore,
but you can use breakpoint debugging in IDE (like vscode) directly

---------

Co-authored-by: Niklas Mischkulnig <4586894+mischnic@users.noreply.github.com>
Co-authored-by: Benjamin Woodruff <benjamin.woodruff@vercel.com>
2026-02-26 20:52:32 -08:00
Benjamin Woodruff 89f3649a00 Turbopack: Panic if a top-level task attempts an eventually consistent read (#89735)
We've had some really bad bugs in the past, which can be hard to root-cause due to eventually-consistent reads a the top-level, e.g. https://github.com/vercel/next.js/pull/77511

Outside of tests, there's no good justification for doing an eventually-consistent read at the top level. It may leak incomplete computations, which can contain errors that would otherwise be resolved by a strongly consistent read.

The basic idea here is simple:

- Store a flag in `CURRENT_TASK_STATE` indicating that we're in a top-level task.
- When reading a task output or cell, check for that flag.

But, there are a few complications:

- `RawVc`'s read and resolution logic is wrong, and internally uses multiple eventually consistent operations after a strongly consistent read.
    - For this to be correct, it needs to happen as one atomic operation inside of the task backend, but it would change the backend API contract, so it's not straightforward to do that.
    - I added a `SUPPRESS_EVENTUAL_CONSISTENCY_TOP_LEVEL_TASK_CHECK` flag that I'm using for now.
- There are a ton of places that are doing eventually consistent reads for no good reason. These aren't causing problems today, but we should fix them instead of suppressing them. Claude helped with this, but it's still a lot.
- Some tests actually do need eventually-consistent reads because they're testing some internal behavior of turbo-tasks. I added an intentionally long-named `unmark_top_level_task_may_leak_eventually_consistent_state` helper for this.

I manually tested `turbopack-cli` against our bundler-benchmark repository that uses it.
2026-02-26 16:14:30 -08:00
Tobias Koppers 891cfe69c8 Turbopack: Add Next.js version to "initialize project" trace span (#90545)
## Summary

Adds the Next.js version as a `version` field on the Turbopack
"initialize project" tracing span. The version is passed from the
TypeScript side (`process.env.__NEXT_VERSION`) through the NAPI bindings
into Rust `ProjectOptions`, where it is recorded on the span.

This makes it easy to correlate trace data with the specific Next.js
version that produced it.

Also standardizes all version reads in `packages/next/src/` to use
`process.env.__NEXT_VERSION` (which is inlined at build time by
`taskfile-swc.js`) instead of `require('next/package.json').version` or
`import { version } from 'next/package.json'`.

### Changes

**Trace span (commit 1):**
- **`crates/next-api/src/project.rs`** — Added `next_version` field to
`ProjectOptions`; recorded as `version` on the `"initialize project"`
span
- **`crates/next-napi-bindings/src/next_api/project.rs`** — Added
`next_version` to `NapiProjectOptions` and wired it through the `From`
impl
- **`crates/next-build-test/src/main.rs`** — Added `next_version` to
test `ProjectOptions` init
- **`packages/next/src/build/swc/generated-native.d.ts`** — Added
`nextVersion` to the TypeScript `NapiProjectOptions` interface
- **`packages/next/src/server/dev/hot-reloader-turbopack.ts`**,
**`packages/next/src/build/turbopack-build/impl.ts`**,
**`packages/next/src/build/turbopack-analyze/index.ts`** — Pass
`nextVersion: process.env.__NEXT_VERSION` when creating the Turbopack
project
- **`test/development/basic/next-rs-api.test.ts`** — Added `nextVersion`
to both `createProject` call sites

**Consistent `__NEXT_VERSION` usage (commit 2):**
- **`packages/next/src/server/dev/hot-reloader-shared-utils.ts`** —
`require('next/package.json').version` → `process.env.__NEXT_VERSION`
- **`packages/next/src/lib/patch-incorrect-lockfile.ts`** —
`nextPkgJson.version` → `process.env.__NEXT_VERSION`; narrowed import to
only `optionalDependencies`
- **`packages/next/src/telemetry/events/swc-load-failure.ts`** — `import
{ version as nextVersion }` → `process.env.__NEXT_VERSION`; narrowed
import to only `optionalDependencies`

## Test Plan

- Verified Rust compilation with `cargo check -p next-api`, `cargo check
-p next-build-test`
- Verified TypeScript types with `pnpm --filter=next types`

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-02-26 18:37:15 +01:00
Tobias Koppers cd6a9bc7d1 Replace mark_root() with #[turbo_tasks::function(root)] flag (#90512)
## Summary

Replaces the runtime `mark_root()` call with a declarative `root` flag
on the `#[turbo_tasks::function]` attribute macro. This moves root task
aggregation number assignment from an imperative runtime call to a
compile-time declaration, making the intent clearer and applying the
aggregation number at task creation time rather than during execution.

### What changed

- **Macro parsing**: Added `root` as a new flag option for
`#[turbo_tasks::function(root)]` (can be combined with other flags, e.g.
`#[turbo_tasks::function(operation, root)]`)
- **NativeFunction**: Added `is_root: bool` field and parameter to all
three constructors (`new_function`, `new_method`,
`new_method_without_this`)
- **Backend**: In `get_or_create_persistent_task` and
`get_or_create_transient_task`, checks `native_fn.is_root` on brand-new
task creation (not cache hits or backing storage restores) and sets
`UpdateAggregationNumber` with `u32::MAX`
- **Usage site**: Changed `whole_app_module_graph_operation` in
`crates/next-api/src/project.rs` from
`#[turbo_tasks::function(operation)]` + `mark_root()` to
`#[turbo_tasks::function(operation, root)]`
- **Cleanup**: Removed `mark_root()`, `set_own_task_aggregation_number`
from `TurboTasksApi` trait, `Backend` trait, and all implementations
(turbo-tasks-backend, turbo-tasks-testing)

### Key design decisions

- Root aggregation number is only set on **brand-new task creation**
(Vacant entry in the task cache when not found in backing storage
either), not on cache hits or when restoring from backing storage
- The `root` flag is stored on `NativeFunction` (which is a static
singleton per function), so it's accessible via
`CachedTaskType.native_fn.is_root` in the backend without any additional
runtime overhead

## Test Plan

- `cargo check -p turbo-tasks-macros -p turbo-tasks -p
turbo-tasks-backend -p next-api` passes
- `cargo test -p turbo-tasks-backend` passes
- `pnpm swc-build-native` builds successfully
2026-02-26 08:24:05 +01:00
Jiwon Choi 46761a3210 Throw when unstable_instant is used in Client Component (#90396)
The `unstable_instant` route segment config is not allowed in Client
Components because the API mainly depends on prefetches, which Client
Components aren't part of.

Closes NAR-774

---------

Co-authored-by: vercel[bot] <35613825+vercel[bot]@users.noreply.github.com>
2026-02-25 23:34:07 +01:00
Niklas Mischkulnig cbb858f032 Turbopack: emit env_diff span attribute for update (#90466)
it already existed for `.create()`, but not `.update()`
2026-02-25 10:22:14 +01:00
Sebastian "Sebbie" Silbermann 409b7a6a28 Add support for Next.js error telemetry for AggregateError (#90391) 2026-02-24 15:35:55 +01:00
Matt Mastracci 797eb7fe7f Turbopack: refactoring to prepare for name mangling (#89406)
## What

Refactors module splitting and re-export handling to prepare for the name mangling PR.

### Changes

1. **`EsmExports::reexport_including_default` helper** — New helper that creates re-export facades (default + star export) from a module reference. Replaces duplicated boilerplate in `NextDynamicEntryModule`, `NextServerComponentModule`, and `NextServerUtilityModule`.

2. **`get_locals_if_split` / `get_facade_if_split` on `EcmascriptModuleAsset`** — Encapsulates the split-check-then-wrap logic that was previously inlined in `turbopack/src/lib.rs`. Returns the locals or facade module when the module has re-exports that should be separated, otherwise returns self.

3. **Simplified `apply_module_type` in `turbopack/src/lib.rs`** — The tree-shaking `ReexportsOnly` path now uses the new helpers instead of manually checking `split_locals_and_reexports` and constructing facade/locals modules inline.

4. **Documentation improvements** — Added doc comments to `EsmExport` variants, `EsmExports` fields, and `split_locals_and_reexports`.

## Why

Extracting these helpers simplifies the upstream code and reduces the diff for the name mangling PR. The `reexport_including_default` helper is needed because the next stage will require additional work for virtual facade modules to function with mangled names. The `get_locals_if_split` / `get_facade_if_split` methods centralize split logic so that next.js module wrappers (which need unmangled export names) can use them directly.
2026-02-23 08:58:50 -07:00
Sebastian "Sebbie" Silbermann 4268acf1b7 [turbopack] Remove obsolete is_internal field (#90329) 2026-02-23 13:52:43 +00:00
Sebastian "Sebbie" Silbermann cbc4888b18 [turbopack] Consider ignoreList of 3rd party sourcemaps in Redbox (#90317) 2026-02-23 11:53:58 +00:00
Luke Sandberg f93a867d77 Update wasm and next-custom-transforms crates to Rust edition 2024 (#90350)
The `wasm` and `next-custom-transforms` crates were still on Rust edition 2018 while the rest of the crates in this repo use edition 2024. This caused a pre-commit hook conflict:

- `cargo fmt` passes the crate's own edition (2018) to `rustfmt`, which uses **case-insensitive** import sorting
- The lint-staged pre-commit hook runs `rustfmt --edition 2024 --`, which uses **ASCII order** import sorting (uppercase before lowercase)

These two sort orders disagree on items like `{custom_before_pass, TransformOptions}` vs `{TransformOptions, custom_before_pass}`, causing an infinite flip-flop: every commit would reorder imports, and the next `cargo fmt` would reorder them back.

## Changes

- Bump `crates/wasm` and `crates/next-custom-transforms` from edition 2018 to 2024
- Add `+ use<C>` precise capturing to `server_actions()` return type to satisfy edition 2024's stricter `impl Trait` lifetime capture rules
- Add `style_edition = "2024"` to `.rustfmt.toml` as a safety net so `cargo fmt` uses 2024-style formatting regardless of individual crate editions
- Reformat all affected files with `cargo fmt`
- Apply new clippy rules
2026-02-23 01:48:12 -08:00
Niklas Mischkulnig ccee817b55 Turbopack: support Subresource Integrity
(#90152)

A spinoff from https://github.com/vercel/next.js/pull/90045

- [x] The SRI test is failing for unrelated reasons (hardcoded chunk name matching)
- [x] Somehow, the hashes are wrong
2026-02-21 10:40:12 +01:00
Sebastian "Sebbie" Silbermann 19dcd1339f [instant] Handle more instant declaration patterns (#90251)
Adds handling for 


```tsx
export { unstable_instant } from './config'
       ^
```
```tsx
const unstable_instant = ...
                         ^
export { unstable_instant }
```
```tsx
const instant = ...
                ^
export { instant as unstable_instant }
```
We're not following assignments recursively and stop at the first declaration:
```tsx
const _instant = ...
const instant = _instant
                ^
export { instant as unstable_instant }
```
2026-02-20 14:19:54 -08:00
Niklas Mischkulnig 9404b901ab Turbopack: add Rope.content_hash and SHA hashing (#90235)
We want `FileContent.content_hash()` to only hash the content bytes. This is also needed to produce the correct hashes [for SRI](https://developer.mozilla.org/en-US/docs/Web/Security/Defenses/Subresource_Integrity)

However, the default `DeterministicHash` and `Hash` impls are ill-suited for that because they're a generic hashing infrastructure.
Hashing only the content bytes isn't what you want actually, otherwise `hash(("a", "b", "c"))`  would be the same as `hash("abc")`
https://doc.rust-lang.org/std/hash/trait.Hasher.html#method.write_str describes this problem as well

This is exactly what we want for Rope though, so this adds a `Rope.content_hash() -> impl DeterministicHash`.

Additionally, this changes `content_hash` to accept a HashAlgorithm to prepare for sha SRI hashes. This required changing the return type to `RcStr`, because of the variable hash lengths. But the return value was always `encode_hex`d everywhere anyway.
2026-02-20 22:25:22 +01:00