From fdc90f1fed77d754c81c9dec07f314dc1d070d8c Mon Sep 17 00:00:00 2001 From: Jacky Date: Thu, 12 Nov 2026 20:10:29 +0800 Subject: [PATCH 1/2] fix: let antdv-next match every minor up to the next major The shared range for antdv-next was pinned to major.minor, so a bundle built against antdv-next 1.5 declared ~1.5. NGINX UI 3.0 ships 1.7 and 3.0.2 ships 1.8, and the host's loader refused such bundles as incompatible: the official DNS-01 plugin's challenge form never loaded on any 3.0 release (0xJacky/nginx-ui#2113). Every routine minor upgrade of the host would do the same to every plugin. antdv-next now gets the same range as vue, vue-router and pinia: >= <. Co-Authored-By: Claude Opus 5.5 --- README.md | 2 +- src/shared-range.ts | 15 ++++++++------- test/shared-range.test.ts | 6 +++--- 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index f692115..bb27138 100644 --- a/README.md +++ b/README.md @@ -172,7 +172,7 @@ export default defineNginxUiPluginConfig({ id: 'io.github.example.myplugin' }) "vue": ">=3.5.42 <4", "vue-router": ">=5.3.1 <6", "pinia": ">=4.0.3 <5", - "antdv-next": "~1.5", + "antdv-next": ">=1.5.4 <2", "@vueuse/core": ">=15.0.0" } } diff --git a/src/shared-range.ts b/src/shared-range.ts index b893190..66504d9 100644 --- a/src/shared-range.ts +++ b/src/shared-range.ts @@ -26,11 +26,13 @@ export function parseSemver(version: string): SemverTriple | null { } /** - * Range strategy per shared library, matching the ranges nginx-ui's own - * webapp/vite.config.ts declares for its dependencies (see app/package.json): - * vue, vue-router and pinia allow every minor/patch up to (not including) the - * next major; antdv-next is pinned to major.minor; @vueuse/core has no - * upper bound. + * Range strategy per shared library: vue, vue-router, pinia and antdv-next + * allow every minor/patch up to (not including) the next major; @vueuse/core + * has no upper bound. + * + * antdv-next used to be pinned to major.minor. The host upgrades its minor + * regularly, and every upgrade then refused every plugin bundle built against + * the previous one, so a bundle stopped loading until its plugin was rebuilt. */ export function rangeForLibrary(pkg: string, version: string): string { const parsed = parseSemver(version) @@ -41,9 +43,8 @@ export function rangeForLibrary(pkg: string, version: string): string { case 'vue': case 'vue-router': case 'pinia': - return `>=${version} <${parsed.major + 1}` case 'antdv-next': - return `~${parsed.major}.${parsed.minor}` + return `>=${version} <${parsed.major + 1}` case '@vueuse/core': default: return `>=${version}` diff --git a/test/shared-range.test.ts b/test/shared-range.test.ts index 49fdb0b..6885db8 100644 --- a/test/shared-range.test.ts +++ b/test/shared-range.test.ts @@ -28,8 +28,8 @@ describe('rangeForLibrary', () => { expect(rangeForLibrary('pinia', '4.0.3')).toBe('>=4.0.3 <5') }) - it('pins antdv-next to major.minor', () => { - expect(rangeForLibrary('antdv-next', '1.5.4')).toBe('~1.5') + it('caps antdv-next below the next major', () => { + expect(rangeForLibrary('antdv-next', '1.5.4')).toBe('>=1.5.4 <2') }) it('leaves @vueuse/core without an upper bound', () => { @@ -52,7 +52,7 @@ describe('buildSharedManifest', () => { expect(shared).toEqual({ 'vue': '>=3.5.42 <4', - 'antdv-next': '~1.5', + 'antdv-next': '>=1.5.4 <2', }) }) }) From 1aea657e200477cb31319cb77dc5ceea533a7b61 Mon Sep 17 00:00:00 2001 From: Jacky Date: Thu, 12 Nov 2026 20:18:29 +0800 Subject: [PATCH 2/2] fix: write the lower bound of a shared range without prerelease A library installed as a prerelease, such as antdv-next 1.9.0-beta.1, produced >=1.9.0-beta.1 <2. The host's range matcher does not accept a prerelease in a range, so the bundle was refused; the old ~1.9 range matched. The lower bound is now major.minor.patch. Co-Authored-By: Claude Opus 5.5 --- src/shared-range.ts | 12 ++++++++++-- test/shared-range.test.ts | 9 +++++++++ 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/src/shared-range.ts b/src/shared-range.ts index 66504d9..b3fe3fe 100644 --- a/src/shared-range.ts +++ b/src/shared-range.ts @@ -44,13 +44,21 @@ export function rangeForLibrary(pkg: string, version: string): string { case 'vue-router': case 'pinia': case 'antdv-next': - return `>=${version} <${parsed.major + 1}` + return `>=${floor(parsed)} <${parsed.major + 1}` case '@vueuse/core': default: - return `>=${version}` + return `>=${floor(parsed)}` } } +/** + * The lower bound of a range: major.minor.patch without prerelease or build + * metadata, which the host's range matcher does not accept. + */ +function floor({ major, minor, patch }: SemverTriple): string { + return `${major}.${minor}.${patch}` +} + /** Builds the webapp.shared map for every library that resolved to a version. */ export function buildSharedManifest(versions: Record): Record { const shared: Record = {} diff --git a/test/shared-range.test.ts b/test/shared-range.test.ts index 6885db8..1c2444e 100644 --- a/test/shared-range.test.ts +++ b/test/shared-range.test.ts @@ -36,6 +36,15 @@ describe('rangeForLibrary', () => { expect(rangeForLibrary('@vueuse/core', '15.0.0')).toBe('>=15.0.0') }) + it('drops prerelease and build metadata from the lower bound', () => { + expect(rangeForLibrary('antdv-next', '1.9.0-beta.1')).toBe('>=1.9.0 <2') + expect(rangeForLibrary('@vueuse/core', '15.1.0+build.2')).toBe('>=15.1.0') + }) + + it('fills in a missing minor and patch', () => { + expect(rangeForLibrary('vue', '3')).toBe('>=3.0.0 <4') + }) + it('passes an unparseable version through unchanged', () => { expect(rangeForLibrary('vue', 'workspace:*')).toBe('workspace:*') })