Build dynamic blog with Gatsby

January 01 2018

GatsbyReactReduxGraphQLMaterialUIMarkdown

I'm a big fan of react ecosystem and I always want to create my own blog to share and record some learning experience, so this is it. Gatsby is a super fast static sit generator which let React users to scaffold out a static site in 'React way'. How it works? At building phase, its SSR allows us to render dynamic components into static html content then serve. With all the benefits from both dynamic and static site, it became my first choice. In this post, I will cover some basic use of Gatsby / React / Redux / GraphQL / Styled Component / Markdown / Netlify.

Install & Config

My current environment:

    node: v8.9.4
    npm: v5.6.0

Start fresh

    npm install -g gatsby-cli // install cli globally
    gatsby new [your-project-name] // create new project

I want to minimize my dependency so that I could add some tools I wanna learn/use, but you could use a starter package from Gatsby Starter for faster result.

Install plugins

This is important, there are hundreds of plugins which make gatsby powerful.
Review them here: Gatsby Plugins.
Then install 3 basic plugins for styled-components / data grabbing from source file (markdown) / markdown parser.

    npm i --s gatsby-plugin-styled-components  gatsby-source-filesystem  gatsby-transformer-remark

Modify root/gatsby-config.js so gatsby could use those plugins.

Gatsby-config.js has similar style as webpack.

    module.exports = {
        // site-wide header meta
        siteMetadata : {
            title : `XX\'s blog`,
        },
        plugins : [
            `gatsby-plugin-react-helmet`,
            `gatsby-plugin-styled-components`,
            `gatsby-transformer-remark`,
            {
                resolve : `gatsby-source-filesystem`,
                options : {
                    name : `pages`,
                    path : `${__dirname}/src/pages/posts`,
                },
            },
        ],
    };

To get the site running, use one command

    gatsby develop

you should be able to see

  • default page on localhost:8000
  • graphql debugger page on localhost:8000/__graphql

Page & Template

Create markdown file

In file /posts, create [your-markdown-file-name].md, inside start with

    ---
    path: '/How-to-use-gatsby-to-create-my-blog-1'  
    title: 'How to use gatsby to create my blog #1' 
    published: true
    date: 01-01-2018
    tag: [Gatsby, React, Redux, GraphQL, Styled Component, Markdown, Netlify]
    ---
    [your-blog-content]

This header for all posts in markdown is called frontmatter, it provides details for each post so that graphql could filter/sort based on the info.

Create post template

Gatsby already set up the basic functions such as routing under the hood, so that we don't need to do those things again. To generate a static page, just create a component file in src/pages, it will be served on domain/[file-name]. To create pages based on these markdown files dynamically, a template is needed as src/template/postTemplate.js.

    import React from 'react';
    
    // data is the props that injected by graphql query
    export default function Template ({data}) {
        const {markdownRemark : post} = data; // markdownRemark from remark plugin
        return (
            <div>
                <h1>{ post.frontmatter.title }</h1>
                <p dangerouslySetInnerHTML={ {__html : post.html} }/> // react api to inject html content
            </div>
        );
    }
    // graphql query
    // detail is in graphql section
    export const postQuery = graphql`
        query BlogPostByPath($path: String!){ 
            markdownRemark(
                frontmatter: {path: {eq: $path}}
            ){
                html
                frontmatter {
                    path
                    title
                }
            }
        }
    `;

Tell plugin to create pages

To let plugins to create pages, config in gatsby-node.js is needed.

    const path = require ('path');
    
    // boundActionCreators let us use gatsby's redux action creators 
    exports.createPages = ({boundActionCreators, graphql}) => {
        const {createPage} = boundActionCreators;
        const postTemplate = path.resolve ('src/templates/postTemplate.js');
        
        // query all markdown data
        return graphql (`{
            allMarkdownRemark() {
                edges{
                    node{
                        html
                        id
                        frontmatter {
                            path
                            title
                            date
                        }
                    }
                }
            }
        }`).then ((res) => {
            if (res.errors) {
                return Promise.reject (res.errors);
            }
            // createPage api will create for each markdown file
            res.data.allMarkdownRemark.edges.forEach (({node}) => {
                createPage ({
                    path : node.frontmatter.path,
                    component : postTemplate,
                });
            });
        });
    };

Now the page should be showing on domain/[file-path]

Create post list in index

To get a list of posts, it's similar as what we did above. Use graphql in pages/index-backup.js to query the list of post info, then pass into a component as props.


Style

Code block highlight

You may wonder how to get the code style and highlight like I did above, it's a plugin called gatsby-remark-prismjs.
install the plugin and modify in gatsby-config like this.

    plugins : [
            `gatsby-plugin-react-helmet`,
            `gatsby-plugin-styled-components`,
            {
                resolve : `gatsby-transformer-remark`,
                options : {
                    plugins : [
                        {
                            resolve : `gatsby-remark-prismjs`,
                            options : {
                                classPrefix : `language-`,
                            },
                        },
                    ],
                },
            },
            {
                resolve : `gatsby-source-filesystem`,
                options : {
                    name : `pages`,
                    path : `${__dirname}/src/pages/posts`,
                },
            },
        ],

Also import a pre-defined style sheet such as prismjs/themes/prism-tomorrow.css in layout/index-backup.js or create your own css class .gatsby-highlight-code-line.
For more detail, read here

Styled component modify markdown

I want to use styled component for modify some markdown default styles, such as subtitles' margin-top.
in src/templates/postTemplate.js

    // create a wrapper
    const MDContentWrapper = styled.div`
        > h1, h2, h3, h4 {
        margin-top: 2.5rem;
        }
    `
    // replace <p> with the new wrapper
    <MDContentWrapper dangerouslySetInnerHTML={ {__html : post.html} }/>

End

This is what I get from the first day learning Gatsby / GraphQL, will write another post once I understand more deeply. The code repo here Github