Is there a way to add modifiers to an existing provider? #2059
-
|
I'm hosting media on Cloudinary and using it together with Nuxt Image. To handle both images and videos, I currently define two providers: // nuxt.config.ts
/**
* Nuxt Image module configuration
* @link https://image.nuxt.com/get-started/installation
*/
image: {
provider: 'cloudinary',
cloudinary: {
baseURL: `https://res.cloudinary.com/${process.env.CLD_CLOUD}/image/upload/`,
modifiers: {
quality: 'auto:best',
format: 'auto',
},
},
providers: {
video: {
provider: 'cloudinary',
options: {
baseURL: `https://res.cloudinary.com/${process.env.CLD_CLOUD}/video/upload/`,
},
},
},
}Defining the extra <NuxtImg
:src="poster"
provider="video"
:width="width"
:height="height"
fit="fill"
:alt="data.title"
:loading="lazy ? 'lazy' : 'eager'"
:modifiers="{
aspectRatio: ASPECT_RATIO,
// @ts-expect-error video-specific modifier
so: '5'
}"
class="w-full h-full object-cover object-center"
/>Is there a way to extend the provider definition so video transforms—like |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment 2 replies
-
|
Hey @remihuigen Few months late but dug into the source and the Cloudinary docs to figure out exactly what's happening. Looking at the Cloudinary provider source, the modifier pipeline works like this:
So you need to solve both: make TypeScript accept the modifiers and make them actually reach the URL. Option 1: Module augmentation + keyMap extension; Extend the types so TS is happy: // types/nuxt-image-cloudinary.d.ts
import type { CloudinaryModifiers } from '@nuxt/image'
declare module '@nuxt/image' {
interface CloudinaryModifiers {
so?: string | number
duration?: string | number
}
}But this alone won't make them work. The Option 2: Typed wrapper. If you just want the TS error gone: // utils/video-modifiers.ts
interface VideoModifiers {
width?: number
height?: number
fit?: string
so?: string | number
duration?: string | number
aspectRatio?: string
}
export const videoMods = (overrides: VideoModifiers = {}) => ({
aspectRatio: '16:9',
so: '5',
...overrides,
})<NuxtImg provider="video" :modifiers="videoMods({ so: '5' })" />TypeScript won't complain. But check if Option 3: Custom provider. Looking at the Cloudinary Transformation Reference, the actual URL params are // providers/video-cloudinary.ts
import { joinURL, encodePath } from 'ufo'
import { defu } from 'defu'
import type { ImageModifiers } from '@nuxt/image'
import { createOperationsGenerator } from '@nuxt/image/runtime/utils'
import { defineProvider } from '@nuxt/image/runtime/utils/provider'
export interface VideoCloudinaryModifiers extends ImageModifiers {
width: number
height: number
fit: string
format: string
quality: string
aspectRatio: string
so: string | number
duration: string | number
}
const operationsGenerator = createOperationsGenerator({
keyMap: {
width: 'w',
height: 'h',
fit: 'c',
format: 'f',
quality: 'q',
aspectRatio: 'ar',
so: 'so',
duration: 'du',
},
joinWith: ',',
formatter: (key, value) => encodePath(key.includes('_') ? `${key}:${value}` : `${key}_${value}`),
})
const defaultModifiers = {
format: 'auto',
quality: 'auto',
}
export default defineProvider({
getImage: (src, { modifiers, baseURL = '/' }) => {
const merged = defu(modifiers, defaultModifiers)
const operations = operationsGenerator(merged as any)
return {
url: joinURL(baseURL, operations, src),
}
},
})// nuxt.config.ts
image: {
providers: {
video: {
provider: '~/providers/video-cloudinary',
options: {
baseURL: `https://res.cloudinary.com/${process.env.CLD_CLOUD}/video/upload/`,
},
},
},
}Now |
Beta Was this translation helpful? Give feedback.
Hey @remihuigen
Few months late but dug into the source and the Cloudinary docs to figure out exactly what's happening. Looking at the Cloudinary provider source, the modifier pipeline works like this:
CloudinaryModifiersis the type interface;soanddurationaren't in it, hence your TS error.operationsGeneratorhas akeyMapthat converts modifier names to Cloudinary URL params;soisn't in there either, so even if you bypass the types, it never reaches the generated URL.So you need to solve both: make TypeScript accept the modifiers and make them actually reach the URL.
Option 1: Module augmentation + keyMap extension; Extend the types so TS is happy:
// types/nuxt-image-cloudinary.…