Categories
Gatsby.js

Gatsby.js — Creating Pages from Data Programmatically

Gatsby is a static web site framework that’s based on React.

We can use it to create static websites from external data sources and more.

In this article, we’ll look at how to create a site with Gatsby.

Creating Pages from Data Programmatically

We can create pages from data programmatically with Gatsby.

For example, we can write:

gatsby-config.js

module.exports = {
  plugins: [
    `gatsby-transformer-remark`,
    {
      resolve: `gatsby-source-filesystem`,
      options: {
        name: `content`,
        path: `${__dirname}/src/content`,
      },
    },
  ],
  siteMetadata: {
    title: "My Homepage",
    description: "This is where I write my thoughts.",
  },
}

src/content/post.md

---
title: My First Post
date: 2019-07-10
path: /my-first-post
---
This is my first Gatsby post written in Markdown!

gatsby-node.js

const { createFilePath } = require(`gatsby-source-filesystem`)

exports.onCreateNode = ({ node, getNode, actions }) => {
  const { createNodeField } = actions
  if (node.internal.type === `MarkdownRemark`) {
    const slug = createFilePath({ node, getNode, basePath: `pages` })
    createNodeField({
      node,
      name: `slug`,
      value: slug,
    })
  }
}

exports.createPages = async function ({ actions, graphql }) {
  const { data } = await graphql(`
    query {
      allMarkdownRemark {
        edges {
          node {
            fields {
              slug
            }
          }
        }
      }
    }
  `)
  data.allMarkdownRemark.edges.forEach(edge => {
    const slug = edge.node.fields.slug
    actions.createPage({
      path: slug,
      component: require.resolve(`./src/templates/post.js`),
      context: { slug },
    })
  })
}

src/templates/post.js

import React from "react"
import { graphql } from "gatsby"

export default function BlogPost({ data }) {
  const post = data.markdownRemark
  return (
    <div>
      <h1>{post.frontmatter.title}</h1>
      <div dangerouslySetInnerHTML={{ __html: post.html }} />
    </div>
  )
}
export const query = graphql`
  query($slug: String!) {
    markdownRemark(fields: { slug: { eq: $slug } }) {
      html
      frontmatter {
        title
      }
    }
  }
`

First, we add the gatsby-transformer-remark and gatsby-source-filesystem plugins to read Markdown files and parse them to HTML.

We create the slug field with the createNode function.

We call createNodeField to create our slug.

With the if statement in onCreateNode , we only add the slug field if we query for MarkdownRemark entries.

Then in the createPages function, we make the query for the slug and then loop through each entry with forEach .

In the forEach callback, we call actions.createPage to add the pages from the entries returned.

path is set to the slug ,

component is set to the template file location.

context has the data we want to display in the template.

In post.js , we make the query for the post with the given slug.

Then we get the data from the data prop and render it in our JSX.

Now when we go to http://localhost:8000/post, we see:

My First Post

This is my first Gatsby post written in Markdown!

displayed.

Conclusion

We can create pages from data programmatically with Gatsby.

This way, we can create our pages from Markdown files and render them.

Categories
Gatsby.js

Gatsby.js — More GraphQL Queries

Gatsby is a static web site framework that’s based on React.

We can use it to create static websites from external data sources and more.

In this article, we’ll look at how to create a site with Gatsby.

Querying Data in Pages with GraphQL

We can query data in pages with GraphQL with Gatsby.

To do this, we write:

gatsby-config.js

module.exports = {
  siteMetadata: {
    title: "My Homepage",
    description: "This is where I write my thoughts.",
  },
}

src/pages/index.js

import React from "react"
import { graphql } from 'gatsby'

export const query = graphql`
  query HomePageQuery {
    site {
      siteMetadata {
        description
      }
    }
  }
`
export default function Home({ data }) {
  return (
    <div>
      Hello!
      {data.site.siteMetadata.description}
    </div>
  )
}

We have the website’s metadata in gatsby-config.js .

Then we can get the data in our page by using a GraphQL query.

We create the query with the graphql tag in index.js .

We use it to get the description of our site.

Then we can get the description in data prop with the data.site.siteMetadata.description property.

Now we see:

