diff --git a/packages/gatsby-plugin-image/gatsby-browser.js b/packages/gatsby-plugin-image/gatsby-browser.js
deleted file mode 100644
index 7ca0ef15141ce..0000000000000
--- a/packages/gatsby-plugin-image/gatsby-browser.js
+++ /dev/null
@@ -1,6 +0,0 @@
-import React from "react"
-import { LaterHydrator } from "."
-
-export function wrapRootElement({ element }) {
- return {element}
-}
diff --git a/packages/gatsby-plugin-image/package.json b/packages/gatsby-plugin-image/package.json
index 9321b7271fcc7..7d708ed899f8e 100644
--- a/packages/gatsby-plugin-image/package.json
+++ b/packages/gatsby-plugin-image/package.json
@@ -27,7 +27,7 @@
"esmodule": "dist/gatsby-image.modern.js",
"browser": {
"./dist/gatsby-image.js": "./dist/gatsby-image.browser.js",
- "./dist/gatsby-image.modern.js": "./dist/gatsby-image.browser.modern.js"
+ "./dist/gatsby-image.module.js": "./dist/gatsby-image.browser.module.js"
},
"files": [
"dist/*",
@@ -93,4 +93,4 @@
},
"author": "Matt Kane ",
"license": "MIT"
-}
\ No newline at end of file
+}
diff --git a/packages/gatsby-plugin-image/src/components/__tests__/gatsby-image.browser.tsx b/packages/gatsby-plugin-image/src/components/__tests__/gatsby-image.browser.tsx
index 25fbcde9c147d..154d8617a5b75 100644
--- a/packages/gatsby-plugin-image/src/components/__tests__/gatsby-image.browser.tsx
+++ b/packages/gatsby-plugin-image/src/components/__tests__/gatsby-image.browser.tsx
@@ -1,8 +1,6 @@
-/* eslint-disable @typescript-eslint/no-explicit-any */
/**
* @jest-environment jsdom
*/
-
import React from "react"
import { render, waitFor } from "@testing-library/react"
import * as hooks from "../hooks"
@@ -145,10 +143,13 @@ describe(`GatsbyImage browser`, () => {
{ container: beforeHydrationContent, hydrate: true }
)
- const placeholder = await waitFor(() =>
- container.querySelector(`[data-placeholder-image=""]`)
+ const placeholder = await waitFor(
+ () =>
+ container.querySelector(`[data-placeholder-image=""]`) as HTMLElement
)
- const mainImage = container.querySelector(`[data-main-image=""]`)
+ const mainImage = container.querySelector(
+ `[data-main-image=""]`
+ ) as HTMLElement
expect(placeholder).toBeDefined()
expect(mainImage).toBeDefined()
diff --git a/packages/gatsby-plugin-image/src/components/gatsby-image.browser.tsx b/packages/gatsby-plugin-image/src/components/gatsby-image.browser.tsx
index de0f809a680b6..a008c015e2e45 100644
--- a/packages/gatsby-plugin-image/src/components/gatsby-image.browser.tsx
+++ b/packages/gatsby-plugin-image/src/components/gatsby-image.browser.tsx
@@ -6,7 +6,11 @@ import {
useLayoutEffect,
useRef,
} from "react"
-import { getWrapperProps, gatsbyImageIsInstalled } from "./hooks"
+import {
+ getWrapperProps,
+ gatsbyImageIsInstalled,
+ hasNativeLazyLoadSupport,
+} from "./hooks"
import { getSizer } from "./layout-wrapper"
import { propTypes } from "./gatsby-image.server"
import type {
@@ -56,25 +60,30 @@ export interface IGatsbyImageData {
placeholder?: Pick
}
-const GatsbyImageHydrator: FC = function GatsbyImageHydrator(
- props
-) {
- const { width, height, layout } = props.image
+const GatsbyImageHydrator: FC = function GatsbyImageHydrator({
+ as = `div`,
+ image,
+ style,
+ backgroundColor,
+ className,
+ class: preactClass,
+ onStartLoad,
+ onLoad,
+ onError,
+ ...props
+}) {
+ const { width, height, layout } = image
const {
style: wStyle,
className: wClass,
...wrapperProps
} = getWrapperProps(width, height, layout)
const root = useRef()
- const cacheKey = useMemo(
- () => JSON.stringify(props.image.images),
- [props.image.images]
- )
+ const cacheKey = useMemo(() => JSON.stringify(image.images), [image.images])
- let className = props.className
// Preact uses class instead of className so we need to check for both
- if (props.class) {
- className = props.class
+ if (preactClass) {
+ className = preactClass
}
const sizer = getSizer(layout, width, height)
@@ -98,23 +107,23 @@ const GatsbyImageHydrator: FC = function GatsbyImageHydrator(
const ssrImage = root.current.querySelector(
`[data-gatsby-image-ssr]`
) as HTMLImageElement
- if (ssrImage) {
+ if (ssrImage && hasNativeLazyLoadSupport()) {
if (ssrImage.complete) {
// Trigger onStartload and onLoad events
- props?.onStartLoad?.({
+ onStartLoad?.({
wasCached: true,
})
- props?.onLoad?.({
+ onLoad?.({
wasCached: true,
})
} else {
- document.addEventListener(`load`, function onLoad() {
- document.removeEventListener(`load`, onLoad)
+ document.addEventListener(`load`, function onLoadListener() {
+ document.removeEventListener(`load`, onLoadListener)
- props?.onStartLoad?.({
+ onStartLoad?.({
wasCached: true,
})
- props?.onLoad?.({
+ onLoad?.({
wasCached: true,
})
})
@@ -134,9 +143,9 @@ const GatsbyImageHydrator: FC = function GatsbyImageHydrator(
renderImageToStringPromise.then(
({ renderImageToString, swapPlaceholderImage }) => {
root.current.innerHTML = renderImageToString({
- image: props.image.images,
isLoading: true,
isLoaded: imageCache.has(cacheKey),
+ image,
...props,
})
@@ -147,10 +156,10 @@ const GatsbyImageHydrator: FC = function GatsbyImageHydrator(
root.current,
cacheKey,
imageCache,
- props.style,
- props.onStartLoad,
- props.onLoad,
- props.onError
+ style,
+ onStartLoad,
+ onLoad,
+ onError
)
}
})
@@ -167,35 +176,35 @@ const GatsbyImageHydrator: FC = function GatsbyImageHydrator(
cleanupCallback()
}
}
- }, [props.image.images])
+ }, [image])
- // We need to run this effect before browser has paint to make sure our html is set so no flickering happens
- //
+ // useLayoutEffect is ran before React commits to the DOM. This allows us to make sure our HTML is using our cached image version
useLayoutEffect(() => {
if (imageCache.has(cacheKey) && renderImage) {
root.current.innerHTML = renderImage({
- image: props.image.images,
isLoading: imageCache.has(cacheKey),
isLoaded: imageCache.has(cacheKey),
+ image,
...props,
})
// Trigger onStartload and onLoad events
- props?.onStartLoad?.({
+ onStartLoad?.({
wasCached: true,
})
- props?.onLoad?.({
+ onLoad?.({
wasCached: true,
})
}
- }, [props.image.images])
+ }, [image])
- return createElement(props.as || `div`, {
+ // By keeping all props equal React will keep the component in the DOM
+ return createElement(as, {
...wrapperProps,
style: {
...wStyle,
- ...props.style,
- backgroundColor: props.backgroundColor,
+ ...style,
+ backgroundColor,
},
className: `${wClass}${className ? ` ${className}` : ``}`,
ref: root,