This was flakey with Turbopack:
```
Error: TIMED OUT: /New page/
404
This page could not be found.
undefined
at check (/root/actions-runner/_work/next.js/next.js/test/lib/next-test-utils.ts:726:9)
at Object.<anonymous> (/root/actions-runner/_work/next.js/next.js/test/integration/read-only-source-hmr/test/index.test.ts:124:7)
```
But somehow Webpack doesn't automatically refresh the page here?
https://github.com/user-attachments/assets/b363dbff-60d1-4813-bb1c-e5a64f0312d3
## 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)
## 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)
For some locations LightningCSS is 1-indexed (but not all of them, the rustdoc describes it though)
IssueSource is always 0-indexed
Previously, it looked like this
```
Error: Turbopack build failed with 1 errors:
./bench/basic-app/app/[variants]/styles.css:7:12
Module not found: Can't resolve './test1.png'
5 | .style {
6 | cursor: url(./test1.png);
> 7 | }
| ^
8 |
```
This includes the set of experimental flag states in events sent to the
trace upload receiver when `--experimental-trace-upload` is set. It only
includes a subset of experimental flags (so things like the trace upload
flag itself isn't meaninglessly sent).
Since reporting is often limited to the scope of a single span, the flag
state attributes are denormalized and copied onto every descendent span.
Limiting the set of flags prevents this from being unnecessarily large.
Test Plan: Added `test/development` test and built an app and verified
these tags are sent with `NEXT_TRACE_UPLOAD_DEBUG`
---------
Co-authored-by: vercel[bot] <35613825+vercel[bot]@users.noreply.github.com>
Co-authored-by: Luke Sandberg <lukesandberg@users.noreply.github.com>
This implements the remainder of functionality needed for Server HMR
(Fast Refresh).
How It Works
- Turbopack detects file changes in RSC modules
- Rust sends HMR update payloads to the Node.js runtime via the existing
chunk update system
- A Node-specific HMR client evaluates changed modules using shared HMR
runtime logic (extracted earlier in this stack)
- Only modified modules are re-evaluated. Unmodified modules retain
their state
- Next.js hot-reloader forwards updates to RSC workers, triggering
automatic re-renders in clients
Test Plan: Added an e2e test confirming that unaffected modules don't
get re-evaluated when others change.
## 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 },
],
},
}
```
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
Analagous to the existing compile-path, which records compile times for
each path in development, we now record path render times as
`render-path`. It corresponds with the value we write to the tty when
rendering routes (e.g. `GET / 200 in 228ms (compile: 129ms, render:
99ms)`).
This change also adds tests for recording hmr data in the trace file.
Test Plan:
- CI
- Made changes in a test app and verified the trace file included valid
entries for these. Confirmed the duration matched what was shown in
the cli.
Mostly mechanical rename.
Also changes the error page to `errors/invalid-instant-configuration`.
I'm not really worried about dangling links here because this is a new
API and we don't expect anyone to be using it yet.
## What?
This PR adds support for detecting `@typescript/native-preview` as an
alternative TypeScript compiler. When installed, Next.js will no longer
automatically install the `typescript` package.
## Why?
Fixes#88580
Users who want to use `@typescript/native-preview` (a Go-based native
TypeScript compiler) should not be forced to also install the
JavaScript-based `typescript` package. This is especially relevant for
projects using `next.config.ts` where TypeScript support is provided by
Node.js native TS or SWC.
## How?
1. Added `hasNativeTypeScriptPreview()` function to detect if
`@typescript/native-preview` is installed
2. Modified the dependency check logic in `verifyTypeScriptSetup()` to
skip auto-installing `typescript` when the native preview is present
3. Added an informative log message to notify users that some TypeScript
features (like type checking during build) require the standard
`typescript` package
4. Added e2e test to verify the behavior
## Test Plan
- Added new e2e test at `test/e2e/app-dir/typescript-native-preview/`
- The test verifies:
- Detection message is shown
- `typescript` is not auto-installed
- The app still works (SWC/Turbopack handles compilation)
With Cache Components enabled in development, fetches without an
explicit cache config were incorrectly routed through
`createCachedPrerenderResponse` during the cache filling phase due to
the `serverComponentsHmrCache` condition. This function awaits the
entire response before returning to the caller, which prevents
infinitely streaming responses from ever being read or aborted.
This is a regression that was introduced in #84088.
These fetches should be treated as dynamic and use
`createCachedDynamicResponse` instead, which returns immediately and
caches in the background with proper error handling. The fix adds
`isCacheableRevalidate` to the condition so only explicitly cacheable
fetches use the blocking path.
Additionally, the "Failed to set fetch cache" warning is now suppressed
when the request's abort signal was triggered, since aborting is
intentional.
## What?
Fixes a bug where `react-loadable-manifest.json` in Turbopack dev mode
contained references to chunk files with wrong hashes, causing 404
errors when loading dynamic imports.
## Why?
When using `next/dynamic` with nested imports (e.g., a dynamic component
that itself imports other modules), the chunk files referenced in
`react-loadable-manifest.json` had different hashes than the actual
generated chunk files.
The root cause was that `collect_next_dynamic_chunks` was
**recomputing** chunk content that was already computed by
`make_chunk_group`. This pattern was inherently brittle because Next.js
code had to carefully mirror Turbopack's internal chunking logic to get
consistent hashes.
This brittleness was exposed when the
`turbopackClientSideNestedAsyncChunking` feature was disabled in dev
mode (released in 16.1). The subtle differences in how availability info
was computed led to hash mismatches.
## How?
Instead of recomputing chunks for next/dynamic imports, this PR
preserves the module→async loader mapping from when chunks are first
computed in `make_chunk_group`, and looks up pre-computed chunks
directly. This eliminates the need for Next.js to replicate Turbopack's
chunking logic.
### Key changes:
1. **Extended `MakeChunkGroupResult` and `ChunkGroupResult`** with
`async_loaders_by_module` field
- Maps `ResolvedVc<Box<dyn ChunkableModule>>` → `ResolvedVc<Box<dyn
ChunkItem>>`
- Preserves the module→loader relationship computed during chunking
2. **Eliminated redundancy** in `MakeChunkGroupResult`
- Removed the separate `references` field (was just upcasted async
loaders)
- Added `references()` method that derives references on-demand from the
map
3. **Simplified `collect_next_dynamic_chunks`**
- Now performs simple lookup instead of recomputation
- Removed `module_graph` and `chunking_context` parameters
- Uses `NextDynamicChunkAvailability` enum to access pre-computed chunk
groups
4. **Added regression test** to verify chunk files referenced in
manifest exist
### Files modified:
- `turbopack/crates/turbopack-core/src/chunk/chunk_group.rs` - Add
mapping, remove redundant field
- `turbopack/crates/turbopack-core/src/chunk/chunking_context.rs` -
Extend ChunkGroupResult
- `turbopack/crates/turbopack-browser/src/chunking_context.rs` - Pass
through mapping
- `turbopack/crates/turbopack-nodejs/src/chunking_context.rs` - Pass
through mapping
- `crates/next-api/src/dynamic_imports.rs` - Lookup instead of recompute
- `crates/next-api/src/pages.rs` - Updated caller
- `crates/next-api/src/app.rs` - Updated caller
- `crates/next-core/src/next_app/app_client_references_chunks.rs` -
Initialize empty map
Fixes#87680
<!-- 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 #
-->
### What?
Add `useEffectEvent` to the list of invalid React APIs in Server
Components.
### Why?
Using `useEffectEvent` in a Server Component results in a **runtime
error**: TypeError: (0 , react_1.useEffectEvent) is not a function.
Without this fix, developers only discover the mistake at runtime. This
change improves the **Developer Experience (DX) by catching the error
immediately in the IDE.**
#### Expected Behavior
<img width="999" height="566" alt="image"
src="https://github.com/user-attachments/assets/79c1cbf9-ae0e-4ad7-b163-f650fb289a3a"
/>
#### Currently
<img width="1708" height="805" alt="image"
src="https://github.com/user-attachments/assets/a33f73e5-24fd-4405-826a-53f1810154a7"
/>
<img width="2091" height="812" alt="image"
src="https://github.com/user-attachments/assets/ed3f191e-a34d-42dd-8779-1d524f6f035d"
/>
### How?
- Added `useEffectEvent` to Rust RSC transform
(`react_server_components.rs`)
- Added `useEffectEvent` to TypeScript constants (`constant.ts`)
- Added `useEffectEvent` to error formatting (`format-server-error.ts`)
- Added test fixture and updated test file
## Note
This is a reapply of the previous
[PR](https://github.com/vercel/next.js/pull/88950).
With help from @timneutkens, I all previously worked code to ensure
nothing was missed before resubmitting.
Co-authored-by: Tim Neutkens <tim@timneutkens.nl>
## Move "Ready in X" log before config loading and eliminate duplicate
`loadConfig` calls
### What?
Reorder the dev server startup flow so the "Ready in X" log appears
before loading the user's `next.config.js`, and eliminate duplicate
`loadConfig` calls in both dev and build paths.
### Why?
Previously, the "Ready in X" time included the time spent loading and
evaluating the user's `next.config.js` file. This made the framework
appear slower than it actually is, especially for projects with complex
config files or slow config evaluation.
Additionally, config was being loaded twice:
- **Dev server**: Once in `getStartServerInfo()` just for logging, then
again in `getRequestHandlers()`
- **Build**: Once for the main build, then again in
`getStartServerInfo()` just for logging
### How?
**Before:**
```
1. getStartServerInfo() → loadConfig #1 (slow - blocks on next.config.js)
2. logStartInfo() → logs version, URLs, experimental features
3. "Ready in X" ← time includes config loading
4. getRequestHandlers() → loadConfig #2
```
**After:**
```
1. logStartInfo() → logs version, URLs, envInfo (no config needed)
2. "Ready in X" ← reflects actual framework startup time
3. getRequestHandlers() → loadConfig (once)
4. logExperimentalInfo() → logs experimental features
```
**Changes:**
- Split `logStartInfo` into two functions:
- `logStartInfo()` - basic info (version, URLs, env) - no config needed
- `logExperimentalInfo()` - experimental features and cacheComponents
- Removed `getStartServerInfo()` which was loading config unnecessarily
- Added `experimentalFeatures` and `cacheComponents` to
`ServerInitResult` so they can be passed back after config loads
- In build, added `reportExperimentalFeatures` callback to the existing
`loadConfig` call instead of loading config twice
---------
Co-authored-by: Vercel <vercel[bot]@users.noreply.github.com>
## What?
Adds `experimental.devCacheControlNoCache` to test `no-cache` vs
`no-store` for development.
Note: This is for testing only right now. If it's an improvement we'll
change the default.
`url.parse` is deprecated in favor of WHATWG URLs.
Almost all tests don't actually test integration with `url.parse`.
The remaining places test integration with the Next.js request handler
which does accept `url.parse` values.
We may deprecate that specific signature in favor of accepting WHATWG
URLs instead.
Rspack now enables persistent caching by default.
## Performance Comparison
### Pages Router
I benchmarked performance using this repo:
https://github.com/SyMind/chakra-ui-docs/tree/next-rspack to test the
Next.js pages router.
I tested the performance with the following steps:
1. Execute `pnpm run dev`
2. Wait for the server to be ready (indicated by the 'Ready' message)
3. Run curl on the root endpoint (/)
Each build was run 5 times, and the shortest time to reach "Compiled
successfully" was recorded.
Test environment: Apple M1 Pro CPU
| Tool | Build without cache | Build with cache | Dev without cache |
Dev with cache |
|-------------|---------------------|------------------|---------------------------------|----------------|
| Rspack | 3.8s | 2.6s | 1.7s | 3ms |
| Webpack | 14.0s | 4.0s | 7.8s | 3.2s |
### App Router
I benchmarked performance using this repo:
https://github.com/SyMind/shadcn-ui/tree/next-rspack to test the Next.js
app router.
I tested the performance with the following steps:
1. Execute `pnpm run dev` or `pnpm run build`
2. Wait for the server to be ready (indicated by the 'Ready' message)
3. Run curl on the root endpoint (/)
Each build was run 5 times, and the shortest time to reach "Compiled
successfully" was recorded.
Test environment: Apple M1 Pro CPU
| Bundler | Build (No Cache) | Build (Cache) | Dev (No Cache) | Dev
(Cache) |
|------------|----------------------|-------------------|--------------------|-----------------|
| Rspack | 12.3s | 5.9s | 7.1s | 1941ms |
| Webpack | 27.0s | 13.0s | 11s | 9.6s |
## About Rspack Persistent Cache Strategy
> packages/next/src/server/dev/hot-reloader-rspack.ts
Rspack's persistent caching differs from Webpack in how it manages
module graphs. While Webpack incrementally updates modules, Rspack
operates on complete module graph snapshots for cache restoration.
Problem:
- Next.js dev server starts with no page modules in the initial entry
points
- When Rspack restores from persistent cache, it finds no modules and
purges the entire module graph
- Later page requests find no cached module information, preventing
cache reuse
Solution:
- Track successfully built page entries after each compilation
- Restore these entries on dev server restart to maintain module graph
continuity
- This ensures previously compiled pages can leverage persistent cache
for faster builds
## Note
I have updated the test case configuration in
`test/integration/telemetry/next.config.use-cache` to disable persistent
cache.
This is because, whether using webpack or Rspack, when persistent
caching is enabled, modules are no longer recompiled by loaders, which
prevents the Telemetry plugin from collecting information.
Please note that this issue also exists with webpack. You can reproduce
it locally by running `pnpm run test
test/integration/telemetry/test/config.test.js` twice.
update @next/rspack-core version to 1.0.2 and update the snapshot
other changes:
- packages/next/src/build/webpack-config.ts
Adjusted configuration to account for differences in default node config
between Rspack and Webpack.
- packages/next/src/shared/lib/format-webpack-messages.ts
Added a fallback to moduleIdentifier in cases where Rspack does not
correctly populate moduleName.
> This place is not a place of honor... no highly esteemed deed is
commemorated here... nothing valued is here.
> What is here was dangerous and repulsive to us. This message is a
warning about danger.
you think you know when setImmediate is supposed to run? no you don't
---
This PR introduces a patch to the Node `setImmediate` builtin. The patch
is enabled by calling
`DANGEROUSLY_runPendingImmediatesAfterCurrentTask()`. All immediates
scheduled after that point (until the end of the task) will be captured
and executed right after that task (after `process.nextTick` and
`microtasks`). This applies to immediates scheduled from immediates as
well.
This is relevant when scheduling back-to-back timeouts for staged
rendering in Cache Components:
```ts
setTimeout(() => {
// runs first
DANGEROUSLY_runPendingImmediatesAfterCurrentTask() // enable the patch
setImmediate(() => {
// runs second (normally, it'd run last!)
})
})
setTimeout(() => {
// runs third
})
```
the immediate scheduled from inside the first timeout will **always**
run before the second timeout.
A side-effect of this is that `setImmediate` will no longer be
considered IO in the Cache Components rendering model, because
immediates will always run before we advance the stage (or abort a
prerender), and thus can't result in a dynamic hole. This brings the
runtime behavior in line with React Devtools, which does not show
`setImmediate` as IO.
This patch also has some observable differences in behavior from native
`setImmediate`, mostly to do with uncaught errors:
1. sync errors in `process.nextTick` no longer interrupt
`processTicksAndRejections` (which would make us move onto the next
event loop step, and run the rest of the nextTick queue after the next
task, breaking our scheduling). They're rethrown in a microtask, which
changes the timing of `uncaughtException` a bit.
2. unhandled rejections will trigger `unhandledRejection` after _all_
fast immediates are done executing, not after each immediate. This
happens because our userspace immediate scheduling relies on nextTick,
and [rejections are only processed after everything else in
`processTicksAndRejections` is
done](https://github.com/nodejs/node/blob/d546e7fd0bc3cbb4bcc2baae6f3aa44d2e81a413/lib/internal/process/task_queues.js#L104-L105).
We hope that these divergences in behavior are niche enough to not
affect any real world code. Both are potentially fixable by managing our
own nextTick queue, more, but we'll try to avoid that complexity for
now.
Fixes#86662
The bug was introduced in #85747, where we added
`RenderStage.Abandoned`. We forgot to update the logic that rejects
promises on abort, so if a render was abandoned (i.e. restarted due to a
cache miss), then promises waiting for the dynamic stage would hang
forever.
This is not generally observable unless the promise is persisted/cached
in userspace. Userspace caches are problematic in Cache Components and
we discourage their usage, but the test app included here should still
work as expected (i.e. without hanging forever while rendering).
When running `next dev`, then stopping it, deleting a route, and running
`next build`, the build would fail with a type error like:
```
.next/dev/types/validator.ts:78:39
Type error: Cannot find module '../../../app/simple-test/page.js'
```
The root cause here is a fundamental tension: we have **one
tsconfig.json** that needs to serve **two different modes**. When
`isolatedDevBuild` is enabled (which is the default), Next.js outputs
types to different directories:
- Development: `.next/dev/types/`
- Production: `.next/types/`
To avoid tsconfig.json changing every time you switch between dev and
build (which causes git noise and forces IDE reloads), we proactively
include both paths:
```json
{
"include": [
".next/types/**/*.ts",
".next/dev/types/**/*.ts"
]
}
```
The problem is that TypeScript checks ALL files matching these patterns.
If `.next/dev/types/validator.ts` exists from a previous dev session and
contains imports to routes that have since been deleted, TypeScript
fails during build because those imports point to non-existent files.
You might ask: why not just completely separate them with two tsconfigs?
The issue is that would require users to know which tsconfig to use for
their IDE, and switching between configs manually defeats the purpose of
a seamless dev/build experience. The single tsconfig approach is
intentional.
The fix filters out `.next/dev/types` files programmatically when
running type check during build, without touching tsconfig.json:
```typescript
let fileNames = effectiveConfiguration.fileNames
if (excludeDevTypes) {
const devTypesPattern = /[/\\]\.next[/\\]dev[/\\]types[/\\]/
fileNames = fileNames.filter((fileName) => !devTypesPattern.test(fileName))
}
```
This way the tsconfig stays unchanged (no git churn, IDE stays happy),
dev types are preserved for concurrent dev sessions, and build only
type-checks its own `.next/types` directory.
By sending the dynamic validation errors to the browser via WebSocket,
instead of rendering a validation outlet into the dynamic dev render
stream, we can avoid artificially delaying the spawned validation to
implicitly wait for the different chunks (static, runtime, and dynamic),
without blocking the dev render stream, and instead wait explicitly for
all chunks to accumulate.
Previously, we were using React's console replaying to get full fidelity
error stacks in the browser (including inspectable virtual server
modules). Now, we're using the same underlying mechanism by sending a
separate RSC stream through the WebSocket that contains only the errors.
In the browser, the received errors are then logged with
`console.error`, which also triggers that they're displayed in a
collapsed Redbox, as was the case before with the replaying.
---------
Co-authored-by: Janka Uryga <lolzatu2@gmail.com>
Prior to this change any "hole" in a prerender that would block the
shell was considered an error and you would be presented with a very
generic message explaining all the different ways you could have failed
this validation check.
With this change we use a new technique to validate the static shell
which can now tell the difference between waiting on uncached data or
runtime data. It also improves the heuristics around generateMetadata
and generateViewport errors.
Added new error pages for runtime sync IO and ensure we only validate
sync IO after runtime data if the page will be validating runtime
prefetches.
Restored the validation on HMR update so you can get feedback after
saving a new file.
---
We've also discovered that hanging inputs are not handled correctly.
Fixing this is non-trivial and will be done in a follow-up, so for now,
we're disabling the failing tests.
---------
Co-authored-by: Josh Story <story@hey.com>
Co-authored-by: Hendrik Liebau <mail@hendrik-liebau.de>
When configuring `cacheMaxMemorySize` to disable memory caching
(typically used for setups to adjust production caching behavior,
especially in multi-process self-hosted setups), this inadvertently also
disabled dev HMR caches which are intended as a performance
optimization. As a result of this, the dev console would be spammed with
"Single item size exceeds maxsize".
It's still possible to use this configuration to set a larger cache, but
otherwise it will have a minimum set to the previous default.
Fixes NAR-463
x-ref:
https://github.com/vercel/next.js/pull/85153#issuecomment-3429636751