Writing HTML by hand is easier than debugging your static site generator
logicgrimoire.wordpress.com
logicgrimoire.wordpress.com
And since I'm already there, I do also like scss + file watching / hot reloading. Though would happily live without it, if there was a 'native' solution to e.g.
<html>
<% include './header.html'>
<body>
...
</body>
<% include './footer.html'>
</html>I think the post you're replying to was trying to make the point "it's worth the complexity"
include("header.html");The only difference between SSG and dynamic backends is the point in time that you're generating cacheable static content.
I do. Partying like it's 1999.
Say you have a menu + banner at the top. It's its own document. looking at the source it all makes perfect sense. The css only affects this frame so you can just target the links image or list items directly without a class or id.
Then you click on the links (at the top) and they open different side menus that are also amazingly simple documents.
Clicking on those opens all kinds of things in the main area. PDF images, video, widgets, error pages, EVEN DIFFERENT DOMAINS!
Or [say] music, in a small frame on the side.
The big frameset issue was that the address bar didn't show a useful url and opening a link in a new tab was a problem. These are now easily fixed by pushstate and you can also rebuild the frameset in a new tab if the user tries to open a link in a new tab.
As there is nothing dynamic about the documents they are easily cached. Clicking around feels like an application!
You can also reuse the side menu frame to open diagrams and charts to accompany the text without scrolling up and down like a madman.
On mobile you simply don't load the frame set. The menu is the mobile application.
We also got <details> and <summary> adding even more dept to the menus entirely without js.
I still have to one day make a website with it.
The top arguments here[1] are:
> 1) Frames prevent users from properly bookmarking pages.
Not true anymore since we have History.pushState() and History.replaceState()
> 2) Frames present challenges for printing web pages.
This is just funny in 2024.
> 3) Users coming from search engines may not have access to navigational elements if they are located in another frame — they are directed to only that frame the search engine found the text in.
The top page is actually so simple that if pages that should be framed are loaded on their own they can can just act like a frameset and load themselves into one of the frames[2] (or redirect to the frame set)
if(window.self == window.top){
frameset = document.createElement('frameset');
frameset.setAttribute('cols', '50%, 50%');
frameset.innerHTML = `
<frame src="https://example.com" />
<frame src="https://example.com" />`;
document.body.replaceWith(frameset);
}
[0] - https://developer.mozilla.org/en-US/docs/Web/HTML/Element/fr...[1] - https://stackoverflow.com/questions/4263509/why-are-frames-d...
Having base64 images within a document encoded saves so much faff of CDNs, excess latency and bandwidth. Gives greater control and more archivability.
Sure the page file size jumps up but web servers enjoy serving large files. Your not losing anything else, you would still be serving xMB from some image service. Possibly double.
If we can serve 8mb SPA applications, we can serve 8mb Base64 images within html files.
A sibling (top-level) comment suggest a standard HTML templating (or SSI) language that many static hosts would support. I like that idea quite a bit conceptually, though of course much easier said than done.
But client-side includes are inherently slower on first load than server-side includes, because they require an additional round trip to fetch the partial content.
That performance hit is particularly painful for the header. You either have to show a flash of content without the header, causing the page to jump around when the header loads in, or slow down the entire page while you wait for the second round-trip request.
"But what about subsequent page loads, where the header is in the browser's cache?" That's fine, but the savings are pretty minimal. Headers and footers are typically not a lot of bytes on the wire, so there's not a huge savings.
If all you want is the developer experience of writing HTML "by hand" without copying and pasting your header, server-side includes are a battle-tested solution.
In that case just flip it-- give links as data urls which hard-code the header/footer and which use a client-side include for the content. :)
Old links eternally provide the navigation the users know and love!
<!doctype html [
<!entity hdr system "header.html">
...
]>
&header <!-- content of header.html gets included here -->
... page body content goes here ...
SGML can also take care of inferring omitted <html>, <head>, and <body> tags here.Moreover, you can also use more sophisticated entity expansion and template mechanisms with type checking, proper HTML-aware auto-escaping (for things such as potentially malicious user-provided comments), table-of-content/nav generation, etc. etc.
Well, the way this would work... already exists. It would be just an iframe.
<INSERT SRC="a_quote.html">https://web.dev/articles/imports https://www.w3.org/TR/html-imports/
Functionally, it would be about the same? Caching would even largely go the way you want it to with it hitting the main layout page first, and then pulling in the content pages.
Edit: Amusingly, this organization strategy also provides a relatively easy way to try out other layouts. Since you can make a new driver page that iframes in your content.
With webcomponents, it's now trivial to do client-side includes. It's not really a missing feature anymore. See this post here (which, for some reason is being downvoted): https://news.ycombinator.com/item?id=40847759
Sure, but only for implementing your own. In practice they don't typically require the author of the page to know any Javascript. I'm using a client-side include by writing only HTML tags (with a 'remote-src' attribute).
It's no different from not having to know C++ in order to write HTML which is rendered by C++ code. The implementation just doesn't matter, because the user (in this case the page/site author) never needs to examine it.
https://www.w3.org/TR/WD-html40-970708/struct/includes.html#...
It can be a delicate balance to stick to simplicity when we say that's what we're after.
One thing that seems to get lost in modern programming is the JS frameworks arose in a time where HTML5+/CSS were also growing to gain some of those capabilities.
For example, Web Components, Web Sockets, etc., are all pretty capable assuming it's a feature implemented in the browsers.
In a recent project / prototype, the task was to build video capture and playing from scratch in html/ vanilla javascript. It was surprising how far it got compared to the libraries and frameworks out there.
In the end, there were some tradeoffs to both but the consensus was no one had every considered HTML/JS alone could do it (even though js frameworks use.. js).
Javascript30.com is a handy spot for new to JS developers to learn Javascript how I think it should be learned. First Vanilla, then Libraries, then Frameworks, in that order. Each helps fill in the "why" of the next.
I’ve mainly seen the object tag used ages ago back when people had Flash animations on websites. I remember Java Applets also but I think at the time people were using the applet tag for Java Applets. PDFs might also have been using the object tag however.
Still, here's another.
https://www.w3schools.com/tags/tag_object.asp
better yet: https://www.w3schools.com/tags/tryit.asp?filename=tryhtml_ob...
Maybe it looks different on desktop than on mobile?
On mobile I didn’t see any mention of embedding another html file in that link.
> https://www.w3schools.com/tags/tryit.asp?filename=tryhtml_ob...
I normally dislike w3schools but yep that’s perfect :)
https://www.joelonsoftware.com/2001/10/12/what-does-citydesk...
I know it’s the transform your xml to anything, but I’ve never seen anyone say “this is how you do a simple transformation”
I would have no clue how to built what you suggest.
For templating, there's a simple rule: always start with the identity transform:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
(In particular note that `xsl:copy` is the only bit here that's largely interchangeable with non-xsl nodes in the stylesheet.)Then, generally, you'll add `xsl:template`s that `match` some hard-coded node names (or the root) and add some other structure instead of `xsl:copy` before (if not switching to simple extraction) calling xsl:apply-templates at a deeper depth.
In my experience, attributes are likely to only ever be copied all at once or not at all (e.g. if only made available for extraction), whereas nodes are likely subject to more complicated logic.
For the specific case of a header-footer template, you'd match the root and hard-code the structure instead of using xsl-copy, then use apply-templates where you want to insert the main body from the file that's calling the template.
Also, remember you can test with `xsltproc` to avoid browser overhead. `xmllint --xpath` is useful for selectors as well.
So what SSG are you using? I was going to just make some jinja templates that I re-render with my own script, but it would be great if there was something that supported this out of the box without going crazy far up the complexity ladder.
[0]: https://www.11ty.dev
I entirely agree with the sentiment "writing HTML once is easier than using a static site generator". Hell, even writing it twice is probably easier. The point of a static site generator is there is lots of HTML (like headers and menus) you don't write just once or twice, or if it is generated from data in a database you write at all.
I'm sure the author of the original post would agree in general, so I was left scratching my head what he is actually objecting to. Going by his comment "This becomes obvious when you eg get a new work machine and need to set up the site generator on the new machine and realize that the exact series of bits you had on disk on the old machine were different than what you can achieve on the new machine" maybe it was a rant about how complex tool chains have become.
Or maybe he's just now coming to understand why people stick to what's in Debian Stable, forgoing all the new shinies NPM and the rest of the ecosystem offers. It doesn't take too many replacement laptops before than realisation dawns.
The scripts can rebuild the entire web page but I actually use document.write in stead. You get to use template strings nowadays. It's hilarious!
document.write(`<div id="kungfu">
<ul>
<li>
<a href="banana.html">banana!</a>
</li>
</ul>
</div>`);
before that I was using multi-line comments in function bodies. Like so https://jsfiddle.net/wLb8hjgn/https://github.com/miragecraft/x-include
The main advantage is that it’s not subject to CORS thus works directly from the local file system without having to set up localhost.
https://htmx.org is a battle tested lib can load partials using ajax. but then your website wont work with javascript off.
I'd have to test if it works locally without a webserver.
With a web server like the embeded Python or PHP webserver, it works everywhere.
<zjs-include remote-src='/project/webroot/zjsi/navbar-signed-in.zjsi'></zjs-include>
<zjs-include remote-src='/project/webroot/zjsi/error-dialog.zjsi'></zjs-include>
<zjs-include remote-src='/project/webroot/zjsi/info-dialog.zjsi'></zjs-include>
So, yeah, you don't need server-side includes if you use one of many free client-side webcomponent. That component `zjs-include` took me 30m to write.Might be true until you need to create those lovely RSS feeds by hand…
> Do you enjoy debugging programming language installations? What about the language’s package ecosystem?
No and that is why I switched from Jekyll to the single binary SSG Hugo. Zola works the same way, single binary.
There are other options. I know for example that there was an extension for Pandoc that did it for you.
Today there's also gojekyll (which is a single binary).
<item>
<title>It's not that hard</title>
<link>http://www.superkuh.com/this-link-doesnt-exist</link>
<description>This is an example of how quickly I can add a new item to my RSS feed.</description>
</item>- It's fun to play around with static site generators as a technical person
- It's very annoying to actually write content (As you link images by using the file name, no nice editing interface, using a markdown editor is clunky as features of the blogging software (Embedded videos tags etc.) are not supported
- It's impossible for non-technical people to use it. My main reason why I would never introduce a static site generator for documentation at work again.
- You still need some kind of tooling to generate RSS feeds, sitemaps, pagination, so I've settled on https://getkirby.com for now which has a nice editor interface but is file based and doesn't need a database. Makes it easy to backup and move between hosts if needed.
The author is referring to a particular generator, which I agree can be a ridiculous process.
Sure, I could have a dynamic site (ROR, or Express or whatever) but static is easier to serve, and changes are quickly diffed except once a month when the structure is updated.
If was just doing a small site, sure, but anything substantial requires something better.
You can also use it to play around with different programming paradigms--I recently rewrote mine from Rust to Go and played around with a maximally parallel architecture (what I thought would be a fun throw-away experiment quickly became my production SSG): https://blog.weberc2.com/posts/efficient-ssg-with-csp.html
I don't know about your static generators, but my 40 lines of bash are very easy to debug!
Astro is only as complex as you make it. It lets you write JSX-like syntax that compiles to static HTML. I use it for my personal site.
[0]: https://astro.build/
[1]: https://sjer.red/
[1]: (source code) https://github.com/shepherdjerred/sjer.red
Theming, shared blocks, etc. are all handled just fine by using includes. If those are stored in Jinja2 templates or HTML files that use SSIs is pretty irrelevant to me.
As long as I can write in Markdown, I'm happy.
Switching to a generator that ships as a single binary largely resolved this for me.
With https://www.getzola.org and similar you only need worry about installing the same version as the one that's building your site in production.
My problem back then was it was hard to understand what features were server side and required a special host (e.g., your all important visitor counter) what was generated by dreamweaver and what was handled client side.
Yes, it _is_ easier to write plain ol HTML. But how do you handle consistency by hand writing each page? How do you scale your site or add * number of posts or headers and footers that do things like show the latest post? If you update a link somewhere, how do you ensure all the links pointing to it are valid?
We don’t do these things because we’re masochistic. We do them because they, on the net, make things easier. I suspect this sentiment is some kind of new version of the Eternal September, where people previously unexposed to the hardships of creating functional websites think we somehow missed something in our slow march toward where we are now.
I happen to have a hand built static site. It had two pages. When I built the second page, I took the first html file, copy pasted it into a new path and made the changes. That works splendidly for a two page site. But most sites are not this way, I imagine.
It depends on your needs, some use a templating language (like Handlebars, Nunjucks, Pug, etc), others might write a script to build the site
The problem with many static site generators is that they grow beyond their initial mission and get bloated in an effort to please a wider audience, so previous adopters get tired of the imposed complexity and problematic dependencies they didn't need or ask for and start looking for simpler solutions that meet their needs.
I want to migrate, but my blog currently has this cool thing and I need it.
And since the audience probably can't settle, and keep trying different setups, all SSGs grow in complexity and more or less reach feature parity among each other.That sounds an awful lot like a static site generator to me?
Right? They didn't abandon the concept, they just picked a solution that better fits their needs. Less headache, less abstraction, and less surprises overall.
Most of Pelican’s code was written by other people, and yet I have spent almost zero time debugging that code, much less my own. After taking advantage of Pelican’s rich plugin ecosystem and adding a handful of useful plugins, I continue to be amazed by how much time this publishing system saves me, and how little time I must spend to keep everything running smoothly.
What it would take to accomplish this by writing HTML by hand instead… I simply can’t fathom it. But once again, that’s just one person’s experience, and YMMV.
[1]: https://github.com/geolessel/vox
[2]: https://fly.io/phoenix-files/crafting-your-own-static-site-g... - HN: https://news.ycombinator.com/item?id=40850021
This means that a "custom buggy sitegenerator" is never a bad dependency to have.
That's why I never use ANY tools like this without getting them working in something like GitHub Actions (which is effectively free these days, and all the good LLMs know how to write YAML workflow files for it.)
If you outsource the running of these tools to a CI service you don't have to worry about setting them up on new machines.
GH says:
"The software tools included in GitHub-hosted runners are updated weekly."
so don't you have the same problem?
For static stuff I can use GitHub Pages directly. Notes here: https://til.simonwillison.net/github-actions/vite-github-pag...
For something like a marketing site, the homepage is usually custom enough that you wouldn't repeat yourself much. Throw in an about us or contact page and you'll be fine. Much past that and I want partials for basics like the header and footer, and likely a few layout components.
Debugging a static site generator should be a thing in my opinion. When you gave to debug an SSG it's because the tool has to much magic built into it like automatic data pipelines, opinionated front-matter schemas, etc.
Right now the problem I have is that text that's been marked up as HTML suddenly then becomes harder to wrangle around than it was to put it into HTML in the first place.
I want an editor where I can "select all <p>" or "search and replace all <h2> tag names with <h1> tag names while leaving attributes intact" and other ways of reasoning about HTML as HTML in my editor.
The only drawback is that I can't really help people when they ask me for an SSG recommendation since most people won't want to do the same. I recently suggested to someone that they use Jekyll (after I did a small amount of research) but reading these comments makes me worried that was a mistake lol
writing html by hand is easier if you post infrequently, you only post basic text content and you're the only contributor. if you're posting daily, or you're sharing photo galleries, or you're trying to manage contributions from multiple authors, or you have any styling more than the absolute most basic stylesheet, then you're going to last about a day before you start trying to automate things again.
And servers which do not have any backend. Even apache2 SSI isn't enabled by default.
A standard default templating system on static content hosters would help.
The benefit was making sure the links all worked and common page elements like the site navigation, header, and footer were all consistent.
Many folks in that era would use an IDE like HomeSite, FrontPage, and DreamWeaver... these would have template features that you would generate your site from. These tools were very much like using my script only slow and expensive.
I do get where the author is coming from though. There are some static site generators that pack more features and require more configuration than a space command centre. I don't get the appeal of those. The key is to keep it as simple as possible.
how many of the dependencies will still be maintained? will it still even build?
back in the day tools like jQuery were a godsend for ironing out the browser incompatibility but now standards are much better.
well supported tools like that were a great abstraction point to help simplify the codebase and provide consistent functionality in an ever changing landscape of web standards and browser compatibility.
today we have the opposite problem. we have a incomprehensible mess of middleware designed to help out in some way or another but when you add it all together you end up with a 10MB hello world with 3,000 npm dependencies.
recently I decided to write a PWA using only hand rolled HTML and JavaScript and it was a pleasure. the only dependency I had to add was Nosleep.js for safari. it was extremely satisfying compared to dealing with a more modern toolchain.
Certainly beats having to change the header or the footer in a thousand pages, or headers getting out of sync!
If you're using Jekyll or Hugo or similar, sure.
My SSG is a tiny shell script that calls pandoc. I have no problem coming back to it to fix it, but because it's so small there's literally nothing to fix.
I can make it even easier if I used Makefiles.