
Show HN: Makesite – A static site generator in 125 lines of Python - sunainapai
https://github.com/sunainapai/makesite
======
vram22
A while ago I had written a tool called PySiteCreator.

It lets you create simple web sites (I originally thought of it for creating
wikis, but later realized it was more general) by writing them purely in
Python, using Python function calls to generate various HTML elements.

It uses a make-like approach (file timestamp checking between input and output
files) and relies on a simple convention that users have to follow, of
defining a Python function called create() in each .py file they write, where
each .py file will be used by the tool to generate a corresponding .html file.
Other than that, it places no restrictions on the user, and any arbitrary
Python code can be used to generate or pull in data from anywhere, to be
included in the web pages it creates.

Blog post about PySiteCreator here:

[https://jugad2.blogspot.in/2009/11/early-release-of-
pysitecr...](https://jugad2.blogspot.in/2009/11/early-release-of-
pysitecreator-v01.html)

Source code here:

[https://bitbucket.org/vasudevram/pysitecreator](https://bitbucket.org/vasudevram/pysitecreator)

------
charlesdaniels
Personally, I used Jekyll for a while before switching to a simple Makefile
based approach. I write everything in Markdown, which gets compiled via
Pandoc, concatenated with a header and footer. I also recently started using
pygments to generate colorized inline HTML to syntax highlight code blocks.

If anyone is interested, I wrote up the process[1], although I have not
updated the post with the pygments script yet.

[1] - [http://cdaniels.net//2017-11-22_make-static-
site.html](http://cdaniels.net//2017-11-22_make-static-site.html)

~~~
sigil
Fellow Jekyll refugee here. I also switched to the Makefile SSG approach for
the much faster incremental rebuilds. Parallel speedup with make -j is also
nice.

My SSG is called tinysite [1] [2]. Templates are jinja2. Posts are written in
markdown with Pygments highlighting for fenced code blocks. Posts also have
JSON frontmatter which can #include other JSON data files, and this is where
it gets Make-y: all affected pages get rebuilt when a data file changes with
the help of a `gcc -M`-style file dependency scanner. I use these frontmatter
"data includes" for site wide metadata and for data driven pages like post
indexes. There's also a dev server so you can quickly preview changes.

The biggest frustration I have with the Makefile + interpreted language
approach is the slow startup time of interpreters these days. When every page
requires a new interpreter process it really starts to add up, if not in
incremental builds, then definitely in full rebuilds of larger sites. Some
quick tests I did recently of `time $INTERPRETER -[c|e] ""`:

    
    
      node 6   ... 70ms
      ruby 2   ... 58ms
      python 2 ... 27ms
      perl 5   ...  5ms
      sh       ...  3ms
    

Perl compares quite favorably here, but I just can't bring myself to go back
to it. I wish these other interpreters would get their startup time act
together! I guess this is an argument for go / Hugo?

[1] [https://github.com/acg/tinysite](https://github.com/acg/tinysite)

[2] [https://github.com/acg/alangrow.com](https://github.com/acg/alangrow.com)

~~~
charlesdaniels
This is very impressive, and definitely more elegant than my approach. Getting
make -j for free was definitely a major plus; before I started using a Python
script to syntax highlight inline code, my site built in under a second... now
it takes around 3.

I am honestly surprised to find Python is so slow in terms of start up time.
This made me wonder if it was generating / searching for .pyc files, but a
quick test revealed this is not the case:

    
    
      sh-4.3$ ls
      nop.py	nop.sh
      sh-4.3$ hexdump -C nop.py
      sh-4.3$ hexdump -C nop.sh
      sh-4.3$ time python3 nop.py
    
      real	0m0.064s
      user	0m0.048s
      sys	0m0.016s
      sh-4.3$ time sh nop.sh
    
      real	0m0.002s
      user	0m0.002s
      sys	0m0.000s
      sh-4.3$ python3 -m compileall .
      Listing '.'...
      Compiling './nop.py'...
      sh-4.3$ time python3 nop.py
    
      real	0m0.062s
      user	0m0.057s
      sys	0m0.004s
    
      sh-4.3$ python3 __pycache__/nop.cpython-35.pyc 
      sh-4.3$ time python3 __pycache__/nop.cpython-35.pyc
    
      real	0m0.060s
      user	0m0.048s
      sys	0m0.012s
    

I would add that shell can be surprisingly fast for certain tasks when used
correctly. It's very easy to write slow (ba)sh code though, so most shell
scripts wind up being fairly non-performent.

Edit: formatting.

------
mwambua
This is cool, and if I had the time I'd want to do something like this for
automatically generating a google-photos style site from my Pictures
directory.

Also, if you're looking for a stable Python-based static site generator...
I've been pretty happy with Pelican
([https://blog.getpelican.com/](https://blog.getpelican.com/)).

~~~
edwinksl
Agree, Pelican is easy to use and configure using Python.

------
dfee
Practically speaking, flask + jinja2 + wget [0] seems like a much more robust
and approachable solution.

[0] [http://www.dheinemann.com/2011/archiving-with-
wget/](http://www.dheinemann.com/2011/archiving-with-wget/)

------
almata
After using several different blogging platforms/tools, I finally decided to
use instead a GitHub repo for my notes. Something really simple that lets me
1) create a note in plain Markdown, and 2) run a publi.sh script. That's all.
After that, the note is already in my GitHub repo ready to be ctrl-f'ed when
I'm looking for something I know I documented. In case anyone is interested I
used this tool [0], but it was first time in my life creating a Bash script,
so fairly assume the code is, well... you know :)

[0]:
[https://github.com/almata/BlogGit/blob/master/README.md](https://github.com/almata/BlogGit/blob/master/README.md)

~~~
thisacctforreal
I'd recommend shellcheck[1] to help avoid common pitfalls with bash/sh,
particularly in regards to word splitting.

[1] [https://www.shellcheck.net/](https://www.shellcheck.net/)

~~~
almata
Many thanks, I'll do.

------
Animats
Maybe browsers should just understand Markdown. Cut out the middleman.

------
adamisntdead
Writing static site generators is my favourite way of learning a language.
Usually covers all the basics, libraries, FS, error checking and so on

~~~
pvinis
Do you have an good example for this, yours or someone else's? I've never
thought of that as a learning-a-language project.

~~~
adventured
Conveniently there seems to be a dozen or more static site generators written
for every popular language, often with varying levels of complexity to learn
from.

For example, Go: [https://gohugo.io/](https://gohugo.io/)

List: [https://github.com/myles/awesome-static-
generators](https://github.com/myles/awesome-static-generators)

~~~
nkantar
Additional resource: [https://www.staticgen.com/](https://www.staticgen.com/)

------
gabrielcsapo
Shameless plug, I have been a little upset about how convoluted the static
site offerings have been. So I have been building
[https://www.gabrielcsapo.com/sweeney/](https://www.gabrielcsapo.com/sweeney/)
in my free time. It needs a ton of work, but trying to keep it compact and
100% tested. The main source of inspiration is making static sites
configurable enough for people to stop using Wordpress and making their
clients lives incredible difficult. Really cool project @makesite!

------
Philipp__
Hugo is still most convenient, at least for me and my workflow. I just pull it
with homebrew, created my theme/template, write blogposts in Emacs org-mode
(using ox-hugo), host it on GH pages for free, and use custom domain and free
tier cloudflare.

I am really enjoying bare essentials I got, very streamlined process that does
the job for me. This looks interesting, I really like minimalist aspects of
software, but what ain't broken don't fix it.

~~~
citilife
Alright - I like your website layout:
[https://defphil.com/](https://defphil.com/)

But to be fair, some people may want different features than the bare minimum.
Also, even if Hugo is the most convenient as an org-mode user, I highly doubt
it'd be the most convenient for others (who don't use org-mode lol).

Also, you should write more posts!

~~~
kaushalmodi
The Hugo generated site features can vary with the theme used (I believe there
are 200+ options), and the features can get as detailed as a user wants if
they just template their own site.

Ox-hugo that the OP mentioned is just an Emacs package that exports Org to
Markdown + front-matter ( __without having to manually specify many of be
front matter data in the Org source.. most of it is auto derived. __).

------
mojoe
I use Jinja2 to template all my static sites -- it helps me host
compellingsciencefiction.com straight from AWS S3 very, very cheaply.

------
est
generate static site with 1 line of shell command

    
    
        echo "<html>" > index.html

~~~
secura
Is this a valid HTML? [https://validator.w3.org/](https://validator.w3.org/)
seems to require this as minimal HTML to validate successfully.

    
    
        <!DOCTYPE html><html><title>0</title>
    

I would thus fix your 1 line shell static site generator like this.

    
    
        echo '<!DOCTYPE html><html><title>0</title>' > index.html

~~~
butz
You can trim <html> tag and still get valid html: <!DOCTYPE
html><title>0</title>

------
foo101
This seems to use the commonmark library to render Markdown? Can it render
Pandoc flavour of Markdown?

How widespread commonmark really is? Any popular sites using it? If I write my
blog posts in commonmark is it safe to assume site generation tools 10 years
from now will correctly render commonmark?

~~~
reificator
The main competitor to CommonMark is GFM, which is now based on CommonMark.

[https://githubengineering.com/a-formal-spec-for-github-
markd...](https://githubengineering.com/a-formal-spec-for-github-markdown/)

~~~
vram22
I had checked out CommonMark a bit and blogged about it here, including an
example of using it, and a bit about their goals:

CommonMark, a pure Python Markdown parser and renderer:

[https://jugad2.blogspot.in/2014/09/commonmark-pure-python-
ma...](https://jugad2.blogspot.in/2014/09/commonmark-pure-python-markdown-
parser.html)

One interesting point from them was this:

[ Reddit user bracewel, who seems to be a CommonMark team member, said on the
Py Reddit thread:

eventually we'd like to add a few more renderers, PDF/RTF being the first....
]

~~~
reificator
Interesting, I have a little sideproject at work that would _really_ benefit
from markdown -> rtf.

------
Avamander
I absolutely love Pelican with M.CSS[1], automatically deployed by my already
existing TeamCity instance that triggers a rebuild on git repository changes.

[1] [http://mcss.mosra.cz](http://mcss.mosra.cz)

------
whalesalad
Can’t speak to the usefulness of the code but really admire the style. Very
clean, concise and lots of composition. Love it.

------
CydeWeys
I did something similar in C++ way back in high school. Even called it
makeSite too:
[http://www.cydeweys.com/archive/makeSite3.cpp](http://www.cydeweys.com/archive/makeSite3.cpp)

Funny how they're fundamentally not that different.

------
jitans
how stupid is to measure code in terms of lines?

Make all that a library then you can claim:

A static site generator in only 3 lines of Python

Measuring lines of codes is completely wrong. See the Scala trend were people
race to find the shortest way to express something generating hard to
understand code. 1) Code has to be written to be maintenable. 2) Code has to
be written to be read by your coworkers. 3) The bottleneck while coding is not
the keyboard.

~~~
z3t4
Unless you have put effort into squeezing as much logic as possible into each
line, the less code the easier it is to maintain. With more code, more stuff
can go wrong. It's not just because we are bad at writing code, we have
probability against us. If the bug average is 1 bug per 100 LOC then 100 LOC
will have less bugs then 10k LOC. We also have physics against us, reading and
comprehending 10k LOC of code will take much longer then reading 100 LOC. With
that said I do agree with you that LOC don't say much about anything. It's a
stupid metric. With higher level languages, a 100 LOC file might actually be
millions LOC if you include all the libraries. Them being libraries means they
are mostly decoupled, which makes things better, because coupling is the root
of most complexity.

~~~
jitans
That's not the point. Trying to squeeze the code in less lines as much
possible is not the way to go if you loose clarity. Python coders keep
repeting the mantra "less line of code" but in the mean time they keep typing:
self. self. self.

------
make3
Please don't use the number of lines as a metric for simplicity, it really
doesn't mean anything

~~~
zeep
For two programs that do the same thing coded in the same language, I would
pick the one with the least amount of lines but that doesn't mean that less
work went into it... Probably the opposite

