Some tips are also accompanied by CodeSandbox (opens in a new tab) examples.
Gives you the date for when you last used gatsby build. In the case of e.g. Netlify that would be the last time you deployed your site (hence buildTime). Please use this query sparingly (e.g. not in your footer component that you share with every page) as otherwise on every build the queries would be invalidated (since the time changed) and you’d unnecessarily rebuild all pages.
CodeSandbox (opens in a new tab)
import * as React from "react"import { graphql } from "gatsby"
const IndexPage = ({ data }) => { return ( <main> <p>This site was last built on:</p> <p>{data.site.buildTime}</p> </main> )}
export default IndexPage
export const query = graphql` query { site { buildTime(formatString: "DD/MM/YYYY") } }`For open source docs it’s good to know when a document was last modified. You can get that information via the parent if you use local files like Markdown, MDX, YAML etc. Use the ___graphql endpoint to explore that information on your own project.
CodeSandbox (opens in a new tab)
query { allMdx { nodes { parent { ... on File { modifiedTime(formatString: "MM/DD/YYYY") } } } }}When you define two (or more) gatsby-source-filesystem entries in your config you can filter your GraphQL queries to only get the result of one source.
CodeSandbox (opens in a new tab)
module.exports = { plugins: [ { resolve: "gatsby-source-filesystem", options: { name: "assets", path: `${__dirname}/src/assets`, }, }, { resolve: "gatsby-source-filesystem", options: { name: "logos", path: `${__dirname}/src/logos`, }, }, "gatsby-transformer-sharp", "gatsby-plugin-sharp", ],}Now place one image file in the src/logos folder and two or more image files in the src/assets folder. This should show the difference between the file and allFile query (of course you can put any number of files into one folder). You can address both folders individually, as shown in the following example:
import * as React from "react"import { graphql } from "gatsby"import { GatsbyImage, getImage } from "gatsby-plugin-image"
const IndexPage = ({ data }) => { return ( <main> <p>First image (logo):</p> <GatsbyImage image={getImage(data.logo)} /> <p>Assets images (two):</p> <div style={{ display: "flex", flexWrap: "wrap" }}> {data.assets.nodes.map((img) => ( <GatsbyImage image={getImage(img.childImageSharp)} /> ))} </div> </main> )}
export default IndexPage
export const query = graphql` query { logo: file(sourceInstanceName: { eq: "logos" }) { childImageSharp { gatsbyImageData(width: 200, quality: 100) } } assets: allFile(filter: { sourceInstanceName: { eq: "assets" } }) { nodes { childImageSharp { gatsbyImageData(width: 200, quality: 100) } } } }`You can not only use async/await in gatsby-node.js but also use Gatsby’s reporter API. Use this to throw errors. You should use panicOnBuild to only stop the process on gatsby build (so that you can debug it with GraphiQL).
const yourTemplate = require.resolve("./src/templates/yourTemplate.js")
exports.createPages = async ({ graphql, actions, reporter }) => { const { createPage } = actions
const result = await graphql(` { ...your GraphQL query } `)
if (result.errors) { reporter.panicOnBuild("Error while running GraphQL query.") return }
result.data.yourNode.nodes.forEach((node) => { // createPage function })}Most of the time you want to show a previous/next post under your blog post to keep the visitor reading. For that you can use pageContext.
CodeSandbox (opens in a new tab)
const bookTemplate = require.resolve("./src/templates/book.js")
exports.createPages = async ({ graphql, actions, reporter }) => { const { createPage } = actions
const result = await graphql( graphql(` { allBooksYaml(sort: { fields: [title], order: ASC }) { nodes { slug title } } } `) )
if (result.errors) { reporter.panicOnBuild("Error while running GraphQL query.") return }
const books = result.data.allBooksYaml.nodes
books.forEach((node, index) => { // Set the prev/next variable for every node so // that you can directly access slug & title
const prev = index === 0 ? null : books[index - 1] const next = index === books.length - 1 ? null : books[index + 1]
createPage({ path: node.slug, component: bookTemplate, context: { slug: node.slug, prev, next, }, }) })}import * as React from "react"import { graphql, Link } from "gatsby"
import Layout from "../components/layout"
const BookTemplate = ({ data: { booksYaml }, pageContext: { prev, next } }) => { return ( <Layout> <h2>{booksYaml.title}</h2> <div> {prev && ( <div> <span>Previous</span> <Link to={prev.slug}>{prev.title}</Link> </div> )} {next && ( <div> <span>Next</span> <Link to={next.slug}>{next.title}</Link> </div> )} </div> </Layout> )}
export default BookTemplate
export const pageQuery = graphql` query BookBySlug($slug: String!) { booksYaml(slug: { eq: $slug }) { title content } }`In contrast to the previous tip you can also show two (or more) random posts by changing gatsby-node.js.
CodeSandbox (opens in a new tab)
const _ = require("lodash")
const prevNext = (list, item) => { // Create a random selection of other posts (excluding the current post) const filterUnique = _.filter(list, (input) => input.slug !== item.slug) const sample = _.sampleSize(filterUnique, 2)
return { prev: sample[0], next: sample[1], }}
const bookTemplate = require.resolve("./src/templates/book.js")
exports.createPages = async ({ graphql, actions, reporter }) => { const { createPage } = actions
const result = await graphql( graphql(` { allBooksYaml(sort: { fields: [title], order: ASC }) { nodes { slug title } } } `) )
if (result.errors) { reporter.panicOnBuild("Error while running GraphQL query.") return }
const books = result.data.allBooksYaml.nodes
books.forEach((node) => { const { prev, next } = prevNext(books, node)
createPage({ path: node.slug, component: bookTemplate, context: { slug: node.slug, prev, next, }, }) })}If your images are hosted on a CDN and you want to use gatsby-plugin-image, you can download them using the createRemoteFileNode helper. Then add the image to the respective node.
This example assumes that you have Gatsby set up with Markdown and want to use the following frontmatter:
---title: My first blog post!featuredImgUrl: https://images.unsplash.com/photo-1560237731-890b122a9b6cfeaturedImgAlt: Mountains with a starry sky---const { createRemoteFileNode } = require("gatsby-source-filesystem")
exports.createSchemaCustomization = ({ actions }) => { const { createTypes } = actions createTypes(` type MarkdownRemark implements Node { frontmatter: Frontmatter featuredImg: File @link(from: "fields.localFile") } type Frontmatter { title: String! featuredImgUrl: String featuredImgAlt: String } `)}
exports.onCreateNode = async ({ node, actions: { createNode, createNodeField }, store, cache, createNodeId,}) => { // For all MarkdownRemark nodes that have a featured image url, call createRemoteFileNode if ( node.internal.type === "MarkdownRemark" && node.frontmatter.featuredImgUrl !== null ) { const 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 you are going to create 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, extend the node with "localFile" if (fileNode) { createNodeField({ node, name: "localFile", value: fileNode.id }) } }}Don’t know exactly why some of your pages load slowly? No problem, you can use gatsby-plugin-webpack-bundle-analyser-v2 (opens in a new tab) to find the culprits.
After installation and setup you’ll see a visual representation of all your bundles.
npm install gatsby-plugin-webpack-bundle-analyser-v2 -DAnd in your gatsby-config.js:
module.exports = { plugins: ["gatsby-plugin-webpack-bundle-analyser-v2"],}Once you run a gatsby build at the end of a build (locally) the browser will open with the bundle analyser.
More content: