Add all deviceSizes to srcset for responsive and fill (#18594)

This commit is contained in:
Steven 2020-10-31 20:26:57 -04:00 committed by GitHub
parent 9569f5a31a
commit f8c32e556c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 78 additions and 19 deletions

View file

@ -105,8 +105,15 @@ function unLazifyImage(lazyImage: HTMLImageElement): void {
lazyImage.classList.remove('__lazy')
}
function getDeviceSizes(width: number | undefined): number[] {
if (typeof width !== 'number') {
function getDeviceSizes(
width: number | undefined,
layout: LayoutValue
): number[] {
if (
typeof width !== 'number' ||
layout === 'fill' ||
layout === 'responsive'
) {
return configDeviceSizes
}
if (configImageSizes.includes(width)) {
@ -125,13 +132,14 @@ function getDeviceSizes(width: number | undefined): number[] {
function computeSrc(
src: string,
unoptimized: boolean,
layout: LayoutValue,
width?: number,
quality?: number
): string {
if (unoptimized) {
return src
}
const widths = getDeviceSizes(width)
const widths = getDeviceSizes(width, layout)
const largest = widths[widths.length - 1]
return callLoader({ src, width: largest, quality })
}
@ -150,6 +158,7 @@ function callLoader(loaderProps: CallLoaderProps) {
type SrcSetData = {
src: string
unoptimized: boolean
layout: LayoutValue
width?: number
quality?: number
}
@ -157,6 +166,7 @@ type SrcSetData = {
function generateSrcSet({
src,
unoptimized,
layout,
width,
quality,
}: SrcSetData): string | undefined {
@ -166,7 +176,7 @@ function generateSrcSet({
return undefined
}
return getDeviceSizes(width)
return getDeviceSizes(width, layout)
.map((w) => `${callLoader({ src, width: w, quality })} ${w}w`)
.join(', ')
}
@ -174,6 +184,7 @@ function generateSrcSet({
type PreloadData = {
src: string
unoptimized: boolean
layout: LayoutValue
width: number | undefined
sizes?: string
quality?: number
@ -181,8 +192,9 @@ type PreloadData = {
function generatePreload({
src,
width,
unoptimized = false,
layout,
width,
sizes,
quality,
}: PreloadData): ReactElement {
@ -195,9 +207,15 @@ function generatePreload({
<link
rel="preload"
as="image"
href={computeSrc(src, unoptimized, width, quality)}
href={computeSrc(src, unoptimized, layout, width, quality)}
// @ts-ignore: imagesrcset and imagesizes not yet in the link element type
imagesrcset={generateSrcSet({ src, unoptimized, width, quality })}
imagesrcset={generateSrcSet({
src,
unoptimized,
layout,
width,
quality,
})}
imagesizes={sizes}
/>
</Head>
@ -410,11 +428,12 @@ export default function Image({
}
// Generate attribute values
const imgSrc = computeSrc(src, unoptimized, widthInt, qualityInt)
const imgSrc = computeSrc(src, unoptimized, layout, widthInt, qualityInt)
const imgSrcSet = generateSrcSet({
src,
width: widthInt,
unoptimized,
layout,
width: widthInt,
quality: qualityInt,
})
@ -458,8 +477,9 @@ export default function Image({
{shouldPreload
? generatePreload({
src,
width: widthInt,
layout,
unoptimized,
width: widthInt,
sizes,
quality: qualityInt,
})

View file

@ -11,28 +11,28 @@ const Page = () => {
width="1200"
height="700"
layout="responsive"
></Image>
/>
<Image
id="responsive2"
src="/wide.png"
width="1200"
height="700"
layout="responsive"
></Image>
/>
<Image
id="responsive3"
src="/wide.png"
width="1200"
height="700"
layout="responsive"
></Image>
/>
<Image
id="responsive4"
src="/wide.png"
width="1200"
height="700"
layout="responsive"
></Image>
/>
<p>Layout Responsive</p>
</div>
)

View file

@ -36,15 +36,24 @@ async function hasImageMatchingUrl(browser, url) {
}
async function getComputed(browser, id, prop) {
const style = await browser.eval(
`getComputedStyle(document.getElementById('${id}')).${prop}`
)
if (typeof style === 'string') {
return parseInt(style.replace(/px$/, ''), 10)
const val = await browser.eval(`document.getElementById('${id}').${prop}`)
if (typeof val === 'number') {
return val
}
if (typeof val === 'string') {
return parseInt(val, 10)
}
return null
}
async function getSrc(browser, id) {
const src = await browser.elementById(id).getAttribute('src')
if (src) {
const url = new URL(src)
return url.href.slice(url.origin.length)
}
}
function getRatio(width, height) {
return Math.round((height / width) * 1000)
}
@ -109,6 +118,12 @@ function runTests(mode) {
const height = 700
const delta = 250
const id = 'fixed1'
expect(await getSrc(browser, id)).toBe(
'/_next/image?url=%2Fwide.png&w=1200&q=75'
)
expect(await browser.elementById(id).getAttribute('srcset')).toBe(
'/_next/image?url=%2Fwide.png&w=320&q=75 320w, /_next/image?url=%2Fwide.png&w=420&q=75 420w, /_next/image?url=%2Fwide.png&w=768&q=75 768w, /_next/image?url=%2Fwide.png&w=1024&q=75 1024w, /_next/image?url=%2Fwide.png&w=1200&q=75 1200w'
)
await browser.setDimensions({
width: width + delta,
height: height + delta,
@ -136,6 +151,12 @@ function runTests(mode) {
const height = 700
const delta = 250
const id = 'intrinsic1'
expect(await getSrc(browser, id)).toBe(
'/_next/image?url=%2Fwide.png&w=1200&q=75'
)
expect(await browser.elementById(id).getAttribute('srcset')).toBe(
'/_next/image?url=%2Fwide.png&w=320&q=75 320w, /_next/image?url=%2Fwide.png&w=420&q=75 420w, /_next/image?url=%2Fwide.png&w=768&q=75 768w, /_next/image?url=%2Fwide.png&w=1024&q=75 1024w, /_next/image?url=%2Fwide.png&w=1200&q=75 1200w'
)
await browser.setDimensions({
width: width + delta,
height: height + delta,
@ -166,6 +187,12 @@ function runTests(mode) {
const height = 700
const delta = 250
const id = 'responsive1'
expect(await getSrc(browser, id)).toBe(
'/_next/image?url=%2Fwide.png&w=1200&q=75'
)
expect(await browser.elementById(id).getAttribute('srcset')).toBe(
'/_next/image?url=%2Fwide.png&w=320&q=75 320w, /_next/image?url=%2Fwide.png&w=420&q=75 420w, /_next/image?url=%2Fwide.png&w=768&q=75 768w, /_next/image?url=%2Fwide.png&w=1024&q=75 1024w, /_next/image?url=%2Fwide.png&w=1200&q=75 1200w'
)
await browser.setDimensions({
width: width + delta,
height: height + delta,
@ -196,6 +223,12 @@ function runTests(mode) {
const height = 350
const delta = 150
const id = 'fill1'
expect(await getSrc(browser, id)).toBe(
'/_next/image?url=%2Fwide.png&w=1200&q=75'
)
expect(await browser.elementById(id).getAttribute('srcset')).toBe(
'/_next/image?url=%2Fwide.png&w=320&q=75 320w, /_next/image?url=%2Fwide.png&w=420&q=75 420w, /_next/image?url=%2Fwide.png&w=768&q=75 768w, /_next/image?url=%2Fwide.png&w=1024&q=75 1024w, /_next/image?url=%2Fwide.png&w=1200&q=75 1200w'
)
await browser.setDimensions({
width: width + delta,
height: height + delta,
@ -226,6 +259,12 @@ function runTests(mode) {
const width = await getComputed(browser, id, 'width')
const height = await getComputed(browser, id, 'height')
await browser.eval(`document.getElementById("${id}").scrollIntoView()`)
expect(await getSrc(browser, id)).toBe(
'/_next/image?url=%2Fwide.png&w=1200&q=75'
)
expect(await browser.elementById(id).getAttribute('srcset')).toBe(
'/_next/image?url=%2Fwide.png&w=320&q=75 320w, /_next/image?url=%2Fwide.png&w=420&q=75 420w, /_next/image?url=%2Fwide.png&w=768&q=75 768w, /_next/image?url=%2Fwide.png&w=1024&q=75 1024w, /_next/image?url=%2Fwide.png&w=1200&q=75 1200w'
)
expect(await getComputed(browser, id, 'width')).toBe(width)
expect(await getComputed(browser, id, 'height')).toBe(height)
const delta = 150