Octopress周りをちょっと整理でもしてみようかと思い、 gemを全般的に新しいのにアップデートしてみました。
特にJekyllが2.5.3から3.3.1と、3系になったのでちょっと色々といじる必要があって 大変だったのでそのまとめ。
Octopressでなくても素のJekyllでの2から3への移行の参考にもなると思います。
Octopressのバージョン
Octopressは2.5のバージョンを使っています。
3.0の開発もありますが、こちらはOctopress自体がgemとして配布されていたり 大分構造が違います。
ただ、どちらも最終コミットが1年前。。。
3.0の方が活発に開発されていくならいずれ移ろうかとも 思ってましたが、どうも停滞中なので 今のところ苦労してまで敢えてOctopress 3.0に移行する必要はないかな、と思っています。
octogray
Octopress用のテーマです。
変更されたGemfile/Rakefile/_config.yml等も含んでいてsetupスクリプトを走らせると必要な設定を一通りしてくれる様にもなっています。
このテーマをJekyll 3用にアップデートしました。
Jekyll 3
Jekyll 3に変更するにあたって一番意味がありそうなのは 生成速度が上がっている、という点。
このサイトのビルドはwerkerで行ってますが、レンダリング時間は Jekyll 2のときと3のときとでそれ程変わらず2分前後になっています。 若干3の方が速い様にも見えますが、一回一回結構差が大きいのと 3の方はまだビルド数が少ないので、まあ今のところ同じくらいかちょっと速いかな、といった感じ。
ビルドスピードに関しては下のようにちょっと工夫してたりしますが、 まだ改善の余地がありそうなのとJekyll 3でまた出来る事もあるかもしれないので また見てみたい所。
他にもシンタックスハイライトなどがデフォルトで使えるようになったり色々アップデートがあるみたいで、 GitHub Pagesのジェネレーターも今年の始めの頃にすでにJekyll 3になっています。
仕様のアップデートに関しては、おそらく今までに作ったプラグイン等、 もっと簡単にうまく書けたりパフォーマンスも良く出来たりするものもあると思いますが、 取り敢えず今回は動く様に、ということでアップデートをしています。
以下、アップデートをする際にしたメモなど。
JEKYLL_ENV=production
jekyll build
を呼ぶ際に使われるJEKYLL_ENV
という環境変数があり、
3ではこれにdevelopment
という値が入っています。
これだといくつかの要素を無視したり、またシンボリックリンクがsource
内にあると
そのままシンボリックリンクとしてコピーします。
勿論そのままでは出来たものを他に持っていって使う事も出来ません。
さらに2回目以降もシンボリックリンクをコピーしようとするので、既にあるシンボリックリンクとバッティングして エラーになります。
実際に公開するものを作るには
$ JEKYLL_ENV=production jekyll build
とこの値をproduction
にします。(環境変数として設定してしまっても勿論OK。)
ctopressではgenerate
というタスクの中でjekyll build
を呼んでますが、
development
にするメリットはないのと、シンボリックリンクを含むようなsource
を使ってて
development
だと使いものにならないので
Rakefileの該当箇所にJEKYLL_ENV=production
を追加しました。
Plugin中のsite.posts
プラグインの中でブログポストの一覧を呼ぶ時に、2ではsite.posts
と呼んでいましたが
3ではsite.posts.docs
がこれにあたります。
一方site.pages
の方はそのまま同じくsite.pages
です。
この辺はビルド時にwarningが出る(エラーにはならないで一応2の時の様に良しなにしてくれる)ので発見しやすいです。
また、ポストやページを書く際にLiquidタグの中でsite.posts
等を使う事もありますが、
この場合はsite.posts
のままです。プラグインの中だけ変更する必要があります。
さらに、このpostsの順番が前と違う?みたいで、
前は古い方から入っていたため、
アーカイブを作る時に以前は並びを逆順にしてたんですが(新しいものを上に書くため)、
Jekyll 3ではどうも逆順に入ってるらしく
この逆順にする部分をはずしました。
1 2 3 4 5 |
|
こんな感じ。
Block/TagのPlugin中のcontext['page']
について
BlockやTagのプラグインを作る際、継承してる関数の引数にあるcontext
から
context['page']
を持ってくることでページの情報を取ってこれます。
このオブジェクトはハッシュの様な機能も持っていて、どの様keyを持ってるかチェックすることがあるのですが、 Jekyll 2では
context['page'].has_key?("xxx")
としていましたが、Jekyll 3ではこのメソッドは常にtrueを返します。 実際にチェックしたい時には
context['page'].key?("xxx")
を使います。
has_key
の方は親クラスが持っていてkey
はこのオブジェクトのクラスで定義してる感じですが、
以前はhas_key
を再定義していたのが何故か違うメソッドを導入したようです。
まあ、なんか便利なことがあるんでしょうが、ここだけ見ると結構混乱のもとなので注意しないといけません。
(trueを返すだけなのでこの場ではエラーにならず、その後実際呼ぼうとしてkeywordエラーが起こる。)
_config.yml/Gemfileのアップデート
ビルド時に出るwarningやerrorに従って
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
|
こんな感じの変更。
またこれらのwarning等と一緒に出てきたgemを追加せよ、というものがあって、
Gemfileにjekyll-pagenate
とpygments.rb
を追加。
gemojiは古いバージョンのまま
Jekyll 3とは関係無いですが、ついでにgemを全て最新のにしてみたところ、 gemojiというgemで問題が起こりました。
octopress-gemojiというプラグインを作って この中で使っているんですが、gemoji 2.1の時にはimages/emoji/の中に 絵文字の画像が全て入っていました。
これが最新の3.0では無くなってimages直下に、もともとimages/emoji直下に 置かれていたunicodeに登録されてない一部の絵文字だけが残っています。
実際にサイトとかで絵文字を使いたい場合には macOS Sierra or lateを用いて抜き出してください、とあります。。。
手元にSierraはあるので一回抜き出してプラグインのレポジトリに入れてしまう、と言う手も無いでも無いですが、 ちょっとあれなのでこのgemに関しては古い2.1を使います。
permalinks
Jekyll 2の時、_config.ymlで
permalink: /blog/:year/:month/:day/:title/
という設定をしていました。これでブログポストのURLは
http://rcmdnk.github.io/blog/2016/12/28/computer-git/
みたいになります。
(blog/2016/12/28/computer-git/index.html
が実際のページのファイル)
一方、source
ディレクトリ直下に適当なMarkdownやHTMLを置いておくと、
たとえばsource/testpage.mdというファイルを作れば
そのままhttp://rcmdnk.github.io/testpage.html
と言ったHTMLが出来ていました。
同じ設定のまま3でビルドしてみるとこのtestpageに関して
/testpage/index.html
というファイルが出来る様になっていました。
ただし、直接HTMLを置いてYAMLの無いものだと何もせずにそのままコピーされるのでディレクトリを作ったりはしません。
結論から言うと、2と同じ様な動作にさせたい場合、_config.ymlの設定を
collections:
posts:
permalink: /blog/:year/:month/:day/:title/
と変更します。
これでsource/_posts/以下にあるブログポストのみにこのpermalinkが適用され
他にはデフォルトのdate
という定義が使われ、この定義だと
ディレクトリを作らずにHTMLのファイル名にもとの名前が使われます。
以下ちょっと細かい話ですが、ちょっとこの辺きちんと見ないと理解できなかったので 見てみました。
2.5の方ではpost.rbの中で
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
という関数が定義されていて、ここでsite.permalink_style
という値が使われてますが、
これは_config.ymlでpermalink
で指定したものになります。
pretty
とかdate
(これがデフォルト)とかを指定すると指定のフォーマットを使い、
それ以外が指定されているとそのまま入力をフォーマットとして使う様になっています。
一方、page.rbの中では
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
となっていて、pretty
かつファイルがHTMLファイル(もしくはMarkdownから変更されたHTML)で
かつindex.html
でないと気に限りファイル名のディレクトリを作って
その中にindex.html
を作る様になっています。
つまり、上の様に/blog...
みたいな定義だと一番下に行って
そのファイル名のままのHTMLが出来ます。
一方、3.3の場合だとpost.rbではなくdocument.rbになりますが、この中で
1 2 3 |
|
となっていて、このcollection.url_template
は
1 2 3 4 5 |
|
で定義されています。
さらに
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
という定義もあります。
簡単に解釈すると、documentの中で呼ばれるurl_template
は
collection
のurl_template
なのですが、
posts
のcollection
に関しては直接
collections:
posts:
permalink: /blog/:year/:month/:day/:title/
と指定しても
permalink: /blog/:year/:month/:day/:title/
とグローバルに指定してもこの値が入ってきます。
なのでどちらで指定しても同じになります。
(pretty
などを変換するメソッドもconfiguration.rbの中にあって2と変わらない定義です。)
一方、page.rbの方は
1 2 3 4 5 6 7 8 9 |
|
となっていて、このadd_permalink_suffix
は
1 2 3 4 5 6 7 8 9 10 11 12 |
|
となっています。
通常の名前付きのHTMLファイルを置いた時にはこのadd_permalink_suffix
が呼ばれるわけですが、
これを見ると自分でpermalink
を設定した場合は一番下に行き、
URLの末尾の構造だけその設定したものと同じ様になる様にしています。
つまり、permalink
でタイトルをHTMLのファイル名に残すような設定にしていれば
ページの方でもファイル名を残す様なURLになります。
一方、上で設定したように最後が/
で終わっていればページの方でも
ファイル名のディレクトリを作ってその中にindex.htmlを作る様になります。
2ではpretty
かそうでないか、だけで分けていたものが
3では独自設定の場合それに沿うような形になるようになっています。
ということで、例えば404.mdの様なファイルも
sourceの下に置いていてそれを404.htmlとして変換したかったりもするわけで、
ページに関しては勝手にディレクトリを作る様なことはしたくないので
上に書いたようにcollections
を使って指定する様にしています。
もし404.mdとか特定のページだけをそうしたいなら
そのページのYAMLブロックにpermalink
を書いても良いわけですが。
で、一番の問題はこの辺のドキュメントがきちんとまだ整理されてないことです。
これらを見ると
ページに関しては完全に独立で基本date
のフォーマットで出力する、という感じに見れ、
変えたいなら各ページのYAMLブロックでの指定、という感じがします。
実際、stackoverflowにも同じ様な話があって、 中の人?っぽい人がサポートしようとしてますが結局良くわからずじまいで終わっています。
html - Jekyll - How do I create pages in the root directory? - Stack Overflow
おそらくこのアップデートは意図的にやってるんだと思いますが、 ドキュメントがドキュメントなのでパット見良くわからないわけです。
また、上のcollections
を使った書き方は別のところにあります。
この辺の話どうなってるのかな、と思ってレポジトリを見てみたら、 2日前にまさにそんな感じのドキュメントのアップデートのPull Requestが出てました。
Improve permalinks docs by tomjohnson1492 · Pull Request #5693 · jekyll/jekyll
まだペンディング中ですが、これにcollections
による書き方と、
上の様な関係性を加えて、permalink
のところに全部まとめてもらえると正しく分かる様になるかな、と。
hookとか
Jekyll 3の開発者側の大きな変化として、ビルドのコマンドの中の 様々なところにHookが仕掛けられる様になったことだと思います。
サイト全体の情報をまとめて載せたかったり、 各ページのレンダリング毎に色々やりたかったりする時、 通常のプラグインを作るだけでは上手く行かないこともあります。
そういった時、Octopressでは octopress/hooks というツールを用意していて、ビルド時の色々な所にタスクを差し込める様にしていました。
Jekyll 3のjekyll/site.rb
を見てみると色々な所にHooks
が入ってます。
これでoctopress/hooksが無くても同じようなことが出来る様になっています。
Octopressの作者の人もJekyll 3の機能で特にこれが待ち望んでたものだと言ってたり。
octogray の中でもoctopress/hooksを使ったりモンキーパッチを入れたりしてますが、 そのうちこれもちゃんと整理していこうかと。
Filters
追記: 2017/01/24
Jekyll 2で何かしら自分でLiquid Filter({{xxx|my_filter}}
の様に使えるfilter)を追加したい時、
1 2 3 4 5 6 7 |
|
みたいにしておくとAfter Filter: xxx
の様に変換するフィルターが自作できました。
この様なFilterの仕組みをplugins/category_generator.rbの中で使っています。
octograyでは同じようなplugins/tag_generator.rb を作ってタグの管理も行っています。
この中でカテゴリーやタグをリンク化するフィルターを登録していましたが これが動いていませんでした。(ポストの下にあるPosted: …の部分。)
Jekyll 3ではFiltersというモジュールも特別なものではなくなり Filterを定義した後にきちんと登録の作業をしないといけないようです。
1 2 3 4 5 6 7 8 9 10 |
|
という、最後のregister_filter
がJekyll 2では無かったのが3ではあります。
ということで、ただ書くだけではダメなので敢えてFiltersの中に入れずに別途 モジュールを作って登録する様にしました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
こんな感じで登録してあげればcategory_links
等が使える様になります。
追記ここまで
まとめ
大概の所はビルド時にwarningやerrorが出てそこから追えば すぐわかるところが大体でしたが、 permalinksの所はドキュメントを見ると内容がアップデートされてないので 逆に混乱してしまったりして、最終的にちゃんとコードを追わないとわからなかったので面倒でした。
でも一通り出来たと思うのでアップデートしてこれも作っています。
ということで、もし何か変なところとかあったら指摘してもらえるとありがたいです。