From 9759e4f9571d4aee276abd182d0f12118f469034 Mon Sep 17 00:00:00 2001 From: Harlan Wilton Date: Thu, 18 Sep 2025 09:43:07 +1000 Subject: [PATCH] feat: add forceDownload option to bypass script cache MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add forceDownload option for development workflows where the latest version of scripts should always be downloaded, bypassing cache. - Add forceDownload option to NuxtUseScriptOptions type with comprehensive documentation - Update AssetBundlerTransformerOptions to include defaultForceDownload configuration - Modify downloadScript function to skip cache when forceDownload is true - Add logic to extract forceDownload option from script configuration - Pass defaultForceDownload from module configuration to transformer - Includes performance warnings about build time impact Resolves #485 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- src/module.ts | 1 + src/plugins/transform.ts | 15 ++++++++++++--- src/runtime/types.ts | 23 ++++++++++++++++------- 3 files changed, 29 insertions(+), 10 deletions(-) diff --git a/src/module.ts b/src/module.ts index 092d355a..3835e9b0 100644 --- a/src/module.ts +++ b/src/module.ts @@ -227,6 +227,7 @@ export {}` addBuildPlugin(NuxtScriptBundleTransformer({ scripts: registryScriptsWithImport, defaultBundle: config.defaultScriptOptions?.bundle, + defaultForceDownload: config.defaultScriptOptions?.forceDownload, moduleDetected(module) { if (nuxt.options.dev && module !== '@nuxt/scripts' && !moduleInstallPromises.has(module) && !hasNuxtModule(module)) moduleInstallPromises.set(module, () => installNuxtModule(module)) diff --git a/src/plugins/transform.ts b/src/plugins/transform.ts index 7bc3d4a3..d14f82cb 100644 --- a/src/plugins/transform.ts +++ b/src/plugins/transform.ts @@ -21,6 +21,7 @@ import type { RegistryScript } from '#nuxt-scripts/types' export interface AssetBundlerTransformerOptions { moduleDetected?: (module: string) => void defaultBundle?: boolean + defaultForceDownload?: boolean assetsBaseURL?: string scripts?: Required[] fallbackOnSrcOnBundleFail?: boolean @@ -56,8 +57,9 @@ async function downloadScript(opts: { src: string url: string filename?: string + forceDownload?: boolean }, renderedScript: NonNullable, fetchOptions?: FetchOptions) { - const { src, url, filename } = opts + const { src, url, filename, forceDownload } = opts if (src === url || !filename) { return } @@ -66,7 +68,7 @@ async function downloadScript(opts: { let res: Buffer | undefined = scriptContent instanceof Error ? undefined : scriptContent?.content if (!res) { // Use storage to cache the font data between builds - if (await storage.hasItem(`bundle:${filename}`)) { + if (!forceDownload && await storage.hasItem(`bundle:${filename}`)) { const res = await storage.getItemRaw(`bundle:${filename}`) renderedScript.set(url, { content: res!, @@ -254,11 +256,18 @@ export function NuxtScriptBundleTransformer(options: AssetBundlerTransformerOpti return prop.type === 'Property' && prop.key?.name === 'bundle' && prop.value.type === 'Literal' }) canBundle = bundleOption ? bundleOption.value.value : canBundle + + // check if scriptOptions contains forceDownload: true + // @ts-expect-error untyped + const forceDownloadOption = scriptOptions?.value.properties?.find((prop) => { + return prop.type === 'Property' && prop.key?.name === 'forceDownload' && prop.value.type === 'Literal' + }) + const forceDownload = forceDownloadOption ? forceDownloadOption.value.value : (options.defaultForceDownload || false) if (canBundle) { const { url: _url, filename } = normalizeScriptData(src, options.assetsBaseURL) let url = _url try { - await downloadScript({ src, url, filename }, renderedScript, options.fetchOptions) + await downloadScript({ src, url, filename, forceDownload }, renderedScript, options.fetchOptions) } catch (e) { if (options.fallbackOnSrcOnBundleFail) { diff --git a/src/runtime/types.ts b/src/runtime/types.ts index 6f45bc7d..117cc235 100644 --- a/src/runtime/types.ts +++ b/src/runtime/types.ts @@ -50,6 +50,15 @@ export type NuxtUseScriptOptions = {}> = * - `false` - Do not bundle the script. (default) */ bundle?: boolean + /** + * Force download of the script even if it exists in cache. Useful for development workflows + * where you want to ensure the latest version is always downloaded. + * - `true` - Force download, bypass cache. + * - `false` - Use cached version if available. (default) + * + * Note: This may significantly increase build time as scripts will be re-downloaded on every build. + */ + forceDownload?: boolean /** * Skip any schema validation for the script input. This is useful for loading the script stubs for development without * loading the actual script and not getting warnings. @@ -173,16 +182,16 @@ export type RegistryScriptInput< Usable extends boolean = false, CanBypassOptions extends boolean = true, > - = (InferIfSchema - & { + = (InferIfSchema + & { /** * A unique key to use for the script, this can be used to load multiple of the same script with different options. */ - key?: string - scriptInput?: ScriptInput - scriptOptions?: Omit - }) - | Partial> & ( + key?: string + scriptInput?: ScriptInput + scriptOptions?: Omit + }) + | Partial> & ( CanBypassOptions extends true ? { /** * A unique key to use for the script, this can be used to load multiple of the same script with different options.