diff --git a/src/runtime/providers/ipx.ts b/src/runtime/providers/ipx.ts index 684ef6a52..7810939b0 100644 --- a/src/runtime/providers/ipx.ts +++ b/src/runtime/providers/ipx.ts @@ -57,6 +57,7 @@ export const operationsGenerator = createOperationsGenerator({ background: 'b', position: 'pos', }, + joinWith: encodeURIComponent('&'), formatter: (key, val: string | number | boolean) => encodeParam(key) + '_' + encodeParam(val.toString()), }) diff --git a/test/e2e/ssr.test.ts b/test/e2e/ssr.test.ts index cab6c08de..ad7158494 100644 --- a/test/e2e/ssr.test.ts +++ b/test/e2e/ssr.test.ts @@ -80,7 +80,7 @@ describe('browser (ssr: true)', () => { expect(await $fetch('/api/image' as any)).toMatchInlineSnapshot(` { "format": "webp", - "url": "/_ipx/f_webp&q_75/image.jpg", + "url": "/_ipx/f_webp%26q_75/image.jpg", } `) }) diff --git a/test/nuxt/image.test.ts b/test/nuxt/image.test.ts index 862fd95e2..b7ebad4f4 100644 --- a/test/nuxt/image.test.ts +++ b/test/nuxt/image.test.ts @@ -233,7 +233,7 @@ describe('Renders placeholder image', () => { let domSrc = wrapper.find('img').element.getAttribute('src') - expect(domSrc).toMatchInlineSnapshot('"/_ipx/q_50&blur_3&s_10x10/image.png"') + expect(domSrc).toMatchInlineSnapshot(`"/_ipx/q_50%26blur_3%26s_10x10/image.png"`) expect(placeholderImage.src).toMatchInlineSnapshot('"/_ipx/s_200x200/image.png"') resolveImage() @@ -296,7 +296,7 @@ describe('Renders placeholder image', () => { "other", ] `) - expect(wrapper.element.getAttribute('src')).toMatchInlineSnapshot('"/_ipx/q_50&blur_3&s_10x10/image.png"') + expect(wrapper.element.getAttribute('src')).toMatchInlineSnapshot(`"/_ipx/q_50%26blur_3%26s_10x10/image.png"`) resolveImage() await nextTick() expect([...wrapper.element.classList]).toMatchInlineSnapshot(` @@ -525,7 +525,7 @@ describe('Renders image, applies module config', () => { sizes: '200,500:500,900:900', }, }) - expect(img.html()).toMatchInlineSnapshot(`""`) + expect(img.html()).toMatchInlineSnapshot(`""`) }) it('Module config .quality + props.quality => props.quality applies', () => { @@ -539,7 +539,7 @@ describe('Renders image, applies module config', () => { quality: 90, }, }) - expect(img.html()).toMatchInlineSnapshot(`""`) + expect(img.html()).toMatchInlineSnapshot(`""`) }) it('Without quality config => default image', () => { diff --git a/test/nuxt/picture.test.ts b/test/nuxt/picture.test.ts index 86c21406e..07629666d 100644 --- a/test/nuxt/picture.test.ts +++ b/test/nuxt/picture.test.ts @@ -49,7 +49,7 @@ describe('Renders simple image', () => { it('Matches snapshot', () => { expect(wrapper.html()).toMatchInlineSnapshot(` " - + " `) }) @@ -66,13 +66,13 @@ describe('Renders simple image', () => { }) expect(img.html()).toMatchInlineSnapshot(` " - + " `) }) it('props.src is picked up by getImage()', () => { - [['source', 'srcset', '/_ipx/f_webp&s_500x500/image.png'], ['img', 'src']].forEach(([element, attribute, customSrc]) => { + [['source', 'srcset', '/_ipx/f_webp%26s_500x500/image.png'], ['img', 'src']].forEach(([element, attribute, customSrc]) => { const domSrc = wrapper.find(element!).element.getAttribute(attribute!) expect(domSrc).toContain(customSrc || src) }) @@ -129,7 +129,7 @@ describe('Renders simple image', () => { await nextTick() - ;[['source', 'srcset', '/_ipx/f_webp&s_500x500/image.jpeg'], ['img', 'src']].forEach(([element, attribute, src]) => { + ;[['source', 'srcset', '/_ipx/f_webp%26s_500x500/image.jpeg'], ['img', 'src']].forEach(([element, attribute, src]) => { const domSrc = wrapper.find(element!).element.getAttribute(attribute!) expect(domSrc).toContain(src || newSource) }) @@ -161,7 +161,7 @@ describe('Renders simple image', () => { }) expect(img.html()).toMatchInlineSnapshot(` " - + " `) }) @@ -197,7 +197,7 @@ describe('Renders image, applies module config', () => { }) expect(picture.html()).toMatchInlineSnapshot(` " - + " `) }) @@ -221,7 +221,7 @@ describe('Renders image, applies module config', () => { }) expect(picture.html()).toMatchInlineSnapshot(` " - + " `) }) @@ -245,8 +245,8 @@ describe('Renders image, applies module config', () => { }) expect(picture.html()).toMatchInlineSnapshot(` " - - + + " `) }) @@ -271,7 +271,7 @@ describe('Renders image, applies module config', () => { }) expect(picture.html()).toMatchInlineSnapshot(` " - + " `) }) @@ -316,7 +316,7 @@ describe('Renders image, applies module config', () => { expect(picture.html()).toMatchInlineSnapshot(` " - + " `) }) diff --git a/test/nuxt/providers.test.ts b/test/nuxt/providers.test.ts index 7ac564e65..fcc619d98 100644 --- a/test/nuxt/providers.test.ts +++ b/test/nuxt/providers.test.ts @@ -75,6 +75,24 @@ describe('Providers', () => { url: '/_ipx/_/images/test.png', }) }) + + it('ipx encodes reserved URI characters', () => { + const context = { ...emptyContext } + + const src = '/images/test.png' + const generated = ipx().getImage(src, { + modifiers: { + fit: 'inside', + format: 'png', + width: 1200, + height: 630, + }, + }, context) + expect(generated).toMatchObject({ + url: '/_ipx/fit_inside%26f_png%26s_1200x630/images/test.png', + }) + }) + it('aliyun', () => { const providerOptions = { baseURL: '/', diff --git a/test/providers.ts b/test/providers.ts index c092b1ddd..51110a653 100644 --- a/test/providers.ts +++ b/test/providers.ts @@ -152,7 +152,7 @@ export const images = [ { args: ['/test.png', { width: 200, height: 200, fit: 'contain' }], none: { url: '/test.png' }, - ipx: { url: '/_ipx/fit_contain&s_200x200/test.png' }, + ipx: { url: '/_ipx/fit_contain%26s_200x200/test.png' }, aliyun: { url: '/test.png?image_process=fit,contain/resize,fw_200,fh_200' }, awsAmplify: { url: '/?url=%2Ftest.png&w=640&h=200&fit=contain&q=100' }, cloudflare: { url: '/cdn-cgi/image/w=200,h=200,fit=contain/test.png' }, @@ -189,7 +189,7 @@ export const images = [ { args: ['/test.png', { width: 200, height: 200, fit: 'contain', format: 'jpeg' }], none: { url: '/test.png' }, - ipx: { url: '/_ipx/fit_contain&f_jpeg&s_200x200/test.png' }, + ipx: { url: '/_ipx/fit_contain%26f_jpeg%26s_200x200/test.png' }, aliyun: { url: '/test.png?image_process=fit,contain/format,jpeg/resize,fw_200,fh_200' }, awsAmplify: { url: '/?url=%2Ftest.png&w=640&h=200&fit=contain&format=jpeg&q=100' }, cloudflare: { url: '/cdn-cgi/image/w=200,h=200,fit=contain,f=jpeg/test.png' },