Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

gatsby-plugin-schema-snapshot avoid WebP picture source from a Json data source #21986

Closed
valse opened this issue Mar 5, 2020 · 5 comments
Closed
Labels
status: confirmed Issue with steps to reproduce the bug that’s been verified by at least one reviewer. topic: GraphQL Related to Gatsby's GraphQL layer type: bug An issue or pull request relating to a bug in Gatsby

Comments

@valse
Copy link
Contributor

valse commented Mar 5, 2020

Hi, I have a project with some Json as data source: I added the gatsby-plugin-schema-snapshot plugin to speed up my build time and I saw that the images served by the gatsby-image component stopped delivering the WebP picture source.

Here a demo of the issue: https://codesandbox.io/s/infallible-snow-i60fj

I changed the image component to get the image childImage field querying the Json source (in the data directory) instead of querying the file system directly.

The source with the WebP format is missing:
image.

I don't knpw if it's correlated but during the build I have this warning message:
The type `File` does not explicitly define the field `childDataJson`. On types with the `@dontInfer` directive, or with the `infer` extension set to `false`, automatically adding fields for children types is deprecated. In Gatsby v3, only children fields explicitly set with the `childOf` extension

Thanks
valse

@valse valse added the type: bug An issue or pull request relating to a bug in Gatsby label Mar 5, 2020
@pieh pieh added the status: confirmed Issue with steps to reproduce the bug that’s been verified by at least one reviewer. label Mar 5, 2020
@pieh
Copy link
Contributor

pieh commented Mar 5, 2020

This is certainly a bug that I can reproduce.

As a workaround (for now), you can exclude gatsby-transformer-sharp from snapshot plugin:

    {
      resolve: `gatsby-plugin-schema-snapshot`,
      options: {
        update: true,
        exclude: {
          plugins: [`gatsby-transformer-sharp`],
        },
      },
    },

Which seems to make it work again.

I'm not sure where to attribute this bug to. With snapshot enabled (and not excluding types from sharp transformer), we get following types in schema:

type ImageSharpFluid {
  base64: String
  tracedSVG: String
  aspectRatio: Float!
  src: String!
  srcSet: String!
  srcWebp: String
  srcSetWebp: String
  sizes: String!
  originalImg: String
  originalName: String
  presentationWidth: Int
  presentationHeight: Int
}

type ImageSharp implements Node @childOf(mimeTypes: [], types: ["File"], many: false) @dontInfer {
  # removed fields other than "fluid" for brevity [...] 
  fluid(
    maxWidth: Int
    maxHeight: Int
    base64Width: Int
    grayscale: Boolean = false
    jpegProgressive: Boolean = true
    pngCompressionSpeed: Int = 4
    duotone: DuotoneGradient
    traceSVG: Potrace
    quality: Int
    jpegQuality: Int
    pngQuality: Int
    webpQuality: Int
    toFormat: ImageFormat = NO_CHANGE
    toFormatBase64: ImageFormat = NO_CHANGE
    cropFocus: ImageCropFocus = ATTENTION
    fit: ImageFit = COVER
    background: String = "rgba(0,0,0,1)"
    rotate: Int = 0
    trim: Float = 0
    sizes: String = ""

    """
    A list of image widths to be generated. Example: [ 200, 340, 520, 890 ]
    """
    srcSetBreakpoints: [Int] = []
  ): ImageSharpFluid
}

Now, resolver for fluid field works fine (

resolve: (image, fieldArgs, context) => {
const file = getNodeAndSavePathDependency(image.parent, context.path)
const args = { ...fieldArgs, pathPrefix }
return Promise.resolve(
fluid({
file,
args,
reporter,
cache,
})
).then(o =>
Object.assign({}, o, {
fieldArgs: args,
image,
file,
})
)
},
}
), but resolver for srcWebp (and probably rest of those resolvers on field of ImageSharpFluid type, I just checked one) is not being hit (
srcWebp: {
type: GraphQLString,
resolve: ({ file, image, fieldArgs }) => {
if (image.extension === `webp` || fieldArgs.toFormat === `webp`) {
return null
}
const args = { ...fieldArgs, pathPrefix, toFormat: `webp` }
return Promise.resolve(
fluid({
file,
args,
reporter,
cache,
})
).then(({ src }) => src)
},
},
). So my gut tells me default resolver is used and because there is no actual srcWebp on object return by fluid - this just make it null?

My guess - ImageSharp type is defined with schema.buildObjectType which seems to play nicely with schema customization (so resolver is attached to type/field defined by schema.gql), while ImageSharpFluid is created using vanilla graphql-js(new GraphQLObjectType({ ... })) which potentially doesn't play nicely?

Thought @vladar?

@pieh pieh added the topic: GraphQL Related to Gatsby's GraphQL layer label Mar 5, 2020
@vladar
Copy link
Contributor

vladar commented Mar 6, 2020

@pieh This is another rabbit hole %) But I think I've found the root of the problem.

The issue is that the type ImageSharpFluid is created inline as a part of ImageSharp type definition:

const fluidNodeType = ({
pathPrefix,
getNodeAndSavePathDependency,
reporter,
name,
cache,
}) => {
return {
type: new GraphQLObjectType({
name: name,
fields: {

In other words when we call createTypes(typeDefs) the type ImageSharpFluid is not in the list of typeDefs. It just sits somewhere deep inside ImageSharp type definition.

It works as long as you don't provide another typeDef for this type (we do this here in snapshot plugin). So instead of merging two typeDefs we rewrite the old typeDef with a new one created from AST (which doesn't have any custom resolvers).

We do this because we don't even know that there is an old ImageSharpFluid typeDef - it is not on our list.

I think the only way to fall into this trap is by using native GraphQL type definitions with schema csutomization. Type builders and AST probably don't have this problem (as you have to add all types to typeDefs directly).

So the unfortunate outcome of this is that we must additionally recursively walk through all fields and manually add any types defined inline into typeDefs.

(I personally think we should probably have fewer options for type definition formats in schema customization API but that's obviously not gonna happen anytime soon for BC and convenience reasons)

@valse This is a very rare and unfortunate edge case and the workaround suggested by @pieh should work for you for now. Still, we must address it in the core as it is a bug.

@valse
Copy link
Contributor Author

valse commented Mar 6, 2020

Yes I confirm that the workaround solve the problem, thanks: could I ignore the "File" warning too?

@vladar
Copy link
Contributor

vladar commented Mar 6, 2020

For the file warning - you could add the following to gatsby-node.js:

// in site's gatsby-node.js:
exports.createSchemaCustomization = ({ actions }) => {
  const typeDefs = `
    type DataJson implements Node @childOf(types: ["File"]) {
      id
    } 
  `
  actions.createTypes(typeDefs)
}

This should fix the warning. There is a bit more context on this in #19674

@vladar vladar self-assigned this Mar 6, 2020
@LekoArts
Copy link
Contributor

Hi!

I'm closing this as a stale issue as in the meantime Gatsby 4 and related packages were released. You can check our Framework Version Support Page to see which versions currently receive active support.

Please try the mentioned issue on the latest version (using the next tag) and if you still see this problem, open a new bug report. It must include a minimal reproduction.

Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
status: confirmed Issue with steps to reproduce the bug that’s been verified by at least one reviewer. topic: GraphQL Related to Gatsby's GraphQL layer type: bug An issue or pull request relating to a bug in Gatsby
Projects
None yet
Development

No branches or pull requests

4 participants