2018年にもなってMiddlemanとJekyllを比較してみたよ

先に結論

独自に拡張していく、外部のデータと連携することを重視するなら Jekyll の方がよさそう。

Rails の view に慣れてて何も設定せずにいきなり使う場合の初速の速さは Middleman の方が上になる。

きっかけ

2016 年に『マイクロサービスアーキテクチャ』を読み、それとは別に Decoupled CMS という概念を知って以来、古くて評判のよくない CMS を使うことや自分で中途半端な CMS もどきを作ることに対して今まで以上に「このままじゃいかんよな」と思うことが増えていて、改めて静的サイトジェネレータをもうちょっとちゃんと試してみようと思っていたのが一つ。

もう一つは Rails の Webpacker gem など、バックエンドや CMS に Ruby を使っていてもフロントエンド周りはフロントエンドの作法に則った方がよさそうなので、その組み合わせ方を知っておかないといけないなと思ったこと。

これまで

Jekyll は GitHub Pages に必須という考え方で触っていて、Liquid が面倒くせえなぁ、ERB で素直に書かせてくれよくらいの気持ちだった。

一方で Middleman は Rails の View を触ったことがあれば違和感なく使えた。特に AssetPipeline のようなものが最初から使える部分でも非常に Rails によく似ており、Rails から大きく考え方や手順を変えることなく、Rails の不要なサイトを作る際に重宝するなぁ、くらいの捉え方だった。

設定

  • Jekyll は YAML
  • Middleman は独自の Config オブジェクトになる config.rb

ここだけ見るとどちらでもよさそうに見える。しかし実際はかなり違う。

なんでもかんでも YAML にするのもどうかとは思うが、一方で Middleman の Config オブジェクトは中に書いたコードの context を変更してしまうので気軽に分割できない。独自の DSL ならまだしも、pure Ruby で context が変わってしまうのはとてもやっかい。正直言うと多少でかく複雑になっても YAML の方がマシに見える。

ERB vs Liquid

ぱっと見て最初に気づく違いだと思うのはテンプレートとして ERB を使えるか否かだ。

個人的には Rails でも Haml や Slim には賛成できない派で、ERB で見にくくなるんなら何かを間違えてるんやで派なんだけど、Jekyll では ERB を使わせてくれない。

Liquid template language

Liquid を通してしか仕組みを提供できないので、一見すごくまどろっこしく感じる。適当に Helper っぽいものを足して気軽に Ruby のコードを call することはできない。ちゃんと Liquid Tag として register して使うように手配しないといけない。

対して Middleman は ERB を書けるので、Rails のようにある意味雑にどんどん Ruby のコードを書いていける。

GitHub Pages など制限環境ではそもそも該当するコードを呼べるかどうかという問題はあるものの、どの程度 adhoc に Ruby のコードを呼びたいか によって、特に最初のもどかしさは変わってくるだろう。なれるまでは Liquid::Tag の register は確かにとてももどかしい。

ただ、最近のフロントエンド向けのテンプレートなどは基本的に Liquid のような制限を持っているものが多いので、フロントエンドから入ってくる人にはそれほど大きな違和感はないかもしれない。もう Rails の View を基本に考える時代ではないのかもしれない。

基本の「構成」はよく似ている

  1. Asset Pipeline 的な Sass, CoffeeScript コンパイル機能を持つ
  2. Front Matter, Data Files, Collection を備える
  3. plugin ( extension ) 機構がある

Asset Pipelineの「外」の実現方法は異なるが考え方は似てる

Asset Pipeline 的なものの機能は似ているが、ではこれらを使わずにモダンフロントエンドの力を使う場合はどうしたらよいか。

  • Middleman v4 には External Pipeline があり、割と賢く asset を管理してくれる
  • Jekyll v3 標準では何も支援機構がないので以下のように自分で設定する
    1. フロントエンド → Jekyll の順に build が走るようにする
    2. 開発中はそれぞれ依存するコードを監視していい具合に動作する

といった具合で、機能の有無で差はあるが、考え方が分かればなんとかなる。ただし cache busting も Jekyll には存在しない機能なので、cache busting にこだわるなら Jekyll Assets など外部の何かを頼るなり、Web サーバの設定に頼るなり、設計が必要になる。

参考

Collectionは大きく違う

Front Matter, Data Files には特に言うことはないのだが、Collection には大きな違いがある。

Jekyll の Collection はものすごく乱暴に言うと Data Files のようにドキュメントを扱えるもの、である。collections_dir 以下に置いたドキュメントの固まりをページとは別に自由に取り出せる。Front Matter も使える。

