From time to time I throw together a static HTML site for something and love how easy it is to just upload the files to s3 and have a fast site with pretty much no cost or work involved. For single-page sites in particular, this is pretty near painless, but as you start to get to a few different HTML pages, work starts repeating.
For larger projects (like GitNOC, or PedalWrencher), I love using Flask, and through that have gotten pretty proficient and pleased with Jinja2 for server-side templating.
So I found myself in this middleground, where I didn’t really need a Flask server for a simple static site, but HTML was getting a bit annoying to muck around with directly. The natural fit for that is one of the many static site generators out there. I’ve used at one point or another:
All of which are great in their own rights, but in my case, I really only wanted to get the modularity afforded by Jinja2, and really didn’t need a blog or CMS or anything like that. So I just wrote a minimal generator. Heres how it works:
To start with, my directory is just a single python file: compiler.py and a single directory: src/. In src, I put in a subdirectory, static, with all of my images, CSS, and javascript (if I have any), and then I put my jinja templates in src.
Compiler looks like:
from jinja2 import Environment import os import shutil from jinja2 import BaseLoader, TemplateNotFound from os.path import join, exists, getmtime class Loader(BaseLoader): def __init__(self, path): self.path = path def get_source(self, environment, template): path = join(self.path, template) if not exists(path): raise TemplateNotFound(template) mtime = getmtime(path) with open(path, 'r') as f: source = f.read() return source, path, lambda: mtime == getmtime(path) class SourceBundle(object): def __init__(self, static_dir='static', src_dir='src', templates=None, dist_dir='dist'): if templates is None: self.templates = ['index.html'] else: self.templates = templates self.static_dir = static_dir self.src_dir = src_dir self.dist_dir = dist_dir def _root(self): return os.path.dirname(os.path.abspath(__file__)) def clean(self): if os.path.exists(self.dist_dir): shutil.rmtree(self.dist_dir) def build(self, **kwargs): if not os.path.exists(os.path.join(self._root(), self.dist_dir)): os.mkdir(os.path.join(self._root(), self.dist_dir)) if self.static_dir is not None: if os.path.exists(os.path.join(self._root(), self.dist_dir, self.static_dir)): shutil.rmtree(os.path.join(self._root(), self.dist_dir, self.static_dir)) shutil.copytree( os.path.join(self._root(), self.src_dir, self.static_dir), os.path.join(self._root(), self.dist_dir, self.static_dir) ) env = Environment(loader=Loader(os.path.join(self._root(), self.src_dir))) for template in self.templates: with open(os.path.join(self._root(), self.dist_dir, template), 'w') as f2: slug = env.get_template(template) slug = slug.render(**kwargs) f2.write(slug) return True if __name__ == '__main__': sb = SourceBundle(templates=[ 'index.html' ]) sb.build()
It’s pretty simple, it just walks the src directory, copies/builds the various files, and dumps them in dist. That directory can then be copied directly to S3 and you’re good to go. Easy.
The post A (really) minimal static website generator with python and jinja2 appeared first on Will’s Noise.