- rename `unstable_after` -> `after`
- remove `experimental.after` flag (and warn if it's present)
i separated the big find-and-replace into a separate commit so that it's
easier to see what else changed apart from that.
does not touch docs, that's in #73038
> [!NOTE]
> The "Test new tests for flakes" may fail due to the number of tests in
a single `hmr.test.ts` file.
> The follow-up stacks are to resolve the issue.
### Why?
The test util `check` is deprecated internally, recommended to replace
to `retry`.
`after` was too restrictive with `draftMode` -- we generally allow reading `draftMode().isEnabled` anywhere. this is because it isn't really a dynamic API -- it's fine to call it in prerender/'use cache' contexts, because we can just prerender/cache it as `isEnabled = false`, and when it's on, it switches everything to dynamic rendering anyway, so that prerender/cache entry is ignored.
However we disallow `draftMode().enable()/disable()` in `after`, because those methods set a cookie, and `after` executes too late for that.
*(Nothing here will change in the upcoming `after` behavior update -- we fundamentally can't get more permissive than this)*
As discussed we are removing the deprecated field from `revalidateTag`
and `revalidatePath` as they aren't going away anytime soon and the new
`expire` APIs will have slightly different semantics so not a 1-1 rename
with no arguments change anymore. We are also adding the `unstable_`
prefix for `expireTag`/`expirePath` while we iterate on them so it's
clear they will change.
---------
Co-authored-by: Zack Tanner <1939140+ztanner@users.noreply.github.com>
# Context
[Test
run](https://github.com/vercel/next.js/actions/runs/11962411287/job/33382985253?pr=73030#step:29:421)
fails due to
```
▲ Next.js 15.0.4-canary.22
- Local: http://[::1]:35903
- Network: http://[::]:35903
✓ Starting...
Error: "next start" does not work with "output: export" configuration. Use "npx serve@latest out" instead.
at <unknown> (dist/server/next.js:215:31)
at async NextServer.prepare (dist/server/next.js:154:24)
at async initializeImpl (dist/server/lib/render-server.js:92:5)
at async initialize (dist/server/lib/router-server.js:436:22)
at async Server.<anonymous> (dist/server/lib/start-server.js:272:36)
```
However, there was no `output: export` specified in the [test
setup](https://github.com/vercel/next.js/tree/jude/which-config-are-we-using/test/integration/edge-runtime-configurable-guards).
**Mysterious!**
# Hypothesis
`next start` recursively finds the `next.config` upwards in the
directory tree and happens to locate an extraneous `next.config` that
specified `output: export`.
# Changes
- Output the config file path in test mode for future debugging
- Short-circuit `findUp` for the broken test by placing an empty config
in the project directory
- The waitFor function now supports a predicate. Unlike retry, waitFor
does not include a timeout. Use it only when the predicate is guaranteed
to evaluate to true before proceeding to the next test. If it runs
indefinitely, Jest enforces a 120-second timeout per test.
- The getCliOutputFromHere utility provides a convenient string getter
that captures CLI output in between.
### Why?
This PR added an indication of where the env was loaded from when
`experimental.typedEnv` was enabled. Also, it allows the user to set
`NODE_ENV=production` to enable the `typedEnv` feature for
`.env.production*` files.

### How?
Modified `@next/env` to pass parsed envs along with the `loadedEnvFiles`
value and used the location to indicate via JSDoc.
In the Segment Cache implementation of prefetching, during a navigation,
it's possible that the prefetch for a segment may already be
in-progress, but we haven't received its data yet. In that case, since
the prefetch is very likely to load faster than the dynamic request, we
might as well use the result, if we can.
This updates type CacheNode.loading to accept a promise for the loading
module data, and updates the LayoutRouter to conditionally unwrap it if
needed. We already use this same strategy in other places, like for
streaming in the main segment data.
We now look through each section for the source and
use that section to determine if a frame is ignore-listed.
Previously, stacks from Turbopack sourcemaps were
not ignore-listed since they were index maps.
Works around https://github.com/nodejs/node/issues/52102
Webpack will be harder to patch and I don't know yet where the Webpack runtime is using `vm.runInThisContext`.
Best way to observe change is in https://github.com/vercel/next.js/pull/71909 and `pnpm test-dev-turbo test/development/app-dir/dynamic-io-dev-errors/ -t "should display error when component accessed data without suspense boundary"`.
Before:
```
Error: [...]
at Page [Server] (<anonymous>)
at InnerLayoutRouter (.next/server/chunks/ssr/[root of the server]__088b8c._.js)
```
After:
```
Error: [...]
at Page [Server] (<anonymous>)
at InnerLayoutRouter (node_modules/.pnpm/file+..+next-repo-2186278d37ae48e2b1397aa86060054592669ed9909b91e96c5af049d12c04c3+packages+n_vk62popbath6ofshgazcbhzdoe/node_modules/next/dist/src/client/components/layout-router.tsx:324:2)
```
Next step is figuring out why the now sourcemapped frames aren't ignore-listed.
Migrated every instance of `sandbox` to use the `using` keyword so that
the `cleanup` will be automatically performed when the execution leaves
the scope.
Tests have been inconsistent due to flaky build-time failures caused by
AMP validation errors:
https://github.com/vercel/next.js/actions/runs/11807856104/attempts/1.
We’re updating the library version with the expectation that this will
resolve the issue.
```
info: undefined
Generating static pages (9/37)
Generating static pages (18/37)
Generating static pages (27/37)
Error occurred prerendering page "/amp-hybrid". Read more: https://nextjs.org/docs/messages/prerender-error
AssertionError: Assertion failed: WebAssembly is uninitialized
at new module$contents$goog$asserts_AssertionError (evalmachine.<anonymous>:102:1441)
at module$contents$goog$asserts_doAssertFailure (evalmachine.<anonymous>:103:354)
at goog.asserts.assertExists (evalmachine.<anonymous>:104:374)
at Object.module$contents$amp$validator_validateString [as validateString] (evalmachine.<anonymous>:2238:108)
at Validator.validateString (/tmp/next-install-89c7ccfd9a04886e2e88ccffb9ad709b236d4b8c8398fcdbb34c9c897118b9e9/node_modules/.pnpm/next@file+..+next-repo-99a8e0af0510a7a2958e71c9affe3d5d83d452a304c40ea8b352506d74651d57+packa_6sb2ai4rhstsynpbl53dxgpt7e/node_modules/next/dist/compiled/amphtml-validator/index.js:17:2057)
at validateAmp (/tmp/next-install-89c7ccfd9a04886e2e88ccffb9ad709b236d4b8c8398fcdbb34c9c897118b9e9/node_modules/.pnpm/next@file+..+next-repo-99a8e0af0510a7a2958e71c9affe3d5d83d452a304c40ea8b352506d74651d57+packa_6sb2ai4rhstsynpbl53dxgpt7e/node_modules/next/dist/export/routes/pages.js:100:34)
at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
at async exportPagesPage (/tmp/next-install-89c7ccfd9a04886e2e88ccffb9ad709b236d4b8c8398fcdbb34c9c897118b9e9/node_modules/.pnpm/next@file+..+next-repo-99a8e0af0510a7a2958e71c9affe3d5d83d452a304c40ea8b352506d74651d57+packa_6sb2ai4rhstsynpbl53dxgpt7e/node_modules/next/dist/export/routes/pages.js:134:17)
at async Span.traceAsyncFn (/tmp/next-install-89c7ccfd9a04886e2e88ccffb9ad709b236d4b8c8398fcdbb34c9c897118b9e9/node_modules/.pnpm/next@file+..+next-repo-99a8e0af0510a7a2958e71c9affe3d5d83d452a304c40ea8b352506d74651d57+packa_6sb2ai4rhstsynpbl53dxgpt7e/node_modules/next/dist/trace/trace.js:153:20)
at async exportPage (/tmp/next-install-89c7ccfd9a04886e2e88ccffb9ad709b236d4b8c8398fcdbb34c9c897118b9e9/node_modules/.pnpm/next@file+..+next-repo-99a8e0af0510a7a2958e71c9affe3d5d83d452a304c40ea8b352506d74651d57+packa_6sb2ai4rhstsynpbl53dxgpt7e/node_modules/next/dist/export/worker.js:336:18)
```
Note that this failure breaks the production integration test almost 10%
of times.

### Why?
To customize Image Optimation, the user can use a custom loader, but
that information was out from the related lint error message.
Closes NDX-181
A multi-zone Next.js app might have complex rewrites for its client
assets. For these apps, resolving a source map through the
`/__nextjs_source-map` dev middleware might fail because the asset might
belong to a different app.
Instead of trying to resolve those rewrites (i.e. using `fetch` instead
of `fs`), we can just bypass the source map dev middleware for client
chunks. Because we control how those source maps are generated, we can
safely assume that the `sourceMappingURL` is relative to the filename,
with an added `.map` extension. The browser can just request this file,
and it gets served through the normal dev server, without the need to
route this through the source map dev middleware.
reverts #72258
This adds `expireTag()` and `expirePath` APIs which are replacing
`revalidateTag` and `revalidatePath`. As such this also marks
`revalidatePath` and `revalidateTag` as deprecated and marked for
removal.
The arguments passed to these methods match `revalidateTag` and
`revalidatePath` with the exception that `expireTag` can receive
multiple tags now as separate arguments which matches our new
`unstable_cacheTag()` API.
We are wanting to update these APIs as `revalidateTag` naming has caused
some confusion as to when the affected items will be updated. The
underlying behavior of `expireTag` is to mark an entry as out of date
and for it to no longer be used so we are expiring it.
If you call `expirePath('/blog/first'`) the next time that item is
requested it is considered expired so the cache will not be used for it
and a fresh entry will be generated. Similarly for `expireTag('posts',
'blog')` the next time any cache with that tag is requested it's
respective cache will not be leveraged and new cache will be populated.
---------
Co-authored-by: Zack Tanner <1939140+ztanner@users.noreply.github.com>
Co-authored-by: Delba de Oliveira <32464864+delbaoliveira@users.noreply.github.com>
We will wait the server to respond with a compile success message after
a file is patched before proceeding to the next steps in the test to
reduce flakiness.
By doing so, we uncovered a few tests that were passing accidentally due
to flakiness of `patchFile`, and fixed them in the PR.
When using Turbopack, and importing a server action into a client
component, the source map for the client chunk will be requested if
devtools are open. The filename for this source map request might be
`/_next/static/chunks/[project]__800ed2._.js`, for example. This
scenario was already handled by the dev middleware.
However, it didn't consider that there might also be an `assetPrefix`
defined in the `next.config.js`. In this case, the filename would be
`/some-asset-prefix/_next/static/chunks/[project]__800ed2._.js`. When
resolving the external source map for this file, we need to strip the
asset prefix.
Again, this can only be tested manually.
Running the tests continuously for an hour on my PC, the tests succeeded
with no failure.
```
while pnpm test-dev-turbo test/development/app-hmr/hmr.test.ts; do :; done
```
Will monitor the flakiness after this lands. Hope it reduces it below
20%.
After adding validation that fixing invalid segment configs (when DIO is
enabled), it revealed that errors weren't being displayed in Turbopack,
because `setHMRServerError` wasn't implemented.
This refactors the implementation to use the existing server component
transform when validating if the segments are valid. This has the
benefit of highlighting precisely where the segment is coming, making it
easier to remove. The test that was skipped in Turbopack is also
re-enabled.
<details>
<summary>Screenshot</summary>

</details>