対して Middleman の Collection は Extension の一形態を取っている。これが曲者で、

  • Middleman でコードを書くのは Contract との戦い
  • Middleman には本体外のコードで使える hook が少ない
    • (before|after)_(configuration|build) しかない

の二重の意味で使いにくくなってしまっている。

collection のデータ形式はこうですよ、こういうデータを作ってください、のような Jekyll 的なアプローチではなく、あくまでどの class のインスタンスを受け取るかというプログラミング言語レベルでのインターフェイスが基本になっていて、collection に対して適当な Array を与えるといったことができない。

Collection というよりは Extension の話になってしまっているし、サンプルに引きずられすぎて可能性を狭めているだけかもしれないが、今のところ collection を設定とデータで実現しやすい Jekyll の方が扱いやすそうに見える。

Plugin vs Extension

自分でそれぞれを拡張しようと思った際に選択できる手法について。

Plugins | Jekyll • Simple, blog-aware, static sites

Jekyll は Plugin であり、その Plugin に種類がある。

  • Generators
  • Converters
  • Commands
  • Tags
  • Filters

Generator は site 全体に対して何らかの追加コンテンツを生成する、Converter はコンテンツを変換するもの、Tags, Filters はそれぞれ Liquid に対する追加 といった具合に役割が整理されている。

Middleman: Custom Extensions

対して Middleman は Extension という仕組みであり、Extension がどんな役割を担うのかは割と自由に決められる。Tag かもしれないし、resources を加工するものだったりする。extension から configuration, template などへメソッドを expose して利用する。

Hookはかなり違う

Jekyll は

Hooks | Jekyll • Simple, blog-aware, static sites

site, page, document に対してそれぞれ細かく hook が設定されており、割といろんなことができそうな感じがする。

Middleman: Custom Extensions

対して Middleman は Extension に対して提供されると決まっているうえで、コア機能以外に解放されているのは

  • before_configuration
  • after_configuration
  • before_build
  • after_build

しかない。

Rack

Middleman は標準で Rack アプリだが、Jekyll は独自に WEBRick 上で動いている。Jekyll を Rack で mount したい場合は rack-jekyll が必要。

adaoraul/rack-jekyll: Transform your Jekyll app into Rack application!

情報量

圧倒的に Jekyll の方が多い。

その他 - MiddlemanのContractに気をつけろ

独自に拡張するコードを書こうと思った場合、ごく単純に言うと Jekyll には Liquid, Middleman には Contract という制約がある。

extension のところでの話のくり返しになってしまうが、Middleman の extension を軽く書いてみた1ところ、Contract がヒジョーにつらいという感想しかなかった。

やったことは単に独自の Collection を生成したかっただけなのだが、ドキュメント不足とあいまって中のコードをひたすら追うことになってしまい、一応動くのは動く状態になったがまったく納得のいくデキにならなかった。

Contract とはごく乱暴に言うと Ruby のコードに対して型を定義できるようなものである。

egonSchiele/contracts.ruby: Contracts for Ruby.

型定義をメソッド定義以外に書けるならよい、と自分は思っていたし、その考え方自体は今もあまり変わらないんだけど、実際には「型だけあってもその型通りのデータを外からどう与えるかという API がないとただツライだけ」だなということがよく分かった。

もともと Web プログラミングのように外から文字列でデータを与えることが前提になっているコードに型だけあってもつらいよねというのは思っていたんだけど、ドキュメントや周辺のツール、そして よい設計 が揃って始めて Contract ベースのプログラミングはスムーズに行えるんだなぁということを痛感したのでした。

※ Contract を外して build するオプションもあるんだけど

正直言うと Contract ベースで書くよりは Liquid のレールに慣れる方がドキュメントも事例も見つかるし、たぶんかなり簡単。

まとめ

ERB と Middleman 標準の asset digest にこだわる必要がないなら Jekyll の方がよさそう。

特に Decoupled CMS やモダンフロントエンドなど、外部とどう組み合わせるかという点を重視した際の拡張しやすさは Jekyll の方に軍配が上がると思う。

  1. 実際には必要なかった 

RubyGems自体のアップデート

なんとなく作業してたけどまとめたことがなかったので自分用まとめ。

いつのバージョンからかは知らないんだけど、少なくとも RubyGems 1.3 時代は

$ gem install rubygems_update
$ update_rubygems

で RubyGems 自体のアップデートを行っていく。Windows の場合どうなるんだろうと思ったら

