Skip to content

Commit 864102f

Browse files
committed
fix: respect env data when bundling
Fixes #441
1 parent a27120d commit 864102f

File tree

3 files changed

+342
-27
lines changed

3 files changed

+342
-27
lines changed

src/module.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import {
77
defineNuxtModule,
88
hasNuxtModule,
99
} from '@nuxt/kit'
10+
import { defu } from 'defu'
1011
import { readPackageJSON } from 'pkg-types'
1112
import type { FetchOptions } from 'ofetch'
1213
import { setupDevToolsUI } from './devtools'
@@ -134,6 +135,18 @@ export default defineNuxtModule<ModuleOptions>({
134135
defaultScriptOptions: config.defaultScriptOptions,
135136
}
136137

138+
// Merge registry config with existing runtimeConfig.public.scripts for proper env var resolution
139+
// Both scripts.registry and runtimeConfig.public.scripts should be supported
140+
if (config.registry) {
141+
// Ensure runtimeConfig.public exists
142+
nuxt.options.runtimeConfig.public = nuxt.options.runtimeConfig.public || {}
143+
144+
nuxt.options.runtimeConfig.public.scripts = defu(
145+
nuxt.options.runtimeConfig.public.scripts || {},
146+
config.registry,
147+
)
148+
}
149+
137150
const composables = [
138151
'useScript',
139152
'useScriptEventPage',
@@ -234,6 +247,7 @@ export {}`
234247
})
235248
addBuildPlugin(NuxtScriptBundleTransformer({
236249
scripts: registryScriptsWithImport,
250+
registryConfig: nuxt.options.runtimeConfig.public.scripts as Record<string, any> | undefined,
237251
defaultBundle: config.defaultScriptOptions?.bundle,
238252
moduleDetected(module) {
239253
if (nuxt.options.dev && module !== '@nuxt/scripts' && !moduleInstallPromises.has(module) && !hasNuxtModule(module))

src/plugins/transform.ts

Lines changed: 55 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,11 @@ export interface AssetBundlerTransformerOptions {
3434
defaultBundle?: boolean | 'force'
3535
assetsBaseURL?: string
3636
scripts?: Required<RegistryScript>[]
37+
/**
38+
* Merged configuration from both scripts.registry and runtimeConfig.public.scripts
39+
* Used to provide default options to script bundling functions when no arguments are provided
40+
*/
41+
registryConfig?: Record<string, any>
3742
fallbackOnSrcOnBundleFail?: boolean
3843
fetchOptions?: FetchOptions
3944
cacheMaxAge?: number
@@ -211,28 +216,42 @@ export function NuxtScriptBundleTransformer(options: AssetBundlerTransformerOpti
211216
return
212217

213218
// integration case
219+
// Get registry key from function name (e.g., useScriptGoogleTagManager -> googleTagManager)
220+
const baseName = fnName.replace(/^useScript/, '')
221+
const registryKey = baseName.length > 0 ? baseName.charAt(0).toLowerCase() + baseName.slice(1) : ''
222+
223+
// Get registry config for this script
224+
const registryConfig = options.registryConfig?.[registryKey] || {}
225+
226+
const fnArg0 = {}
227+
214228
// extract the options as the first argument that we'll use to reconstruct the src
215229
if (node.arguments[0]?.type === 'ObjectExpression') {
216230
const optionsNode = node.arguments[0] as ObjectExpression
217-
const fnArg0 = {}
218231
// extract literal values from the object to reconstruct the options
219232
for (const prop of optionsNode.properties) {
220-
if (prop.type === 'Property' && prop.value.type === 'Literal')
233+
if (prop.type === 'Property' && prop.value.type === 'Literal' && prop.key && 'name' in prop.key)
221234
// @ts-expect-error untyped
222235
fnArg0[prop.key.name] = prop.value.value
223236
}
237+
224238
const srcProperty = node.arguments[0].properties.find(
225239
(p: any) => (p.key?.name === 'src' || p.key?.value === 'src') && p?.value.type === 'Literal' && p.type === 'Property',
226240
) as Property | undefined
227241
if ((srcProperty?.value as Literal)?.value) {
228242
scriptSrcNode = srcProperty?.value as Literal & { start: number, end: number }
229243
}
230-
else {
231-
src = registryNode.scriptBundling && registryNode.scriptBundling(fnArg0 as any as InferInput<any>)
232-
// not supported
233-
if (src === false)
234-
return
235-
}
244+
}
245+
246+
// If no src was found from function arguments, try to generate from registry config
247+
if (!scriptSrcNode) {
248+
// Merge registry config with function arguments (function args take precedence)
249+
const mergedOptions = { ...registryConfig, ...fnArg0 }
250+
251+
src = registryNode.scriptBundling && registryNode.scriptBundling(mergedOptions as InferInput<any>)
252+
// not supported
253+
if (src === false)
254+
return
236255
}
237256
}
238257

@@ -296,7 +315,7 @@ export function NuxtScriptBundleTransformer(options: AssetBundlerTransformerOpti
296315
}
297316
}
298317
// @ts-expect-error untyped
299-
const scriptOptions = node.arguments[0].properties?.find(
318+
const scriptOptions = node.arguments[0]?.properties?.find(
300319
(p: any) => (p.key?.name === 'scriptOptions'),
301320
) as Property | undefined
302321
// we need to check if scriptOptions contains bundle: true/false/'force', if it exists
@@ -335,28 +354,37 @@ export function NuxtScriptBundleTransformer(options: AssetBundlerTransformerOpti
335354
s.overwrite(scriptSrcNode.start, scriptSrcNode.end, `'${url}'`)
336355
}
337356
else {
338-
const optionsNode = node.arguments[0] as ObjectExpression
339-
// check if there's a scriptInput property
340-
const scriptInputProperty = optionsNode.properties.find(
341-
(p: any) => p.key?.name === 'scriptInput' || p.key?.value === 'scriptInput',
342-
)
343-
// see if there is a script input on it
344-
if (scriptInputProperty) {
345-
// @ts-expect-error untyped
346-
const scriptInput = scriptInputProperty.value
347-
if (scriptInput.type === 'ObjectExpression') {
348-
const srcProperty = scriptInput.properties.find(
349-
(p: any) => p.key?.name === 'src' || p.key?.value === 'src',
350-
)
351-
if (srcProperty)
352-
s.overwrite(srcProperty.value.start, srcProperty.value.end, `'${url}'`)
353-
else
354-
s.appendRight(scriptInput.end, `, src: '${url}'`)
357+
// Handle case where we need to add scriptInput
358+
if (node.arguments[0]) {
359+
// There's at least one argument
360+
const optionsNode = node.arguments[0] as ObjectExpression
361+
// check if there's a scriptInput property
362+
const scriptInputProperty = optionsNode.properties.find(
363+
(p: any) => p.key?.name === 'scriptInput' || p.key?.value === 'scriptInput',
364+
)
365+
// see if there is a script input on it
366+
if (scriptInputProperty) {
367+
// @ts-expect-error untyped
368+
const scriptInput = scriptInputProperty.value
369+
if (scriptInput.type === 'ObjectExpression') {
370+
const srcProperty = scriptInput.properties.find(
371+
(p: any) => p.key?.name === 'src' || p.key?.value === 'src',
372+
)
373+
if (srcProperty)
374+
s.overwrite(srcProperty.value.start, srcProperty.value.end, `'${url}'`)
375+
else
376+
s.appendRight(scriptInput.end, `, src: '${url}'`)
377+
}
378+
}
379+
else {
380+
// @ts-expect-error untyped
381+
s.appendRight(node.arguments[0].start + 1, ` scriptInput: { src: '${url}' }, `)
355382
}
356383
}
357384
else {
385+
// No arguments at all, need to create the first argument
358386
// @ts-expect-error untyped
359-
s.appendRight(node.arguments[0].start + 1, ` scriptInput: { src: '${url}' }, `)
387+
s.appendRight(node.callee.end, `({ scriptInput: { src: '${url}' } })`)
360388
}
361389
}
362390
}

0 commit comments

Comments
 (0)