DEV Community

Cover image for Gatsby project structure
Hari Krishnan
Hari Krishnan

Posted on

Gatsby project structure

Gatsby Boilerplate

The Gatsby boilerplate gives us a set of files and directories which we use to build static sites. It consists of the following files and directories :

|-- /.cache
|-- /public
|-- /src
    |-- /pages
    |-- /templates
|-- gatsby-config.js
|-- gatsby-node.js
|-- gatsby-ssr.js
|-- gatsby-browser.js
Enter fullscreen mode Exit fullscreen mode

Let's not follow the order with respect to the above file structure. Instead we would have a close look over each file and directory.

package.json and package-lock.json

The node dependencies required for the Gatsby project development are mentioned in the package.json file. The package-lock.json keeps track of what already has been installed. The Gatsby cli and Gatsby itself will be installed using the system from npm. These files also allow us to specify how we want our scripts to run and compile our code.

gatsby-config.js

This is important to create the global metadata information about the website. It is the file where we add our configuration options for our Gatsby site. For example : we add our site name and description, the Gatsby plugins, and their settings etc.

gatsby-source-firestore plugin in the below config file generates GraphQL end points with cloud firestore as the datasource. During build time, Gatsby pulls data from this endpoint and then generates the static HTML content. We can also have datasource from any RDS or No-SQL database.

module.exports = {
  siteMetadata: {
    title: `My first gatsby project`,
    description: `My first gatsby site's description`,
    author: `@Hari Krishnan`,
  },
  plugins: [
    {
      resolve: `gatsby-source-firestore`,
      options: {
        // firebase.json contains the credentials and other metadata to connect to your firebase server
        // below code generates the graphql endpoints with the firebase cloud firestore as the source
        credential: require('./firebase.json'),
        types:[
          {
            type: 'Products',
            collection: 'products',
            map: doc => ({
              name: doc.name,
              id: doc.id,
              description: doc.description,
              price: doc.price
            })
          }
        ]
      }
    },
    `gatsby-plugin-react-helmet`,
    {
      resolve: `gatsby-source-filesystem`,
      options: {
        name: `images`,
        path: `${__dirname}/src/images`,
      },
    },
    `gatsby-transformer-sharp`,
    `gatsby-plugin-postcss`,
    `gatsby-plugin-sharp`,
    {
      resolve: `gatsby-plugin-manifest`,
      options: {
        name: `gatsby-starter-default`,
        short_name: `starter`,
        start_url: `/`,
        background_color: `#663399`,
        theme_color: `#663399`,
        display: `minimal-ui`,
        icon: `src/images/gatsby-icon.png`, // This path is relative to the root of the site.
      },
    },
    // this (optional) plugin enables Progressive Web App + Offline functionality
    // To learn more, visit: https://gatsby.dev/offline
    // `gatsby-plugin-offline`,
  ],
}

Enter fullscreen mode Exit fullscreen mode

gatsby-node.js

We use this file to create our custom pages. For example: in an e-commerce site, we may have n number of products, for each product Gatsby creates a separate html static file during build time. We specify how each product file should be built and how the url should look like etc.

In this node file, we specify from which server endpoint (ex: GraphQL endpoint) we need to get the data to build the static custom pages during build time. So this node file will actually execute before the application is built, this feature makes Gatsby so powerful.

Once we get the data from the endpoints, Gatsby uses the function called createPages to create static pages with data from an external source. Most important point to note is that we list only Gatsby plugins here, not any other plugin.

exports.createPages = ({graphql,actions}) => {
    const { createPage } = actions;
    // product template is the html page whose layout will be 
    // reused for each product page in an e-commerce site.
    // This file resides in the src/templates folder
    const productTemplate = path.resolve('src/templates/productTemplate.js');
    // the below graphql query gets the data from a firebase 
    // server and then generates the 
    return graphql(`
        {
            allProducts {
                edges {
                    node {
                            name
                            price
                            id
                            description
                    }
                }
            }
        }
    `).then((result) => {
        if(result.errors) {
            throw result.errors;
        }
        result.data.allProducts.edges.forEach(product => {
            createPage({
                path: `/product/${product.node.id}`,
                component: productTemplate,
                context: product.node
                // context is the data that we pass to the productTemplate component
                // we can access it in the productTemplate component using the props 
            })
        })
    });
}
Enter fullscreen mode Exit fullscreen mode

