@nuxt/scripts 0.10.5 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +71 -71
- package/dist/client/200.html +10 -10
- package/dist/client/404.html +10 -10
- package/dist/client/_nuxt/{BOGJUGGn.js → BFM-Ncmx.js} +1 -1
- package/dist/client/_nuxt/{Bso10INu.js → BSA2bgdb.js} +1 -1
- package/dist/client/_nuxt/CtQNcfGE.js +1 -0
- package/dist/client/_nuxt/DuCkB5R-.js +21 -0
- package/dist/client/_nuxt/builds/latest.json +1 -1
- package/dist/client/_nuxt/builds/meta/e03354ab-f2ce-4d6b-8542-7b38262b3671.json +1 -0
- package/dist/client/_nuxt/{entry.CJckMUzn.css → entry.ipQkUTQD.css} +1 -1
- package/dist/client/_nuxt/error-404.BdjopNsg.css +1 -0
- package/dist/client/_nuxt/error-500.Bd7Z7Q7I.css +1 -0
- package/dist/client/index.html +10 -10
- package/dist/module.json +2 -2
- package/dist/module.mjs +7 -13
- package/dist/runtime/components/ScriptAriaLoadingIndicator.vue +5 -5
- package/dist/runtime/components/ScriptCarbonAds.vue +83 -83
- package/dist/runtime/components/ScriptCrisp.vue +94 -94
- package/dist/runtime/components/ScriptGoogleAdsense.vue +93 -93
- package/dist/runtime/components/ScriptGoogleMaps.vue +469 -469
- package/dist/runtime/components/ScriptIntercom.vue +103 -103
- package/dist/runtime/components/ScriptLemonSqueezy.vue +52 -52
- package/dist/runtime/components/ScriptLoadingIndicator.vue +22 -22
- package/dist/runtime/components/ScriptStripePricingTable.vue +74 -74
- package/dist/runtime/components/ScriptVimeoPlayer.vue +289 -289
- package/dist/runtime/components/ScriptYouTubePlayer.vue +215 -215
- package/dist/runtime/composables/useScript.d.ts +8 -4
- package/dist/runtime/composables/useScript.js +10 -59
- package/dist/runtime/registry/google-analytics.js +0 -3
- package/dist/runtime/registry/google-maps.d.ts +4 -10
- package/dist/runtime/registry/google-tag-manager.js +0 -3
- package/dist/runtime/registry/matomo-analytics.js +0 -4
- package/dist/runtime/registry/segment.js +0 -18
- package/dist/runtime/types.d.ts +2 -2
- package/dist/runtime/utils.js +1 -1
- package/package.json +32 -35
- package/dist/client/_nuxt/BqRljlc8.js +0 -21
- package/dist/client/_nuxt/CgFBdOe6.js +0 -1
- package/dist/client/_nuxt/builds/meta/a79d2e11-f9af-444c-b10e-0675b6cf7f55.json +0 -1
- package/dist/client/_nuxt/error-404.DrjQUyCj.css +0 -1
- package/dist/client/_nuxt/error-500.CIXIBnf9.css +0 -1
|
@@ -1,215 +1,215 @@
|
|
|
1
|
-
<script setup lang="ts">
|
|
2
|
-
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
3
|
-
// @ts-nocheck
|
|
4
|
-
|
|
5
|
-
/// <reference types="youtube" />
|
|
6
|
-
import { computed, onMounted, ref, watch } from 'vue'
|
|
7
|
-
import type { HTMLAttributes, ImgHTMLAttributes, Ref } from 'vue'
|
|
8
|
-
import { defu } from 'defu'
|
|
9
|
-
import { useHead } from '@unhead/vue'
|
|
10
|
-
import type { ElementScriptTrigger } from '../types'
|
|
11
|
-
import { useScriptTriggerElement } from '../composables/useScriptTriggerElement'
|
|
12
|
-
import { useScriptYouTubePlayer } from '../registry/youtube-player'
|
|
13
|
-
import ScriptAriaLoadingIndicator from './ScriptAriaLoadingIndicator.vue'
|
|
14
|
-
|
|
15
|
-
export type YoutubeThumbnailSize =
|
|
16
|
-
// 120x90
|
|
17
|
-
'1' | '2' | '3' | 'default' |
|
|
18
|
-
// 320x180
|
|
19
|
-
'mq1' | 'mq2' | 'mq3' | 'mqdefault' |
|
|
20
|
-
// 480x360
|
|
21
|
-
'0' | 'hq1' | 'hq2' | 'hq3' | 'hqdefault' |
|
|
22
|
-
// 640x480
|
|
23
|
-
'sd1' | 'sd2' | 'sd3' | 'sddefault' |
|
|
24
|
-
// 1280x720
|
|
25
|
-
'hq720' |
|
|
26
|
-
// 1920x1080
|
|
27
|
-
'maxresdefault'
|
|
28
|
-
|
|
29
|
-
const props = withDefaults(defineProps<{
|
|
30
|
-
placeholderAttrs?: ImgHTMLAttributes
|
|
31
|
-
rootAttrs?: HTMLAttributes
|
|
32
|
-
aboveTheFold?: boolean
|
|
33
|
-
trigger?: ElementScriptTrigger
|
|
34
|
-
videoId: string
|
|
35
|
-
playerVars?: YT.PlayerVars
|
|
36
|
-
width?: number
|
|
37
|
-
height?: number
|
|
38
|
-
/**
|
|
39
|
-
* Whether to use youtube-nocookie.com for embedding.
|
|
40
|
-
*
|
|
41
|
-
* @default false
|
|
42
|
-
*/
|
|
43
|
-
cookies?: boolean
|
|
44
|
-
playerOptions?: YT.PlayerOptions
|
|
45
|
-
thumbnailSize?: YoutubeThumbnailSize
|
|
46
|
-
webp?: boolean
|
|
47
|
-
}>(), {
|
|
48
|
-
cookies: false,
|
|
49
|
-
trigger: 'mousedown',
|
|
50
|
-
thumbnailSize: 'hq720',
|
|
51
|
-
webp: true,
|
|
52
|
-
// @ts-expect-error untyped
|
|
53
|
-
playerVars: { autoplay: 0, playsinline: 1 },
|
|
54
|
-
width: 640,
|
|
55
|
-
height: 360,
|
|
56
|
-
})
|
|
57
|
-
|
|
58
|
-
const emits = defineEmits<{
|
|
59
|
-
'ready': [e: YT.PlayerEvent]
|
|
60
|
-
'state-change': [e: YT.OnStateChangeEvent, target: YT.Player]
|
|
61
|
-
'playback-quality-change': [e: YT.OnPlaybackQualityChangeEvent, target: YT.Player]
|
|
62
|
-
'playback-rate-change': [e: YT.OnPlaybackRateChangeEvent, target: YT.Player]
|
|
63
|
-
'error': [e: YT.OnErrorEvent, target: YT.Player]
|
|
64
|
-
}>()
|
|
65
|
-
const events: (keyof YT.Events)[] = [
|
|
66
|
-
'onReady',
|
|
67
|
-
'onStateChange',
|
|
68
|
-
'onPlaybackQualityChange',
|
|
69
|
-
'onPlaybackRateChange',
|
|
70
|
-
'onError',
|
|
71
|
-
'onApiChange',
|
|
72
|
-
]
|
|
73
|
-
const rootEl = ref()
|
|
74
|
-
const youtubeEl = ref()
|
|
75
|
-
const ready = ref(false)
|
|
76
|
-
const trigger = useScriptTriggerElement({ trigger: props.trigger, el: rootEl })
|
|
77
|
-
const script = useScriptYouTubePlayer({
|
|
78
|
-
scriptOptions: {
|
|
79
|
-
trigger,
|
|
80
|
-
},
|
|
81
|
-
})
|
|
82
|
-
const { onLoaded, status } = script
|
|
83
|
-
|
|
84
|
-
const player: Ref<YT.Player | undefined> = ref()
|
|
85
|
-
let clickTriggered = false
|
|
86
|
-
if (props.trigger === 'mousedown' && trigger instanceof Promise) {
|
|
87
|
-
trigger.then((triggered) => {
|
|
88
|
-
if (triggered) {
|
|
89
|
-
clickTriggered = true
|
|
90
|
-
}
|
|
91
|
-
})
|
|
92
|
-
}
|
|
93
|
-
onMounted(() => {
|
|
94
|
-
onLoaded(async (instance) => {
|
|
95
|
-
const YouTube = instance.YT instanceof Promise ? await instance.YT : instance.YT
|
|
96
|
-
await new Promise<void>((resolve) => {
|
|
97
|
-
if (typeof YT.Player === 'undefined')
|
|
98
|
-
YouTube.ready(resolve)
|
|
99
|
-
else
|
|
100
|
-
resolve()
|
|
101
|
-
})
|
|
102
|
-
player.value = new YT.Player(youtubeEl.value, {
|
|
103
|
-
host: !props.cookies ? 'https://www.youtube-nocookie.com' : 'https://www.youtube.com',
|
|
104
|
-
...props,
|
|
105
|
-
...props.playerOptions,
|
|
106
|
-
events: Object.fromEntries(events.map(event => [event, (e: any) => {
|
|
107
|
-
const emitEventName = event.replace(/([A-Z])/g, '-$1').replace('on-', '').toLowerCase()
|
|
108
|
-
// @ts-expect-error untyped
|
|
109
|
-
emits(emitEventName, e)
|
|
110
|
-
if (event === 'onReady') {
|
|
111
|
-
ready.value = true
|
|
112
|
-
if (clickTriggered) {
|
|
113
|
-
player.value?.playVideo()
|
|
114
|
-
clickTriggered = false
|
|
115
|
-
}
|
|
116
|
-
watch(() => props.videoId, () => {
|
|
117
|
-
player.value?.loadVideoById(props.videoId)
|
|
118
|
-
})
|
|
119
|
-
}
|
|
120
|
-
}])),
|
|
121
|
-
})
|
|
122
|
-
})
|
|
123
|
-
watch(status, (status) => {
|
|
124
|
-
if (status === 'error') {
|
|
125
|
-
// @ts-expect-error untyped
|
|
126
|
-
emits('error')
|
|
127
|
-
}
|
|
128
|
-
})
|
|
129
|
-
})
|
|
130
|
-
|
|
131
|
-
defineExpose({
|
|
132
|
-
player,
|
|
133
|
-
})
|
|
134
|
-
|
|
135
|
-
const rootAttrs = computed(() => {
|
|
136
|
-
return defu(props.rootAttrs, {
|
|
137
|
-
'aria-busy': status.value === 'loading',
|
|
138
|
-
'aria-label': status.value === 'awaitingLoad'
|
|
139
|
-
? 'YouTube Player - Placeholder'
|
|
140
|
-
: status.value === 'loading'
|
|
141
|
-
? 'YouTube Player - Loading'
|
|
142
|
-
: 'YouTube Player - Loaded',
|
|
143
|
-
'aria-live': 'polite',
|
|
144
|
-
'role': 'application',
|
|
145
|
-
'style': {
|
|
146
|
-
cursor: 'pointer',
|
|
147
|
-
position: 'relative',
|
|
148
|
-
backgroundColor: 'black',
|
|
149
|
-
width: '100%',
|
|
150
|
-
aspectRatio: `${props.width}/${props.height}`,
|
|
151
|
-
},
|
|
152
|
-
...(trigger instanceof Promise ? trigger.ssrAttrs || {} : {}),
|
|
153
|
-
}) as HTMLAttributes
|
|
154
|
-
})
|
|
155
|
-
|
|
156
|
-
const fallbackPlaceHolder = computed(() => `https://i.ytimg.com/vi/${props.videoId}/hqdefault.jpg`)
|
|
157
|
-
const placeholder = computed(() => `https://i.ytimg.com/${props.webp ? 'vi_webp' : 'vi'}/${props.videoId}/${props.thumbnailSize}.${props.webp ? 'webp' : 'jpg'}`)
|
|
158
|
-
const isFallbackPlaceHolder = ref(false)
|
|
159
|
-
|
|
160
|
-
if (import.meta.server) {
|
|
161
|
-
// dns-prefetch https://i.vimeocdn.com
|
|
162
|
-
useHead({
|
|
163
|
-
link: [
|
|
164
|
-
{
|
|
165
|
-
key: `nuxt-script-youtube-img`,
|
|
166
|
-
rel: props.aboveTheFold ? 'preconnect' : 'dns-prefetch',
|
|
167
|
-
href: 'https://i.ytimg.com',
|
|
168
|
-
},
|
|
169
|
-
props.aboveTheFold
|
|
170
|
-
// we can preload the placeholder image
|
|
171
|
-
? {
|
|
172
|
-
key: `nuxt-script-youtube-img`,
|
|
173
|
-
rel: 'preload',
|
|
174
|
-
as: 'image',
|
|
175
|
-
href: placeholder.value,
|
|
176
|
-
}
|
|
177
|
-
: {},
|
|
178
|
-
],
|
|
179
|
-
})
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
const placeholderAttrs = computed(() => {
|
|
183
|
-
return defu(props.placeholderAttrs, {
|
|
184
|
-
src: isFallbackPlaceHolder.value ? fallbackPlaceHolder.value : placeholder.value,
|
|
185
|
-
alt: '',
|
|
186
|
-
loading: props.aboveTheFold ? 'eager' : 'lazy',
|
|
187
|
-
style: {
|
|
188
|
-
width: '100%',
|
|
189
|
-
objectFit: 'contain',
|
|
190
|
-
height: '100%',
|
|
191
|
-
},
|
|
192
|
-
onLoad(payload) {
|
|
193
|
-
const img = payload.target as HTMLImageElement
|
|
194
|
-
if (img.naturalWidth === 120 && img.naturalHeight === 90) {
|
|
195
|
-
isFallbackPlaceHolder.value = true
|
|
196
|
-
}
|
|
197
|
-
},
|
|
198
|
-
} satisfies ImgHTMLAttributes)
|
|
199
|
-
})
|
|
200
|
-
</script>
|
|
201
|
-
|
|
202
|
-
<template>
|
|
203
|
-
<div ref="rootEl" v-bind="rootAttrs">
|
|
204
|
-
<div ref="youtubeEl" style="width: 100%; height: 100%; position: absolute; top: 0; left: 0;" />
|
|
205
|
-
<slot v-if="!ready" :placeholder="placeholder" name="placeholder">
|
|
206
|
-
<img v-bind="placeholderAttrs">
|
|
207
|
-
</slot>
|
|
208
|
-
<slot v-if="status === 'loading'" name="loading">
|
|
209
|
-
<ScriptAriaLoadingIndicator />
|
|
210
|
-
</slot>
|
|
211
|
-
<slot v-if="status === 'awaitingLoad'" name="awaitingLoad" />
|
|
212
|
-
<slot v-else-if="status === 'error'" name="error" />
|
|
213
|
-
<slot />
|
|
214
|
-
</div>
|
|
215
|
-
</template>
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
3
|
+
// @ts-nocheck
|
|
4
|
+
|
|
5
|
+
/// <reference types="youtube" />
|
|
6
|
+
import { computed, onMounted, ref, watch } from 'vue'
|
|
7
|
+
import type { HTMLAttributes, ImgHTMLAttributes, Ref } from 'vue'
|
|
8
|
+
import { defu } from 'defu'
|
|
9
|
+
import { useHead } from '@unhead/vue'
|
|
10
|
+
import type { ElementScriptTrigger } from '../types'
|
|
11
|
+
import { useScriptTriggerElement } from '../composables/useScriptTriggerElement'
|
|
12
|
+
import { useScriptYouTubePlayer } from '../registry/youtube-player'
|
|
13
|
+
import ScriptAriaLoadingIndicator from './ScriptAriaLoadingIndicator.vue'
|
|
14
|
+
|
|
15
|
+
export type YoutubeThumbnailSize =
|
|
16
|
+
// 120x90
|
|
17
|
+
'1' | '2' | '3' | 'default' |
|
|
18
|
+
// 320x180
|
|
19
|
+
'mq1' | 'mq2' | 'mq3' | 'mqdefault' |
|
|
20
|
+
// 480x360
|
|
21
|
+
'0' | 'hq1' | 'hq2' | 'hq3' | 'hqdefault' |
|
|
22
|
+
// 640x480
|
|
23
|
+
'sd1' | 'sd2' | 'sd3' | 'sddefault' |
|
|
24
|
+
// 1280x720
|
|
25
|
+
'hq720' |
|
|
26
|
+
// 1920x1080
|
|
27
|
+
'maxresdefault'
|
|
28
|
+
|
|
29
|
+
const props = withDefaults(defineProps<{
|
|
30
|
+
placeholderAttrs?: ImgHTMLAttributes
|
|
31
|
+
rootAttrs?: HTMLAttributes
|
|
32
|
+
aboveTheFold?: boolean
|
|
33
|
+
trigger?: ElementScriptTrigger
|
|
34
|
+
videoId: string
|
|
35
|
+
playerVars?: YT.PlayerVars
|
|
36
|
+
width?: number
|
|
37
|
+
height?: number
|
|
38
|
+
/**
|
|
39
|
+
* Whether to use youtube-nocookie.com for embedding.
|
|
40
|
+
*
|
|
41
|
+
* @default false
|
|
42
|
+
*/
|
|
43
|
+
cookies?: boolean
|
|
44
|
+
playerOptions?: YT.PlayerOptions
|
|
45
|
+
thumbnailSize?: YoutubeThumbnailSize
|
|
46
|
+
webp?: boolean
|
|
47
|
+
}>(), {
|
|
48
|
+
cookies: false,
|
|
49
|
+
trigger: 'mousedown',
|
|
50
|
+
thumbnailSize: 'hq720',
|
|
51
|
+
webp: true,
|
|
52
|
+
// @ts-expect-error untyped
|
|
53
|
+
playerVars: { autoplay: 0, playsinline: 1 },
|
|
54
|
+
width: 640,
|
|
55
|
+
height: 360,
|
|
56
|
+
})
|
|
57
|
+
|
|
58
|
+
const emits = defineEmits<{
|
|
59
|
+
'ready': [e: YT.PlayerEvent]
|
|
60
|
+
'state-change': [e: YT.OnStateChangeEvent, target: YT.Player]
|
|
61
|
+
'playback-quality-change': [e: YT.OnPlaybackQualityChangeEvent, target: YT.Player]
|
|
62
|
+
'playback-rate-change': [e: YT.OnPlaybackRateChangeEvent, target: YT.Player]
|
|
63
|
+
'error': [e: YT.OnErrorEvent, target: YT.Player]
|
|
64
|
+
}>()
|
|
65
|
+
const events: (keyof YT.Events)[] = [
|
|
66
|
+
'onReady',
|
|
67
|
+
'onStateChange',
|
|
68
|
+
'onPlaybackQualityChange',
|
|
69
|
+
'onPlaybackRateChange',
|
|
70
|
+
'onError',
|
|
71
|
+
'onApiChange',
|
|
72
|
+
]
|
|
73
|
+
const rootEl = ref()
|
|
74
|
+
const youtubeEl = ref()
|
|
75
|
+
const ready = ref(false)
|
|
76
|
+
const trigger = useScriptTriggerElement({ trigger: props.trigger, el: rootEl })
|
|
77
|
+
const script = useScriptYouTubePlayer({
|
|
78
|
+
scriptOptions: {
|
|
79
|
+
trigger,
|
|
80
|
+
},
|
|
81
|
+
})
|
|
82
|
+
const { onLoaded, status } = script
|
|
83
|
+
|
|
84
|
+
const player: Ref<YT.Player | undefined> = ref()
|
|
85
|
+
let clickTriggered = false
|
|
86
|
+
if (props.trigger === 'mousedown' && trigger instanceof Promise) {
|
|
87
|
+
trigger.then((triggered) => {
|
|
88
|
+
if (triggered) {
|
|
89
|
+
clickTriggered = true
|
|
90
|
+
}
|
|
91
|
+
})
|
|
92
|
+
}
|
|
93
|
+
onMounted(() => {
|
|
94
|
+
onLoaded(async (instance) => {
|
|
95
|
+
const YouTube = instance.YT instanceof Promise ? await instance.YT : instance.YT
|
|
96
|
+
await new Promise<void>((resolve) => {
|
|
97
|
+
if (typeof YT.Player === 'undefined')
|
|
98
|
+
YouTube.ready(resolve)
|
|
99
|
+
else
|
|
100
|
+
resolve()
|
|
101
|
+
})
|
|
102
|
+
player.value = new YT.Player(youtubeEl.value, {
|
|
103
|
+
host: !props.cookies ? 'https://www.youtube-nocookie.com' : 'https://www.youtube.com',
|
|
104
|
+
...props,
|
|
105
|
+
...props.playerOptions,
|
|
106
|
+
events: Object.fromEntries(events.map(event => [event, (e: any) => {
|
|
107
|
+
const emitEventName = event.replace(/([A-Z])/g, '-$1').replace('on-', '').toLowerCase()
|
|
108
|
+
// @ts-expect-error untyped
|
|
109
|
+
emits(emitEventName, e)
|
|
110
|
+
if (event === 'onReady') {
|
|
111
|
+
ready.value = true
|
|
112
|
+
if (clickTriggered) {
|
|
113
|
+
player.value?.playVideo()
|
|
114
|
+
clickTriggered = false
|
|
115
|
+
}
|
|
116
|
+
watch(() => props.videoId, () => {
|
|
117
|
+
player.value?.loadVideoById(props.videoId)
|
|
118
|
+
})
|
|
119
|
+
}
|
|
120
|
+
}])),
|
|
121
|
+
})
|
|
122
|
+
})
|
|
123
|
+
watch(status, (status) => {
|
|
124
|
+
if (status === 'error') {
|
|
125
|
+
// @ts-expect-error untyped
|
|
126
|
+
emits('error')
|
|
127
|
+
}
|
|
128
|
+
})
|
|
129
|
+
})
|
|
130
|
+
|
|
131
|
+
defineExpose({
|
|
132
|
+
player,
|
|
133
|
+
})
|
|
134
|
+
|
|
135
|
+
const rootAttrs = computed(() => {
|
|
136
|
+
return defu(props.rootAttrs, {
|
|
137
|
+
'aria-busy': status.value === 'loading',
|
|
138
|
+
'aria-label': status.value === 'awaitingLoad'
|
|
139
|
+
? 'YouTube Player - Placeholder'
|
|
140
|
+
: status.value === 'loading'
|
|
141
|
+
? 'YouTube Player - Loading'
|
|
142
|
+
: 'YouTube Player - Loaded',
|
|
143
|
+
'aria-live': 'polite',
|
|
144
|
+
'role': 'application',
|
|
145
|
+
'style': {
|
|
146
|
+
cursor: 'pointer',
|
|
147
|
+
position: 'relative',
|
|
148
|
+
backgroundColor: 'black',
|
|
149
|
+
width: '100%',
|
|
150
|
+
aspectRatio: `${props.width}/${props.height}`,
|
|
151
|
+
},
|
|
152
|
+
...(trigger instanceof Promise ? trigger.ssrAttrs || {} : {}),
|
|
153
|
+
}) as HTMLAttributes
|
|
154
|
+
})
|
|
155
|
+
|
|
156
|
+
const fallbackPlaceHolder = computed(() => `https://i.ytimg.com/vi/${props.videoId}/hqdefault.jpg`)
|
|
157
|
+
const placeholder = computed(() => `https://i.ytimg.com/${props.webp ? 'vi_webp' : 'vi'}/${props.videoId}/${props.thumbnailSize}.${props.webp ? 'webp' : 'jpg'}`)
|
|
158
|
+
const isFallbackPlaceHolder = ref(false)
|
|
159
|
+
|
|
160
|
+
if (import.meta.server) {
|
|
161
|
+
// dns-prefetch https://i.vimeocdn.com
|
|
162
|
+
useHead({
|
|
163
|
+
link: [
|
|
164
|
+
{
|
|
165
|
+
key: `nuxt-script-youtube-img`,
|
|
166
|
+
rel: props.aboveTheFold ? 'preconnect' : 'dns-prefetch',
|
|
167
|
+
href: 'https://i.ytimg.com',
|
|
168
|
+
},
|
|
169
|
+
props.aboveTheFold
|
|
170
|
+
// we can preload the placeholder image
|
|
171
|
+
? {
|
|
172
|
+
key: `nuxt-script-youtube-img`,
|
|
173
|
+
rel: 'preload',
|
|
174
|
+
as: 'image',
|
|
175
|
+
href: placeholder.value,
|
|
176
|
+
}
|
|
177
|
+
: {},
|
|
178
|
+
],
|
|
179
|
+
})
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
const placeholderAttrs = computed(() => {
|
|
183
|
+
return defu(props.placeholderAttrs, {
|
|
184
|
+
src: isFallbackPlaceHolder.value ? fallbackPlaceHolder.value : placeholder.value,
|
|
185
|
+
alt: '',
|
|
186
|
+
loading: props.aboveTheFold ? 'eager' : 'lazy',
|
|
187
|
+
style: {
|
|
188
|
+
width: '100%',
|
|
189
|
+
objectFit: 'contain',
|
|
190
|
+
height: '100%',
|
|
191
|
+
},
|
|
192
|
+
onLoad(payload) {
|
|
193
|
+
const img = payload.target as HTMLImageElement
|
|
194
|
+
if (img.naturalWidth === 120 && img.naturalHeight === 90) {
|
|
195
|
+
isFallbackPlaceHolder.value = true
|
|
196
|
+
}
|
|
197
|
+
},
|
|
198
|
+
} satisfies ImgHTMLAttributes)
|
|
199
|
+
})
|
|
200
|
+
</script>
|
|
201
|
+
|
|
202
|
+
<template>
|
|
203
|
+
<div ref="rootEl" v-bind="rootAttrs">
|
|
204
|
+
<div ref="youtubeEl" style="width: 100%; height: 100%; position: absolute; top: 0; left: 0;" />
|
|
205
|
+
<slot v-if="!ready" :placeholder="placeholder" name="placeholder">
|
|
206
|
+
<img v-bind="placeholderAttrs">
|
|
207
|
+
</slot>
|
|
208
|
+
<slot v-if="status === 'loading'" name="loading">
|
|
209
|
+
<ScriptAriaLoadingIndicator />
|
|
210
|
+
</slot>
|
|
211
|
+
<slot v-if="status === 'awaitingLoad'" name="awaitingLoad" />
|
|
212
|
+
<slot v-else-if="status === 'error'" name="error" />
|
|
213
|
+
<slot />
|
|
214
|
+
</div>
|
|
215
|
+
</template>
|
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
import type { UseScriptInput } from '@unhead/vue';
|
|
2
|
-
import type {
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
import type { UseScriptInput } from '@unhead/vue/scripts';
|
|
2
|
+
import type { NuxtUseScriptOptions, UseScriptContext } from '../types.js';
|
|
3
|
+
type UseFunctionType<T, U> = T extends {
|
|
4
|
+
use: infer V;
|
|
5
|
+
} ? V extends (...args: any) => any ? ReturnType<V> : U : U;
|
|
6
|
+
export declare function resolveScriptKey(input: any): string;
|
|
7
|
+
export declare function useScript<T extends Record<symbol | string, any> = Record<symbol | string, any>>(input: UseScriptInput, options?: NuxtUseScriptOptions<T>): UseScriptContext<UseFunctionType<NuxtUseScriptOptions<T>, T>>;
|
|
8
|
+
export {};
|
|
@@ -1,45 +1,12 @@
|
|
|
1
|
-
import { resolveScriptKey } from "unhead";
|
|
2
1
|
import { defu } from "defu";
|
|
3
|
-
import { useScript as _useScript
|
|
4
|
-
import { parseURL } from "ufo";
|
|
5
|
-
import { onNuxtReady, useHead, useNuxtApp, useRuntimeConfig } from "nuxt/app";
|
|
2
|
+
import { useScript as _useScript } from "@unhead/vue/scripts";
|
|
6
3
|
import { reactive } from "vue";
|
|
7
|
-
import {
|
|
4
|
+
import { onNuxtReady, useNuxtApp, useRuntimeConfig, injectHead } from "#imports";
|
|
8
5
|
function useNuxtScriptRuntimeConfig() {
|
|
9
6
|
return useRuntimeConfig().public["nuxt-scripts"];
|
|
10
7
|
}
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
function warmup(_, rel, head) {
|
|
14
|
-
const { src } = _;
|
|
15
|
-
const $url = parseURL(src);
|
|
16
|
-
const isPreconnect = rel && PreconnectServerModes.includes(rel);
|
|
17
|
-
const href = isPreconnect ? `${$url.protocol}${$url.host}` : src;
|
|
18
|
-
const isCrossOrigin = !!$url.host;
|
|
19
|
-
if (!rel || isPreconnect && !isCrossOrigin) {
|
|
20
|
-
return;
|
|
21
|
-
}
|
|
22
|
-
const link = {
|
|
23
|
-
href,
|
|
24
|
-
rel,
|
|
25
|
-
...pick(_, [
|
|
26
|
-
// shared keys between script and link
|
|
27
|
-
"crossorigin",
|
|
28
|
-
"referrerpolicy",
|
|
29
|
-
"fetchpriority",
|
|
30
|
-
"integrity"
|
|
31
|
-
// ignore id
|
|
32
|
-
])
|
|
33
|
-
};
|
|
34
|
-
const defaults = { fetchpriority: "low" };
|
|
35
|
-
if (rel === "preload") {
|
|
36
|
-
defaults.as = "script";
|
|
37
|
-
}
|
|
38
|
-
if (isCrossOrigin) {
|
|
39
|
-
defaults.crossorigin = "anonymous";
|
|
40
|
-
defaults.referrerpolicy = "no-referrer";
|
|
41
|
-
}
|
|
42
|
-
return useHead({ link: [defu(link, defaults)] }, { head, tagPriority: "high" });
|
|
8
|
+
export function resolveScriptKey(input) {
|
|
9
|
+
return input.key || input.src || (typeof input.innerHTML === "string" ? input.innerHTML : "");
|
|
43
10
|
}
|
|
44
11
|
export function useScript(input, options) {
|
|
45
12
|
input = typeof input === "string" ? { src: input } : input;
|
|
@@ -49,33 +16,17 @@ export function useScript(input, options) {
|
|
|
49
16
|
const head = options.head || injectHead();
|
|
50
17
|
nuxtApp.$scripts = nuxtApp.$scripts || reactive({});
|
|
51
18
|
const exists = !!nuxtApp.$scripts?.[id];
|
|
52
|
-
if (
|
|
53
|
-
options.warmupStrategy
|
|
54
|
-
|
|
55
|
-
if (options.trigger === "onNuxtReady") {
|
|
56
|
-
options.trigger = onNuxtReady;
|
|
57
|
-
}
|
|
58
|
-
if (import.meta.client) {
|
|
59
|
-
if (!exists) {
|
|
60
|
-
performance?.mark?.("mark_feature_usage", {
|
|
61
|
-
detail: {
|
|
62
|
-
feature: options.performanceMarkFeature ?? `nuxt-scripts:${id}`
|
|
63
|
-
}
|
|
64
|
-
});
|
|
19
|
+
if (options.trigger === "onNuxtReady" || options.trigger === "client") {
|
|
20
|
+
if (!options.warmupStrategy) {
|
|
21
|
+
options.warmupStrategy = "preload";
|
|
65
22
|
}
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
instance.warmup = (rel) => {
|
|
69
|
-
if (!instance._warmupEl) {
|
|
70
|
-
instance._warmupEl = warmup(input, rel, head);
|
|
23
|
+
if (options.trigger === "onNuxtReady") {
|
|
24
|
+
options.trigger = onNuxtReady;
|
|
71
25
|
}
|
|
72
|
-
};
|
|
73
|
-
if (options.warmupStrategy) {
|
|
74
|
-
instance.warmup(options.warmupStrategy);
|
|
75
26
|
}
|
|
27
|
+
const instance = _useScript(input, options);
|
|
76
28
|
const _remove = instance.remove;
|
|
77
29
|
instance.remove = () => {
|
|
78
|
-
instance._warmupEl?.dispose();
|
|
79
30
|
nuxtApp.$scripts[id] = void 0;
|
|
80
31
|
return _remove();
|
|
81
32
|
};
|
|
@@ -1,12 +1,4 @@
|
|
|
1
1
|
import type { RegistryScriptInput } from '#nuxt-scripts/types';
|
|
2
|
-
declare namespace google {
|
|
3
|
-
namespace maps {
|
|
4
|
-
/**
|
|
5
|
-
* @internal
|
|
6
|
-
*/
|
|
7
|
-
function __ib__(): void;
|
|
8
|
-
}
|
|
9
|
-
}
|
|
10
2
|
export declare const GoogleMapsOptions: import("valibot").ObjectSchema<{
|
|
11
3
|
readonly apiKey: import("valibot").StringSchema<undefined>;
|
|
12
4
|
readonly libraries: import("valibot").OptionalSchema<import("valibot").ArraySchema<import("valibot").StringSchema<undefined>, undefined>, undefined>;
|
|
@@ -15,14 +7,16 @@ export declare const GoogleMapsOptions: import("valibot").ObjectSchema<{
|
|
|
15
7
|
readonly v: import("valibot").OptionalSchema<import("valibot").UnionSchema<[import("valibot").LiteralSchema<"weekly", undefined>, import("valibot").LiteralSchema<"beta", undefined>, import("valibot").LiteralSchema<"alpha", undefined>], undefined>, undefined>;
|
|
16
8
|
}, undefined>;
|
|
17
9
|
export type GoogleMapsInput = RegistryScriptInput<typeof GoogleMapsOptions>;
|
|
18
|
-
type MapsNamespace = typeof google.maps;
|
|
10
|
+
type MapsNamespace = typeof window.google.maps;
|
|
19
11
|
export interface GoogleMapsApi {
|
|
20
12
|
maps: Promise<MapsNamespace>;
|
|
21
13
|
}
|
|
22
14
|
declare global {
|
|
23
15
|
interface Window {
|
|
24
16
|
google: {
|
|
25
|
-
maps:
|
|
17
|
+
maps: {
|
|
18
|
+
__ib__(): void;
|
|
19
|
+
};
|
|
26
20
|
};
|
|
27
21
|
}
|
|
28
22
|
}
|
|
@@ -15,9 +15,6 @@ export function useScriptGoogleTagManager(_options) {
|
|
|
15
15
|
use: () => {
|
|
16
16
|
return { dataLayer: window[options.l ?? "dataLayer"], google_tag_manager: window.google_tag_manager };
|
|
17
17
|
},
|
|
18
|
-
stub: import.meta.client ? void 0 : ({ fn }) => {
|
|
19
|
-
return fn === "dataLayer" ? [] : void 0;
|
|
20
|
-
},
|
|
21
18
|
performanceMarkFeature: "nuxt-third-parties-gtm",
|
|
22
19
|
tagPriority: 1
|
|
23
20
|
},
|
|
@@ -24,10 +24,6 @@ export function useScriptMatomoAnalytics(_options) {
|
|
|
24
24
|
scriptOptions: {
|
|
25
25
|
use() {
|
|
26
26
|
return { _paq: window._paq };
|
|
27
|
-
},
|
|
28
|
-
// allow _paq to be accessed on the server
|
|
29
|
-
stub: import.meta.client ? void 0 : ({ fn }) => {
|
|
30
|
-
return fn === "_paq" ? [] : void 0;
|
|
31
27
|
}
|
|
32
28
|
},
|
|
33
29
|
clientInit: import.meta.server ? void 0 : () => {
|
|
@@ -33,24 +33,6 @@ export function useScriptSegment(_options) {
|
|
|
33
33
|
},
|
|
34
34
|
schema: import.meta.dev ? SegmentOptions : void 0,
|
|
35
35
|
scriptOptions: {
|
|
36
|
-
stub: import.meta.server ? ({ fn }) => {
|
|
37
|
-
if (fn === "analytics") {
|
|
38
|
-
return {
|
|
39
|
-
track: () => {
|
|
40
|
-
},
|
|
41
|
-
page: () => {
|
|
42
|
-
},
|
|
43
|
-
identify: () => {
|
|
44
|
-
},
|
|
45
|
-
group: () => {
|
|
46
|
-
},
|
|
47
|
-
alias: () => {
|
|
48
|
-
},
|
|
49
|
-
reset: () => {
|
|
50
|
-
}
|
|
51
|
-
};
|
|
52
|
-
}
|
|
53
|
-
} : void 0,
|
|
54
36
|
use() {
|
|
55
37
|
return methods.reduce((acc, key) => {
|
|
56
38
|
acc[key] = window[k].factory(key);
|
package/dist/runtime/types.d.ts
CHANGED
|
@@ -34,14 +34,14 @@ export type UseScriptContext<T extends Record<symbol | string, any>> = (Promise<
|
|
|
34
34
|
warmup: (rel: WarmupStrategy) => void;
|
|
35
35
|
_warmupEl?: void | ActiveHeadEntry<any>;
|
|
36
36
|
};
|
|
37
|
-
export type NuxtUseScriptOptions<T extends Record<symbol | string, any> = {}
|
|
37
|
+
export type NuxtUseScriptOptions<T extends Record<symbol | string, any> = {}> = Omit<UseScriptOptions<T>, 'trigger'> & {
|
|
38
38
|
/**
|
|
39
39
|
* The trigger to load the script:
|
|
40
40
|
* - `onNuxtReady` - Load the script when Nuxt is ready.
|
|
41
41
|
* - `manual` - Load the script manually by calling `load()`.
|
|
42
42
|
* - `Promise` - Load the script when the promise resolves.
|
|
43
43
|
*/
|
|
44
|
-
trigger?: UseScriptOptions<T
|
|
44
|
+
trigger?: UseScriptOptions<T>['trigger'] | 'onNuxtReady';
|
|
45
45
|
/**
|
|
46
46
|
* Should the script be bundled as an asset and loaded from your server. This is useful for improving the
|
|
47
47
|
* performance by avoiding the extra DNS lookup and reducing the number of requests. It also
|
package/dist/runtime/utils.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { defu } from "defu";
|
|
2
2
|
import { useRuntimeConfig } from "nuxt/app";
|
|
3
|
-
import { useScript } from "
|
|
3
|
+
import { useScript } from "#imports";
|
|
4
4
|
import { parse } from "#nuxt-scripts-validator";
|
|
5
5
|
function validateScriptInputSchema(key, schema, options) {
|
|
6
6
|
if (import.meta.dev) {
|