GraphCMSとHugoを連携してGithub Pagesで公開する(2)〜Hugoの設定 

# 概要

GraphCMSとHugoの連携二回目。
今回はHugoの設定の話。

# Hugoによるサイト構築

## インストール

ここではHugoのインストール方法は割愛する。

最初にサイトを作成する。

```shell
hugo new site my-site
```

上記コマンドで作成した場合は以下のようなファイル構成となる。

```
my-site
├── archetypes
│   └── default.md
├── config.toml
├── content
├── data
├── layouts
├── static
└── themes
```

テーマ(themes)は既存のものを導入するとして最小限編集する必要があるのは`config.toml`と`content`である。
その名の通り後者が具体的なサイトのコンテンツとなる。
なのでここにGraphCMSのコンテンツを流し込むようにする。

その前にまずGitレポジトリの初期化を行う。

```shell
cd my-site
git init
echo '*~' >> .gitignore
echo '*.bak' >> .gitignore
echo '*.orig' >> .gitignore
echo '.env' >> .gitignore
echo 'public' >> .gitignore
echo 'resources' >> .gitignore
```

次にテーマの導入。
テーマはお好みのものを使ってもらえればいいが、本例では[Ananke](https://github.com/theNewDynamic/gohugo-theme-ananke)を使う。

```shell
git submodule add https://github.com/budparr/gohugo-theme-ananke.git themes/ananke
cp themes/ananke/exampleSite/config.toml .
```

そしてconfig.tomlの編集

```toml
title = "Hugo GraphCMS Site"
baseURL = ""
languageCode = "en-us"
theme = "ananke"
#themesDir = "../.."
#resourceDir = "../resources"

DefaultContentLanguage = "ja"
SectionPagesMenu = "main"
Paginate = 3 # this is set low for demonstrating with dummy content. Set to a higher number
googleAnalytics = ""
enableRobotsTXT = true

[languages]
  #[languages.en]
  #  title = "My blog"
  #  weight = 2
  #  contentDir = "content/en"
  [languages.ja]
    title = "私のブログ"
    weight = 1
    #contentDir = "content/ja"
    contentDir = "content"
# 以下省略
```

重要なのは`theme`と`themesDir`あたり。これを適切に設定しないエラーになるか真っ白な画面になる。
また`languages.en`の設定は不要だが、後で多言語化にトライしてみるつもりなので残してある。

では確認

```shell
huge serve
```
![FireShot Capture 115 - 私のブログ - localhost.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/691494/c5c07d9c-c27d-e0b2-4f1d-e433ab3efc5c.png)

ここまでのソース → [Release v1\.0 · higebobo/hugo\-graphcms\-blog](https://github.com/higebobo/hugo-graphcms-blog/releases/tag/v1.0)

# Hugoのコンテンツ形式

Hugoのコンテンツは一般的には`content`ディレクトリにMarkdown形式のファイルをおいてビルドする。だけである。
コンテンツのメタ情報はフロントマターと呼ばれる`yaml`形式または`toml`形式で記述する。
なのでものすごくシンプルにするとこんな感じになる。

```markdown
---
title: はじめまして
date: "2021-09-16T12:58:01+09:00"
---
# こんににちは

私もブログをはじめました。
```

コンテンツの雛形は`archetype`と呼ばれ、コマンドでコンテンツを作成する時に呼び出される。
(Hugoのサイト作成時に`archetypes/default.md`が生成される)
例えば`content`ディレクトリに`hello.md`を作成したい場合は以下を実行する。

```shell
hugo new content/post/hello.md
```

するとフロントマターが生成された状態のコンテンツが作成されるので後は本文を書けばよい。

```markdown
---
title: "Hello"
date: 2021-09-24T08:23:45+09:00
draft: true
---
```

## Anankeテーマの場合

**(他のテーマを使う場合は不要または適時読み替え)**

Anankeテーマを使う場合は`archetype`もテーマ用のものを使う必要がある。
デフォルトでは`archetypes/default.md`が呼び出されるのでテーマのものに替える。
コピーして上書きでもよいが、archetypesの検索順([参照記事](http://staff.feedtailor.jp/2016/06/01/hugo_07/))を利用して**呼び出す順位を変える**。

```shell
# 変更する名前はdefault.mdやpost.mdでなければよい
mv archetypes/default.md archetypes/_default.md
```

またAnankeテーマのコンテンツは`_index.md`というインデックスページ([参照記事](https://maku77.github.io/hugo/layout/section.html))を利用しているので以下のように準備する。

```
content
├── _index.md
└── post
    └── _index.md
```

content/_index.md

```markdown
---
title: "Hugo GraphCMS Blog"
featured_image: '/images/gohugo-default-sample-hero-image.jpg'
description: "HugoとGraphCMSを連携したブログです"
---
みなさん、こんにちは。  
私のブログへようこそ
```

content/post/_index.md

```markdown
---
title: "投稿記事"
date: 2021-09-24T09:18:44+09:00
---
ブログの投稿記事一覧です。

```

準備ができたら記事を作成する。

```shell
hugo new content/post/first-post.md
```

以上がAnankeを使う場合の作法だが、テーマごとのコンテンツ作成ルールなどは正直初見ではわかりにくい。
まずはテーマがたいてい`exampleSite`を用意しているのでその中の`content`をまるっとコピーしてくるとよい。

# Pythonによるコンテンツの雛形生成

`archetype`のところを長々と説明したけども、今回はHugoの`archetype`の仕組みは利用せずPythonで作る。
この段階ではわざわざPythonで作る必要は無い。しかし後で述べるGraphCMSとの連携を考慮した。
Go言語がわかればHugo内で直接WEB-APIを叩いてMarkdownを作成すればよいと思うが、Pythonistaの私はPythonで実装するほうが手っ取り早い。

> 「Python使い」の意味だったと思うPythonistaがいつの間にかアプリ名になっている。。。

ざっと実装するとこんな感じ。
(Markdown作成の考えた方は同じなので好きな言語で実装してもらえればよいかとは思う)

`app/__main__.py`

```python
import argparse
import datetime
import os

ROOT_DIR = os.path.abspath(os.path.dirname(os.path.dirname(__file__)))
CONTENT_DIR = os.path.join(ROOT_DIR, 'content', 'post')

def check_args():
    parser = argparse.ArgumentParser()
    parser.add_argument('-t', '--title', default='My Post', help='blog title')
    parser.add_argument('-i', '--image', help='featured image')
    parser.add_argument('--tags', help='blog tags')

    return parser.parse_args()

def main(content_dir=CONTENT_DIR):
    args = check_args()
    now = datetime.datetime.now()
    timestamp = now.strftime('%Y%m%dT%H%M%S')
    # ファイル名をタイムスタンプで生成
    filepath = os.path.join(content_dir, f'{timestamp}.md')
    if os.path.exists(filepath):
        # 同一ファイル名が存在する場合は終了
        print(f'{filepath} is exists')
        return
    # フロントマターのメタ情報設定
    front_matter_map = {
        'title': f'"{args.title}"',
        'date': now.strftime('%Y-%m-%dT%H:%M:%S+09:00'),
    }
    # カバー写真の処理
    if args.image:
        front_matter_map.update({"featured_image": f'"{args.image}"'})
    # タグの処理
    if args.tags:
        front_matter_map.update({"tags": str(args.tags.split(','))})
    # 出力内容の生成
    output = '---\n'
    for k, v in front_matter_map.items():
        output += f'{k}: {v}\n'
    output += '---\n\n<!--more-->\n'
    # ファイルへの書き込み
    with open(filepath, 'w') as f:
        f.write(output)
    print(f'create {filepath}')

if __name__ == "__main__":
    main()
```

オプションでフロントマターの情報を与えられるようにしたので例えば以下のように実行すると

```shell
python -m app -t "Pythonからこんにちは" -i https://www.python.org/static/community_logos/python-logo-master-v3-TM.png --tags="Python,挨拶"
```
こんなMarkdownが生成される。

```markdown
---
title: "Pythonからこんにちは"
date: 2021-09-27T10:00:27+09:00
featured_image: "https://www.python.org/static/community_logos/python-logo-master-v3-TM.png"
tags: ['Python', '挨拶']
---

<!--more-->
```

適当に本文を作成してサーバ起動する。

![FireShot Capture 116 - Pythonからこんにちは - 私のブログ - localhost.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/691494/8cd8104e-c19d-7a72-ab5d-58eee280f36b.png)

こんな感じでできあがる。

Pythonで実装しているのでフロントマターのみならず本文もオプションで自由に設定することはできる。
例えばyoutube動画を埋め込むとかいろいろ。
しかし現実的には長々とコマンドラインに引数を与えて実行するよりも単純に

```shell
python -m app
```

として後は自由に編集するのが一番よいかと思う。

ここまでのソース → [Release v1\.1 · higebobo/hugo\-graphcms\-blog](https://github.com/higebobo/hugo-graphcms-blog/releases/tag/v1.1)

# まとめ

今回はHugoのコンテンツを**わざわざ**Pythonで生成する方法を解説した。
が、これは次回説明する本題のGraphCMSとHugoの連携についての前置きであるのでご了承いただきたい。