2018-10-27

Nikola を始める話

info
  • 現在はNextJSに引っ越したのでNikolaは使っていません。

前回の引っ越し から 約半年ほどしか経っていませんが 先日ブログを Miyadaiku から Nikola に変えました。

ついでに少しレイアウトも変えたけど多少は見やすくなりましたか?

Nikola は Miyadaiku と同じく Python製の 静的サイトジェネレータです。

実は前から少し気になってました(意味深

経緯

このブログの場合は技術記事をメインで書いています。

特殊な例ですが、記事ごとに環境を分けられれば状況の再現や検証が容易なので 設定ファイルなどを記事と同じディレクトリに置いて管理をしたいと思っていました。

そのとき 関係ないファイルがビルドされるとエラーが発生したりビルドが長引いたりするため、 ビルド対象のファイルから除外する必要がありました。

Nikola は除外設定ではありませんが、ビルド対象のファイルを自分で選択できるようになっているので 要件を満たすことができ、採用となりました。

始め方

詳しくは Getting Started | Nikola を見ればいいんですが少しだけ解説。

インストール

必要であれば仮想環境を作ってから

$ python3 -m venv venv $ source venv/bin/activate

nikolaをインストールします。

(venv) $ pip install nikola

簡単ですね。

初期化

init コマンドを使って サイトの初期化ができます。

ディレクトリに移動するとこんな感じのファイル構成になってます。

(venv) sitename $ ls README.txt conf.py files galleries images listings pages posts templates

用途としては、次のような感じだと思う。

conf.py
  • Nikolaの設定ファイル。
files/
  • 記事以外の静的ファイル(ビルド対象でないファイル)を入れるディレクトリ。そのままの構成で output に出力される。
galleries/
  • 記事として公開したい画像などのメディアファイルを入れるディレクトリ(使ってないので詳細は不明)
images/
  • 画像ファイルを入れるディレクトリ。サムネイルも勝手に作ってくれるっぽい?(使ってないので詳細は不明)
listings/
  • ファイルの一覧を見せるためのディレクトリ。ソースファイルとかを入れるだけで一覧ページを作ってくれる(使ってないので詳細は不明)
pages/
  • 固定ページを見せるためのディレクトリ(使ってないので詳細は不明)
posts/
  • 記事を入れるディレクトリ。ブログ等の時系列な記事はこの中に入れる。
templates/
  • 記事のテンプレートを入れるディレクトリ。
  • テーマのテンプレートではない
  • 今の所は使ってないため詳細はわからないが、便利だったら使うかも

ブログ記事を書く場合、 new_post コマンドを使うと posts/ ディレクトリに空の記事ファイルを作成してくれます。

(venv) sitename $ nikola new_post Creating New Post ----------------- Title: test Scanning posts........done!

ファイルの中身はこんなかんじ

info
  • posts/ 配下にフラットに記事ファイルを置いておくのが Nikola で想定される一般的な使い方だと思います。
  • 個人的な意見を言わせてもらうと記事が多くなるにつれて、運用するのが辛くなってくるので、 頻繁に見返したり書き換えたりする場合はディレクトリを区切ったほうがよいと思います。
  • 区切った場合であっても その中を辿ってビルドしてくれます。
  • Miyadaiku の場合は このディレクトリ構成を全く同じように保ってファイルを出力するのですが、
  • Nikola の場合は 記事を配置したディレクトリパス(posts/ からの相対)を起点として slug に指定した文字列をつなげたのが最終的な公開パスとなります。
  • この記事は posts/2018/start-nikola/ というディレクトリの index.rst というファイルに 書いているんですが、slug は常に index としています。
  • これにより記事を置いているディレクトリパスがそのまま公開パスとなります
  • 前述した new_post コマンドはファイルしか作成できないため、 自分の場合は 記事の雛形となるディレクトリを毎回コピーして作るようにしています。 (これはMiyadaikuの頃から同じ)
  • sitemap.xml includes not published posts · Issue #3180 · getnikola/nikolaEnvironment (if reporting a bug) Python Version: 3.6.5 Nikola Version: 8.0.1 Operating System: Mac Description: It seems Nikola's sitemap includes not published posts, but I don't want it to publis...https://github.com/getnikola/nikola/issues/3180

ビルド

記事のビルドは build を使います。

(venv) sitename $ nikola build Scanning posts........done! . scale_images:output/images/frontispiece.jpg . scale_images:output/images/illus_001.jpg . render_posts:timeline_changes . render_posts:cache/pages/dr-nikolas-vendetta.html . render_posts:cache/pages/path_handlers.html . render_posts:cache/pages/creating-a-theme.html Trying "doc" as canonical role name. . render_posts:cache/pages/charts.html . render_posts:cache/pages/social_buttons.html . render_posts:cache/pages/listings-demo.html . render_posts:cache/pages/1.html . render_posts:cache/pages/bootstrap-demo.html . render_posts:cache/pages/extending.html . render_posts:cache/pages/internals.html . render_posts:cache/pages/manual.html . render_posts:cache/pages/quickref.html . render_posts:cache/pages/quickstart.html . render_posts:cache/posts/1.html . render_posts:cache/pages/theming.html . render_sources:output/pages/dr-nikolas-vendetta/index.rst . render_sources:output/pages/path-handlers/index.rst . render_sources:output/pages/creating-a-theme/index.rst . render_sources:output/pages/charts/index.rst . render_sources:output/pages/social_buttons/index.rst . render_sources:output/pages/listings-demo/index.rst . render_sources:output/pages/about-nikola/index.rst . render_sources:output/pages/bootstrap-demo/index.rst . render_sources:output/pages/extending/index.rst . render_sources:output/pages/internals/index.rst . render_sources:output/pages/handbook/index.rst . render_sources:output/pages/quickref/index.rst . render_sources:output/pages/quickstart/index.rst . render_sources:output/posts/welcome-to-nikola/index.rst . render_sources:output/pages/theming/index.rst . render_galleries:output/galleries . render_galleries:output/galleries/demo . render_galleries:output/galleries/index.html . render_galleries:output/galleries/rss.xml . render_galleries:output/galleries/demo/tesla4_lg.thumbnail.jpg . render_galleries:output/galleries/demo/tesla4_lg.jpg . render_galleries:output/galleries/demo/tesla_tower1_lg.thumbnail.jpg . render_galleries:output/galleries/demo/tesla_tower1_lg.jpg . render_galleries:output/galleries/demo/tesla_conducts_lg.thumbnail.jpg . render_galleries:output/galleries/demo/tesla_conducts_lg.jpg . render_galleries:output/galleries/demo/tesla_lightning2_lg.thumbnail.jpg . render_galleries:output/galleries/demo/tesla_lightning2_lg.jpg . render_galleries:output/galleries/demo/tesla_lightning1_lg.thumbnail.jpg . render_galleries:output/galleries/demo/tesla_lightning1_lg.jpg . render_galleries:cache/galleries/demo/index.html . render_galleries:output/galleries/demo/index.html . render_galleries:output/galleries/demo/rss.xml . copy_files:output/favicon.ico . copy_files:output/images/nikola.png . render_listings:output/listings/index.html . render_listings:output/listings/hello.py.html . render_listings:output/listings/hello.py . render_listings:output/listings/__pycache__/index.html . copy_assets:output/assets/css/bootblog.css . copy_assets:output/assets/css/bootstrap.min.css . copy_assets:output/assets/css/theme.css . copy_assets:output/assets/js/jquery.min.js . copy_assets:output/assets/js/bootstrap.min.js . copy_assets:output/assets/js/popper.min.js . copy_assets:output/assets/css/nikola_rst.css . copy_assets:output/assets/css/nikola_ipython.css . copy_assets:output/assets/css/html4css1.css . copy_assets:output/assets/css/rst.css . copy_assets:output/assets/css/ipython.min.css . copy_assets:output/assets/css/rst_base.css . copy_assets:output/assets/css/baguetteBox.min.css . copy_assets:output/assets/js/html5.js . copy_assets:output/assets/js/fancydates.js . copy_assets:output/assets/js/gallery.min.js . copy_assets:output/assets/js/fancydates.min.js . copy_assets:output/assets/js/gallery.js . copy_assets:output/assets/js/baguetteBox.min.js . copy_assets:output/assets/js/html5shiv-printshiv.min.js . copy_assets:output/assets/js/justified-layout.min.js . copy_assets:output/assets/js/moment-with-locales.min.js . copy_assets:output/assets/xml/atom.xsl . copy_assets:output/assets/xml/rss.xsl . copy_assets:output/assets/css/code.css . render_taxonomies:output/index.html . render_taxonomies:output/categories/cat_nikola/index.html . render_taxonomies:output/categories/blog/index.html . render_taxonomies:output/categories/demo/index.html . render_taxonomies:output/categories/nikola/index.html . render_taxonomies:output/categories/python/index.html . render_taxonomies:output/2012/index.html . render_taxonomies:output/archive.html . render_taxonomies:output/categories/index.html . render_pages:output/pages/handbook/index.html . render_pages:output/pages/quickstart/index.html . render_taxonomies:output/categories/python.xml . render_pages:output/pages/creating-a-theme/index.html . render_taxonomies:output/rss.xml . render_pages:output/posts/welcome-to-nikola/index.html . render_pages:output/pages/theming/index.html . render_pages:output/pages/internals/index.html . render_pages:output/pages/path-handlers/index.html . render_pages:output/pages/bootstrap-demo/index.html . render_taxonomies:output/categories/nikola.xml . render_pages:output/pages/charts/index.html . render_taxonomies:output/categories/cat_nikola.xml . render_pages:output/pages/social_buttons/index.html . render_pages:output/pages/listings-demo/index.html . render_pages:output/pages/dr-nikolas-vendetta/index.html . render_taxonomies:output/categories/blog.xml . render_pages:output/pages/about-nikola/index.html . render_pages:output/pages/quickref/index.html . render_pages:output/pages/extending/index.html . render_taxonomies:output/categories/demo.xml . create_bundles:output/assets/css/all-nocdn.css . create_bundles:output/assets/css/all.css . create_bundles:output/assets/js/all-nocdn.js . create_bundles:output/assets/js/all.js . sitemap:output/sitemap.xml . sitemap:output/sitemapindex.xml . robots_file:output/robots.txt

serve コマンドでサーバを起動できます。

(venv) sitename $ nikola serve INFO: serve: Serving HTTP on 0.0.0.0 port 8000...

アクセスしてみると

見れましたね。やったぜ。

info
  • (venv) sitename \$ nikola auto とすることで サーバ起動ファイルの変更監視 を並行して行えます。

conf.py の修正

自分の場合は自分でテーマを作っているためいくつか関係のないところもありますが、 基本的には 次の箇所を変更し、ほかはいじってません。

特筆するところは以下の3箇所です。

  • THEME = \"cronote\" はテーマの指定です。後述します。
  • COPY_SOURCES = False にしたのは 記事のHTMLの元になった rst が同じ名前(拡張子を除く)で勝手に公開されるのを防止するためです
  • POSTS の 第2インデックスを \"\" (空文字) にしているのは 記事が出力されるパスのプリフィックスを消すためです。
    • これにより元の記事のパスを変えずに保持できました。

テーマ

設定ファイルの THEME 変数ではテーマ名を指定します。

私の場合は上記で cronote というテーマを使っているのですが、 これは自作のテーマです。

自作が面倒な場合は Themes for Nikola で 自分の好きなテーマを選択しましょう。(2018/10時点で)35種類あります。

自作する場合、このあたりを参考にして書くと良いでしょう。

jinja2mako というテンプレートエンジンが使えます。

HTML の改変

実は以下のツイートは Nikola へのリプレース直後に発生した問題でした。

Metaタグでの文字コード指定が抜けていたことが原因で発生していたので、 <meta charset="utf-8" /> に指定したら解消しました。

しかし、テンプレートには <meta http-equiv="content-type" content="text/html; charset=UTF-8" /> (確か) とちゃんと記述されていました。なんで削られたんだろう。謎です。

また、特殊なHTMLタグを描画したい場合も、期待通りに出力されないことがあります。

例えば私のブログでは Google のカスタム検索 プラグインを 埋め込んでるんですが、 以下のようなHTMLをテンプレートに記述したところ

<div> <script> (function() { var cx = '004084638320604569659:o5gzqwuvr4g'; var gcse = document.createElement('script'); gcse.type = 'text/javascript'; gcse.async = true; gcse.src = 'https://cse.google.com/cse.js?cx=' + cx; var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(gcse, s); })(); </script> <gcse:search></gcse:search> </div>

<gcse:search></gcse:search> の部分が <search></search> に変換されてスクリプトが動かないということがありました。

たぶんビルド後のHTMLを一度パースしたときに 対応してない一部の情報が欠落してるんじゃないかなと思います。

パースの対象にならないように script タグの中で出力するとうまくいきます。

<script> document.write('<gcse:search></gcse:search>'); </script>

Tag のパーマリンクが小文字に変換される

簡単に言うと Python というタグは python というパーマリンクでアクセスできます。

このブログの場合は Python のタグは http://note.crohaco.net/tags/python/ です。

なので テンプレートを自作する場合は

<a href="/tags/{{ tag.lower() }}/">{{ tag }}</a>

のようにします。

v7 用のプラグインが v8 で動作しない

実際に version 7 は使ったことないので正確にはわからないんですが、 一部の公式プラグインは version 8 で動作しませんでした。

少し直せば動くので v8 のプラグインを見ながら修正してみてください。 意外と簡単です。

作ったプラグインについては別記事で公開します。

docutils の writer が html4css1 で動作している

Nikola は 内部的に docutils を使って描画しているんですが、 writer は html4css1 を使っているようです。 そのため、一部で意図しない出力となる可能性があります。

自分の場合は 前にMiyadaiku を使っていたときは、 field-list の出力が dl (definition list) タグで出力されていましたが、 Nikola に変えて table で出力されるようになりました。

たとえば

:URL: https://note.crohaco.net/ :名前: くろのて

みたいなやつです。

html4css1 モードで dl タグで出力したい場合は definition list 記法を使って以下のように書きます。

URL https://note.crohaco.net/ 名前 くろのて
warning
  • definition list ではヘッダと内容の間に空行を入れてはいけません。 (内容がただの引用文になります)
info
  • 最初は原因が全くわからなかったんですが、ぼくらの @shimizukawaさんが 10分 で解決してくれました
  • shimizukawa [10:08] https://repo.or.cz/docutils.git?a=blame_incremental;hb=28086129e5087833cb8da00b920f92f3f533104f;f=docutils%2Fdocutils%2Fwriters%2F_html_base.py#l720 https://repo.or.cz/docutils.git?a=blame_incremental;hb=705901dedf01dcbe499f3eb1591bbaa255f59571;f=docutils%2Fdocutils%2Fwriters%2Fhtml4css1.py#l353 ふむ 使ってるdocutilsのwriterが違うんだね `docutils.writers.html4css1` の場合、field-listはtableで出力される `docutils.writers.html5_polyglot` の場合、field-listはdl/dtで出力される Sphinxでも、html5 writerを使うオプションを有効にしたら同じ結果になりそう http://www.sphinx-doc.org/ja/master/usage/configuration.html#confval-html_experimental_html5_writer
  • なんだただの神か

ちなみに dl タグを horizontal な テーブルのように表示するためには CSS を当てる必要があります。 今どきなら flexbox ですね。

参考

dl要素をtableのような段組レイアウトにする - 25egg:Webデザイナー備忘録dt,dd要素をtableのような横並びのレイアウトにします。 横幅を縮めた際は縦並びに変更しています。 flhttps://blog.25egg.com/?p=235

終わりに

変える前は、Miyadaiku でできたことが全部 Nikolaでできるのか?という不安があったんですが、 一応全部できたと思っています。

Nikola は プラガブルな設計になっているので 機能が足りない場合は プラグインを使うことで概ね補完できそうです。

社内だと matsupods さんが仲間です。 (The Pym Particle)

Docsはわかりやすくて、記事を書くまで特に苦労することはなかった感じです。 Travis CIの説明もわかりやすく、ファーストトライでできました。(Pelicanはかなり苦労していて、一晩潰れた記憶あります)

(from BP slack)

割と機能が豊富なので、みなさんもどうでしょう(巻き込んでいくスタイル)

参考

Nikolaでブログ - QiitaNikolaってなに?NikolaはPython製の静的サイトジェネレータです。公式サイト: https://getnikola.com静的サイトジェネレータはJekyllやHUGO、Hexo…https://qiita.com/driller/items/4d998ca765717c7e0a6c Nikola を windows でやるぞ [2] - ゆくゆくは有へとテンプレをみる Nikola のテンプレは…少ない……。Jekyll とかに比べるとそりゃ、まあね。 nikola install_theme [theme name] でインストールできる。 [theme name] はここで探してちょ: Themes for Nikola bootstrap3 系は、bootswatch のカスタムができる。Bootswatch: Free themes for Bootstrap nikola bootswatch_theme -n [theme name] -s [theme name] -p [parent theme] これで、サイトフォルダの t…https://iuk.hateblo.jp/entry/2016/10/28/040908