Help us understand the problem. What is going on with this article?

Gatsbyを使ってみる

More than 1 year has passed since last update.

Gatsbyとは

Reactを使った静的サイト生成ツール
static PWA(Progressive Web Application)を作れるらしい。PWAとはネイティブアプリのようなWEBアプリと自分は解釈している。

Reactのことをさっぱり分かっていないこともあり、学習も兼ねて使ってみた。
静的サイト生成ツールはこちらの一覧が参考になった。

markdownを書いてblog記事にするためのhow to

1. インストールと設定

gatsby-plugin-react-helmetが2系だと、$ gatsby developでエラー出てたけどもう直ってるかも?

$ node -v 
v9.3.0
$ npm install -g gatsby-cli
$ gatsby new my-blog
$ cd my-blog
$ npm install gatsby-source-filesystem gatsby-transformer-remark
$ npm ls -g --depth=0
/home/kw/.nvm/versions/node/v9.3.0/lib
├── gatsby-cli@1.1.28
└── npm@5.5.1
$ npm ls --depth=0
gatsby-starter-default@1.0.0 /path/to/my-blog
├── gatsby@1.9.145
├── gatsby-link@1.6.32
├── gatsby-plugin-react-helmet@1.0.8
├── gatsby-source-filesystem@1.5.11
├── gatsby-transformer-remark@1.7.26
└── prettier@1.9.2

gatsby-config.jsを下記のように編集

module.exports = {
  siteMetadata: {
    title: `Gatsby Default Starter`,
  },
  plugins: [
    `gatsby-plugin-react-helmet`,
    `gatsby-transformer-remark`,
    {
      resolve: `gatsby-source-filesystem`,
      options: {
        name: `src`,
        path: `${__dirname}/src`,
      },
    },
  ],
};

2. markdownでブログ記事を書く

$ cd src/pages
$ mkdir -p 2018/01/14
$ touch 2018/01/14/hello-my-blog.md

hello-my-blog.mdは次のように記述する

---
path: "/2018/01/14/hello-my-blog"
date: "2018-01-14T22:35:00Z"
title: "Gatsbyとgithub pagesでブログ"
tags: ['gatsby', 'react']
excerpt: "Gatsbyとgithub pagesでブログを作成してみた"
---

# Gatsbyとは
.
.
.

3. index.jsを修正する

src/pages/index.jsを修正する

import React from 'react';
import Link from 'gatsby-link';

const IndexPage = ({data}) => {
  const {edges: posts} = data.allMarkdownRemark;
  return (
      <div>
        {posts.map(({node: post}) => {
          const {frontmatter} = post;
          return (
              <div key={post.id}>
                <h2>
                  <Link to={frontmatter.path}>
                    {frontmatter.title}
                  </Link>
                </h2>
                <p>{frontmatter.date}</p>
                <p>{frontmatter.excerpt}</p>
              </div>
          );
        })}
      </div>
  );
};

export const query = graphql`
  query IndexQuery {
    allMarkdownRemark {
      totalCount
      edges {
        node {
          id
          frontmatter {
            title
            date(formatString: "MMMM DD, YYYY")
            path
            tags
            excerpt
          }
        }
      }
    }
  }
`;

export default IndexPage;

localサーバーを起動して確かめる

localhost:8000にアクセスできる

$ gatsby develop

4. Blogコンテンツ内容を表示するテンプレートの作成

blog記事の一覧をindexで表示することはできたが、個別のページへのリンクをクリックすると404のままなので、テンプレートを作成する。

$ pwd
src
$ ls
layouts pages
$ mkdir templates
$ touch templates/blog-post.js

blog-post.jsを編集して次のようにする

import React from 'react';
import Link from 'gatsby-link';
import Helmet from 'react-helmet';

const Template = ({data, location, pathContext}) => {
  const {markdownRemark: post} = data;
  const {frontmatter, html} = post;
  const {title, date} = frontmatter;

  return (
      <div>
        <Helmet title={`${frontmatter.title} - My Blog`}/>
        <div>
          <h1>{title}</h1>
          <h3>{date}</h3>
          <div dangerouslySetInnerHTML={{__html: html}}/>
        </div>
      </div>
  );
};

export const pageQuery = graphql`
  query BlogPostByPath($path: String!){
    markdownRemark(frontmatter: { path: { eq: $path } }) {
      html
      frontmatter {
        title
        date(formatString: "MMMM DD, YYYY")
        path
        tags
        excerpt
      }
    } 
  }
`;

export default Template;

