Skip to content

Commit 0dff7de

Browse files
authored
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
1 parent d4397d8 commit 0dff7de

File tree

2 files changed

+26
-20
lines changed

2 files changed

+26
-20
lines changed

packages/next/next-server/server/image-optimizer.ts

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,11 @@ const WEBP = 'image/webp'
1717
const PNG = 'image/png'
1818
const JPEG = 'image/jpeg'
1919
const GIF = 'image/gif'
20+
const SVG = 'image/svg+xml'
2021
const MIME_TYPES = [/* AVIF, */ WEBP, PNG, JPEG]
2122
const CACHE_VERSION = 1
2223
const ANIMATABLE_TYPES = [WEBP, PNG, GIF]
24+
const VECTOR_TYPES = [SVG]
2325

2426
export async function imageOptimizer(
2527
server: Server,
@@ -200,21 +202,20 @@ export async function imageOptimizer(
200202
}
201203
}
202204

203-
const expireAt = maxAge * 1000 + now
204-
let contentType: string
205-
206-
if (
207-
upstreamType &&
208-
ANIMATABLE_TYPES.includes(upstreamType) &&
209-
isAnimated(upstreamBuffer)
210-
) {
211-
if (upstreamType) {
205+
if (upstreamType) {
206+
const vector = VECTOR_TYPES.includes(upstreamType)
207+
const animate =
208+
ANIMATABLE_TYPES.includes(upstreamType) && isAnimated(upstreamBuffer)
209+
if (vector || animate) {
212210
res.setHeader('Content-Type', upstreamType)
211+
res.end(upstreamBuffer)
212+
return { finished: true }
213213
}
214-
res.end(upstreamBuffer)
215-
return { finished: true }
216214
}
217215

216+
const expireAt = maxAge * 1000 + now
217+
let contentType: string
218+
218219
if (mimeType) {
219220
contentType = mimeType
220221
} else if (upstreamType?.startsWith('image/') && getExtension(upstreamType)) {

test/integration/image-optimizer/test/index.test.js

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,20 @@ function runTests({ w, isDev, domains }) {
7373
expect(isAnimated(await res.buffer())).toBe(true)
7474
})
7575

76+
it('should maintain vector svg', async () => {
77+
const query = { w, q: 90, url: '/test.svg' }
78+
const opts = { headers: { accept: 'image/webp' } }
79+
const res = await fetchViaHTTP(appPort, '/_next/image', query, opts)
80+
expect(res.status).toBe(200)
81+
expect(res.headers.get('Content-Type')).toContain('image/svg+xml')
82+
const actual = await res.text()
83+
const expected = await fs.readFile(
84+
join(__dirname, '..', 'public', 'test.svg'),
85+
'utf8'
86+
)
87+
expect(actual).toMatch(expected)
88+
})
89+
7690
it('should fail when url is missing', async () => {
7791
const query = { w, q: 100 }
7892
const res = await fetchViaHTTP(appPort, '/_next/image', query, {})
@@ -203,15 +217,6 @@ function runTests({ w, isDev, domains }) {
203217
await expectWidth(res, w)
204218
})
205219

206-
it('should resize relative url with invalid accept header as svg', async () => {
207-
const query = { url: '/test.svg', w, q: 80 }
208-
const opts = { headers: { accept: 'image/invalid' } }
209-
const res = await fetchViaHTTP(appPort, '/_next/image', query, opts)
210-
expect(res.status).toBe(200)
211-
expect(res.headers.get('Content-Type')).toBe('image/svg+xml')
212-
await expectWidth(res, w)
213-
})
214-
215220
it('should resize relative url with invalid accept header as tiff', async () => {
216221
const query = { url: '/test.tiff', w, q: 80 }
217222
const opts = { headers: { accept: 'image/invalid' } }

0 commit comments

Comments
 (0)