Skip to content

Commit

Permalink
Move all image intersectionObserver logic into image instance
Browse files Browse the repository at this point in the history
  • Loading branch information
atcastle committed Oct 16, 2020
1 parent 24ec9ee commit 9c2e235
Show file tree
Hide file tree
Showing 4 changed files with 70 additions and 46 deletions.
73 changes: 70 additions & 3 deletions packages/next/client/image.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { ReactElement } from 'react'
import React, { ReactElement, useEffect } from 'react'
import Head from '../next-server/lib/head'

const loaders: { [key: string]: (props: LoaderProps) => string } = {
Expand Down Expand Up @@ -31,6 +31,41 @@ type ImageProps = {
let imageData: any = process.env.__NEXT_IMAGE_OPTS
const breakpoints = imageData.breakpoints || [640, 1024, 1600]

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

function getObserver(): IntersectionObserver | undefined {
// Return shared instance of IntersectionObserver if already created
if (cachedObserver) {
return cachedObserver
}

// Only create shared IntersectionObserver if supported in browser
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.classList.remove('__lazy')
cachedObserver.unobserve(lazyImage)
}
})
},
{ rootMargin: '200px' }
))
}

function computeSrc(src: string, host: string, unoptimized: boolean): string {
if (unoptimized) {
return src
Expand Down Expand Up @@ -145,6 +180,21 @@ export default function Image({
src = src.slice(1)
}

let thisEl: any

useEffect(() => {
if (!lazy) {
return () => {}
}
const observer = getObserver()
if (observer) {
observer.observe(thisEl)
return () => {
observer.unobserve(thisEl)
}
}
}, [thisEl, lazy])

// Generate attribute values
const imgSrc = computeSrc(src, host, unoptimized)
let imgSrcset = null
Expand Down Expand Up @@ -182,10 +232,27 @@ export default function Image({
let imgElement
if (className) {
imgElement = (
<img {...rest} {...imgAttributes} className={className} sizes={sizes} />
<img
{...rest}
ref={(el) => {
thisEl = el
}}
{...imgAttributes}
className={className}
sizes={sizes}
/>
)
} else {
imgElement = <img {...rest} {...imgAttributes} sizes={sizes} />
imgElement = (
<img
ref={(el) => {
thisEl = el
}}
{...rest}
{...imgAttributes}
sizes={sizes}
/>
)
}

return (
Expand Down
33 changes: 0 additions & 33 deletions packages/next/next-server/lib/router/router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -830,7 +830,6 @@ export default class Router implements BaseRouter {
window.scrollTo((options as any)._N_X, (options as any)._N_Y)
}
}
this.updateLazyObserver()
Router.events.emit('routeChangeComplete', as)

return true
Expand Down Expand Up @@ -1216,38 +1215,6 @@ export default class Router implements BaseRouter {
})
}

updateLazyObserver(): void {
// @ts-ignore This has to be global since it's initially set before hydration
window.__NEXT_lazy_observer.disconnect()
var lazyImages = [].slice.call(document.querySelectorAll('img.__lazy'))
if ('IntersectionObserver' in window) {
let lazyImageObserver = new IntersectionObserver(
function (entries) {
entries.forEach(function (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.classList.remove('__lazy')
lazyImageObserver.unobserve(lazyImage)
}
})
},
{ rootMargin: '0px 0px 200px 0px' }
)

lazyImages.forEach(function (lazyImage) {
lazyImageObserver.observe(lazyImage)
})
// @ts-ignore see above
window.__NEXT_lazy_observer = lazyImageObserver
}
}

abortComponentLoad(as: string): void {
if (this.clc) {
Router.events.emit('routeChangeError', buildCancellationError(), as)
Expand Down
9 changes: 0 additions & 9 deletions packages/next/pages/_document.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -544,10 +544,6 @@ export class NextScript extends Component<OriginProps> {
static safariNomoduleFix =
'!function(){var e=document,t=e.createElement("script");if(!("noModule"in t)&&"onbeforeload"in t){var n=!1;e.addEventListener("beforeload",function(e){if(e.target===t)n=!0;else if(!e.target.hasAttribute("nomodule")||!n)return;e.preventDefault()},!0),t.type="module",t.src=".",e.head.appendChild(t),t.remove()}}();'

// Source: https://gist.github.com/atcastle/046c0f416dc69c84cca20a173fb0344e
static lazyImageScript = `
document.addEventListener("DOMContentLoaded",function(){var e=[].slice.call(document.querySelectorAll("img.__lazy"));if("IntersectionObserver"in window){let t=new IntersectionObserver(function(e,n){e.forEach(function(e){if(e.isIntersecting){let n=e.target;n.src=n.dataset.src,n.dataset.srcset&&(n.srcset=n.dataset.srcset),n.classList.remove("__lazy"),t.unobserve(n)}})},{rootMargin:"0px 0px 200px 0px"});e.forEach(function(e){t.observe(e)}),window.__NEXT_lazy_observer=t}});
`
getDynamicChunks(files: DocumentFiles) {
const {
dynamicImports,
Expand Down Expand Up @@ -758,11 +754,6 @@ export class NextScript extends Component<OriginProps> {
}}
/>
)}
<script
dangerouslySetInnerHTML={{
__html: NextScript.lazyImageScript,
}}
/>
{process.env.__NEXT_MODERN_BUILD && !disableRuntimeJS ? (
<script
nonce={this.props.nonce}
Expand Down
1 change: 0 additions & 1 deletion test/integration/image-component/basic/test/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,6 @@ function lazyLoadingTests() {
await browser.eval(
`window.scrollTo(0, ${topOfBottomImage - (viewportHeight + buffer)})`
)
await waitFor(5000)
expect(await browser.elementById('lazy-bottom').getAttribute('src')).toBe(
'https://www.otherhost.com/foo3.jpg'
)
Expand Down

0 comments on commit 9c2e235

Please sign in to comment.