🕊️

Sphinx+ABlog+PyDataテーマで個人ブログをつくる

に公開

概要

GitHub Pagesで個人を作成する際,MarkdownとJekyllで作成するのが簡便である。
検索しても多くの場合その情報が出てくるが,ここではSphinxとその拡張機能を使用したやり方について,概要を述べる。

なお,Sphinxそのものがどういうものかという解説は割愛する。

Sphinxの基本

Sphinxの基本的な作業を以下にまとめる。
なお,作業ディレクトリ直下にいるとする。

初期設定

sphinx-quickstart

プロジェクト名など聞かれるので適宜入力する。
ここで,quickstartしたときにソースと同じ階層にビルド先を置くか(デフォルト),ソースとビルド先を別にするか選ぶことができる。

htmlの生成

make html

もしくは,

sphinx-build -b html sourcedir builddir

sourcedirはソースファイル置き場,builddirはビルドしたhtmlなどの置き場。

makeコマンドが基本は手軽だが,ソースディレクトリやビルドディレクトリをデフォルトでないところにしたいなど,いろいろいじりたい場合はsphinx-buildで直接指定する。

以下,イメージのしやすさのためsphinx-quickstart時点での作業ディレクトリ構成を示しておく。

  • ソースと同じ階層にビルド先があるとき(デフォルト)
.
├── Makefile
├── _build
├── _static
├── _templates
├── conf.py
├── index.rst
└── make.bat
  • ソースとビルド先を別ディレクトリにしたとき
.
├── Makefile
├── build
│   ├── doctrees
│   └── html
├── make.bat
└── source
    ├── _static
    ├── _templates
    ├── conf.py
    └── index.rst

ABlog

Sphinxじたいはドキュメント作成がメインの使用方法であり,個人ブログ的な体裁には微妙にフィットしない。
そこでABlogという拡張機能を使うことで,それっぽい体裁にできる。

具体的には,

  • 投稿した記事一覧ページの生成
  • 記事へのタグ付け,カテゴリ付け

などが可能になる。

インストールしてconf.pyに以下を追記。

extensions = [
# ... 
 "ablog",
# ...
]

なお,オリジナルのABlogはすでに長いことメンテナンスされていない。
現在では,太陽物理学のデータ分析環境を提供しているSunPyプロジェクトによりメンテナンスされている。

こちらには,「SunPyプロジェクトのウェブサイトが動作することを目的としているため,それに直接影響のないバグ修正や機能追加が行われることはほぼない」,と書いてある。

したがって何か不具合があれば基本自分で解決ということになる可能性が高く,SunPyプロジェクトの方針しだいで近い将来使えなくなるかもしれない。

ABlogの基本

まだsphinx-quickstartでプロジェクト生成をしていなければ,次のコマンドをし使用してもよい。

ablog start

プロジェクト名など聞かれるので適宜入力する。
これで生成されるディレクトリ構成は以下のようになる。

.
├── _static
├── _templates
├── about.rst
├── conf.py
├── first-post.rst
└── index.rst

ここで生成されるconf.pyにはABlogの様々な設定が書かれているので,一度見ておくとよいかもしれない。

htmlの生成には,

ablog build

もしくは,

ablog build -s sourcedir -w builddir

とする。
その後のディレクトリ構成は以下のようになる。

.
├── __pycache__
├── _static
├── _templates
├── _website
├── about.rst
├── conf.py
├── first-post.rst
└── index.rst

Sphinxの基本コマンドと同様,ソースディレクトリとビルドディレクトリをデフォルトでないところに設定できる。

ソースからビルドされたhtmlファイルは,_websiteにある。
その構成は以下の通り。

.
├── _sources
├── _static
├── about
├── blog
├── first-post
├── genindex
├── index.html
├── objects.inv
├── search
└── searchindex.js

記事ソースのファイル名と同じフォルダ内(上であればfirst-post)にその記事のhtmlなどができ,blogには記事一覧ページのhtmlなどができる。
他にもタグ関連のファイルなどいろいろある。

一覧ページの場所設定

デフォルトではビルド先の_website/blog内のindex.htmlである。
変更したい場合はconf.pyで

# blog_path = "blog"
blog_path = "posts"

などとする。

このほかにも様々な設定ができるが,ここでは割愛する。

記事の投稿

ABlogにこれは記事だと認識させるには,Markdownファイルのフロントマターを以下のような形式で書いておく。

---
blogpost: true
date: 0000-00-00
author: author1
location: World
category: Theory
tags: tag1,tag2
language: English
---

執筆途中で公開される状態にはしたくない場合や,一度公開したが非公開にしたい場合は,日付部分を削除すればよい。

---
blogpost: true
author: author1
location: World
category: Theory
tags: tag1,tag2
language: English
---

ただし,この場合記事として公開されないだけであって,ビルドされドラフトと扱われ,_website/blog/draftsにhtmlが格納される。
つまり,のちにGitHubにpushしたりすれば当然GitHub上では閲覧できる。

一応,reSTの場合は以下。

.. post:: 0000-00-00
   :tags: tag1,tag2
   :category: Theory
   :author: author1
   :location: World
   :language: English

以下でもよいらしい。

:blogpost: true
:date: 0000-00-00
:author: author1
:location: World
:category: Theory
:tags: tag1,tag2
:language: English

PyDataテーマ

ゼロから自作したい人以外であれば,既存のテーマを使用するのが最も簡単だろう。

