gatsby-background-image icon indicating copy to clipboard operation
gatsby-background-image copied to clipboard

Compatibility with Gatsby 3 & workaround (☂️ Umbrella Issue)

Open YannickMol opened this issue 3 years ago • 19 comments

Hi Team,

As the new version of gatsby-image is coming up in the form of the gatsby-plugin-image plugin, I was wondering whether this will be reflected in a new version of the gatsby-background-image plugin. When using the new API and gatsbyImageData in a BackgroundImage component, it gives the following error: Warning: Failed prop type: Invalid prop "fluid" supplied to "BackgroundImage"..

Thanks, Yannick

YannickMol avatar Jan 27 '21 19:01 YannickMol

Hi Yannick,

wished I were a team, but I'm flying solo on gbi ; ). Already looked into the new plugin, see #132, but didn't look into its Types. Will try to rectify this week - or feel free to open a PR : ).

Best,

Tim.

timhagn avatar Feb 02 '21 17:02 timhagn

Hi @YannickMol,

just looked into it & have to say: Uffz. Quite another paradigm of handling images oO. ~~Trying to implement a converter function for the new gatsbyImageData Type, but couldn't replicate your error... Would you be able to give me some sources or (even better) a reproduction repo?~~ Scratch that, the aspectRatio was missing, as the gatsbyImageData Type directly gives width & height instead of it.

Best,

Tim.

timhagn avatar Feb 07 '21 21:02 timhagn

Hi @YannickMol, again.

As written above, I just worked on a converter function. It isn't completely finished & I'm gonna try adding it to gbi in the upcoming week, but should you want to try it, have a look below : ).


import React from 'react'
import { graphql, useStaticQuery } from 'gatsby'
import { GatsbyImage, getImage } from "gatsby-plugin-image"
import BackgroundImage from "gatsby-background-image"

// ------------------ COPY FROM HERE -------------------------------------------
// Helper functions.
const getBgImageType = imageData => imageData.layout === 'fixed' ? 'fixed' : 'fluid'
const getAspectRatio = imageData => imageData.width / imageData.height
const getPlaceholder = imageData => {
  if (imageData.placeholder) {
    return imageData.placeholder.fallback.includes(`base64`) ?
      { base64: imageData.placeholder.fallback }
      : { tracedSvg: imageData.placeholder.fallback }
  }
  return {}
}

/**
 * Tries to Backport the new `gatsbyImageData` type to the classic `fluid` / `fixed` form.
 *
 * @param imageData   {object}    The image data to convert.
 * @returns {{}}
 */
const convertToBgImage = imageData => {
  if (imageData && imageData.layout) {
    const returnBgObject = {}
    const bgType = getBgImageType(imageData)
    const aspectRatio = getAspectRatio(imageData)
    const placeholder = getPlaceholder(imageData)
    returnBgObject[bgType] = {
      ...imageData.images.fallback,
      ...placeholder,
      aspectRatio,
    }
    return returnBgObject
  }
  return {}
}
// ------------------ TO HERE --------------------------------------------------

const GpiTest = () => {
  const {placeholderImage, oldImage} = useStaticQuery(
    graphql`
      query {
        placeholderImage: file(relativePath: { eq: "gatsby-astronaut.png" }) {
          childImageSharp {
            gatsbyImageData(
              width: 200
              placeholder: BLURRED
              formats: [AUTO, WEBP, AVIF]
            )
          }
        }
      }
    `
  )
  const image = getImage(placeholderImage)

  // Use like this:
  const bgImage = convertToBgImage(image)

  return (
    <BackgroundImage
      Tag="section"
      // Spread bgImage into BackgroundImage:
      {...bgImage}
      preserveStackingContext
    >
      <div style={{minHeight: 1000, minWidth: 1000}}>
        <GatsbyImage image={image} alt={"testimage"}/>
      </div>
    </BackgroundImage>
  )
}
export default GpiTest


