Skip to content

Commit ee44634

Browse files
authored
[build-utils] Optimize getAvailableNodeVersions to skip discontinued versions (#14686)
## Summary - Optimize `isNodeVersionAvailable` to use `statSync` with `{ throwIfNoEntry: false }` instead of try-catch pattern for better efficiency - Skip old Node versions (< 18) in `getAvailableNodeVersions` to avoid unnecessary filesystem checks for versions that don't exist in the build container - Update error message to mention "discontinued" versions for better user guidance ## Changes 1. **Non-throwing `statSync`**: Replace try-catch block with `statSync(path, { throwIfNoEntry: false })` which returns `undefined` instead of throwing when the path doesn't exist 2. **Filter old versions**: Add a filter to skip Node versions < 18 (e.g., Node 8, 10, 12, 14, 16) before checking filesystem availability, as these versions don't have directories in the build container. This reduces unnecessary `statSync` calls while preserving behavior for Node 18+ which still have directories available. 3. **Improved error message**: Change error from `"Found invalid Node.js Version"` to `"Found invalid or discontinued Node.js Version"` to give users a hint that their requested version may have been discontinued
1 parent 583c052 commit ee44634

3 files changed

Lines changed: 16 additions & 11 deletions

File tree

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@vercel/build-utils': patch
3+
---
4+
5+
Optimize `getAvailableNodeVersions` to skip discontinued versions and use non-throwing `statSync`

packages/build-utils/src/fs/node-version.ts

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -79,18 +79,18 @@ function getOptions(): NodeVersion[] {
7979
}
8080

8181
function isNodeVersionAvailable(version: NodeVersion): boolean {
82-
try {
83-
return statSync(`/node${version.major}`).isDirectory();
84-
} catch {
85-
// ENOENT, or any other error, we don't care about
86-
}
87-
return false;
82+
const stat = statSync(`/node${version.major}`, { throwIfNoEntry: false });
83+
return stat?.isDirectory() ?? false;
8884
}
8985

9086
export function getAvailableNodeVersions(): NodeVersionMajor[] {
91-
return getOptions()
92-
.filter(isNodeVersionAvailable)
93-
.map(n => n.major);
87+
return (
88+
getOptions()
89+
// Only check versions >= 18, as older versions don't have directories in the build container
90+
.filter(v => v.major >= 18)
91+
.filter(isNodeVersionAvailable)
92+
.map(n => n.major)
93+
);
9494
}
9595

9696
function getHint(isAuto = false, availableVersions?: NodeVersionMajor[]) {
@@ -149,7 +149,7 @@ export async function getSupportedNodeVersion(
149149
throw new NowBuildError({
150150
code: 'BUILD_UTILS_NODE_VERSION_INVALID',
151151
link: 'https://vercel.link/node-version',
152-
message: `Found invalid Node.js Version: "${engineRange}". ${getHint(
152+
message: `Found invalid or discontinued Node.js Version: "${engineRange}". ${getHint(
153153
isAuto,
154154
availableVersions
155155
)}`,

packages/build-utils/test/unit.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ it('should only nodejs24.x', async () => {
141141
it('should not allow nodejs18.x when not available', async () => {
142142
// Simulates AL2023 build-container
143143
await expect(getSupportedNodeVersion('18.x', true, [20])).rejects.toThrow(
144-
'Found invalid Node.js Version: "18.x". Please set Node.js Version to 20.x in your Project Settings to use Node.js 20.'
144+
'Found invalid or discontinued Node.js Version: "18.x". Please set Node.js Version to 20.x in your Project Settings to use Node.js 20.'
145145
);
146146
});
147147

0 commit comments

Comments
 (0)