Code Monkey home page Code Monkey logo

gatsby-transformer-cloudinary's Introduction

Gatsby Transformer Cloudinary

With gatsby-transformer-cloudinary you may:

  • ๐Ÿ–ผ๏ธ Add gatsby-plugin-image support to any GraphQL Types describing a Cloudinary assets.
  • ๐Ÿ“ค Upload local and remote images to Cloudinary from within your Gatsby project.

๐Ÿ“ฅ But if you want to pull data from your Cloudinary account into the Gatsby data layer use our other plugin, gatsby-source-cloudinary

This is a community library supported by the Cloudinary Developer Experience team.

๐Ÿ“– Table of Contents

ย 

๐Ÿ–ผ๏ธ Add Gatsby Image Support to Existing Cloudinary Assets

Use assets hosted by Cloudinary together with Gatsby's Image component:

  • The plugin adds the gatsbyImageData resolver to each GraphQLType configured.

This configuration and example assumes your Gatsby Data Layer has at least one node of type BlogPost with a heroImage field describing an already uploaded Cloudinary asset.

๐Ÿ‘‰ More details in Transform Type Requierments.

Install Packages

npm install gatsby-transformer-cloudinary gatsby-plugin-image

or

yarn add gatsby-transformer-cloudinary gatsby-plugin-image

Configure Plugins

// File: ./gatsby-config.js

module.exports = {
  plugins: [
    {
      resolve: `gatsby-transformer-cloudinary`,
      options: {
        // Add the `gatsbyImageData` resolver to `BlogPostHeroImage`
        transformTypes: [`BlogPostHeroImage`],
        // Optional transformation option
        defaultTransformations: ['c_fill', 'g_auto', 'q_auto'],
      },
    },
    `gatsby-plugin-image`,
  ],
};

Example Usage

// File: ./pages/{BlogPost.slug}.js

import React from 'react';
import { graphql } from 'gatsby';
import { GatsbyImage, getImage } from 'gatsby-plugin-image';

const BlogPost = ({ data }) => {
  const { blogPost } = data;
  const gatsbyImage = getImage(blogPost.heroImage);
  return (
    <article>
      <h1>{blogPost.title}</h1>
      <GatsbyImage image={gatsbyImage} aria-hidden="true" alt="Hero Image" />
      {/* ... */}
    </article>
  );
};

export const query = graphql`
  query BlogPostById($id: String!) {
    blogPost(id: { eq: $id }) {
      title
      heroImage {
        gatsbyImageData(
          height: 300
          aspectRatio: 2
          placeholder: TRACED_SVG
          transformations: ["c_fill", "e_grayscale"]
        )
      }
    }
  }
`;

export default BlogPost;

Transform Type Requierments

You may add Gatsby Image support to any GraphQL Type describing a Cloudinary assets with this data shape:

{
  // Required
  cloudName: "my-amazing-blog",
  publicId: "blue-blue-blue",
  // Optional: Saves a network request for size/format data per image queried if all are added
  originalHeight: 360,
  originalWidth: 820,
  originalFormat: "jpg",
  // Optional: Saves a Cloudinary transformation per image queried with `placeholder=BLURRED` as this value will be used instead
  defaultBase64: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mMMXG/8HwAEwAI0Bj1bnwAAAABJRU5ErkJggg==",
  // Optional: Saves a Cloudinary transformation per image queried with `placeholder=TRACED_SVG` as this value will be used instead
  defaultTracedSVG: "data:image/svg+xml,%3Csvg%20height%3D%229999%22%20viewBox%3D%220%200%209999%209999%22%20width%3D%229999%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%3Cpath%20d%3D%22m0%200h9999v9999h-9999z%22%20fill%3D%22%23f9fafb%22%2F%3E%3C%2Fsvg%3E",
}

To find the GraphQL Type describing your Cloudinary assets use the built in GraphiQL exlorer. Either hover over the field describing the asset, or look in the "Documentation Explorer".

defaultBase64 and defaultTracedSVG is the base64 URI of the placeholder image, it must comply with RFC 2397.

ย 

๐Ÿ“ค Upload Local Images and Add Gatsby Image Support

If you upload local images to Cloudinary and skip the gatsby-transformer-sharp you speed up your build process and enjoy Cloudinary's transformations:

  • The plugin creates a CloudinaryAsset node for each image.
  • The plugin adds a gatsbyImageData resolver to each node by default.

This configuration and example assumes you have your images folder in the root of your project.

Install packages

npm install gatsby-transformer-cloudinary gatsby-source-filesystem gatsby-plugin-image

or

yarn add gatsby-transformer-cloudinary gatsby-source-filesystem gatsby-plugin-image

Configure plugins

// File: ./gatsby-config.js

module.exports = {
  plugins: [
    {
      resolve: `gatsby-source-filesystem`,
      options: {
        name: `gallery`,
        path: `${__dirname}/gallery`,
      },
    },
    {
      resolve: 'gatsby-transformer-cloudinary',
      options: {
        // Required for uploading
        cloudName: process.env.CLOUDINARY_CLOUD_NAME,
        apiKey: process.env.CLOUDINARY_API_KEY,
        apiSecret: process.env.CLOUDINARY_API_SECRET,
        // Optional uploading options
        uploadFolder: process.env.CLOUDINARY_UPLOAD_FOLDER,
        uploadSourceInstanceNames: ['gallery'],
        overwriteExisting: process.env.NODE_ENV === 'production' ? true : false,
        // Optional transformation options
        transformTypes: ['CloudinaryAsset'],
        defaultTransformations: ['c_fill', 'g_auto', 'q_auto'],
      },
    },
  ],
};

process.env โ‰๏ธ Read about env variables in the Gatsby docs.

Example Usage

Example of the plugin fetching an asset using the useStaticQuery API of Gatsby:

// File ./components/local-upload.js

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

const LocalUploadExample = () => {
  // Using gatsby-transformer-sharp
  // commented out for comparison

  // const data = useStaticQuery(graphql`
  //   query {
  //     file(name: { eq: "sergey-semin-unsplash" }) {
  //       childImageSharp {
  //         gatsbyImageData(height: 300, layout: FIXED)
  //       }
  //     }
  //   }
  // `);

  const data = useStaticQuery(graphql`
    query {
      file(name: { eq: "sergey-semin-unsplash" }) {
        childCloudinaryAsset {
          gatsbyImageData(height: 300, layout: FIXED)
        }
      }
    }
  `);

  // const gatsbyImage = getImage(data.file.childImageSharp);
  const gatsbyImage = getImage(data.file.childCloudinaryAsset);

  return (
    <GatsbyImage
      image={gatsbyImage}
      alt="Pirate photo by Sergey Semin from Unsplash."
    />
  );
};

export default LocalUploadExample;

ย 

๐Ÿ“ค Upload Remote Images and add Gatsby Image Support

Upload remote images referenced in any node to Cloudinary and enjoy Cloudinary's transformations:

  • The plugin creates a CloudinaryAsset node for each image.
  • The plugin adds the gatsbyImageData resolver to each node by default.

Uploading remote image requires you to write some custom code. We'd like to make it configurable instead, let us know if you'd benefit by joining the discussion.

