From c7a741ee2ee9c270e9c0b2f1041edcf097a3ea6d Mon Sep 17 00:00:00 2001 From: "Vlad Z." Date: Sat, 14 Feb 2026 22:19:33 -0500 Subject: [PATCH 01/13] Added imgproxy support; --- docs/content/3.providers/imgproxy.md | 123 ++++++++++++++ package.json | 1 + playground/app/providers.ts | 61 +++++++ playground/nuxt.config.ts | 5 + pnpm-lock.yaml | 9 + src/provider.ts | 1 + src/runtime/providers/imgproxy.ts | 231 ++++++++++++++++++++++++++ test/e2e/__snapshots__/imgproxy.json5 | 18 ++ test/nuxt/providers.test.ts | 177 ++++++++++++++++++++ test/providers.ts | 6 + 10 files changed, 632 insertions(+) create mode 100644 docs/content/3.providers/imgproxy.md create mode 100644 src/runtime/providers/imgproxy.ts create mode 100644 test/e2e/__snapshots__/imgproxy.json5 diff --git a/docs/content/3.providers/imgproxy.md b/docs/content/3.providers/imgproxy.md new file mode 100644 index 000000000..54435c666 --- /dev/null +++ b/docs/content/3.providers/imgproxy.md @@ -0,0 +1,123 @@ +--- +title: Imgproxy +description: Nuxt Image has first class integration with Imgproxy. +links: + - label: Source + icon: i-simple-icons-github + to: https://github.com/nuxt/image/blob/main/src/runtime/providers/imgproxy.ts + size: xs +--- + +Integration between [Imgproxy](https://imgproxy.net/) and the image module. + +At a minimum, you must configure the `imgproxy` provider with the `baseURL`, `key` and `salt` set to your Imgproxy instance: + +```ts [nuxt.config.ts] +export default defineNuxtConfig({ + image: { + imageengine: { + baseURL: 'http://localhost:8080/', + key: 'ee3b0e07dfc9ec20d5d9588a558753547a8a88c48291ae96171330daf4ce2800', + salt: '8dd0e39bb7b14eeaf02d49e5dc76d2bc0abd9e09d52e7049e791acd3558db68e', + } + } +}) +``` + +## Imgproxy `fit` Values + +All `fit` values are converted to [`resizing_type`](https://docs.imgproxy.net/usage/processing#resizing-type) option provided by Imgproxy. +The `fit` option is kept for backwards compatibility with @nuxt/image. The `contain` value is converted to `fill`. + +## Imgproxy default options + +## Imgproxy Modifiers + +By default, the Imgproxy provider has the following settings for modifiers +``` + resizingType: 'fit', + gravity: 'ce', + enlarge: true, + format: 'webp', + ``` + +If you want to change them, define them in your nuxt.config.ts file. + +In addition to the [standard modifiers](/usage/nuxt-img#modifiers), you can also use most of [Imgproxy Options](https://docs.imgproxy.net/usage/processing#processing-options) by adding them to the `modifiers` property with the following attribute names: + +- `format` +- `resizingType` - alias for `fit` +- `resize` +- `size` +- `minWidth` +- `minHeight` +- `zoom` +- `dpr` +- `enlarge` +- `extend` +- `extendAspectRatio` +- `gravity` +- `crop` +- `autoRotate` +- `rotate` +- `background` +- `sharpen` +- `pixelate` +- `stripMetadata` +- `keepCopyright` +- `stripColorProfile` +- `enforceThumbnail` +- `maxBytes` +- `raw` +- `cachebuster` +- `expires` +- `filename` +- `returnAttachment` +- `preset` +- `maxSrcResolution` +- `maxSrcFileSize` +- `maxAnimationFrames` +- `maxAnimationFrameResolution` +- `maxResultDimension` + +> The provider does not verify the accuracy of your data entry. If you see “Invalid URL” from Imgproxy, check that the parameters are correct. Some parameters (e.g., `crop`) accept an object as input and convert the request into a valid string for your server. You can find more detailed information about all modifiers on the [Imgproxy](https://docs.imgproxy.net/usage/processing#processing-options) website. + +Example 1: Cropping an image to a width and height of 500x500 and rotate by 180 degrees: + +```vue + +``` + +Example 2: Add blur to an image: + +```vue + +``` + +Example 2: Using [presets](https://docs.imgproxy.net/configuration/options#presets): + +```vue + +``` + + + + diff --git a/package.json b/package.json index 9ac4e3e91..e8090aea2 100755 --- a/package.json +++ b/package.json @@ -46,6 +46,7 @@ "test:built:types": "nuxt typecheck playground && nuxt typecheck example" }, "dependencies": { + "@noble/hashes": "^2.0.1", "@nuxt/kit": "^4.3.1", "consola": "^3.4.2", "defu": "^6.1.4", diff --git a/playground/app/providers.ts b/playground/app/providers.ts index 6417d39fb..f362d8442 100644 --- a/playground/app/providers.ts +++ b/playground/app/providers.ts @@ -437,6 +437,67 @@ export const providers: Provider[] = [ }, ], }, + // imgproxy + { + name: 'imgproxy', + samples: [ + { + src: 'https://mars.nasa.gov/system/downloadable_items/39099_Mars-MRO-orbiter-fresh-crater-sirenum-fossae.jpg', + width: 300, + height: 300, + }, + { + src: 'https://mars.nasa.gov/system/downloadable_items/39099_Mars-MRO-orbiter-fresh-crater-sirenum-fossae.jpg', + width: 300, + height: 300, + quality: 10, + }, + { + src: 'https://mars.nasa.gov/system/downloadable_items/39099_Mars-MRO-orbiter-fresh-crater-sirenum-fossae.jpg', + background: 'FFCC00', + modifiers: { + resize: 'fit:500:500:1:1', + }, + }, + { + src: 'https://mars.nasa.gov/system/downloadable_items/39099_Mars-MRO-orbiter-fresh-crater-sirenum-fossae.jpg', + width: 500, + height: 500, + modifiers: { + rotate: 180, + }, + }, + { + src: 'https://mars.nasa.gov/system/downloadable_items/39099_Mars-MRO-orbiter-fresh-crater-sirenum-fossae.jpg', + width: 500, + height: 500, + modifiers: { + blur: 100, + }, + }, + { + src: 'https://mars.nasa.gov/system/downloadable_items/39099_Mars-MRO-orbiter-fresh-crater-sirenum-fossae.jpg', + width: 500, + height: 500, + modifiers: { + dpr: 0.1, + extend: true, + extendAspectRatio: '1:no:0:1', + rotate: 192, + background: '255:255:0', + sharpen: 10, + pixelate: 10, + stripMetadata: true, + keepCopyright: false, + stripColorProfile: true, + maxBytes: 10, + cachebuster: 'test', + expires: 4106340630, + filename: 'test', + }, + }, + ], + }, // imgix { name: 'imgix', diff --git a/playground/nuxt.config.ts b/playground/nuxt.config.ts index 9e9db4485..81e0febfa 100644 --- a/playground/nuxt.config.ts +++ b/playground/nuxt.config.ts @@ -82,6 +82,11 @@ export default defineNuxtConfig({ imgix: { baseURL: 'https://assets.imgix.net', }, + imgproxy: { + baseURL: 'http://localhost:8080', + key: 'ee3b0e07dfc9ec20d5d9588a558753547a8a88c48291ae96171330daf4ce2800', + salt: '8dd0e39bb7b14eeaf02d49e5dc76d2bc0abd9e09d52e7049e791acd3558db68e', + }, imagekit: { baseURL: 'https://ik.imagekit.io/demo', }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index df87bdfec..99005a89b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -14,6 +14,9 @@ importers: .: dependencies: + '@noble/hashes': + specifier: ^2.0.1 + version: 2.0.1 '@nuxt/kit': specifier: ^4.3.1 version: 4.3.1(magicast@0.5.1) @@ -1304,6 +1307,10 @@ packages: '@napi-rs/wasm-runtime@1.1.1': resolution: {integrity: sha512-p64ah1M1ld8xjWv3qbvFwHiFVWrq1yFvV4f7w+mzaqiR4IlSgkqhcRdHwsGgomwzBH51sRY4NEowLxnaBjcW/A==} + '@noble/hashes@2.0.1': + resolution: {integrity: sha512-XlOlEbQcE9fmuXxrVTXCTlG2nlRXa9Rj3rr5Ue/+tX+nmkgbX720YHh0VR3hBF9xDvwnb8D2shVGOwNx+ulArw==} + engines: {node: '>= 20.19.0'} + '@nodelib/fs.scandir@2.1.5': resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} engines: {node: '>= 8'} @@ -9158,6 +9165,8 @@ snapshots: '@tybys/wasm-util': 0.10.1 optional: true + '@noble/hashes@2.0.1': {} + '@nodelib/fs.scandir@2.1.5': dependencies: '@nodelib/fs.stat': 2.0.5 diff --git a/src/provider.ts b/src/provider.ts index e41451151..edbec91cd 100644 --- a/src/provider.ts +++ b/src/provider.ts @@ -32,6 +32,7 @@ export const BuiltInProviders = [ 'imageengine', 'imagekit', 'imgix', + 'imgproxy', 'ipx', 'ipxStatic', 'netlify', diff --git a/src/runtime/providers/imgproxy.ts b/src/runtime/providers/imgproxy.ts new file mode 100644 index 000000000..fdbde6755 --- /dev/null +++ b/src/runtime/providers/imgproxy.ts @@ -0,0 +1,231 @@ +// https://imgproxy.net/ + +import { joinURL } from 'ufo' +import { createOperationsGenerator } from '../utils/index' +import { defineProvider } from '../utils/provider' +import { hmac } from '@noble/hashes/hmac.js' +import { sha256 } from '@noble/hashes/sha2.js' +import { defu } from 'defu' +import type { ImageModifiers } from '@nuxt/image' + +// https://docs.imgproxy.net/usage/processing#resizing-type +export type ImgproxyResizingType = 'fit' | 'fill' | 'fill-down' | 'force' | 'auto' + +export type ImgproxyGravityType = 'ce' | 'no' | 'so' | 'ea' | 'we' | 'noea' | 'nowe' | 'soea' | 'sowe' + +export interface ImgproxyCrop { + width: number + height: number + gravity?: ImgproxyGravityType +} + +export type ImgproxyFormat = 'webp' | 'png' | 'jpg' | 'jpeg' | 'jxl' | 'avif' | 'gif' | 'ico' | 'svg' | 'heic' | 'bmp' | 'tiff' | 'pdf' | 'psd' | 'mp4' + +export type ImgproxyBooleanPrimitive = string | number | boolean | 't' + +export interface ImgproxyModifiers extends Omit { + width: number + height: number + format: ImgproxyFormat + fit: ImgproxyResizingType | 'contain' + resizingType: ImgproxyResizingType + resize: string + size: string + minWidth: number + minHeight: number + zoom: string | number + dpr: number + enlarge: boolean + extend: boolean + extendAspectRatio: string + gravity: ImgproxyGravityType | string + crop: ImgproxyCrop + autoRotate: boolean + rotate: number + background: string + sharpen: number + pixelate: number + stripMetadata: boolean + keepCopyright: boolean + stripColorProfile: boolean + enforceThumbnail: boolean + maxBytes: number + raw: boolean + cachebuster: string + expires: number + filename: string + returnAttachment: boolean + preset: string + maxSrcResolution: number + maxSrcFileSize: number + maxAnimationFrames: number + maxAnimationFrameResolution: string + maxResultDimension: string +} + +interface ImgproxyOptions { + baseURL: string + salt: string + key: string + modifiers?: Partial +} + +const booleanMap = (value: string | number | boolean | ImgproxyCrop | ImgproxyBooleanPrimitive): number => { + if (typeof value === 'boolean') { + return value ? 1 : 0 + } + + if (typeof value === 'object') { + return 0 + } + + switch (value) { + case 't': + case 1: + case 'true': + return 1 + default: + return 0 + } +} + +// https://docs.imgproxy.net/usage/processing +const operationsGenerator = createOperationsGenerator({ + keyMap: { + resize: 'rs', + size: 's', + resizingType: 'rt', + width: 'w', + height: 'h', + minWidth: 'mw', + minHeight: 'mh', + zoom: 'z', + dpr: 'dpr', + enlarge: 'el', + extendAspectRatio: 'exar', + gravity: 'g', + crop: 'c', + autoRotate: 'ar', + rotate: 'rot', + background: 'bg', + blur: 'bl', + sharpen: 'sh', + pixelate: 'pix', + stripMetadata: 'sm', + keepCopyright: 'kcr', + stripColorProfile: 'scp', + enforceThumbnail: 'eth', + quality: 'q', + maxBytes: 'mb', + format: 'f', + raw: 'raw', + cachebuster: 'cb', + expires: 'exp', + filename: 'fn', + returnAttachment: 'att', + preset: 'pr', + maxSrcResolution: 'msr', + maxSrcFileSize: 'msfs', + maxAnimationFrames: 'maf', + maxAnimationFrameResolution: 'mafr', + maxResultDimension: 'mrd', + }, + valueMap: { + crop: (value: string | number | boolean | ImgproxyCrop | ImgproxyBooleanPrimitive): string => { + if (typeof value === 'string') { + return value + } + + if (typeof value === 'object') { + return `${value.width}:${value.height}${value?.gravity ? `:${value.gravity}` : ''}` + } + + throw new Error('Wrong crop format') + }, + enlarge: booleanMap, + extend: booleanMap, + autoRotate: booleanMap, + stripMetadata: booleanMap, + keepCopyright: booleanMap, + stripColorProfile: booleanMap, + enforceThumbnail: booleanMap, + raw: booleanMap, + returnAttachment: booleanMap, + rotate: (value): number => { + if (typeof value !== 'number' || value <= 0 || value >= 359) { + throw new TypeError('Wrong rotate format') + } + + return value - (value % 90) + }, + }, + formatter: (key, value) => `${key}:${value}`, + joinWith: '/', +}) + +function hexToBytes(hex: string): Uint8Array { + const bytes = new Uint8Array(hex.length / 2) + for (let i = 0; i < hex.length; i += 2) { + bytes[i / 2] = Number.parseInt(hex.slice(i, i + 2), 16) + } + return bytes +} + +function urlSafeBase64(input: string | Uint8Array): string { + const bytes = typeof input === 'string' + ? new TextEncoder().encode(input) + : input + + const binaryString = String.fromCharCode(...bytes) + const base64 = btoa(binaryString) + + return base64 + .replace(/=/g, '') + .replace(/\+/g, '-') + .replace(/\//g, '_') +} + +function sign(salt: string, target: string, secret: string) { + const signature = hmac.create(sha256, hexToBytes(secret)) + signature.update(hexToBytes(salt)) + signature.update(new TextEncoder().encode(target)) + + return urlSafeBase64(signature.digest()) +} + +const defaultModifiers: Partial = { + resizingType: 'fit', + gravity: 'ce', + enlarge: true, + format: 'webp', +} + +function resolveModifiers(modifiers: Partial): Partial { + if (modifiers?.fit) { + switch (modifiers.fit) { + case 'contain': + modifiers.resizingType = 'fill' + break + default: + modifiers.resizingType = modifiers.fit + break + } + delete modifiers.fit + } + + return modifiers +} + +export default defineProvider({ + getImage: (src, { modifiers, baseURL, key, salt }) => { + const mergeModifiers = resolveModifiers(defu(modifiers, defaultModifiers)) + + const encodedUrl = urlSafeBase64(src) + const path = joinURL('/', operationsGenerator(mergeModifiers), encodedUrl) + const signature = sign(salt, path, key) + + return { + url: joinURL(baseURL, signature, path), + } + }, +}) diff --git a/test/e2e/__snapshots__/imgproxy.json5 b/test/e2e/__snapshots__/imgproxy.json5 new file mode 100644 index 000000000..bfadcd7ff --- /dev/null +++ b/test/e2e/__snapshots__/imgproxy.json5 @@ -0,0 +1,18 @@ +{ + "requests": [ + "http://localhost:8080/1uXmW9_-sqlIy-jMJhbuzuc1LNJhUS3_Y6XlI2Thpxs/rt:fit/g:ce/el:1/f:webp/rot:180/w:500/h:500/aHR0cHM6Ly9tYXJzLm5hc2EuZ292L3N5c3RlbS9kb3dubG9hZGFibGVfaXRlbXMvMzkwOTlfTWFycy1NUk8tb3JiaXRlci1mcmVzaC1jcmF0ZXItc2lyZW51bS1mb3NzYWUuanBn", + "http://localhost:8080/5jW0RvKS5LLaIGrEYhsrePimbs3JZpoYic2tle0Gozs/rt:fit/g:ce/el:1/f:webp/w:300/h:300/aHR0cHM6Ly9tYXJzLm5hc2EuZ292L3N5c3RlbS9kb3dubG9hZGFibGVfaXRlbXMvMzkwOTlfTWFycy1NUk8tb3JiaXRlci1mcmVzaC1jcmF0ZXItc2lyZW51bS1mb3NzYWUuanBn", + "http://localhost:8080/BWjK1nDdf6W4ADkaOFgkZINIWLc9DcPrGy_KR5Pg_kg/rt:fit/g:ce/el:1/f:webp/dpr:0.1/extend:1/exar:1:no:0:1/rot:180/sh:10/pix:10/sm:1/kcr:0/scp:1/mb:10/cb:test/exp:4106340630/fn:test/w:500/h:500/aHR0cHM6Ly9tYXJzLm5hc2EuZ292L3N5c3RlbS9kb3dubG9hZGFibGVfaXRlbXMvMzkwOTlfTWFycy1NUk8tb3JiaXRlci1mcmVzaC1jcmF0ZXItc2lyZW51bS1mb3NzYWUuanBn", + "http://localhost:8080/eHukUJ_Jv2GPz-IxT9W2RFi_Q_M-ukbvS0TfX9ufdjE/rt:fit/g:ce/el:1/f:webp/bl:100/w:500/h:500/aHR0cHM6Ly9tYXJzLm5hc2EuZ292L3N5c3RlbS9kb3dubG9hZGFibGVfaXRlbXMvMzkwOTlfTWFycy1NUk8tb3JiaXRlci1mcmVzaC1jcmF0ZXItc2lyZW51bS1mb3NzYWUuanBn", + "http://localhost:8080/lJ49NfkZxmXrGGEsstAvBpizYiYPiOXXqJ272USfslU/rt:fit/g:ce/el:1/f:webp/w:300/h:300/q:10/aHR0cHM6Ly9tYXJzLm5hc2EuZ292L3N5c3RlbS9kb3dubG9hZGFibGVfaXRlbXMvMzkwOTlfTWFycy1NUk8tb3JiaXRlci1mcmVzaC1jcmF0ZXItc2lyZW51bS1mb3NzYWUuanBn", + "http://localhost:8080/mLAfol3DwMbw_OBOMmUXKlSd1tqolehTwFy5GxhWOFg/rt:fit/g:ce/el:1/f:webp/rs:fit:500:500:1:1/bg:FFCC00/aHR0cHM6Ly9tYXJzLm5hc2EuZ292L3N5c3RlbS9kb3dubG9hZGFibGVfaXRlbXMvMzkwOTlfTWFycy1NUk8tb3JiaXRlci1mcmVzaC1jcmF0ZXItc2lyZW51bS1mb3NzYWUuanBn", + ], + "sources": [ + "http://localhost:8080/5jW0RvKS5LLaIGrEYhsrePimbs3JZpoYic2tle0Gozs/rt:fit/g:ce/el:1/f:webp/w:300/h:300/aHR0cHM6Ly9tYXJzLm5hc2EuZ292L3N5c3RlbS9kb3dubG9hZGFibGVfaXRlbXMvMzkwOTlfTWFycy1NUk8tb3JiaXRlci1mcmVzaC1jcmF0ZXItc2lyZW51bS1mb3NzYWUuanBn", + "http://localhost:8080/lJ49NfkZxmXrGGEsstAvBpizYiYPiOXXqJ272USfslU/rt:fit/g:ce/el:1/f:webp/w:300/h:300/q:10/aHR0cHM6Ly9tYXJzLm5hc2EuZ292L3N5c3RlbS9kb3dubG9hZGFibGVfaXRlbXMvMzkwOTlfTWFycy1NUk8tb3JiaXRlci1mcmVzaC1jcmF0ZXItc2lyZW51bS1mb3NzYWUuanBn", + "http://localhost:8080/mLAfol3DwMbw_OBOMmUXKlSd1tqolehTwFy5GxhWOFg/rt:fit/g:ce/el:1/f:webp/rs:fit:500:500:1:1/bg:FFCC00/aHR0cHM6Ly9tYXJzLm5hc2EuZ292L3N5c3RlbS9kb3dubG9hZGFibGVfaXRlbXMvMzkwOTlfTWFycy1NUk8tb3JiaXRlci1mcmVzaC1jcmF0ZXItc2lyZW51bS1mb3NzYWUuanBn", + "http://localhost:8080/1uXmW9_-sqlIy-jMJhbuzuc1LNJhUS3_Y6XlI2Thpxs/rt:fit/g:ce/el:1/f:webp/rot:180/w:500/h:500/aHR0cHM6Ly9tYXJzLm5hc2EuZ292L3N5c3RlbS9kb3dubG9hZGFibGVfaXRlbXMvMzkwOTlfTWFycy1NUk8tb3JiaXRlci1mcmVzaC1jcmF0ZXItc2lyZW51bS1mb3NzYWUuanBn", + "http://localhost:8080/eHukUJ_Jv2GPz-IxT9W2RFi_Q_M-ukbvS0TfX9ufdjE/rt:fit/g:ce/el:1/f:webp/bl:100/w:500/h:500/aHR0cHM6Ly9tYXJzLm5hc2EuZ292L3N5c3RlbS9kb3dubG9hZGFibGVfaXRlbXMvMzkwOTlfTWFycy1NUk8tb3JiaXRlci1mcmVzaC1jcmF0ZXItc2lyZW51bS1mb3NzYWUuanBn", + "http://localhost:8080/BWjK1nDdf6W4ADkaOFgkZINIWLc9DcPrGy_KR5Pg_kg/rt:fit/g:ce/el:1/f:webp/dpr:0.1/extend:1/exar:1:no:0:1/rot:180/sh:10/pix:10/sm:1/kcr:0/scp:1/mb:10/cb:test/exp:4106340630/fn:test/w:500/h:500/aHR0cHM6Ly9tYXJzLm5hc2EuZ292L3N5c3RlbS9kb3dubG9hZGFibGVfaXRlbXMvMzkwOTlfTWFycy1NUk8tb3JiaXRlci1mcmVzaC1jcmF0ZXItc2lyZW51bS1mb3NzYWUuanBn", + ], +} \ No newline at end of file diff --git a/test/nuxt/providers.test.ts b/test/nuxt/providers.test.ts index 21e7c6b25..3d9bfcc4b 100644 --- a/test/nuxt/providers.test.ts +++ b/test/nuxt/providers.test.ts @@ -2,6 +2,8 @@ import { describe, it, expect } from 'vitest' import { images } from '../providers' +import type { ImgproxyModifiers } from '../../dist/runtime/providers/imgproxy' + import { useNuxtApp } from '#imports' import ipx from '../../dist/runtime/providers/ipx' import none from '../../dist/runtime/providers/none' @@ -16,6 +18,7 @@ import picsum from '../../dist/runtime/providers/picsum' import prepr from '../../dist/runtime/providers/prepr' import glide from '../../dist/runtime/providers/glide' import imgix from '../../dist/runtime/providers/imgix' +import imgproxy from '../../dist/runtime/providers/imgproxy' import gumlet from '../../dist/runtime/providers/gumlet' import imageengine from '../../dist/runtime/providers/imageengine' import unsplash from '../../dist/runtime/providers/unsplash' @@ -263,6 +266,180 @@ describe('Providers', () => { } }) + it('imgproxy', () => { + const providerOptions = { + baseURL: 'http://localhost:8080/', + key: 'ee3b0e07dfc9ec20d5d9588a558753547a8a88c48291ae96171330daf4ce2800', + salt: '8dd0e39bb7b14eeaf02d49e5dc76d2bc0abd9e09d52e7049e791acd3558db68e', + } + for (const image of images) { + const [_src, modifiers] = image.args + const generated = imgproxy().getImage('https://mars.nasa.gov/system/downloadable_items/39099_Mars-MRO-orbiter-fresh-crater-sirenum-fossae.jpg', { modifiers, ...providerOptions }, emptyContext) + + expect(generated.url).toBe(image.imgproxy.url) + } + }) + + it('imgproxy modifiers', () => { + const providerOptions = { + baseURL: 'http://localhost:8080/', + key: 'ee3b0e07dfc9ec20d5d9588a558753547a8a88c48291ae96171330daf4ce2800', + salt: '8dd0e39bb7b14eeaf02d49e5dc76d2bc0abd9e09d52e7049e791acd3558db68e', + } + + const sourceUrl: string = 'https://mars.nasa.gov/system/downloadable_items/39099_Mars-MRO-orbiter-fresh-crater-sirenum-fossae.jpg' + + const testCases: { + modifiers: Partial + expected: { + url: string + } + }[] = [ + { + modifiers: { + width: 100, + height: 100, + fit: 'contain', + format: 'jpeg', + }, + expected: { + url: 'http://localhost:8080/JuXjzxljKHBzGDgciOoZyjbyy1B3vfIs28cnFpVLlHg/rt:fill/g:ce/el:1/f:jpeg/w:100/h:100/aHR0cHM6Ly9tYXJzLm5hc2EuZ292L3N5c3RlbS9kb3dubG9hZGFibGVfaXRlbXMvMzkwOTlfTWFycy1NUk8tb3JiaXRlci1mcmVzaC1jcmF0ZXItc2lyZW51bS1mb3NzYWUuanBn', + }, + }, + { + modifiers: { + resizingType: 'fit', + width: 100, + height: 100, + }, + expected: { + url: 'http://localhost:8080/4HFgdembz0YITmriZMLJHMlr1n2RkQ9vXhHaovfzKE4/rt:fit/g:ce/el:1/f:webp/w:100/h:100/aHR0cHM6Ly9tYXJzLm5hc2EuZ292L3N5c3RlbS9kb3dubG9hZGFibGVfaXRlbXMvMzkwOTlfTWFycy1NUk8tb3JiaXRlci1mcmVzaC1jcmF0ZXItc2lyZW51bS1mb3NzYWUuanBn', + }, + }, + { + modifiers: { + resize: 'fit:100:100:1:1', + background: 'FFCC00', + }, + expected: { + url: 'http://localhost:8080/OuVctWg0AYa-XJyMHCCCQ2dkq9tY2HzaNQTzjsv7pl0/rt:fit/g:ce/el:1/f:webp/rs:fit:100:100:1:1/bg:FFCC00/aHR0cHM6Ly9tYXJzLm5hc2EuZ292L3N5c3RlbS9kb3dubG9hZGFibGVfaXRlbXMvMzkwOTlfTWFycy1NUk8tb3JiaXRlci1mcmVzaC1jcmF0ZXItc2lyZW51bS1mb3NzYWUuanBn', + }, + }, + { + modifiers: { + width: 100, + height: 100, + minWidth: 2000, + minHeight: 2000, + }, + expected: { + url: 'http://localhost:8080/wH6sFQa8jrkfqze2v23klLy9AjiVQgHw1D6dMMAoW_Q/rt:fit/g:ce/el:1/f:webp/w:100/h:100/mw:2000/mh:2000/aHR0cHM6Ly9tYXJzLm5hc2EuZ292L3N5c3RlbS9kb3dubG9hZGFibGVfaXRlbXMvMzkwOTlfTWFycy1NUk8tb3JiaXRlci1mcmVzaC1jcmF0ZXItc2lyZW51bS1mb3NzYWUuanBn', + }, + }, + { + modifiers: { + zoom: '0.2:0.2', + }, + expected: { + url: 'http://localhost:8080/oWAkVGeA2Fk5f7ie0gcqot-R3pBE1rK4gQWomhuTDzE/rt:fit/g:ce/el:1/f:webp/z:0.2:0.2/aHR0cHM6Ly9tYXJzLm5hc2EuZ292L3N5c3RlbS9kb3dubG9hZGFibGVfaXRlbXMvMzkwOTlfTWFycy1NUk8tb3JiaXRlci1mcmVzaC1jcmF0ZXItc2lyZW51bS1mb3NzYWUuanBn', + }, + }, + { + modifiers: { + enlarge: true, + width: 500, + height: 500, + fit: 'fill', + }, + expected: { + url: 'http://localhost:8080/GwqS_Fx_BqRYUi6ccR8yLtbHpQbMV3JnkC0gMycKKx8/rt:fill/g:ce/el:1/f:webp/w:500/h:500/aHR0cHM6Ly9tYXJzLm5hc2EuZ292L3N5c3RlbS9kb3dubG9hZGFibGVfaXRlbXMvMzkwOTlfTWFycy1NUk8tb3JiaXRlci1mcmVzaC1jcmF0ZXItc2lyZW51bS1mb3NzYWUuanBn', + }, + }, + { + modifiers: { + gravity: 'noea', + crop: { + width: 500, + height: 500, + }, + fit: 'fill', + }, + expected: { + url: 'http://localhost:8080/QrUkWSrgGSNMPTi3bptTdRWpGoxI-N0rMUB-dtrpz18/rt:fill/g:noea/el:1/f:webp/c:500:500/aHR0cHM6Ly9tYXJzLm5hc2EuZ292L3N5c3RlbS9kb3dubG9hZGFibGVfaXRlbXMvMzkwOTlfTWFycy1NUk8tb3JiaXRlci1mcmVzaC1jcmF0ZXItc2lyZW51bS1mb3NzYWUuanBn', + }, + }, + { + modifiers: { + autoRotate: true, + }, + expected: { + url: 'http://localhost:8080/ISWjsCzehqjIX2-45HfMLgLc5s27SXJ_caQoVyllS2E/rt:fit/g:ce/el:1/f:webp/ar:1/aHR0cHM6Ly9tYXJzLm5hc2EuZ292L3N5c3RlbS9kb3dubG9hZGFibGVfaXRlbXMvMzkwOTlfTWFycy1NUk8tb3JiaXRlci1mcmVzaC1jcmF0ZXItc2lyZW51bS1mb3NzYWUuanBn', + }, + }, + { + modifiers: { + dpr: 0.1, + extend: true, + extendAspectRatio: '1:no:0:1', + rotate: 192, + background: '255:255:0', + sharpen: 10, + pixelate: 10, + stripMetadata: true, + keepCopyright: false, + stripColorProfile: true, + maxBytes: 10, + cachebuster: 'test', + expires: 4106340630, + filename: 'test', + blur: 100, + }, + expected: { + url: 'http://localhost:8080/VMAygcMqJJaGCooHTgpnsiXdQ2GwGZ8nU-W0ccILWBU/rt:fit/g:ce/el:1/f:webp/dpr:0.1/extend:1/exar:1:no:0:1/rot:180/bg:255:255:0/sh:10/pix:10/sm:1/kcr:0/scp:1/mb:10/cb:test/exp:4106340630/fn:test/bl:100/aHR0cHM6Ly9tYXJzLm5hc2EuZ292L3N5c3RlbS9kb3dubG9hZGFibGVfaXRlbXMvMzkwOTlfTWFycy1NUk8tb3JiaXRlci1mcmVzaC1jcmF0ZXItc2lyZW51bS1mb3NzYWUuanBn', + }, + }, + { + modifiers: { + returnAttachment: true, + }, + expected: { + url: 'http://localhost:8080/wrMWTP6VnM75QBEI8ndqQQrMjADjmRgRpkwzEfefs4k/rt:fit/g:ce/el:1/f:webp/att:1/aHR0cHM6Ly9tYXJzLm5hc2EuZ292L3N5c3RlbS9kb3dubG9hZGFibGVfaXRlbXMvMzkwOTlfTWFycy1NUk8tb3JiaXRlci1mcmVzaC1jcmF0ZXItc2lyZW51bS1mb3NzYWUuanBn', + }, + }, + { + modifiers: { + preset: 'blurry', + }, + expected: { + url: 'http://localhost:8080/edhMPuEjwQSSCGxqpWqG3Q35t1oynvCmKmGQn441sLs/rt:fit/g:ce/el:1/f:webp/pr:blurry/aHR0cHM6Ly9tYXJzLm5hc2EuZ292L3N5c3RlbS9kb3dubG9hZGFibGVfaXRlbXMvMzkwOTlfTWFycy1NUk8tb3JiaXRlci1mcmVzaC1jcmF0ZXItc2lyZW51bS1mb3NzYWUuanBn', + }, + }, + { + modifiers: { + width: 100, + height: 100, + raw: true, + }, + expected: { + url: 'http://localhost:8080/hdLz86a2oYcpYa_K1vf6jff2iskp6OdDnSyhndR1asU/rt:fit/g:ce/el:1/f:webp/w:100/h:100/raw:1/aHR0cHM6Ly9tYXJzLm5hc2EuZ292L3N5c3RlbS9kb3dubG9hZGFibGVfaXRlbXMvMzkwOTlfTWFycy1NUk8tb3JiaXRlci1mcmVzaC1jcmF0ZXItc2lyZW51bS1mb3NzYWUuanBn', + }, + }, + ] + + for (const { modifiers, expected } of testCases) { + const generated = imgproxy().getImage( + sourceUrl, + { + modifiers, + ...providerOptions, + }, + emptyContext, + ) + + expect(generated).toMatchObject(expected) + } + }) + it('imageengine', () => { const providerOptions = { baseURL: '', diff --git a/test/providers.ts b/test/providers.ts index 122d0183e..72254bafb 100644 --- a/test/providers.ts +++ b/test/providers.ts @@ -36,6 +36,7 @@ export const images = [ weserv: { url: 'https://wsrv.nl/?filename=test.png&we&url=https%3A%2F%2Fmy-website.com%2Ftest.png' }, sirv: { url: 'https://demo.sirv.com/test.png' }, hygraph: { url: 'https://eu-central-1-shared-euc1-02.graphassets.com/cltsj3mii0pvd07vwb5cyh1ig/auto_image/cltsrex89477t08unlckqx9ue' }, + imgproxy: { url: 'http://localhost:8080/RnSHbxgnAY8L7YXPPaSYnoMdOEq2dabao5-dLb7I0VM/rt:fit/g:ce/el:1/f:webp/aHR0cHM6Ly9tYXJzLm5hc2EuZ292L3N5c3RlbS9kb3dubG9hZGFibGVfaXRlbXMvMzkwOTlfTWFycy1NUk8tb3JiaXRlci1mcmVzaC1jcmF0ZXItc2lyZW51bS1mb3NzYWUuanBn' }, caisy: { url: 'https://assets.caisy.io/assets/b76210be-a043-4989-98df-ecaf6c6e68d8/056c27e2-81f5-4cd3-b728-cef181dfe7dc/d83ea6f0-f90a-462c-aebd-b8bc615fdce0pexelsmiguelapadrinan1591056.jpg' }, bunny: { url: 'https://bunnyoptimizerdemo.b-cdn.net' }, builderio: { url: 'https://cdn.builder.io/api/v1/image/assets%2FYJIGb4i01jvw0SRdL5Bt%2F869bfbaec9c64415ae68235d9b7b1425' }, @@ -78,6 +79,7 @@ export const images = [ weserv: { url: 'https://wsrv.nl/?filename=test.png&we&w=200&url=https%3A%2F%2Fmy-website.com%2Ftest.png' }, sirv: { url: 'https://demo.sirv.com/test.png?w=200' }, hygraph: { url: 'https://eu-central-1-shared-euc1-02.graphassets.com/cltsj3mii0pvd07vwb5cyh1ig/resize=width:200/auto_image/cltsrex89477t08unlckqx9ue' }, + imgproxy: { url: 'http://localhost:8080/41rs6qPwSaHdR9Hi_iyUucFJjK9baq-mFzDLzyStTjA/rt:fit/g:ce/el:1/f:webp/w:200/aHR0cHM6Ly9tYXJzLm5hc2EuZ292L3N5c3RlbS9kb3dubG9hZGFibGVfaXRlbXMvMzkwOTlfTWFycy1NUk8tb3JiaXRlci1mcmVzaC1jcmF0ZXItc2lyZW51bS1mb3NzYWUuanBn' }, caisy: { url: 'https://assets.caisy.io/assets/b76210be-a043-4989-98df-ecaf6c6e68d8/056c27e2-81f5-4cd3-b728-cef181dfe7dc/d83ea6f0-f90a-462c-aebd-b8bc615fdce0pexelsmiguelapadrinan1591056.jpg?w=200' }, bunny: { url: 'https://bunnyoptimizerdemo.b-cdn.net?width=200' }, builderio: { url: 'https://cdn.builder.io/api/v1/image/assets%2FYJIGb4i01jvw0SRdL5Bt%2F869bfbaec9c64415ae68235d9b7b1425?width=200' }, @@ -119,6 +121,7 @@ export const images = [ weserv: { url: 'https://wsrv.nl/?filename=test.png&we&h=200&url=https%3A%2F%2Fmy-website.com%2Ftest.png' }, sirv: { url: 'https://demo.sirv.com/test.png?h=200' }, hygraph: { url: 'https://eu-central-1-shared-euc1-02.graphassets.com/cltsj3mii0pvd07vwb5cyh1ig/resize=height:200/auto_image/cltsrex89477t08unlckqx9ue' }, + imgproxy: { url: 'http://localhost:8080/_xAmWIavytrl341UbnVsMx85d592eDBTifdSHDOBOCY/rt:fit/g:ce/el:1/f:webp/h:200/aHR0cHM6Ly9tYXJzLm5hc2EuZ292L3N5c3RlbS9kb3dubG9hZGFibGVfaXRlbXMvMzkwOTlfTWFycy1NUk8tb3JiaXRlci1mcmVzaC1jcmF0ZXItc2lyZW51bS1mb3NzYWUuanBn' }, caisy: { url: 'https://assets.caisy.io/assets/b76210be-a043-4989-98df-ecaf6c6e68d8/056c27e2-81f5-4cd3-b728-cef181dfe7dc/d83ea6f0-f90a-462c-aebd-b8bc615fdce0pexelsmiguelapadrinan1591056.jpg?h=200' }, bunny: { url: 'https://bunnyoptimizerdemo.b-cdn.net?height=200' }, builderio: { url: 'https://cdn.builder.io/api/v1/image/assets%2FYJIGb4i01jvw0SRdL5Bt%2F869bfbaec9c64415ae68235d9b7b1425?height=200' }, @@ -160,6 +163,7 @@ export const images = [ weserv: { url: 'https://wsrv.nl/?filename=test.png&we&w=200&h=200&url=https%3A%2F%2Fmy-website.com%2Ftest.png' }, sirv: { url: 'https://demo.sirv.com/test.png?w=200&h=200' }, hygraph: { url: 'https://eu-central-1-shared-euc1-02.graphassets.com/cltsj3mii0pvd07vwb5cyh1ig/resize=width:200,height:200/auto_image/cltsrex89477t08unlckqx9ue' }, + imgproxy: { url: 'http://localhost:8080/IJ3EJDIxR-uSe2nRNHgzCGDeZ5PDA5C1Uulkg1eWCic/rt:fit/g:ce/el:1/f:webp/w:200/h:200/aHR0cHM6Ly9tYXJzLm5hc2EuZ292L3N5c3RlbS9kb3dubG9hZGFibGVfaXRlbXMvMzkwOTlfTWFycy1NUk8tb3JiaXRlci1mcmVzaC1jcmF0ZXItc2lyZW51bS1mb3NzYWUuanBn' }, caisy: { url: 'https://assets.caisy.io/assets/b76210be-a043-4989-98df-ecaf6c6e68d8/056c27e2-81f5-4cd3-b728-cef181dfe7dc/d83ea6f0-f90a-462c-aebd-b8bc615fdce0pexelsmiguelapadrinan1591056.jpg?w=200&h=200' }, bunny: { url: 'https://bunnyoptimizerdemo.b-cdn.net?width=200&height=200' }, builderio: { url: 'https://cdn.builder.io/api/v1/image/assets%2FYJIGb4i01jvw0SRdL5Bt%2F869bfbaec9c64415ae68235d9b7b1425?width=200&height=200' }, @@ -201,6 +205,7 @@ export const images = [ weserv: { url: 'https://wsrv.nl/?filename=test.png&we&w=200&h=200&fit=contain&url=https%3A%2F%2Fmy-website.com%2Ftest.png' }, sirv: { url: 'https://demo.sirv.com/test.png?w=200&h=200&scale.option=fit' }, hygraph: { url: 'https://eu-central-1-shared-euc1-02.graphassets.com/cltsj3mii0pvd07vwb5cyh1ig/resize=width:200,height:200,fit:max/auto_image/cltsrex89477t08unlckqx9ue' }, + imgproxy: { url: 'http://localhost:8080/8JBjeY3YrZC5J-cod4TbQZphtoipjrQDa_YPGRMiTjE/rt:fill/g:ce/el:1/f:webp/w:200/h:200/aHR0cHM6Ly9tYXJzLm5hc2EuZ292L3N5c3RlbS9kb3dubG9hZGFibGVfaXRlbXMvMzkwOTlfTWFycy1NUk8tb3JiaXRlci1mcmVzaC1jcmF0ZXItc2lyZW51bS1mb3NzYWUuanBn' }, caisy: { url: 'https://assets.caisy.io/assets/b76210be-a043-4989-98df-ecaf6c6e68d8/056c27e2-81f5-4cd3-b728-cef181dfe7dc/d83ea6f0-f90a-462c-aebd-b8bc615fdce0pexelsmiguelapadrinan1591056.jpg?w=200&h=200' }, bunny: { url: 'https://bunnyoptimizerdemo.b-cdn.net?width=200&height=200' }, builderio: { url: 'https://cdn.builder.io/api/v1/image/assets%2FYJIGb4i01jvw0SRdL5Bt%2F869bfbaec9c64415ae68235d9b7b1425?width=200&height=200&fit=contain' }, @@ -242,6 +247,7 @@ export const images = [ weserv: { url: 'https://wsrv.nl/?filename=test.png&we&w=200&h=200&fit=contain&output=jpg&url=https%3A%2F%2Fmy-website.com%2Ftest.png' }, sirv: { url: 'https://demo.sirv.com/test.png?w=200&h=200&scale.option=fit&format=jpg' }, hygraph: { url: 'https://eu-central-1-shared-euc1-02.graphassets.com/cltsj3mii0pvd07vwb5cyh1ig/resize=width:200,height:200,fit:max/output=format:jpeg/cltsrex89477t08unlckqx9ue' }, + imgproxy: { url: 'http://localhost:8080/NSn3mqMg-kDwJXakPDTP57pwzg6f74UoUFRre4qk-9s/rt:fill/g:ce/el:1/f:jpeg/w:200/h:200/aHR0cHM6Ly9tYXJzLm5hc2EuZ292L3N5c3RlbS9kb3dubG9hZGFibGVfaXRlbXMvMzkwOTlfTWFycy1NUk8tb3JiaXRlci1mcmVzaC1jcmF0ZXItc2lyZW51bS1mb3NzYWUuanBn' }, caisy: { url: 'https://assets.caisy.io/assets/b76210be-a043-4989-98df-ecaf6c6e68d8/056c27e2-81f5-4cd3-b728-cef181dfe7dc/d83ea6f0-f90a-462c-aebd-b8bc615fdce0pexelsmiguelapadrinan1591056.jpg?w=200&h=200' }, bunny: { url: 'https://bunnyoptimizerdemo.b-cdn.net?width=200&height=200' }, builderio: { url: 'https://cdn.builder.io/api/v1/image/assets%2FYJIGb4i01jvw0SRdL5Bt%2F869bfbaec9c64415ae68235d9b7b1425?width=200&height=200&fit=contain&format=jpeg' }, From e93d25e4785feb37a81294e1af32aaf6abb9edbc Mon Sep 17 00:00:00 2001 From: "Vlad Z." Date: Sat, 14 Feb 2026 22:40:55 -0500 Subject: [PATCH 02/13] fix: downgrade package version; --- package.json | 2 +- pnpm-lock.yaml | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/package.json b/package.json index e8090aea2..d1a15d1c9 100755 --- a/package.json +++ b/package.json @@ -46,7 +46,7 @@ "test:built:types": "nuxt typecheck playground && nuxt typecheck example" }, "dependencies": { - "@noble/hashes": "^2.0.1", + "@noble/hashes": "^1.8.0", "@nuxt/kit": "^4.3.1", "consola": "^3.4.2", "defu": "^6.1.4", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 99005a89b..045857d2f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -15,8 +15,8 @@ importers: .: dependencies: '@noble/hashes': - specifier: ^2.0.1 - version: 2.0.1 + specifier: ^1.8.0 + version: 1.8.0 '@nuxt/kit': specifier: ^4.3.1 version: 4.3.1(magicast@0.5.1) @@ -1307,9 +1307,9 @@ packages: '@napi-rs/wasm-runtime@1.1.1': resolution: {integrity: sha512-p64ah1M1ld8xjWv3qbvFwHiFVWrq1yFvV4f7w+mzaqiR4IlSgkqhcRdHwsGgomwzBH51sRY4NEowLxnaBjcW/A==} - '@noble/hashes@2.0.1': - resolution: {integrity: sha512-XlOlEbQcE9fmuXxrVTXCTlG2nlRXa9Rj3rr5Ue/+tX+nmkgbX720YHh0VR3hBF9xDvwnb8D2shVGOwNx+ulArw==} - engines: {node: '>= 20.19.0'} + '@noble/hashes@1.8.0': + resolution: {integrity: sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==} + engines: {node: ^14.21.3 || >=16} '@nodelib/fs.scandir@2.1.5': resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} @@ -9165,7 +9165,7 @@ snapshots: '@tybys/wasm-util': 0.10.1 optional: true - '@noble/hashes@2.0.1': {} + '@noble/hashes@1.8.0': {} '@nodelib/fs.scandir@2.1.5': dependencies: From 4e139031d939302f3baf38c4b4e7929bcec4cd9d Mon Sep 17 00:00:00 2001 From: "Vlad Z." Date: Sat, 14 Feb 2026 22:47:35 -0500 Subject: [PATCH 03/13] fix: code review fixes; --- docs/content/3.providers/imgproxy.md | 10 ++++++---- playground/app/providers.ts | 2 +- test/nuxt/providers.test.ts | 2 +- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/docs/content/3.providers/imgproxy.md b/docs/content/3.providers/imgproxy.md index 54435c666..deb628ed8 100644 --- a/docs/content/3.providers/imgproxy.md +++ b/docs/content/3.providers/imgproxy.md @@ -15,7 +15,7 @@ At a minimum, you must configure the `imgproxy` provider with the `baseURL`, `ke ```ts [nuxt.config.ts] export default defineNuxtConfig({ image: { - imageengine: { + imgproxy: { baseURL: 'http://localhost:8080/', key: 'ee3b0e07dfc9ec20d5d9588a558753547a8a88c48291ae96171330daf4ce2800', salt: '8dd0e39bb7b14eeaf02d49e5dc76d2bc0abd9e09d52e7049e791acd3558db68e', @@ -34,11 +34,13 @@ The `fit` option is kept for backwards compatibility with @nuxt/image. The `cont ## Imgproxy Modifiers By default, the Imgproxy provider has the following settings for modifiers -``` +```typescript +const defaultModifiers: Partial = { resizingType: 'fit', gravity: 'ce', enlarge: true, format: 'webp', +} ``` If you want to change them, define them in your nuxt.config.ts file. @@ -98,7 +100,7 @@ Example 2: Add blur to an image: ```vue { dpr: 0.1, extend: true, extendAspectRatio: '1:no:0:1', - rotate: 192, + rotate: 180, background: '255:255:0', sharpen: 10, pixelate: 10, From 5b6f7cb53bd4363d04816d11f2bef3f780d5a4c3 Mon Sep 17 00:00:00 2001 From: "Vlad Z." Date: Sat, 14 Feb 2026 22:50:30 -0500 Subject: [PATCH 04/13] fix: allow zero for rotate; --- src/runtime/providers/imgproxy.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/runtime/providers/imgproxy.ts b/src/runtime/providers/imgproxy.ts index fdbde6755..28019f5d4 100644 --- a/src/runtime/providers/imgproxy.ts +++ b/src/runtime/providers/imgproxy.ts @@ -152,7 +152,7 @@ const operationsGenerator = createOperationsGenerator { - if (typeof value !== 'number' || value <= 0 || value >= 359) { + if (typeof value !== 'number' || value < 0 || value >= 359) { throw new TypeError('Wrong rotate format') } From e9eb8cbed6b85027f73f622a31d1cf0e14c3dca7 Mon Sep 17 00:00:00 2001 From: "Vlad Z." Date: Sat, 14 Feb 2026 22:57:47 -0500 Subject: [PATCH 05/13] fix: added JSdoc --- src/runtime/providers/imgproxy.ts | 49 +++++++++++++++++++++++++++++-- 1 file changed, 46 insertions(+), 3 deletions(-) diff --git a/src/runtime/providers/imgproxy.ts b/src/runtime/providers/imgproxy.ts index 28019f5d4..0ed802e3d 100644 --- a/src/runtime/providers/imgproxy.ts +++ b/src/runtime/providers/imgproxy.ts @@ -1,5 +1,3 @@ -// https://imgproxy.net/ - import { joinURL } from 'ufo' import { createOperationsGenerator } from '../utils/index' import { defineProvider } from '../utils/provider' @@ -70,6 +68,11 @@ interface ImgproxyOptions { modifiers?: Partial } +/** + * Convert boolean, number, string or ImgproxyCrop to Imgproxy boolean primitive + * + * @param value + */ const booleanMap = (value: string | number | boolean | ImgproxyCrop | ImgproxyBooleanPrimitive): number => { if (typeof value === 'boolean') { return value ? 1 : 0 @@ -131,6 +134,11 @@ const operationsGenerator = createOperationsGenerator { if (typeof value === 'string') { return value @@ -151,8 +159,16 @@ const operationsGenerator = createOperationsGenerator { - if (typeof value !== 'number' || value < 0 || value >= 359) { + if (typeof value !== 'number' || value < 0 || value > 359) { throw new TypeError('Wrong rotate format') } @@ -163,6 +179,11 @@ const operationsGenerator = createOperationsGenerator = { format: 'webp', } +/** + * Convert @nuxt/image modifiers to Imgproxy modifiers + * + * @param modifiers + */ function resolveModifiers(modifiers: Partial): Partial { if (modifiers?.fit) { switch (modifiers.fit) { @@ -216,6 +255,10 @@ function resolveModifiers(modifiers: Partial): Partial({ getImage: (src, { modifiers, baseURL, key, salt }) => { const mergeModifiers = resolveModifiers(defu(modifiers, defaultModifiers)) From 9751805d5550abcdc5b0fad9c189abdb6c753323 Mon Sep 17 00:00:00 2001 From: "Vlad Z." Date: Sat, 14 Feb 2026 23:00:02 -0500 Subject: [PATCH 06/13] fix: Remove empty header; --- docs/content/3.providers/imgproxy.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/docs/content/3.providers/imgproxy.md b/docs/content/3.providers/imgproxy.md index deb628ed8..bdc1a75f2 100644 --- a/docs/content/3.providers/imgproxy.md +++ b/docs/content/3.providers/imgproxy.md @@ -29,8 +29,6 @@ export default defineNuxtConfig({ All `fit` values are converted to [`resizing_type`](https://docs.imgproxy.net/usage/processing#resizing-type) option provided by Imgproxy. The `fit` option is kept for backwards compatibility with @nuxt/image. The `contain` value is converted to `fill`. -## Imgproxy default options - ## Imgproxy Modifiers By default, the Imgproxy provider has the following settings for modifiers From 060e723ae3bf612c46706f0266b4103c26a89e35 Mon Sep 17 00:00:00 2001 From: "Vlad Z." Date: Sat, 14 Feb 2026 23:01:00 -0500 Subject: [PATCH 07/13] fix: update doc; --- docs/content/3.providers/imgproxy.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/content/3.providers/imgproxy.md b/docs/content/3.providers/imgproxy.md index bdc1a75f2..12363b596 100644 --- a/docs/content/3.providers/imgproxy.md +++ b/docs/content/3.providers/imgproxy.md @@ -90,7 +90,7 @@ Example 1: Cropping an image to a width and height of 500x500 and rotate by 180 src="/some-image.jpg" width="500" height="500" - :modifiers="{ rotate: '180' }" + :modifiers="{ rotate: 180 }" /> ``` From 8a0d6d3fd2ce17af9fb3c64fc7a7beb9f1ea6669 Mon Sep 17 00:00:00 2001 From: "Vlad Z." Date: Sat, 14 Feb 2026 23:02:06 -0500 Subject: [PATCH 08/13] fix: missing extend; --- src/runtime/providers/imgproxy.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/runtime/providers/imgproxy.ts b/src/runtime/providers/imgproxy.ts index 0ed802e3d..5c48f4187 100644 --- a/src/runtime/providers/imgproxy.ts +++ b/src/runtime/providers/imgproxy.ts @@ -105,6 +105,7 @@ const operationsGenerator = createOperationsGenerator Date: Sun, 15 Feb 2026 11:57:47 -0500 Subject: [PATCH 09/13] chore(imgproxy provider): Added more examples; Added support of default fit modifier; Updated documentation; --- docs/content/3.providers/imgproxy.md | 240 +++++++++++++++++++++++---- src/runtime/providers/imgproxy.ts | 27 ++- test/nuxt/providers.test.ts | 64 +++++-- test/providers.ts | 12 +- 4 files changed, 284 insertions(+), 59 deletions(-) diff --git a/docs/content/3.providers/imgproxy.md b/docs/content/3.providers/imgproxy.md index 12363b596..581edb6bc 100644 --- a/docs/content/3.providers/imgproxy.md +++ b/docs/content/3.providers/imgproxy.md @@ -10,43 +10,189 @@ links: Integration between [Imgproxy](https://imgproxy.net/) and the image module. -At a minimum, you must configure the `imgproxy` provider with the `baseURL`, `key` and `salt` set to your Imgproxy instance: +At a minimum, you must configure the `imgproxy` provider with the `baseURL`, `key` and `salt` set to your Imgproxy +instance: ```ts [nuxt.config.ts] export default defineNuxtConfig({ - image: { - imgproxy: { - baseURL: 'http://localhost:8080/', - key: 'ee3b0e07dfc9ec20d5d9588a558753547a8a88c48291ae96171330daf4ce2800', - salt: '8dd0e39bb7b14eeaf02d49e5dc76d2bc0abd9e09d52e7049e791acd3558db68e', + image: { + imgproxy: { + baseURL: 'http://localhost:8080/', + key: 'ee3b0e07dfc9ec20d5d9588a558753547a8a88c48291ae96171330daf4ce2800', + salt: '8dd0e39bb7b14eeaf02d49e5dc76d2bc0abd9e09d52e7049e791acd3558db68e', + } } - } }) ``` -## Imgproxy `fit` Values +## Processing of `fit` values by the imgproxy provider -All `fit` values are converted to [`resizing_type`](https://docs.imgproxy.net/usage/processing#resizing-type) option provided by Imgproxy. -The `fit` option is kept for backwards compatibility with @nuxt/image. The `contain` value is converted to `fill`. +The `fit` modifier controls how images are resized using **imgproxy**. +It maps to the following imgproxy-related fields: + +- `resizingType` — defines the resizing strategy (`fill`, `fit`, `force`) +- `extend` - enables canvas extension (letterboxing) when required + +The behavior depends on whether valid `width` and/or `height` values are provided. + +--- + +### Dimension Handling + +Before applying any `fit` behavior: + +- If both `width` and `height` are positive numbers → **both dimensions are considered defined**. +- If only one dimension is provided → behavior falls back to proportional resizing. +- If neither dimension is provided → resizing defaults to proportional behavior. + +Exact box-based behaviors (`cover`, `contain`, `fill`, `outside`) fully apply only when both dimensions are defined. + +--- + +### Supported `fit` Values + +#### `cover` + +**Description** + +Preserves an aspect ratio and ensures the image fully covers the target box. +When both dimensions are defined, parts of the image may be cropped. + +**Parameters Used** + +- `resizingType = 'fill'` when both dimensions are provided +- `resizingType = 'fit'` when one or both dimensions are missing + +**Behavior** + +- With both dimensions: full coverage of the box (cropping allowed). +- With partial or no dimensions: proportional resizing without enforced coverage. + +--- + +#### `contain` + +**Description** + +Preserves aspect ratio and fits the image within the target box. +When both dimensions are defined, padding (letterboxing) is applied so the final image matches the exact dimensions. + +**Parameters Used** + +- `resizingType = 'fit'` +- `extend = true` when both dimensions are provided +- `extend = false` (or omitted) when not + +**Behavior** + +- Proportional scaling within bounds. +- Padding is applied only when both width and height are defined. +- With a single dimension, padding is not applied. + +--- + +#### `fill` + +**Description** + +Ignores the original aspect ratio and stretches the image to exactly match the provided dimensions. + +**Parameters Used** + +- `resizingType = 'force'` when both dimensions are provided +- `resizingType = 'fit'` when one or both dimensions are missing + +**Behavior** + +- With both dimensions: image is stretched (aspect ratio ignored). +- Otherwise: proportional resizing is used instead of distortion. + +--- + +#### `inside` + +**Description** + +Preserves an aspect ratio and resizes the image to be as large as possible while ensuring its dimensions are less than or +equal to the specified box. + +**Parameters Used** + +- `resizingType = 'fit'` + +**Behavior** + +- Always performs proportional scaling. +- Works consistently with one, two, or no defined dimensions. + +--- + +#### `outside` + +**Description** + +Preserves an aspect ratio and resizes the image so that both dimensions are greater than or equal to the specified box. + +**Implementation Note** + +imgproxy does not provide a dedicated resizing strategy that guarantees true `outside` behavior without inspecting the +source image’s aspect ratio. +This implementation approximates the behavior. + +**Parameters Used** + +- `resizingType = 'fill'` when both dimensions are provided +- `resizingType = 'fit'` when one or both dimensions are missing + +**Behavior** + +- With both dimensions: behaves similarly to `cover` (may crop). +- Otherwise: falls back to proportional resizing. + +--- + +# Summary Table + +| fit value | Both Dimensions Provided | resizingType | extend | +|-----------|--------------------------|--------------|--------| +| cover | Yes | fill | — | +| cover | No | fit | — | +| contain | Yes | fit | true | +| contain | No | fit | false | +| fill | Yes | force | — | +| fill | No | fit | — | +| inside | Any | fit | — | +| outside | Yes | fill | — | +| outside | No | fit | — | + +--- + +# Dimension Edge Cases + +- If neither `width` nor `height` is provided, resizing defaults to proportional behavior. +- If only one dimension is provided, proportional scaling is applied. +- Exact box behaviors are guaranteed only when both dimensions are defined. ## Imgproxy Modifiers By default, the Imgproxy provider has the following settings for modifiers + ```typescript const defaultModifiers: Partial = { - resizingType: 'fit', - gravity: 'ce', - enlarge: true, - format: 'webp', + resizingType: 'auto', + gravity: 'ce', + format: 'webp', } ``` -If you want to change them, define them in your nuxt.config.ts file. +If you want to change them, you can define it `nuxt.config.ts` file. -In addition to the [standard modifiers](/usage/nuxt-img#modifiers), you can also use most of [Imgproxy Options](https://docs.imgproxy.net/usage/processing#processing-options) by adding them to the `modifiers` property with the following attribute names: +In addition to the [standard modifiers](/usage/nuxt-img#modifiers), you can also use most +of [Imgproxy Options](https://docs.imgproxy.net/usage/processing#processing-options) by adding them to the `modifiers` +property with the following attribute names: -- `format` -- `resizingType` - alias for `fit` +- `format` +- `resizingType` - `resize` - `size` - `minWidth` @@ -80,41 +226,65 @@ In addition to the [standard modifiers](/usage/nuxt-img#modifiers), you can also - `maxAnimationFrameResolution` - `maxResultDimension` -> The provider does not verify the accuracy of your data entry. If you see “Invalid URL” from Imgproxy, check that the parameters are correct. Some parameters (e.g., `crop`) accept an object as input and convert the request into a valid string for your server. You can find more detailed information about all modifiers on the [Imgproxy](https://docs.imgproxy.net/usage/processing#processing-options) website. +> The provider does not verify the accuracy of your data entry. If you see “Invalid URL” from Imgproxy, check that the +> parameters are correct. Some parameters (e.g., `crop`) accept an object as input and convert the request into a valid +> string for your server. You can find more detailed information about all image processing options on +> the [Imgproxy](https://docs.imgproxy.net/usage/processing#processing-options) website. Example 1: Cropping an image to a width and height of 500x500 and rotate by 180 degrees: ```vue + ``` Example 2: Add blur to an image: ```vue + ``` -Example 2: Using [presets](https://docs.imgproxy.net/configuration/options#presets): +Example 3: Using [presets](https://docs.imgproxy.net/configuration/options#presets): ```vue + + +``` + +Example 4: Advanced image manipulation: + +```vue + ``` diff --git a/src/runtime/providers/imgproxy.ts b/src/runtime/providers/imgproxy.ts index 5c48f4187..c90e01775 100644 --- a/src/runtime/providers/imgproxy.ts +++ b/src/runtime/providers/imgproxy.ts @@ -25,7 +25,7 @@ export interface ImgproxyModifiers extends Omit = { - resizingType: 'fit', + resizingType: 'auto', gravity: 'ce', - enlarge: true, format: 'webp', } @@ -242,13 +241,29 @@ const defaultModifiers: Partial = { */ function resolveModifiers(modifiers: Partial): Partial { if (modifiers?.fit) { + const hasW = typeof modifiers?.width === 'number' && modifiers.width > 0 + const hasH = typeof modifiers?.height === 'number' && modifiers.height > 0 + const hasBoth = hasW && hasH + switch (modifiers.fit) { + case 'cover': + modifiers.resizingType = hasBoth ? 'fill' : 'fit' + break case 'contain': - modifiers.resizingType = 'fill' + modifiers.resizingType = 'fit' + modifiers.extend = hasBoth break - default: - modifiers.resizingType = modifiers.fit + case 'fill': + modifiers.resizingType = hasBoth ? 'force' : 'fit' break + case 'inside': + modifiers.resizingType = 'fit' + break + case 'outside': + modifiers.resizingType = hasBoth ? 'fill' : 'fit' + break + default: + throw new TypeError('Unsupported fit format') } delete modifiers.fit } diff --git a/test/nuxt/providers.test.ts b/test/nuxt/providers.test.ts index a5e141f60..6a030bee2 100644 --- a/test/nuxt/providers.test.ts +++ b/test/nuxt/providers.test.ts @@ -295,6 +295,46 @@ describe('Providers', () => { url: string } }[] = [ + { + modifiers: { + fit: 'contain', + width: 100, + height: 100, + }, + expected: { + url: 'http://localhost:8080/WDEF0lvBmcLhtzT11ww-9XMtA9YY2BiMWACintty0yg/rt:fit/g:ce/f:webp/w:100/h:100/ex:1/aHR0cHM6Ly9tYXJzLm5hc2EuZ292L3N5c3RlbS9kb3dubG9hZGFibGVfaXRlbXMvMzkwOTlfTWFycy1NUk8tb3JiaXRlci1mcmVzaC1jcmF0ZXItc2lyZW51bS1mb3NzYWUuanBn', + }, + }, + { + modifiers: { + fit: 'cover', + width: 100, + height: 100, + }, + expected: { + url: 'http://localhost:8080/xnHZGPNtwahuGtmDh7vD5PQYjsxB8vpvyGr3eiq3jGo/rt:fill/g:ce/f:webp/w:100/h:100/aHR0cHM6Ly9tYXJzLm5hc2EuZ292L3N5c3RlbS9kb3dubG9hZGFibGVfaXRlbXMvMzkwOTlfTWFycy1NUk8tb3JiaXRlci1mcmVzaC1jcmF0ZXItc2lyZW51bS1mb3NzYWUuanBn', + }, + }, + { + modifiers: { + fit: 'outside', + width: 100, + height: 100, + }, + expected: { + url: 'http://localhost:8080/xnHZGPNtwahuGtmDh7vD5PQYjsxB8vpvyGr3eiq3jGo/rt:fill/g:ce/f:webp/w:100/h:100/aHR0cHM6Ly9tYXJzLm5hc2EuZ292L3N5c3RlbS9kb3dubG9hZGFibGVfaXRlbXMvMzkwOTlfTWFycy1NUk8tb3JiaXRlci1mcmVzaC1jcmF0ZXItc2lyZW51bS1mb3NzYWUuanBn', + }, + }, + { + modifiers: { + fit: 'inside', + width: 100, + height: 100, + }, + expected: { + url: 'http://localhost:8080/J-5_ixsKBIzg0qwYtypqPcC6MnEp2a5iErUKCbNqID8/rt:fit/g:ce/f:webp/w:100/h:100/aHR0cHM6Ly9tYXJzLm5hc2EuZ292L3N5c3RlbS9kb3dubG9hZGFibGVfaXRlbXMvMzkwOTlfTWFycy1NUk8tb3JiaXRlci1mcmVzaC1jcmF0ZXItc2lyZW51bS1mb3NzYWUuanBn', + }, + }, { modifiers: { width: 100, @@ -303,7 +343,7 @@ describe('Providers', () => { format: 'jpeg', }, expected: { - url: 'http://localhost:8080/JuXjzxljKHBzGDgciOoZyjbyy1B3vfIs28cnFpVLlHg/rt:fill/g:ce/el:1/f:jpeg/w:100/h:100/aHR0cHM6Ly9tYXJzLm5hc2EuZ292L3N5c3RlbS9kb3dubG9hZGFibGVfaXRlbXMvMzkwOTlfTWFycy1NUk8tb3JiaXRlci1mcmVzaC1jcmF0ZXItc2lyZW51bS1mb3NzYWUuanBn', + url: 'http://localhost:8080/0s7rNhOEt_rzLVU0CdGXMbkV6j5fH2VOI6PQlxaQbsc/rt:fit/g:ce/f:jpeg/w:100/h:100/ex:1/aHR0cHM6Ly9tYXJzLm5hc2EuZ292L3N5c3RlbS9kb3dubG9hZGFibGVfaXRlbXMvMzkwOTlfTWFycy1NUk8tb3JiaXRlci1mcmVzaC1jcmF0ZXItc2lyZW51bS1mb3NzYWUuanBn', }, }, { @@ -313,7 +353,7 @@ describe('Providers', () => { height: 100, }, expected: { - url: 'http://localhost:8080/4HFgdembz0YITmriZMLJHMlr1n2RkQ9vXhHaovfzKE4/rt:fit/g:ce/el:1/f:webp/w:100/h:100/aHR0cHM6Ly9tYXJzLm5hc2EuZ292L3N5c3RlbS9kb3dubG9hZGFibGVfaXRlbXMvMzkwOTlfTWFycy1NUk8tb3JiaXRlci1mcmVzaC1jcmF0ZXItc2lyZW51bS1mb3NzYWUuanBn', + url: 'http://localhost:8080/J-5_ixsKBIzg0qwYtypqPcC6MnEp2a5iErUKCbNqID8/rt:fit/g:ce/f:webp/w:100/h:100/aHR0cHM6Ly9tYXJzLm5hc2EuZ292L3N5c3RlbS9kb3dubG9hZGFibGVfaXRlbXMvMzkwOTlfTWFycy1NUk8tb3JiaXRlci1mcmVzaC1jcmF0ZXItc2lyZW51bS1mb3NzYWUuanBn', }, }, { @@ -322,7 +362,7 @@ describe('Providers', () => { background: 'FFCC00', }, expected: { - url: 'http://localhost:8080/OuVctWg0AYa-XJyMHCCCQ2dkq9tY2HzaNQTzjsv7pl0/rt:fit/g:ce/el:1/f:webp/rs:fit:100:100:1:1/bg:FFCC00/aHR0cHM6Ly9tYXJzLm5hc2EuZ292L3N5c3RlbS9kb3dubG9hZGFibGVfaXRlbXMvMzkwOTlfTWFycy1NUk8tb3JiaXRlci1mcmVzaC1jcmF0ZXItc2lyZW51bS1mb3NzYWUuanBn', + url: 'http://localhost:8080/0RHxLESHHIkkMAv8z4RlWIG6smintg8G9wtf0l5hCR0/rt:auto/g:ce/f:webp/rs:fit:100:100:1:1/bg:FFCC00/aHR0cHM6Ly9tYXJzLm5hc2EuZ292L3N5c3RlbS9kb3dubG9hZGFibGVfaXRlbXMvMzkwOTlfTWFycy1NUk8tb3JiaXRlci1mcmVzaC1jcmF0ZXItc2lyZW51bS1mb3NzYWUuanBn', }, }, { @@ -333,7 +373,7 @@ describe('Providers', () => { minHeight: 2000, }, expected: { - url: 'http://localhost:8080/wH6sFQa8jrkfqze2v23klLy9AjiVQgHw1D6dMMAoW_Q/rt:fit/g:ce/el:1/f:webp/w:100/h:100/mw:2000/mh:2000/aHR0cHM6Ly9tYXJzLm5hc2EuZ292L3N5c3RlbS9kb3dubG9hZGFibGVfaXRlbXMvMzkwOTlfTWFycy1NUk8tb3JiaXRlci1mcmVzaC1jcmF0ZXItc2lyZW51bS1mb3NzYWUuanBn', + url: 'http://localhost:8080/Zbqd-IqLtLZnIiHtFKAYPEpo6FuQOPraNd4nsL52Isg/rt:auto/g:ce/f:webp/w:100/h:100/mw:2000/mh:2000/aHR0cHM6Ly9tYXJzLm5hc2EuZ292L3N5c3RlbS9kb3dubG9hZGFibGVfaXRlbXMvMzkwOTlfTWFycy1NUk8tb3JiaXRlci1mcmVzaC1jcmF0ZXItc2lyZW51bS1mb3NzYWUuanBn', }, }, { @@ -341,7 +381,7 @@ describe('Providers', () => { zoom: '0.2:0.2', }, expected: { - url: 'http://localhost:8080/oWAkVGeA2Fk5f7ie0gcqot-R3pBE1rK4gQWomhuTDzE/rt:fit/g:ce/el:1/f:webp/z:0.2:0.2/aHR0cHM6Ly9tYXJzLm5hc2EuZ292L3N5c3RlbS9kb3dubG9hZGFibGVfaXRlbXMvMzkwOTlfTWFycy1NUk8tb3JiaXRlci1mcmVzaC1jcmF0ZXItc2lyZW51bS1mb3NzYWUuanBn', + url: 'http://localhost:8080/3GanjhskAMK8HRDfxSmIk1e_pE7BgjRptfSaokW1mDM/rt:auto/g:ce/f:webp/z:0.2:0.2/aHR0cHM6Ly9tYXJzLm5hc2EuZ292L3N5c3RlbS9kb3dubG9hZGFibGVfaXRlbXMvMzkwOTlfTWFycy1NUk8tb3JiaXRlci1mcmVzaC1jcmF0ZXItc2lyZW51bS1mb3NzYWUuanBn', }, }, { @@ -352,7 +392,7 @@ describe('Providers', () => { fit: 'fill', }, expected: { - url: 'http://localhost:8080/GwqS_Fx_BqRYUi6ccR8yLtbHpQbMV3JnkC0gMycKKx8/rt:fill/g:ce/el:1/f:webp/w:500/h:500/aHR0cHM6Ly9tYXJzLm5hc2EuZ292L3N5c3RlbS9kb3dubG9hZGFibGVfaXRlbXMvMzkwOTlfTWFycy1NUk8tb3JiaXRlci1mcmVzaC1jcmF0ZXItc2lyZW51bS1mb3NzYWUuanBn', + url: 'http://localhost:8080/brfso4JHXYB1bTSWet-LEmhVhZbPr_T6kgZi2gRs5CM/rt:force/g:ce/f:webp/el:1/w:500/h:500/aHR0cHM6Ly9tYXJzLm5hc2EuZ292L3N5c3RlbS9kb3dubG9hZGFibGVfaXRlbXMvMzkwOTlfTWFycy1NUk8tb3JiaXRlci1mcmVzaC1jcmF0ZXItc2lyZW51bS1mb3NzYWUuanBn', }, }, { @@ -365,7 +405,7 @@ describe('Providers', () => { fit: 'fill', }, expected: { - url: 'http://localhost:8080/QrUkWSrgGSNMPTi3bptTdRWpGoxI-N0rMUB-dtrpz18/rt:fill/g:noea/el:1/f:webp/c:500:500/aHR0cHM6Ly9tYXJzLm5hc2EuZ292L3N5c3RlbS9kb3dubG9hZGFibGVfaXRlbXMvMzkwOTlfTWFycy1NUk8tb3JiaXRlci1mcmVzaC1jcmF0ZXItc2lyZW51bS1mb3NzYWUuanBn', + url: 'http://localhost:8080/h90gjXPIuMedfFTptj3YBVx6wQybWqirYzoN_w3DfqM/rt:fit/g:noea/f:webp/c:500:500/aHR0cHM6Ly9tYXJzLm5hc2EuZ292L3N5c3RlbS9kb3dubG9hZGFibGVfaXRlbXMvMzkwOTlfTWFycy1NUk8tb3JiaXRlci1mcmVzaC1jcmF0ZXItc2lyZW51bS1mb3NzYWUuanBn', }, }, { @@ -373,7 +413,7 @@ describe('Providers', () => { autoRotate: true, }, expected: { - url: 'http://localhost:8080/ISWjsCzehqjIX2-45HfMLgLc5s27SXJ_caQoVyllS2E/rt:fit/g:ce/el:1/f:webp/ar:1/aHR0cHM6Ly9tYXJzLm5hc2EuZ292L3N5c3RlbS9kb3dubG9hZGFibGVfaXRlbXMvMzkwOTlfTWFycy1NUk8tb3JiaXRlci1mcmVzaC1jcmF0ZXItc2lyZW51bS1mb3NzYWUuanBn', + url: 'http://localhost:8080/YJn9J2b4RzApSgFXomIHirK3lt1oxhVj-FR7odgPGE0/rt:auto/g:ce/f:webp/ar:1/aHR0cHM6Ly9tYXJzLm5hc2EuZ292L3N5c3RlbS9kb3dubG9hZGFibGVfaXRlbXMvMzkwOTlfTWFycy1NUk8tb3JiaXRlci1mcmVzaC1jcmF0ZXItc2lyZW51bS1mb3NzYWUuanBn', }, }, { @@ -395,7 +435,7 @@ describe('Providers', () => { blur: 100, }, expected: { - url: 'http://localhost:8080/VMAygcMqJJaGCooHTgpnsiXdQ2GwGZ8nU-W0ccILWBU/rt:fit/g:ce/el:1/f:webp/dpr:0.1/extend:1/exar:1:no:0:1/rot:180/bg:255:255:0/sh:10/pix:10/sm:1/kcr:0/scp:1/mb:10/cb:test/exp:4106340630/fn:test/bl:100/aHR0cHM6Ly9tYXJzLm5hc2EuZ292L3N5c3RlbS9kb3dubG9hZGFibGVfaXRlbXMvMzkwOTlfTWFycy1NUk8tb3JiaXRlci1mcmVzaC1jcmF0ZXItc2lyZW51bS1mb3NzYWUuanBn', + url: 'http://localhost:8080/2M-s-AwAAAm54MhfBSM8luh3_6fadayCOd8LHqsSD10/rt:auto/g:ce/f:webp/dpr:0.1/ex:1/exar:1:no:0:1/rot:180/bg:255:255:0/sh:10/pix:10/sm:1/kcr:0/scp:1/mb:10/cb:test/exp:4106340630/fn:test/bl:100/aHR0cHM6Ly9tYXJzLm5hc2EuZ292L3N5c3RlbS9kb3dubG9hZGFibGVfaXRlbXMvMzkwOTlfTWFycy1NUk8tb3JiaXRlci1mcmVzaC1jcmF0ZXItc2lyZW51bS1mb3NzYWUuanBn', }, }, { @@ -403,7 +443,7 @@ describe('Providers', () => { returnAttachment: true, }, expected: { - url: 'http://localhost:8080/wrMWTP6VnM75QBEI8ndqQQrMjADjmRgRpkwzEfefs4k/rt:fit/g:ce/el:1/f:webp/att:1/aHR0cHM6Ly9tYXJzLm5hc2EuZ292L3N5c3RlbS9kb3dubG9hZGFibGVfaXRlbXMvMzkwOTlfTWFycy1NUk8tb3JiaXRlci1mcmVzaC1jcmF0ZXItc2lyZW51bS1mb3NzYWUuanBn', + url: 'http://localhost:8080/u_mLtYCSpOu7VawiphkQ51pZeNb0PFcP-3lRSIVALAg/rt:auto/g:ce/f:webp/att:1/aHR0cHM6Ly9tYXJzLm5hc2EuZ292L3N5c3RlbS9kb3dubG9hZGFibGVfaXRlbXMvMzkwOTlfTWFycy1NUk8tb3JiaXRlci1mcmVzaC1jcmF0ZXItc2lyZW51bS1mb3NzYWUuanBn', }, }, { @@ -411,7 +451,7 @@ describe('Providers', () => { preset: 'blurry', }, expected: { - url: 'http://localhost:8080/edhMPuEjwQSSCGxqpWqG3Q35t1oynvCmKmGQn441sLs/rt:fit/g:ce/el:1/f:webp/pr:blurry/aHR0cHM6Ly9tYXJzLm5hc2EuZ292L3N5c3RlbS9kb3dubG9hZGFibGVfaXRlbXMvMzkwOTlfTWFycy1NUk8tb3JiaXRlci1mcmVzaC1jcmF0ZXItc2lyZW51bS1mb3NzYWUuanBn', + url: 'http://localhost:8080/DJ4Naz9SLYbQOIJDeq83o5RBj-7u4gcFoB-eFhHbU3o/rt:auto/g:ce/f:webp/pr:blurry/aHR0cHM6Ly9tYXJzLm5hc2EuZ292L3N5c3RlbS9kb3dubG9hZGFibGVfaXRlbXMvMzkwOTlfTWFycy1NUk8tb3JiaXRlci1mcmVzaC1jcmF0ZXItc2lyZW51bS1mb3NzYWUuanBn', }, }, { @@ -421,7 +461,7 @@ describe('Providers', () => { raw: true, }, expected: { - url: 'http://localhost:8080/hdLz86a2oYcpYa_K1vf6jff2iskp6OdDnSyhndR1asU/rt:fit/g:ce/el:1/f:webp/w:100/h:100/raw:1/aHR0cHM6Ly9tYXJzLm5hc2EuZ292L3N5c3RlbS9kb3dubG9hZGFibGVfaXRlbXMvMzkwOTlfTWFycy1NUk8tb3JiaXRlci1mcmVzaC1jcmF0ZXItc2lyZW51bS1mb3NzYWUuanBn', + url: 'http://localhost:8080/MQLhXkyO7bXibkqMUJL7RffHQ9Ks_jMwjWTPvAG9vhM/rt:auto/g:ce/f:webp/w:100/h:100/raw:1/aHR0cHM6Ly9tYXJzLm5hc2EuZ292L3N5c3RlbS9kb3dubG9hZGFibGVfaXRlbXMvMzkwOTlfTWFycy1NUk8tb3JiaXRlci1mcmVzaC1jcmF0ZXItc2lyZW51bS1mb3NzYWUuanBn', }, }, ] diff --git a/test/providers.ts b/test/providers.ts index 72254bafb..2b6967f20 100644 --- a/test/providers.ts +++ b/test/providers.ts @@ -36,7 +36,7 @@ export const images = [ weserv: { url: 'https://wsrv.nl/?filename=test.png&we&url=https%3A%2F%2Fmy-website.com%2Ftest.png' }, sirv: { url: 'https://demo.sirv.com/test.png' }, hygraph: { url: 'https://eu-central-1-shared-euc1-02.graphassets.com/cltsj3mii0pvd07vwb5cyh1ig/auto_image/cltsrex89477t08unlckqx9ue' }, - imgproxy: { url: 'http://localhost:8080/RnSHbxgnAY8L7YXPPaSYnoMdOEq2dabao5-dLb7I0VM/rt:fit/g:ce/el:1/f:webp/aHR0cHM6Ly9tYXJzLm5hc2EuZ292L3N5c3RlbS9kb3dubG9hZGFibGVfaXRlbXMvMzkwOTlfTWFycy1NUk8tb3JiaXRlci1mcmVzaC1jcmF0ZXItc2lyZW51bS1mb3NzYWUuanBn' }, + imgproxy: { url: 'http://localhost:8080/nMRxrWjsgSmUuYkivM76-7f1WaCa2GCxFOx8zqJnRmY/rt:auto/g:ce/f:webp/aHR0cHM6Ly9tYXJzLm5hc2EuZ292L3N5c3RlbS9kb3dubG9hZGFibGVfaXRlbXMvMzkwOTlfTWFycy1NUk8tb3JiaXRlci1mcmVzaC1jcmF0ZXItc2lyZW51bS1mb3NzYWUuanBn' }, caisy: { url: 'https://assets.caisy.io/assets/b76210be-a043-4989-98df-ecaf6c6e68d8/056c27e2-81f5-4cd3-b728-cef181dfe7dc/d83ea6f0-f90a-462c-aebd-b8bc615fdce0pexelsmiguelapadrinan1591056.jpg' }, bunny: { url: 'https://bunnyoptimizerdemo.b-cdn.net' }, builderio: { url: 'https://cdn.builder.io/api/v1/image/assets%2FYJIGb4i01jvw0SRdL5Bt%2F869bfbaec9c64415ae68235d9b7b1425' }, @@ -79,7 +79,7 @@ export const images = [ weserv: { url: 'https://wsrv.nl/?filename=test.png&we&w=200&url=https%3A%2F%2Fmy-website.com%2Ftest.png' }, sirv: { url: 'https://demo.sirv.com/test.png?w=200' }, hygraph: { url: 'https://eu-central-1-shared-euc1-02.graphassets.com/cltsj3mii0pvd07vwb5cyh1ig/resize=width:200/auto_image/cltsrex89477t08unlckqx9ue' }, - imgproxy: { url: 'http://localhost:8080/41rs6qPwSaHdR9Hi_iyUucFJjK9baq-mFzDLzyStTjA/rt:fit/g:ce/el:1/f:webp/w:200/aHR0cHM6Ly9tYXJzLm5hc2EuZ292L3N5c3RlbS9kb3dubG9hZGFibGVfaXRlbXMvMzkwOTlfTWFycy1NUk8tb3JiaXRlci1mcmVzaC1jcmF0ZXItc2lyZW51bS1mb3NzYWUuanBn' }, + imgproxy: { url: 'http://localhost:8080/jBlUz9woW03iM4Vz0jHSO_2Z2tEKxtBtp5gQFcmlqWs/rt:auto/g:ce/f:webp/w:200/aHR0cHM6Ly9tYXJzLm5hc2EuZ292L3N5c3RlbS9kb3dubG9hZGFibGVfaXRlbXMvMzkwOTlfTWFycy1NUk8tb3JiaXRlci1mcmVzaC1jcmF0ZXItc2lyZW51bS1mb3NzYWUuanBn' }, caisy: { url: 'https://assets.caisy.io/assets/b76210be-a043-4989-98df-ecaf6c6e68d8/056c27e2-81f5-4cd3-b728-cef181dfe7dc/d83ea6f0-f90a-462c-aebd-b8bc615fdce0pexelsmiguelapadrinan1591056.jpg?w=200' }, bunny: { url: 'https://bunnyoptimizerdemo.b-cdn.net?width=200' }, builderio: { url: 'https://cdn.builder.io/api/v1/image/assets%2FYJIGb4i01jvw0SRdL5Bt%2F869bfbaec9c64415ae68235d9b7b1425?width=200' }, @@ -121,7 +121,7 @@ export const images = [ weserv: { url: 'https://wsrv.nl/?filename=test.png&we&h=200&url=https%3A%2F%2Fmy-website.com%2Ftest.png' }, sirv: { url: 'https://demo.sirv.com/test.png?h=200' }, hygraph: { url: 'https://eu-central-1-shared-euc1-02.graphassets.com/cltsj3mii0pvd07vwb5cyh1ig/resize=height:200/auto_image/cltsrex89477t08unlckqx9ue' }, - imgproxy: { url: 'http://localhost:8080/_xAmWIavytrl341UbnVsMx85d592eDBTifdSHDOBOCY/rt:fit/g:ce/el:1/f:webp/h:200/aHR0cHM6Ly9tYXJzLm5hc2EuZ292L3N5c3RlbS9kb3dubG9hZGFibGVfaXRlbXMvMzkwOTlfTWFycy1NUk8tb3JiaXRlci1mcmVzaC1jcmF0ZXItc2lyZW51bS1mb3NzYWUuanBn' }, + imgproxy: { url: 'http://localhost:8080/dtMPxKBvt7NNP8oDcJoSP1CPORtvk_FW__-EeVgYuHQ/rt:auto/g:ce/f:webp/h:200/aHR0cHM6Ly9tYXJzLm5hc2EuZ292L3N5c3RlbS9kb3dubG9hZGFibGVfaXRlbXMvMzkwOTlfTWFycy1NUk8tb3JiaXRlci1mcmVzaC1jcmF0ZXItc2lyZW51bS1mb3NzYWUuanBn' }, caisy: { url: 'https://assets.caisy.io/assets/b76210be-a043-4989-98df-ecaf6c6e68d8/056c27e2-81f5-4cd3-b728-cef181dfe7dc/d83ea6f0-f90a-462c-aebd-b8bc615fdce0pexelsmiguelapadrinan1591056.jpg?h=200' }, bunny: { url: 'https://bunnyoptimizerdemo.b-cdn.net?height=200' }, builderio: { url: 'https://cdn.builder.io/api/v1/image/assets%2FYJIGb4i01jvw0SRdL5Bt%2F869bfbaec9c64415ae68235d9b7b1425?height=200' }, @@ -163,7 +163,7 @@ export const images = [ weserv: { url: 'https://wsrv.nl/?filename=test.png&we&w=200&h=200&url=https%3A%2F%2Fmy-website.com%2Ftest.png' }, sirv: { url: 'https://demo.sirv.com/test.png?w=200&h=200' }, hygraph: { url: 'https://eu-central-1-shared-euc1-02.graphassets.com/cltsj3mii0pvd07vwb5cyh1ig/resize=width:200,height:200/auto_image/cltsrex89477t08unlckqx9ue' }, - imgproxy: { url: 'http://localhost:8080/IJ3EJDIxR-uSe2nRNHgzCGDeZ5PDA5C1Uulkg1eWCic/rt:fit/g:ce/el:1/f:webp/w:200/h:200/aHR0cHM6Ly9tYXJzLm5hc2EuZ292L3N5c3RlbS9kb3dubG9hZGFibGVfaXRlbXMvMzkwOTlfTWFycy1NUk8tb3JiaXRlci1mcmVzaC1jcmF0ZXItc2lyZW51bS1mb3NzYWUuanBn' }, + imgproxy: { url: 'http://localhost:8080/KtShqkyGorHRam6uqGtvd0fNn7oDWod4pbdezs7v2Co/rt:auto/g:ce/f:webp/w:200/h:200/aHR0cHM6Ly9tYXJzLm5hc2EuZ292L3N5c3RlbS9kb3dubG9hZGFibGVfaXRlbXMvMzkwOTlfTWFycy1NUk8tb3JiaXRlci1mcmVzaC1jcmF0ZXItc2lyZW51bS1mb3NzYWUuanBn' }, caisy: { url: 'https://assets.caisy.io/assets/b76210be-a043-4989-98df-ecaf6c6e68d8/056c27e2-81f5-4cd3-b728-cef181dfe7dc/d83ea6f0-f90a-462c-aebd-b8bc615fdce0pexelsmiguelapadrinan1591056.jpg?w=200&h=200' }, bunny: { url: 'https://bunnyoptimizerdemo.b-cdn.net?width=200&height=200' }, builderio: { url: 'https://cdn.builder.io/api/v1/image/assets%2FYJIGb4i01jvw0SRdL5Bt%2F869bfbaec9c64415ae68235d9b7b1425?width=200&height=200' }, @@ -205,7 +205,7 @@ export const images = [ weserv: { url: 'https://wsrv.nl/?filename=test.png&we&w=200&h=200&fit=contain&url=https%3A%2F%2Fmy-website.com%2Ftest.png' }, sirv: { url: 'https://demo.sirv.com/test.png?w=200&h=200&scale.option=fit' }, hygraph: { url: 'https://eu-central-1-shared-euc1-02.graphassets.com/cltsj3mii0pvd07vwb5cyh1ig/resize=width:200,height:200,fit:max/auto_image/cltsrex89477t08unlckqx9ue' }, - imgproxy: { url: 'http://localhost:8080/8JBjeY3YrZC5J-cod4TbQZphtoipjrQDa_YPGRMiTjE/rt:fill/g:ce/el:1/f:webp/w:200/h:200/aHR0cHM6Ly9tYXJzLm5hc2EuZ292L3N5c3RlbS9kb3dubG9hZGFibGVfaXRlbXMvMzkwOTlfTWFycy1NUk8tb3JiaXRlci1mcmVzaC1jcmF0ZXItc2lyZW51bS1mb3NzYWUuanBn' }, + imgproxy: { url: 'http://localhost:8080/VV3y1JTp_YUqWy0Lrpu6-GDJfpehkO7Zx7kTYMgER-g/rt:fit/g:ce/f:webp/w:200/h:200/ex:1/aHR0cHM6Ly9tYXJzLm5hc2EuZ292L3N5c3RlbS9kb3dubG9hZGFibGVfaXRlbXMvMzkwOTlfTWFycy1NUk8tb3JiaXRlci1mcmVzaC1jcmF0ZXItc2lyZW51bS1mb3NzYWUuanBn' }, caisy: { url: 'https://assets.caisy.io/assets/b76210be-a043-4989-98df-ecaf6c6e68d8/056c27e2-81f5-4cd3-b728-cef181dfe7dc/d83ea6f0-f90a-462c-aebd-b8bc615fdce0pexelsmiguelapadrinan1591056.jpg?w=200&h=200' }, bunny: { url: 'https://bunnyoptimizerdemo.b-cdn.net?width=200&height=200' }, builderio: { url: 'https://cdn.builder.io/api/v1/image/assets%2FYJIGb4i01jvw0SRdL5Bt%2F869bfbaec9c64415ae68235d9b7b1425?width=200&height=200&fit=contain' }, @@ -247,7 +247,7 @@ export const images = [ weserv: { url: 'https://wsrv.nl/?filename=test.png&we&w=200&h=200&fit=contain&output=jpg&url=https%3A%2F%2Fmy-website.com%2Ftest.png' }, sirv: { url: 'https://demo.sirv.com/test.png?w=200&h=200&scale.option=fit&format=jpg' }, hygraph: { url: 'https://eu-central-1-shared-euc1-02.graphassets.com/cltsj3mii0pvd07vwb5cyh1ig/resize=width:200,height:200,fit:max/output=format:jpeg/cltsrex89477t08unlckqx9ue' }, - imgproxy: { url: 'http://localhost:8080/NSn3mqMg-kDwJXakPDTP57pwzg6f74UoUFRre4qk-9s/rt:fill/g:ce/el:1/f:jpeg/w:200/h:200/aHR0cHM6Ly9tYXJzLm5hc2EuZ292L3N5c3RlbS9kb3dubG9hZGFibGVfaXRlbXMvMzkwOTlfTWFycy1NUk8tb3JiaXRlci1mcmVzaC1jcmF0ZXItc2lyZW51bS1mb3NzYWUuanBn' }, + imgproxy: { url: 'http://localhost:8080/Ry5p-XqKl7_kgwAm1Ir1V8aCKdax2jnzDXtscG85zmg/rt:fit/g:ce/f:jpeg/w:200/h:200/ex:1/aHR0cHM6Ly9tYXJzLm5hc2EuZ292L3N5c3RlbS9kb3dubG9hZGFibGVfaXRlbXMvMzkwOTlfTWFycy1NUk8tb3JiaXRlci1mcmVzaC1jcmF0ZXItc2lyZW51bS1mb3NzYWUuanBn' }, caisy: { url: 'https://assets.caisy.io/assets/b76210be-a043-4989-98df-ecaf6c6e68d8/056c27e2-81f5-4cd3-b728-cef181dfe7dc/d83ea6f0-f90a-462c-aebd-b8bc615fdce0pexelsmiguelapadrinan1591056.jpg?w=200&h=200' }, bunny: { url: 'https://bunnyoptimizerdemo.b-cdn.net?width=200&height=200' }, builderio: { url: 'https://cdn.builder.io/api/v1/image/assets%2FYJIGb4i01jvw0SRdL5Bt%2F869bfbaec9c64415ae68235d9b7b1425?width=200&height=200&fit=contain&format=jpeg' }, From ad2b3be31d0760425f2b4c7bfd910a48abb89c4a Mon Sep 17 00:00:00 2001 From: "Vlad Z." Date: Sun, 15 Feb 2026 12:02:21 -0500 Subject: [PATCH 10/13] fix: tests; --- .nuxtrc | 2 +- test/e2e/__snapshots__/imgproxy.json5 | 24 ++++++++++++------------ 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/.nuxtrc b/.nuxtrc index 1e1fe8339..59379b578 100644 --- a/.nuxtrc +++ b/.nuxtrc @@ -1 +1 @@ -setups.@nuxt/test-utils="4.0.0" \ No newline at end of file +setups.@nuxt/test-utils="4.0.0" diff --git a/test/e2e/__snapshots__/imgproxy.json5 b/test/e2e/__snapshots__/imgproxy.json5 index bfadcd7ff..905f81f35 100644 --- a/test/e2e/__snapshots__/imgproxy.json5 +++ b/test/e2e/__snapshots__/imgproxy.json5 @@ -1,18 +1,18 @@ { "requests": [ - "http://localhost:8080/1uXmW9_-sqlIy-jMJhbuzuc1LNJhUS3_Y6XlI2Thpxs/rt:fit/g:ce/el:1/f:webp/rot:180/w:500/h:500/aHR0cHM6Ly9tYXJzLm5hc2EuZ292L3N5c3RlbS9kb3dubG9hZGFibGVfaXRlbXMvMzkwOTlfTWFycy1NUk8tb3JiaXRlci1mcmVzaC1jcmF0ZXItc2lyZW51bS1mb3NzYWUuanBn", - "http://localhost:8080/5jW0RvKS5LLaIGrEYhsrePimbs3JZpoYic2tle0Gozs/rt:fit/g:ce/el:1/f:webp/w:300/h:300/aHR0cHM6Ly9tYXJzLm5hc2EuZ292L3N5c3RlbS9kb3dubG9hZGFibGVfaXRlbXMvMzkwOTlfTWFycy1NUk8tb3JiaXRlci1mcmVzaC1jcmF0ZXItc2lyZW51bS1mb3NzYWUuanBn", - "http://localhost:8080/BWjK1nDdf6W4ADkaOFgkZINIWLc9DcPrGy_KR5Pg_kg/rt:fit/g:ce/el:1/f:webp/dpr:0.1/extend:1/exar:1:no:0:1/rot:180/sh:10/pix:10/sm:1/kcr:0/scp:1/mb:10/cb:test/exp:4106340630/fn:test/w:500/h:500/aHR0cHM6Ly9tYXJzLm5hc2EuZ292L3N5c3RlbS9kb3dubG9hZGFibGVfaXRlbXMvMzkwOTlfTWFycy1NUk8tb3JiaXRlci1mcmVzaC1jcmF0ZXItc2lyZW51bS1mb3NzYWUuanBn", - "http://localhost:8080/eHukUJ_Jv2GPz-IxT9W2RFi_Q_M-ukbvS0TfX9ufdjE/rt:fit/g:ce/el:1/f:webp/bl:100/w:500/h:500/aHR0cHM6Ly9tYXJzLm5hc2EuZ292L3N5c3RlbS9kb3dubG9hZGFibGVfaXRlbXMvMzkwOTlfTWFycy1NUk8tb3JiaXRlci1mcmVzaC1jcmF0ZXItc2lyZW51bS1mb3NzYWUuanBn", - "http://localhost:8080/lJ49NfkZxmXrGGEsstAvBpizYiYPiOXXqJ272USfslU/rt:fit/g:ce/el:1/f:webp/w:300/h:300/q:10/aHR0cHM6Ly9tYXJzLm5hc2EuZ292L3N5c3RlbS9kb3dubG9hZGFibGVfaXRlbXMvMzkwOTlfTWFycy1NUk8tb3JiaXRlci1mcmVzaC1jcmF0ZXItc2lyZW51bS1mb3NzYWUuanBn", - "http://localhost:8080/mLAfol3DwMbw_OBOMmUXKlSd1tqolehTwFy5GxhWOFg/rt:fit/g:ce/el:1/f:webp/rs:fit:500:500:1:1/bg:FFCC00/aHR0cHM6Ly9tYXJzLm5hc2EuZ292L3N5c3RlbS9kb3dubG9hZGFibGVfaXRlbXMvMzkwOTlfTWFycy1NUk8tb3JiaXRlci1mcmVzaC1jcmF0ZXItc2lyZW51bS1mb3NzYWUuanBn", + "http://localhost:8080/1iW16unhWC6fdIuuk5gVNEq48L4MGEepYK6DjeFwWmo/rt:auto/g:ce/f:webp/rot:180/w:500/h:500/aHR0cHM6Ly9tYXJzLm5hc2EuZ292L3N5c3RlbS9kb3dubG9hZGFibGVfaXRlbXMvMzkwOTlfTWFycy1NUk8tb3JiaXRlci1mcmVzaC1jcmF0ZXItc2lyZW51bS1mb3NzYWUuanBn", + "http://localhost:8080/U0eyKFEnztOizBuOIb5abnDeKWBVW-b_Ke1qVQwqm-Y/rt:auto/g:ce/f:webp/bl:100/w:500/h:500/aHR0cHM6Ly9tYXJzLm5hc2EuZ292L3N5c3RlbS9kb3dubG9hZGFibGVfaXRlbXMvMzkwOTlfTWFycy1NUk8tb3JiaXRlci1mcmVzaC1jcmF0ZXItc2lyZW51bS1mb3NzYWUuanBn", + "http://localhost:8080/Ylc_Rt5-wznwDNG9DYlu0I7YJBKQ_3fd1IW3UdJ-qFk/rt:auto/g:ce/f:webp/rs:fit:500:500:1:1/bg:FFCC00/aHR0cHM6Ly9tYXJzLm5hc2EuZ292L3N5c3RlbS9kb3dubG9hZGFibGVfaXRlbXMvMzkwOTlfTWFycy1NUk8tb3JiaXRlci1mcmVzaC1jcmF0ZXItc2lyZW51bS1mb3NzYWUuanBn", + "http://localhost:8080/biYdMhkZl8V5vnTlYnYsAoXLP9NnHBVkFT0cGLjxdVU/rt:auto/g:ce/f:webp/dpr:0.1/ex:1/exar:1:no:0:1/rot:180/sh:10/pix:10/sm:1/kcr:0/scp:1/mb:10/cb:test/exp:4106340630/fn:test/w:500/h:500/aHR0cHM6Ly9tYXJzLm5hc2EuZ292L3N5c3RlbS9kb3dubG9hZGFibGVfaXRlbXMvMzkwOTlfTWFycy1NUk8tb3JiaXRlci1mcmVzaC1jcmF0ZXItc2lyZW51bS1mb3NzYWUuanBn", + "http://localhost:8080/cboFXjcBPZOl8x-rxAeX-uWPjY3xqpFfYQDOsBLVoGs/rt:auto/g:ce/f:webp/w:300/h:300/aHR0cHM6Ly9tYXJzLm5hc2EuZ292L3N5c3RlbS9kb3dubG9hZGFibGVfaXRlbXMvMzkwOTlfTWFycy1NUk8tb3JiaXRlci1mcmVzaC1jcmF0ZXItc2lyZW51bS1mb3NzYWUuanBn", + "http://localhost:8080/zTIsniZNIm8038SWjYOnlQClTBbrPyebnl62k1gjze8/rt:auto/g:ce/f:webp/w:300/h:300/q:10/aHR0cHM6Ly9tYXJzLm5hc2EuZ292L3N5c3RlbS9kb3dubG9hZGFibGVfaXRlbXMvMzkwOTlfTWFycy1NUk8tb3JiaXRlci1mcmVzaC1jcmF0ZXItc2lyZW51bS1mb3NzYWUuanBn", ], "sources": [ - "http://localhost:8080/5jW0RvKS5LLaIGrEYhsrePimbs3JZpoYic2tle0Gozs/rt:fit/g:ce/el:1/f:webp/w:300/h:300/aHR0cHM6Ly9tYXJzLm5hc2EuZ292L3N5c3RlbS9kb3dubG9hZGFibGVfaXRlbXMvMzkwOTlfTWFycy1NUk8tb3JiaXRlci1mcmVzaC1jcmF0ZXItc2lyZW51bS1mb3NzYWUuanBn", - "http://localhost:8080/lJ49NfkZxmXrGGEsstAvBpizYiYPiOXXqJ272USfslU/rt:fit/g:ce/el:1/f:webp/w:300/h:300/q:10/aHR0cHM6Ly9tYXJzLm5hc2EuZ292L3N5c3RlbS9kb3dubG9hZGFibGVfaXRlbXMvMzkwOTlfTWFycy1NUk8tb3JiaXRlci1mcmVzaC1jcmF0ZXItc2lyZW51bS1mb3NzYWUuanBn", - "http://localhost:8080/mLAfol3DwMbw_OBOMmUXKlSd1tqolehTwFy5GxhWOFg/rt:fit/g:ce/el:1/f:webp/rs:fit:500:500:1:1/bg:FFCC00/aHR0cHM6Ly9tYXJzLm5hc2EuZ292L3N5c3RlbS9kb3dubG9hZGFibGVfaXRlbXMvMzkwOTlfTWFycy1NUk8tb3JiaXRlci1mcmVzaC1jcmF0ZXItc2lyZW51bS1mb3NzYWUuanBn", - "http://localhost:8080/1uXmW9_-sqlIy-jMJhbuzuc1LNJhUS3_Y6XlI2Thpxs/rt:fit/g:ce/el:1/f:webp/rot:180/w:500/h:500/aHR0cHM6Ly9tYXJzLm5hc2EuZ292L3N5c3RlbS9kb3dubG9hZGFibGVfaXRlbXMvMzkwOTlfTWFycy1NUk8tb3JiaXRlci1mcmVzaC1jcmF0ZXItc2lyZW51bS1mb3NzYWUuanBn", - "http://localhost:8080/eHukUJ_Jv2GPz-IxT9W2RFi_Q_M-ukbvS0TfX9ufdjE/rt:fit/g:ce/el:1/f:webp/bl:100/w:500/h:500/aHR0cHM6Ly9tYXJzLm5hc2EuZ292L3N5c3RlbS9kb3dubG9hZGFibGVfaXRlbXMvMzkwOTlfTWFycy1NUk8tb3JiaXRlci1mcmVzaC1jcmF0ZXItc2lyZW51bS1mb3NzYWUuanBn", - "http://localhost:8080/BWjK1nDdf6W4ADkaOFgkZINIWLc9DcPrGy_KR5Pg_kg/rt:fit/g:ce/el:1/f:webp/dpr:0.1/extend:1/exar:1:no:0:1/rot:180/sh:10/pix:10/sm:1/kcr:0/scp:1/mb:10/cb:test/exp:4106340630/fn:test/w:500/h:500/aHR0cHM6Ly9tYXJzLm5hc2EuZ292L3N5c3RlbS9kb3dubG9hZGFibGVfaXRlbXMvMzkwOTlfTWFycy1NUk8tb3JiaXRlci1mcmVzaC1jcmF0ZXItc2lyZW51bS1mb3NzYWUuanBn", + "http://localhost:8080/cboFXjcBPZOl8x-rxAeX-uWPjY3xqpFfYQDOsBLVoGs/rt:auto/g:ce/f:webp/w:300/h:300/aHR0cHM6Ly9tYXJzLm5hc2EuZ292L3N5c3RlbS9kb3dubG9hZGFibGVfaXRlbXMvMzkwOTlfTWFycy1NUk8tb3JiaXRlci1mcmVzaC1jcmF0ZXItc2lyZW51bS1mb3NzYWUuanBn", + "http://localhost:8080/zTIsniZNIm8038SWjYOnlQClTBbrPyebnl62k1gjze8/rt:auto/g:ce/f:webp/w:300/h:300/q:10/aHR0cHM6Ly9tYXJzLm5hc2EuZ292L3N5c3RlbS9kb3dubG9hZGFibGVfaXRlbXMvMzkwOTlfTWFycy1NUk8tb3JiaXRlci1mcmVzaC1jcmF0ZXItc2lyZW51bS1mb3NzYWUuanBn", + "http://localhost:8080/Ylc_Rt5-wznwDNG9DYlu0I7YJBKQ_3fd1IW3UdJ-qFk/rt:auto/g:ce/f:webp/rs:fit:500:500:1:1/bg:FFCC00/aHR0cHM6Ly9tYXJzLm5hc2EuZ292L3N5c3RlbS9kb3dubG9hZGFibGVfaXRlbXMvMzkwOTlfTWFycy1NUk8tb3JiaXRlci1mcmVzaC1jcmF0ZXItc2lyZW51bS1mb3NzYWUuanBn", + "http://localhost:8080/1iW16unhWC6fdIuuk5gVNEq48L4MGEepYK6DjeFwWmo/rt:auto/g:ce/f:webp/rot:180/w:500/h:500/aHR0cHM6Ly9tYXJzLm5hc2EuZ292L3N5c3RlbS9kb3dubG9hZGFibGVfaXRlbXMvMzkwOTlfTWFycy1NUk8tb3JiaXRlci1mcmVzaC1jcmF0ZXItc2lyZW51bS1mb3NzYWUuanBn", + "http://localhost:8080/U0eyKFEnztOizBuOIb5abnDeKWBVW-b_Ke1qVQwqm-Y/rt:auto/g:ce/f:webp/bl:100/w:500/h:500/aHR0cHM6Ly9tYXJzLm5hc2EuZ292L3N5c3RlbS9kb3dubG9hZGFibGVfaXRlbXMvMzkwOTlfTWFycy1NUk8tb3JiaXRlci1mcmVzaC1jcmF0ZXItc2lyZW51bS1mb3NzYWUuanBn", + "http://localhost:8080/biYdMhkZl8V5vnTlYnYsAoXLP9NnHBVkFT0cGLjxdVU/rt:auto/g:ce/f:webp/dpr:0.1/ex:1/exar:1:no:0:1/rot:180/sh:10/pix:10/sm:1/kcr:0/scp:1/mb:10/cb:test/exp:4106340630/fn:test/w:500/h:500/aHR0cHM6Ly9tYXJzLm5hc2EuZ292L3N5c3RlbS9kb3dubG9hZGFibGVfaXRlbXMvMzkwOTlfTWFycy1NUk8tb3JiaXRlci1mcmVzaC1jcmF0ZXItc2lyZW51bS1mb3NzYWUuanBn", ], } \ No newline at end of file From c1ef973cd489d4776de4867bc0a6df9ff01591f5 Mon Sep 17 00:00:00 2001 From: "Vlad Z." Date: Sun, 15 Feb 2026 12:09:48 -0500 Subject: [PATCH 11/13] fix: docs for imgproxy; --- docs/content/3.providers/imgproxy.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/content/3.providers/imgproxy.md b/docs/content/3.providers/imgproxy.md index 581edb6bc..278046084 100644 --- a/docs/content/3.providers/imgproxy.md +++ b/docs/content/3.providers/imgproxy.md @@ -151,7 +151,7 @@ This implementation approximates the behavior. --- -# Summary Table +### Summary Table | fit value | Both Dimensions Provided | resizingType | extend | |-----------|--------------------------|--------------|--------| @@ -167,7 +167,7 @@ This implementation approximates the behavior. --- -# Dimension Edge Cases +### Dimension Edge Cases - If neither `width` nor `height` is provided, resizing defaults to proportional behavior. - If only one dimension is provided, proportional scaling is applied. @@ -231,6 +231,8 @@ property with the following attribute names: > string for your server. You can find more detailed information about all image processing options on > the [Imgproxy](https://docs.imgproxy.net/usage/processing#processing-options) website. +## Examples + Example 1: Cropping an image to a width and height of 500x500 and rotate by 180 degrees: ```vue From d489e0dd52d56436ffbb52d76fc0e17c75d53076 Mon Sep 17 00:00:00 2001 From: "Vlad Z." Date: Mon, 16 Feb 2026 09:27:20 -0500 Subject: [PATCH 12/13] fix: update imgproxy docs; --- docs/content/3.providers/imgproxy.md | 35 +++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/docs/content/3.providers/imgproxy.md b/docs/content/3.providers/imgproxy.md index 278046084..b9b9b87d9 100644 --- a/docs/content/3.providers/imgproxy.md +++ b/docs/content/3.providers/imgproxy.md @@ -185,7 +185,24 @@ const defaultModifiers: Partial = { } ``` -If you want to change them, you can define it `nuxt.config.ts` file. +If you want to change them, you can define them in your `nuxt.config.ts` file: + +```ts [nuxt.config.ts] +export default defineNuxtConfig({ + image: { + imgproxy: { + baseURL: 'http://localhost:8080/', + key: 'ee3b0e07dfc9ec20d5d9588a558753547a8a88c48291ae96171330daf4ce2800', + salt: '8dd0e39bb7b14eeaf02d49e5dc76d2bc0abd9e09d52e7049e791acd3558db68e', + modifiers: { + resizingType: 'fit', + gravity: 'no', + format: 'png', + } + } + } +}) +``` In addition to the [standard modifiers](/usage/nuxt-img#modifiers), you can also use most of [Imgproxy Options](https://docs.imgproxy.net/usage/processing#processing-options) by adding them to the `modifiers` @@ -290,6 +307,22 @@ Example 4: Advanced image manipulation: /> ``` +### Contributing + +When developing this provider, a locally installed version of imgproxy was used with the following settings: + +```yaml [docker-compose.yml] + +services: + app: + image: ghcr.io/imgproxy/imgproxy + environment: + - IMGPROXY_KEY=ee3b0e07dfc9ec20d5d9588a558753547a8a88c48291ae96171330daf4ce2800 + - IMGPROXY_SALT=8dd0e39bb7b14eeaf02d49e5dc76d2bc0abd9e09d52e7049e791acd3558db68e + - IMGPROXY_PRESETS=default=resizing_type:fill/enlarge:1,sharp=sharpen:0.7,blurry=blur:100 + ports: + - 8080:8080 +``` From cfdf8fa9b54eae378dde5b5d4e38bd70c2b017b1 Mon Sep 17 00:00:00 2001 From: "Vlad Z." Date: Fri, 27 Feb 2026 18:18:46 -0500 Subject: [PATCH 13/13] chore: rebase --- test/nuxt/providers.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/nuxt/providers.test.ts b/test/nuxt/providers.test.ts index 6a030bee2..bc0886790 100644 --- a/test/nuxt/providers.test.ts +++ b/test/nuxt/providers.test.ts @@ -274,7 +274,7 @@ describe('Providers', () => { } for (const image of images) { const [_src, modifiers] = image.args - const generated = imgproxy().getImage('https://mars.nasa.gov/system/downloadable_items/39099_Mars-MRO-orbiter-fresh-crater-sirenum-fossae.jpg', { modifiers, ...providerOptions }, emptyContext) + const generated = imgproxy().getImage('https://mars.nasa.gov/system/downloadable_items/39099_Mars-MRO-orbiter-fresh-crater-sirenum-fossae.jpg', { modifiers, ...providerOptions }, getEmptyContext()) expect(generated.url).toBe(image.imgproxy.url) } @@ -473,7 +473,7 @@ describe('Providers', () => { modifiers, ...providerOptions, }, - emptyContext, + getEmptyContext(), ) expect(generated).toMatchObject(expected)