at posts/single.html

tDiaryの日記を静的サイトジェネレータで表示したい (1)

最近は日記の更新頻度がすっかり減った。とはいえ、過去の日記は自分のためにも見返せるようにしておきたい。そこで、そろそろtDiaryで書いてきた日記を、tDiaryがなくても表示できるようにしておこう。

考えることはいろいろある。

  • 日記をどのように表示するか
  • 日記データの取り出し方

日記をどのように表示するか

tDiaryが生成したHTMLファイルをそのままWebサーバでホスティングすることもできるが、今後のことを考えて静的サイトジェネレータ (SSG) を使うことにする。静的サイトジェネレータには、Hugo, Jekyll, Gatsby, Next.jsなどがある。それぞれ一通り触ってみたところ、すぐに動かすなら Hugo、細かくカスタマイズしたいなら Next.js が良さそうだった。まずは日記データを取り出せるところから確かめたいので、すぐに動かせるHugoを使ってみる。

日記データを取り出す

tDiaryは複数の記法(スタイル)に対応している。この日記は最近ではMarkdown (GFMスタイル)を使っていて、以前はHiki形式 (Wikiスタイル) を使っていた。

1つ目は、Markdown形式でSSGツールに読み込ませる方法。これはHiki形式の日記をMarkdownに変換するのが大変そう。それから、インラインプラグインを使っている箇所は何らかの手段で変換しないといけない。

2つ目は、tDiaryが出力したHTML形式をSSGツールに読み込ませる方法。日記のスタイル(Markdown, Hiki)に依存せず読み込めることがメリット。

tDiaryには、生成したHTMLファイルをファイルで保存する squeeze.rb というプラグインがある。これを改造し、SSGツール (Hugo) での読み込みに必要なFrontMatter付きのHTMLを出力できるようにした。

  • 日単位ではなくセクション単位でHTMLを生成する
  • FrontMatterにtDiaryのタグ情報を記載

squeeze.rbの改造箇所

module ::TDiary
  class YATDiarySqueeze
    def execute
      dest = @dest
      diary = @diary
      suffix = @suffix

      template = File.read("hugo.rhtml")
      Dir.mkdir(dest, 0755) unless File.directory?(dest)
      section_index = 0
      diary.each_section do |section|
        section_index += 1
        load_plugins
        filename = format("#{diary.date.strftime('%Y%m%d')}p%02d#{suffix}", section_index)
        begin
          html = @plugin.eval_src(ERB.new(section.body_to_html || section.subtitle).src)
        rescue => e
          STDERR.puts "plugin error at #{filename}"
          STDERR.puts e
          html = section.body_to_html
        end

        props = {}
        props["title"] = section.stripped_subtitle
        props["date"] = diary.date
        props["url"] = URI.parse(@conf.base_url + filename).path
        props["lastmod"] = diary.last_modified
        props["draft"] = ! diary.visible?
        props["tags"] = section.categories unless section.categories.empty?
        props["categories"] = "#{diary.date.year}/#{diary.date.month}"
        props["summary"] = @conf.shorten(remove_tag(html), 100)
        props["aliases"] = [ URI.parse(@conf.base_url + @plugin.anchor(diary.date.strftime('%Y%m%d'))).path ]
    
        r = ERB.new(template).result(binding)
        # binding.irb
        File::open("#{dest}/#{filename}", 'w') {|f|	f.write(r) }
      end
      diary.date.strftime('%Y%m%d')
    end

    def remove_tag( str )
      str.gsub( /<[^"'<>]*(?:"[^"]*"[^"'<>]*|'[^']*'[^"'<>]*)*(?:>|(?=<)|$)/, '' )
    end
  end
end

hugo.rhtml

<%= props.to_yaml %>
---
<%= html %>

tDiaryを設置してあるルートディレクトリでこのツールを動かす。

bundle exec ruby squeeze.rb -x .html -s html

FrontMatter付きのHTMLを生成できた。

---
title: tDiaryのプレビュー画面を横並びで表示
date: 2016-05-07 00:00:00.000000000 +09:00
url: "/diary/20160507p01.html"
lastmod: 2016-05-08 06:32:03.000000000 +09:00
draft: false
tags:
- tDiary
categories:
- '201605'
summary: tDiaryのプレビュー画面をリアルタイムで更新するpreviewプラグインを、横並びでいい感じに表示できるようにした。これでまた、日記が書きやすくなったよ。  以前は縦に並んでいたので、更新する..
aliases:
- "/diary/20160507.html"

---
<p>tDiaryのプレビュー画面をリアルタイムで更新するpreviewプラグインを、<a href="https://github.com/tdiary/tdiary-contrib/pull/157">横並びでいい感じに表示できるようにした</a>。これでまた、日記が書きやすくなったよ。</p>
(以下略)

出力したHTMLファイルをhugoに取り込むと、ほぼカスタマイズなしでいい感じに表示された。タグもちゃんと引き継がれている。

セクションごとにHTMLファイルを分けるようにしたので、次はURLをどうするかを考えないとな。

関連する日記