2019-05-03

ブログを自作の静的サイトジェネレータ Salmon に移行しました

このエントリーをはてなブックマークに追加

このブログを構成するためのフレームワークとして、ながらく Middleman を愛用してきましたが、このたび自作の静的サイトジェネレータであるところの Salmon に移行しました。一文字目は大文字にするのがカノニカルな表記です。

過去の記事はもちろん、この記事も Salmon を使って生成しています。まだ README をちゃんと書けていないので、この記事をたたき台にしようと思っています。

まだかわいいロゴがないので、イメージ画像としていらすとやからサーモンのおすしの画像をお借りしてきました。

なぜ移行したのか

理由はいくつかあります。

ビルドが遅い

まず、遅いこと。ページ数としては 50 に満たないサイトですが、middleman build を実行してビルドが完了するまでには、数十秒かかっていました。ライブプレビューがあるとはいえ、それでもやはりこの数十秒のビルド時間は、わたしにとっては耐え難いものでした。

シンプルなブログを構成するツールとして見ると複雑である

そして、シンプルなブログを構築するツールとしては、必要以上に複雑であるということ。汎用的に使えるように設計されているため、凝ったサイトを作る分には便利なのですが、ブログ用のフレームワークとしては大きすぎると感じています。

Wordpress vs 静的サイトジェネレータの文脈で、わたしはよく「お刺身を切り分けるのにチェーンソーは使わないでしょ」という比喩を持ち出すのですが、ブログというお刺身を切り分けるためには、Middleman ですらサイズが合わないように感じるようになりました。

技術志向の変化

そしてここ数年、仕事や個人的な興味の方向性が、ウェブアプリケーションそのものを作ることよりも、インフラや基盤技術に向いているということがあります。そのため、Ruby によるウェブアプリケーションにおけるエコシステムの変化を、昔ほど積極的にキャッチアップすることが難しくなってきました。

遅いという不満を解消するためには内部の仕組みを深く理解してチューニングする必要があります。しかしながら、そこにリソースを割くよりも、自分好みでシンプルなツールを作るのがもっとも理想に近い形に落ち着くのではないかと思い、自作するという道を選びました。

と、ここまでいろいろ書いてきましたが、汎用的なジェネレータとして使うならば Middleman は強力な選択肢だと思っていますし、個人のブログ用としては Salmon を使い始めた今でも、そのような案件があれば第一候補としてあげるでしょう。

使い方

ブログの構築に特化しており、設定より規約を原則としています。そのため、記事やレイアウトといったプロジェクトを構成するファイルは、所定のディレクトリに配置する必要があります。とはいえ、ページネーションの 1 ページあたりの記事数すらもハードコードされていたりして、さすがにあんまりなので最低限のオプションを設定できる機能は追加する予定です。

とりあえず試すぶんには、Docker Hub の mozamimy/salmon から Docker イメージがダウンロードできるので、docker pull して docker run --rm -v ${PWD}:/my_blog mozamimy/salmon salmon /my_blog のように実行するのがもっとも楽でしょう。

salmon build [プロジェクトのルートディレクトリ] のように実行すると、そのディレクトリにある build ディレクトリにファイルが生成されます。

ディレクトリ構造

プロジェクトのルートには、以下のようにディレクトリを作り、その中に記事やレイアウトファイルを置いていきます。このブログのソースのリポジトリも合わせて見るとよいでしょう。

  • articles: この中に記事の markdown ファイルを置いていきます。articles/2019/05/03/salmon.md のように、articles/YYYY/MM/DD/nanika.md にファイルを配置します。
  • codes: 記事に埋め込むコードを置きます。
  • layouts: レイアウトファイルを置きます。テンプレートエンジンである handlebars の記法が使えます。
  • pages: 単一のページをここに置きます。https://mozami.me/salmon.html のように、記事とは別のレイアウトを適用できます。
  • partials: ここに置いたレイアウトファイルは、記事やインデックスページなどのレイアウトに埋め込んで、使い回すことができます。
  • resources: 画像ファイルや CSS などを置きます。

記事の記法

記事は markdown で書きます。pulldown-cmark というライブラリを使っていて、CommonMark Spec に準拠しています。

Middleman を使っていたときは redcarpet を使っていましたが、わたしの使っていた範囲では、ほぼ修正なしで移行できました。ただし画像のパスは salmon への移行で変わってしまったため、それは修正する必要がありました。

また、一般的な静的サイトジェネレータとは違い、Salmon では記事本体と、記事中に埋めるコードは別の概念として切り離して取り扱います。コードは codes/2019/05/03/example.md のように保存しておき、記事中では以下のようにして埋め込むことができます。

<p>
{{ embed_code "/2019/05/03/example.md" }}
</p>

コードの配置場所は日付を利用した階層構造にする必要はなく、自由に配置し、べつべつの複数の記事に埋め込むこともできます。

レイアウトの記法

レイアウトは handlebars で書きます。handlebars-rust というライブラリを使っているため、本家の実装と違いがある点には注意が必要です。

Middleman では Slim を利用していましたが、そこまで気持ちがなかったので適当に handlebars を採用しました。

レイアウトや記事中では、しょぼいヘルパ関数が使えます。このブログで必要になったものしか実装してません。

レイアウト内では、articles といったデータを使うことができ、基本的にはそれを each 記法でぐるぐる回して出力する、というような形になると思います。

画像や CSS などのリソース

たとえば、resources/foo/bar/baz.png に画像を配置すると、ビルド後には <img src="/foo/bar/baz.png"> のように使うことができます。その他のファイルも、基本的に何もせずに単に出力ディレクトリにコピーしているだけです。

ただし、.sass 拡張子を持つ Sass ファイルだけは特別扱いしており、CSS として出力した結果を出力ディレクトリに書き出します。libsass のラッパーである sass-rs を利用しています。

Slim が使えなくなることに対しては特に気持ちはありませんでしたが、生 CSS を書くのだけは許容できなかったので、Sass で書けるようにして Middleman 版からそのまま Salmon に移植しました。

使用感

自分が使いやすいように作っているので当然ですし手前味噌ですが、使いやすいです。

しかもビルドが速くて快適です。Middleman だと数十秒かかっていたビルド時間が、1 秒程度になりました。速度は正義。

さらなる改善

とりあえず最低限使えるようにはなりましたが、まだいくつか機能が欠けていると感じているので、引き続きゆるゆると改良していきます。

  • 組み込みのウェブサーバとライブプレビュー機能
    • middleman server のような salmon server 機能が欲しい。
  • 非効率な実装になっている箇所がたくさんあるので、パフォーマンスチューニングしてさらに高速にする
  • linkgen ヘルパ関数の実装
    • ビルド時にリンク先のサイトの OGP を取得して、リッチなリンクを埋め込める機能
    • 当然ビルドは激遅になるので、ドィスクにキャッシュするなど工夫が必要そう
  • RSS フィードをテンプレートを使わずに構築できるようにする
  • 最低限のオプションを外部の設定ファイルから注入できるようにする

などなど。だいたい満足してるので、あとは正直、盆栽ですね...。

なんでサーモンなの?

サーモンのお刺身を食べながら「ゴールデウィークはこれでヒマをつぶすぞ!」と思いついたからです。サーモンだいすき。

あくまで一時的なコードネームのつもりで公開時にはもっとセンスのいい名前にしようと思っていたのですが、実装してるとだんだんと愛着がわいてきてしまい、結局 Salmon に決定しました。