ここでは,PyDataテーマを使用する。

conf.pyのhtml_themeの部分を使用テーマの名前に書き換えるだけでよい。

html_theme = 'pydata_sphinx_theme'

少しいじってみた限り,PyDataテーマは個人的にはリッチすぎて使いこなせてない気もするが,他によさそうなものが見つからないのでこれで進める。

ソースリンクの問題

PyDataテーマでは,各記事のソースを公開するボタンが設置できる。
PyDataテーマのページなどを見てもらうとわかるように,次の画像のように表示される。

なお,ページのソースを見ると以下の通り。

  <div class="sidebar-secondary-item">

  <div class="tocsection sourcelink">
    <a href="../_sources/user_guide/index.md">
      <i class="fa-solid fa-file-lines"></i> Show Source
    </a>
  </div>
</div>

しかし,現在このソースリンクが次のような表示になる場合がある。

ページのソースは以下の通り。

  <div class="sidebar-secondary-item">
  <div role="note" aria-label="source link">
    <h3>This Page</h3>
    <ul class="this-page-menu">
      <li><a href="_sources/index.md.txt"
            rel="nofollow">Show Source</a></li>
    </ul>
   </div></div>

原因は,現時点で最新の安定バージョン0.16.1のPyDataテーマで,この部分に相当するsourcelink.htmlが(あるソースでは)sourcelink.hとなってしまっていることである。

ファイル名がおかしいため,PyDataテーマのかわりにデフォルトのSphinxのsourcelink.htmlが読み込まれて,先の画像のようになってしまう。

この問題はすでに議論されているようで,近い将来修正されるだろう。
https://github.com/pydata/pydata-sphinx-theme/issues/2088

とりあえず個人でできる対応としては,

  • pydata_sphinx_themeのバージョンを下げる
  • (ローカルでしか動作させない場合)自分の環境にインストールしたソースのsourcelink.hを直接sourcelink.htmlに直す
  • (同上)_templatesフォルダにPyDataテーマのsourcelink.htmlを貼り付け,conf.pyでtemplates_path = ["_templates"]とする

など,とにかく正しくsourcelink.htmlが読み込まれるようにすればよい。

各種設定

Jekyll無効化

GitHub PagesはデフォルトでJekyllをサポートしているため,何もせずSphinxで作成したプロジェクトをpushしてもアンダースコアで始まるファイル等は無視されるらしい。
するとウェブページのようなものは表示されるがCSSとかが完全に無視された状態になる。

そこで.nojekyllというファイルを作成すればこれを回避できるらしい。
Sphinxはデフォルトでこれをサポートしている。

具体的には,conf.pyのextentionsに以下を追記。

extensions = [
# ... 
 "sphinx.ext.githubpages",
# ...
]

Myst-Parserの導入

SphinxはデフォルトではreSTという形式のファイルをソースとして受け付けるが,Myst-Parser[1]という拡張機能でMarkdownも使えるようになる。

conf.pyに以下を追記。

extensions = [
# ... 
 "myst_parser",
# ...
]

source_suffix = {
	'.rst': 'restructuredtext',
	'.md': 'markdown',
}

基本はよく使われるMarkdown記法だが,Sphinxで変換する場合に頻出なものとしてロール(インライン要素を対象として修飾等をする命令)とディレクティブ(ブロック要素を対象として修飾等をする命令)がある。

それぞれ次のように記述する。

  • ロール
    文中でCCCというロール要素にDDDという値を与えるには,
AAABBB:CCC:`DDD`EEEFFF

とする。

  • ディレクティブ
    ブロックとしてAAAというディレクティブ要素にBBBという値を与え,ブロック内にCCCと記述するには,
```{AAA} BBB
CCC
```

とする。
なお,MySTの拡張機能でcolon_fenceを以下のように有効にすると、

myst_enable_extensions = [
# ...,
"colon_fence",
# ...

ディレクティブの記法としてコロンを使ってもよい。

:::{AAA} BBB
CCC
:::

数式などでいろいろ凝りたい場合は拡張機能を入れることで簡単に解決するかもしれない。
ここを確認してconf.pyにmyst_enable_extensions = ["....."]で随時追加していく。

その他

今回使用するPyDataテーマにはいろいろなデザインの何かが仕込まれている。
公式ドキュメントを見ていろいろ試すと楽しいのかもしれない。

試すには追加で該当パッケージをインストールしなければいけない場合があるが,sphinx-design,mermaid,sphinx-copybuttonを入れておけばだいたい大丈夫と思われる。

conf.pyに以下を追記。

extensions = [
# ... 
 "sphinx_design",
 "sphinxcontrib.mermaid",
 "sphinx_copybutton",
# ...
]

GitHub Actionsで自動化

一度手もとでビルドして,htmlが問題なく生成されているかなど確認してからGitHubにpushしてもよいが,GitHub Actionsを利用すればソースをpushするだけで自動的に生成されるようにもできる。

ここでは詳細は割愛するが,既存のスターター
https://github.com/actions/starter-workflows/
や,以下の記事が参考になる。
https://zenn.dev/shotakaha/articles/1df7d807137f61

ひとつ注意点を挙げるとすれば,ABlogを使う場合,ワークフローのyamlファイルでビルドするときの命令をablog buildにすることくらいだろう。

脚注
  1. YouTubeなどで英語の解説動画などを探して見るとわかるが,Mystは「ミスト」と読むらしい。 ↩︎

Discussion