123 comments

[ 3.3 ms ] story [ 190 ms ] thread
Nicely done. Pico.css is a cool idea I hadn't seen before.

I have built 2 SSG's over the years, once in 2009 and one this year. So it's fun to read through someone's internal thought process on their motivations and decisions.

Someone put together this mega list of 460 SSGs that I found helpful for inspiration and learning: https://staticsitegenerators.net/. Also would be a good place to add Teeny, though not sure if they are still updating the actual website.

Yes it is quite cool, I also wasn't aware of it.

I guess I finally found out the theme I have been searching for.

Not fond of Pico.css’s weight, though: over 50KB, nowhere near as lightweight as the name suggests (even if it’s above-average compressible, 8KB gzipped—but I wouldn’t count even 8KB uncompressed as pico); in this case, if you flatten the variables and strip unused code, you’re left with under 4KB (~1.4KB gzipped). Lots of bloat from unused light mode support, things like form controls, and a fair bit of frivolous custom properties usage. This is the sort of place where I see the appeal of the likes of Tailwind, because they generate such huge amounts of CSS that you just about have to use an unused style remover. But it is another build step, and contrary to the deliberate intent here.
I've made my own (in a few incarnations) for my own website. I should do a writeup some day, I made my own Make and everything. I figure I'm at about 2 posts per technological revision, but given that's sort of why it's there I'm fine with it.
I definitely advocate for writing your own static generator. For me, my personal web page is my sanctum. Maintaining it is a labor of love.
back in the day, i built my own blog in php[0], while my friend built an ssg for hers (using perl no less). i scoffed at the time, but seeing how things turned out, it seems she gets the last laugh. perhaps the difference is not so large now that cdn's are a dime a dozen.

[0]: after seeing and deriding the code for wordpress. another, much bigger, last laugh there too.

Been here, done that :) thx for a fun read :)

My most recent attempt to rekindle my old blog turned into a write-a-SSG-that-can-import-tumblr and then a quest to recapture the nostalgic MySpace/text-mode feel, and no actual new blog entries.

Writing an SSG was procrastination at its finest. I did manage to migrate to ghpages and make the old tumblr and google-sites versions auto-redirect.

Yeah, on the other hand, my pro website is based on Jekyll and it doesn’t compile anymore because of version shenanigans…
Yeah I just checked and at least my SSG code is python3. That's a bit of a surprise to me, actually.

Its telling how, over the years, I've had to keep moving my free-hosted blog to a new provider. This is the third time. I'm hoping ghpages are here to stay and don't start doing a sourceforge ad angle or anything...

If only network connectivity had scaled up as remarkably as CPUs did over the years, we could all be hosting services from our home machines in true peer to peer manner. Distressingly though ISPs are reinforcing the client-server model by asymmetric bandwidth, blocking ports, forcing customers to purchase business plans for static addresses and so on. All technically unwarranted, purely user-hostile behaviour.
I am afraid to sound millennial but why not WordPress + Static Site Generator Plugin? I totally get it, this is a fun project to test some skills but if the concern was going live, I can go live with vanilla wordpress with their default theme in less than a minute.
Off the top of my head, no constant site-breaking WordPress updates to install, no constant WordPress/plugin vulnerabilities, not to mention much less CPU/storage needed to host the site. Further, since the site is generated to static files, you can host it on any server technology without any concern for whether your given "stack" is supported.
(comment deleted)
I think it's the same reason as Gatsby:

> you add your name, a bio, some links, and Gatsby does the rest.

>

> But that comes at a cost. And that cost was made clear by me hunting the favicon file

some reasons i can think of:

1) it's more fun

2) it's good practice as a programmer

3) you get complete control over what content is generated (i.e. can minimize CSS/JS size)

4) you get complete customization - you can make your own way to template things that is convenient for you, or auto-import a particular file format you like to keep for your notes on disk, etc

5) you don't have to learn how to use wordpress

