Gatsby: Add responsiveness support for images uploaded through Netlify CMS

Created on 22 Nov 2017  Â·  14Comments  Â·  Source: gatsbyjs/gatsby

Currently, the recommended way to upload images to a static website through Netlify CMS is by using the static folder, which does not offer any support for responsiveness. I would like to ask for a way to make CMS-managed assets queryable through GraphQL.

Most helpful comment

Thank you for your kind assistance! Although the createNodeField method didn't work as expected, I ended up with the following code, based on yours:

exports.onCreateNode = ({
  node, getNode, getNodes, boundActionCreators,
}) => {
  const { createNodeField, createParentChildLink } = boundActionCreators;

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

    // Attach thumbnail's ImageSharp node by public path if necessary
    if (typeof node.frontmatter.thumbnail === 'string') {
      // Find absolute path of linked path
      const pathToFile = path
        .join(__dirname, 'static', node.frontmatter.thumbnail)
        .split(path.sep)
        .join('/');

      // Find ID of File node
      const fileNode = getNodes().find(n => n.absolutePath === pathToFile);

      if (fileNode != null) {
        // Find ImageSharp node corresponding to the File node
        const imageSharpNodeId = fileNode.children.find(n => n.endsWith('>> ImageSharp'));
        const imageSharpNode = getNodes().find(n => n.id === imageSharpNodeId);

        // Add ImageSharp node as child
        createParentChildLink({ parent: node, child: imageSharpNode });
      }
    }
  }
};

It would be great if there was a more in-depth documentation about linking nodes (or even their properties) together.

All 14 comments

You could setup gatsby-source-filesystem to read files from the static folder.

I think that gatsby-source-filesystem wouldn't help much here. Basically, I'm trying to read a thumbnail attribute which points to an image like /images/uploads/test.png as an absolute URL (so, the aforementioned file is physically stored at static/images/uploads/test.png). The thumbnail attribute gets read as a string instead of being transformed into an image object.

@KyleAMathews How can I transform a String node into an ImageSharp node? I just set up gatsby-source-filesystem to read files from the static folder, but need to access those images' nodes by a public path.

Basically, I have a string property called thumbnail in some of my markdown files' frontmatter, and I want to transform them into ImageSharp nodes:

E.g. from /assets/uploads/conference.jpg into an ImageSharp node with the following absolute path: C:/Development/Projects/mvk-web/static/assets/uploads/conference.jpg (where C:/Development/Projects/mvk-web is my Gatsby project root)

Use onCreateNode to create a link to the File node — can give you a code sample if that's not enough a hint.

It would be great if you could provide me a code sample. Thank you in advance!

// In your gatsby-node.js
// Not tested
exports.onCreateNode = ({ node, getNode, getNodes, boundActionCreators }) => {
  const { createNode, createNodeField } = boundActionCreators
  if (node.internal.type === `MarkdownRemark`) {
    // Create link
    // Find absolute path of linked path
    const pathToFile = path.resolve(getNode(node.parent).absolutePath, node.frontmatter.thumbnail)
    // Find ID of File node
    const fileNode = getNodes().find(n => n.absolutePath === pathToFile)
    createNodeField({
      node,
      name: `imageLink___NODE`,
      value: fileNode.id,
    })
  }
  // Transform the new node here and create a new node or
  // create a new node field.
}

Thank you for your kind assistance! Although the createNodeField method didn't work as expected, I ended up with the following code, based on yours:

exports.onCreateNode = ({
  node, getNode, getNodes, boundActionCreators,
}) => {
  const { createNodeField, createParentChildLink } = boundActionCreators;

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

    // Attach thumbnail's ImageSharp node by public path if necessary
    if (typeof node.frontmatter.thumbnail === 'string') {
      // Find absolute path of linked path
      const pathToFile = path
        .join(__dirname, 'static', node.frontmatter.thumbnail)
        .split(path.sep)
        .join('/');

      // Find ID of File node
      const fileNode = getNodes().find(n => n.absolutePath === pathToFile);

      if (fileNode != null) {
        // Find ImageSharp node corresponding to the File node
        const imageSharpNodeId = fileNode.children.find(n => n.endsWith('>> ImageSharp'));
        const imageSharpNode = getNodes().find(n => n.id === imageSharpNodeId);

        // Add ImageSharp node as child
        createParentChildLink({ parent: node, child: imageSharpNode });
      }
    }
  }
};

It would be great if there was a more in-depth documentation about linking nodes (or even their properties) together.

@kripod Do you have any example of this working that I could clone and test with? I'm trying the same thing but not having much luck.

@martynhoyer Yeah, it can be found here along with a working website: https://github.com/simonyiszk/mvk-web/blob/master/gatsby-node.js

Thanks @kripod! Much appreciated. Unfortunately I'm still stuck... it seems the getNodes() call doesn't have any of the images in it so const fileNode = getNodes().find(n => n.absolutePath === pathToFile); always returns undefined. The images show in allImageSharp and allFile in GraphiQL so they seem to be getting processed correctly.

Any quick suggestions, or shall I open a new issue?

Netlify Image Solution

To allow using gatsby image processing plugins on your frontmatter

In each Markdown file

relpath: ../../..  
logo: /static/images/myimage.png

In gatsby-config.js

Under plugins add the code to access the static image folder as files

{
      resolve: 'gatsby-source-filesystem',
      options: {
        name: 'static/images',
        path: `${__dirname}/static/images`,
      },
    },

In gatsby-node.js

Create a new nodeField for each image needed

exports.onCreateNode = ({ node, getNode, actions }) => {
  const { createNodeField } = actions;

if (node.internal.type === 'MarkdownRemark') {

if (node.frontmatter.relpath && node.frontmatter.logo ) {

      const logopath = node.frontmatter.relpath + node.frontmatter.logo

      createNodeField({
        node,
        name: 'logolink',
        value: logopath
      });
    }

}

}

In config.yml

Add media folder

media_folder: "static/images" 

In each collection in config.yml

State relative path for each collection that require an image in the frontmatter as a hidden field that user doesn't need to modify

- {label: "Relative Path", name: "relpath", widget: "hidden", default: "../../.."}

Query in Graphql

{
  allMarkdownRemark {
    edges {
      node {
        id
        frontmatter {
          title
        }
        fields {
          logolink {
            childImageSharp {
              id
            }
          }
        }
      }
    }
  }
}

Thank you for the tip, @waywardm!

I just came across an article about a similar situation:
https://blog.alexluong.com/generate-gatsby-image-sharp-from-an-image-url/

exports.onCreateNode = ({ node, getNode, actions }) => {
const { createNodeField } = actions;

if (node.internal.type === 'MarkdownRemark') {

if (node.frontmatter.relpath && node.frontmatter.logo ) {

  const logopath = node.frontmatter.relpath + node.frontmatter.logo

  createNodeField({
    node,
    name: 'logolink',
    value: logopath
  });
}

}

}

@waywardm What if my frontmatter has images defined in different places? like node.frontmatter.intro.image and node.frontmatter.product.image. Is there a function that can deal with all of these cases?

Was this page helpful?
0 / 5 - 0 ratings

Related issues

Oppenheimer1 picture Oppenheimer1  Â·  3Comments

KyleAMathews picture KyleAMathews  Â·  3Comments

ghost picture ghost  Â·  3Comments

totsteps picture totsteps  Â·  3Comments

kalinchernev picture kalinchernev  Â·  3Comments