WebP (& AVIF) handling is currently missing (& for the latter I have to adapt gbi), but at least at my place it worked like the above. Have phun : )!

Best,

Tim.

P.S.: With this function you could use the new type with the "old" GatsbyImage as well, should you want to ; ).

timhagn avatar Feb 07 '21 21:02 timhagn

Hi there! As @timhagn momentarily is the main contributor to this package, this issue has been automatically marked as stale because it has not had any recent activity. It will be closed if no further activity occurs, though we're open to suggestions on how to get more maintainers! Thank you for your contributions : )!

github-actions[bot] avatar Feb 24 '21 00:02 github-actions[bot]

I have created a simple wrapper that can be used as a 1:1 replacement for <BackgroundImage> until its fully compatible. Note that I only use fluid images. So you might need to tweak a little bit.

// Helper functions.
import BackgroundImage, { IBackgroundImageProps, IFixedObject, IFluidObject } from 'gatsby-background-image'
import { getImage } from 'gatsby-plugin-image'
import { IGatsbyImageData } from 'gatsby-plugin-image/dist/src/components/gatsby-image.browser'
import React, { CSSProperties } from 'react'
import { FunctionComponent } from 'react'

const getBgImageType = (imageData: IGatsbyImageData) => (imageData.layout === 'fixed' ? 'fixed' : 'fluid')
const getAspectRatio = (imageData: IGatsbyImageData) => imageData.width / imageData.height
const getPlaceholder = (imageData: IGatsbyImageData) => {
  if (imageData.placeholder) {
    return imageData.placeholder!.fallback?.includes(`base64`)
      ? { base64: imageData.placeholder!.fallback }
      : { tracedSVG: imageData.placeholder!.fallback }
  }
  return {}
}

/**
 * Tries to Backport the new `gatsbyImageData` type to the classic `fluid` / `fixed` form.
 *
 * @param imageData   {object}    The image data to convert.
 * @returns {{}}
 */
export function convertToBgImage(imageData: IGatsbyImageData): Partial<IBackgroundImageProps> {
  if (imageData && imageData.layout) {
    const returnBgObject: Partial<IBackgroundImageProps> = {}
    const bgType = getBgImageType(imageData)
    const aspectRatio = getAspectRatio(imageData)
    const placeholder = getPlaceholder(imageData)
    // @ts-ignore
    returnBgObject[bgType] = {
      ...imageData.images.fallback,
      ...placeholder,
      aspectRatio,
    }
    return returnBgObject
  }
  return {}
}

export interface IBgImageProps {
  fluid?: IGatsbyImageData
  className?: string
  onClick?: (e: Event) => void
  tabIndex?: number
  fadeIn?: boolean
  id?: string
  style?: CSSProperties
  role?: string
  preserveStackingContext?: boolean
}

/**
 * This is a temporary stopgap solution until `<BackgroundImage>` natively supports `gatsby-plugin-image`,
 * see [https://github.com/timhagn/gatsby-background-image/issues/141](https://github.com/timhagn/gatsby-background-image/issues/141).
 * @param {React.PropsWithChildren<IBgImageProps>} props
 * @return {JSX.Element}
 * @constructor
 */
export const BgImage: FunctionComponent<IBgImageProps> = (props) => {
  const { fluid, children, ...args } = props
  if (fluid) {
    const image = getImage(fluid)
    const bgImage = image && convertToBgImage(image)
    return (
      <BackgroundImage {...bgImage} {...args}>
        {children}
      </BackgroundImage>
    )
  } else {
    return <div>{children}</div>
  }
}

Depending on which other features you need, you might need to add them to IBgImageProps

rburgst avatar Mar 08 '21 05:03 rburgst

@timhagn @rburgst The getPlaceholder helper needs to return the traced svg as { tracedSVG: 'svg...' } not tracedSvg.

joernroeder avatar Mar 08 '21 10:03 joernroeder

Currently, this workaround is very basic. I'm planning to extend this to support webp and art direction as well.

