mirror of
https://github.com/hanzoai/next.js.git
synced 2026-10-30 14:46:38 +00:00
### 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 <[email protected]>
19 lines
530 B
TypeScript
19 lines
530 B
TypeScript
import { nextTestSetup } from 'e2e-utils'
|
|
|
|
describe('next-config-ts-node-api-cjs', () => {
|
|
// TODO: Remove this once we bump minimum Node.js version to v22
|
|
if (!(process.features as any).typescript) {
|
|
it.skip('requires `process.features.typescript` to feature detect Node.js native TS', () => {})
|
|
return
|
|
}
|
|
|
|
const { next } = nextTestSetup({
|
|
files: __dirname,
|
|
})
|
|
|
|
it('should be able to use Node.js API (CJS)', async () => {
|
|
const $ = await next.render$('/')
|
|
expect($('p').text()).toBe('foo')
|
|
})
|
|
})
|