(It's not to say I think using wordpress is bad - if you like it, use it!)

(comment deleted)
Because it's slow. Even the fastest wordpress static site plugin still requires the huge wordpress site to initialize. I have never seen a fast wordpress site. I mean sub 50ms loading times. With a plain nginx route to index.html containing some fixed CSS,js files is so much faster.
My Wordpress sites have minimal plugins (hence minimal JS and CSS) and run via a VPS and using Litespeed Enterprise, and they're almost as fast as static sites - but with 100x the ease of use and power.

Heck, my Wordpress blogs are faster than when I had static sites on shared hosting.

I think you're misunderstanding what Wordpress's static site generator plugin does. It bakes the WP content in to static HTML files that the server (eg nginx) then serves to the user. Website visitors never hit any part of WP. It's only there for the admin and editor. You can serve the static files from a different server infrastructure (say, an S3 bucket) with a little work.

In other words, it does precisely what you're saying it should do.

So sounds like you now have to maintain a static site and a wordpress site - is this any easier than just using a static site generator directly?
You only have to maintain the Wordpress site unless you do fancy stuff on top of it. And on modern Wordpress that's quite minimal. The point of this approach is that people with Wordpress expertise can continue to manage the website and you get all the benefits of a static website.
Is “sounding millennial” meant as a young people thing, or an old people thing?
I believe it is meant to sound old in the parent poster's context but normally genX'ers and above are considered the oldies.
Agreed.

I have a series of content websites, and at first I used Jekyll and it was fast to load, but everything took 10x longer to do than just using WordPress.

I now use WordPress on a VPS and served with Litespeed Enterprise and the performance (read: load times and CWV/GMetrix scores) is very very good - better than static sites hosted on shared hosting, in-fact.

I have been burnt many times by wordpress. Updates that fail and hose everything, continual hacks because you can't update, then automated updates that worked until they didn't, obscure PHP errors from oddly configured hosts, dodgy plugins that people add that get them hacked even if they are updated to the newest version of wordpress.

It is great for non-technical people, but the risks are high.

I personally find that github pages is a better alternative now: most users can handle doing edits in github's web UI, and on commit the changes are auto-deployed to the live site and appear within 60 seconds or so. And it helps me to see their git history when they screw something up.

20 years ago I built my own SSG. There weren't as many back then. :) I even built my own RSS2 generator - https://pypi.org/project/PyRSS2Gen/ .

It was great when I started. I did some teaching back then and put my lectures in its own section, which I could re-build and serve to the local network for my students.

I no longer know how it works. I don't care to maintain it. It needs big changes to handle something like embedding a Jupyter notebook. And it depends on Python 2.6(!).

With hundreds of pages, and its own custom URL layout that I don't want to break, I dread migrating to a modern system.

I do not know if where you host your website, but if you have to upload it to a hosting provider, it is nice to have an upload folder that contains only the files that have changed (or regenerate the files that have changed). For my personal website, in plain HTML, I have a syntax/link check program that places the new files in an ftp folder. For another website that is generated with javascript en node.js, I use a script to copy the generated files to a certain folder if they have changed.
rsync is the tool to know for copying trees of files where most are unchanged.
Does that also work if FTP is the only means to upload files to your hosting provider? If not, do you know of a simple FTP client that can do the same?
My approach to static site generation these days is to use Parcel Bundler. (Note that V2 has come out, but most of my experience with V1, so YMMV.)

It’s a little bit of a strange tool, but you can start by pointing it at an HTML file, and it will automatically build it, bundling and minifying any dependent resources and giving them a hashed filename for better caching.

If you want to do multiple pages, it’s simple; you can just link them. Parcel Bundler will pull the links and bundle them just like the first page, recursively. When it generates linked pages, it won’t make a hashed filename, so your directory structure will be left in-tact. If you want nice subdir pages, you can put index.html files into subdirectories, and voila. And as a bonus, any resources you depend on from two different pages will share the same bundled resource, as you would probably hope.

But HTML can get repetitive, so you probably want templating of some sort. For that, I tend to rely on Pug templates. They support blocks and template inheritance, so now you can do more advanced stuff without having to repeat yourself constantly.

Finally, if you wanted to use TypeScript or SCSS, you just, can. They will be compiled and bundled to JS and CSS transparently, exactly like you would probably hope.

And then maybe you want to do something more interesting than what it can do out of the box. Like for example, maybe you want to render Markdown files into a template (obviously relevant to this use case.) In that case, you can extend Parcel. My favorite shameless plug is a documentation site I have set up for a reverse engineering project which uses Parcel to render Markdown and Kaitai Struct files into templates which are interlinked with each-other. The resulting site is fully static and the build process is relatively quick. I don’t know of any cleaner way to do something like this!

https://packets.pangdox.com/

The biggest downside of Parcel is that I did, in fact, need a custom plugin to render Markdown files directly into templates. Maybe there’s a simpler way or a plugin on NPM that serves this relatively common use case. But I just love having the page graph intertwined with the asset graph like this; it’s super powerful for building fully static websites. The only thing it feels weak for is if you want to generate pages from data somehow; Parcel is pretty tethered to pages being an asset, so as far as I know you can’t simply synthesize them. Still, despite this and other quirks, I really do enjoy the experience.

I've written my own static site generators before, too, and with all static site generators pretty much, I’ve felt unsatisfied with how they interacted with bundlers and compilers.

My website is constructed (and deployed) by a Makefile with a crappy find-and-replace script masquerading as a templating system. More or less this:

    all: $(addprefix $(OUTDIR)/, $(addsuffix .html, $(PAGES))) $(addprefix $(OUTDIR)/, $(notdir $(wildcard imgs/*)))  $(OUTDIR)/styles.css 

    $(OUTDIR)/%: imgs/% | $(OUTDIR)
        ln $< $@

    $(OUTDIR)/%.html: pages/%.page template | $(OUTDIR)
        $(BUILDER) template $< $@

    $(OUTDIR)/styles.css: styles.css
        ln $< $@ 

    deploy: 
       rsync -avh $(OUTDIR)/ $(DEST)
What $(BUILDER) are you using? Could be GNU m4 (been there, done that) or something more (or less?) evolved.
Nothing fancy, just a python script that parses each page's "header" (a set of '='-delimited KVPs), interprets the rest as the main content, and then does some text substitution in the template (in practice, I only have a KVP for the page title that's used in the template).
Yes, but it gets tricky real quick.

You might want to have all html pages added to a <ul> in an index.html.

Then you might want a sitemap (similar solution to above).

Then you might want an RSS feed (and an atom feed).

Then you might want height and width attributes automatically set in <img> tags.

It's all doable, but soon your build script is a classic static site generator and dwarfs the Makefile in functionality and complexity.

Indeed, but that's overkill for most personal sites...
That isn't really true. Adding things like image width and height attributes are basic essentials for any content drive website. If you push new content regularly then an RSS feed is very useful for visitors. If you want to be found in Google then you need a sitemap.

If you're not going to do the absolute minimum for your site's users why bother making a site in the first place?

I wouldn't say any of those qualify as "absolute minimum", particularly for personal sites which owe nothing to their visitors. Omitting img dimensions will cause nothing worse than reflow, while a "what's new" section can be a partial alternative to RSS. As for Google, I'd presume a properly linked (internally) site should be fully crawled even without a sitemap. Maybe not as efficiently, but again, for a personal homepage it is sufficient. Of course in that case one can ask why not just use WP or a SSG that gives you those for free. The downside is of course the time you need to invest upfront in learning those tools and then keeping up to date with their changes and breakages. In contrast, simple HTML, CSS and JS can be safely expected to work for decades at the very least.
In contrast, simple HTML, CSS and JS can be safely expected to work for decades at the very least.

'make' is older than html by almost 20 years.

Okay, you get nerd points for that.

I write my website in Emacs org mode, then export to html. I like to think that I win on nerd points :-)

I tried that but couldn't grok how to set an arbitrary page structure. The default org html export is awful and it seems very opinionated about the workflow, but the docs weren't clear about what those opinions were.

Now I'm using a Frankenstein's monster of org-pandoc and `cat`

> I tried that but couldn't grok how to set an arbitrary page structure.

I don't know what this means - I write a normal org document with headings and suchlike, and then export. For site structure I store each page as a separate org file and the html-export exports the links correctly.

It might just be that I am happy with the output so I didn't try to change anything, so didn't run into the problem you did.

What do you do if you want to change the layout of the rendered html?

For example, suppose you wanted a sidebar, or an absolute-positioned floating navbar or something.

> For example, suppose you wanted a sidebar, or an absolute-positioned floating navbar or something.

I suppose that I would have to specify that I wanted to export a ToC with a maximum depth of 1. Currently all my css rules are in a different file (not managed by emacs/org) and I would modify the css in that file to ensure that the ToC appears in a left positioned div, or a floating absolute div, etc.

To be honest, I think that that will only work for a ToC. If you asked "how would you specify a list for the sidebar and another for the top menu navbar" I won't be able to give you an answer[1].

[1] Hey, maybe it can be done, but not as far as I know.

I was about to that myself this weekend, you just saved me few hours, I'll start using it right away :)
I should preface I'm a solo-founder with a few side-projects(nothing big). Thus you have to usually make due with "just good enough" and move on to the other 10 tasks awaiting you.

My deploy script (it's just 5-10 lines of bash) mostly for some of my "old" angularjs(yes v1)

1) merge all js files (cat file.js >> app.js)

2) make sure any files that request/include JS and HTML files are not cached (generate new random ?rcc=random-num)

    find -type  f  | egrep  "html|js" | xargs sed -Ei s/"rcc=([0-9]+)"/rcc=$RANDOM/g

3) ssh-copy over to server

Sexy ? Absolutely not , does it work ? Like a dream :)

Having the ability to just type "./deploy-aws.sh" and be done in 5 sec is an amazing ability to have for you project. Especially if you are SOLO founder.

Thought about using s3? I have static content I keep version controlled in github with a git hub action.

When I push to the production branch, a github action does an aws s3 sync. My web service pulls static content from the s3 bucket.

It works well and i really like github actions for this kind of work.

Perhaps you'd like to package your preprocessor into something to make Personal Home Pages...
Nice job :)

I don't completely agree about Jekyll (it can be very light weight, requiring zero Ruby unless you need to extend things), but rolling your own solution for a personal home page is always nice.

"This was nice, but I lost the flexibility I would have wanted to customize the pages a bit - GitHub let's you pick a theme and that's that."

You can actually make your own themes with github pages

I had my own static site generator. A bunch of PHP and Shell scripts, but I moved everything to 11ty a few years ago and haven’t looked back. If you haven’t tried it, check it out.

https://www.11ty.dev/

What I like about 11ty is that it comes with several template languages out of the box and you can pick whatever you want. You can also mix several languages.

Or you can run it in a bare-bones minimal version. I guess it just fits my mental model.

Furthermore, it doesn’t have constant updates. The API is quite stable (although 1.0 will be released soon, which requires some manual work). But I haven’t had to change a thing in a couple years.

Not affiliated, just happy with it.

Why I'll never build another static site generator:

- because I've done it already and I haven't gained anything from it other than feeding my ego

- it makes me work on keeping it updated to "my custom needs" more than I work on the actual project that needs it

- it always gets outdated really fast, esp if it uses js a lot

- I've learned that it's generally a waste of time, time better spent on other areas of your business and existing tools are good enough

The idea of a static site generator becoming outdated fast is utterly alien to me: it's a freaking compiler, text in, HTML & CSS out. Unless you sit on a seriously unstable set of dependencies, the whole thing should be pretty stable. I haven't changed my own generator in years. Also, what do you need JavaScript for?

The other points I won't deny, though I sure liked feeding my ego.

In fact, stability is one of the reasons why I use my own static site generator - nothing changes unless I want it to.
(comment deleted)
> it always gets outdated really fast, esp if it uses js a lot

Think you worded that incorrectly. It should be

> it always gets outdated really fast if it uses js a lot

I agree with that point. I wouldn't write a static site generator in JS for that reason.

JS is stable. More stable than most other languages. If you have reservations about NodeJS and the precarious NPM ecosystem, then say that. But equating JS with NodeJS and its community's dubious practices just exacerbates the problem.
Many people equate programming languages with their ecosystem. That’s how you get people claiming that $newlang is so much worse than $oldlang, because it has no tools, no libraries, the compiler generates slow code, there is no community, and you can’t get commercial support.

That may be true, but that doesn’t say which language is better.

It better to generate single-purpose tools, which can be reused, instead of single-use static generator, which cannot be reused.
I made my own static site generator in a very similar fashion, a small recommendation/tip I found is that instead of creating your own "use this template" definition, you could use "Front Matter"[1] to define this initially:

    ---
    template: custom.html
    ---

    # My normal markdown
Since it's a fairly standard tool, parsing it is trivial with npm packages[2] and you don't need to be manually parsing the strings:

    import fm from "front-matter";

    const data = await fs.readFile(...);
    const { attributes, body } = await fm(data);
    // attributes: { template: "custom.html" }
    // body: "# My normal markdown ..."
[1] https://jekyllrb.com/docs/front-matter/

[2] https://www.npmjs.com/package/front-matter

Front matter are YAML. I wouldn't call parsing it trivial, though if you want to create a simpler alternative and don't think about it, you're probably going to end up with something worse than YAML.
I never did. I call trivial using an existing tool designed for this, I would def not expect the author be parsing front-matter code manually (as shown in my example).
Hey, thanks for pointing out the `front-matter` library. I've updated Teeny to use that instead of HTML comments.
The two things I really want from a SSG for my blog are the ability to avoid indexing posts by dates and the ability to link from md files to other md or image files in the same directory. I’ve tried maybe 8 or so of the most popular options and haven’t found this.
I also wanted the ability to handle relative links between Markdown files (and relative links for images). I'm surprised this isn't a default feature of nearly every static site generator, honestly.

Fortunately, some of the extensible static site generators make this fairly easy to add as a feature. Here's an example for Eleventy (aka 11ty):

https://github.com/11ty/eleventy/discussions/1973#discussion...

I have taken a different route [1]. Started to work on a desktop app for creating static sites. It features a block/frame based editor, works fully offline (except deployment of course). It should specifically target non-technical users.

[1] https://www.project-daily.com/pages/an-experiment_1065.html

Interested. I have a few decidedly "non-technical users" in mind. Any way to keep updated on the project?
Message me at "h e l l o AT project - daily DOT com". Remove the spaces etc. I will try to keep you updated. I am also planning on generating an RSS feed from the app itself. Once this works, you can subscribe that.
That's quite the excessive obfuscation considering the generic local part that spammers will surely try anyway.
That is informative and inspiring. Thank you for having shared your initiative.
I felt in love with building static websites last year too.

Thanks to a custom build with kotlinxhtml and a bunch of other tools, I'm very efficient. High performance thanks to simple html+css and a little vanilla js, so the pages show up instantly with 38k+ monthly visitors on a low-spec cheap server. No background loading or rendering in js or whatever.

(comment deleted)
I built mine too, for similar reasons: it felt easier to write from scratch, so that my site looked the way I wanted it, than customize some of the existing solutions (Jekyll, Hugo, etc).

Sure it’s not customizable at all: it can only generate my site. And that’s fine. I like it that way.

For example: I sometimes translate poetry, and I have a bunch of code that renders individual poems from plaintext (not Markdown, because newlines and whitespace _are_ significant): https://github.com/nathell/nhp/blob/master/src/nhp/poems.clj