This configuration and example assumes your Gatsby Data Layer has at least one node of type Project with a coverImageUrl field containg a url pointing to a publically available image file.

Install Packages

npm install gatsby-transformer-cloudinary gatsby-plugin-image

or

yarn add gatsby-transformer-cloudinary gatsby-plugin-image

Configure Plugins

// File: ./gatsby-config.js

module.exports = {
  plugins: [
    {
      resolve: 'gatsby-transformer-cloudinary',
      options: {
        // Required for uploading
        cloudName: process.env.CLOUDINARY_CLOUD_NAME,
        apiKey: process.env.CLOUDINARY_API_KEY,
        apiSecret: process.env.CLOUDINARY_API_SECRET,
        // Optional uploading options
        uploadFolder: process.env.CLOUDINARY_UPLOAD_FOLDER,
        overwriteExisting: process.env.NODE_ENV === 'production' ? true : false,
        // Optional transformation options
        transformTypes: ['CloudinaryAsset'],
        defaultTransformations: ['c_fill', 'g_auto', 'q_auto'],
      },
    },
  ],
};

process.env โ‰๏ธ Read about env variables in the Gatsby docs.

Example Usage

// File: ./gatsby-node.js

import { createRemoteImageNode } from 'gatsby-transformer-cloudinary';

export async function onCreateNode({
  node,
  actions: { createNode },
  createNodeId,
  createContentDigest,
  reporter,
}) {
  if (node.internal.type === 'Project' && node.coverImageUrl) {
    // Upload the image to Cloudinary
    const imageNode = await createRemoteImageNode({
      url: node.coverImageUrl,
      parentNode: node,
      createNode,
      createNodeId,
      createContentDigest,
      reporter,
    });

    // Add node field to be used by "createSchemaCustomization"
    createNodeField({ node: node, name: 'coverImage', value: imageNode.id });
  }
}

exports.createSchemaCustomization = (gatsbyUtils) => {
  const { actions } = gatsbyUtils;

  // Connect the node to the CloudinaryAsset using @link
  const ProjectType = `
      type Project implements Node  {
        coverImageUrl: String!
        coverImage: CloudinaryAsset @link(from: "fields.coverImage" by: "id")
      }
    `;

  actions.createTypes([ProjectType]);
};
// File: ./pages/{Article.slug}.js

import React from 'react';
import { graphql } from 'gatsby';
import { GatsbyImage, getImage } from 'gatsby-plugin-image';

const Project = ({ data }) => {
  const { project } = data;
  const gatsbyImage = getImage(project.coverImage);
  return (
    <article>
      <h1>{project.name}</h1>
      <GatsbyImage image={gatsbyImage} aria-hidden="true" alt="Cover Image" />
      {/* ... */}
    </article>
  );
};

export const query = graphql`
  query ProjectById($id: String!) {
    project(id: { eq: $id }) {
      name
      coverImage {
        gatsbyImageData(
          height: 300
          aspectRatio: 2
          placeholder: TRACED_SVG
          transformations: ["c_fill", "g_auto:subject", "q_auto"]
        )
      }
    }
  }
`;

export default Project;

ย 

๐Ÿ”Œ Plugin Options

In gatsby-config.js the plugin accepts the following options:

cloudName (required for upload functionality)

You'll find your Cloudinary account's cloudName in your Cloudinary console.

Type: String
Default: n/a
Note: Store and retrieve your cloudName as an environment variable.

apiKey (required for upload functionality)

You'll find your Cloudinary API Key in the Cloudinary console.

Type: String
Default: n/a
Note: Store and retrieve your apiKey as an environment variable.

apiSecret (required for upload functionality)

You'll find your Cloudinary API Secret in your Cloudinary console.

secure

When set to false uses http instead of https for the image urls.

Type: Boolean Default: true

height / width

Type: String
Default: n/a
Note: Store and retrieve your apiSecret as an environment variable.

uploadFolder

An optional folder name where the uploaded assets will be stored on Cloudinary.

Type: String
Default: n/a\

uploadSourceInstanceNames

An optional array limiting uploads to file nodes with a matching sourceInstanceName.

Type: [String]
Default: n/a\

transformTypes

An optional array of GraphQL Types to add the gatsbyImageData resolver for Gatsby Image support.

Type: [String]
Default: ['CloudinaryAsset']

overwriteExisting

Whether to overwrite existing assets with the same public ID. When set to false, return immediately if an asset with the same Public ID was found. It's recommended that this is set to false in development as each image overwrite costs one Cloudinary transformation.

Type: Boolean
Default: false

defaultTransformations

The default value for the gatsbyImageData resolver argument transformations.

Type: [String]
Default: ['c_fill', 'g_auto', 'q_auto']

ย 

๐Ÿ–ผ๏ธ Gatsby Plugin Image (gatsbyImageData) API

The plugin supports gatsby-plugin-image by adding a gatsbyImageData resolver to the configured GraphQL types.

Arguments for gatsbyImageData

transformations

An array of "raw" cloudinary transformations added to the initial transformation together with the width and height.

Type: [String]
Default:["c_fill", "g_auto", "q_auto"] or the configured defaultTransformations
Example: ["c_crop", "x_300"]

WARNING: Changing the sizing using transformations will mess with the Gatsby Image Component

chained

An array of "raw" cloudinary transformations added after the initial transformations above.

Type: [String]
Default: []
Example: ["e_grayscale","e_pixelate_faces,e_tint:100:663399:0p:white:100p"]

WARNING: Changing the sizing using chained transformations will mess with the Gatsby Image Component

placeholder

The style of the temporary image shown while the larger image is loaded.

Type: NONE, BLURRED or TRACED_SVG
Default: NONE
Example: BLURRED

NOTE: DOMINANT_COLOR is not supported

Read the Gatsby Plugin Image Docs for more information.

height / width

Read the Gatsby Plugin Image Docs on height / width.

aspectRatio

Read the Gatsby Plugin Image Docs on aspectRatio.

layout

Read the Gatsby Plugin Image Docs on layout.

backgroundColor

Read the Gatsby Plugin Image Docs on backgroundColor.

breakpoints

Read the Gatsby Plugin Image Docs on breakpoints.

outputPixelDensities

Read the Gatsby Plugin Image Docs on outputPixelDensities.

sizes

Read the Gatsby Plugin Image Docs on sizes.

ย 

๐Ÿ“š Other Resources

ย 

๐Ÿดโ€โ˜ ๏ธ Contribute

You may improve the documentation, help fellow users, report bugs, suggest enhancements, contribute code and more.

Get started by reading the contribution docs.

gatsby-transformer-cloudinary's People

Contributors

calag4n avatar chuloo avatar cloudinary-raae avatar colbyfayock avatar dependabot[bot] avatar jastuccio avatar jlengstorf avatar kurttomlinson avatar olavea avatar paulgaumer avatar raae avatar semantic-release-bot avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

gatsby-transformer-cloudinary's Issues

Api key required

Documentation states:

The options cloudName, apiKey, and apiSecret are required if any images will be uploaded to Cloudinary during the build process. If you're solely using images already uploaded to Cloudinary, then these options can be safely omitted.

But if i remove one of these option (i don't need upload, since my files are already on cloudinary) i got the following error when running gatsby develop:

[gatsby-transformer-cloudinary] "apiKey" is a required plugin option. You can add it to the options object for "gatsby-transformer-cloudinary" in your gatsby-config file.

also leaving the values blank leads to errors, so it looks like the plugin cant be used with images already stored on cloudinary without uploading;

it works only by disabling gatsby-source-filesystem image section, but i cant do it since im using the local images for other things;

a "no-upload" option would be really useful

Memory leak when uploading lots of images?

I'm trying to replace images served from Netlify with ones served from Cloudinary on an existing site which contains quite a lot of images, however when I run gatsby develop or gatsby build I get the following error:

success onPreBootstrap - 0.008s

 ERROR 

undefined undefined



  Error: 

not finished source and transform nodes - 12.517s

 ERROR 

Warning: Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in a useEffect cleanup function.
    in StoreStateProvider
    in App

Looking in my uploads folder in Cloudinary there seem to be a few more images uploaded each time I run gatsby develop or gatsby build so it looks like it's during the upload process that the memory leak gets caught and the process is cancelled.

ERROR Type with name "RemoteFileResize" does not exists

We are getting an error right after the Cloudinary nodes get processed in the build so we suspect that this is related. This is happening when builds are triggered by a webhook, however a cache clear build always works, and if we get this error the next build always works. So there seems to be something happening with an expected cache perhaps. There isn't much information in the trace that makes sense to me, aside from looking up RemoteFileResize (and finding it within Gatsby) I can't get much further.

Any ideas?

14:25:21 PM: success Building static HTML for pages - 0.464s - 6/6 12.93/s
14:25:22 PM: ERROR Type with name "RemoteFileResize" does not exists
14:25:22 PM:  Error: Type with name "RemoteFileResize" does not exists
14:25:22 PM:  - TypeStorage.js:44 SchemaComposer.get
14:25:22 PM:    [www]/[graphql-compose]/lib/TypeStorage.js:44:13
14:25:22 PM:  - TypeMapper.js:585 ThunkComposer._thunk
14:25:22 PM:    [www]/[graphql-compose]/lib/TypeMapper.js:585:34
14:25:22 PM:  - ThunkComposer.js:42 ThunkComposer.getUnwrappedTC
14:25:22 PM:    [www]/[graphql-compose]/lib/ThunkComposer.js:42:17
14:25:22 PM:    [www]/[graphql-compose]/lib/ThunkComposer.js:20:34
14:25:22 PM:  - ThunkComposer.js:20 ThunkComposer.get ofType [as ofType]
14:25:22 PM:  - typeHelpers.js:208 unwrapTC
14:25:22 PM:    [www]/[graphql-compose]/lib/utils/typeHelpers.js:208:31
14:25:22 PM:  - typeHelpers.js:209 unwrapTC
14:25:22 PM:    [www]/[graphql-compose]/lib/utils/typeHelpers.js:209:12
14:25:22 PM:  - typeHelpers.js:220 unwrapOutputTC
14:25:22 PM:    [www]/[graphql-compose]/lib/utils/typeHelpers.js:220:10
14:25:22 PM:  - ObjectTypeComposer.js:380 ObjectTypeComposer.getFieldTC
14:25:22 PM:    [www]/[graphql-compose]/lib/ObjectTypeComposer.js:380:44
14:25:22 PM:  - SchemaComposer.js:194 
14:25:22 PM:    [www]/[graphql-compose]/lib/SchemaComposer.js:194:26
14:25:22 PM:  - Array.forEach
14:25:22 PM:  - SchemaComposer.js:193 SchemaComposer.removeEmptyTypes
14:25:22 PM:    [www]/[graphql-compose]/lib/SchemaComposer.js:193:24
14:25:22 PM:    [www]/[graphql-compose]/lib/SchemaComposer.js:207:18
14:25:22 PM:  - SchemaComposer.js:207 
14:25:22 PM:  - Array.forEach
14:25:22 PM:  - SchemaComposer.js:193 SchemaComposer.removeEmptyTypes
14:25:22 PM:    [www]/[graphql-compose]/lib/SchemaComposer.js:193:24
14:25:22 PM:    [www]/[graphql-compose]/lib/SchemaComposer.js:207:18
14:25:22 PM:  - SchemaComposer.js:207 
14:25:22 PM:  - Array.forEach
14:25:22 PM: not finished onPostBuild - 1.205s
14:25:22 PM: not finished rebuild schema - 1.389s

specify allowed paths, owners or types

I'm currently combining the cloudinary transformer with several other source and transformer plugins and I am having a hard time limiting the scope of files which should be uploaded to cloudinary. For example the transformer currently picks up images inside the .cache directory, which makes it impossible to use it with other plugins which cache their remote files.
Being able to include/exclude files by their path owner or type would help.

I'm happy to submit a pull request to allow limiting source path.

support for gatsby 4

Does this module support Gatsby v4, after upgrading a previously working site i'm finding inconsistent results with cloudinary images. We are using the plugin to use images on cloudinary and have a mongodb object with cloudinaryAssetData: true, this worked well for gatsby 3.

We see that nodes are transformed in the graphql on develop, they have the fixed, fluid objects present, however running develop is inconsistent, sometimes we see images, sometimes not. Build will have no images present. For the most part running develop has empty cloudinary nodes with only the very last having the src with a cloudinary URL.

It does look like the plugin hasn't been updated in a while, but if anyone can confirm whether it should run ok with gatsby 4 that would be useful and i can try to help debug whats going on here if there is an issue.

Cannot convert undefined or null to object - when some image nodes are null

The plugin is functioning and we get graphQL nodes created from the Cloudinary images, however we get the following error:

error "gatsby-transformer-cloudinary" threw an error while running the onCreateNode lifecycle:

Cannot convert undefined or null to object

  53 |   const currentNode = basePath === '' ? node : get(node, basePath);
  54 | 
> 55 |   const directAssetDataPaths = Object.keys(currentNode)
     |                                       ^
  56 |     .filter(key => {
  57 |       return currentNode[key] && currentNode[key].cloudinaryAssetData === true;
  58 |     })


  TypeError: Cannot convert undefined or null to object
  
  - Function.keys
  
  - create-asset-nodes-from-data.js:55 getAssetDataPaths
    [mysite]/[gatsby-transformer-cloudinary]/gatsby-node/create-asset-nodes-from-data.js:55:39
...

This occurs in develop and build, in develop it will get past this error, but build fails.

We are adding an object for cloudinary with all the applicable data, but due to our database structure this object is occasionally null. For instance:

mediaItems: [
   {
   ...,
   "cloudinary": {
      "cloudName": "mycloudname",
      "orginalHeight: 2250,
      "cloudinaryAssetData": true,
      ...
       }
   },
   "cloudinary": null
]

Currently the situation is that the plugin appears to be working ok - the above structure is how it looks before the plugin is working. These get replaced with the fixed/fluid image graphQL node and the plugin appears to be working fine. But it still produces the error above, which of course fails the build.

It would be good if this isn't an error! A warning at most, so long as it finds at least some useable objects that would seem to be sufficient. Unfortunately making changes to our DB is a little difficult, there may be a way round this with gatsby-node.js, but it would be good to see if there's a fix perhaps.

Question: query childCloudinaryAsset from markdownRemark?

Hello,

So my problem, that I would love to get some help with, is that I want to be able to query an childCloudinaryAsset on frontImageDesktop here to be able to use it with gatsby-image:

    allMarkdownRemark(sort: { fields: [frontmatter___date], order: DESC }) {
          edges {
            node {
              excerpt
              frontmatter {
                date(formatString: "MMMM DD, YYYY")
                title
                bg_color
                text_color
                description1
                description2
                frontImageDesktop
              }
            }
          }
        }

But I cant since my posts looks like this, frontImageDesktop only contains the url :

    ---
    title: Test
    bg_color: white
    text_color: black
    date: 2021-03-27T23:37:27.616Z
    description1: Big desc
    description2: sm
    frontImageDesktop: https://res.cloudinary.com/name/image/upload/v161688xxx/_web.jpg
    ---

The Cloudinary assets are created and it works fine to query an asset like this:

     file(name: { eq: "_web" }) {
          childCloudinaryAsset {
            fixed {
              ...CloudinaryAssetFixed
            }
          }
        } 

What I would like to be able to do is this:

    allMarkdownRemark(sort: { fields: [frontmatter___date], order: DESC }) {
                  edges {
                    node {
                      excerpt
                      frontmatter {
                        date(formatString: "MMMM DD, YYYY")
                        title
                        bg_color
                        text_color
                        description1
                        description2
                        frontImageDesktop {
                          childCloudinaryAsset {
                            fixed {
                              ...CloudinaryAssetFixed
                            }
                          }
                        } 
                      }
                    }
                  }
                }

SETUP:

    //gatsby-config.js
    require("dotenv").config()
    
    module.exports = {
      plugins: [
        `gatsby-transformer-sharp`,
        `gatsby-plugin-sharp`,
        {
          resolve: `gatsby-source-filesystem`,
          options: {
            path: `${__dirname}/static/img`,
            name: `images`,
          },
        },
        {
          resolve: `gatsby-source-filesystem`,
          options: {
            path: `${__dirname}/content/blog`,
            name: `blog`,
          },
        },
        {
          resolve: "gatsby-transformer-cloudinary",
          options: {
            cloudName: process.env.CLOUDINARY_CLOUD_NAME,
            apiKey: process.env.CLOUDINARY_API_KEY,
            apiSecret: process.env.CLOUDINARY_API_SECRET,
            uploadFolder: "name",
          },
        },
    
        {
          resolve: `gatsby-transformer-remark`,
          options: {
            plugins: [
              {
                resolve: `gatsby-remark-relative-images`,
              },
              {
                resolve: `gatsby-remark-images`,
                options: {
                  maxWidth: 590,
                },
              },
            ],
          },
        },
        {
          resolve: "gatsby-plugin-netlify-cms",
          options: {
            modulePath: `${__dirname}/cms/cms.js`,
          },
        },
    
        `gatsby-plugin-offline`,
        `gatsby-plugin-react-helmet`,
        `gatsby-plugin-sitemap`,
        {
        },
      ],
    }

    // gatsby-node.js
    import { createRemoteImageNode } from "gatsby-transformer-cloudinary"
    
    const POST_NODE_TYPE = "MarkdownRemark"
    
    export async function onCreateNode({
      node,
      actions: { createNode },
      createNodeId,
      createContentDigest,
      reporter,
    }) {
      // Testing for frontImageDesktop
      if (node.internal.type === POST_NODE_TYPE && node.frontImageDesktop) {
        await createRemoteImageNode({
          url: node.frontImageDesktop,
          parentNode: node,
          relationshipName: "frontImageDesktop",
          createNode,
          createNodeId,
          createContentDigest,
          reporter,
        })
      }
    }


    //config.yml
    
    backend:
      name: git-gateway
      branch: master
    
    media_folder: static/img
    public_folder: /img
    
    media_library:
      name: cloudinary
      config:
        cloud_name: name
        api_key: key
    
    collections:
      - name: "blog"
        label: "Blog"
        folder: "content/blog"
        create: true
        slug: "{{year}}-{{month}}-{{day}}-{{slug}}"
        editor:
          preview: false
        fields:
          - { label: "Title", name: "title", widget: "string", required: true }
          - {
              label: "Background Color",
              name: "bg_color",
              widget: "string",
              required: true,
            }
          - {
              label: "Text Color",
              name: "text_color",
              widget: "string",
              required: true,
            }
          - { label: "Publish Date", name: "date", widget: "datetime" }
          - {
              label: "Big desc",
              name: "description1",
              widget: "text",
              required: true,
            }
          - {
              label: "Small desc",
              name: "description2",
              widget: "text",
              required: false,
            }
          - {
              label: "Front Image Desktop",
              name: "frontImageDesktop",
              widget: "image",
              required: true,
            }

Strapi and Cloudinary working with gatsby-transformer-cloudinary

Hey Guys! nice job with the plugin!

Unfortunately I can't make this works, I have a CMS with Strapi and Cloudinary as a plugin, when I try to use the
gatsby-transformer-cloudinary, all the Cloudinary existing images are upload again in a cache folder, i wanna try the existing images steps but is not clear to me, could you explain to me a little more how can i do for integrate this!

Thanks in advance @jastuccio @jlengstorf

Querying images already uploaded to Cloudinary

Hi there!

I'm trying to make use of the third method mentioned here. Information and examples are a bit sparse though, so I'm struggling to make it work.

Images are uploaded through a custom CMS, that uploads images to cloudinary and exposes a graphql endpoint which my Gatsby configuration consumes.

To try it out, I made this json file:

{
  "title": "Helloooo!",
  "coverPhoto": {
    "cloudinaryAssetData": true,
    "cloudName": "<my-cloud-name>",
    "publicId": "sample",
    "originalWidth": 864,
    "originalHeight": 576
  }
}

My gatsby-config.js is looking like this:

require("dotenv").config({
  path: `.env.${process.env.NODE_ENV}`,
})

module.exports = {
  siteMetadata: {
    title: `My cool site with cloudinary stuff on it`,
    description: `Cool description`,
    author: `@CodeMostly`,
  },
  plugins: [
    `gatsby-plugin-react-helmet`,
    {
      resolve: `gatsby-source-filesystem`,
      options: {
        name: `images`,
        path: `${__dirname}/src/images`,
      },
    },
    {
      resolve: `gatsby-source-filesystem`,
      options: {
        name: `posts`,
        path: `${__dirname}/data/posts`,
      },
    },
    `gatsby-transformer-sharp`,
    {
      resolve: "gatsby-transformer-cloudinary",
      options: {
        cloudName: process.env.CLOUDINARY_CLOUD_NAME,
        apiKey: process.env.CLOUDINARY_API_KEY,
        apiSecret: process.env.CLOUDINARY_API_SECRET,
      },
    },
    `gatsby-transformer-json`,
    `gatsby-plugin-sharp`,
    `gatsby-plugin-styled-components`,
    {
      resolve: `gatsby-plugin-manifest`,
      options: {
        name: `name`,
        short_name: `Short`,
        start_url: `/`,
        background_color: `#08101d`,
        theme_color: `#f18805`,
        display: `minimal-ui`,
        icon: `static/icon.svg`, // This path is relative to the root of the site.
      },
    },
    {
      resolve: "gatsby-source-graphql",
      options: {
        typeName: "MyCustomGraphQL",
        fieldName: "customGraphql",
        url: "<super-secret-url>",
      },
    },
    // this (optional) plugin enables Progressive Web App + Offline functionality
    // To learn more, visit: https://gatsby.dev/offline
    // `gatsby-plugin-offline`,
  ],
}

But all I can query in my graphql is this:

query MyQuery {
  allPostsJson {
    edges {
      node {
        coverPhoto {
          cloudName
          cloudinaryAssetData
          originalWidth
          publicId
          originalHeight
        }
      }
    }
  }
}

So, no replacement is taking place. What am I doing wrong?

Manually creating fluid images with Cloudinary Media Transformations

Hey, Jason!

Cloudindary Transformer to convert gif => mp4

As you advised I created Cloudindary Transformer to convert gif => mp4 and manually added fluid image with the above transformer.

/** @jsx jsx */
import { jsx } from 'theme-ui'
import { useEffect, useState } from 'react'
import Image from 'gatsby-image'
import { getFluidImageObject } from 'gatsby-transformer-cloudinary'

export default () => {
  const [fluid, setFluid] = useState(false)

  useEffect(() => {
    getFluidImageObject({
      public_id: 'gatsby-cloudinary/simpson',
      cloudName: 'iamskok',
      originalHeight: โ€Š264,
      originalWidth: 382,
      transformations: ['t_gif-to-mp4-transform'],
    })
    .then(result => setFluid(result))
  }, [])

  return (
    fluid ?
    <Image
      fluid={ fluid }
      sx={{
        maxWidth: 382,
        maxHeight: 264,
      }}
    /> :
    <div
      sx={{
        height: '100vh',
        width: '100vw',
        maxWidth: 382,
        maxHeight: 264,
      }}
    />
  )
}

Though the final image markup gets outputted without .mp4 and the default .gif gets served.

Image markup

gatsby-config.js

The live example can be found here on the /3 slide.

The original motivation to make this working comes from Google's Web Fundamentals article

Question: Getting query working with Cloudinary

New Note: Ok, I got it fixed...I will close this!

Note: I fixed it so that I'm not getting errors...now seeing if I can display the image.

Here's a query that is working in a similar way to Jason's in the Gatsby Transformer Cloudinary video:

{
  allFile {
    nodes {
      name
      childCloudinaryAsset {
        fluid {
          srcSet
          base64
          aspectRatio
        }
      }
    }
  }
}

I set up my component like this:

import { graphql, useStaticQuery } from 'gatsby';
import Image from 'gatsby-image';
import React from 'react';

 
const CarImage = () => {
  const data = useStaticQuery(graphql`
    query {
      image: file(name: {eq: "car" }) {
        cloudinary: childCloudinaryAsset {
          fluid {
            ...CloudinaryAssetFluid
          }
        }
      }
    }
  `);

  return <Image fluid={data.childCloudinaryAsset.fluid} alt="car image" />;
};

export default CarImage

What am I doing wrong? I don't get an error until I try to use it on a page...then I get:
TypeError: Cannot read property 'fluid' of undefined

I'm very excited to get this working! Cloudinary looks really cool.

I'm using the standard starter. My repo is here:
https://github.com/erichodges/cloudinary-test

Note that the plugin is uploading the images correctly to Cloudinary.

Include original Cloudinary JSON data after transformer has run

The current implementation of the transformer completely replaces the Cloudinary JSON data with the new CloudinaryAsset GQL type.

It would be useful to still have the option of accessing some of the original properties - particularly the public_id field - if we wish to do some manual transformation via the Cloudinary SDK.

Integration with gatsby-source-graphql

Hello,
When using the plugin gatsby-source-graphql and calling data from it, It seems that the gatsby-transfomer-cloudinary plugin don't recognize coming objects with the structure:

{
  ...,
  coverPhoto: {
      cloudinaryAssetData: true,
      cloudName: "my-amazing-blog",
      publicId: "blue-blue-blue",
      originalHeight: 360,
      originalWidth: 820
  }
}

to automatically fetch images from Cloudinary, and have a node of type CouldinaryAsset as described here.
The only thing that I can do as query is the following:

query Data {
  pos {
    products {
      coverPhoto {
        alt
        cloudName
        cloudinaryAssetData
        originalWidth
        originalHeight
        publicId
      }
    }
  }
}

Add option to generate props for cloudinary-react

For example: can add a cldFixed, cldFluid, cldSomeTransformation objects, like the fluid/fixed objects that are added for easy integration with gatsby-image.

It could then be used like this:

import {Image} from 'cloudinary-react';
/* get cldTransformations using GraphQL*/

in render():
<Image {...cldTransformations.fixed}/>
<Image {...cldTransformations.faceThumbnail}/>
<Image {...cldTransformations.responsive}/>
etc...

Aspect ratio transformation not working

Hello,
It seems that there is a bug when trying to get a fluid image object with an aspect ratio transformation.

query Query {
  product {
    image {
      fluid(transformations: "ar_0.74,c_fill") {
        ...CloudinaryAssetFluid
      }
    }
  }
}

I have as an error:

Error: Cannot return null for non-nullable field CloudinaryAssetFluid.aspectRatio.

File Size too large - createSchemaCustomization

Hello,

I was working on a gatsby project similar to the gatsby Netlify starter template. I installed this plugin and my site no longer builds and gives me this error.

image

I am able to build when I uninstall the plugin. I also used gatsby-plugin-extract-schema to create a json file to compare with the original template's and they are pretty similar in size. Also, my build time for the schema is .042s so I don't think anything is happening on my end unless it is my Netlify setup.

My gatsby-config file

// Load the environment variables.
require('dotenv').config({
  path: `.env.${process.env.NODE_ENV}`,
});

module.exports = {
  siteMetadata: {
    title: `Ohmni`,
    description: `Template for Ohmni Projects`,
    siteUrl: 'https://ohmni-temp.netlify.app',
    image: 'https://ohmni-temp.netlify.app/img/logo-title.svg',
    author: `@byersjacob`,
    organization: {
      name: 'Ohmni',
      url: 'https://ohmni-temp.netlify.app',
      logo: 'https://ohmni-temp.netlify.app/img/logo-title.svg',
    },
    social: {
      twitter: '@ohmnitec',
      fbAppID: '513264866034794',
    },
  },
  plugins: [
    `gatsby-plugin-react-helmet`,
    `gatsby-plugin-sass`,
    {
      // keep as first gatsby-source-filesystem plugin for gatsby image support
      resolve: 'gatsby-source-filesystem',
      options: {
        path: `${__dirname}/static/img`,
        name: 'uploads',
      },
    },
    {
      resolve: `gatsby-source-filesystem`,
      options: {
        name: `content`,
        path: `${__dirname}/content/`,
      },
    },
    {
      resolve: 'gatsby-source-filesystem',
      options: {
        path: `${__dirname}/src/pages`,
        name: 'pages',
      },
    },
    {
      resolve: "gatsby-plugin-extract-schema",
        options: {
          dest: `${__dirname}/path/to/schema.json`,
        },
    },
    {
      resolve: `gatsby-source-filesystem`,
      options: {
        name: `images`,
        path: `${__dirname}/src/images`,
      },
    },
    {
      resolve: 'gatsby-transformer-cloudinary',
      options: {
        cloudName: process.env.CLOUDINARY_CLOUD_NAME,
        apiKey: process.env.CLOUDINARY_API_KEY,
        apiSecret: process.env.CLOUDINARY_API_SECRET,
        uploadFolder: 'ohmni-test',
      },
    },
    `gatsby-plugin-sharp`,
    `gatsby-transformer-sharp`,
    {
      resolve: 'gatsby-transformer-remark',
      options: {
        plugins: [
          {
            resolve: 'gatsby-remark-relative-images',
            options: {
              name: 'uploads',
            },
          },
          {
            resolve: 'gatsby-remark-images',
            options: {
              // It's important to specify the maxWidth (in pixels) of
              // the content container as this plugin uses this as the
              // base for generating different widths of each image.
              maxWidth: 2048,
            },
          },
          {
            resolve: 'gatsby-remark-copy-linked-files',
            options: {
              destinationDir: 'static',
            },
          },
        ],
      },
    },
    {
      resolve: `gatsby-plugin-manifest`,
      options: {
        name: `gatsby-starter-default`,
        short_name: `starter`,
        start_url: `/`,
        background_color: `#fff`,
        theme_color: `#fff`,
        display: `minimal-ui`,
        icon: `src/images/logo.png`, // This path is relative to the root of the site.
      },
    },
    {
       resolve: `gatsby-plugin-typography`,
       options: {
         pathToConfigModule: `src/utils/typography`,
       },
     },
     {
       resolve: 'gatsby-plugin-netlify-cms',
       options: {
         modulePath: `${__dirname}/src/cms/cms.js`,
       },
     },
     `gatsby-plugin-offline`,
     "gatsby-plugin-netlify",
    // this (optional) plugin enables Progressive Web App + Offline functionality
    // To learn more, visit: https://gatsby.dev/offline
    // `gatsby-plugin-offline`,
  ],
  mapping: {
    'MarkdownRemark.fields.author': `MarkdownRemark`,
  },
}

My gatsby-node file

const _ = require('lodash')
const path = require('path')
const { createFilePath } = require('gatsby-source-filesystem')
const { fmImagesToRelative } = require('gatsby-remark-relative-images')

exports.createPages = ({ actions, graphql }) => {
  const { createPage } = actions

  return graphql(`
    {
      allMarkdownRemark(limit: 1000) {
        edges {
          node {
            id
            fields {
              slug
            }
            frontmatter {
              tags
              templateKey
              title
            }
          }
        }
      }
    }
  `).then(result => {
    if (result.errors) {
      result.errors.forEach(e => console.error(e.toString()))
      return Promise.reject(result.errors)
    }

    const posts = result.data.allMarkdownRemark.edges

    posts.forEach(edge => {
      const id = edge.node.id
      const title = edge.node.frontmatter.title
      createPage({
        path: edge.node.fields.slug,
        tags: edge.node.frontmatter.tags,
        component: path.resolve(
          `src/templates/${String(edge.node.frontmatter.templateKey)}.js`
        ),
        // additional data can be passed via context
        context: {
          id,
          title,
        },
      })
    })

    // Tag pages:
    let tags = []
    // Iterate through each post, putting all found tags into `tags`
    posts.forEach(edge => {
      if (_.get(edge, `node.frontmatter.tags`)) {
        tags = tags.concat(edge.node.frontmatter.tags)
      }
    })
    // Eliminate duplicate tags
    tags = _.uniq(tags)

    // Make tag pages
    tags.forEach(tag => {
      const tagPath = `/tags/${_.kebabCase(tag)}/`

      createPage({
        path: tagPath,
        component: path.resolve(`src/components/tag-section/tags.js`),
        context: {
          tag,
        },
      })
    })
  })
}

exports.onCreateNode = ({ node, actions, getNode }) => {
  const { createNodeField } = actions
  fmImagesToRelative(node) // convert image paths for gatsby images

  if (node.internal.type === `MarkdownRemark`) {
    const value = createFilePath({ node, getNode })
    createNodeField({
      name: `slug`,
      node,
      value,
    })
  }
}

//Make Author Nodes
exports.sourceNodes = ({ actions, getNodes, getNode }) => {
  const { createNodeField } = actions

  const markdownNodes = getNodes()
    .filter(node => node.internal.type === `MarkdownRemark`)
    .forEach(node => {
      if (node.frontmatter.author) {
        const authorNode = getNodes().find(
          node2 =>
            node2.internal.type === `MarkdownRemark` &&
            node2.frontmatter.title === node.frontmatter.author
        )

        if (authorNode) {
          createNodeField({
            node,
            name: `author`,
            value: authorNode.id,
          })
        }
      }
    })
}

Link to my project not including the plugin

Could the schema this plugin creates be too large? I am a newbie with this so bear with me if it is a mistake on my end.

Overall I am really excited about this plugin. Really thankful for its release ๐Ÿ™

undefined undefined error

I've problem transforming and sourcing back from cloudinary.
I've raised a ticket here. The problem is not yet solved.
Do help me out. Thanks.

image

images are getting uploaded to cloudinary in a .cache folder with gatsby-remark-images-anywhere

Hey,

I'm using gatsby-transformer-cloudinary to utilize createRemoteImageNode() in conjunction with frontmatter data saved from NetlifyCMS in markdown files, so I can use gatsby-images. I'm only using createRemoteImageNode on the images in the frontmatter portion of my markdown files, and not doing anything with the images in the body of the markdown files because I couldn't figure out a way to do that with gatsby-transformer-cloudinary.

I was using gatsby-remark-relative-images for those body images, sourcing them from a relative folder, but have since removed all image files from my repo since they are in cloudinary now. To get the gatsby-image benefits that gatsby-remark-relative-images provides, I found gatsby-remark-images-anywhere which creates the nodes needed for a gatsby-image.

However, once I added gatsby-remark-images-anywhere, I noticed a .cache folder inside of my uploadFolder that I have set in the options for gatsby-transformer-cloudinary.

I'm only uploading certain images in gatsby-node using createRemoteImageNode, so I'm wondering why it is also uploading other files automatically. I've tried changing the order of the plugins but doesn't seem to matter. Any insights into why this might be happening?

The directory structure in Cloudinary looks like:

getpackup/ /* the one set up as my uploadFolder in gatsby-transformer-cloudinary */
|--.cache/
|----caches/
|------gatsby-remark-images-anywhere/
|--------bunch of folders with uid's/
|----------image file

Minimal gatsby-config and gatsby-node files below. Thanks!

gatsby-config:

require('dotenv').config({
  path: `.env.${process.env.NODE_ENV}`,
});

module.exports = {
  flags: {
    FAST_DEV: false,
    PARALLEL_SOURCING: true,
  },
  siteMetadata: {
    ...
  },
  plugins: [
    ...
    {
      resolve: 'gatsby-source-filesystem',
      options: {
        path: `${__dirname}/src/pages`,
        name: 'pages',
      },
    },
    {
      resolve: 'gatsby-source-filesystem',
      options: {
        name: 'images',
        path: `${__dirname}/src/images`,
      },
    },
    {
      resolve: 'gatsby-source-filesystem',
      options: {
        name: 'blog',
        path: `${__dirname}/src/pages/blog`,
      },
    },
    {
      resolve: 'gatsby-transformer-cloudinary',
      options: {
        cloudName: process.env.GATSBY_CLOUDINARY_CLOUD_NAME,
        apiKey: process.env.GATSBY_CLOUDINARY_API_KEY,
        apiSecret: process.env.GATSBY_CLOUDINARY_API_SECRET,
        uploadFolder: 'getpackup',
        fluidMaxWidth: 2048,
        overwrite: false,
      },
    },
    ...
    'gatsby-transformer-sharp',
    'gatsby-plugin-sharp',
    {
      resolve: 'gatsby-transformer-remark',
      options: {
        plugins: [
          {
            resolve: 'gatsby-remark-images-anywhere',
            options: {
              staticDir: 'static',
              sharpMethod: 'fluid',
            },
          },
        ],
      },
    },
    {
      resolve: 'gatsby-plugin-netlify-cms',
      options: {
        publicPath: 'cms',
        modulePath: `${__dirname}/src/cms/cms.ts`,
      },
    }
  ],
};

gatsby-node

const path = require('path');
const { createFilePath } = require('gatsby-source-filesystem');
const { createRemoteImageNode } = require('gatsby-transformer-cloudinary');

...

exports.onCreateNode = async ({
  node,
  actions,
  getNode,
  createNodeId,
  createContentDigest,
  reporter,
}) => {
  const { createNodeField, createNode } = actions;

  const POST_NODE_TYPE = 'MarkdownRemark';

  if (node.internal.type === POST_NODE_TYPE) {
    const value = createFilePath({ node, getNode });
    createNodeField({
      name: 'slug',
      node,
      value,
    });

    if (node.frontmatter && node.frontmatter.heroImage) {
      await createRemoteImageNode({
        url: node.frontmatter.heroImage,
        parentNode: node,
        relationshipName: 'heroImage',
        createNode,
        createNodeId,
        createContentDigest,
        reporter,
      });
    }
};

Improve error logging

Could we add more detail to the error messages (during build)?
If this is something that can be done within the plugin, I'm happy to work on a PR for this.

Errors:
Request failed with status code 404

GraphQL request:8:13
7 | childImageSharp: childCloudinaryAsset {
8 | fluid {
| ^
9 | ...CloudinaryAssetFluid,Request failed with status code 404

"apiKey" is a required plugin option

I was using the plugin for a while but I've been getting a trouble since yesterday. gatsby develop is running but when I run gatsby build command, I am getting this error below.

[gatsby-transformer-cloudinary] "apiKey" is a required plugin option. You can add it to the options object for "gatsby-transformer-cloudinary" in your gatsby-config file.

Integrate with gatsby-source-cloudinary

Currently this plugin uploads local images to cloudinary.
Assets that are already in the user's Cloudinary media library isn't handled. To solve this, can act on nodes created by gatsby-source-cloudinary. This will require making sure from time to time that the selection of which nodes to act on is aligned with how gatsby-source-cloudinary names the nodes it creates.

Not able to query Cloudinary Assets

I have setup the gatsby-transformer-cloudinary plugin as per the docs.

Using the GraphQL playground (localhost:8000/__graphql) I am not able to query any of the images (and consequently, I don't see the results in my app either):

{
  file(name: {eq: "winter-jumper"}) {
    cloudinary: childCloudinaryAsset {
      fluid {
        src
      }
    }
  }
}

The above returns

{
  "data": {
    "file": null
  }
}

Even though I can confirm that an image with the public ID specified above exists, in the folder that I have added in the configuration (see below).

gatsby.config.js:

require('dotenv').config({
  path: `.env.development`,
});

module.exports = {
  plugins: [
  // other plugins ... ,
  {
    resolve: `gatsby-source-filesystem`,
    options: {
      name: `images`,
      path: `${__dirname}/src/images`,
    },
    {
      resolve: `gatsby-transformer-cloudinary`,
      options: {
        cloudName: process.env.CLOUDINARY_CLOUD_NAME,
        apiKey: process.env.CLOUDINARY_API_KEY,
        apiSecret: process.env.CLOUDINARY_API_SECRET,
        uploadFolder: `jamstack-training`,
      },
    },
  ]
};

Can't set `maxWidth` of images to be above 650px

Hi @jlengstorf and Cloudinary team!
I'm so excited to use this plugin โ€” it's something I've wanted for ages but don't have the skills to build myself, so thanks you so much!
Something I use gatsby-image for quite a lot is to lazy-load large hero images. I tried to do this and set the maxWidth argument in the query to 1920 but unfortunately the images returned max out at 650px (which is the default).
I wasn't sure how to fix or I would have submitted a PR (especially since it's Hacktober!)

Support for SVG

Is there any reason why SVGs don't get uploaded if they're in the path to upload? Cloudinary does a pretty good job optimizing them vs compressing them locally, which is why I prefer to use them from Cloudinary. However, they never get uploaded with this plugin. Is this something we can change in the config to define which asset types we'd like uploaded?

childCloudinaryAsset undefined

I'm having some issues with the default examples shown. I have no issues getting my files uploaded, and querying them using what's in GraphiQL, but when I try to use the example I see this:

image
image
image

Have there been some changes since you published this?

Cannot read property 'fluid' of null

Hi Jason,
I just discovered your package and tried out the demo example site.

After running gatsby develop I get the following error when trying to load the site:
Cannot read property 'fluid' of null

This is related to the following error during build (gatsby develop):

The GraphQL query from /Users/markus/repositories/Bitbucket/gatsby-cloudinary/src/examples/fluid-silly.js failed.

Errors:
  Request failed with status code 400

  GraphQL request:4:7
  4 |       fluid(transformations: ["e_blackwhite"], chained: ["e_vectorize:colors:2:d
    |       ^
    | especkle:20,e_tint:100:tomato:0p:white:100p", "l_beard_png,w_0.77,fl_relative,g_
Plugin:
  none
Query:
  query usersMarkusRepositoriesBitbucketGatsbyCloudinarySrcExamplesFluidSillyJs3123034595 {
    image: file(name: {eq: "marisa"}) {
      cloudinary: childCloudinaryAsset {
        fluid(transformations: ["e_blackwhite"], chained: ["e_vectorize:colors:2:despeckle:20,e_tint:100:tomato:0p:white:100p", "l_beard_png,w_0.77,fl_relative,g_face,a_-5,y_0.06"]) {
          ...CloudinaryAssetFluid
        }
      }
    }
  }

  fragment CloudinaryAssetFluid on CloudinaryAssetFluid {
    aspectRatio
    base64
    sizes
    src
    srcSet
  }

Each build creates many new transformations on already uploaded images

We have a library of about 11,000 images that are being added in gatsby-node using exports.sourceNodes
each image then gets added with createRemoteFileNode

This successfully uploads everything to cloudinary. The issue we're having is that it does this on every build and is burning through a lot of transformations each time. All our images are now uploaded, so its simply going through existing images each time and is doing new transformations.

I've tried setting createDerived to false, in the last build it created 43,300 transformations on 11226 images.

How do we prevent Cloudinary doing new transformations on images it already has?

(I also posted this in a closed issue that I'm unable to reopen - sorry for the multiple posts)

Combine gatsby-source-wordpress-experimental and gatsby-transformer-cloudinary

Hi, I'm tryning to improve gatsby-source-wordpress-experimental making him retrieve data from CDN instead of from local static. Unfortunately all the markup of the single pages is contained in a MySQL DB and paginated through a dangerouslySetInnerHTML component in React js.

At the moment I'm setting up the createRemoteImageNode function inside the gatsby-node.js file, but I'm having problems pairing it with the already written code.

Am I missing something? Maybe setting up the plug-in? And if not, some clue on how can I set up gatsby-transformer-cloudinary in order to catch the images and process them?

gatsby-node.zip

db_content

dangerouslySetInnerHTML

Yarn Install

I have created yarn workspaces from scratch, but I am having trouble with this one. I cloned your repo & I created a Cloudinary account and input my settings in the .env file & I ran yarn install from the root, which I thought would install all dependencies and and got the following....

$ yarn workspaces info
yarn workspaces v1.17.3
{
"gatsby-transformer-cloudinary": {
"location": "packages/gatsby-transformer-cloudinary",
"workspaceDependencies": [],
"mismatchedWorkspaceDependencies": []
},
"site": {
"location": "site",
"workspaceDependencies": [],
"mismatchedWorkspaceDependencies": [
"gatsby-transformer-cloudinary"
]
}
}
Done in 0.06s.

Environment

System:
OS: Windows 10
CPU: (8) x64 Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz
Binaries:
Yarn: 1.17.3 - C:\Program Files (x86)\Yarn\bin\yarn.CMD
npm: 6.8.0 - C:\Program Files\nodejs\npm.CMD
Browsers:
Chrome

I appreciate your work on this, it looks like the future!

Source and Transform Nodes (undefined undefined)

I am trying to use this transformer, however I have run into this issue:

success initialize cache - 0.020s
success copy gatsby files - 0.046s
success onPreBootstrap - 0.005s

 ERROR 

undefined undefined
  Error: 
not finished source and transform nodes - 61.578s

This is how my gatsby-config looks like:

require('dotenv').config({
  path: `.env.development`,
});

module.exports = {
  siteMetadata: {
    title: `ChristMart`,
    description: `ChristMart - Your Favourite Online Christmas Store`,
    author: `Tamas Piros`,
    company: `Full Stack Training Ltd`,
    companyWebsite: `https://fullstacktraining.com`
  },
  plugins: [
    `gatsby-plugin-react-helmet`,
    `gatsby-transformer-remark`,
    {
      resolve: `gatsby-source-filesystem`,
      options: {
        name: `content`,
        path: `${__dirname}/src/content`,
      },
    },
    {
      resolve: `gatsby-plugin-layout`,
      options: {
        component: require.resolve(`./src/components/layout`),
      },
    },
    {
      resolve: `gatsby-source-filesystem`,
      options: {
        name: `images`,
        path: `${__dirname}/src/images`,
      },
    },
    {
      resolve: 'gatsby-transformer-cloudinary',
      options: {
        cloudName: process.env.CLOUDINARY_CLOUD_NAME,
        apiKey: process.env.CLOUDINARY_API_KEY,
        apiSecret: process.env.CLOUDINARY_API_SECRET,
        uploadFolder: 'gatsby-cloudinary',
      },
    },
    `gatsby-plugin-postcss`,
    {
      resolve: 'gatsby-plugin-purgecss',
      options: {
        tailwind: true,
        purgeOnly: ['src/css/style.css', 'src/css/global.css'],
      },
    },
  ],
}

I can also confirm that I have the right cloudname, apikey and secret setup.

Any suggestions why this error is happening?

CloudinaryAsset for a list of remote images

Hello,
When trying to use images that already exist on Cloudinary, It seems that the plugin does not recognize a list of images with the structure defined on the documentation, here is an example:

{
  "title": "Foo",
  "images": [
    {
      "cloudinaryAssetData": true,
      "cloudName": "bar",
      "publicId": "bar/whatever-1",
      "originalHeight": 969,
      "originalWidth": 546
    },
    {
      "cloudinaryAssetData": true,
      "cloudName": "bar",
      "publicId": "bar/whatever-2",
      "originalHeight": 969,
      "originalWidth": 546
    }
  ]
}

But if there is only one image, it works as expected :

{
   ...,
  "image": {
      "cloudinaryAssetData": true,
      "cloudName": "bar",
      "publicId": "bar/whatever-1",
      "originalHeight": 969,
      "originalWidth": 546
  }
}

I can't even query for cloudName, publicId, etc.
A possible solution for this?

Using `cloudinaryAssetData` via frontmatter

This is more a question, than a bug report probably. I was wondering if it's possible to use frontmatter data as opposed to a json object to describe the cloudinaryAssetData?

I tried to following but it's not working:

post.md

---
date: "2021-02-21"
title: "titlel"
intro: "Details of the trip to nowhere"
author: "Linda Watkins"
coverPhoto:
  cloudinaryAssetData: true,
  cloudName: "<>"
  publicId: "pID"
---

blog entry ....

Turn Off Uploading During Development?

Is it possible to turn off the uploading of the thousands of files I have during development? This takes several minutes for images that are already on my cloudinary even with overwriteExisting set to false. Is there a reason why this isn't already in place? I think it would be nice to toggle that off.

Add upload options like create_derived=true/false

Should let the user define options in gatsby-config.js that will affect uploading.
for example: create_derived=false to cloudinary.v2.uploader.upload() function, will make sure that the plugin does not create tens of transformations for each image.

How & Where to create Nodes so that coverPhoto is transformed into the CloudinaryAsset Type?

Trying to figure out how to create nodes for assets that are already on cloudinary? So far, I have tried to create these nodes in gatsby-node.js like so:

exports.sourceNodes = ({
  actions: { createNode },
  createNodeId,
  createContentDigest,
}) => {
  return avengers.map((avenger) =>
    createNode({
      ...avenger,
      id: createNodeId(avenger.name),
      internal: {
        type: `Avenger`,
        contentDigest: createContentDigest(avenger),
      },
      title: 'Some Title,
      publishedAt: '2020-11-12',
      coverPhoto: { //just some static data in here for now for testing purposes
        cloudinaryAssetData: true,
        cloudName: 'mycloudname',
        publicId: 'myfolder/someimage.png',
        originalHeight: 2048,
        originalWidth: 2048,
      },
    })
  )
}

In the docs it says:

The coverPhoto property in the node above will be deleted and replaced by gatsby-transformer-cloudinary with a CloudinaryAsset node that can be used with gatsby-image

However, in graphql it still shows me coverPhoto and all its properties. and does not replace it with CloudinaryAsset, which I would've expected. Is the order in which the gatsby-node file run before the transformer plugin maybe?

How can I create the image nodes in a way so that gatsby-transformer-cloudinary can do its magic?

maxHeight Support?

It's possible to support also the maxHeight as gatsby-plugin-sharp? thanks

Question on uploading to cloudinary

I'm wondering what the advantage of uploading local images to cloudinary is. One could upload images directly to a folder on cloudinary and then they would not be needed in the project repo.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.