C:\Ruby\bin\update_rubygems.bat

がインストールされていたので、基本的には Ruby のインストールディレクトリに入るのかな? コードもマニュアルも読まずに書いてるけど。

一部で流行りの ~/.gems? 方式でどうするのかは分からない。

AutoPagerize をイントラアプリで

AutoPagerize を常用するようになってから初めて CodeRepos の Trac を見に行って気づいた。

何もせずに changeset を遡れる!

AutoPagerize のメリットは理解していたつもりだったけど、今回がいちばん感動した。なんでかなと思ったんだけど、普段 AutoPagerize の対象になるページは

  • ニュースサイトの分割記事(最近これ多すぎ)
  • 検索結果一覧

くらいで、実はこの二つは AutoPagerize がなくてもある程度の分量の情報を一目で確認できる。

しかし changeset の場合は極端な話、ほとんど情報量のない changeset が途中で混ざっていたりする1ので、一つずつめくらなければいけない状態が結構ストレスだったようだ。自覚はなかったけど、AutoPagerize が利いたときの驚きのでかさがそれを示している。なるほど、これが「ゼロクリックにする革命」なわけだ。

ということで早速イントラの Trac でも AutoPagerize が利くようにしたいなと思ったんだけど、ここで二つ問題が。

  • イントラアプリの SITEINFO を Wedata に上げるわけにはいかない
  • かといって localhost の AutoPagerize を書き換える方法では恩恵に預かれるのは自分一人。喜びを分かち合うことができない。

そこで今回はイントラ内に HTTP で JSON を提供してくれる場所を用意することにした。これなら最初の一回は AutoPagerize の書き換えが必要だけど、以降は SITEINFO を追加していくとどんどん対応アプリを増やすことができる。

イントラの HTTP で JSON を serve

うちの場合、Subversion を WebDAV で運用しているので、Web サーバ周りで特にやることはない。具体的な方法は

JSON を Subversion リポジトリに突っ込んでその URL を AutoPagerize に教えてやるだけ

コード上では

var SITEINFO_IMPORT_URLS = [
   'http://wedata.net/databases/AutoPagerize/items.json',
]

にイントラの JSON の URL を書き足してやればオーケー。

JSON ファイルを作る

SITEINFO を作るにはまず最初

var SITEINFO = [
  {
     url: ,
     nextLink,
     pageElement,
     exampleUrl
  }
]

を書き換えていく。この過程は Wedata に上げる場合と一緒。

Wedata に上げる場合はこのままできあがったものをコピペするだけでよい。AutoPagerize では JSON を受け取ってパースするが、先ほどコピペしたデータを Wedata 側で JSON にして提供してくれるので Wedata に上げる場合は単なるコピペでよいのだ。

しかしイントラ JSON の場合は

自分で Wedata 形式に合わせて JSON にエンコードしてやる必要がある

ここだけが違う。

まず Wedata からどういうフォーマットでデータが来ているのか確認。この間作ったもので見てみるとこんな感じ。

{
  "name": "i\u30bf\u30a6\u30f3\u30da\u30fc\u30b8 (Lite)",
  "updated_at": "2008-11-29T21:33:09+09:00",
  "database_resource_url": "http:\/\/wedata.net\/databases\/AutoPagerize",
  "created_by": "wtnabe",
  "resource_url": "http:\/\/wedata.net\/items\/25850",
  "data": {
    "pageElement": "\/\/table[descendant::hr][position() > 1]",
    "url": "^http:\/\/(?:www\\.)?itp\\.ne\\.jp\/servlet\/jp\\.ne\\.itp ...",
    "nextLink": "\/\/a[text() = \"\u6b21\u3000\u30da\u30fc\u30b8\"]",
    "exampleUrl": "http:\/\/itp.ne.jp\/servlet\/jp.ne.itp.sear.SKWSVmai ..."
  },
  "created_at": "2008-11-28T11:18:17+09:00"
}

ということは

{
  "data": {
    "pageElement": "",
    "url": "",
    "nextLink": "",
    "exampleUrl": ""
  }
}

があればいいんだな。全体としては

[
  {
    "data": {
      "pageElement": "",
      "url": "",
      "nextLink": "",
      "exampleUrl": ""
    }
  },
  {
    "data": {
      "pageElement": "",
      "url": "",
      "nextLink": "",
      "exampleUrl": ""
    }
  },
  ...
]

こんな感じになる。

JSON は意外なほどきっちりしていて、key も文字列でなければいけないとか文字列は " で囲む必要があったりするんだけど、そういうのはいちいち自分で気にするのはばからしいので、完成したら適当なツールを使ってエンコードするとよい。

