PIYO - Tech & Life -

Hugo + Netlifyでブログを再構築

ブログ Hugo

2つほど前の記事でRailsで作ったよと書いて早1年。Railsで作った時点で満足し、その間ほとんど新しい投稿をすることもなく過ぎてしまった。心機一転ブログを再開する気持ちになったものの、なんか盛り上がらないなーということでまずは引っ越しからはじめました。

今までWordpressを自分でホストしたり、ブログサービスを使ってみたり、CMSごと作ったりと色々やってきて、次も違うやり方をしたいなと思いスタティックサイトジェネレータとNetlifyを使うことにします。

スタティックサイトジェネレータにはGo言語製のHugoを選びました。Rubyのより早そうだし。

The world’s fastest framework for building websites | Hugo

データエクスポート

各記法への対応

引っ越しということで、過去データがあるのでそれを移行しなきゃいけません。はてなブログ時代のはてな記法が残っているのをなんとかする必要があります。

例えばこのへん。

  • Amazonアソシエイト
  • Twitter
  • ブログカード

はてなの記法はすごく便利なんだけど、独自だから移行のときにめんどくさいんですよね。

[asin:XXXXXXXXXXXX:detail]
[https://twitter.com/pi_cha_n/status/835146845626118146:embed]
[http://hogehogehoge.com/:embed:cite]

Rails製のブログでは画面出力のときにマークダウンの本文の中からこの手の記法を正規表現で見つけてはHTMLに置換するというのをやっていました。

Hugoのマークダウンには素のHTMLを書くこともできます。Railsブログから移行用のデータを出力する際、上の記法をHTMLに変換したうえで出力するというスクリプトを書きました。

URLが変わらないように

元のRailsブログのURLはhost名/posts/{slug}となっていました。Hugoでもその構造にできそうだったので、pathを維持したまま移行することにできました。

幸い元の記事のPathには、各記事ごとに持つ文字列(=slug)を使うようにしていたので、それをそのまま記事のファイル名とすることで対応できました。

スクリプトはこんな感じ

Post.all.each do |post|
  File.open("#{post.slug}.md", 'w') do |f|
    title = post.title.gsub(/@|:/, '')

    f.puts('---')
    f.puts("title: #{title}")
    f.puts("description: #{title}")
    f.puts("tags: [#{post.tag_list.join(',')}]")
    f.puts("date: #{post.published_at}")
    f.puts('---')

    f.puts

    # 各記法をよしなに変換する
    f.puts convert(post.content)
  end
end

そうするとメタデータ(?)の部分がこのようになります(例)。

---
title: 快適な目覚めのため、カーテンを自動で開閉する
description: 快適な目覚めのため、カーテンを自動で開閉する
tags: [生活]
date: 2017-03-03 22:18:00 +0900
---

(あとは内容が続く)

続いてコンテンツの変換部分

Twitter

Hugoにはショートコードという仕組みがあります。大体はてな記法のようなものですが、自分で新しくつくることができ、出力されるHTMLも自由に書けるため自由度が高いです。

この先また移行、となると面倒なんだけどひとまずおいておきましょう。

例えばTwitterの場合はTweetのIDがあればこんな風に

{{< tweet 877500564405444608 >}}

書くことでHugoのデフォルトの状態でもTweetが展開されます。

(これ、コードブロックの中に書くと展開されちゃうのが不便だ。。。)

ブログカード

はてなブログカードはリンクを貼るときにただの文字だけじゃなくて、メタデータや画像込みで表示してくれる機能です。

はてなのブログカード

画像付、いいですよね。簡易でもいいのでなんとか実現したい。Rails製ブログのときにも使っていたHeartRailsのサービスを使って実現します。↓こんなのですね。

ざっくりいうとこんな感じで変換できます。

def convert(content)
  screenshot = "[![](https://capture.heartrails.com/200x150/shadow/border?\\1)](\\1)\n[\\1](\\1)"
  content = content
    .gsub(/\[(.+):embed:cite\]/, screenshot)
    .gsub(/\[(.+):embed\]/, screenshot)
    .gsub(/\[(.+):title\]/, screenshot)
end

Amazonアソシエイト

Amazonは難しかったです。はてなの場合はasinを書くだけで商品情報を貼り付けることができましたが、あれははてなブログ側でProduct Advertising APIを使って情報を取得してくれているのだと思います。asinだけではAmazonへのリンクを作るのは難しかったはず。

ということでググってみると、同様の仕組みを実現している方がいました。

簡単にいうと、、

  • Advertising APIのXMLをJSONに変換して返すWebサーバーをローカルに立てる
  • Amazonアソシエイト用のショートコードを用意して、asinを渡す
  • ショートコードのHTMLでWebサーバーにリクエストを送る
  • 戻ってきたJSONの情報を用いてHTMLを組み立てる

というようなことを行っているようでした。HugoはJSON APIの戻り値をそのまま画面に出せるような仕組みがあります。

ショートコードやHTMLは自分用に少しいじりましたが、概ねこの方法でやってみました。

{{< amazon asin=“B01ERLNK72” >}}

と書いておくと、↓のように展開されます。すごく良いですね。

ですが、このままではNetlifyでデプロイできません

JSONのサーバーをローカルで動かしているので、ローカルでビルド→ファイルをそのままコピーという形でのデプロイではうまくいきます。

しかし、Netlify上でビルドする場合にはNetlify上のビルドプロセスがアクセスできるところにAdvertising APIのJSONを返すサーバーが必要です。

なのでローカルで動かしていたWebサーバーをインターネット上に公開する必要がありました。この部分を話すと長くなりそうなので後日に回しますが、なんとかWeb上で動かすことができた結果、Netlifyでのビルドも通りました。

終わりに

静的サイトにしたことで閲覧が速くなりました。記事を書くときはローカルのエディタが使えるので、それも便利になった気がします。

復帰第一弾は引っ越し記事でした。