Hello!This is where I write my thoughts.

displayed.

Add Query Variables to a Page Query

We can add query variables to make our page query more flexible.

For example, we can write:

src/templates/post.js

import React from "react"
import { graphql } from "gatsby"
export default function Template({ data }) {
  const { markdownRemark } = data
  const { frontmatter, html } = markdownRemark
  return (
    <div className="blog-post">
      <h1>{frontmatter.title}</h1>
      <h2>{frontmatter.date}</h2>
      <div
        className="blog-post-content"
        dangerouslySetInnerHTML={{ __html: html }}
      />
    </div>
  )
}
export const pageQuery = graphql`
  query($path: String!) {
    markdownRemark(frontmatter: { path: { eq: $path } }) {
      html
      frontmatter {
        date(formatString: "MMMM DD, YYYY")
        path
        title
      }
    }
  }
`

We add a query that takes the $path parameter.

And we specified that it’s a string.

Then we pass that into our markdownRemark query to search for posts with the given path.

Then in the Template component, we get the query result from the data prop,

frontmatter has the front matter, which is a post’s metadata.

And html has the HTML content.

StaticQuery

Another way to query for data on our website is with the StaticQuery component.

To use it, we write:

import React from "react"
import { graphql, StaticQuery } from 'gatsby'

export default function Home() {
  return (
    <div>
      <StaticQuery
        query={graphql`
          query HeadingQuery {
            site {
              siteMetadata {
                title
              }
            }
          }
      `}
        render={data => (
          <header>
            <h1>{data.site.siteMetadata.title}</h1>
          </header>
        )}
      />
    </div>
  )
}

We use the StaticQuery component with the query prop.

It has the GraphQL query we want to make as the value.

Then in the render prop, we can pass in a function to render the query result.

The data prop has the query result.

We query the same metadata from the gatsby-config.js .

Conclusion

Gatsby provides us with several ways to make queries to get data.

Categories
Gatsby.js

Gatsby.js — Conditional Queries and Create Pages

Gatsby is a static web site framework that’s based on React.

We can use it to create static websites from external data sources and more.

In this article, we’ll look at how to create a site with Gatsby.

Conditionals

We can add conditional operations with our GraphQL queries.

For example, we can with:

query GetBlogPosts($withDate: Boolean = false) {
  allMarkdownRemark(limit: 3, skip: 1) {
    edges {
      node {
        frontmatter {
          title
          date @include(if: $withDate)
        }
      }
    }
  }
}

We use the $withDate boolean value in our if operator.

Creating and Modifying Pages

We can use GraphQL queries to create pages in the gatsby-node.js file.

For example, we can write:

gatsby-node.js

exports.createPages = async ({ graphql, actions, reporter }) => {
  const { createPage } = actions
  const result = await graphql(
    `
      {
        allMarkdownRemark(limit: 1000) {
          edges {
            node {
              frontmatter {
                path
              }
            }
          }
        }
      }
    `
  )
  if (result.errors) {
    reporter.panicOnBuild(`Error while running GraphQL query.`)
    return
  }

  const blogPostTemplate = path.resolve(`src/templates/post.js`)
  result.data.allMarkdownRemark.edges.forEach(({ node }) => {
    const path = node.frontmatter.path
    createPage({
      path,
      component: blogPostTemplate,
      context: {
        pagePath: path,
      },
    })
  })
}

gatsby-config.js

module.exports = {
  plugins: [
    `gatsby-transformer-remark`,
    {
      resolve: `gatsby-source-filesystem`,
      options: {
        name: `content`,
        path: `${__dirname}/src/content`,
      },
    },
  ]
}

src/templates/post.js

import React from "react"
import { graphql } from "gatsby"
export default function Template({ data }) {
  const { markdownRemark } = data
  const { frontmatter, html } = markdownRemark
  return (
    <div className="blog-post">
      <h1>{frontmatter.title}</h1>
      <h2>{frontmatter.date}</h2>
      <div
        className="blog-post-content"
        dangerouslySetInnerHTML={{ __html: html }}
      />
    </div>
  )
}
export const pageQuery = graphql`
  query($path: String!) {
    markdownRemark(frontmatter: { path: { eq: $path } }) {
      html
      frontmatter {
        date(formatString: "MMMM DD, YYYY")
        path
        title
      }
    }
  }
`