自分の場合は AutoPagerize 内に直接書いた SITEINFO を別ファイルに書き出して、Ruby なり PHP なりでエンコードして、それを先ほどの JSON ファイルの方にコピペしている。

イントラ AutoPagerize、これは便利。

ちなみに Trac の SITEINFO は 0.10 系と 0.11 系で異なる。CodeRepos はこの段階で 0.11 系でイントラのものは 0.10 系だったので丸ごとコピペしただけでは動かなかった。

  1. typo を直したとか 

DQ4終了、10年来の恨みを晴らす

DQ4 やってたんすよ、ドラクエ、ドラクエ。

※ 以下ネタバレあり、注意

いやー実は以前ファミコンでやったときにね、取り忘れてたんですよ、つのぶえ。人の話をちゃんと聞いてなかったらしくて、最後の戦いでめっちゃ苦労したんです。いれかえできないから。Lv42 くらいまで鍛えたように記憶しています。

で、解いちゃってから当時流行ってた4コマでそのアイテムの存在を知ったんですよ。

えぇぇえぇぇえぇ! つのぶえって何!!

と思ったけどあとの祭り。さすがにやり直す気力はない。

あれから10年以上経ち、DS で再挑戦。やっと想定された通りの解き方ができました。なんて強力なんだ、スクルトとフバーハのコンボ。

しかしリメイク版の本当の苦しみはその後にありました。第6章の意味が分からねぇ。なんか知らんけど時間がちょっと戻っててナニしたらいいのか分からない。まぁまた人の話聞いてなかっただけかもしれないけど。なんかすれちがい通信に使う町を思いっきり整備したらいいんだ!と勘違いしてせっせと頑張るも無駄。タネが分かってからは延々と同じ戦闘のくり返し。ひどい。もう少しストーリー作ってくれたってよかったじゃないか。まぁハッピーエンドはハッピーエンドなんだけどさ。ハッピーエンドっぷりは本編よりもステキ。ドラクエは FF のようには救えない感がないところが好きだな、やっぱり。

Creole とな

Creole: Home

via

いよいよ本家と言えそうなところで Wiki 記法の標準化を検討し始めているっぽい。

でも。個人的にはこの手のプロジェクトではいい成果が出そうにない気配をいつも感じている。もちろん標準案が完成したらそれはとてもいい成果だろう。でもそれが Web 向けの構造化テキストの標準として本当に「いいもの」になるかどうか、どうにも疑問なのだ。

現段階でもいきなり bold を <strong> で、italic を <em> で実現しようとしているところが気になって仕方がない。bold の <strong> はまぁいいとしよう。でも italic は <em> とは限らないはずだ。たまたま HTML ブラウザのデフォルトスタイルで <em> が italic になっているだけで、italic の意味するところが <em> であるというわけではない。この二つはイコールではなくて意味的には一方通行のはずである。italic が <em> を意味しないとは言わない。しかし <em> とは限らないだろう。

どうせ HTML への変換を前提に考えているんだから、最初から obsolete な italic や bold という要素を入れなければいいのになぁ。それとも物理マークアップ推奨派の人が多いのか? それはそれで合点がいくんだけど。bold や italic は文脈に応じてこういう意味になるという慣用があるので、それに従えばよいという考え方もなくはないと思うし、論理マークアップ前提にするとどうしても記法が増えてしまうので、シンプルに保つという意味では物理マークアップの方が都合がよい。

でもだったらそのものずばりの物理マークアップを推奨してくれた方がよほど潔いと思うんだよな。というかこれはあれか、Wiki 記法ではなく XHTML の方を問題にすべきなのか? でも XHTML の考え方も理解できるしなぁ。

Wiki 記法がメール上での利用など、HTML 以外のシーンも考慮する気があるのであれば物理マークアップ推奨はアリ、考慮する気がないのであれば HTML の思想に従うべき、とここではいったん単純化してみることにしよう。

で、それとは別に、個人的には引用と注の記法はぜひ考えてほしい。普通に文章書くときにはこれこそ大事だと思うんだけど、あんまり Wiki 界の人(って誰)は必要性感じてないのかな?

メッセンジャー

  • プラットフォームを選ばず
  • ファイル転送可
  • 特定のベンダーに囲い込まれない

そんなメッセンジャーないかな。MacOS Classic まで含むのでメッセンジャ−を諦めて irc ってのがいちばんだとは思うんだけど。