@timhagn @rburgst, I'm trying to also support avif as well. The original fluid object has srcWebp and srcSetWebp fields, I imagine if I specify srcAvif and srcSetAvif, they will be simply ignored?

mwskwong avatar Mar 12 '21 01:03 mwskwong

Hi @all!

Wow, thanks for the effort to all of you! Great enhancement of my meager backport @rburgst : )! And you're right @matthewkwong2, right now srcAvif and srcSetAvif would simply be ignored right now, but I'm just working on it : )!

Best,

Tim.

timhagn avatar Mar 13 '21 11:03 timhagn

Hi again @all,

if you head over to the gbimage-bridge branch & package, you may see the proceedings of the new adapter and may of course add your knowledge and code : )!

Best,

Tim.

timhagn avatar Mar 13 '21 12:03 timhagn

Hi again @all!

Uffz, heavy lifting. It's alread working with WebP (see g3bitest ; ). Nearly there, just a few more steps:

  • [x] add type & sizes to source sets
  • [x] add iterator over all srcSet${Type}s

Hope to finish it tomorrow, but any help welcome in the meantime (see here) : )!

Best,

Tim.

timhagn avatar Mar 13 '21 21:03 timhagn

And once more with feeling: Hi @all!

Just published the first version of gbimage-bridge & new versions of gbi(-es5). In combination it now has:

  • [X] support for the new gatsby-plugin-image query syntax (in GbImage & solo through convertToBgImage())
  • [X] AVIF support
  • [X] conversion for art-directed / stacked images

Have a look at gbimage-bridge, grab [email protected] & give it a spin : )!

Best,

Tim.

P.S.: The resulting image from the conversion could even be used with classic gatsby-image for whomever can't update right now, so thanks for giving me a push to create this ; )!

timhagn avatar Mar 15 '21 19:03 timhagn

@timhagn It's a bit weird you decided to publish it as a separated package. I thought there will be a new major release of the original one.

mwskwong avatar Mar 15 '21 23:03 mwskwong

Hi @matthewkwong2,

it was way faster to write the bridge & gain more experience with the new format than going through all the code and every important moving part to rip our fluid / fixed & replace it with IGatsbyImageData ^^.

Next step (apart from trying to fix more issues % ) is a rewrite, as the current code has become quite a behemoth through "organic growth" that everything should be revisited. Especially looking at the LCP-Score & suchlike ; ).

Best,

Tim.

timhagn avatar Mar 16 '21 10:03 timhagn

Hi @timhagn,

thanks a lot, it works, but there is one major issue, the images all seem to load twice. Even in your demo repository you can see it in the network: https://github.com/timhagn/g3bitest

image

Any ideas?

JStumpp avatar Mar 16 '21 10:03 JStumpp

Hi @timhagn,

thanks a lot, it works, but there is one major issue, the images all seem to load twice. Even in your demo repository you can see it in the network: https://github.com/timhagn/g3bitest

image

Any ideas?

I notice the same thing. While this issue also happens on gatsby-plugin-image as well.

mwskwong avatar Mar 16 '21 11:03 mwskwong

hmmz Would have to invest a little more, but I guess this has to do with #125. The bug I opened in the Gatsby repo for it just got closed -.- And when you say:

While this issue also happens on gatsby-plugin-image as well.

we might perhaps give them a shout, or what do you think?

timhagn avatar Mar 16 '21 13:03 timhagn

Already done it in https://github.com/gatsbyjs/gatsby/issues/30272

mwskwong avatar Mar 16 '21 22:03 mwskwong

@timhagn I know you are the only person working on this, but do you have any ETA when this will be available without the gbimage-bridge? No pressure of course...

pkuczynski avatar Mar 23 '21 20:03 pkuczynski

Already done it in gatsbyjs/gatsby#30272

This issue seems to be fixed with the latest release of gatsby-plugin-image and gatsby-transformer-sharp. Guess it is not our fault after all. It would be great if someone else can verify that.

mwskwong avatar Mar 24 '21 02:03 mwskwong