Static site generator, I love and hate them at the sametime. They really render your markdowns into a beautiful website without need of knowing web technologies. Then there are the constant hustles once you try to customize it, change a theme, adding different functionalities or upgrade. It is YOUR website, you want it look different than others, right. At some point, whether you like it or not, the SSG users will take the role of website designers by tangling with CSS.
This site, in particular, is generated by pelican, a python based SSG. I choosed it because I am comfortable with python. Pelican was among the top tier candidates. I was happy with it at the first, you get a Makefile to build and publish your website. But after a while when you come back, your python virtualenv was broken… I can’t complain that much really, I’ve been using this for several years now, usually satisfied.
Today I am here to address another generator, the sphinx-doc. To my feeling, it is rather a frankenstein style SSG. I use it generate the Taiwins website. It is all powerful when you want to host the documents of your project, but you don’t like the doxygen style. In my setup, I took the doxyrest route (didn’t get breathe to work).
Sphinx is good for hosting documentations. We have an index page. a navbar that direct us to documentations, external links like code repo. It was simple and perfect. The new challenge here is that I want to have a blog system inside for since like release notes and dev blogs. In this your website may be more “alive”. Luckily someone already did it. The ABlog extension is specfic for that.
Doxygen Stage
Doxygen scans EVERYING other than generates document from source based on
Makefile. It is sort of a compiler of its own so carefully configure your
EXCLUDE_PATTERNS
in your Doxyfile. Doxygen also collects your Markdowns if
there it finds it and append them in the “related pages section”, so you may
want to exclude them somehow. I just choose to document in ReStructuredText so
doxygen doesn’t read them. And finally, for sphinx to work with doxygen, set
GENERATE_XML = YES
in the Doxyfile.
Doxyrest Stage
Doxyrest takes XMLs generated from Doxygen and output into Sphinx RSTs(Sphinx
RST is a special dialect which use many non standard directives like
:ref:
that usually not available outside). It also requires a config called
doxyrest-config.lua
, you give an input xml(the index.xml generated by
doxygen) and it outputs RSTs with an index.rst
. Doxyrest is rather
straightforward but there are many options you can pass in.
Sphinx Stage
Now we have a handful of RST documents. The index.rst
from doxyrest is the
document intro page so you may want to rename it to something else. Then we
need to work with sphinx
configuration. This
is certainly a beast of its own. But note that we need to enable some
extensions here :
extensions = [
'doxyrest',
'cpplexer',
'ablog',
'sphinx.ext.intersphinx'
]
doxyrest takes doxyrest
and cpplexer
and ablog requires ablog
and
intersphinx
.
Before we finally run sphinx-build, there are something to note here, sphinx
takes a unified template, namely layout.html
unless you specify the
html_additional_pages
option in conf.py
. It sort of works for a few pages
like index.rst
and about.rst
. But since we uses ablog extension we don’t
want to list all the posts there. Note that ablog also generates a handful
htmls like archives, postlist, etc. My solution right now is pretty much a
hack. I have my own layout.html
which extends the theme. Inside, an ugly
if-else statement is present:
{% if pagename == "index" %}
{% include 'master.html' %}
{% elif pagename == posts or pagename in ablog %}
<!-- apparently the inheritance screwed up the include, we have to do this way -->
<div class="row">
<div class="{{ bs_span_prefix }}2"></div>
<div class="body {{ bs_span_prefix }}{{ bs_content_width }} content" role="main">{% block body %}{% endblock %}</div>
<div class="{{ bs_span_prefix }}2"></div>
</div>
{% else %}
{% include 'document.html' %}
{% endif %}
The first thing to notice is that I have three different templates:
- for index.html, use master.html
- the documents, uses document.html.
- The blog posts and post list. The condition
pagename in ablog
will pick out the blog posts for us andpagename == posts
picks the post list.
The second thing your probably notice is that why blog posts are not using include? The reason is rather awkward. The ablog templates is actually the sub-template of us. If we uses an include, the jinja sub-templates doesn’t seem to read what is inside. But again, this is a hack.
In Conclusion
I have to say, if you want to make your project a website with documentations and custom pages. Sphinx is pretty much the only choice. And it also has a blogging extension for posting more frequent contents. On the other hand, this pipeline is long and slow compare to other SSGs, configurations is two times the work. As what they say, you can never have all the good eggs in one basket.