5. Dynamicにコンテンツを生成する

gatsby-node.jsを編集して次のようにする。

/**
 * Implement Gatsby's Node APIs in this file.
 *
 * See: https://www.gatsbyjs.org/docs/node-apis/
 */
const path = require('path');

exports.createPages = ({boundActionCreators, graphql}) => {
  const {createPage} = boundActionCreators;
  const blogPostTemplate = path.resolve(`src/templates/blog-post.js`);

  return graphql(`{
    allMarkdownRemark {
      edges {
        node {
          html
          id
          frontmatter {
            date
            path
            title
            excerpt
            tags
          }
        }
      }
    }
  }`).then(result => {
    if (result.errors) {
      return Promise.reject(result.errors);
    }
    const posts = result.data.allMarkdownRemark.edges;

    posts.forEach(({node}, index) => {
      createPage({
        path: node.frontmatter.path,
        component: blogPostTemplate,
      });
    });
  });
};

これでblog記事へのリンクをクリックするとコンテンツが表示される

$ gatsby develop

6. 前後の記事へのリンクをつくる

blog-post.jsは下記のように修正

import React from 'react';
import Link from 'gatsby-link';
import Helmet from 'react-helmet';

const Template = ({data, location, pathContext}) => {
  const {markdownRemark: post} = data;
  const {frontmatter, html} = post;
  const {title, date} = frontmatter;
  const {next, prev} = pathContext;

  return (
      <div>
        <Helmet title={`${frontmatter.title} - My Blog`}/>
        <div>
          <h1>{title}</h1>
          <h3>{date}</h3>
          <div dangerouslySetInnerHTML={{__html: html}}/>
          <p>
            {prev && (
                <Link to={prev.frontmatter.path}>
                  Previous: {prev.frontmatter.title}
                </Link>
            )}
          </p>
          <p>
            {next && (
                <Link to={next.frontmatter.path}>
                  Next: {next.frontmatter.title}
                </Link>
            )}
          </p>
        </div>
      </div>
  );
};

export const pageQuery = graphql`
  query BlogPostByPath($path: String!){
    markdownRemark(frontmatter: { path: { eq: $path } }) {
      html
      frontmatter {
        title
        date(formatString: "MMMM DD, YYYY")
        path
        tags
        excerpt
      }
    } 
  }
`;

export default Template;

gatsby-node.jsは次のように修正

/**
 * Implement Gatsby's Node APIs in this file.
 *
 * See: https://www.gatsbyjs.org/docs/node-apis/
 */
const path = require('path');

exports.createPages = ({boundActionCreators, graphql}) => {
  const {createPage} = boundActionCreators;
  const blogPostTemplate = path.resolve(`src/templates/blog-post.js`);

  return graphql(`{
    allMarkdownRemark {
      edges {
        node {
          html
          id
          frontmatter {
            date
            path
            title
            excerpt
            tags
          }
        }
      }
    }
  }`).then(result => {
    if (result.errors) {
      return Promise.reject(result.errors);
    }
    const posts = result.data.allMarkdownRemark.edges;

    posts.forEach(({node}, index) => {
      createPage({
        path: node.frontmatter.path,
        component: blogPostTemplate,
        context: {
          prev: index === 0 ? null : posts[index - 1].node,
          next: index === (posts.length - 1) ? null : posts[index + 1].node,
        },
      });
    });
  });
};

7. tag一覧を作る

テンプレートを作成する

$ pwd
blog/src
$ ls
layouts pages templates
$ touch templates/all-tags.js
$ touch templates/tags.js

all-tags.jsは下記のように

import React from 'react';
import Link from 'gatsby-link';

const AllTags = ({pathContext}) => {
  const {tags} = pathContext;

  if (tags) {
    return (
        <div>
          <ul>
            {tags.map(tag => {
              return (
                  <li>
                    <Link to={`/tags/${tag}`}>
                      {tag}
                    </Link>
                  </li>
              );
            })}
          </ul>
        </div>
    );
  }
};

export default AllTags;

tags.jsは次のように

import React from 'react';
import Link from 'gatsby-link';

const Tags = ({pathContext}) => {
  const {posts, tagName} = pathContext;

  if (posts) {
    return (
        <div>
          <span>
            Posts abount {tagName}:
          </span>
          <ul>
            {posts.map(post => {
              return (
                  <li>
                    <Link to={post.frontmatter.path}>
                      {post.frontmatter.title}
                    </Link>
                  </li>
              );
            })}
          </ul>
        </div>
    );
  }
};