なんか前にもこんなこと書いたような気がするな。

IQサプリ

伊東四朗はきらいじゃないが、深夜のときの香林坊出身篠井英介さんの方が好きだった。

まーそれはともかくマッチ棒クイズってマジカル頭脳パワー思い出しますね。ダメですか。オヤジですか。うっさいわ。

referer のカット

Referer リクエストヘッダの除去

つーことは。結局 local の Wiki からたどりましたよーという referer をカットしようと思ったら透過proxy 立てるのがベストってことですね。

RSS はメールに似ている?

ふと思いついたネタ。ちゃんと書けるかどうか分からないけどとりあえず見出しを置いておく。

ネタ元は textfile.org 経由で「BulknewsとRSSの現在・未来」CNET Japan の楳田blog のゲスト、Bulknews の宮川さん。

マージーでーーーーー

米IBM、パソコン部門を中国大手に売却か、米紙報道

デスクトップ型からノート型まで全範囲のパソコン部門を、中国のパソコン・メーカー最大手に売却する方向で交渉していることが3日分かった。

ThinkPad が、ThinkPad がーーーーーーっ。(はいここムスカ風で)

orz orz orz orz orz orz orz orz orz orz

ThinkPad は残してください。お願いします(T_T) あの作り、あのサポートは IBM でなければ実現できませんて。プロの弁当道具箱、ThinkPad は家電メーカーの作る雑魚とは違うのだよ。雑魚とは!

販売価格の安さではない市場価値を持つ製品、メーカーは多くありません。IBM にはその舞台から下りてほしくないなぁ。Apple じゃダメなんですよ。なぜなら Apple はユーザーの声を本当に真剣には聞かないから。Apple ユーザーはそれを分かって使っているけど、やっぱそれは健全な姿じゃない。IBM のビジネスに対する姿勢こそが大事にされるべきだと思うのです。

About

例によって個人のなんちゃらです

Recent Posts

Categories

Tool 日々 Web Biz Net Apple MS ことば News Unix howto Food PHP Movie Edu Community Book Security Text TV Perl Ruby Music Pdoc 生き方 RDoc ViewCVS CVS Rsync Disk Mail FreeBSD Cygwin PDF Photo Zebedee Debian OSX Comic Cron Sysadmin Font Analog iCal Sunbird DNS Linux Wiki Emacs Thunderbird Sitecopy Terminal Drawing tDiary AppleScript Life Money Omni PukiWiki Xen XREA Zsh Screen CASL Firefox Fink zsh haXe Ecmascript PATH_INFO SQLite PEAR Lighttpd FastCGI Subversion au prototype.js jsUnit Apache Trac Template Java Rhino Mochikit Feed Bloglines CSS del.icio.us SBS qwikWeb gettext Ajax JSDoc Rails HTML CHM EPWING NDTP EB IE CLI ck ThinkPad Toy WSH RFC readline rlwrap ImageMagick epeg Frenzy sysprep Ubuntu MeCab DTP ERD DBMS eclipse Eclipse Awk RD Diigo XAMPP RubyGems PHPDoc iCab DOM YAML Camino Geekmonkey w3m Scheme Gauche Lisp JSAN Google VMware DSL SLAX Safari Markdown Textile IRC Jabber Fastladder MacPorts LLSpirit CPAN Mozilla Twitter OpenFL Rswatch ITS NTP GUI Pragger Yapra XML Mobile Git Study JSON VirtualBox Samba Pear Growl Mercurial Rack Capistrano Rake Win RSS Mechanize Sitemaps Android JavaScript Python RTM OOo iPod Yahoo Unicode Github iTunes God SBM friendfeed Friendfeed HokuUn Sinatra TDD Test Project Evernote iPad Geohash Location Map Search Simplenote Image WebKit RSpec Phone CSV WiMAX USB Chrome RubyKaigi RubyKaigi2011 Space CoffeeScript Nokogiri Hpricot Rubygems jQuery Node GTD CI UX Design VCS Kanazawa.rb Kindle Amazon Agile Vagrant Chef Windows Composer Dotenv PaaS Itamae SaaS Docker Swagger Grape WebAPI Microservices OmniAuth HTTP 分析基盤 CDN Terraform IaaS HCL Webpack Vue.js BigQuery Middleman CMS AWS PNG Laravel Selenium OAuth OpenAPI GitHub UML GCP TypeScript SQL Hanami Document SVG AsciiDoc Pandoc DocBook Develop Jekyll macOS Node.js Vite Heroku Transformer AI Data Cloud Wasm