From 0dff7def7ac95407f36c3fd4c8a33e6d61c0b1e2 Mon Sep 17 00:00:00 2001 From: Steven Date: Fri, 23 Oct 2020 21:26:52 -0400 Subject: [PATCH] Bypass image optimization for vector images (#18179) Previously, vector images like svg were being converted to webp and resized. However, vector images already handle any size so we can bypass the same we do for animated images. Related to #18122 --- .../next-server/server/image-optimizer.ts | 23 ++++++++++--------- .../image-optimizer/test/index.test.js | 23 +++++++++++-------- 2 files changed, 26 insertions(+), 20 deletions(-) diff --git a/packages/next/next-server/server/image-optimizer.ts b/packages/next/next-server/server/image-optimizer.ts index d914aab89bec3..83314a2af466c 100644 --- a/packages/next/next-server/server/image-optimizer.ts +++ b/packages/next/next-server/server/image-optimizer.ts @@ -17,9 +17,11 @@ const WEBP = 'image/webp' const PNG = 'image/png' const JPEG = 'image/jpeg' const GIF = 'image/gif' +const SVG = 'image/svg+xml' const MIME_TYPES = [/* AVIF, */ WEBP, PNG, JPEG] const CACHE_VERSION = 1 const ANIMATABLE_TYPES = [WEBP, PNG, GIF] +const VECTOR_TYPES = [SVG] export async function imageOptimizer( server: Server, @@ -200,21 +202,20 @@ export async function imageOptimizer( } } - const expireAt = maxAge * 1000 + now - let contentType: string - - if ( - upstreamType && - ANIMATABLE_TYPES.includes(upstreamType) && - isAnimated(upstreamBuffer) - ) { - if (upstreamType) { + if (upstreamType) { + const vector = VECTOR_TYPES.includes(upstreamType) + const animate = + ANIMATABLE_TYPES.includes(upstreamType) && isAnimated(upstreamBuffer) + if (vector || animate) { res.setHeader('Content-Type', upstreamType) + res.end(upstreamBuffer) + return { finished: true } } - res.end(upstreamBuffer) - return { finished: true } } + const expireAt = maxAge * 1000 + now + let contentType: string + if (mimeType) { contentType = mimeType } else if (upstreamType?.startsWith('image/') && getExtension(upstreamType)) { diff --git a/test/integration/image-optimizer/test/index.test.js b/test/integration/image-optimizer/test/index.test.js index 6dab8c60c082a..0ac1960dc091f 100644 --- a/test/integration/image-optimizer/test/index.test.js +++ b/test/integration/image-optimizer/test/index.test.js @@ -73,6 +73,20 @@ function runTests({ w, isDev, domains }) { expect(isAnimated(await res.buffer())).toBe(true) }) + it('should maintain vector svg', async () => { + const query = { w, q: 90, url: '/test.svg' } + const opts = { headers: { accept: 'image/webp' } } + const res = await fetchViaHTTP(appPort, '/_next/image', query, opts) + expect(res.status).toBe(200) + expect(res.headers.get('Content-Type')).toContain('image/svg+xml') + const actual = await res.text() + const expected = await fs.readFile( + join(__dirname, '..', 'public', 'test.svg'), + 'utf8' + ) + expect(actual).toMatch(expected) + }) + it('should fail when url is missing', async () => { const query = { w, q: 100 } const res = await fetchViaHTTP(appPort, '/_next/image', query, {}) @@ -203,15 +217,6 @@ function runTests({ w, isDev, domains }) { await expectWidth(res, w) }) - it('should resize relative url with invalid accept header as svg', async () => { - const query = { url: '/test.svg', w, q: 80 } - const opts = { headers: { accept: 'image/invalid' } } - const res = await fetchViaHTTP(appPort, '/_next/image', query, opts) - expect(res.status).toBe(200) - expect(res.headers.get('Content-Type')).toBe('image/svg+xml') - await expectWidth(res, w) - }) - it('should resize relative url with invalid accept header as tiff', async () => { const query = { url: '/test.tiff', w, q: 80 } const opts = { headers: { accept: 'image/invalid' } }