src/templates

All the custom page layouts are defined in the templates folder. For example : each product page will follow this template to create the HTML output page.

const ProductTemplate = (props) => {
  return (
    <div>
      <h1>{props.name}</h1>
      <h2>{props.price}</h2>
      <p>{props.description}</p>
    </div>
  );
}

export default ProductTemplate;
Enter fullscreen mode Exit fullscreen mode

gatsby-browser.js

This file gives you control over Gatsby's behaviour in the browser. Like we can trigger some method or function when the user changes the routes. Even more, you can call a function when the user first opens any page. For example, when the client-side rendering happens, we can wrap all the page content in a special React component using the wrapPageElement or the wrapRootElement. Also you can do some executions while the client opens the page by onClientEntry (called when the site is first rendered on to the browser) or give an order to the serviceWorkers .

This file is for advanced use cases when we want a customised what happens when your site appears in the browser. For most use cases we won't need this file, if we want we can also delete this.

gatsby-ssr.js

SSR stands for server-side rendering . This file lets you customise how Gatsby generates the static HTML files that your browser uses to load your site quickly. If you have known about Sapper (another SSR framework), this concept is something similar to the sapper's preload function , where we will get the data from the browser and the page is served as HTML content from the server itself. If we don't need SSR, we can also delete this file.

SSR is best suitable when we need SEO, because web crawlers do not wait until the page is loaded with all the data, so server-side rendering can be used to load the data from the server itself. This makes our HTML page easily visible for web-crawlers.

src

This folder contains the main views for our Gatsby site. These are the front end pages that our users will see and interact with.

src/components

All the basic layout files and the templates that typically get included with every page; such as the overall 'Layout.js' file, your 'Header.js' file which contains your top of the page '' html and may be your navbar etc.. is put into this folder. These are structured as React components and are translated into your HTML page by the Gatsby core API itself when 'building'.

src/pages

All the main pages of your site, including your initial index.js page is put to this folder. index.js is the page which users land on when they land on the home page of your website. You also have your other pages referenced here, such as your 'about-us.js' page and your 'contact.js' page etc.. . These are also structured as React components and are translated into your HTML page by the Gatsby core API itself when 'building'.

//(index.js file)
import React from "react"
import { Link, graphql } from "gatsby"
import Layout from "../components/layout"
import Image from "../components/image"
import SEO from "../components/seo"

// when we export a query like this in our page
// gatsby automatically executes the query and  gets the
// result
// and injects it into the props fo the below react component 

export const query = graphql`
  {
    allProducts {
      edges {
        node {
          id
          price
          description
          name
        }
      }
    }
  }
`;


const IndexPage = (props) => {
  console.log(props);
  return (
    <Layout>
      {props.data.allProducts.edges.map(edge => (
        <div key={edge.node.id}>
          <h2>
            {edge.node.name} - <small>{edge.node.price}</small>
          </h2>
          <div>
            {edge.node.description}
          </div>
          <Link to={`/product/${edge.node.id}`}>
            Route to individual product page
          </Link>
        </div>
      ))}
    </Layout>
  );
}


export default IndexPage;
Enter fullscreen mode Exit fullscreen mode

public/

This is the folder where your built files live. Once we have run our build scripts, this is the path where the files that will ultimately be served end up.

Page Routing

Gatsby automatically turns the pages in the src/pages (which are structured in the form of react components) into your final HTML output pages. For example your 'about-us.js' would be accessible via 'yoursite.com/about-us.js'

If you have any kind of feedback, suggestions or ideas - feel free to comment this post!

Discussion (0)