Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ jobs:
- {nuxt: 4.6.0, node: 22.22.3, future: true, panel: false, base: /}
- {nuxt: 4.6.0, node: 24.15.0, future: false, panel: false, base: /, edge: true}
- {nuxt: 4.6.0, node: 24.15.0, future: true, panel: true, base: /sub/}
- {nuxt: 5.0.0-2610060838-ddb1dab, node: 24.15.0, future: false, panel: true, base: /}
- {nuxt: 5.0.0-2610061032-c7ad8cd, node: 24.15.0, future: false, panel: true, base: /}
steps:
- uses: actions/checkout@v7
with:
Expand Down
2 changes: 1 addition & 1 deletion .nuxtrc
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
imports.autoImport=true
modules.0="@nuxt/scripts"
setups.@nuxt/test-utils="4.3.2"
setups.@nuxt/test-utils="4.3.3"
2 changes: 1 addition & 1 deletion examples/cookie-consent/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
},
"dependencies": {
"@nuxt/scripts": "latest",
"@nuxt/ui": "^4.11.1",
"@nuxt/ui": "^4.11.3",
"nuxt": "^4.6.0",
"tailwindcss": "^4.3.3",
"vue": "^3.5.43"
Expand Down
2 changes: 1 addition & 1 deletion examples/custom-script/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
},
"dependencies": {
"@nuxt/scripts": "latest",
"@nuxt/ui": "^4.11.1",
"@nuxt/ui": "^4.11.3",
"nuxt": "^4.6.0",
"tailwindcss": "^4.3.3",
"vue": "^3.5.43"
Expand Down
2 changes: 1 addition & 1 deletion examples/granular-consent/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
},
"dependencies": {
"@nuxt/scripts": "latest",
"@nuxt/ui": "^4.11.1",
"@nuxt/ui": "^4.11.3",
"nuxt": "^4.6.0",
"tailwindcss": "^4.3.3",
"vue": "^3.5.43"
Expand Down
2 changes: 1 addition & 1 deletion examples/performance/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
},
"dependencies": {
"@nuxt/scripts": "latest",
"@nuxt/ui": "^4.11.1",
"@nuxt/ui": "^4.11.3",
"nuxt": "^4.6.0",
"tailwindcss": "^4.3.3",
"vue": "^3.5.43"
Expand Down
2 changes: 1 addition & 1 deletion examples/regional-consent/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
},
"dependencies": {
"@nuxt/scripts": "latest",
"@nuxt/ui": "^4.11.1",
"@nuxt/ui": "^4.11.3",
"nuxt": "^4.6.0",
"tailwindcss": "^4.3.3",
"vue": "^3.5.43"
Expand Down
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,12 +49,14 @@
"@types/youtube": "catalog:",
"@typescript/native": "catalog:",
"@unhead/vue": "catalog:",
"@vimeo/player": "catalog:",
"@vue/test-utils": "catalog:",
"bumpp": "catalog:",
"defu": "catalog:",
"eslint": "catalog:",
"eslint-plugin-harlanzw": "catalog:",
"h3": "catalog:",
"h3-next": "catalog:",
"happy-dom": "catalog:",
"jest-image-snapshot": "catalog:",
"maplibre-gl": "catalog:",
Expand Down
17 changes: 8 additions & 9 deletions packages/script/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -77,18 +77,18 @@
},
"peerDependencies": {
"@googlemaps/markerclusterer": "^2.6.2",
"@paypal/paypal-js": "^11.0.1",
"@paypal/paypal-js": "^11.2.1",
"@speedcurve/lux": "^4.5.2",
"@stripe/stripe-js": "^9.16.0",
"@stripe/stripe-js": "^10.0.0",
"@types/geojson": "^7946.0.16",
"@types/google.maps": "^3.66.2",
"@types/google.maps": "^3.66.5",
"@types/leaflet": "^1.9.22",
"@types/vimeo__player": "^2.18.3",
"@types/youtube": "^0.3.0",
"@unhead/vue": "^3.4.2",
"maplibre-gl": "^6.9.1",
"@vimeo/player": "^2.30.4",
"maplibre-gl": "^6.12.0",
"nuxt": "^4.6.0 || ^5.0.0",
"posthog-js": "^1.433.3",
"posthog-js": "^1.437.0",
"unhead": "^3.4.2"
},
"peerDependenciesMeta": {
Expand All @@ -113,10 +113,10 @@
"@types/leaflet": {
"optional": true
},
"@types/vimeo__player": {
"@types/youtube": {
"optional": true
},
"@types/youtube": {
"@vimeo/player": {
"optional": true
},
"maplibre-gl": {
Expand All @@ -133,7 +133,6 @@
"@vueuse/shared": "catalog:",
"consola": "catalog:",
"defu": "catalog:",
"h3": "catalog:",
"lru-cache": "catalog:",
"magic-string": "catalog:",
"ofetch": "catalog:",
Expand Down
43 changes: 20 additions & 23 deletions packages/script/src/assets.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { addDevServerHandler, extendRouteRules, tryUseNuxt, useNuxt } from '@nuxt/kit'
import { createError, eventHandler, lazyEventHandler, setHeader } from 'h3'
import { fetch } from 'ofetch'
import { join, resolve } from 'pathe'
import { joinURL } from 'ufo'
Expand Down Expand Up @@ -42,32 +41,30 @@ export function setupPublicAssetStrategy(assetsBaseURL: string) {
// Register font proxy URL for development
addDevServerHandler({
route: assetsBaseURL,
handler: lazyEventHandler(async () => {
return eventHandler(async (event) => {
const cleanPath = (event.path || '').split('?')[0]?.slice(1) || ''
const filename = cleanPath
const scriptDescriptor = renderedScript.get(join(assetsBaseURL, cleanPath))
handler: async (event) => {
const cleanPath = (event.path || '').split('?')[0]?.slice(1) || ''
const filename = cleanPath
const scriptDescriptor = renderedScript.get(join(assetsBaseURL, cleanPath))

if (!scriptDescriptor || scriptDescriptor instanceof Error)
throw createError({ statusCode: 404 })
if (!scriptDescriptor || scriptDescriptor instanceof Error)
return new Response(null, { status: 404 })

setHeader(event, 'content-type', 'application/javascript; charset=utf-8')
const headers = { 'content-type': 'application/javascript; charset=utf-8' }

// Use pre-rendered content which includes proxy rewrites for first-party mode
if (scriptDescriptor.content) {
return scriptDescriptor.content
}
// Use pre-rendered content which includes proxy rewrites for first-party mode
if (scriptDescriptor.content) {
return new Response(new Uint8Array(scriptDescriptor.content), { headers })
}

// Fallback to storage cache
const key = `bundle:${filename}`
let res = await storage.getItemRaw(key)
if (!res) {
res = await fetch(scriptDescriptor.src).then(r => r.arrayBuffer()).then(r => Buffer.from(r))
await storage.setItemRaw(key, res)
}
return res
})
}),
// Fallback to storage cache
const key = `bundle:${filename}`
let res = await storage.getItemRaw(key)
if (!res) {
res = await fetch(scriptDescriptor.src).then(r => r.arrayBuffer()).then(r => Buffer.from(r))
await storage.setItemRaw(key, res)
}
return new Response(new Uint8Array(res), { headers })
},
})

if (nuxt.options.dev) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ let clusterUpdateId = 0
let pendingClusterUpdateIds: number[] = []
/** True while a `setData` call of this component waits for a worker round. */
let pendingDataRound = false
/** A data update must settle before a later cluster change reaches the worker. */
let dataUpdate: Promise<void> | undefined
/** What the worker round MapLibre is currently running was asked to do. */
let runningRound: { kind: 'cluster', updateId: number } | { kind: 'data' } | { kind: 'foreign' } = { kind: 'foreign' }
let layerSubscriptions: MapLibreGl.Subscription[] = []
Expand Down Expand Up @@ -139,8 +141,8 @@ function onMapError(event: MapErrorEvent): void {
* MapLibre runs one worker round at a time and fires a source `dataloading`
* event when the next one starts. Tile loads of this source fire the same
* event with the tile attached, and a tile load never starts a worker round,
* so those events are ignored. Queued data wins over queued cluster options,
* mirroring MapLibre's own `_pendingWorkerUpdate` order. One round runs every
* so those events are ignored. Data loads settle before deferred cluster calls.
* One round runs every
* queued cluster call with the last call's options, so the round takes the
* last id and clears the queue. The next `error` event for this source
* belongs to the round that is running, so it can never be blamed on an
Expand Down Expand Up @@ -355,6 +357,7 @@ function removeOwnedResources(map: MapLibreGl.Map): void {
clusterUpdateId++
pendingClusterUpdateIds = []
pendingDataRound = false
dataUpdate = undefined
runningRound = { kind: 'foreign' }
}

Expand Down Expand Up @@ -434,12 +437,21 @@ function updateClusterOptions(source: MapLibreGl.GeoJSONSource, options: MapLibr
const updateId = ++clusterUpdateId
appliedStructure = structureSignature()
appliedSourceOptions = detachSourceOptions()
pendingClusterUpdateIds.push(updateId)
// The failure arrives as the map `error` event attributed above.
void source.setClusterOptions(options).catch(() => {
// Unreachable: MapLibre catches a worker failure, fires a map `error`
// event and resolves the promise, so the failure is already reported.
})
const apply = () => {
if (updateId !== clusterUpdateId || source !== geoJson.value?.map.getSource(props.sourceId))
return
pendingClusterUpdateIds.push(updateId)
// The failure arrives as the map `error` event attributed above.
void source.setClusterOptions(options).catch(() => {
// MapLibre reports worker failures through the map error event.
})
}
// MapLibre 6.12 skips a cluster request while data waits in its queue.
// Apply the latest options after that data load settles, including failures.
if (dataUpdate)
void dataUpdate.then(apply)
else
apply()
}

/** Applies every changed entry of one paint or layout block to a live layer. */
Expand Down Expand Up @@ -575,7 +587,14 @@ watch(() => props.data, (data) => {
// Set before the call, so a round that MapLibre starts synchronously
// already carries it.
pendingDataRound = true
;(source as MapLibreGl.GeoJSONSource).setData(toRaw(data))
const update = (source as MapLibreGl.GeoJSONSource).setData(toRaw(data)).catch((error) => {
reportMapLibreResourceError(error, failure => emit('error', failure))
})
dataUpdate = update
void update.then(() => {
if (dataUpdate === update)
dataUpdate = undefined
})
}
}, { deep: 2 })

Expand Down
8 changes: 4 additions & 4 deletions packages/script/src/runtime/components/ScriptVimeoPlayer.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,18 @@
// eslint-disable-next-line ts/ban-ts-comment
// @ts-nocheck

import type Vimeo from '@vimeo/player'
import type { PlayerEventMap, VideoQualityId } from '@vimeo/player'
import type { HTMLAttributes, ImgHTMLAttributes } from 'vue'
import type { ElementScriptTrigger } from '../types'
import { defu } from 'defu'
import { useAsyncData, useHead } from 'nuxt/app'
/// <reference types="vimeo__player" />
import { computed, onBeforeUnmount, onMounted, ref, watch } from 'vue'
import { useScriptTriggerElement } from '../composables/useScriptTriggerElement'
import { useScriptVimeoPlayer } from '../registry/vimeo-player'
import ScriptAriaLoadingIndicator from './ScriptAriaLoadingIndicator.vue'

interface VimeoOptions {
// copied from @types/vimeo__player
id?: number | undefined
url?: string | undefined
autopause?: boolean | undefined
Expand All @@ -36,7 +36,7 @@ interface VimeoOptions {
portrait?: boolean | undefined
responsive?: boolean | undefined
speed?: boolean | undefined
quality?: Vimeo.VimeoVideoQuality | undefined
quality?: VideoQualityId | undefined
texttrack?: string | undefined
title?: boolean | undefined
transparent?: boolean | undefined
Expand Down Expand Up @@ -75,7 +75,7 @@ defineSlots<{
error?: () => any
}>()

type EventMap<E extends keyof Vimeo.EventMap> = [event: Vimeo.EventMap[E], player: Vimeo]
type EventMap<E extends keyof PlayerEventMap> = [event: PlayerEventMap[E], player: Vimeo]

interface TEmits {
play: EventMap<'play'>
Expand Down
Loading
Loading