From 591ec958c9488d927ec1b07587170dc44d5e1264 Mon Sep 17 00:00:00 2001 From: Nathan Walker Date: Thu, 28 Aug 2025 12:37:02 -0700 Subject: [PATCH] feat(webpack): consider prereleases in runtime detection for commonjs auto-fallback --- packages/webpack5/src/configuration/base.ts | 7 +-- packages/webpack5/src/helpers/dependencies.ts | 54 +++++++++++++++---- 2 files changed, 49 insertions(+), 12 deletions(-) diff --git a/packages/webpack5/src/configuration/base.ts b/packages/webpack5/src/configuration/base.ts index 273f0c2bc..72e25bb79 100644 --- a/packages/webpack5/src/configuration/base.ts +++ b/packages/webpack5/src/configuration/base.ts @@ -2,6 +2,7 @@ import { extname, relative, resolve } from 'path'; import { ContextExclusionPlugin, HotModuleReplacementPlugin } from 'webpack'; import Config from 'webpack-chain'; import { satisfies } from 'semver'; +import { isVersionGteConsideringPrerelease } from '../helpers/dependencies'; import { existsSync } from 'fs'; import ForkTsCheckerWebpackPlugin from 'fork-ts-checker-webpack-plugin'; @@ -64,7 +65,7 @@ export default function (config: Config, env: IWebpackEnv = _env): Config { getResolvedDependencyVersionForCheck('@nativescript/ios', '9.0.0') ?? iosVersion ?? undefined; - if (iosResolved && satisfies(iosResolved, '>=9.0.0')) { + if (isVersionGteConsideringPrerelease(iosResolved, '9.0.0')) { useSourceMapFiles(); } else { env.commonjs = true; @@ -77,7 +78,7 @@ export default function (config: Config, env: IWebpackEnv = _env): Config { ) ?? visionosVersion ?? undefined; - if (visionosResolved && satisfies(visionosResolved, '>=9.0.0')) { + if (isVersionGteConsideringPrerelease(visionosResolved, '9.0.0')) { useSourceMapFiles(); } else { env.commonjs = true; @@ -90,7 +91,7 @@ export default function (config: Config, env: IWebpackEnv = _env): Config { ) ?? androidVersion ?? undefined; - if (androidResolved && satisfies(androidResolved, '>=9.0.0')) { + if (isVersionGteConsideringPrerelease(androidResolved, '9.0.0')) { useSourceMapFiles(); } else { env.commonjs = true; diff --git a/packages/webpack5/src/helpers/dependencies.ts b/packages/webpack5/src/helpers/dependencies.ts index 585c064bc..c6cd74487 100644 --- a/packages/webpack5/src/helpers/dependencies.ts +++ b/packages/webpack5/src/helpers/dependencies.ts @@ -76,7 +76,10 @@ export function getDependencyVersion(dependencyName: string): string | null { * - fall back to declared version in project package.json (dependencies/devDependencies) * - if declared is a common dist-tag (alpha|beta|rc|next) return a 9.x prerelease */ -export function getResolvedDependencyVersionForCheck(dependencyName: string, target: string): string | null { +export function getResolvedDependencyVersionForCheck( + dependencyName: string, + target: string, +): string | null { // try installed const installed = getDependencyVersion(dependencyName); if (installed) { @@ -85,19 +88,17 @@ export function getResolvedDependencyVersionForCheck(dependencyName: string, tar // try declared in project package.json const pkg = getPackageJson(); - const declared = (pkg.dependencies && pkg.dependencies[dependencyName]) || (pkg.devDependencies && pkg.devDependencies[dependencyName]); + const declared = + (pkg.dependencies && pkg.dependencies[dependencyName]) || + (pkg.devDependencies && pkg.devDependencies[dependencyName]); if (!declared) { return null; } // if declared already satisfies semver check, use it - try { - if (satisfies(declared, `>=${target}`)) { - return declared; - } - } catch (e) { - // ignore parse errors - } + // Note: declared may be a dist-tag like 'alpha' or a range. We only treat + // common tags as prereleases of target. Avoid trying to interpret arbitrary + // ranges here. // common dist-tags -> treat as prerelease of 9.x for the purpose of >=9 checks if (/^(alpha|beta|rc|next)$/.test(String(declared))) { @@ -106,3 +107,38 @@ export function getResolvedDependencyVersionForCheck(dependencyName: string, tar return declared ?? null; } + +/** + * Numeric comparison that treats prerelease versions as being at the same + * numeric level as their base version. e.g. 9.0.0-alpha.2 >= 9.0.0 + */ +export function isVersionGteConsideringPrerelease( + version: string | null | undefined, + target: string, +): boolean { + if (!version) { + return false; + } + + try { + const v = require('semver').parse(String(version)); + const t = require('semver').parse(String(target)); + if (!v || !t) { + // fallback to semver.satisfies with a prerelease-aware lower bound + return require('semver').satisfies(String(version), `>=${target}-0`); + } + + if (v.major > t.major) return true; + if (v.major < t.major) return false; + if (v.minor > t.minor) return true; + if (v.minor < t.minor) return false; + if (v.patch >= t.patch) return true; + return false; + } catch (e) { + try { + return require('semver').satisfies(String(version), `>=${target}-0`); + } catch (e) { + return false; + } + } +}