67
59

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Gatsbyを使ってみる

Posted at

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

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

67
59
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
67
59

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?