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

docs: preprocessing external images page #17497

Merged
merged 23 commits into from
Oct 17, 2019
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
56437da
Initial work on preprocessing external images page
lannonbr Sep 9, 2019
1bf0b81
Applying Lennart's suggestions from code review
lannonbr Sep 15, 2019
f3ded70
Finishing up initial draft of post & adding images
lannonbr Sep 15, 2019
4fbdd71
Apply suggestions from Muescha code review
lannonbr Sep 16, 2019
5206d66
Removing 2nd "That said" in intro paragraphs
lannonbr Sep 16, 2019
6da663c
Apply suggestions from code review
lannonbr Sep 16, 2019
b3c750c
Update docs/docs/preprocessing-external-images.md
lannonbr Sep 16, 2019
ba53010
Update docs/docs/preprocessing-external-images.md
lannonbr Sep 16, 2019
970b797
Update preprocessing-external-images.md
lannonbr Sep 16, 2019
aa08e47
Updating with changes suggested by Muescha and Lennart
lannonbr Sep 16, 2019
0b43c9f
adding punctuation
lannonbr Sep 16, 2019
df9b0a3
Apply suggestions from code review
lannonbr Sep 16, 2019
3b94362
Update docs/docs/preprocessing-external-images.md
lannonbr Sep 16, 2019
7858b23
Apply suggestions from code review
lannonbr Sep 16, 2019
32cb4ac
Adding alt text for featured image through guide
lannonbr Sep 16, 2019
8fcb3b3
Update docs/docs/preprocessing-external-images.md
lannonbr Sep 17, 2019
918c7e2
Apply suggestions from code review
lannonbr Oct 6, 2019
352851f
Adding paragraph for mentioning Schema Customization API before code …
lannonbr Oct 6, 2019
0b41a5e
Add note that new node is not part of frontmatter
lannonbr Oct 6, 2019
c0d71ca
Apply suggestions from code review
lannonbr Oct 9, 2019
487091e
Merge remote-tracking branch 'origin/master' into docs/preprocessing-…
Oct 11, 2019
c54c76e
revert svg changes
wardpeet Oct 14, 2019
02a4e58
chore: remove svg changes
wardpeet Oct 14, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added docs/docs/images/remote-file-node-blogpost.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
176 changes: 176 additions & 0 deletions docs/docs/preprocessing-external-images.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
---
title: Preprocessing External Images
---

