From 168702401270e1d8b8c8e915b42645faaedca677 Mon Sep 17 00:00:00 2001 From: ascorbic Date: Sat, 3 Feb 2024 09:57:17 +0000 Subject: [PATCH 01/17] feat: support Netlify Image CDN --- .gitignore | 3 ++ docs/pages/index.vue | 2 +- playground/nuxt.config.ts | 3 +- playground/providers.ts | 20 +++++++- src/provider.ts | 2 + src/runtime/providers/netlify.ts | 55 +++------------------- src/runtime/providers/netlifyImageCdn.ts | 53 +++++++++++++++++++++ src/runtime/providers/netlifyLargeMedia.ts | 50 ++++++++++++++++++++ 8 files changed, 136 insertions(+), 52 deletions(-) create mode 100644 src/runtime/providers/netlifyImageCdn.ts create mode 100644 src/runtime/providers/netlifyLargeMedia.ts diff --git a/.gitignore b/.gitignore index a23125d21..5c0b9ddff 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,6 @@ sw.* .idea .vercel .output + +# Local Netlify folder +.netlify diff --git a/docs/pages/index.vue b/docs/pages/index.vue index c41eba44d..469c61274 100644 --- a/docs/pages/index.vue +++ b/docs/pages/index.vue @@ -16,7 +16,7 @@ useSeoMeta({ const source = ref('npm i @nuxt/image') const { copy, copied } = useClipboard({ source }) -const providers = ['caisy', 'bunny', 'cloudflare', 'cloudimage', 'cloudinary', 'directus', 'edgio', 'fastly', 'glide', 'gumlet', 'hygraph', 'imageengine', 'imagekit', 'imgix', 'ipx', 'netlify', 'prepr', 'prismic', 'sanity', 'storyblok', 'strapi', 'twicpics', 'unsplash', 'uploadcare', 'vercel', 'weserv'] +const providers = ['caisy', 'bunny', 'cloudflare', 'cloudimage', 'cloudinary', 'directus', 'edgio', 'fastly', 'glide', 'gumlet', 'hygraph', 'imageengine', 'imagekit', 'imgix', 'ipx', 'netlify', 'netlifyImageCdn', 'netlifyLargeMedia', 'prepr', 'prismic', 'sanity', 'storyblok', 'strapi', 'twicpics', 'unsplash', 'uploadcare', 'vercel', 'weserv'] // Disabling because svg to png does not work now with SSG // Related issue: https://github.com/unjs/ipx/issues/160 // const img = useImage() diff --git a/playground/nuxt.config.ts b/playground/nuxt.config.ts index 0cb4268d6..27df8be5c 100644 --- a/playground/nuxt.config.ts +++ b/playground/nuxt.config.ts @@ -74,7 +74,8 @@ export default defineNuxtConfig({ imagekit: { baseURL: 'https://ik.imagekit.io/demo' }, - netlify: { + netlify: {}, + netlifyLargeMedia: { baseURL: 'https://netlify-photo-gallery.netlify.app' }, layer0: { diff --git a/playground/providers.ts b/playground/providers.ts index 23ecd3594..96bd785e3 100644 --- a/playground/providers.ts +++ b/playground/providers.ts @@ -338,12 +338,28 @@ export const providers: Provider[] = [ name: 'netlify', samples: [ { - src: '/images/apple.jpg', + src: '/images/colors.jpg', + width: 100, + height: 100, + fit: 'cover' + }, + { + src: '/images/colors.jpg', + width: 400, + height: 300 + } + ] + }, + { + name: 'netlifyLargeMedia', + samples: [ + { + src: '/images/colors.jpg', width: 101, fit: 'contain' }, { - src: '/images/apple.jpg', + src: '/images/colors.jpg', width: 200, height: 200, fit: 'fill' diff --git a/src/provider.ts b/src/provider.ts index 7eab191bf..67ad1f110 100644 --- a/src/provider.ts +++ b/src/provider.ts @@ -32,6 +32,8 @@ const BuiltInProviders = [ 'ipxStatic', 'layer0', 'netlify', + 'netlifyLargeMedia', + 'netlifyImageCdn', 'prepr', 'none', 'prismic', diff --git a/src/runtime/providers/netlify.ts b/src/runtime/providers/netlify.ts index 36b84c13b..c75659e5b 100644 --- a/src/runtime/providers/netlify.ts +++ b/src/runtime/providers/netlify.ts @@ -1,50 +1,9 @@ -import { joinURL } from 'ufo' -import type { ProviderGetImage } from '../../types' -import { createOperationsGenerator } from '#image' +import { getImage as largeMediaGetImage, operationsGenerator as largeMediaOptionsGenerator } from './netlifyLargeMedia' +import { getImage as cdnGetImage, operationsGenerator as cdnOptionsGenerator } from './netlifyImageCdn' -export const operationsGenerator = createOperationsGenerator({ - keyMap: { - height: 'h', - fit: 'nf_resize', - width: 'w' - }, - valueMap: { - fit: { - fill: 'smartcrop', - contain: 'fit' - } - }, - joinWith: '&', - formatter: (key, value) => `${key}=${value}` -}) +// If the site has the deprecated Netlify Large Media enabled we will use the old +// Large Media adapter. Otherwise, we will use the Netlify Image CDN +const hasLargeMedia = Boolean(process.env.NETLIFY_LFS_ORIGIN_URL) -const isDev = process.env.NODE_ENV === 'development' - -// https://docs.netlify.com/large-media/transform-images/ - -export const getImage: ProviderGetImage = (src, { modifiers = {}, baseURL = '/' } = {}) => { - if (modifiers.format) { - // Not currently supported - delete modifiers.format - } - const hasTransformation = modifiers.height || modifiers.width - if (!modifiers.fit && hasTransformation) { - // fit is required for resizing images - modifiers.fit = 'contain' - } - if (hasTransformation && modifiers.fit !== 'contain' && !(modifiers.height && modifiers.width)) { - // smartcrop is only supported with both height and width - if (isDev) { - // eslint-disable-next-line - console.warn(`Defaulting to fit=contain as smart cropping is only supported when providing both height and width. Warning originated from \`${src}\`.`) - } - modifiers.fit = 'contain' - } - if (isDev) { - return { url: src } - } - const operations = operationsGenerator(modifiers) - return { - url: joinURL(baseURL, src + (operations ? ('?' + operations) : '')) - } -} +export const getImage = hasLargeMedia ? largeMediaGetImage : cdnGetImage +export const operationsGenerator = hasLargeMedia ? largeMediaOptionsGenerator : cdnOptionsGenerator diff --git a/src/runtime/providers/netlifyImageCdn.ts b/src/runtime/providers/netlifyImageCdn.ts new file mode 100644 index 000000000..d6e7138bd --- /dev/null +++ b/src/runtime/providers/netlifyImageCdn.ts @@ -0,0 +1,53 @@ +import { joinURL } from 'ufo' +import type { ProviderGetImage } from '../../types' +import { createOperationsGenerator } from '#image' + +// https://docs.netlify.com/image-cdn/overview/ +export const operationsGenerator = createOperationsGenerator({ + keyMap: { + width: 'w', + height: 'h', + format: 'fm', + quality: 'q', + position: 'position', + fit: 'fit' + }, + valueMap: { + fit: { + fill: 'fill', + cover: 'cover', + contain: 'contain' + }, + format: { + avif: 'avif', + gif: 'gif', + jpg: 'jpg', + png: 'png', + webp: 'webp' + }, + position: { + top: 'top', + right: 'right', + bottom: 'bottom', + left: 'left', + center: 'center' + } + }, + joinWith: '&', + formatter: (key: string, value: string) => `${key}=${value ?? ''}` +}) + +export const getImage: ProviderGetImage = (src, { modifiers = {}, baseURL = '/.netlify/images' } = {}) => { + const mods: Record = { ...modifiers } + mods.url = src + if (modifiers.width) { + mods.width = modifiers.width.toString() + } + if (modifiers.height) { + mods.height = modifiers.height.toString() + } + const operations = operationsGenerator(mods) + return { + url: `${baseURL}?${operations}` + } +} diff --git a/src/runtime/providers/netlifyLargeMedia.ts b/src/runtime/providers/netlifyLargeMedia.ts new file mode 100644 index 000000000..f0f207ab8 --- /dev/null +++ b/src/runtime/providers/netlifyLargeMedia.ts @@ -0,0 +1,50 @@ +import { joinURL } from 'ufo' +import type { ProviderGetImage } from '../../types' +import { createOperationsGenerator } from '#image' + +export const operationsGenerator = createOperationsGenerator({ + keyMap: { + height: 'h', + fit: 'nf_resize', + width: 'w' + }, + valueMap: { + fit: { + fill: 'smartcrop', + contain: 'fit' + } + }, + joinWith: '&', + formatter: (key: string, value: string) => `${key}=${value}` +}) + +const isDev = process.env.NODE_ENV === 'development' + +// https://docs.netlify.com/large-media/transform-images/ + +export const getImage: ProviderGetImage = (src, { modifiers = {}, baseURL = '/' } = {}) => { + if (modifiers.format) { + // Not currently supported + delete modifiers.format + } + const hasTransformation = modifiers.height || modifiers.width + if (!modifiers.fit && hasTransformation) { + // fit is required for resizing images + modifiers.fit = 'contain' + } + if (hasTransformation && modifiers.fit !== 'contain' && !(modifiers.height && modifiers.width)) { + // smartcrop is only supported with both height and width + if (isDev) { + // eslint-disable-next-line + console.warn(`Defaulting to fit=contain as smart cropping is only supported when providing both height and width. Warning originated from \`${src}\`.`) + } + modifiers.fit = 'contain' + } + if (isDev) { + return { url: src } + } + const operations = operationsGenerator(modifiers) + return { + url: joinURL(baseURL, src + (operations ? ('?' + operations) : '')) + } +} From 46b1225fe15daf7208f98f4d05cfbae0615a200b Mon Sep 17 00:00:00 2001 From: Matt Kane Date: Wed, 7 Feb 2024 14:26:09 +0000 Subject: [PATCH 02/17] chore: add tests --- playground/providers.ts | 16 ++++++++++++++++ src/runtime/providers/netlifyImageCdn.ts | 5 ++--- test/providers.ts | 24 ++++++++++++++++++------ 3 files changed, 36 insertions(+), 9 deletions(-) diff --git a/playground/providers.ts b/playground/providers.ts index 96bd785e3..642b4d54b 100644 --- a/playground/providers.ts +++ b/playground/providers.ts @@ -350,6 +350,22 @@ export const providers: Provider[] = [ } ] }, + { + name: 'netlifyImageCdn', + samples: [ + { + src: '/images/colors.jpg', + width: 100, + height: 100, + fit: 'cover' + }, + { + src: '/images/colors.jpg', + width: 400, + height: 300 + } + ] + }, { name: 'netlifyLargeMedia', samples: [ diff --git a/src/runtime/providers/netlifyImageCdn.ts b/src/runtime/providers/netlifyImageCdn.ts index d6e7138bd..0c992be5d 100644 --- a/src/runtime/providers/netlifyImageCdn.ts +++ b/src/runtime/providers/netlifyImageCdn.ts @@ -1,4 +1,3 @@ -import { joinURL } from 'ufo' import type { ProviderGetImage } from '../../types' import { createOperationsGenerator } from '#image' @@ -37,7 +36,7 @@ export const operationsGenerator = createOperationsGenerator({ formatter: (key: string, value: string) => `${key}=${value ?? ''}` }) -export const getImage: ProviderGetImage = (src, { modifiers = {}, baseURL = '/.netlify/images' } = {}) => { +export const getImage: ProviderGetImage = (src, { modifiers = {}, baseURL } = {}) => { const mods: Record = { ...modifiers } mods.url = src if (modifiers.width) { @@ -48,6 +47,6 @@ export const getImage: ProviderGetImage = (src, { modifiers = {}, baseURL = '/.n } const operations = operationsGenerator(mods) return { - url: `${baseURL}?${operations}` + url: `${baseURL || '/.netlify/images'}?${operations}` } } diff --git a/test/providers.ts b/test/providers.ts index c1f8ff7d0..97528c7af 100644 --- a/test/providers.ts +++ b/test/providers.ts @@ -15,7 +15,9 @@ export const images = [ imageengine: { url: '/test.png' }, unsplash: { url: '/test.png' }, imagekit: { url: '/test.png' }, - netlify: { url: '/test.png' }, + netlify: { url: '/.netlify/images?url=/test.png' }, + netlifyImageCdn: { url: '/.netlify/images?url=/test.png' }, + netlifyLargeMedia: { url: '/test.png' }, prepr: { url: 'https://projectName.stream.prepr.io/image-test-300x450-png' }, prismic: { url: '/test.png?auto=compress,format&rect=0,0,200,200&w=100&h=100' }, sanity: { url: 'https://cdn.sanity.io/images/projectid/production/test-300x450.png?auto=format' }, @@ -49,7 +51,9 @@ export const images = [ imageengine: { url: '/test.png?imgeng=/w_200' }, unsplash: { url: '/test.png?w=200' }, imagekit: { url: '/test.png?tr=w-200' }, - netlify: { url: '/test.png?w=200&nf_resize=fit' }, + netlify: { url: '/.netlify/images?w=200&url=/test.png' }, + netlifyImageCdn: { url: '/.netlify/images?w=200&url=/test.png' }, + netlifyLargeMedia: { url: '/test.png?w=200&nf_resize=fit' }, prepr: { url: 'https://projectName.stream.prepr.io/w_200/image-test-300x450-png' }, prismic: { url: '/test.png?auto=compress,format&rect=0,0,200,200&w=200&h=100' }, sanity: { url: 'https://cdn.sanity.io/images/projectid/production/test-300x450.png?w=200&auto=format' }, @@ -83,7 +87,9 @@ export const images = [ imageengine: { url: '/test.png?imgeng=/h_200' }, unsplash: { url: '/test.png?h=200' }, imagekit: { url: '/test.png?tr=h-200' }, - netlify: { url: '/test.png?h=200&nf_resize=fit' }, + netlify: { url: '/.netlify/images?h=200&url=/test.png' }, + netlifyImageCdn: { url: '/.netlify/images?h=200&url=/test.png' }, + netlifyLargeMedia: { url: '/test.png?h=200&nf_resize=fit' }, prepr: { url: 'https://projectName.stream.prepr.io/h_200/image-test-300x450-png' }, prismic: { url: '/test.png?auto=compress,format&rect=0,0,200,200&w=100&h=200' }, sanity: { url: 'https://cdn.sanity.io/images/projectid/production/test-300x450.png?h=200&auto=format' }, @@ -117,7 +123,9 @@ export const images = [ imageengine: { url: '/test.png?imgeng=/w_200/h_200' }, unsplash: { url: '/test.png?w=200&h=200' }, imagekit: { url: '/test.png?tr=w-200,h-200' }, - netlify: { url: '/test.png?w=200&h=200&nf_resize=fit' }, + netlify: { url: '/.netlify/images?w=200&h=200&url=/test.png' }, + netlifyImageCdn: { url: '/.netlify/images?w=200&h=200&url=/test.png' }, + netlifyLargeMedia: { url: '/test.png?w=200&h=200&nf_resize=fit' }, prismic: { url: '/test.png?auto=compress,format&rect=0,0,200,200&w=200&h=200' }, prepr: { url: 'https://projectName.stream.prepr.io/w_200,h_200/image-test-300x450-png' }, sanity: { url: 'https://cdn.sanity.io/images/projectid/production/test-300x450.png?w=200&h=200&auto=format' }, @@ -151,7 +159,9 @@ export const images = [ imageengine: { url: '/test.png?imgeng=/w_200/h_200/m_letterbox' }, unsplash: { url: '/test.png?w=200&h=200&fit=fill' }, imagekit: { url: '/test.png?tr=w-200,h-200,cm-pad_resize' }, - netlify: { url: '/test.png?w=200&h=200&nf_resize=fit' }, + netlify: { url: '/.netlify/images?w=200&h=200&fit=contain&url=/test.png' }, + netlifyImageCdn: { url: '/.netlify/images?w=200&h=200&fit=contain&url=/test.png' }, + netlifyLargeMedia: { url: '/test.png?w=200&h=200&nf_resize=fit' }, prismic: { url: '/test.png?auto=compress,format&rect=0,0,200,200&w=200&h=200&fit=fill' }, prepr: { url: 'https://projectName.stream.prepr.io/w_200,h_200,fit_contain/image-test-300x450-png' }, sanity: { url: 'https://cdn.sanity.io/images/projectid/production/test-300x450.png?w=200&h=200&fit=fill&auto=format&bg=ffffff' }, @@ -185,7 +195,9 @@ export const images = [ imageengine: { url: '/test.png?imgeng=/w_200/h_200/m_letterbox/f_jpg' }, unsplash: { url: '/test.png?w=200&h=200&fit=fill&fm=jpeg' }, imagekit: { url: '/test.png?tr=w-200,h-200,cm-pad_resize,f-jpeg' }, - netlify: { url: '/test.png?w=200&h=200&nf_resize=fit' }, + netlify: { url: '/.netlify/images?w=200&h=200&fit=contain&fm=jpeg&url=/test.png' }, + netlifyImageCdn: { url: '/.netlify/images?w=200&h=200&fit=contain&fm=jpeg&url=/test.png' }, + netlifyLargeMedia: { url: '/test.png?w=200&h=200&nf_resize=fit' }, prismic: { url: '/test.png?auto=compress,format&rect=0,0,200,200&w=200&h=200&fit=fill&fm=jpeg' }, sanity: { url: 'https://cdn.sanity.io/images/projectid/production/test-300x450.png?w=200&h=200&fit=fill&fm=jpg&bg=ffffff' }, prepr: { url: 'https://projectName.stream.prepr.io/w_200,h_200,fit_contain,format_jpg/image-test-300x450-png' }, From 186d67dffce92b455ca46ff61919292144f6e3f3 Mon Sep 17 00:00:00 2001 From: Kristen Lavavej <35638702+klavavej@users.noreply.github.com> Date: Wed, 7 Feb 2024 11:17:00 -0800 Subject: [PATCH 03/17] Update netlify.md --- docs/content/3.providers/netlify.md | 63 +++++++++++++++++++++++++---- 1 file changed, 55 insertions(+), 8 deletions(-) diff --git a/docs/content/3.providers/netlify.md b/docs/content/3.providers/netlify.md index 121707208..c37d4fab7 100644 --- a/docs/content/3.providers/netlify.md +++ b/docs/content/3.providers/netlify.md @@ -8,21 +8,68 @@ links: size: xs --- +When deploying your Nuxt applications to [Netlify's composable platform](https://docs.netlify.com/platform/overview/), the image module can use [Netlify Image CDN](https://docs.netlify.com/image-cdn/overview/) to optimize and transform images on demand without impacting build times. Netlify Image CDN also handles content negotiation to use the most efficient image format for the requesting client. + +To use Netlify Image CDN by default, add the following to your Nuxt configuration: + +```ts [nuxt.config.ts] +export default defineNuxtConfig({ + image: { + provider: 'netlify', + } +}) +``` + +## Remote images + +To transform a source image hosted on another domain, you must first configure allowed domains in your `netlify.toml` file. + +```toml [netlify.toml] +[images] + remote_images = ["https://my-images.com/.*", "https://animals.more-images.com/[bcr]at/.*"] +``` + +The `remote_images` property accepts an array of regex. If your images are in specific subdomains or directories, you can use regex to allow just those subdomains or directories. + +## Modifiers + +In addition to the [standard modifiers](https://image.nuxt.com/usage/nuxt-img#modifiers), all of the [Netlify Image CDN transformation options](https://docs.netlify.com/image-cdn/overview/#transform-images) are available as modifiers for Nuxt Image. + +```vue + +``` + +## Deprecated Netlify Large Media option + ::callout{color="amber" icon="i-ph-warning-duotone"} -Netlify’s Large Media service is [deprecated](https://answers.netlify.com/t/large-media-feature-deprecated-but-not-removed/100804). If this feature is already enabled, Large Media will continue to work on these sites as usual. New Large Media configuration is not recommended. +Netlify’s Large Media service is [deprecated](https://answers.netlify.com/t/large-media-feature-deprecated-but-not-removed/100804). If this feature is already enabled for your site on Netlify and you have already set `provider: 'netlify'` in your Nuxt configuration, then Large Media continues to work on your site as usual. However, new Large Media configuration is not recommended. :: -Netlify offers dynamic image transformation for all JPEG, PNG, and GIF files you have set to be tracked with [Netlify Large Media](https://docs.netlify.com/large-media/overview/). +### Migrate to Netlify Image CDN -::callout -Before setting `provider: 'netlify'`, make sure you have followed the steps to enable [Netlify Large Media](https://docs.netlify.com/large-media/overview/). -:: +To migrate from the deprecated Netlify Large Media option to the more robust Netlify Image CDN option, change `provider: 'netlify'` to `provider: 'netlifyImageCdn'`. -## Modifiers -In addition to `height` and `width`, the Netlify provider supports the following modifiers: +### Use deprecated Netlify Large Media option + +If you're not ready to migrate to the more robust Netlify Image CDN option, Netlify continues to support dynamic image transformation for all JPEG, PNG, and GIF files you have set to be tracked with [Netlify Large Media](https://docs.netlify.com/large-media/overview/). + +#### Large Media Modifiers + +In addition to `height` and `width`, the deprecated Netlify Large Media provider supports the following modifiers: -### `fit` +##### `fit` * **Default**: `contain` * **Valid options**: `contain` (equivalent to `nf_resize=fit`) and `fill` (equivalent to `nf_resize=smartcrop`) From 8b3bbd0a37c90c61206c36f908c5f7a6013be02c Mon Sep 17 00:00:00 2001 From: Kristen Lavavej <35638702+klavavej@users.noreply.github.com> Date: Wed, 7 Feb 2024 12:21:07 -0800 Subject: [PATCH 04/17] Update docs/content/3.providers/netlify.md --- docs/content/3.providers/netlify.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/content/3.providers/netlify.md b/docs/content/3.providers/netlify.md index c37d4fab7..ebfbf48f4 100644 --- a/docs/content/3.providers/netlify.md +++ b/docs/content/3.providers/netlify.md @@ -33,7 +33,7 @@ The `remote_images` property accepts an array of regex. If your images are in sp ## Modifiers -In addition to the [standard modifiers](https://image.nuxt.com/usage/nuxt-img#modifiers), all of the [Netlify Image CDN transformation options](https://docs.netlify.com/image-cdn/overview/#transform-images) are available as modifiers for Nuxt Image. +In addition to the [standard properties](https://image.nuxt.com/usage/nuxt-img), all of the [Netlify Image CDN transformation options](https://docs.netlify.com/image-cdn/overview/#transform-images) are available as modifiers for Nuxt Image. ```vue Date: Thu, 8 Feb 2024 08:59:33 +0000 Subject: [PATCH 05/17] fix: detect at build time --- playground/providers.ts | 17 ----------------- src/provider.ts | 13 ++++++++++++- src/runtime/providers/netlify.ts | 9 --------- 3 files changed, 12 insertions(+), 27 deletions(-) delete mode 100644 src/runtime/providers/netlify.ts diff --git a/playground/providers.ts b/playground/providers.ts index 642b4d54b..8e1e82d21 100644 --- a/playground/providers.ts +++ b/playground/providers.ts @@ -333,23 +333,6 @@ export const providers: Provider[] = [ } ] }, - // Netlify - { - name: 'netlify', - samples: [ - { - src: '/images/colors.jpg', - width: 100, - height: 100, - fit: 'cover' - }, - { - src: '/images/colors.jpg', - width: 400, - height: 300 - } - ] - }, { name: 'netlifyImageCdn', samples: [ diff --git a/src/provider.ts b/src/provider.ts index 67ad1f110..74ac4f65d 100644 --- a/src/provider.ts +++ b/src/provider.ts @@ -120,6 +120,10 @@ export async function resolveProvider (_nuxt: any, key: string, input: InputProv input.provider = input.name } + if (input.provider in normalizableProviders) { + input.provider = normalizableProviders[input.provider]!() + } + const resolver = createResolver(import.meta.url) input.provider = BuiltInProviders.includes(input.provider as ImageProviderName) ? await resolver.resolve('./runtime/providers/' + input.provider) @@ -138,7 +142,14 @@ export async function resolveProvider (_nuxt: any, key: string, input: InputProv const autodetectableProviders: Partial> = { vercel: 'vercel', - aws_amplify: 'awsAmplify' + aws_amplify: 'awsAmplify', + netlify: 'netlify' +} + +const normalizableProviders: Partial ImageProviderName>> = { + netlify: () => { + return process.env.NETLIFY_LFS_ORIGIN_URL ? 'netlifyLargeMedia' : 'netlifyImageCdn' + } } export function detectProvider (userInput: string = '') { diff --git a/src/runtime/providers/netlify.ts b/src/runtime/providers/netlify.ts deleted file mode 100644 index c75659e5b..000000000 --- a/src/runtime/providers/netlify.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { getImage as largeMediaGetImage, operationsGenerator as largeMediaOptionsGenerator } from './netlifyLargeMedia' -import { getImage as cdnGetImage, operationsGenerator as cdnOptionsGenerator } from './netlifyImageCdn' - -// If the site has the deprecated Netlify Large Media enabled we will use the old -// Large Media adapter. Otherwise, we will use the Netlify Image CDN -const hasLargeMedia = Boolean(process.env.NETLIFY_LFS_ORIGIN_URL) - -export const getImage = hasLargeMedia ? largeMediaGetImage : cdnGetImage -export const operationsGenerator = hasLargeMedia ? largeMediaOptionsGenerator : cdnOptionsGenerator From d5868a09a02e0e0bacdbd3fc775d8aeb05258bc5 Mon Sep 17 00:00:00 2001 From: Kristen Lavavej <35638702+klavavej@users.noreply.github.com> Date: Thu, 8 Feb 2024 08:51:59 -0800 Subject: [PATCH 06/17] edits based on feedback --- docs/content/3.providers/netlify.md | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/docs/content/3.providers/netlify.md b/docs/content/3.providers/netlify.md index ebfbf48f4..b63572f03 100644 --- a/docs/content/3.providers/netlify.md +++ b/docs/content/3.providers/netlify.md @@ -8,9 +8,11 @@ links: size: xs --- -When deploying your Nuxt applications to [Netlify's composable platform](https://docs.netlify.com/platform/overview/), the image module can use [Netlify Image CDN](https://docs.netlify.com/image-cdn/overview/) to optimize and transform images on demand without impacting build times. Netlify Image CDN also handles content negotiation to use the most efficient image format for the requesting client. +When deploying your Nuxt applications to [Netlify's composable platform](https://docs.netlify.com/platform/overview/), the image module uses [Netlify Image CDN](https://docs.netlify.com/image-cdn/overview/) to optimize and transform images on demand without impacting build times. Netlify Image CDN also handles content negotiation to use the most efficient image format for the requesting client. -To use Netlify Image CDN by default, add the following to your Nuxt configuration: +This provider is automatically enabled in Netlify deployments. + +You can also manually enable this provider for sites deployed on other platforms. To do so, add the following to your Nuxt configuration: ```ts [nuxt.config.ts] export default defineNuxtConfig({ @@ -20,6 +22,10 @@ export default defineNuxtConfig({ }) ``` +::callout +If you manually enable the `netlify` provider and want to test image transformations locally, use [Netlify Dev](https://docs.netlify.com/cli/local-development/). This feature of the Netlify CLI runs a local development server that mimics Netlify Image CDN. +::: + ## Remote images To transform a source image hosted on another domain, you must first configure allowed domains in your `netlify.toml` file. @@ -33,20 +39,18 @@ The `remote_images` property accepts an array of regex. If your images are in sp ## Modifiers -In addition to the [standard properties](https://image.nuxt.com/usage/nuxt-img), all of the [Netlify Image CDN transformation options](https://docs.netlify.com/image-cdn/overview/#transform-images) are available as modifiers for Nuxt Image. +Beyond the [standard properties](https://image.nuxt.com/usage/nuxt-img), you can use the [Netlify Image CDN `position` parameter](https://docs.netlify.com/image-cdn/overview/#positions) as a modifier for Nuxt Image. ```vue ``` From 0bf0a7028e5656df2ffa72a239eeb96b68040295 Mon Sep 17 00:00:00 2001 From: Kristen Lavavej <35638702+klavavej@users.noreply.github.com> Date: Thu, 8 Feb 2024 08:59:36 -0800 Subject: [PATCH 07/17] Update netlify.md --- docs/content/3.providers/netlify.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/content/3.providers/netlify.md b/docs/content/3.providers/netlify.md index b63572f03..534f5c3c0 100644 --- a/docs/content/3.providers/netlify.md +++ b/docs/content/3.providers/netlify.md @@ -24,7 +24,7 @@ export default defineNuxtConfig({ ::callout If you manually enable the `netlify` provider and want to test image transformations locally, use [Netlify Dev](https://docs.netlify.com/cli/local-development/). This feature of the Netlify CLI runs a local development server that mimics Netlify Image CDN. -::: +:: ## Remote images From 546a86f89be5f0565029e2ecb7c01f50e893375e Mon Sep 17 00:00:00 2001 From: Kristen Lavavej <35638702+klavavej@users.noreply.github.com> Date: Thu, 8 Feb 2024 09:01:43 -0800 Subject: [PATCH 08/17] typo --- docs/content/3.providers/netlify.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/content/3.providers/netlify.md b/docs/content/3.providers/netlify.md index 534f5c3c0..8f5d011d7 100644 --- a/docs/content/3.providers/netlify.md +++ b/docs/content/3.providers/netlify.md @@ -39,7 +39,7 @@ The `remote_images` property accepts an array of regex. If your images are in sp ## Modifiers -Beyond the [standard properties](https://image.nuxt.com/usage/nuxt-img), you can use the [Netlify Image CDN `position` parameter](https://docs.netlify.com/image-cdn/overview/#positions) as a modifier for Nuxt Image. +Beyond the [standard properties](https://image.nuxt.com/usage/nuxt-img), you can use the [Netlify Image CDN `position` parameter](https://docs.netlify.com/image-cdn/overview/#position) as a modifier for Nuxt Image. ```vue Date: Thu, 8 Feb 2024 09:14:32 -0800 Subject: [PATCH 09/17] different take on manual enablement --- docs/content/3.providers/netlify.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/content/3.providers/netlify.md b/docs/content/3.providers/netlify.md index 8f5d011d7..2a485d7ff 100644 --- a/docs/content/3.providers/netlify.md +++ b/docs/content/3.providers/netlify.md @@ -12,7 +12,9 @@ When deploying your Nuxt applications to [Netlify's composable platform](https:/ This provider is automatically enabled in Netlify deployments. -You can also manually enable this provider for sites deployed on other platforms. To do so, add the following to your Nuxt configuration: +## Local development + +You can also manually enable this provider for local development. To do so, add the following to your Nuxt configuration: ```ts [nuxt.config.ts] export default defineNuxtConfig({ @@ -22,9 +24,7 @@ export default defineNuxtConfig({ }) ``` -::callout -If you manually enable the `netlify` provider and want to test image transformations locally, use [Netlify Dev](https://docs.netlify.com/cli/local-development/). This feature of the Netlify CLI runs a local development server that mimics Netlify Image CDN. -:: +Then, to test image transformations locally, use [Netlify Dev](https://docs.netlify.com/cli/local-development/). This feature of the Netlify CLI runs a local development server that mimics the Netlify production environment, including Netlify Image CDN. ## Remote images From 573e42e5151f9eff47a9dab474cfcd8db6753e75 Mon Sep 17 00:00:00 2001 From: Matt Kane Date: Fri, 9 Feb 2024 12:38:53 +0000 Subject: [PATCH 10/17] chore: update doc --- docs/content/3.providers/netlify.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/content/3.providers/netlify.md b/docs/content/3.providers/netlify.md index 2a485d7ff..bbfe07419 100644 --- a/docs/content/3.providers/netlify.md +++ b/docs/content/3.providers/netlify.md @@ -10,11 +10,9 @@ links: When deploying your Nuxt applications to [Netlify's composable platform](https://docs.netlify.com/platform/overview/), the image module uses [Netlify Image CDN](https://docs.netlify.com/image-cdn/overview/) to optimize and transform images on demand without impacting build times. Netlify Image CDN also handles content negotiation to use the most efficient image format for the requesting client. -This provider is automatically enabled in Netlify deployments. +This provider is automatically enabled in Netlify deployments, and also when running locally using [the Netlify CLI](https://docs.netlify.com/cli/local-development/). -## Local development - -You can also manually enable this provider for local development. To do so, add the following to your Nuxt configuration: +You can also manually enable this provider. To do so, set the provider to `netlify` or add the following to your Nuxt configuration: ```ts [nuxt.config.ts] export default defineNuxtConfig({ @@ -24,7 +22,9 @@ export default defineNuxtConfig({ }) ``` -Then, to test image transformations locally, use [Netlify Dev](https://docs.netlify.com/cli/local-development/). This feature of the Netlify CLI runs a local development server that mimics the Netlify production environment, including Netlify Image CDN. +## Local development + +To test image transformations locally, use [Netlify Dev](https://docs.netlify.com/cli/local-development/). This feature of the Netlify CLI runs a local development server that mimics the Netlify production environment, including Netlify Image CDN. ## Remote images @@ -57,12 +57,12 @@ Beyond the [standard properties](https://image.nuxt.com/usage/nuxt-img), you can ## Deprecated Netlify Large Media option ::callout{color="amber" icon="i-ph-warning-duotone"} -Netlify’s Large Media service is [deprecated](https://answers.netlify.com/t/large-media-feature-deprecated-but-not-removed/100804). If this feature is already enabled for your site on Netlify and you have already set `provider: 'netlify'` in your Nuxt configuration, then Large Media continues to work on your site as usual. However, new Large Media configuration is not recommended. +Netlify’s Large Media service is [deprecated](https://answers.netlify.com/t/large-media-feature-deprecated-but-not-removed/100804). If this feature is already enabled for your site on Netlify and you have already set `provider: 'netlify'` in your Nuxt configuration, then this will be detected at build time and Large Media continues to work on your site as usual. You can also explicitly enable it by setting `provider: 'netlifyLargeMedia'`. However, new Large Media configuration is not recommended. :: ### Migrate to Netlify Image CDN -To migrate from the deprecated Netlify Large Media option to the more robust Netlify Image CDN option, change `provider: 'netlify'` to `provider: 'netlifyImageCdn'`. +To migrate from the deprecated Netlify Large Media option to the more robust Netlify Image CDN option, change `provider: 'netlify'` to `provider: 'netlifyImageCdn'`. This will enable the Netlify Image CDN service, even if large media is enabled on your site. ### Use deprecated Netlify Large Media option From 8a61fe6ada5d7d65f0bde26d9b5803ce514f05be Mon Sep 17 00:00:00 2001 From: Matt Kane Date: Wed, 14 Feb 2024 11:10:16 +0000 Subject: [PATCH 11/17] chore: update tests --- playground/nuxt.config.ts | 4 +++- playground/providers.ts | 8 ++++---- test/e2e/__snapshots__/ssr.test.ts.snap | 18 ++++++++++++++++-- 3 files changed, 23 insertions(+), 7 deletions(-) diff --git a/playground/nuxt.config.ts b/playground/nuxt.config.ts index 27df8be5c..8a8527239 100644 --- a/playground/nuxt.config.ts +++ b/playground/nuxt.config.ts @@ -74,7 +74,9 @@ export default defineNuxtConfig({ imagekit: { baseURL: 'https://ik.imagekit.io/demo' }, - netlify: {}, + netlifyImageCdn: { + baseURL: 'https://netlify-photo-gallery.netlify.app' + }, netlifyLargeMedia: { baseURL: 'https://netlify-photo-gallery.netlify.app' }, diff --git a/playground/providers.ts b/playground/providers.ts index 8e1e82d21..22d26bba3 100644 --- a/playground/providers.ts +++ b/playground/providers.ts @@ -337,13 +337,13 @@ export const providers: Provider[] = [ name: 'netlifyImageCdn', samples: [ { - src: '/images/colors.jpg', + src: '/images/apple.jpg', width: 100, height: 100, fit: 'cover' }, { - src: '/images/colors.jpg', + src: '/images/apple.jpg', width: 400, height: 300 } @@ -353,12 +353,12 @@ export const providers: Provider[] = [ name: 'netlifyLargeMedia', samples: [ { - src: '/images/colors.jpg', + src: '/images/apple.jpg', width: 101, fit: 'contain' }, { - src: '/images/colors.jpg', + src: '/images/apple.jpg', width: 200, height: 200, fit: 'fill' diff --git a/test/e2e/__snapshots__/ssr.test.ts.snap b/test/e2e/__snapshots__/ssr.test.ts.snap index ba6e3bd4c..072c03898 100644 --- a/test/e2e/__snapshots__/ssr.test.ts.snap +++ b/test/e2e/__snapshots__/ssr.test.ts.snap @@ -286,14 +286,28 @@ exports[`browser (ssr: true) > layer0 should render images 2`] = ` ] `; -exports[`browser (ssr: true) > netlify should render images 1`] = ` +exports[`browser (ssr: true) > netlifyImageCdn should render images 1`] = ` +[ + "https://netlify-photo-gallery.netlify.app?w=100&h=100&fit=cover&url=/images/apple.jpg", + "https://netlify-photo-gallery.netlify.app?w=400&h=300&url=/images/apple.jpg", +] +`; + +exports[`browser (ssr: true) > netlifyImageCdn should render images 2`] = ` +[ + "https://netlify-photo-gallery.netlify.app/?w=400&h=300&url=/images/apple.jpg", + "https://netlify-photo-gallery.netlify.app/?w=100&h=100&fit=cover&url=/images/apple.jpg", +] +`; + +exports[`browser (ssr: true) > netlifyLargeMedia should render images 1`] = ` [ "https://netlify-photo-gallery.netlify.app/images/apple.jpg?w=101&nf_resize=fit", "https://netlify-photo-gallery.netlify.app/images/apple.jpg?w=200&h=200&nf_resize=smartcrop", ] `; -exports[`browser (ssr: true) > netlify should render images 2`] = ` +exports[`browser (ssr: true) > netlifyLargeMedia should render images 2`] = ` [ "https://netlify-photo-gallery.netlify.app/images/apple.jpg?w=101&nf_resize=fit", "https://netlify-photo-gallery.netlify.app/images/apple.jpg?w=200&h=200&nf_resize=smartcrop", From 21f186054e11a1f8a536e56d18d36acd456582bd Mon Sep 17 00:00:00 2001 From: Matt Kane Date: Wed, 14 Feb 2024 11:12:57 +0000 Subject: [PATCH 12/17] chore: update no-ssr test --- test/e2e/__snapshots__/no-ssr.test.ts.snap | 26 +++++++++++++++++----- 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/test/e2e/__snapshots__/no-ssr.test.ts.snap b/test/e2e/__snapshots__/no-ssr.test.ts.snap index 333d811ff..1edef0d7a 100644 --- a/test/e2e/__snapshots__/no-ssr.test.ts.snap +++ b/test/e2e/__snapshots__/no-ssr.test.ts.snap @@ -20,13 +20,13 @@ exports[`browser (ssr: false) > aliyun should render images 2`] = ` exports[`browser (ssr: false) > awsAmplify should render images 1`] = ` [ - "https://example.amplifyapp.com/_amplify/image?url=%2Ftest.jpg&w=320&q=100", + "https://example.amplifyapp.com/_amplify/image?url=/test.jpg&w=320&q=100", ] `; exports[`browser (ssr: false) > awsAmplify should render images 2`] = ` [ - "https://example.amplifyapp.com/_amplify/image?url=%2Ftest.jpg&w=320&q=100", + "https://example.amplifyapp.com/_amplify/image?url=/test.jpg&w=320&q=100", ] `; @@ -286,14 +286,28 @@ exports[`browser (ssr: false) > layer0 should render images 2`] = ` ] `; -exports[`browser (ssr: false) > netlify should render images 1`] = ` +exports[`browser (ssr: false) > netlifyImageCdn should render images 1`] = ` +[ + "https://netlify-photo-gallery.netlify.app?w=100&h=100&fit=cover&url=/images/apple.jpg", + "https://netlify-photo-gallery.netlify.app?w=400&h=300&url=/images/apple.jpg", +] +`; + +exports[`browser (ssr: false) > netlifyImageCdn should render images 2`] = ` +[ + "https://netlify-photo-gallery.netlify.app/?w=100&h=100&fit=cover&url=/images/apple.jpg", + "https://netlify-photo-gallery.netlify.app/?w=400&h=300&url=/images/apple.jpg", +] +`; + +exports[`browser (ssr: false) > netlifyLargeMedia should render images 1`] = ` [ "https://netlify-photo-gallery.netlify.app/images/apple.jpg?w=101&nf_resize=fit", "https://netlify-photo-gallery.netlify.app/images/apple.jpg?w=200&h=200&nf_resize=smartcrop", ] `; -exports[`browser (ssr: false) > netlify should render images 2`] = ` +exports[`browser (ssr: false) > netlifyLargeMedia should render images 2`] = ` [ "https://netlify-photo-gallery.netlify.app/images/apple.jpg?w=101&nf_resize=fit", "https://netlify-photo-gallery.netlify.app/images/apple.jpg?w=200&h=200&nf_resize=smartcrop", @@ -573,13 +587,13 @@ exports[`browser (ssr: false) > uploadcare should render images 2`] = ` exports[`browser (ssr: false) > vercel should render images 1`] = ` [ - "https://image-component.nextjs.gallery/_next/image?url=%2Fcolors.jpg&w=750&q=75", + "https://image-component.nextjs.gallery/_next/image?url=/colors.jpg&w=750&q=75", ] `; exports[`browser (ssr: false) > vercel should render images 2`] = ` [ - "https://image-component.nextjs.gallery/_next/image?url=%2Fcolors.jpg&w=750&q=75", + "https://image-component.nextjs.gallery/_next/image?url=/colors.jpg&w=750&q=75", ] `; From 10006eba1207c859f38e23a52e4403d40223abe3 Mon Sep 17 00:00:00 2001 From: Daniel Roe Date: Wed, 14 Feb 2024 11:36:34 +0000 Subject: [PATCH 13/17] test: update snapshots with url encoded slashes from `ufo` upgrade --- src/runtime/providers/netlifyImageCdn.ts | 3 ++- test/e2e/__snapshots__/no-ssr.test.ts.snap | 16 +++++++-------- test/e2e/__snapshots__/ssr.test.ts.snap | 8 ++++---- test/providers.ts | 24 +++++++++++----------- 4 files changed, 26 insertions(+), 25 deletions(-) diff --git a/src/runtime/providers/netlifyImageCdn.ts b/src/runtime/providers/netlifyImageCdn.ts index 0c992be5d..3b8426aaa 100644 --- a/src/runtime/providers/netlifyImageCdn.ts +++ b/src/runtime/providers/netlifyImageCdn.ts @@ -1,3 +1,4 @@ +import { encodeQueryItem } from 'ufo' import type { ProviderGetImage } from '../../types' import { createOperationsGenerator } from '#image' @@ -33,7 +34,7 @@ export const operationsGenerator = createOperationsGenerator({ } }, joinWith: '&', - formatter: (key: string, value: string) => `${key}=${value ?? ''}` + formatter: (key, value) => encodeQueryItem(key, value) }) export const getImage: ProviderGetImage = (src, { modifiers = {}, baseURL } = {}) => { diff --git a/test/e2e/__snapshots__/no-ssr.test.ts.snap b/test/e2e/__snapshots__/no-ssr.test.ts.snap index 1edef0d7a..6a833ba74 100644 --- a/test/e2e/__snapshots__/no-ssr.test.ts.snap +++ b/test/e2e/__snapshots__/no-ssr.test.ts.snap @@ -20,13 +20,13 @@ exports[`browser (ssr: false) > aliyun should render images 2`] = ` exports[`browser (ssr: false) > awsAmplify should render images 1`] = ` [ - "https://example.amplifyapp.com/_amplify/image?url=/test.jpg&w=320&q=100", + "https://example.amplifyapp.com/_amplify/image?url=%2Ftest.jpg&w=320&q=100", ] `; exports[`browser (ssr: false) > awsAmplify should render images 2`] = ` [ - "https://example.amplifyapp.com/_amplify/image?url=/test.jpg&w=320&q=100", + "https://example.amplifyapp.com/_amplify/image?url=%2Ftest.jpg&w=320&q=100", ] `; @@ -288,15 +288,15 @@ exports[`browser (ssr: false) > layer0 should render images 2`] = ` exports[`browser (ssr: false) > netlifyImageCdn should render images 1`] = ` [ - "https://netlify-photo-gallery.netlify.app?w=100&h=100&fit=cover&url=/images/apple.jpg", - "https://netlify-photo-gallery.netlify.app?w=400&h=300&url=/images/apple.jpg", + "https://netlify-photo-gallery.netlify.app?w=100&h=100&fit=cover&url=%2Fimages%2Fapple.jpg", + "https://netlify-photo-gallery.netlify.app?w=400&h=300&url=%2Fimages%2Fapple.jpg", ] `; exports[`browser (ssr: false) > netlifyImageCdn should render images 2`] = ` [ - "https://netlify-photo-gallery.netlify.app/?w=100&h=100&fit=cover&url=/images/apple.jpg", - "https://netlify-photo-gallery.netlify.app/?w=400&h=300&url=/images/apple.jpg", + "https://netlify-photo-gallery.netlify.app/?w=100&h=100&fit=cover&url=%2Fimages%2Fapple.jpg", + "https://netlify-photo-gallery.netlify.app/?w=400&h=300&url=%2Fimages%2Fapple.jpg", ] `; @@ -587,13 +587,13 @@ exports[`browser (ssr: false) > uploadcare should render images 2`] = ` exports[`browser (ssr: false) > vercel should render images 1`] = ` [ - "https://image-component.nextjs.gallery/_next/image?url=/colors.jpg&w=750&q=75", + "https://image-component.nextjs.gallery/_next/image?url=%2Fcolors.jpg&w=750&q=75", ] `; exports[`browser (ssr: false) > vercel should render images 2`] = ` [ - "https://image-component.nextjs.gallery/_next/image?url=/colors.jpg&w=750&q=75", + "https://image-component.nextjs.gallery/_next/image?url=%2Fcolors.jpg&w=750&q=75", ] `; diff --git a/test/e2e/__snapshots__/ssr.test.ts.snap b/test/e2e/__snapshots__/ssr.test.ts.snap index 8a62a6d9e..71951ceb2 100644 --- a/test/e2e/__snapshots__/ssr.test.ts.snap +++ b/test/e2e/__snapshots__/ssr.test.ts.snap @@ -288,15 +288,15 @@ exports[`browser (ssr: true) > layer0 should render images 2`] = ` exports[`browser (ssr: true) > netlifyImageCdn should render images 1`] = ` [ - "https://netlify-photo-gallery.netlify.app?w=100&h=100&fit=cover&url=/images/apple.jpg", - "https://netlify-photo-gallery.netlify.app?w=400&h=300&url=/images/apple.jpg", + "https://netlify-photo-gallery.netlify.app?w=100&h=100&fit=cover&url=%2Fimages%2Fapple.jpg", + "https://netlify-photo-gallery.netlify.app?w=400&h=300&url=%2Fimages%2Fapple.jpg", ] `; exports[`browser (ssr: true) > netlifyImageCdn should render images 2`] = ` [ - "https://netlify-photo-gallery.netlify.app/?w=400&h=300&url=/images/apple.jpg", - "https://netlify-photo-gallery.netlify.app/?w=100&h=100&fit=cover&url=/images/apple.jpg", + "https://netlify-photo-gallery.netlify.app/?w=400&h=300&url=%2Fimages%2Fapple.jpg", + "https://netlify-photo-gallery.netlify.app/?w=100&h=100&fit=cover&url=%2Fimages%2Fapple.jpg", ] `; diff --git a/test/providers.ts b/test/providers.ts index 6edbd3a5c..d27b2deba 100644 --- a/test/providers.ts +++ b/test/providers.ts @@ -15,8 +15,8 @@ export const images = [ imageengine: { url: '/test.png' }, unsplash: { url: '/test.png' }, imagekit: { url: '/test.png' }, - netlify: { url: '/.netlify/images?url=/test.png' }, - netlifyImageCdn: { url: '/.netlify/images?url=/test.png' }, + netlify: { url: '/.netlify/images?url=%2Ftest.png' }, + netlifyImageCdn: { url: '/.netlify/images?url=%2Ftest.png' }, netlifyLargeMedia: { url: '/test.png' }, prepr: { url: 'https://projectName.stream.prepr.io/image-test-300x450-png' }, prismic: { url: '/test.png?auto=compress,format&rect=0,0,200,200&w=100&h=100' }, @@ -51,8 +51,8 @@ export const images = [ imageengine: { url: '/test.png?imgeng=/w_200' }, unsplash: { url: '/test.png?w=200' }, imagekit: { url: '/test.png?tr=w-200' }, - netlify: { url: '/.netlify/images?w=200&url=/test.png' }, - netlifyImageCdn: { url: '/.netlify/images?w=200&url=/test.png' }, + netlify: { url: '/.netlify/images?w=200&url=%2Ftest.png' }, + netlifyImageCdn: { url: '/.netlify/images?w=200&url=%2Ftest.png' }, netlifyLargeMedia: { url: '/test.png?w=200&nf_resize=fit' }, prepr: { url: 'https://projectName.stream.prepr.io/w_200/image-test-300x450-png' }, prismic: { url: '/test.png?auto=compress,format&rect=0,0,200,200&w=200&h=100' }, @@ -87,8 +87,8 @@ export const images = [ imageengine: { url: '/test.png?imgeng=/h_200' }, unsplash: { url: '/test.png?h=200' }, imagekit: { url: '/test.png?tr=h-200' }, - netlify: { url: '/.netlify/images?h=200&url=/test.png' }, - netlifyImageCdn: { url: '/.netlify/images?h=200&url=/test.png' }, + netlify: { url: '/.netlify/images?h=200&url=%2Ftest.png' }, + netlifyImageCdn: { url: '/.netlify/images?h=200&url=%2Ftest.png' }, netlifyLargeMedia: { url: '/test.png?h=200&nf_resize=fit' }, prepr: { url: 'https://projectName.stream.prepr.io/h_200/image-test-300x450-png' }, prismic: { url: '/test.png?auto=compress,format&rect=0,0,200,200&w=100&h=200' }, @@ -123,8 +123,8 @@ export const images = [ imageengine: { url: '/test.png?imgeng=/w_200/h_200' }, unsplash: { url: '/test.png?w=200&h=200' }, imagekit: { url: '/test.png?tr=w-200,h-200' }, - netlify: { url: '/.netlify/images?w=200&h=200&url=/test.png' }, - netlifyImageCdn: { url: '/.netlify/images?w=200&h=200&url=/test.png' }, + netlify: { url: '/.netlify/images?w=200&h=200&url=%2Ftest.png' }, + netlifyImageCdn: { url: '/.netlify/images?w=200&h=200&url=%2Ftest.png' }, netlifyLargeMedia: { url: '/test.png?w=200&h=200&nf_resize=fit' }, prismic: { url: '/test.png?auto=compress,format&rect=0,0,200,200&w=200&h=200' }, prepr: { url: 'https://projectName.stream.prepr.io/w_200,h_200/image-test-300x450-png' }, @@ -159,8 +159,8 @@ export const images = [ imageengine: { url: '/test.png?imgeng=/w_200/h_200/m_letterbox' }, unsplash: { url: '/test.png?w=200&h=200&fit=fill' }, imagekit: { url: '/test.png?tr=w-200,h-200,cm-pad_resize' }, - netlify: { url: '/.netlify/images?w=200&h=200&fit=contain&url=/test.png' }, - netlifyImageCdn: { url: '/.netlify/images?w=200&h=200&fit=contain&url=/test.png' }, + netlify: { url: '/.netlify/images?w=200&h=200&fit=contain&url=%2Ftest.png' }, + netlifyImageCdn: { url: '/.netlify/images?w=200&h=200&fit=contain&url=%2Ftest.png' }, netlifyLargeMedia: { url: '/test.png?w=200&h=200&nf_resize=fit' }, prismic: { url: '/test.png?auto=compress,format&rect=0,0,200,200&w=200&h=200&fit=fill' }, prepr: { url: 'https://projectName.stream.prepr.io/w_200,h_200,fit_contain/image-test-300x450-png' }, @@ -195,8 +195,8 @@ export const images = [ imageengine: { url: '/test.png?imgeng=/w_200/h_200/m_letterbox/f_jpg' }, unsplash: { url: '/test.png?w=200&h=200&fit=fill&fm=jpeg' }, imagekit: { url: '/test.png?tr=w-200,h-200,cm-pad_resize,f-jpeg' }, - netlify: { url: '/.netlify/images?w=200&h=200&fit=contain&fm=jpeg&url=/test.png' }, - netlifyImageCdn: { url: '/.netlify/images?w=200&h=200&fit=contain&fm=jpeg&url=/test.png' }, + netlify: { url: '/.netlify/images?w=200&h=200&fit=contain&fm=jpeg&url=%2Ftest.png' }, + netlifyImageCdn: { url: '/.netlify/images?w=200&h=200&fit=contain&fm=jpeg&url=%2Ftest.png' }, netlifyLargeMedia: { url: '/test.png?w=200&h=200&nf_resize=fit' }, prismic: { url: '/test.png?auto=compress,format&rect=0,0,200,200&w=200&h=200&fit=fill&fm=jpeg' }, sanity: { url: 'https://cdn.sanity.io/images/projectid/production/test-300x450.png?w=200&h=200&fit=fill&fm=jpg&bg=ffffff' }, From 10a26f9a8d2a168fd262dca5c16aa7d1fce1ddaf Mon Sep 17 00:00:00 2001 From: Daniel Roe Date: Wed, 14 Feb 2024 11:36:57 +0000 Subject: [PATCH 14/17] test: update provider tests --- test/unit/providers.test.ts | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/test/unit/providers.test.ts b/test/unit/providers.test.ts index c924dac2b..598a821ab 100644 --- a/test/unit/providers.test.ts +++ b/test/unit/providers.test.ts @@ -21,7 +21,8 @@ import * as gumlet from '#image/providers/gumlet' import * as imageengine from '#image/providers/imageengine' import * as unsplash from '#image/providers/unsplash' import * as imagekit from '#image/providers/imagekit' -import * as netlify from '#image/providers/netlify' +import * as netlifyImageCdn from '#image/providers/netlifyImageCdn' +import * as netlifyLargeMedia from '#image/providers/netlifyLargeMedia' import * as prismic from '#image/providers/prismic' import * as sanity from '#image/providers/sanity' import * as contentful from '#image/providers/contentful' @@ -288,15 +289,27 @@ describe('Providers', () => { } }) - it('netlify', () => { + it('netlifyImageCdn', () => { const providerOptions = { baseURL: '' } for (const image of images) { const [src, modifiers] = image.args - const generated = netlify.getImage(src, { modifiers: { ...modifiers }, ...providerOptions }, emptyContext) - expect(generated).toMatchObject(image.netlify) + const generated = netlifyImageCdn.getImage(src, { modifiers: { ...modifiers }, ...providerOptions }, emptyContext) + expect(generated).toMatchObject(image.netlifyImageCdn) + } + }) + + it('netlifyLargeMedia', () => { + const providerOptions = { + baseURL: '' + } + + for (const image of images) { + const [src, modifiers] = image.args + const generated = netlifyLargeMedia.getImage(src, { modifiers: { ...modifiers }, ...providerOptions }, emptyContext) + expect(generated).toMatchObject(image.netlifyLargeMedia) } }) From f41ce38dff7c75478a6489862298abdad0046117 Mon Sep 17 00:00:00 2001 From: Daniel Roe Date: Wed, 14 Feb 2024 11:38:46 +0000 Subject: [PATCH 15/17] chore: remove old provider test entry --- test/providers.ts | 6 ------ 1 file changed, 6 deletions(-) diff --git a/test/providers.ts b/test/providers.ts index d27b2deba..acb5eb2a1 100644 --- a/test/providers.ts +++ b/test/providers.ts @@ -15,7 +15,6 @@ export const images = [ imageengine: { url: '/test.png' }, unsplash: { url: '/test.png' }, imagekit: { url: '/test.png' }, - netlify: { url: '/.netlify/images?url=%2Ftest.png' }, netlifyImageCdn: { url: '/.netlify/images?url=%2Ftest.png' }, netlifyLargeMedia: { url: '/test.png' }, prepr: { url: 'https://projectName.stream.prepr.io/image-test-300x450-png' }, @@ -51,7 +50,6 @@ export const images = [ imageengine: { url: '/test.png?imgeng=/w_200' }, unsplash: { url: '/test.png?w=200' }, imagekit: { url: '/test.png?tr=w-200' }, - netlify: { url: '/.netlify/images?w=200&url=%2Ftest.png' }, netlifyImageCdn: { url: '/.netlify/images?w=200&url=%2Ftest.png' }, netlifyLargeMedia: { url: '/test.png?w=200&nf_resize=fit' }, prepr: { url: 'https://projectName.stream.prepr.io/w_200/image-test-300x450-png' }, @@ -87,7 +85,6 @@ export const images = [ imageengine: { url: '/test.png?imgeng=/h_200' }, unsplash: { url: '/test.png?h=200' }, imagekit: { url: '/test.png?tr=h-200' }, - netlify: { url: '/.netlify/images?h=200&url=%2Ftest.png' }, netlifyImageCdn: { url: '/.netlify/images?h=200&url=%2Ftest.png' }, netlifyLargeMedia: { url: '/test.png?h=200&nf_resize=fit' }, prepr: { url: 'https://projectName.stream.prepr.io/h_200/image-test-300x450-png' }, @@ -123,7 +120,6 @@ export const images = [ imageengine: { url: '/test.png?imgeng=/w_200/h_200' }, unsplash: { url: '/test.png?w=200&h=200' }, imagekit: { url: '/test.png?tr=w-200,h-200' }, - netlify: { url: '/.netlify/images?w=200&h=200&url=%2Ftest.png' }, netlifyImageCdn: { url: '/.netlify/images?w=200&h=200&url=%2Ftest.png' }, netlifyLargeMedia: { url: '/test.png?w=200&h=200&nf_resize=fit' }, prismic: { url: '/test.png?auto=compress,format&rect=0,0,200,200&w=200&h=200' }, @@ -159,7 +155,6 @@ export const images = [ imageengine: { url: '/test.png?imgeng=/w_200/h_200/m_letterbox' }, unsplash: { url: '/test.png?w=200&h=200&fit=fill' }, imagekit: { url: '/test.png?tr=w-200,h-200,cm-pad_resize' }, - netlify: { url: '/.netlify/images?w=200&h=200&fit=contain&url=%2Ftest.png' }, netlifyImageCdn: { url: '/.netlify/images?w=200&h=200&fit=contain&url=%2Ftest.png' }, netlifyLargeMedia: { url: '/test.png?w=200&h=200&nf_resize=fit' }, prismic: { url: '/test.png?auto=compress,format&rect=0,0,200,200&w=200&h=200&fit=fill' }, @@ -195,7 +190,6 @@ export const images = [ imageengine: { url: '/test.png?imgeng=/w_200/h_200/m_letterbox/f_jpg' }, unsplash: { url: '/test.png?w=200&h=200&fit=fill&fm=jpeg' }, imagekit: { url: '/test.png?tr=w-200,h-200,cm-pad_resize,f-jpeg' }, - netlify: { url: '/.netlify/images?w=200&h=200&fit=contain&fm=jpeg&url=%2Ftest.png' }, netlifyImageCdn: { url: '/.netlify/images?w=200&h=200&fit=contain&fm=jpeg&url=%2Ftest.png' }, netlifyLargeMedia: { url: '/test.png?w=200&h=200&nf_resize=fit' }, prismic: { url: '/test.png?auto=compress,format&rect=0,0,200,200&w=200&h=200&fit=fill&fm=jpeg' }, From 6a7becd5ec3a33f300384e583e4529e9a4edc3ba Mon Sep 17 00:00:00 2001 From: Matt Kane Date: Wed, 14 Feb 2024 11:44:25 +0000 Subject: [PATCH 16/17] chore: fix fixture root --- playground/nuxt.config.ts | 2 +- test/e2e/__snapshots__/no-ssr.test.ts.snap | 8 ++++---- test/e2e/__snapshots__/ssr.test.ts.snap | 8 ++++---- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/playground/nuxt.config.ts b/playground/nuxt.config.ts index 8a8527239..fc6f3a995 100644 --- a/playground/nuxt.config.ts +++ b/playground/nuxt.config.ts @@ -75,7 +75,7 @@ export default defineNuxtConfig({ baseURL: 'https://ik.imagekit.io/demo' }, netlifyImageCdn: { - baseURL: 'https://netlify-photo-gallery.netlify.app' + baseURL: 'https://netlify-photo-gallery.netlify.app/.netlify/images' }, netlifyLargeMedia: { baseURL: 'https://netlify-photo-gallery.netlify.app' diff --git a/test/e2e/__snapshots__/no-ssr.test.ts.snap b/test/e2e/__snapshots__/no-ssr.test.ts.snap index 6a833ba74..28cd43881 100644 --- a/test/e2e/__snapshots__/no-ssr.test.ts.snap +++ b/test/e2e/__snapshots__/no-ssr.test.ts.snap @@ -288,15 +288,15 @@ exports[`browser (ssr: false) > layer0 should render images 2`] = ` exports[`browser (ssr: false) > netlifyImageCdn should render images 1`] = ` [ - "https://netlify-photo-gallery.netlify.app?w=100&h=100&fit=cover&url=%2Fimages%2Fapple.jpg", - "https://netlify-photo-gallery.netlify.app?w=400&h=300&url=%2Fimages%2Fapple.jpg", + "https://netlify-photo-gallery.netlify.app/.netlify/images?w=100&h=100&fit=cover&url=%2Fimages%2Fapple.jpg", + "https://netlify-photo-gallery.netlify.app/.netlify/images?w=400&h=300&url=%2Fimages%2Fapple.jpg", ] `; exports[`browser (ssr: false) > netlifyImageCdn should render images 2`] = ` [ - "https://netlify-photo-gallery.netlify.app/?w=100&h=100&fit=cover&url=%2Fimages%2Fapple.jpg", - "https://netlify-photo-gallery.netlify.app/?w=400&h=300&url=%2Fimages%2Fapple.jpg", + "https://netlify-photo-gallery.netlify.app/.netlify/images?w=100&h=100&fit=cover&url=%2Fimages%2Fapple.jpg", + "https://netlify-photo-gallery.netlify.app/.netlify/images?w=400&h=300&url=%2Fimages%2Fapple.jpg", ] `; diff --git a/test/e2e/__snapshots__/ssr.test.ts.snap b/test/e2e/__snapshots__/ssr.test.ts.snap index 71951ceb2..d23cd1944 100644 --- a/test/e2e/__snapshots__/ssr.test.ts.snap +++ b/test/e2e/__snapshots__/ssr.test.ts.snap @@ -288,15 +288,15 @@ exports[`browser (ssr: true) > layer0 should render images 2`] = ` exports[`browser (ssr: true) > netlifyImageCdn should render images 1`] = ` [ - "https://netlify-photo-gallery.netlify.app?w=100&h=100&fit=cover&url=%2Fimages%2Fapple.jpg", - "https://netlify-photo-gallery.netlify.app?w=400&h=300&url=%2Fimages%2Fapple.jpg", + "https://netlify-photo-gallery.netlify.app/.netlify/images?w=100&h=100&fit=cover&url=%2Fimages%2Fapple.jpg", + "https://netlify-photo-gallery.netlify.app/.netlify/images?w=400&h=300&url=%2Fimages%2Fapple.jpg", ] `; exports[`browser (ssr: true) > netlifyImageCdn should render images 2`] = ` [ - "https://netlify-photo-gallery.netlify.app/?w=400&h=300&url=%2Fimages%2Fapple.jpg", - "https://netlify-photo-gallery.netlify.app/?w=100&h=100&fit=cover&url=%2Fimages%2Fapple.jpg", + "https://netlify-photo-gallery.netlify.app/.netlify/images?w=400&h=300&url=%2Fimages%2Fapple.jpg", + "https://netlify-photo-gallery.netlify.app/.netlify/images?w=100&h=100&fit=cover&url=%2Fimages%2Fapple.jpg", ] `; From a5d92125107e70936ce6e2c5a8a8c0d3b4aad7c7 Mon Sep 17 00:00:00 2001 From: Daniel Roe Date: Wed, 14 Feb 2024 11:51:02 +0000 Subject: [PATCH 17/17] fix: also encode for netlifyLargeMedia --- src/runtime/providers/netlifyLargeMedia.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/runtime/providers/netlifyLargeMedia.ts b/src/runtime/providers/netlifyLargeMedia.ts index f0f207ab8..412ab731c 100644 --- a/src/runtime/providers/netlifyLargeMedia.ts +++ b/src/runtime/providers/netlifyLargeMedia.ts @@ -1,4 +1,4 @@ -import { joinURL } from 'ufo' +import { encodeQueryItem, joinURL } from 'ufo' import type { ProviderGetImage } from '../../types' import { createOperationsGenerator } from '#image' @@ -15,7 +15,7 @@ export const operationsGenerator = createOperationsGenerator({ } }, joinWith: '&', - formatter: (key: string, value: string) => `${key}=${value}` + formatter: (key, value) => encodeQueryItem(key, value) }) const isDev = process.env.NODE_ENV === 'development'