export default Tags;

gatsby-node.jsは次のようにtagに関する記述を追加する

/**
 * Implement Gatsby's Node APIs in this file.
 *
 * See: https://www.gatsbyjs.org/docs/node-apis/
 */
const path = require('path');

const createTagPages = (createPage, posts) => {
  const tagPageTemplate = path.resolve(`src/templates/tags.js`);
  const allTagsTemplate = path.resolve(`src/templates/all-tags.js`);

  const postsByTags = {};

  posts.forEach(({node}) => {
    if (node.frontmatter.tags) {
      node.frontmatter.tags.forEach(tag => {
        if (!postsByTags[tag]) {
          postsByTags[tag] = [];
        }
        postsByTags[tag].push(node);
      });
    }
  });

  const tags = Object.keys(postsByTags);

  createPage({
    path: `/tags`,
    component: allTagsTemplate,
    context: {
      tags: tags.sort(),
    },
  });

  tags.forEach(tagName => {
    const posts = postsByTags[tagName];

    createPage({
      path: `/tags/${tagName}`,
      component: tagPageTemplate,
      context: {
        posts,
        tagName,
      },
    });
  });
};

exports.createPages = ({boundActionCreators, graphql}) => {
  const {createPage} = boundActionCreators;
  const blogPostTemplate = path.resolve(`src/templates/blog-post.js`);

  return graphql(`{
    allMarkdownRemark {
      edges {
        node {
          html
          id
          frontmatter {
            date
            path
            title
            excerpt
            tags
          }
        }
      }
    }
  }`).then(result => {
    if (result.errors) {
      return Promise.reject(result.errors);
    }
    const posts = result.data.allMarkdownRemark.edges;

    createTagPages(createPage, posts);

    posts.forEach(({node}, index) => {
      createPage({
        path: node.frontmatter.path,
        component: blogPostTemplate,
        context: {
          prev: index === 0 ? null : posts[index - 1].node,
          next: index === (posts.length - 1) ? null : posts[index + 1].node,
        },
      });
    });
  });
};

さらにpages/index.jsを修正

import React from 'react';
import Link from 'gatsby-link';

const IndexPage = ({data}) => {
  const {edges: posts} = data.allMarkdownRemark;
  return (
      <div>
        {posts.map(({node: post}) => {
          const {frontmatter} = post;
          return (
              <div key={post.id}>
                <h2>
                  <Link to={frontmatter.path}>
                    {frontmatter.title}
                  </Link>
                </h2>
                <p>{frontmatter.date}</p>
                <p>{frontmatter.excerpt}</p>
                <ul key={post.id}>
                  {post.frontmatter.tags.map(tag => {
                    return (
                        <li>
                          <Link to={`/tags/${tag}`}>
                            {tag}
                          </Link>
                        </li>
                    );
                  })}
                </ul>
              </div>
          );
        })}
      </div>
  );
};

export const query = graphql`
  query IndexQuery {
    allMarkdownRemark {
      totalCount
      edges {
        node {
          id
          frontmatter {
            title
            date(formatString: "MMMM DD, YYYY")
            path
            tags
            excerpt
          }
        }
      }
    }
  }
`;

export default IndexPage;

8. github pagesにdeployする

モジュールを追加する

$ npm install --save gh-pages

package.jsonを修正する

.
.
"dependencies": {
    "gatsby": "^1.9.145",
    "gatsby-link": "^1.6.32",
    "gatsby-plugin-react-helmet": "^1.0.8",
    "gatsby-source-filesystem": "^1.5.11",
    "gatsby-transformer-remark": "^1.7.26",
    "gh-pages": "^1.1.0"
  },
  "keywords": [
    "gatsby"
  ],
  "license": "MIT",
  "main": "n/a",
  "scripts": {
    "build": "gatsby build",
    "deploy": "gatsby build --prefix-paths && gh-pages -d public",
    "develop": "gatsby develop",
    "format": "prettier --trailing-comma es5 --no-semi --single-quote --write \"src/**/*.js\"",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
.
.

deployコマンドが追加されている。

github pagesを使ってサイトを作るにはレポジトリを作成して設定からgithub pagesの設定をすることで作成可能になる。

プロジェクト名がパス名になるので、このプロジェクトの名前はblogだ。(private repoにしているがgithub pagesは利用可能だ)

デプロイするには下記のコマンドを実行する

$ npm run-script deploy

https://abcb2.github.io/blog

でアクセスできるようになっている。

abcb2
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした