From f5cc40d7a9f367d761c60ec5db6e5480fedddd56 Mon Sep 17 00:00:00 2001 From: Harlan Wilton Date: Thu, 14 May 2026 14:58:57 +1000 Subject: [PATCH 1/2] fix(plausible): honor scriptInput.src in bundle.resolve for self-hosted MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The build-time bundle transformer calls `bundle.resolve()` with the merged registry config to determine which URL to download. For Plausible, the resolver only inspected `scriptId`/`extension` and always returned `plausible.io`, so self-hosted users hit fetch failures (e.g. `https://plausible.io/js/pa-.js` → 404) at build time and runtime overrides were never reached. Honor `options.scriptInput?.src` first so self-hosted Plausible bundles from the user-configured origin. Fixes #768 --- packages/script/src/registry.ts | 5 +++ test/unit/plausible-bundle-resolve.test.ts | 40 ++++++++++++++++++++++ 2 files changed, 45 insertions(+) create mode 100644 test/unit/plausible-bundle-resolve.test.ts diff --git a/packages/script/src/registry.ts b/packages/script/src/registry.ts index fc9b22c9..4b33a3e1 100644 --- a/packages/script/src/registry.ts +++ b/packages/script/src/registry.ts @@ -301,6 +301,11 @@ export async function registry(resolve?: (path: string) => Promise): Pro envDefaults: { domain: '' }, bundle: { resolve: (options?: PlausibleAnalyticsInput) => { + // Self-hosted Plausible: when a custom `scriptInput.src` is provided, + // bundle from that origin instead of the default plausible.io CDN. + const userSrc = (options as any)?.scriptInput?.src + if (typeof userSrc === 'string' && userSrc.length > 0) + return userSrc if (options?.scriptId) return `https://plausible.io/js/pa-${options.scriptId}.js` const extensions = Array.isArray(options?.extension) ? options.extension.join('.') : [options?.extension] diff --git a/test/unit/plausible-bundle-resolve.test.ts b/test/unit/plausible-bundle-resolve.test.ts new file mode 100644 index 00000000..4279f09d --- /dev/null +++ b/test/unit/plausible-bundle-resolve.test.ts @@ -0,0 +1,40 @@ +import { describe, expect, it } from 'vitest' +import { getBundleResolve, registry } from '../../packages/script/src/registry' + +async function getPlausibleResolve() { + const all = await registry() + const script = all.find(s => s.registryKey === 'plausibleAnalytics')! + const resolve = getBundleResolve(script) + if (!resolve) + throw new Error('plausibleAnalytics bundle.resolve missing') + return resolve +} + +describe('plausibleAnalytics bundle.resolve', () => { + it('returns default plausible.io URL with scriptId', async () => { + const resolve = await getPlausibleResolve() + expect(resolve({ scriptId: 'abc123' } as any)).toBe('https://plausible.io/js/pa-abc123.js') + }) + + it('returns default plausible.io URL with legacy extension', async () => { + const resolve = await getPlausibleResolve() + expect(resolve({ extension: 'hash' } as any)).toBe('https://plausible.io/js/script.hash.js') + }) + + it('returns default basic plausible.io URL with no options', async () => { + const resolve = await getPlausibleResolve() + expect(resolve(undefined)).toBe('https://plausible.io/js/script.js') + }) + + it('honors user-supplied scriptInput.src for self-hosted Plausible', async () => { + // Regression test for https://github.com/nuxt/scripts/issues/768 + const resolve = await getPlausibleResolve() + const selfHosted = 'https://my-self-hosted-plausible.io/js/script.js' + expect( + resolve({ scriptId: 'abc123', scriptInput: { src: selfHosted } } as any), + ).toBe(selfHosted) + expect( + resolve({ scriptInput: { src: selfHosted } } as any), + ).toBe(selfHosted) + }) +}) From 12ba38868408b94a2f825bd9ebf8167103c34ea5 Mon Sep 17 00:00:00 2001 From: Harlan Wilton Date: Thu, 14 May 2026 15:03:46 +1000 Subject: [PATCH 2/2] fix(plausible): trim whitespace-only scriptInput.src --- packages/script/src/registry.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/script/src/registry.ts b/packages/script/src/registry.ts index 4b33a3e1..ddb75384 100644 --- a/packages/script/src/registry.ts +++ b/packages/script/src/registry.ts @@ -304,8 +304,8 @@ export async function registry(resolve?: (path: string) => Promise): Pro // Self-hosted Plausible: when a custom `scriptInput.src` is provided, // bundle from that origin instead of the default plausible.io CDN. const userSrc = (options as any)?.scriptInput?.src - if (typeof userSrc === 'string' && userSrc.length > 0) - return userSrc + if (typeof userSrc === 'string' && userSrc.trim().length > 0) + return userSrc.trim() if (options?.scriptId) return `https://plausible.io/js/pa-${options.scriptId}.js` const extensions = Array.isArray(options?.extension) ? options.extension.join('.') : [options?.extension]