From 87072563b12441151d4a3cddbbe0cf4156d3c558 Mon Sep 17 00:00:00 2001 From: Shu Ding Date: Tue, 9 Mar 2021 21:13:33 +0800 Subject: [PATCH 1/2] reorder attributes --- packages/next/client/image.tsx | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/next/client/image.tsx b/packages/next/client/image.tsx index 2cd80c1d0c6ba..7c43e21414125 100644 --- a/packages/next/client/image.tsx +++ b/packages/next/client/image.tsx @@ -150,7 +150,6 @@ function generateImgAttrs({ const last = widths.length - 1 return { - src: loader({ src, quality, width: widths[last] }), sizes: !sizes && kind === 'w' ? '100vw' : sizes, srcSet: widths .map( @@ -160,6 +159,14 @@ function generateImgAttrs({ }${kind}` ) .join(', '), + + // It's intended to keep `src` the last attribute because React updates + // attributes in order. If we keep `src` the first one, Safari will + // immediately start to fetch `src`, before `sizes` and `srcSet` are even + // updated by React. That causes multiple unnecessary requests if `srcSet` + // and `sizes` are defined. + // This bug cannot be reproduced in Chrome or Firefox. + src: loader({ src, quality, width: widths[last] }), } } From a8d94f4f87fba557a41f6d5b10c130f7866b29dc Mon Sep 17 00:00:00 2001 From: Shu Ding Date: Wed, 10 Mar 2021 00:25:24 +0800 Subject: [PATCH 2/2] add integration test --- .../integration/image-component/basic/pages/index.js | 7 +++++++ .../image-component/basic/test/index.test.js | 12 ++++++++++++ 2 files changed, 19 insertions(+) diff --git a/test/integration/image-component/basic/pages/index.js b/test/integration/image-component/basic/pages/index.js index db07560c03ec0..2e35634ab8cc8 100644 --- a/test/integration/image-component/basic/pages/index.js +++ b/test/integration/image-component/basic/pages/index.js @@ -7,6 +7,13 @@ const Page = () => { return (

Hello World

+ { ) ).toBe(false) }) + it('should only be loaded once if `sizes` is set', async () => { + // Get all network requests + const resourceEntries = await browser.eval( + 'window.performance.getEntries()' + ) + + // "test-sizes.jpg" should only occur once + const requests = resourceEntries.filter((entry) => + entry.name.includes('test-sizes.jpg') + ) + expect(requests.length).toBe(1) + }) describe('Client-side Errors', () => { beforeAll(async () => { await browser.eval(`(function() {