feat: use Node.js native TS resolver for `next.config.ts` (#83240)
### Why?
Since `next.config.ts` was resolved via require-hook, it had a
restriction with Native ESM syntax, like top-level await, dynamic
import, and Node.js ESM APIs like `import.meta.url`. There were previous
attempts to resolve this via the ESM loader, but those approaches
(https://github.com/vercel/next.js/pull/68365,
https://github.com/vercel/next.js/pull/83120) ended up adding ~39ms
compared to the require-hook due to the loader registration time.
However, Node.js natively supports TS since v22.7.0 under the
experimental flag, and was enabled by default since v23.6.0. Therefore,
this PR feature detects the Node.js version and uses its feature to
resolve `next.config.ts` and allows native ESM syntax.
As a comparison, the usage of ESM loader vs Native TS on a "Large App":
- Duration: ~65% faster (186 ms → 66 ms)
- RSS: ~41% lower (80 MB → 47 MB)
- Heap: ~78% lower (18 MB → 4 MB)
<details><summary>Benchmark Details</summary>
<p>
| Type | Transpile Duration (ms) | Resident Set Size (MB) | Heap Used
(MB) |
|---------|--------------------------|------------------------|----------------|
| ESM | 186.04 | 79.94 | 17.68 |
| Native | 66.09 | 47.32 | 3.81 |
| **Δ (Abs)** | -119.95 | -32.62 | -13.87 |
| **Δ (%)** | -64.5% | -40.8% | -78.4% |
</p>
</details>
### How?
Used Node.js Native TS support (since v22.7.0). Feature detected with
`process.features.typescript` (since v22.10.0), and fallback to the
legacy resolution for the current session if it throws. This feature
follows the restriction of the Native TS support. The notable
restrictions are:
- Requires extensions for file imports
- Doesn't read tsconfig.json (no import alias)
- Requires `with { type: 'json' }` when importing JSON
For details, see [Node.js Type
stripping](https://nodejs.org/api/typescript.html#type-stripping).
See the changes below to get the idea of what is restricted or newly
allowed.
- Changes to fixtures due to restrictions:
https://github.com/vercel/next.js/pull/83240/commits/de1bec89f1976aa6f0cba03aa38cae4c1977abec
- Additions to fixtures due to ESM support:
https://github.com/vercel/next.js/pull/83240/commits/622a2a828693422aa511793af56734f40569d9f5
Added `next-config-ts-native-ts` tests on CI to run on Node.js v22 and
v24.
## Benchmark
#### Hello World App
- Duration: ~68% faster (102 ms → 32 ms)
- RSS: ~65% lower (72 MB → 25 MB)
- Heap: ~87% lower (31 MB → 4 MB)
<details><summary>Benchmark Details</summary>
<p>
| Attempt | Transpile Duration (ms) | Resident Set Size (MB) | Heap Used
(MB) |
|-----------|--------------------------|------------------------|----------------|
| CJS 1 | 104.03 | 69.16 | 30.32 |
| CJS 2 | 100.35 | 59.95 | 30.14 |
| CJS 3 | 100.77 | 75.83 | 32.18 |
| CJS 4 | 103.43 | 77.33 | 30.13 |
| CJS 5 | 100.82 | 76.30 | 30.22 |
| Native 1 | 33.75 | 25.19 | 3.84 |
| Native 2 | 28.71 | 21.72 | 3.85 |
| Native 3 | 33.49 | 28.95 | 3.85 |
| Native 4 | 32.78 | 24.97 | 3.85 |
| Native 5 | 33.43 | 24.89 | 3.85 |
| **CJS Avg** | 101.88 | 71.71 | 30.60 |
| **Native Avg**| 32.43 | 25.14 | 3.85 |
| **Δ (Abs)** | -69.45 | -46.57 | -26.75 |
| **Δ (%)** | -68.2% | -64.9% | -87.4% |
</p>
</details>
#### Large App
> Benchmarked from a large repository that imports packages like
`@next/bundle-analyzer`.
- Duration: ~56% faster (152 ms → 66 ms)
- RSS: ~30% lower (68 MB → 47 MB)
- Heap: ~78% lower (17 MB → 4 MB)
<details><summary>Benchmark Details</summary>
<p>
| Attempt | Transpile Duration (ms) | Resident Set Size (MB) | Heap Used
(MB) |
|-----------|--------------------------|------------------------|----------------|
| CJS 1 | 154.35 | 67.73 | 17.16 |
| CJS 2 | 148.02 | 61.33 | 17.32 |
| CJS 3 | 152.44 | 66.06 | 17.14 |
| CJS 4 | 149.89 | 74.33 | 17.17 |
| CJS 5 | 156.27 | 68.20 | 17.25 |
| Native 1 | 68.01 | 34.66 | 5.51 |
| Native 2 | 66.41 | 53.83 | 5.48 |
| Native 3 | 62.39 | 45.80 | 1.48 |
| Native 4 | 65.20 | 52.02 | 1.35 |
| Native 5 | 68.44 | 50.31 | 5.25 |
| **CJS Avg** | 152.19 | 67.53 | 17.21 |
| **Native Avg**| 66.09 | 47.32 | 3.81 |
| **Δ (Abs)** | -86.10 | -20.21 | -13.39 |
| **Δ (%)** | -56.6% | -29.9% | -77.8% |
</p>
</details>
Fixes https://github.com/vercel/next.js/issues/67765
Fixes https://github.com/vercel/next.js/issues/71705
Closes [NDX-494](https://linear.app/vercel/issue/NDX-494)
---------
Co-authored-by: vercel[bot] <35613825+vercel[bot]@users.noreply.github.com>
Co-authored-by: graphite-app[bot] <96075541+graphite-app[bot]@users.noreply.github.com>
Co-authored-by: Sebastian "Sebbie" Silbermann <silbermann.sebastian@gmail.com>