Gatsby allows powerful image processing features using the [`Sharp`](https://github.com/lovell/sharp/) library to automatically process images to be performant, with features like lazy-loading. That said, this only works if the image is a `File` node in the GraphQL layer.

If you want the same functionality for files that are remotely hosted online and not located in your Git repo, [`gatsby-source-filesystem`](/packages/gatsby-source-filesystem/) has an API called `createRemoteFileNode` to solve this.

This guide will show you how to use the `createRemoteFileNode` process and get the same benefits of gatsby-transformer-sharp with externally sourced images.

## Setup

A use case that this technique can support is if you want to create a featured image in a blog post with an image sourced from a URL out on the web, instead of a local file. This could be hosted somewhere like Imgur, S3, or anywhere on the internet.

Given a sample post:

```markdown
---
title: My first blogpost!
featuredImgUrl: https://images.unsplash.com/photo-1560237731-890b122a9b6c
featuredImgAlt: Mountains with a starry sky
---

Hello World
```

You can use a custom Frontmatter field for the URL of the featured image you want to pull down and use as part of the site.

By default, this is a string value as you haven't told Gatsby yet how to interpret it. However, you can add some code into `gatsby-node.js` to modify it.

## Gatsby Node

In your `gatsby-node.js` file, you can do some processing to create file nodes for the custom `featuredImgUrl` Frontmatter field.
marcysutton marked this conversation as resolved.
Show resolved Hide resolved

```js:title=gatsby-node.js
const { createRemoteFileNode } = require("gatsby-source-filesystem")

exports.createSchemaCustomization = ({ actions }) => {
const { createTypes } = actions

createTypes(`
type MarkdownRemark implements Node {
frontmatter: Frontmatter
}

type Frontmatter {
title: String!
featuredImgUrl: String
featuredImgAlt: String
}
`)
}

exports.onCreateNode = async ({
node,
actions: { createNode },
store,
cache,
createNodeId,
}) => {
// For all MarkdownRemark nodes that have a featured image url, call createRemoteFileNode
if (
node.internal.type === "MarkdownRemark" &&
node.frontmatter.featuredImgUrl !== null
) {
let fileNode = await createRemoteFileNode({
url: node.frontmatter.featuredImgUrl, // string that points to the URL of the image
parentNodeId: node.id, // id of the parent node of the fileNode we are going to create
lannonbr marked this conversation as resolved.
Show resolved Hide resolved
createNode, // helper function in gatsby-node to generate the node
createNodeId, // helper function in gatsby-node to generate the node id
cache, // Gatsby's cache
store, // Gatsby's redux store
})

// if the file was created, attach the new node to the parent node
if (fileNode) {
node.featuredImg___NODE = fileNode.id
}
}
}
```

Going step by step through the code:

1. Define some types for `MarkdownRemark` using the [Schema Customization API](/docs/schema-customization/) so if `featuredImgUrl` is not in a Markdown file, it will return `null`. As well, defining a field for alternative text, in this case `featuredImgAlt`, can improve accessibility as well as give context to the image even if it fails to load.
lannonbr marked this conversation as resolved.
Show resolved Hide resolved
2. Create an `onCreateNode` function so you can watch for when `MarkdownRemark` nodes are made.
3. Use `createRemoteFileNode` by passing in the various required fields and get a reference to the file afterwards.
4. If the Node is created, attach it as a child of the original Node. `___NODE` tells the GraphQL layer that the name before it is going to be a field on the parent Node that links to another Node. To do this, pass the `id` as the reference.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should add a note here about how the image is no longer part of the frontmatter, as I could see that tripping people up.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done!


And since it is a File Node, `gatsby-transformer-sharp` will pick it up and create a `childImageSharp` child Node inside this newly created Node.

## Usage in templates

Now that the images are being generated and available in GraphQL, you can use them in action.

If you open GraphiQL and write a query on the Markdown Nodes, you can see a new Node attached to any `MarkdownRemark` Node that had a featured image:

```graphql
query {
allMarkdownRemark {
nodes {
featuredImg {
childImageSharp {
# ...
}
}
}
}
}
```

![Screenshot of GraphiQL with above query inserted](images/remote-file-node-graphiql-preview.png)

You can then use `gatsby-transformer-sharp` to fill in the query for a fixed image here.
lannonbr marked this conversation as resolved.
Show resolved Hide resolved

```graphql
query {
allMarkdownRemark {
nodes {
featuredImg {
childImageSharp {
fixed(width: 600) {
...GatsbyImageSharpFixed
}
}
}
}
}
}
```

And finally, you can update the template for this blog post to include this image. This template is based on the one in the [Programmatically create pages from data](/tutorial/part-seven/) section of the Gatsby Tutorial.
lannonbr marked this conversation as resolved.
Show resolved Hide resolved

```jsx
import React from "react"
import Img from "gatsby-image"
import { graphql } from "gatsby"

const template = ({ data }) => {
return (
<>
<h1>{data.markdownRemark.frontmatter.title}</h1>
<Img
fixed={data.markdownRemark.featuredImg.childImageSharp.fixed}
alt={data.markdownRemark.frontmatter.featuredImgAlt}
/>
<div dangerouslySetInnerHTML={{ __html: data.markdownRemark.html }} />
</>
)
}

export default template

export const query = graphql`
query BlogPostQuery($slug: String) {
markdownRemark(fields: { slug: { eq: $slug } }) {
frontmatter {
title
featuredImgAlt
}
html
featuredImg {
childImageSharp {
fixed(width: 600) {
...GatsbyImageSharpFixed
}
}
}
}
}
`
```

And if you run `gatsby develop`, you'll see the remote file locally now:

![Screenshot of rendered blopost with featured image](images/remote-file-node-blogpost.png)
2 changes: 2 additions & 0 deletions www/src/data/sidebars/doc-links.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,8 @@
- title: Working with Images in Markdown
link: /docs/working-with-images-in-markdown/
breadcrumbTitle: Images in Markdown
- title: Preprocessing External Images
link: /docs/preprocessing-external-images/
- title: Sourcing Content and Data
link: /docs/content-and-data/
items:
Expand Down