We get the results with the createPages function in gatsby-node.js .

Then we loop through the items with the forEach call and call createPage to create the posts.

We reference post.js , which is the template component.

And then we call createPage and set the template as the component.

context has data we want to display on our page.

We access that in the data prop of the Template component.

Removing Trailing Slashes

We can remove trailing slashes from the path when we create the page.

For instance, we can write:

const replacePath = path => (path === `/` ? path : path.replace(//$/, ``))

exports.createPages = async ({ graphql, actions, reporter }) => {
  const { createPage, deletePage } = actions
  const result = await graphql(
    `
      {
        allMarkdownRemark(limit: 1000) {
          edges {
            node {
              frontmatter {
                path
              }
            }
          }
        }
      }
    `
  )
  if (result.errors) {
    reporter.panicOnBuild(`Error while running GraphQL query.`)
    return
  }

  const blogPostTemplate = path.resolve(`src/templates/post.js`)
  result.data.allMarkdownRemark.edges.forEach(({ node }) => {
    const path = node.frontmatter.path
    const page = {
      path,
      component: blogPostTemplate,
      context: {
        pagePath: path,
      },
    }
    const oldPage = Object.assign({}, page)
    page.path = replacePath(page.path)
    if (page.path !== oldPage.path) {
      deletePage(oldPage)
      createPage(page)
    }
  })
}

We check if the oldPage.path is equal to page.path .

If they aren’t equal, then we call deletePage to delete the old page and call createPage to add the new page.

Conclusion

We can make conditional queries and create pages from GraphQL queries with Gatsby.

Categories
Gatsby.js

Gatsby.js — Site and Post Queries

Gatsby is a static web site framework that’s based on React.

We can use it to create static websites from external data sources and more.

In this article, we’ll look at how to create a site with Gatsby.

Excerpt

We can get post excerpts from GraphQL queries.

To do this, we write:

{
  allMarkdownRemark(filter: {frontmatter: {date: {ne: null}}}, limit: 5) {
    edges {
      node {
        frontmatter {
          title
        }
        excerpt(format: PLAIN, pruneLength: 200, truncate: true)
      }
    }
  }
}

We add the excerpt function with the format , pruneLength , and truncate parameters.

format has the excerpt format.

pruneLength is the max length of the excerpt.

truncate indicates that we want to truncate the excerpt to the given length.

Sort, Filter, Limit, and Format Together

We can combine sort, filter, limit, and format together.

For instance, we can write:

{
  allMarkdownRemark(limit: 3, filter: {frontmatter: {date: {ne: null}}}, sort: {fields: [frontmatter___date], order: DESC}) {
    edges {
      node {
        frontmatter {
          title
          date(formatString: "dddd DD MMMM YYYY")
        }
      }
    }
  }
}

We just put them all in the allMarkdownRemark query and all the operations will be applied.

Query Variables

We don’t have to create queries with fixed values.

To reuse our queries, we can use query variables.

For example, we can write:

query GetBlogPosts($limit: Int, $filter: MarkdownRemarkFilterInput, $sort: MarkdownRemarkSortInput) {
  allMarkdownRemark(limit: $limit, filter: $filter, sort: $sort) {
    edges {
      node {
        frontmatter {
          title
          date(formatString: "dddd DD MMMM YYYY")
        }
      }
    }
  }
}

Then we can put the following the query variables screen:

{
  "limit": 5,
  "filter": {
    "frontmatter": {
      "date": {
        "ne": null
      }
    }
  },
  "sort": {
    "fields": "frontmatter___title",
    "order": "DESC"
  }
}

We set the limit , filter , and sort variables in the Query Variables pane to set the variable values.

Group

We can group values by fields.

To do this, we run:

{
  allMarkdownRemark(filter: {frontmatter: {title: {ne: ""}}}) {
    group(field: frontmatter___date) {
      fieldValue
      totalCount
      edges {
        node {
          frontmatter {
            title
          }
        }
      }
    }
    nodes {
      frontmatter {
        title
        date
      }
    }
  }
}

We group the posts by date, so the results will be grouped by date.

Fragments

Fragments let us save frequently used queries for reuse.

We can apply fragments in our queries.

For instance, we can run:

fragment fragmentName on Site {
  siteMetadata {
    title
  }
}

{
  site {
    ...fragmentName
  }
}

We add the fragmentName fragment and applied it to our site query.

It just gets the title metadata of the site.

Aliasing

We can alias queries to run 2 queries on the same data source.

For example, we can write:

{
  someEntries: allMarkdownRemark(skip: 3, limit: 3) {
    edges {
      node {
        frontmatter {
          title
        }
      }
    }
  }
  someMoreEntries: allMarkdownRemark(limit: 3) {
    edges {
      node {
        frontmatter {
          title
        }
      }
    }
  }
}

We have the someEntries and someMoreEntries queries and we get results from them.

Conclusion

We can make various kinds of GraphQL queries with Gatsby to get data for our site.

Categories
Gatsby.js

Gatsby.js — GraphQL Queries

Gatsby is a static web site framework that’s based on React.

We can use it to create static websites from external data sources and more.

In this article, we’ll look at how to create a site with Gatsby.

Limit

We can limit the number of results that are returned in the GraphQL query results.

For instance, we can write:

{
  allMarkdownRemark(limit: 3) {
    totalCount
    edges {
      node {
        frontmatter {
          title
        }
      }
    }
  }
}

to get the first 3 Markdown posts with the title field.

Skip

We can skip over a number of results with the skip parameter:

{
  allMarkdownRemark(skip: 3) {
    totalCount
    edges {
      node {
        frontmatter {
          title
        }
      }
    }
  }
}

Filter

We can filter results with the filter parameter:

{
  allMarkdownRemark(filter: {frontmatter: {title: {ne: ""}}}) {
    totalCount
    edges {
      node {
        frontmatter {
          title
        }
      }
    }
  }
}

We set the filtet to an object with the title not equal to an empty string in the frontmatter .

We can combine multiple fields.

For instance, we can write:

{
  allMarkdownRemark(filter: {frontmatter: {title: {ne: ""}}, wordCount: {words: {gte: 1}}}) {
    totalCount
    edges {
      node {
        frontmatter {
          title
        }
      }
    }
  }
}

to search for Markdown posts that have title not equal to an empty string and with a word count bigger than or equal to 1.

Operators

The full list of operators include:

  • eq: short for equal, must match the given data exactly
  • ne: short for not equal, must be different from the given data
  • regex: short for regular expression, must match the given pattern. Note that backslashes need to be escaped twice, so /\w+/ needs to be written as "/\\\\w+/".
  • glob: short for global, allows us to use wildcard * which acts as a placeholder for any non-empty string
  • in: short for in an array, must be an element of the array
  • nin: short for not in an array, must not be an element of the array
  • gt: short for greater than, must be greater than given value
  • gte: short for greater than or equal, must be greater than or equal to the given value
  • lt: short for less than, must be less than given value
  • lte: short for less than or equal, must be less than or equal to the given value
  • elemMatch: short for element match. We find the elements that match the given value with this operator.

Sort

We can sort items that are returned in the results.

To do this, we write:

{
  allMarkdownRemark(sort: {fields: [frontmatter___date], order: ASC}) {
    totalCount
    edges {
      node {
        frontmatter {
          title
          date
        }
      }
    }
  }
}

to add the order field to let us sort the frontmatter.date field.

Format Dates

We can format our results. To format dates, we write:

{
  allMarkdownRemark(filter: {frontmatter: {date: {ne: null}}}) {
    edges {
      node {
        frontmatter {
          title
          date(formatString: "dddd DD MMMM YYYY")
        }
      }
    }
  }
}

Then we get the full date, something like:

{
  "data": {
    "allMarkdownRemark": {
      "edges": [
        {
          "node": {
            "frontmatter": {
              "title": "My First Post",
              "date": "Wednesday 10 July 2019"
            }
          }
        }
      ]
    }
  },
  "extensions": {}
}

Conclusion

We can make various kinds of queries with Gatsby’s GraphQL API.