Static Site Generator in 86 Lines
alexxx.co
alexxx.co
template.html:
<header><h3>%(header)s</h3></header>
<div>%(content)s</div>
<footer>%(footer)s</footer>
generate.py: content = """# This is a markdown content"""
from markdown import markdown
with open('output.html', 'w') as f:
f.write(open('template.html').read() % {
'header': 'welcome',
'content': markdown.markdown(content),
'footer': 'amazing company inc'
})
for serving it: python3 -m http.server
it will be running on 127.0.0.1:8000cat template.html | sed s/content/$(markdowncompiler content.md)/
class partial(dict):
... def __getitem__(self, k):
... return open(k).read()
So we will render the template like thistemplate.html:
<header><h3>%(header)s</h3></header>
<div>%(content)s</div>
<footer>%(footer.html)s</footer>
generate.py content = """# This is a markdown content"""
with open('output.html', 'w') as f:
f.write(open('template.html').read() % partial({
title: 'Velkommen',
content: markdown.markdown('markdown content')
}))What I’m trying to say is that even if this qualifies as fashionable in your time scale, a decade is a lot.
This isn’t criticism of your approach. It’s better to stick to whatever works for you and focus on the problem domain rather than the tech stack.
... and you can probably build a 100 LOC static page generator in Java as well.
My thing does a lot of weird crap, though. Like it also acts as a Gemini protocol server, you can publish from the web and it pushes every change to a git repo. It also tracks backlinks and re-publishes every page that is mentioned. It also renders from a specialized version of gemtext so there really isn't any standard libraries to use (that I'm aware of).
Hehe, given how verbose Java can get, I’d increase the word wrap limit x3 in that case.
But yeah, I see your point and the project sounds pretty cool. Can I find it anywhere?
https://github.com/vlofgren/50-line-java-ssg
Does deal with partials, bit stuff like an automatic index requires maybe 5-10 additional lines.
Took about an hour (plus 15 minutes to try to figure out how to get into my github account, which I haven't actively used in the last 15 odd years).
My "real" Java SSG is used to generate https://memex.marginalia.nu/. Unfortunately I don't have the source published.
for file in *.md; do
pandoc --quiet --template layout.html $file -o "${file%.*}.html"
done $ find -maxdepth 0 -name \*md -exec sh -c 'pandoc --quiet --template layout.html "$0" -o ${0%.*}.html' {} \;(* = Well, it was easy, but I feel like this ESM business now means npm/yarn install doesn't Just Work™ in some cases.)
This does seem to align with it being a modern perl
1. drop markdown support, and posts in HTML
2. find a way to parse HTML via regex, which is doable if I use a different notation than a tag for `<partial src=...`
3. use a language that has filesystem support natively, to read files without a dependency
I'm working on 2 and 3. But I don't want to drop markdown support on the blog posts...so I guess I will live with this :)
I made mine with Python and which is uses Github pages -
- Jinja templating engine
- Markdownpy
- Subprocess (for git CLI commands)
- And a classless CSS of your choice
const parse = require('node-html-parser').parse;
const beautify = require('js-beautify').html;
const loadYaml = require('js-yaml').load;
const showdown = require('showdown');1. drop markdown support, and posts in HTML
2. find a way to parse HTML via regex, which is doable if I use a different notation than a tag for `<partial src=...`
3. use a language that has filesystem support natively, to read files without a dependency
I'm working on 2 and 3. But I don't want to drop markdown support on the blog posts...so I guess I will live with this :)
%.html: %.m4
m4 -P < $< > $@ <partial src="partials/layout.html">
My fancy content
</partial> for file in *.md; do
pandoc --quiet --template layout.html $file -o "${file%.*}.html"
done <partial src="partials/layout.html">
My fancy content
</partial>
Because I can use HTML parsers. But now I'm thinking of a way to remove all dependencies, to I will have to get rid of html parser, and find a way to those substitutions without parsing HTML, with just regex replacement.It was 100 lines. But a little deceptive, since like yours it relied on a markdown parsing library.
The bulk of the code was handling creating a sitemap.xml and all the of meta/opengraph/twitter tags.
[0] https://github.com/mourner/tinyjam [1] https://agafonkin.com/
I wrote this very simple SSG, and would like to receive feedback on how to simplify code.
Also, I would be happy to fix any bug.
1. Layouts / Template Inheritance
2. Sass Compiler
3. Live Reload
Love the baseline set of tools here though!
<partial src="partials/layout.html">
My fancy content
</partial>> Just like every dev writing a blog, my first question was: What is the minimum set of features to maintain it comfortably?
Then you created a program in JS that requires NodeJS to run. But cool programs written in JS don't require NodeJS when it's not necessary. They just run in the browser.
PS: Really cool static site generators that shoot for simplicity don't require you to create extra template files written in a new, made-up template language. When you want to create a new post, you give it (a) the static files from your existing site and (b) the markdown for your new post. The "templating" engine inspects your existing posts (incl. e.g. class attributes) and then copies the same document structure into a new file, except with the right stuff (timestamp, title and heading, post content...) substituted in to the places where it's supposed to go.
<https://developer.mozilla.org/en-US/docs/Web/HTML/Element/in...>
<https://developer.mozilla.org/en-US/docs/Web/API/HTML_Drag_a...>
for file in *.md; do
pandoc --quiet --template template.html $file -o "${file%.*}.html"
done
But I wanted a flexible way to reuse components. So I need the <partial> trick to support outer and inner partials in the reusable components. For example a form that I want to reuse on some pages, or a custom call to action.Let's say you have static site today with your lost post being "2022/03/31/working-on-a-new-tool.html". To author your new post, the tool could derive the template based on what the actual, HTML-formatted version of your last post looks like, and then it would substitute the new post content into the appropriate places. For example, where your previous post has a date stamp indicating it was published on March 31, the tool would put the date of the new post. Where your previous post has the title in an H1 or whathaveyou, your new title would appear. Where the main text of your last post appears, the main text of your new post appears. This would all be written into a new file. There's no need for an explicit template file.
PS: Pandoc doesn't run in the browser, either. You're already going to have your browser open to check the output. Its runtime is both powerful enough, and it's right there, so use it. No need to bring other runtimes into this.
Check out fncli if you want to add some command line args... might be nice to specify some of the config that way
Obviously not that difficult to add some javascript and APIs if you want, which avoids the need to mix in a different stack while generating the same look-and-feel. Or you can use NGINX/Apache frontend to redirect certain paths to a more traditional dynamic stack/CMS of course. Just curious if there's any "standard" approach or off-the-shelf tooling for that for (eg) Jekyll or similar.
You can get a site running in Vercel+Next in <2m from ‘git init’.
I use it for https://potato.horse and most PoCs now, but we’ve scaled Vercel+Next to hundreds of thousands of users per day in other projects.
You could also use Netlify with Netlify functions, although I prefer the (slightly) less opinionated way of handing releases and per-commit vanity URLs Vercel offers.
Aaand if you want to get more funky with your approach, check out Astrojs (island architecture: start with static content and sprinkle the interactions on top of it).
You could also try, Elixir + Phoenix + Live View if you want to learn a new tech stack, feed your brain, and… spend a few days yak shaving. Nope, none of the 5 new versions of your blog will be live by the time you’re done, but you’ll become good friends with Erlang and co. Speaking from the experience, I use next when I want my stack to be boring.
...However, if what you want is dynamic content/interactivity within the context of a page that is served static from your SSG process, then I (reluctantly) resort to javascript (Sorry, my reluctance is because i'm not much of a fan of javascript...and in fact have tried to omit as much of it as reasonable from my projects.)