Ask HN: Server-side HTML Templates based on DOM?
For instance the "main template" for a site could be an HTML page that has a <article> inside it which is a placeholder for the content. The content is itself an HTML page, and the <body> of the content is inserted into the <article>, also the metadata gets merged so the <title> passes through.
You might write
<div>First Name: <span id="#insertFirstName"></span></div>
and the system would insert the firstName into that span, for instance.I've done the same thing in Java with tools like jsoup and HTMLUnit.
This system can rewrite links and do other interesting transformations on the guest HTML.
One thing I'll concede is that this is slow compared to the alternatives. In a crude test a system like this and not optimized might be able to transform 10-50 pages per second on a core whereas it is easy to get 3000+ with string based templates.
I haven't seen other people do this, are there any examples you of know of DOM-based templating? Any thoughts?
23 comments
[ 3.0 ms ] story [ 53.9 ms ] threadHighlevel idea: It reads in all HTML files, parses them with JSDOM, builds a metamodel of the overall website, which (ab-)uses standard HTML meta tags as alternative to a frontmatter (e.g <meta name="template" content="articles"> declares the particular file as the template for the category articles, while <meta name="category" content="article"> declares a particular file as part of the category articles. And then it uses a non-standard HTML tag to call JS plugins with the whole meta-model of the site, so it can plug together content and template, rewrite parts of the DOM (for example add bidirectional links when desired, run a syntax highlighter on <code> tag, count words). When all plugins have run the DOM is serialized into HTML. Admittedly it could be a tad faster, but for my purposes it is good enough. I don't mind running a ton of JS on my machine, but still can serve mostly static HTML with very few sprinkles of client-side JS
[0] https://github.com/fnh/intertwingle/
I think this sounds more like what the author means.
https://symfony.com/bundles/ux-live-component/current/index....
PHPTAL is another system I've heard of (but never used) that seems to be built on this idea. It is also very mature (old). https://phptal.org/
In general working with DOM doesn't seem to be very cool these days. Everyone uses template systems that are glorified string concatenators, like Mustache, and doesn't care about security issues due to bad escaping.
(also, if you need to transform 200 requests per second that's slowing things down, there's almost certainly a cache-layer missing?)
For your example, you can just match in `[id^="insert"]` and add the actual firstName value in the handler.
I use it alot on the server side, but it's for JavaScript side, or Rust if you use the lower level lol-html.
https://crates.io/crates/lol_html
This approach only really has one major benefit over string-based templating, namely, it lets you re-use code across server and client side DOM logic.
It recently got support from all the major browsers.
- https://developer.chrome.com/docs/css-ui/declarative-shadow-...
- https://lamplightdev.com/blog/2024/01/10/streaming-html-out-...
I'm also considering trying something similar to you, and thought that perhaps GoQuery (essentially jQuery written in much faster Golang) could be useful here. https://github.com/PuerkitoBio/goquery
If you need to do the scraping stuff, Colly could be used (which uses GoQuery under the hood). https://go-colly.org/
You could also create a sort of hypermedia "single page app" if you serve the shell once, and then use something like HTMX (or even jquery) to swap the body and other html fragments without a full page reload.
https://github.com/Floofies/cdaTemplate
10–50 pages per second is already more output than a human can produce input for, so it shouldn't be considered a problem.
Converting from a string to a DOM is very expensive because of all the non-XML non-standard cruft HTML accumulated over the years. If you can do a simple string find/replace instead, it should be less computationally expensive. No reason to actually parse the HTML unless you need to actually render it or at least work with it semantically/structurally, which doesn't sound like the case here.