Skip to content

Commit

Permalink
Unlazify images if no intersection observer found (#18345)
Browse files Browse the repository at this point in the history
  • Loading branch information
atcastle committed Oct 27, 2020
1 parent 27f56eb commit 5d7f7a4
Show file tree
Hide file tree
Showing 4 changed files with 75 additions and 11 deletions.
33 changes: 22 additions & 11 deletions packages/next/client/image.tsx
Expand Up @@ -48,10 +48,10 @@ configDeviceSizes.sort((a, b) => a - b)
configImageSizes.sort((a, b) => a - b)

let cachedObserver: IntersectionObserver
const IntersectionObserver =
typeof window !== 'undefined' ? window.IntersectionObserver : null

function getObserver(): IntersectionObserver | undefined {
const IntersectionObserver =
typeof window !== 'undefined' ? window.IntersectionObserver : null
// Return shared instance of IntersectionObserver if already created
if (cachedObserver) {
return cachedObserver
Expand All @@ -61,20 +61,12 @@ function getObserver(): IntersectionObserver | undefined {
if (!IntersectionObserver) {
return undefined
}

return (cachedObserver = new IntersectionObserver(
(entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
let lazyImage = entry.target as HTMLImageElement
if (lazyImage.dataset.src) {
lazyImage.src = lazyImage.dataset.src
}
if (lazyImage.dataset.srcset) {
lazyImage.srcset = lazyImage.dataset.srcset
}
lazyImage.style.visibility = 'visible'
lazyImage.classList.remove('__lazy')
unLazifyImage(lazyImage)
cachedObserver.unobserve(lazyImage)
}
})
Expand All @@ -83,6 +75,17 @@ function getObserver(): IntersectionObserver | undefined {
))
}

function unLazifyImage(lazyImage: HTMLImageElement): void {
if (lazyImage.dataset.src) {
lazyImage.src = lazyImage.dataset.src
}
if (lazyImage.dataset.srcset) {
lazyImage.srcset = lazyImage.dataset.srcset
}
lazyImage.style.visibility = 'visible'
lazyImage.classList.remove('__lazy')
}

function getDeviceSizes(width: number | undefined): number[] {
if (typeof width !== 'number') {
return configDeviceSizes
Expand Down Expand Up @@ -234,6 +237,11 @@ export default function Image({
lazy = true
}

if (typeof window !== 'undefined' && !window.IntersectionObserver) {
// Rendering client side on browser without intersection observer
lazy = false
}

useEffect(() => {
const target = thisEl.current

Expand All @@ -246,6 +254,9 @@ export default function Image({
return () => {
observer.unobserve(target)
}
} else {
//browsers without intersection observer
unLazifyImage(target)
}
}
}, [thisEl, lazy])
Expand Down
4 changes: 4 additions & 0 deletions test/integration/image-component/basic/pages/lazy.js
@@ -1,5 +1,6 @@
import React from 'react'
import Image from 'next/image'
import Link from 'next/link'

const Lazy = () => {
return (
Expand Down Expand Up @@ -45,6 +46,9 @@ const Lazy = () => {
height={400}
width={1900}
></Image>
<Link href="/missing-observer">
<a id="observerlink">observer</a>
</Link>
</div>
)
}
Expand Down
25 changes: 25 additions & 0 deletions test/integration/image-component/basic/pages/missing-observer.js
@@ -0,0 +1,25 @@
import React, { useLayoutEffect } from 'react'
import Image from 'next/image'

const Lazy = () => {
useLayoutEffect(() => {
IntersectionObserver = null //eslint-disable-line
})
return (
<div>
<p id="stubtext">
This is a page with one lazy-loaded image, to be used in the test for
browsers without intersection observer.
</p>
<Image
id="lazy-no-observer"
src="foox.jpg"
height={400}
width={1024}
loading="lazy"
></Image>
</div>
)
}

export default Lazy
24 changes: 24 additions & 0 deletions test/integration/image-component/basic/test/index.test.js
Expand Up @@ -280,6 +280,17 @@ describe('Image Component Tests', () => {
browser = null
})
lazyLoadingTests()
it('should automatically load images if observer does not exist', async () => {
browser = await webdriver(appPort, '/missing-observer')
expect(
await browser.elementById('lazy-no-observer').getAttribute('src')
).toBe('https://example.com/myaccount/foox.jpg?auto=format&w=1024')
expect(
await browser.elementById('lazy-no-observer').getAttribute('srcset')
).toBe(
'https://example.com/myaccount/foox.jpg?auto=format&w=480 480w, https://example.com/myaccount/foox.jpg?auto=format&w=1024 1024w'
)
})
})
describe('Client-side Lazy Loading Tests', () => {
beforeAll(async () => {
Expand All @@ -291,5 +302,18 @@ describe('Image Component Tests', () => {
browser = null
})
lazyLoadingTests()
it('should automatically load images if observer does not exist', async () => {
await browser.waitForElementByCss('#observerlink').click()
await waitFor(500)
browser = await webdriver(appPort, '/missing-observer')
expect(
await browser.elementById('lazy-no-observer').getAttribute('src')
).toBe('https://example.com/myaccount/foox.jpg?auto=format&w=1024')
expect(
await browser.elementById('lazy-no-observer').getAttribute('srcset')
).toBe(
'https://example.com/myaccount/foox.jpg?auto=format&w=480 480w, https://example.com/myaccount/foox.jpg?auto=format&w=1024 1024w'
)
})
})
})

0 comments on commit 5d7f7a4

Please sign in to comment.