Show HN: Shite – little hot-reloadin' static site maker from shell (github.com)
A caveat before any more; nobody was supposed to promote this insanity.
Like, terrible things have been done involving inotify and xdotool. But. It showed up on HN some months ago. That too while it was still, shall we say, fermenting. It got "done" some time thence, and of course one could not let the half-past just be. So here we are, for better or worse.
Thank you HN mods for helping me repost! _\\//
The README explains all, animated GIFs and whatnot. Some assorted highlights:
- shite's, ah, "business logic" (except templates) is about 300 lines of Bash, written in Functional Programming style [^]. Pipeline all the things!
- The innards won't surprise Perl/PHP/Shell gentleperson hackers from the last century.
- The local hot reloading workflow is surprisingly nice, and occasionally hilarious! No JavaScript needed.
- Full rebuilds are low performance and that's fine :)
- Pandoc is great.
- Sometimes sed and regex is exactly the HTML parser you need. *Very* sometimes.
- stdio buffering can mess you up
- jq -Rr @html # escapes HTML; what?!
... and all sorts of other stuff noted in the README and inline docs.[^] because shell ain't a bad place to FP... https://www.evalapply.org/posts/shell-aint-a-bad-place-to-fp...
---
P.S.The commit history stops at 3-odd months ago, because I've been using a private fork for day-to-day content drafting, publishing, and layout tweaks. The "business logic" is by and large the same as the public version linked here.
61 comments
[ 25.2 ms ] story [ 1604 ms ] threadeg https://www.99-bottles-of-beer.net/language-bourne-shell-108...
That is a big reason why I use functions. They help me define sane fallbacks, and/or enforce API contracts. Those, in turn, are points where I can enforce "fail and die" behaviour.
Design notes: https://www.evalapply.org/posts/shell-aint-a-bad-place-to-fp...
Example from shite: Hard stop if mandatory front matter for posts is absent: https://github.com/adityaathalye/shite/blob/master/bin/templ...
edit: clarity
It was a bit of a lightbulb moment. I wanted a way to just write HTML templates. What really sealed the deal was the ability to punch content from stdin anywhere within a heredoc's scope using `$(cat -)`: https://github.com/adityaathalye/shite#templating-system
I was trying to cook up a clever tagline, and fell upon "static sites from shell" and my brain looped about and found the tongue twister, sort of like "She sells sea shells on the sea shore", and well all esh shounds shtarted shounding like thish.
These days I like that name more because it (hopefully) alerts the Dear Reader about the quality of software they are about to visit, should they take it upon themselves to do so.
Right here in real life I just do http://zim-wiki.org + a custom CSS Template + a few shell scripts.
http://jrm4.com
Likewise, I'm basically locked into "life in plaintext", as a die-hard orgmode user.
With what I have on disk, a big positive is any "system" of organisation is opt-in, post-hoc, and fungible.
Like, today, shite can be seen as merely one lens into a subset of my org files, to compile that subset into a website. Tomorrow I could bring back hugo.
That choice has no bearing on how any other method of organisation might use those same files (e.g. I can pull up index views using orgmode's own query feature set).
And further, a single blog posts's org file can power live demos in Emacs (org-babel), and gets exported as a blog post, and as a PDF slide deck, like this: https://www.evalapply.org/posts/why-and-how-i-use-org-mode/i...
As much as I've been enjoying hugo, I've been craving something that's much closer to this.
I confess, I take childlike delight in every hotreload on save. Had it not worked well enough, I'd have stuck with hugo at the cost of a jankier authoring + build pipeline (org --ox-hugo--> markdown --hugo--> html).
https://www.urbandictionary.com/define.php?term=Shite
Kind of depressing that people find this amusing.
this bit of fry and laurie https://www.youtube.com/watch?v=cVe3fTL1cPM
this bit by atkinson and cleese https://www.youtube.com/watch?v=OGFz9gt0-Fc
and this bit by atkinson alone https://www.youtube.com/watch?v=R7OxTxAvvLw
made my day :)
I think it's a pretty bad look for the industry.
Not to say there shouldn't be humour — there should be more humour. Personally, my most popular software projects are purely comedic, and they're also a little more coarse than this.
To put it another way: I'd prefer the software humour to be a little more Sean Lock and a little less Beavis and Butt-Head.
[0]: https://github.com/edankwan/penis.js/
You see, there comes a time in every self-respecting Yak-shaving programmer’s life when one is driven to render large-scale follicle trimmage unto a sizeable Yak. In my case, ‘twas and ‘tis the deceptively diminutive but in fact mighty Site-Maker-Yak that renders World Wide Web Sites publishable unto the Internet.
I wager, engaging oneself in the glorious enterprise of Yak-shaving is at least as therapeutic for the trimmer as it must be to the trimmee. I wholeheartedly recommend it :)
I don’t think they knew that.
Then you can `shite(1)` anywhere you want after you put the command in your PATH and feel like a proper `git(1)`.
Good `shite(1)` mate. Love it.
Apropos your note, may I direct you to "Unrealised Ambitions" in the README https://github.com/adityaathalye/shite#unrealised-ambitions
It doesn't have to be an unrealized ambition with a simple `mv` command ;)
Maybe you will enjoy my "bash-toolkit" repo: https://github.com/adityaathalye/bash-toolkit which I've dubbed my "Swiss Army Toolkit" of functions-as-cmd-line-tools and useful-to-me patterns.
Which reminds me, I've collected more and should update the repo!
If it were designed as a proper userspace tool (it is not, and may never be), I might have dropped the file extension. But I might also have chosen to keep the `.sh`, and create an alias instead, during install. That way I get to have both micro-conveniences.
I started writing a "Goals" and "Anti-Goals" section, as I almost always do for sizeable projects [^]. But then I thought two things, "that's boring", and "waitaminute... when people say 'goals', what do they really want to achieve or fulfill? Dreams and desires.". And so it came to be.
[^] e.g. https://github.com/adityaathalye/clojure-by-example#workshop...
I never heard of the xdotool method ... although it sounds like it has some drawbacks? https://github.com/adityaathalye/shite/blob/master/bin/hotre...
I do it with a crappy Python web server that dynamically inserts some JavaScript. This also has bugs and drawbacks, though I don't think any fundamental ones ... At some point I would like to "make it nice", but it has been working well in practice for years
I think the method is reasonable, and doesn't depend on your local desktop environment as much.
I also have a Makefile for incremental rebuilds, but I would really like to replace that with Ninja. Ninja goes pretty well with shell (although it also has the issue of needing to escape $ as $$)
> although it sounds like it has some drawbacks?
Oh yes. The Xdotool Reload Method emulates keystrokes, so it has... drawbacks... as you put it mildly :)
For my use-case, it literally does F5, or it fills out a url and hits Enter. cf. this `case` statement: https://github.com/adityaathalye/shite/blob/master/bin/hotre...
I wanted to keep /mandatory/ moving parts to a minimum in a hand-rolled setup. So I sort of went hardline about avoiding prerequisites like a server process, and especially a JS client. The xdotool trick worked surprisingly well (for the most part), and so I stuck with it!
> it has been working well in practice for years
This is the holy grail. I really hope I get years-long stability out of it. Based on my experience so far, I feel good about the long-term odds.
> I also have a Makefile for incremental rebuilds, but I would really like to replace that with Ninja.
I was going to write a Makefile at some point. I'll have a look at Ninja. Thanks for the tip!
But maybe this counts because it’s a static site.
I'm using it to send keypresses to the browser, as you rightly observe.
So if I want to just reload a page, the browser gets F5.
To GOTO some page, it gets a stream of keystrokes for the URL characters and then Enter.
It's really that simple-minded, and it works!
This case statement covers my usage: https://github.com/adityaathalye/shite/blob/master/bin/hotre...
https://github.com/karlb/karl.berlin
https://git.2f30.org/shite/files.html
> https://git.2f30.org/shite/files.html
So I looked at the templating code. Have you considered here documents for templating? Being able to declare complete HTML fragments is a big advantage for debugging parts, and keeping overall HTML valid. I author HTML fragments in an HTML-mode buffer and get linting etc. to make sure my markup is OK. Then I can just copy-paste it back into the heredoc.
Another thing I did was to use functions as wrappers for each HTML fragment, so that I could define guarantees in the scope of the HTML (any variable / field that must be present or must be of a certain type).
In general, I like making programs out of declarative constructs and/or literal data, because it's so much easier to do "local reasoning" with those things, as compared to imperative procedures, or heaven forefend, live objects.